Introduce Variable: Do not create separate template to edit type reference

#KT-4314 Fixed
This commit is contained in:
Alexey Sedunov
2014-12-24 20:27:30 +03:00
parent 46ceed8586
commit e296390dd6
3 changed files with 105 additions and 34 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -141,24 +141,8 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
return type == null ? ErrorUtils.createErrorType("null type") : type;
}
public static void addTypeAnnotation(Project project, @Nullable Editor editor, @NotNull JetCallableDeclaration declaration, @NotNull JetType exprType) {
if (editor != null) {
addTypeAnnotationWithTemplate(project, editor, declaration, exprType);
}
else {
declaration.setTypeReference(anyTypeRef(project));
}
}
private static void addTypeAnnotationWithTemplate(
@NotNull Project project,
@NotNull Editor editor,
@NotNull final JetCallableDeclaration declaration,
@NotNull JetType exprType
) {
assert !exprType.isError() : "Unexpected error type, should have been checked before: "
+ JetPsiUtil.getElementTextWithContext(declaration) + ", type = " + exprType;
@NotNull
public static Expression createTypeExpressionForTemplate(JetType exprType) {
ClassifierDescriptor descriptor = exprType.getConstructor().getDeclarationDescriptor();
boolean isAnonymous = descriptor != null && DescriptorUtils.isAnonymousObject(descriptor);
@@ -166,7 +150,7 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
List<JetType> types = isAnonymous ? new ArrayList<JetType>() : Lists.newArrayList(exprType);
types.addAll(allSupertypes);
Expression expression = new JetTypeLookupExpression<JetType>(
return new JetTypeLookupExpression<JetType>(
types,
types.iterator().next(),
JetBundle.message("specify.type.explicitly.add.action.name")
@@ -181,6 +165,39 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
return IdeDescriptorRenderers.SOURCE_CODE.renderType(element);
}
};
}
public static void addTypeAnnotation(Project project, @Nullable Editor editor, @NotNull JetCallableDeclaration declaration, @NotNull JetType exprType) {
if (editor != null) {
addTypeAnnotationWithTemplate(project, editor, declaration, exprType);
}
else {
declaration.setTypeReference(anyTypeRef(project));
}
}
public static TemplateEditingAdapter createTypeReferencePostprocessor(final JetCallableDeclaration declaration) {
return new TemplateEditingAdapter() {
@Override
public void templateFinished(Template template, boolean brokenOff) {
JetTypeReference typeRef = declaration.getTypeReference();
if (typeRef != null) {
ShortenReferences.INSTANCE$.process(typeRef);
}
}
};
}
private static void addTypeAnnotationWithTemplate(
@NotNull Project project,
@NotNull Editor editor,
@NotNull JetCallableDeclaration declaration,
@NotNull JetType exprType
) {
assert !exprType.isError() : "Unexpected error type, should have been checked before: "
+ JetPsiUtil.getElementTextWithContext(declaration) + ", type = " + exprType;
Expression expression = createTypeExpressionForTemplate(exprType);
declaration.setTypeReference(anyTypeRef(project));
@@ -195,15 +212,7 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
editor.getCaretModel().moveToOffset(newTypeRef.getNode().getStartOffset());
TemplateManagerImpl manager = new TemplateManagerImpl(project);
manager.startTemplate(editor, builder.buildInlineTemplate(), new TemplateEditingAdapter() {
@Override
public void templateFinished(Template template, boolean brokenOff) {
JetTypeReference typeRef = declaration.getTypeReference();
if (typeRef != null) {
ShortenReferences.INSTANCE$.process(typeRef);
}
}
});
manager.startTemplate(editor, builder.buildInlineTemplate(), createTypeReferencePostprocessor(declaration));
}
private static JetTypeReference anyTypeRef(@NotNull Project project) {
@@ -16,6 +16,9 @@
package org.jetbrains.jet.plugin.refactoring.introduce.introduceVariable;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
@@ -23,25 +26,29 @@ import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.refactoring.introduce.inplace.InplaceVariableIntroducer;
import com.intellij.ui.NonFocusableCheckBox;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction;
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.LinkedHashSet;
public class KotlinInplaceVariableIntroducer extends InplaceVariableIntroducer<JetExpression> {
@@ -117,12 +124,19 @@ public class KotlinInplaceVariableIntroducer extends InplaceVariableIntroducer<J
}
}
}
SpecifyTypeExplicitlyAction.addTypeAnnotation(myProject, myEditor, myProperty, myExprType);
PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument());
String renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(myExprType);
myProperty.setTypeReference(new JetPsiFactory(myProject).createType(renderedType));
}
else {
myProperty.setTypeReference(null);
}
TemplateState templateState =
TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor));
if (templateState != null) {
myEditor.putUserData(INTRODUCE_RESTART, true);
templateState.cancelTemplate();
}
}
}.execute();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@@ -145,6 +159,10 @@ public class KotlinInplaceVariableIntroducer extends InplaceVariableIntroducer<J
}
});
if (myEditor.getUserData(INTRODUCE_RESTART) == Boolean.TRUE) {
myInitialName = myProperty.getName();
performInplaceRefactoring(getSuggestionsForNextRun());
}
}
});
}
@@ -171,6 +189,49 @@ public class KotlinInplaceVariableIntroducer extends InplaceVariableIntroducer<J
return panel;
}
private LinkedHashSet<String> getSuggestionsForNextRun() {
LinkedHashSet<String> nameSuggestions;
String currentName = myProperty.getName();
if (myNameSuggestions.contains(currentName)) {
nameSuggestions = myNameSuggestions;
}
else {
nameSuggestions = new LinkedHashSet<String>();
nameSuggestions.add(currentName);
nameSuggestions.addAll(myNameSuggestions);
}
return nameSuggestions;
}
@Override
protected void addAdditionalVariables(TemplateBuilderImpl builder) {
JetTypeReference typeReference = myProperty.getTypeReference();
if (typeReference != null) {
builder.replaceElement(typeReference, SpecifyTypeExplicitlyAction.createTypeExpressionForTemplate(myExprType));
}
}
@Override
protected boolean buildTemplateAndStart(
Collection<PsiReference> refs,
Collection<Pair<PsiElement, TextRange>> stringUsages,
PsiElement scope,
PsiFile containingFile
) {
myEditor.putUserData(INTRODUCE_RESTART, false);
//noinspection ConstantConditions
myEditor.getCaretModel().moveToOffset(getNameIdentifier().getTextOffset());
boolean result = super.buildTemplateAndStart(refs, stringUsages, scope, containingFile);
TemplateState templateState =
TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor));
if (templateState != null && myProperty.getTypeReference() != null) {
templateState.addTemplateStateListener(SpecifyTypeExplicitlyAction.createTypeReferencePostprocessor(myProperty));
}
return result;
}
@Override
protected void moveOffsetAfter(boolean success) {
if (!myReplaceOccurrence || myExprMarker == null) {