From 57a097f90cbe290c91011fe17f00a937d7f81b8a Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 17 Nov 2014 12:08:51 +0100 Subject: [PATCH] introduce variable: common api (IDEA-94609; IDEA-125286; IDEA-131965; IDEA-131930) --- .../InplaceIntroduceConstantPopup.java | 2 +- .../InplaceIntroduceFieldPopup.java | 2 +- .../InplaceIntroduceParameterPopup.java | 2 +- .../IntroduceVariableBase.java | 164 ++++----- .../JavaVariableInplaceIntroducer.java | 330 ++++++++++-------- .../allIncomplete.java | 6 + .../allIncomplete_after.java | 6 + .../allInsertFinal.java | 11 + .../allInsertFinal_after.java | 12 + .../inplaceIntroduceVariable/cast.java | 5 + .../castToObject.java | 5 + .../castToObject_after.java | 6 + .../inplaceIntroduceVariable/cast_after.java | 6 + .../escapePosition.java | 5 + .../escapePositionIfTyped.java | 5 + .../escapePositionIfTyped_after.java | 5 + .../escapePosition_after.java | 5 + .../fromExpression.java | 5 + .../fromExpression_after.java | 6 + .../fromParenthesis.java | 5 + .../fromParenthesis_after.java | 5 + .../inplaceIntroduceVariable/noWritable.java | 7 + .../noWritable_after.java | 8 + .../inplaceIntroduceVariable/ranges.java | 9 + .../ranges_after.java | 10 + .../inplaceIntroduceVariable/stopEditing.java | 5 + .../stopEditing_after.java | 8 + .../inplaceIntroduceVariable/writable.java | 7 + .../writable_after.java | 8 + .../ReturnNonExportedArray.after.java | 2 +- .../AbstractJavaInplaceIntroduceTest.java | 6 +- .../InplaceIntroduceVariableTest.java | 250 +++++++++++++ .../inplace/AbstractInplaceIntroducer.java | 50 +-- .../rename/inplace/InplaceRefactoring.java | 9 +- .../AbstractInplaceIntroduceTest.java | 11 +- 35 files changed, 725 insertions(+), 263 deletions(-) create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable_after.java create mode 100644 java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java index 98645dca001e..ac2c06c28f0f 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java @@ -230,7 +230,7 @@ public class InplaceIntroduceConstantPopup extends AbstractInplaceIntroduceField @Override protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) { - return super.startsOnTheSameElement(handler, element) && handler instanceof IntroduceConstantHandler; + return handler instanceof IntroduceConstantHandler && super.startsOnTheSameElement(handler, element); } @Override diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java index 11f2d4a64079..1ad65a6b1b44 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java @@ -172,7 +172,7 @@ public class InplaceIntroduceFieldPopup extends AbstractInplaceIntroduceFieldPop @Override protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) { - return super.startsOnTheSameElement(handler, element) && handler instanceof IntroduceFieldHandler; + return handler instanceof IntroduceFieldHandler && super.startsOnTheSameElement(handler, element); } @Override diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index 44b0d09dac09..f36212e505eb 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -174,7 +174,7 @@ public class InplaceIntroduceParameterPopup extends AbstractJavaInplaceIntroduce @Override protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) { - return super.startsOnTheSameElement(handler, element) && handler instanceof IntroduceParameterHandler; + return handler instanceof IntroduceParameterHandler && super.startsOnTheSameElement(handler, element); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index ca51d31a50c9..572221b8cf78 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -18,7 +18,6 @@ package com.intellij.refactoring.introduceVariable; import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.highlighting.HighlightManager; -import com.intellij.codeInsight.intention.impl.TypeExpression; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.unwrap.ScopeHighlighter; import com.intellij.featureStatistics.FeatureUsageTracker; @@ -37,10 +36,7 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pass; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.WindowManager; @@ -77,6 +73,7 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import java.util.*; @@ -91,6 +88,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { protected static final String REFACTORING_NAME = RefactoringBundle.message("introduce.variable.title"); public static final Key NEED_PARENTHESIS = Key.create("NEED_PARENTHESIS"); + private JavaVariableInplaceIntroducer myInplaceIntroducer; public static SuggestedNameInfo getSuggestedName(@Nullable PsiType type, @NotNull final PsiExpression expression) { return getSuggestedName(type, expression, expression); @@ -645,76 +643,74 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { final Pass callback = new Pass() { @Override public void pass(final OccurrencesChooser.ReplaceChoice choice) { - final boolean allOccurences = choice == OccurrencesChooser.ReplaceChoice.ALL || choice == OccurrencesChooser.ReplaceChoice.NO_WRITE; - final Ref> variable = new Ref>(); - - final Editor topLevelEditor; - if (!InjectedLanguageManager.getInstance(project).isInjectedFragment(anchorStatement.getContainingFile())) { - topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(editor); - } else { - topLevelEditor = editor; - } - - final IntroduceVariableSettings settings; - final PsiElement chosenAnchor; if (choice != null) { - chosenAnchor = chooseAnchor(allOccurences, choice == OccurrencesChooser.ReplaceChoice.NO_WRITE, nonWrite, anchorStatementIfAll, anchorStatement); - settings = getSettings(project, topLevelEditor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, chosenAnchor, choice); - } - else { - settings = getSettings(project, topLevelEditor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, anchorStatement, choice); - chosenAnchor = chooseAnchor(settings.isReplaceAllOccurrences(), hasWriteAccess, nonWrite, anchorStatementIfAll, anchorStatement); - } - if (!settings.isOK()) { - wasSucceed[0] = false; - return; - } - typeSelectorManager.setAllOccurrences(allOccurences); - final TypeExpression expression = new TypeExpression(project, allOccurences ? typeSelectorManager.getTypesForAll() : typeSelectorManager.getTypesForOne()); - final RangeMarker exprMarker = topLevelEditor.getDocument().createRangeMarker(expr.getTextRange()); - final SuggestedNameInfo suggestedName = getSuggestedName(settings.getSelectedType(), expr, chosenAnchor); - final List occurrenceMarkers = new ArrayList(); - final boolean noWrite = choice == OccurrencesChooser.ReplaceChoice.NO_WRITE; - for (PsiExpression occurrence : occurrences) { - if (allOccurences || (noWrite && !PsiUtil.isAccessedForWriting(occurrence))) { - occurrenceMarkers.add(topLevelEditor.getDocument().createRangeMarker(occurrence.getTextRange())); + final boolean replaceAll = choice == OccurrencesChooser.ReplaceChoice.ALL || choice == OccurrencesChooser.ReplaceChoice.NO_WRITE; + typeSelectorManager.setAllOccurrences(replaceAll); + + final PsiElement chosenAnchor = + chooseAnchor(replaceAll, choice == OccurrencesChooser.ReplaceChoice.NO_WRITE, nonWrite, anchorStatementIfAll, anchorStatement); + final IntroduceVariableSettings settings = + getSettings(project, editor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, chosenAnchor, choice); + + final boolean cantChangeFinalModifier = (hasWriteAccess || inFinalContext) && choice == OccurrencesChooser.ReplaceChoice.ALL; + + final boolean noWrite = choice == OccurrencesChooser.ReplaceChoice.NO_WRITE; + final List allOccurrences = new ArrayList(); + for (PsiExpression occurrence : occurrences) { + if (expr.equals(occurrence) && expr.getParent() instanceof PsiExpressionStatement) continue; + if (choice == OccurrencesChooser.ReplaceChoice.ALL || (noWrite && !PsiUtil.isAccessedForWriting(occurrence)) || expr.equals(occurrence)) { + allOccurrences.add(occurrence); + } + } + myInplaceIntroducer = new JavaVariableInplaceIntroducer(project, + settings, + chosenAnchor, + editor, expr, cantChangeFinalModifier, + allOccurrences.toArray(new PsiExpression[allOccurrences.size()]), + typeSelectorManager, + REFACTORING_NAME); + if (myInplaceIntroducer.startInplaceIntroduceTemplate()) { + return; } } - final RefactoringEventData beforeData = new RefactoringEventData(); - beforeData.addElement(expr); - project.getMessageBus() - .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringStarted(REFACTORING_ID, beforeData); - final String expressionText = expr.getText(); - final Runnable runnable = introduce(project, expr, topLevelEditor, chosenAnchor, occurrences, settings, variable); + CommandProcessor.getInstance().executeCommand( project, new Runnable() { public void run() { + final Editor topLevelEditor ; + if (!InjectedLanguageManager.getInstance(project).isInjectedFragment(anchorStatement.getContainingFile())) { + topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(editor); + } else { + topLevelEditor = editor; + } + + PsiVariable variable = null; try { - ApplicationManager.getApplication().runWriteAction(runnable); + final IntroduceVariableSettings settings = + getSettings(project, topLevelEditor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, anchorStatement, choice); + if (!settings.isOK()) { + wasSucceed[0] = false; + return; + } + + final RefactoringEventData beforeData = new RefactoringEventData(); + beforeData.addElement(expr); + project.getMessageBus() + .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringStarted(REFACTORING_ID, beforeData); + + final PsiElement chosenAnchor = + chooseAnchor(settings.isReplaceAllOccurrences(), hasWriteAccess, nonWrite, anchorStatementIfAll, anchorStatement); + + variable = ApplicationManager.getApplication().runWriteAction( + introduce(project, expr, topLevelEditor, chosenAnchor, occurrences, settings)); } finally { final RefactoringEventData afterData = new RefactoringEventData(); - final SmartPsiElementPointer pointer = variable.get(); - afterData.addElement(pointer != null ? pointer.getElement() : null); + afterData.addElement(variable); project.getMessageBus() .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringDone(REFACTORING_ID, afterData); } - - if (isInplaceAvailableOnDataContext) { - final PsiVariable elementToRename = variable.get().getElement(); - if (elementToRename != null) { - topLevelEditor.getCaretModel().moveToOffset(elementToRename.getTextOffset()); - final boolean cantChangeFinalModifier = (hasWriteAccess || inFinalContext) && choice == OccurrencesChooser.ReplaceChoice.ALL; - final JavaVariableInplaceIntroducer renamer = - new JavaVariableInplaceIntroducer(project, expression, topLevelEditor, elementToRename, cantChangeFinalModifier, - typeSelectorManager.getTypesForAll().length > 1, exprMarker, occurrenceMarkers, - REFACTORING_NAME); - renamer.initInitialText(expressionText); - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(topLevelEditor.getDocument()); - renamer.performInplaceRefactoring(new LinkedHashSet(Arrays.asList(suggestedName.names))); - } - } } }, REFACTORING_NAME, null); } @@ -724,16 +720,25 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { callback.pass(null); } else { - OccurrencesChooser.simpleChooser(editor).showChooser(callback, occurrencesMap); + OccurrencesChooser.ReplaceChoice choice = getOccurrencesChoice(); + if (choice != null) { + callback.pass(choice); + } else { + OccurrencesChooser.simpleChooser(editor).showChooser(callback, occurrencesMap); + } } return wasSucceed[0]; } + + protected OccurrencesChooser.ReplaceChoice getOccurrencesChoice() { + return null; + } - protected PsiElement chooseAnchor(boolean allOccurences, - boolean hasWriteAccess, - List nonWrite, - PsiElement anchorStatementIfAll, - PsiElement anchorStatement) { + protected static PsiElement chooseAnchor(boolean allOccurences, + boolean hasWriteAccess, + List nonWrite, + PsiElement anchorStatementIfAll, + PsiElement anchorStatement) { if (allOccurences) { if (hasWriteAccess) { return RefactoringUtil.getAnchorElementForMultipleExpressions(nonWrite.toArray(new PsiExpression[nonWrite.size()]), null); @@ -792,13 +797,12 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { return parent3 instanceof JspHolderMethod; } - private static Runnable introduce(final Project project, - final PsiExpression expr, - final Editor editor, - final PsiElement anchorStatement, - final PsiExpression[] occurrences, - final IntroduceVariableSettings settings, - final Ref> variable) { + public static Computable introduce(final Project project, + final PsiExpression expr, + final Editor editor, + final PsiElement anchorStatement, + final PsiExpression[] occurrences, + final IntroduceVariableSettings settings) { final PsiElement container = anchorStatement.getParent(); PsiElement child = anchorStatement; if (!RefactoringUtil.isLoopOrIf(container)) { @@ -837,8 +841,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { final PsiCodeBlock newDeclarationScope = PsiTreeUtil.getParentOfType(container, PsiCodeBlock.class, false); final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(settings.getEnteredName(), newDeclarationScope); - return new Runnable() { - public void run() { + return new Computable() { + @Override + public PsiVariable compute() { try { PsiStatement statement = null; final boolean isInsideLoop = RefactoringUtil.isLoopOrIf(container); @@ -913,11 +918,12 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { declaration = (PsiDeclarationStatement)JavaCodeStyleManager.getInstance(project).shortenClassReferences(declaration); PsiVariable var = (PsiVariable) declaration.getDeclaredElements()[0]; PsiUtil.setModifierProperty(var, PsiModifier.FINAL, settings.isDeclareFinal()); - variable.set(SmartPointerManager.getInstance(project).createSmartPsiElementPointer(var)); fieldConflictsResolver.fix(); + return var; } catch (IncorrectOperationException e) { LOG.error(e); } + return null; } private PsiDeclarationStatement addDeclaration(PsiDeclarationStatement declaration, PsiExpression initializer) { @@ -1165,6 +1171,6 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { @Override public AbstractInplaceIntroducer getInplaceIntroducer() { - return null; + return myInplaceIntroducer; } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java index f9e88de162cf..438009068cb9 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -21,7 +21,6 @@ import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.command.impl.StartMarkAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; @@ -30,87 +29,70 @@ import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.vfs.ReadonlyStatusHandler; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.scope.processor.VariablesProcessor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.introduce.inplace.InplaceVariableIntroducer; +import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.introduceParameter.AbstractJavaInplaceIntroducer; import com.intellij.refactoring.rename.ResolveSnapshotProvider; import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.ui.NonFocusableCheckBox; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; import java.util.List; /** * User: anna * Date: 12/8/10 */ -public class JavaVariableInplaceIntroducer extends InplaceVariableIntroducer { - protected final Project myProject; - private final SmartPsiElementPointer myPointer; +public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer { + + private SmartPsiElementPointer myPointer; private JCheckBox myCanBeFinalCb; - + private IntroduceVariableSettings mySettings; + private SmartPsiElementPointer myChosenAnchor; private final boolean myCantChangeFinalModifier; - private final String myTitle; - private String myExpressionText; - protected final SmartTypePointer myDefaultType; - protected final TypeExpression myExpression; - + private boolean myHasTypeSuggestion; private ResolveSnapshotProvider.ResolveSnapshot myConflictResolver; + private TypeExpression myExpression; + private boolean myReplaceSelf; + private boolean myDeleteSelf = true; public JavaVariableInplaceIntroducer(final Project project, - final TypeExpression expression, - final Editor editor, - @NotNull final PsiVariable elementToRename, + IntroduceVariableSettings settings, PsiElement chosenAnchor, final Editor editor, + final PsiExpression expr, final boolean cantChangeFinalModifier, - final boolean hasTypeSuggestion, - final RangeMarker exprMarker, - final List occurrenceMarkers, + final PsiExpression[] occurrences, + final TypeSelectorManagerImpl selectorManager, final String title) { - super(elementToRename, editor, project, title, new PsiExpression[0], null); - myProject = project; + super(project, editor, RefactoringUtil.outermostParenthesizedExpression(expr), null, occurrences, selectorManager, title); + mySettings = settings; + myChosenAnchor = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(chosenAnchor); myCantChangeFinalModifier = cantChangeFinalModifier; + myHasTypeSuggestion = selectorManager.getTypesForAll().length > 1; myTitle = title; - setExprMarker(exprMarker); - setOccurrenceMarkers(occurrenceMarkers); - final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(elementToRename, PsiDeclarationStatement.class); - myPointer = declarationStatement != null ? SmartPointerManager.getInstance(project).createSmartPsiElementPointer(declarationStatement) : null; - editor.putUserData(ReassignVariableUtil.DECLARATION_KEY, myPointer); - if (occurrenceMarkers != null) { - final ArrayList rangeMarkers = new ArrayList(occurrenceMarkers); - rangeMarkers.add(exprMarker); - editor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, - rangeMarkers.toArray(new RangeMarker[rangeMarkers.size()])); - } - myExpression = expression; - final PsiType defaultType = elementToRename.getType(); - myDefaultType = SmartTypePointerManager.getInstance(project).createSmartTypePointer(defaultType); - setAdvertisementText(getAdvertisementText(declarationStatement, defaultType, hasTypeSuggestion)); - } + myExpression = new TypeExpression(myProject, isReplaceAllOccurrences() + ? myTypeSelectorManager.getTypesForAll() + : myTypeSelectorManager.getTypesForOne()); - public void initInitialText(String text) { - myExpressionText = text; - } - - @Override - protected StartMarkAction startRename() throws StartMarkAction.AlreadyStartedException { - return StartMarkAction.start(myEditor, myProject, getCommandName()); + final List rangeMarkers = getOccurrenceMarkers(); + editor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, + rangeMarkers.toArray(new RangeMarker[rangeMarkers.size()])); + myReplaceSelf = myExpr.getParent() instanceof PsiExpressionStatement; } @Override @@ -122,7 +104,7 @@ public class JavaVariableInplaceIntroducer extends InplaceVariableIntroducer 0 && vars[0] instanceof PsiVariable) { - final PsiFile containingFile = element.getContainingFile(); - //todo pull up method restore state - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - final RangeMarker exprMarker = getExprMarker(); - if (exprMarker != null) { - myExpr = AbstractJavaInplaceIntroducer.restoreExpression(containingFile, (PsiVariable)vars[0], elementFactory, exprMarker, myExpressionText); - if (myExpr != null && myExpr.isPhysical()) { - myExprMarker = createMarker(myExpr); - } - } - List markers = getOccurrenceMarkers(); - for (RangeMarker occurrenceMarker : markers) { - if (getExprMarker() != null && occurrenceMarker.getStartOffset() == getExprMarker().getStartOffset() && myExpr != null) { - continue; - } - AbstractJavaInplaceIntroducer - .restoreExpression(containingFile, (PsiVariable)vars[0], elementFactory, occurrenceMarker, myExpressionText); - } - final PsiExpression initializer = ((PsiVariable)vars[0]).getInitializer(); - if (initializer != null && Comparing.strEqual(initializer.getText(), myExpressionText) && myExpr == null) { - element.replace(JavaPsiFacade.getInstance(myProject).getElementFactory().createStatementFromText(myExpressionText, element)); - } else { - element.delete(); - } - } - } - } - }); - } - } - } - finally { - myEditor.putUserData(ReassignVariableUtil.DECLARATION_KEY, null); - for (RangeMarker occurrenceMarker : getOccurrenceMarkers()) { - occurrenceMarker.dispose(); - } - myEditor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, null); - if (getExprMarker() != null) getExprMarker().dispose(); + @Override + protected void restoreState(PsiVariable psiField) { + if (myDeleteSelf) return; + super.restoreState(psiField); + } + + @Override + protected boolean ensureValid() { + final PsiVariable variable = getVariable(); + return variable != null && isIdentifier(getInputName(), variable.getLanguage()); + } + + @Override + protected void performCleanup() { + super.performCleanup(); + super.restoreState(getVariable()); + } + + @Override + protected void deleteTemplateField(PsiVariable variable) { + if (!myDeleteSelf) return; + if (myReplaceSelf) { + variable.replace(variable.getInitializer()); + } else { + super.deleteTemplateField(variable); } } + @Override + protected void performIntroduce() { + final PsiVariable psiVariable = getVariable(); + if (psiVariable == null) { + return; + } + + TypeSelectorManagerImpl.typeSelected(psiVariable.getType(), myTypeSelectorManager.getDefaultType()); + if (myCanBeFinalCb != null) { + JavaRefactoringSettings.getInstance().INTRODUCE_LOCAL_CREATE_FINALS = psiVariable.hasModifierProperty(PsiModifier.FINAL); + } + + final Document document = myEditor.getDocument(); + LOG.assertTrue(psiVariable.isValid()); + adjustLine(psiVariable, document); + + int startOffset = getExprMarker() != null && getExprMarker().isValid() ? getExprMarker().getStartOffset() : psiVariable.getTextOffset(); + final PsiFile file = psiVariable.getContainingFile(); + final PsiReference referenceAt = file.findReferenceAt(startOffset); + if (referenceAt != null && referenceAt.resolve() instanceof PsiVariable) { + startOffset = referenceAt.getElement().getTextRange().getEndOffset(); + } + else { + final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(psiVariable, PsiDeclarationStatement.class); + if (declarationStatement != null) { + startOffset = declarationStatement.getTextRange().getEndOffset(); + } + } + + myEditor.getCaretModel().moveToOffset(startOffset); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + if (psiVariable.getInitializer() != null) { + appendTypeCasts(getOccurrenceMarkers(), file, myProject, psiVariable); + } + if (myConflictResolver != null && myInsertedName != null && isIdentifier(myInsertedName, psiVariable.getLanguage())) { + myConflictResolver.apply(psiVariable.getName()); + } + } + }); + } + + @Override + public boolean isReplaceAllOccurrences() { + return mySettings.isReplaceAllOccurrences(); + } + + @Override + public void setReplaceAllOccurrences(boolean allOccurrences) {} + + @Override + protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) { + return handler instanceof IntroduceVariableHandler && super.startsOnTheSameElement(handler, element); + } @Nullable protected JComponent getComponent() { @@ -265,8 +240,27 @@ public class JavaVariableInplaceIntroducer extends InplaceVariableIntroducer> stringUsages) { + if (isReplaceAllOccurrences()) { + for (PsiExpression expression : getOccurrences()) { + LOG.assertTrue(expression.isValid(), expression.getText()); + stringUsages.add(Pair.create(expression, new TextRange(0, expression.getTextLength()))); + } + } else if (getExpr() != null && !myReplaceSelf) { + final PsiExpression expr = getExpr(); + LOG.assertTrue(expr.isValid(), expr.getText()); + stringUsages.add(Pair.create(expr, new TextRange(0, expr.getTextLength()))); + } } private static void appendTypeCasts(List occurrenceMarkers, @@ -353,21 +347,49 @@ public class JavaVariableInplaceIntroducer extends InplaceVariableIntroducer 0) { - return "Press " + shortcuts[0] + " to change type"; + @Override + protected int getCaretOffset() { + final PsiVariable variable = getVariable(); + if (variable != null) { + final PsiIdentifier identifier = variable.getNameIdentifier(); + if (identifier != null) { + return identifier.getTextOffset(); } } - return null; + return super.getCaretOffset(); + } + + @Override + protected String[] suggestNames(PsiType defaultType, String propName) { + return IntroduceVariableBase.getSuggestedName(defaultType, myExpr).names; + } + + @Override + protected VariableKind getVariableKind() { + return VariableKind.LOCAL_VARIABLE; } } diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete.java new file mode 100644 index 000000000000..377da56e3975 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete.java @@ -0,0 +1,6 @@ +class C { + { + new C(); + new C(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete_after.java new file mode 100644 index 000000000000..f83b8e61cd52 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allIncomplete_after.java @@ -0,0 +1,6 @@ +class C { + { + C c = new C(); + c; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal.java new file mode 100644 index 000000000000..476e9111cdfb --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal.java @@ -0,0 +1,11 @@ +class C { + { + C c = new C(); + Runnable r = new Runnable() { + @Override + public void run() { + new C(); + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal_after.java new file mode 100644 index 000000000000..c6f2df805826 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/allInsertFinal_after.java @@ -0,0 +1,12 @@ +class C { + { + final C c1 = new C(); + C c = c1; + Runnable r = new Runnable() { + @Override + public void run() { + c1; + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast.java new file mode 100644 index 000000000000..f175eb2b1b32 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject.java new file mode 100644 index 000000000000..f175eb2b1b32 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject_after.java new file mode 100644 index 000000000000..0e98b27791c3 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/castToObject_after.java @@ -0,0 +1,6 @@ +class C { + { + Object c1 = new C(); + C c = (C) c1; + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast_after.java new file mode 100644 index 000000000000..04af17ef8d89 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/cast_after.java @@ -0,0 +1,6 @@ +class C { + { + Integer c1 = (Integer) new C(); + C c = (C) c1; + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition.java new file mode 100644 index 000000000000..f175eb2b1b32 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped.java new file mode 100644 index 000000000000..f175eb2b1b32 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped_after.java new file mode 100644 index 000000000000..2cbdef758fe1 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePositionIfTyped_after.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition_after.java new file mode 100644 index 000000000000..2cbdef758fe1 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/escapePosition_after.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression.java new file mode 100644 index 000000000000..ea322fae5609 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression_after.java new file mode 100644 index 000000000000..f9a85d873dd3 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromExpression_after.java @@ -0,0 +1,6 @@ +class C { + { + C expr = new C(); + C c = expr; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis.java new file mode 100644 index 000000000000..5cdaaed4c679 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis.java @@ -0,0 +1,5 @@ +class C { + { + (new C()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis_after.java new file mode 100644 index 000000000000..eaf079348a53 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/fromParenthesis_after.java @@ -0,0 +1,5 @@ +class C { + { + C expr = new C(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable.java new file mode 100644 index 000000000000..f577e27bde64 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable.java @@ -0,0 +1,7 @@ +class C { + { + int[] a = new int[1]; + a[1] = 42; + System.out.println(a[1]); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable_after.java new file mode 100644 index 000000000000..803af2c8f1da --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/noWritable_after.java @@ -0,0 +1,8 @@ +class C { + { + int[] a = new int[1]; + a[1] = 42; + int x = a[1]; + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges.java new file mode 100644 index 000000000000..52c72d38f322 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges.java @@ -0,0 +1,9 @@ +class Bar {} +class Foo { + static Bar bar; +} +class C { + { + Bar b = Foo.bar; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges_after.java new file mode 100644 index 000000000000..9c92767441f5 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/ranges_after.java @@ -0,0 +1,10 @@ +class Bar {} +class Foo { + static Bar bar; +} +class C { + { + Bar expr = Foo.bar; + Bar b = expr; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing.java new file mode 100644 index 000000000000..ea322fae5609 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing.java @@ -0,0 +1,5 @@ +class C { + { + C c = new C(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing_after.java new file mode 100644 index 000000000000..26a73045f173 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/stopEditing_after.java @@ -0,0 +1,8 @@ +class C { + { + C + + c1 = new C(); + C c = c1; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable.java new file mode 100644 index 000000000000..f577e27bde64 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable.java @@ -0,0 +1,7 @@ +class C { + { + int[] a = new int[1]; + a[1] = 42; + System.out.println(a[1]); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable_after.java new file mode 100644 index 000000000000..66a0280705f0 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceVariable/writable_after.java @@ -0,0 +1,8 @@ +class C { + { + int[] a = new int[1]; + int x = a[1]; + x = 42; + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/ReturnNonExportedArray.after.java b/java/java-tests/testData/refactoring/introduceVariable/ReturnNonExportedArray.after.java index ebd5a17ad231..bcf896651037 100644 --- a/java/java-tests/testData/refactoring/introduceVariable/ReturnNonExportedArray.after.java +++ b/java/java-tests/testData/refactoring/introduceVariable/ReturnNonExportedArray.after.java @@ -3,6 +3,6 @@ import java.io.File; class Test { java.io.File[] get() {return null;} { - File[] files = get(); + File[] i = get(); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/AbstractJavaInplaceIntroduceTest.java b/java/java-tests/testSrc/com/intellij/refactoring/AbstractJavaInplaceIntroduceTest.java index 4f2cb602af67..9cd5d069c875 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/AbstractJavaInplaceIntroduceTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/AbstractJavaInplaceIntroduceTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -72,6 +72,10 @@ public abstract class AbstractJavaInplaceIntroduceTest extends AbstractInplaceIn @Override protected AbstractInplaceIntroducer invokeRefactoring() { final MyIntroduceHandler introduceHandler = createIntroduceHandler(); + return invokeRefactoring(introduceHandler); + } + + protected AbstractInplaceIntroducer invokeRefactoring(MyIntroduceHandler introduceHandler) { final PsiExpression expression = getExpressionFromEditor(); if (expression != null) { introduceHandler.invokeImpl(LightPlatformTestCase.getProject(), expression, getEditor()); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java new file mode 100644 index 000000000000..6e75fbb2bdd8 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceVariableTest.java @@ -0,0 +1,250 @@ +/* + * Copyright 2000-2014 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 com.intellij.refactoring; + +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pass; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.PsiLocalVariable; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer; +import com.intellij.refactoring.introduce.inplace.OccurrencesChooser; +import com.intellij.refactoring.introduceVariable.IntroduceVariableHandler; +import com.intellij.testFramework.MapDataContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTest { + + @Nullable + @Override + protected PsiExpression getExpressionFromEditor() { + final PsiExpression expression = super.getExpressionFromEditor(); + if (expression != null) { + return expression; + } + final PsiExpression expr = PsiTreeUtil.getParentOfType(getFile().findElementAt(getEditor().getCaretModel().getOffset()), PsiExpression.class); + return expr instanceof PsiLiteralExpression ? expr : null; + } + + public void testFromExpression() throws Exception { + doTest(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) { + type("expr"); + } + }); + } + + public void testRanges() throws Exception { + doTest(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) { + type("expr"); + } + }); + } + + public void testFromParenthesis() throws Exception { + doTest(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) { + type("expr"); + } + }); + } + + public void testCast() throws Exception { + doTestTypeChange("Integer"); + } + + public void testCastToObject() throws Exception { + doTestTypeChange("Object"); + } + + public void testEscapePosition() { + doTestStopEditing(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer introducer) { + invokeEditorAction(IdeActions.ACTION_EDITOR_ESCAPE); + invokeEditorAction(IdeActions.ACTION_EDITOR_ESCAPE); + } + }); + } + + public void testEscapePositionIfTyped() { + doTestStopEditing(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer introducer) { + type("fooBar"); + invokeEditorAction(IdeActions.ACTION_EDITOR_ESCAPE); + } + }); + } + + public void testWritable() throws Exception { + doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL); + } + + public void testNoWritable() throws Exception { + doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.NO_WRITE); + } + + public void testAllInsertFinal() throws Exception { + doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL); + } + + public void testAllIncomplete() throws Exception { + doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL); + } + + public void testStopEditing() { + doTestStopEditing(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer introducer) { + invokeEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_LEFT); + invokeEditorAction(IdeActions.ACTION_EDITOR_ENTER); + invokeEditorAction(IdeActions.ACTION_EDITOR_ENTER); + } + }); + } + + private void doTestStopEditing(Pass pass) { + String name = getTestName(true); + configureByFile(getBasePath() + name + getExtension()); + final boolean enabled = getEditor().getSettings().isVariableInplaceRenameEnabled(); + try { + TemplateManagerImpl.setTemplateTesting(getProject(), getTestRootDisposable()); + getEditor().getSettings().setVariableInplaceRenameEnabled(true); + + final AbstractInplaceIntroducer introducer = invokeRefactoring(); + pass.pass(introducer); + checkResultByFile(getBasePath() + name + "_after" + getExtension()); + } + finally { + TemplateState state = TemplateManagerImpl.getTemplateState(getEditor()); + if (state != null) { + state.gotoEnd(true); + } + getEditor().getSettings().setVariableInplaceRenameEnabled(enabled); + } + } + + private void doTestTypeChange(final String newType) { + final Pass typeChanger = new Pass() { + @Override + public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) { + type(newType); + } + }; + String name = getTestName(true); + configureByFile(getBasePath() + name + getExtension()); + final boolean enabled = getEditor().getSettings().isVariableInplaceRenameEnabled(); + try { + TemplateManagerImpl.setTemplateTesting(getProject(), getTestRootDisposable()); + getEditor().getSettings().setVariableInplaceRenameEnabled(true); + + final AbstractInplaceIntroducer introducer = invokeRefactoring(); + TemplateState state = TemplateManagerImpl.getTemplateState(getEditor()); + assert state != null; + state.previousTab(); + typeChanger.pass(introducer); + state.gotoEnd(false); + checkResultByFile(getBasePath() + name + "_after" + getExtension()); + } + finally { + getEditor().getSettings().setVariableInplaceRenameEnabled(enabled); + } + } + + private void doTestReplaceChoice(OccurrencesChooser.ReplaceChoice choice) { + doTestReplaceChoice(choice, null); + } + + private void doTestReplaceChoice(OccurrencesChooser.ReplaceChoice choice, Pass pass) { + String name = getTestName(true); + configureByFile(getBasePath() + name + getExtension()); + final boolean enabled = getEditor().getSettings().isVariableInplaceRenameEnabled(); + try { + TemplateManagerImpl.setTemplateTesting(getProject(), getTestRootDisposable()); + getEditor().getSettings().setVariableInplaceRenameEnabled(true); + + MyIntroduceHandler handler = createIntroduceHandler(); + ((MyIntroduceVariableHandler)handler).setChoice(choice); + final AbstractInplaceIntroducer introducer = invokeRefactoring(handler); + if (pass != null) { + pass.pass(introducer); + } + TemplateState state = TemplateManagerImpl.getTemplateState(getEditor()); + assert state != null; + state.gotoEnd(false); + checkResultByFile(getBasePath() + name + "_after" + getExtension()); + } + finally { + getEditor().getSettings().setVariableInplaceRenameEnabled(enabled); + } + } + + private static void invokeEditorAction(String actionId) { + EditorActionManager.getInstance().getActionHandler(actionId) + .execute(getEditor(), getEditor().getCaretModel().getCurrentCaret(), new MapDataContext()); + } + + + @Override + protected String getBasePath() { + return "/refactoring/inplaceIntroduceVariable/"; + } + + @Override + protected MyIntroduceHandler createIntroduceHandler() { + return new MyIntroduceVariableHandler(); + } + + public static class MyIntroduceVariableHandler extends IntroduceVariableHandler implements MyIntroduceHandler { + private OccurrencesChooser.ReplaceChoice myChoice = null; + + public void setChoice(OccurrencesChooser.ReplaceChoice choice) { + myChoice = choice; + } + + @Override + public boolean invokeImpl(Project project, @NotNull PsiExpression selectedExpr, Editor editor) { + return super.invokeImpl(project, selectedExpr, editor); + } + + @Override + public boolean invokeImpl(Project project, PsiLocalVariable localVariable, Editor editor) { + return super.invokeImpl(project, localVariable, editor); + } + + @Override + protected OccurrencesChooser.ReplaceChoice getOccurrencesChoice() { + return myChoice; + } + + @Override + protected boolean isInplaceAvailableInTestMode() { + return true; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java index d16183c7d069..b8063e1edbde 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -473,10 +473,8 @@ public abstract class AbstractInplaceIntroducer pass) { String name = getTestName(true); configureByFile(getBasePath() + name + getExtension()); final boolean enabled = getEditor().getSettings().isVariableInplaceRenameEnabled(); @@ -37,7 +41,10 @@ public abstract class AbstractInplaceIntroduceTest extends LightPlatformCodeInsi TemplateManagerImpl.setTemplateTesting(getProject(), getTestRootDisposable()); getEditor().getSettings().setVariableInplaceRenameEnabled(true); - invokeRefactoring(); + final AbstractInplaceIntroducer introducer = invokeRefactoring(); + if (pass != null) { + pass.pass(introducer); + } TemplateState state = TemplateManagerImpl.getTemplateState(getEditor()); assert state != null; state.gotoEnd(true);