Type-related quick fixes: Render types using fully qualified names

This commit is contained in:
Alexey Sedunov
2014-10-16 20:42:24 +04:00
parent b212fbd0b5
commit 07a2a16232
30 changed files with 356 additions and 69 deletions
@@ -34,6 +34,7 @@ import org.jetbrains.jet.analyzer.analyzeInContext
import org.jetbrains.jet.lang.resolve.calls.callUtil.getCalleeExpressionIfAny
import java.util.LinkedHashSet
import org.jetbrains.jet.lang.resolve.ImportPath
import org.jetbrains.jet.lang.psi.psiUtil.getQualifiedElement
public object ShortenReferences {
public fun process(element: JetElement) {
@@ -90,21 +91,52 @@ public object ShortenReferences {
}
}
fun processAllReferencesInFile(descriptors: List<DeclarationDescriptor>, file: JetFile) {
val renderedDescriptors = descriptors.map { it.asString() }
val referenceToContext = resolveReferencesInFile(file).filter { e ->
val (ref, context) = e
val renderedTargets = ref.getTargets(context).map { it.asString() }
ref is JetSimpleNameExpression && renderedDescriptors.any { it in renderedTargets }
}
shortenReferencesInFile(
file,
referenceToContext.keySet().map { (it as JetSimpleNameExpression).getQualifiedElement() },
referenceToContext,
{ FilterResult.PROCESS }
)
}
private enum class FilterResult {
SKIP
GO_INSIDE
PROCESS
}
private fun resolveReferencesInFile(
file: JetFile,
fileElements: List<JetElement> = Collections.singletonList(file)
): Map<JetReferenceExpression, BindingContext> {
ImportInsertHelper.getInstance().optimizeImportsOnTheFly(file)
return JetFileReferencesResolver.resolve(file, fileElements, resolveShortNames = false)
}
private fun shortenReferencesInFile(
file: JetFile,
elements: List<JetElement>,
referenceToContext: Map<JetReferenceExpression, BindingContext>,
elementFilter: (PsiElement) -> FilterResult
) {
val importInserter = ImportInserter(file)
processElements(elements, ShortenTypesVisitor(file, elementFilter, referenceToContext, importInserter))
processElements(elements, ShortenQualifiedExpressionsVisitor(file, elementFilter, referenceToContext, importInserter))
}
private fun process(elements: Iterable<JetElement>, elementFilter: (PsiElement) -> FilterResult) {
for ((file, fileElements) in elements.groupBy { element -> element.getContainingJetFile() }) {
val importInserter = ImportInserter(file)
// first resolve all qualified references - optimization
val referenceToContext = JetFileReferencesResolver.resolve(file, fileElements, resolveShortNames = false)
processElements(fileElements, ShortenTypesVisitor(file, elementFilter, referenceToContext, importInserter))
processElements(fileElements, ShortenQualifiedExpressionsVisitor(file, elementFilter, referenceToContext, importInserter))
val referenceToContext = resolveReferencesInFile(file, fileElements)
shortenReferencesInFile(file, fileElements, referenceToContext, elementFilter)
}
}
@@ -207,16 +239,6 @@ public object ShortenReferences {
resolveMap: Map<JetReferenceExpression, BindingContext>,
importInserter: ImportInserter
) : ShorteningVisitor<JetQualifiedExpression>(file, elementFilter, resolveMap, importInserter) {
private fun adjustDescriptor(it: DeclarationDescriptor): DeclarationDescriptor {
return (it as? ConstructorDescriptor)?.getContainingDeclaration() ?: it
}
private fun JetReferenceExpression.getTargets(context: BindingContext): Collection<DeclarationDescriptor> {
return context[BindingContext.REFERENCE_TARGET, this]?.let { Collections.singletonList(adjustDescriptor(it)) }
?: context[BindingContext.AMBIGUOUS_REFERENCE_TARGET, this]?.mapTo(HashSet<DeclarationDescriptor>()) { adjustDescriptor(it) }
?: Collections.emptyList()
}
private fun canShorten(qualifiedExpression: JetDotQualifiedExpression): Boolean {
val context = bindingContext(qualifiedExpression)
@@ -268,6 +290,15 @@ public object ShortenReferences {
private fun DeclarationDescriptor.asString()
= DescriptorRenderer.FQ_NAMES_IN_TYPES.render(this)
private fun JetReferenceExpression.getTargets(context: BindingContext): Collection<DeclarationDescriptor> {
fun adjustDescriptor(it: DeclarationDescriptor): DeclarationDescriptor =
(it as? ConstructorDescriptor)?.getContainingDeclaration() ?: it
return context[BindingContext.REFERENCE_TARGET, this]?.let { Collections.singletonList(adjustDescriptor(it)) }
?: context[BindingContext.AMBIGUOUS_REFERENCE_TARGET, this]?.mapTo(HashSet<DeclarationDescriptor>()) { adjustDescriptor(it) }
?: Collections.emptyList()
}
// this class is needed to optimize imports only when we actually insert any import (optimization)
private class ImportInserter(val file: JetFile) {
private var optimizeImports = true
@@ -27,6 +27,8 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames
import org.jetbrains.jet.lang.types.isFlexible
import org.jetbrains.jet.lang.types.flexibility
import java.util.ArrayList
import java.util.LinkedHashSet
fun JetType.makeNullable() = TypeUtils.makeNullable(this)
fun JetType.makeNotNullable() = TypeUtils.makeNotNullable(this)
@@ -63,3 +65,15 @@ public fun approximateFlexibleTypes(jetType: JetType, outermost: Boolean = true)
private fun JetType.isMarkedReadOnly() = getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_READONLY_ANNOTATION) != null
private fun JetType.isMarkedNotNull() = getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION) != null
public fun JetType.getAllReferencedTypes(): Set<JetType> {
val types = LinkedHashSet<JetType>()
fun addType(type: JetType) {
types.add(type)
type.getArguments().forEach { addType(it.getType()) }
}
addType(this)
return types
}
@@ -16,6 +16,7 @@
package org.jetbrains.jet.plugin.quickfix;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
@@ -43,6 +44,7 @@ import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureDa
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -51,6 +53,7 @@ import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignatu
public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
private final JetCallElement callElement;
private final boolean hasTypeMismatches;
private final List<JetType> typesToShorten = new ArrayList<JetType>();
public AddFunctionParametersFix(
@NotNull JetCallElement callElement,
@@ -105,10 +108,16 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
return true;
}
@Override
public boolean startInWriteAction() {
return true;
}
@Override
protected void invoke(@NotNull Project project, Editor editor, JetFile file) {
BindingContext bindingContext = ResolvePackage.getBindingContext((JetFile) callElement.getContainingFile());
runChangeSignature(project, functionDescriptor, addParameterConfiguration(), bindingContext, callElement, getText());
QuickFixUtil.shortenReferencesOfTypes(typesToShorten, file);
}
private JetChangeSignatureConfiguration addParameterConfiguration() {
@@ -128,14 +137,18 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
JetType argumentType = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null;
JetType parameterType = parameters.get(i).getType();
if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType))
changeSignatureData.getParameters().get(i).setTypeText(IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(argumentType));
if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) {
changeSignatureData.getParameters().get(i).setTypeText(IdeDescriptorRenderers.SOURCE_CODE.renderType(argumentType));
typesToShorten.add(argumentType);
}
}
else {
JetParameterInfo parameterInfo = getNewParameterInfo(bindingContext, argument, validator);
typesToShorten.add(parameterInfo.getType());
if (expression != null)
if (expression != null) {
parameterInfo.setDefaultValueText(expression.getText());
}
changeSignatureData.addParameter(parameterInfo);
}
@@ -38,18 +38,20 @@ import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class CastExpressionFix extends JetIntentionAction<JetExpression> {
private final JetType type;
private final String renderedType;
public CastExpressionFix(@NotNull JetExpression element, @NotNull JetType type) {
super(element);
this.type = type;
renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
}
@NotNull
@Override
public String getText() {
return JetBundle.message("cast.expression.to.type", element.getText(), renderedType);
return JetBundle.message(
"cast.expression.to.type",
element.getText(),
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type)
);
}
@NotNull
@@ -68,6 +70,8 @@ public class CastExpressionFix extends JetIntentionAction<JetExpression> {
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
String renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(type);
JetPsiFactory psiFactory = JetPsiFactory(file);
JetBinaryExpressionWithTypeRHS castExpression =
(JetBinaryExpressionWithTypeRHS) psiFactory.createExpression("(" + element.getText() + ") as " + renderedType);
@@ -81,6 +85,8 @@ public class CastExpressionFix extends JetIntentionAction<JetExpression> {
if (JetPsiUtil.areParenthesesUseless(castExpressionInParentheses)) {
castExpressionInParentheses.replace(castExpression);
}
QuickFixUtil.shortenReferencesOfType(type, file);
}
@NotNull
@@ -88,7 +94,7 @@ public class CastExpressionFix extends JetIntentionAction<JetExpression> {
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
DiagnosticWithParameters2<JetExpression, JetType, String> diagnosticWithParameters =
Errors.SMARTCAST_IMPOSSIBLE.cast(diagnostic);
return new CastExpressionFix(diagnosticWithParameters.getPsiElement(), diagnosticWithParameters.getA());
@@ -32,7 +32,7 @@ import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class ChangeAccessorTypeFix extends JetIntentionAction<JetPropertyAccessor> {
private String renderedType;
private JetType type;
public ChangeAccessorTypeFix(@NotNull JetPropertyAccessor element) {
super(element);
@@ -44,7 +44,7 @@ public class ChangeAccessorTypeFix extends JetIntentionAction<JetPropertyAccesso
if (property == null) return false;
JetType type = QuickFixUtil.getDeclarationReturnType(property);
if (super.isAvailable(project, editor, file) && type != null && !type.isError()) {
renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
this.type = type;
return true;
}
return false;
@@ -53,9 +53,10 @@ public class ChangeAccessorTypeFix extends JetIntentionAction<JetPropertyAccesso
@NotNull
@Override
public String getText() {
return element.isGetter()
? JetBundle.message("change.getter.type", renderedType)
: JetBundle.message("change.setter.type", renderedType);
return JetBundle.message(
element.isGetter() ? "change.getter.type" : "change.setter.type",
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type)
);
}
@NotNull
@@ -67,7 +68,7 @@ public class ChangeAccessorTypeFix extends JetIntentionAction<JetPropertyAccesso
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
JetPropertyAccessor newElement = (JetPropertyAccessor) element.copy();
JetTypeReference newTypeReference = JetPsiFactory(file).createType(renderedType);
JetTypeReference newTypeReference = JetPsiFactory(file).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type));
if (element.isGetter()) {
JetTypeReference returnTypeReference = newElement.getReturnTypeReference();
@@ -82,12 +83,14 @@ public class ChangeAccessorTypeFix extends JetIntentionAction<JetPropertyAccesso
CodeEditUtil.replaceChild(parameter.getNode(), typeReference.getNode(), newTypeReference.getNode());
}
element.replace(newElement);
QuickFixUtil.shortenReferencesOfType(type, file);
}
public static JetSingleIntentionActionFactory createFactory() {
return new JetSingleIntentionActionFactory() {
@Override
public JetIntentionAction<JetPropertyAccessor> createAction(Diagnostic diagnostic) {
public JetIntentionAction<JetPropertyAccessor> createAction(@NotNull Diagnostic diagnostic) {
JetPropertyAccessor accessor = QuickFixUtil.getParentElementOfType(diagnostic, JetPropertyAccessor.class);
if (accessor == null) return null;
return new ChangeAccessorTypeFix(accessor);
@@ -46,13 +46,13 @@ import java.util.List;
import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFunctionLiteralExpression> {
private final String renderedType;
private final JetType type;
private final JetTypeReference functionLiteralReturnTypeRef;
private IntentionAction appropriateQuickFix = null;
public ChangeFunctionLiteralReturnTypeFix(@NotNull JetFunctionLiteralExpression functionLiteralExpression, @NotNull JetType type) {
super(functionLiteralExpression);
renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
this.type = type;
functionLiteralReturnTypeRef = functionLiteralExpression.getFunctionLiteral().getTypeReference();
BindingContext context = ResolvePackage.getBindingContext(functionLiteralExpression.getContainingJetFile());
@@ -111,7 +111,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
if (appropriateQuickFix != null) {
return appropriateQuickFix.getText();
}
return JetBundle.message("change.function.literal.return.type", renderedType);
return JetBundle.message("change.function.literal.return.type", IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type));
}
@NotNull
@@ -129,7 +129,8 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
if (functionLiteralReturnTypeRef != null) {
functionLiteralReturnTypeRef.replace(JetPsiFactory(file).createType(renderedType));
functionLiteralReturnTypeRef.replace(JetPsiFactory(file).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)));
QuickFixUtil.shortenReferencesOfType(type, file);
}
if (appropriateQuickFix != null && appropriateQuickFix.isAvailable(project, editor, file)) {
appropriateQuickFix.invoke(project, editor, file);
@@ -141,7 +142,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
JetFunctionLiteralExpression functionLiteralExpression = QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralExpression.class);
if (functionLiteralExpression == null) return null;
return new ChangeFunctionLiteralReturnTypeFix(functionLiteralExpression, KotlinBuiltIns.getInstance().getUnitType());
@@ -52,13 +52,11 @@ import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction> {
private final JetType type;
private final String renderedType;
private final ChangeFunctionLiteralReturnTypeFix changeFunctionLiteralReturnTypeFix;
public ChangeFunctionReturnTypeFix(@NotNull JetFunction element, @NotNull JetType type) {
super(element);
this.type = type;
renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
if (element instanceof JetFunctionLiteral) {
JetFunctionLiteralExpression functionLiteralExpression = PsiTreeUtil.getParentOfType(element, JetFunctionLiteralExpression.class);
assert functionLiteralExpression != null : "FunctionLiteral outside any FunctionLiteralExpression: " +
@@ -86,6 +84,7 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
JetBundle.message("remove.no.name.function.return.type") :
JetBundle.message("remove.function.return.type", functionName);
}
String renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
return functionName == null ?
JetBundle.message("change.no.name.function.return.type", renderedType) :
JetBundle.message("change.function.return.type", functionName, renderedType);
@@ -103,17 +102,18 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
}
@Override
public void invoke(@NotNull Project project, @Nullable Editor editor, @Nullable JetFile file) throws IncorrectOperationException {
public void invoke(@NotNull Project project, @Nullable Editor editor, JetFile file) throws IncorrectOperationException {
if (changeFunctionLiteralReturnTypeFix != null) {
changeFunctionLiteralReturnTypeFix.invoke(project, editor, file);
}
else {
if (!(KotlinBuiltIns.getInstance().isUnit(type) && element.hasBlockBody())) {
element.setTypeReference(JetPsiFactory(project).createType(renderedType));
element.setTypeReference(JetPsiFactory(project).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)));
}
else {
element.setTypeReference(null);
}
QuickFixUtil.shortenReferencesOfType(type, file);
}
}
@@ -131,7 +131,7 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
JetMultiDeclarationEntry entry = getMultiDeclarationEntryThatTypeMismatchComponentFunction(diagnostic);
BindingContext context = ResolvePackage.getBindingContext((JetFile) entry.getContainingFile().getContainingFile());
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
@@ -152,7 +152,7 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
JetExpression expression = QuickFixUtil.getParentElementOfType(diagnostic, JetExpression.class);
assert expression != null : "HAS_NEXT_FUNCTION_TYPE_MISMATCH reported on element that is not within any expression";
BindingContext context = ResolvePackage.getBindingContext(expression.getContainingJetFile());
@@ -173,7 +173,7 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
JetBinaryExpression expression = QuickFixUtil.getParentElementOfType(diagnostic, JetBinaryExpression.class);
assert expression != null : "COMPARE_TO_TYPE_MISMATCH reported on element that is not within any expression";
BindingContext context = ResolvePackage.getBindingContext(expression.getContainingJetFile());
@@ -234,7 +234,7 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
JetFunction function = QuickFixUtil.getParentElementOfType(diagnostic, JetFunction.class);
return function == null ? null : new ChangeFunctionReturnTypeFix(function, KotlinBuiltIns.getInstance().getUnitType());
}
@@ -42,6 +42,7 @@ import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester;
import org.jetbrains.jet.plugin.refactoring.JetNameValidator;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import java.util.List;
@@ -116,7 +117,10 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
JetExpression expression = argument.getArgumentExpression();
JetType type = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null;
type = type != null ? type : KotlinBuiltIns.getInstance().getNullableAnyType();
return new JetParameterInfo(name, type);
JetParameterInfo parameterInfo = new JetParameterInfo(name, type);
parameterInfo.setTypeText(IdeDescriptorRenderers.SOURCE_CODE.renderType(type));
return parameterInfo;
}
private static boolean hasTypeMismatches(
@@ -34,13 +34,13 @@ import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class ChangeParameterTypeFix extends JetIntentionAction<JetParameter> {
private final String renderedType;
private final JetType type;
private final String containingDeclarationName;
private final boolean isPrimaryConstructorParameter;
public ChangeParameterTypeFix(@NotNull JetParameter element, @NotNull JetType type) {
super(element);
renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
this.type = type;
JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
isPrimaryConstructorParameter = declaration instanceof JetClass;
FqName declarationFQName = declaration == null ? null : declaration.getFqName();
@@ -55,6 +55,7 @@ public class ChangeParameterTypeFix extends JetIntentionAction<JetParameter> {
@NotNull
@Override
public String getText() {
String renderedType = renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
return isPrimaryConstructorParameter ?
JetBundle.message("change.primary.constructor.parameter.type", element.getName(), containingDeclarationName, renderedType) :
JetBundle.message("change.function.parameter.type", element.getName(), containingDeclarationName, renderedType);
@@ -68,6 +69,7 @@ public class ChangeParameterTypeFix extends JetIntentionAction<JetParameter> {
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
element.setTypeReference(JetPsiFactory(file).createType(renderedType));
element.setTypeReference(JetPsiFactory(file).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)));
QuickFixUtil.shortenReferencesOfType(type, file);
}
}
@@ -28,25 +28,29 @@ import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences;
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class ChangeTypeFix extends JetIntentionAction<JetTypeReference> {
private final JetType type;
private final String renderedType;
public ChangeTypeFix(@NotNull JetTypeReference element, JetType type) {
super(element);
renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
this.type = type;
renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(type);
}
@NotNull
@Override
public String getText() {
return JetBundle.message("change.type", element.getText(), renderedType);
String currentTypeText = element.getText();
return JetBundle.message("change.type", currentTypeText, QuickFixUtil.renderTypeWithFqNameOnClash(type, currentTypeText));
}
@NotNull
@@ -58,6 +62,7 @@ public class ChangeTypeFix extends JetIntentionAction<JetTypeReference> {
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
element.replace(JetPsiFactory(file).createType(renderedType));
QuickFixUtil.shortenReferencesOfType(type, file);
}
@NotNull
@@ -65,7 +70,7 @@ public class ChangeTypeFix extends JetIntentionAction<JetTypeReference> {
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
DiagnosticWithParameters1<JetParameter, JetType> diagnosticWithParameters = Errors.EXPECTED_PARAMETER_TYPE_MISMATCH.cast(diagnostic);
JetTypeReference typeReference = diagnosticWithParameters.getPsiElement().getTypeReference();
assert typeReference != null : "EXPECTED_PARAMETER_TYPE_MISMATCH reported on parameter without explicitly declared type";
@@ -79,7 +84,7 @@ public class ChangeTypeFix extends JetIntentionAction<JetTypeReference> {
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
DiagnosticWithParameters1<JetTypeReference, JetType> diagnosticWithParameters = Errors.EXPECTED_RETURN_TYPE_MISMATCH.cast(diagnostic);
return new ChangeTypeFix(diagnosticWithParameters.getPsiElement(), diagnosticWithParameters.getA());
}
@@ -40,7 +40,6 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.LinkedList;
import java.util.List;
@@ -50,12 +49,10 @@ import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclaration> {
private final static Logger LOG = Logger.getInstance(ChangeVariableTypeFix.class);
private final String renderedType;
private final JetType type;
public ChangeVariableTypeFix(@NotNull JetVariableDeclaration element, @NotNull JetType type) {
super(element);
renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type);
this.type = type;
}
@@ -66,7 +63,7 @@ public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclara
FqName fqName = element.getFqName();
if (fqName != null) propertyName = fqName.asString();
return JetBundle.message("change.element.type", propertyName, renderedType);
return JetBundle.message("change.element.type", propertyName, IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type));
}
@NotNull
@@ -82,27 +79,29 @@ public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclara
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
element.setTypeReference(null);
JetPsiFactory psiFactory = JetPsiFactory(file);
PsiElement nameIdentifier = element.getNameIdentifier();
assert nameIdentifier != null : "ChangeVariableTypeFix applied to variable without name";
JetPsiFactory psiFactory = JetPsiFactory(file);
element.addAfter(psiFactory.createType(renderedType), nameIdentifier);
element.addAfter(psiFactory.createColon(), nameIdentifier);
JetTypeReference replacingTypeReference = psiFactory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type));
element.setTypeReference(replacingTypeReference);
if (element instanceof JetProperty) {
JetPropertyAccessor getter = ((JetProperty) element).getGetter();
JetTypeReference getterReturnTypeRef = getter == null ? null : getter.getReturnTypeReference();
if (getterReturnTypeRef != null) {
getterReturnTypeRef.replace(psiFactory.createType(renderedType));
getterReturnTypeRef.replace(replacingTypeReference);
}
JetPropertyAccessor setter = ((JetProperty) element).getSetter();
JetParameter setterParameter = setter == null ? null : setter.getParameter();
JetTypeReference setterParameterTypeRef = setterParameter == null ? null : setterParameter.getTypeReference();
if (setterParameterTypeRef != null) {
setterParameterTypeRef.replace(psiFactory.createType(renderedType));
setterParameterTypeRef.replace(replacingTypeReference);
}
}
QuickFixUtil.shortenReferencesOfType(type, file);
}
@NotNull
@@ -110,7 +109,7 @@ public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclara
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
JetMultiDeclarationEntry entry = ChangeFunctionReturnTypeFix.getMultiDeclarationEntryThatTypeMismatchComponentFunction(diagnostic);
BindingContext context = ResolvePackage.getBindingContext(entry.getContainingJetFile());
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
@@ -22,6 +22,8 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
@@ -32,14 +34,23 @@ import org.jetbrains.jet.lang.diagnostics.Diagnostic;
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.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.DeferredType;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences;
import org.jetbrains.jet.plugin.references.BuiltInsReferenceResolver;
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import org.jetbrains.jet.plugin.util.UtilPackage;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class QuickFixUtil {
@@ -195,4 +206,42 @@ public class QuickFixUtil {
return usedParameters;
}
public static String renderTypeWithFqNameOnClash(JetType type, String nameToCheckAgainst) {
FqName typeFqName = DescriptorUtils.getFqNameSafe(DescriptorUtils.getClassDescriptorForType(type));
FqName fqNameToCheckAgainst = new FqName(nameToCheckAgainst);
DescriptorRenderer renderer = typeFqName.shortName().equals(fqNameToCheckAgainst.shortName())
? IdeDescriptorRenderers.SOURCE_CODE
: IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES;
return renderer.renderType(type);
}
public static void shortenReferencesOfType(@NotNull JetType type, @NotNull JetFile file) {
shortenReferencesOfTypes(Collections.singletonList(type), file);
}
public static void shortenReferencesOfTypes(@NotNull List<JetType> types, @NotNull JetFile file) {
Set<JetType> typesToShorten = KotlinPackage.flatMapTo(
types,
new LinkedHashSet<JetType>(),
new Function1<JetType, Iterable<JetType>>() {
@Override
public Iterable<JetType> invoke(JetType type) {
return UtilPackage.getAllReferencedTypes(type);
}
}
);
ShortenReferences.INSTANCE$.processAllReferencesInFile(
KotlinPackage.map(
typesToShorten,
new Function1<JetType, DeclarationDescriptor>() {
@Override
public DeclarationDescriptor invoke(JetType type) {
return DescriptorUtils.getClassDescriptorForType(type);
}
}
),
file
);
}
}
@@ -166,6 +166,10 @@ public class JetParameterInfo implements ParameterInfo {
this.valOrVar = valOrVar;
}
public JetType getType() {
return type;
}
public String getDeclarationSignature(boolean isInherited, PsiElement inheritedFunction, JetMethodDescriptor baseFunction) {
StringBuilder buffer = new StringBuilder();
JetValVar valVar = getValOrVar();
@@ -0,0 +1,11 @@
// "Add parameter to function 'foo'" "true"
// DISABLE-ERRORS
import kotlin.modules.ModuleBuilder
fun foo(x: Int,
moduleBuilder: ModuleBuilder) {
foo(, ModuleBuilder("", ""));
foo(1, ModuleBuilder("", ""));
foo(2, ModuleBuilder("", ""));
}
@@ -0,0 +1,8 @@
// "Add parameter to function 'foo'" "true"
// DISABLE-ERRORS
fun foo(x: Int) {
foo(,);
foo(1);
foo(2, kotlin.modules.ModuleBuilder("", "")<caret>);
}
@@ -0,0 +1,7 @@
// "Change getter type to Module" "true"
import kotlin.modules.Module
class A() {
val i: Module
get(): <caret>Module = kotlin.modules.ModuleBuilder("", "")
}
@@ -0,0 +1,5 @@
// "Change getter type to Module" "true"
class A() {
val i: kotlin.modules.Module
get(): <caret>Any = kotlin.modules.ModuleBuilder("", "")
}
@@ -0,0 +1,9 @@
// "Change type from 'String' to '(ModuleBuilder) -> Module'" "true"
import kotlin.modules.ModuleBuilder
import kotlin.modules.Module
fun foo(f: ((ModuleBuilder) -> Module) -> String) {
foo {
(f: (ModuleBuilder) -> Module) -> "42"
}
}
@@ -0,0 +1,5 @@
// "Change 'bar' function return type to 'Module'" "true"
import kotlin.modules.Module
fun bar(): Module = kotlin.modules.ModuleBuilder("", "")
fun foo(): Module = bar(<caret>)
@@ -0,0 +1,8 @@
// "Change type from 'String' to 'Module'" "true"
import kotlin.modules.Module
fun foo(f: (Module) -> String) {
foo {
(x: Module<caret>) -> ""
}
}
@@ -0,0 +1,6 @@
// "Change 'f' type to '(Delegates) -> Unit'" "true"
import kotlin.properties.Delegates
fun foo() {
var f: (Delegates) -> Unit = { (x: Delegates) -> }<caret>
}
@@ -0,0 +1,6 @@
// "Change type from 'String' to '(ModuleBuilder) -> Module'" "true"
fun foo(f: ((kotlin.modules.ModuleBuilder) -> kotlin.modules.Module) -> String) {
foo {
(f: String<caret>) -> "42"
}
}
@@ -0,0 +1,3 @@
// "Change 'bar' function return type to 'Module'" "true"
fun bar(): Any = kotlin.modules.ModuleBuilder("", "")
fun foo(): kotlin.modules.Module = bar(<caret>)
@@ -0,0 +1,6 @@
// "Change type from 'String' to 'Module'" "true"
fun foo(f: (kotlin.modules.Module) -> String) {
foo {
(x: String<caret>) -> ""
}
}
@@ -0,0 +1,4 @@
// "Change 'f' type to '(Delegates) -> Unit'" "true"
fun foo() {
var f: Int = { (x: kotlin.properties.Delegates) -> }<caret>
}
@@ -0,0 +1,9 @@
// "Cast expression 'module' to 'ModuleBuilder'" "true"
// DISABLE-ERRORS
import kotlin.modules.ModuleBuilder
fun foo(): ModuleBuilder {
val module: kotlin.modules.Module = ModuleBuilder("", "")
return module as ModuleBuilder
}
@@ -0,0 +1,7 @@
// "Cast expression 'module' to 'ModuleBuilder'" "true"
// DISABLE-ERRORS
fun foo(): kotlin.modules.ModuleBuilder {
val module: kotlin.modules.Module = kotlin.modules.ModuleBuilder("", "")
return module<caret>
}
@@ -0,0 +1,8 @@
// "Change parameter 'x' type of function 'bar.foo' to '(Module) -> Int'" "true"
package bar
import kotlin.modules.Module
fun foo(w: Int = 0, x: (Module) -> Int, y: Int = 0, z: (Int) -> Int = {42}) {
foo(1, {(a: Module) -> 42}<caret>, 1)
}
@@ -0,0 +1,5 @@
// "Change parameter 'x' type of function 'bar.foo' to '(Module) -> Int'" "true"
package bar
fun foo(w: Int = 0, x: Int, y: Int = 0, z: (Int) -> Int = {42}) {
foo(1, {(a: kotlin.modules.Module) -> 42}<caret>, 1)
}
@@ -440,7 +440,13 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/beforeAddFunctionParameterAndChangeTypes.kt");
doTest(fileName);
}
@TestMetadata("beforeAddFunctionParameterLongNameRuntime.kt")
public void testAddFunctionParameterLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/beforeAddFunctionParameterLongNameRuntime.kt");
doTest(fileName);
}
@TestMetadata("beforeAddParameterNotAvailableForBuiltins.kt")
public void testAddParameterNotAvailableForBuiltins() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/beforeAddParameterNotAvailableForBuiltins.kt");
@@ -3189,7 +3195,13 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeAddition/beforeWrongGetterParameterType.kt");
doTest(fileName);
}
@TestMetadata("beforeWrongGetterParameterTypeLongNameRuntime.kt")
public void testWrongGetterParameterTypeLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeAddition/beforeWrongGetterParameterTypeLongNameRuntime.kt");
doTest(fileName);
}
@TestMetadata("beforeWrongSetterParameterType.kt")
public void testWrongSetterParameterType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeAddition/beforeWrongSetterParameterType.kt");
@@ -3250,13 +3262,25 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeChangeFunctionLiteralParameterTypeToFunctionType.kt");
doTest(fileName);
}
@TestMetadata("beforeChangeFunctionLiteralParameterTypeToFunctionTypeLongNameRuntime.kt")
public void testChangeFunctionLiteralParameterTypeToFunctionTypeLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeChangeFunctionLiteralParameterTypeToFunctionTypeLongNameRuntime.kt");
doTest(fileName);
}
@TestMetadata("beforeChangeFunctionReturnTypeToMatchExpectedTypeOfCall.kt")
public void testChangeFunctionReturnTypeToMatchExpectedTypeOfCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeChangeFunctionReturnTypeToMatchExpectedTypeOfCall.kt");
doTest(fileName);
}
@TestMetadata("beforeChangeFunctionReturnTypeToMatchExpectedTypeOfCallLongNameRuntime.kt")
public void testChangeFunctionReturnTypeToMatchExpectedTypeOfCallLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeChangeFunctionReturnTypeToMatchExpectedTypeOfCallLongNameRuntime.kt");
doTest(fileName);
}
@TestMetadata("beforeChangeReturnTypeWhenFunctionNameIsMissing.kt")
public void testChangeReturnTypeWhenFunctionNameIsMissing() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeWhenFunctionNameIsMissing.kt");
@@ -3286,7 +3310,13 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeExpectedParameterTypeMismatch.kt");
doTest(fileName);
}
@TestMetadata("beforeExpectedParameterTypeMismatchLongNameRuntime.kt")
public void testExpectedParameterTypeMismatchLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeExpectedParameterTypeMismatchLongNameRuntime.kt");
doTest(fileName);
}
@TestMetadata("beforeExpectedReturnTypeMismatch.kt")
public void testExpectedReturnTypeMismatch() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeExpectedReturnTypeMismatch.kt");
@@ -3310,7 +3340,13 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforePropertyTypeMismatch.kt");
doTest(fileName);
}
@TestMetadata("beforePropertyTypeMismatchLongNameRuntime.kt")
public void testPropertyTypeMismatchLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforePropertyTypeMismatchLongNameRuntime.kt");
doTest(fileName);
}
@TestMetadata("beforeReturnTypeMismatch.kt")
public void testReturnTypeMismatch() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeReturnTypeMismatch.kt");
@@ -3384,6 +3420,13 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/beforeTypeMismatch5.kt");
doTest(fileName);
}
@TestMetadata("beforeTypeMismatchLongNameRuntime.kt")
public void testTypeMismatchLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/beforeTypeMismatchLongNameRuntime.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/quickfix/typeMismatch/componentFunctionReturnTypeMismatch")
@@ -3489,6 +3532,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeChangeFunctionParameterType5.kt");
doTest(fileName);
}
@TestMetadata("beforeChangeParameterTypeLongNameRuntime.kt")
public void testChangeParameterTypeLongNameRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeChangeParameterTypeLongNameRuntime.kt");
doTest(fileName);
}
@TestMetadata("beforeChangePrimaryConstructorParameterType.kt")
public void testChangePrimaryConstructorParameterType() throws Exception {