diff options
Diffstat (limited to 'java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java')
-rw-r--r-- | java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java new file mode 100644 index 000000000000..9571807cd229 --- /dev/null +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java @@ -0,0 +1,124 @@ +package com.intellij.refactoring.typeMigration.intentions; + +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.codeInsight.intention.impl.TypeExpression; +import com.intellij.codeInsight.template.*; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.typeMigration.TypeMigrationProcessor; +import com.intellij.refactoring.typeMigration.TypeMigrationRules; +import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** + * @author anna + */ +public class ChangeClassParametersIntention extends PsiElementBaseIntentionAction { + + private static final Logger LOG = Logger.getInstance("#" + ChangeClassParametersIntention.class); + + @NotNull + @Override + public String getText() { + return getFamilyName(); + } + + @NotNull + @Override + public String getFamilyName() { + return "Change class type parameter"; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + final PsiTypeElement typeElement = PsiTreeUtil.getTopmostParentOfType(element, PsiTypeElement.class); + final PsiElement parent = typeElement != null ? typeElement.getParent() : null; + final PsiReferenceParameterList parameterList = parent instanceof PsiReferenceParameterList ? (PsiReferenceParameterList)parent : null; + if (parameterList != null && parameterList.getTypeArguments().length > 0) { + final PsiMember member = PsiTreeUtil.getParentOfType(parameterList, PsiMember.class); + if (member instanceof PsiAnonymousClass) { + final PsiClassType.ClassResolveResult result = ((PsiAnonymousClass)member).getBaseClassType().resolveGenerics(); + return result.getElement() != null && ((PsiAnonymousClass)member).getBaseClassReference().getParameterList() == parameterList; + } + } + return false; + } + + @Override + public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException { + if (!FileModificationService.getInstance().preparePsiElementsForWrite(element)) return; + + final PsiTypeElement typeElement = PsiTreeUtil.getTopmostParentOfType(element, PsiTypeElement.class); + final PsiReferenceParameterList parameterList = PsiTreeUtil.getParentOfType(element, PsiReferenceParameterList.class); + if (parameterList != null && typeElement != null) { + final PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + if (aClass instanceof PsiAnonymousClass) { + editor.getCaretModel().moveToOffset(aClass.getTextOffset()); + final PsiTypeElement[] typeElements = parameterList.getTypeParameterElements(); + final int changeIdx = ArrayUtil.find(typeElements, typeElement); + + final PsiClassType.ClassResolveResult result = ((PsiAnonymousClass)aClass).getBaseClassType().resolveGenerics(); + final PsiClass baseClass = result.getElement(); + LOG.assertTrue(baseClass != null); + final PsiTypeParameter typeParameter = baseClass.getTypeParameters()[changeIdx]; + + final TemplateBuilderImpl templateBuilder = (TemplateBuilderImpl)TemplateBuilderFactory.getInstance().createTemplateBuilder(aClass); + + final String oldTypeText = typeElement.getText(); + final String varName = "param"; + templateBuilder.replaceElement(typeElement, varName, new TypeExpression(project, new PsiType[]{typeElement.getType()}), true); + + final Template template = templateBuilder.buildInlineTemplate(); + TemplateManager.getInstance(project).startTemplate(editor, template, false, null, new TemplateEditingAdapter() { + private String myNewType; + + @Override + public void beforeTemplateFinished(TemplateState state, Template template) { + final TextResult value = state.getVariableValue(varName); + myNewType = value != null ? value.getText() : ""; + final int segmentsCount = state.getSegmentsCount(); + final Document document = state.getEditor().getDocument(); + for (int i = 0; i < segmentsCount; i++) { + final TextRange segmentRange = state.getSegmentRange(i); + document.replaceString(segmentRange.getStartOffset(), segmentRange.getEndOffset(), oldTypeText); + } + } + + @Override + public void templateFinished(Template template, boolean brokenOff) { + if (!brokenOff) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); + try { + final PsiType targetParam = elementFactory.createTypeFromText(myNewType, aClass); + final TypeMigrationRules myRules = new TypeMigrationRules(((PsiAnonymousClass)aClass).getBaseClassType()); + final PsiSubstitutor substitutor = result.getSubstitutor().put(typeParameter, targetParam); + final PsiType targetClassType = elementFactory.createType(baseClass, substitutor); + myRules.setMigrationRootType(targetClassType); + myRules.setBoundScope(new LocalSearchScope(aClass)); + new TypeMigrationProcessor(project, ((PsiAnonymousClass)aClass).getBaseClassReference().getParameterList(), myRules).run(); + } + catch (IncorrectOperationException e) { + HintManager.getInstance().showErrorHint(editor, "Incorrect type"); + } + } + } + }); + } + } + } + + @Override + public boolean startInWriteAction() { + return true; + } +} |