inplace introduce variable

This commit is contained in:
anna
2010-10-15 17:09:31 +04:00
parent 850a856efe
commit 3ba50c2ca4
12 changed files with 369 additions and 109 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2010 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.
@@ -24,29 +24,35 @@
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.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.DataManager;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.colors.EditorColors;
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.Pass;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.*;
import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.IntroduceHandlerBase;
import com.intellij.refactoring.IntroduceTargetChooser;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.*;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler;
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.FieldConflictsResolver;
@@ -55,13 +61,12 @@ import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.occurences.ExpressionOccurenceManager;
import com.intellij.refactoring.util.occurences.NotInSuperCallOccurenceFilter;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public abstract class IntroduceVariableBase extends IntroduceHandlerBase implements RefactoringActionHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceVariable.IntroduceVariableBase");
@@ -69,6 +74,15 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
protected static String REFACTORING_NAME = RefactoringBundle.message("introduce.variable.title");
public static SuggestedNameInfo getSuggestedName(PsiType type, final PsiExpression expression) {
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject());
final SuggestedNameInfo nameInfo = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, expression, type);
final String[] strings = JavaCompletionUtil
.completeVariableNameForRefactoring(codeStyleManager, type, VariableKind.LOCAL_VARIABLE, nameInfo);
final SuggestedNameInfo.Delegate delegate = new SuggestedNameInfo.Delegate(strings, nameInfo);
return codeStyleManager.suggestUniqueVariableName(delegate, expression, true);
}
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, DataContext dataContext) {
final SelectionModel selectionModel = editor.getSelectionModel();
if (!selectionModel.hasSelection()) {
@@ -351,10 +365,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
return false;
}
final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
PsiType originalType = RefactoringUtil.getTypeByExpressionWithExpectedType(expr);
final PsiType originalType = RefactoringUtil.getTypeByExpressionWithExpectedType(expr);
if (originalType == null) {
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("unknown.expression.type"));
showErrorMessage(project, editor, message);
@@ -370,7 +382,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
final PsiElement physicalElement = expr.getUserData(ElementToWorkOn.PARENT);
PsiElement anchorStatement = RefactoringUtil.getParentStatement(physicalElement != null ? physicalElement : expr, false);
final PsiElement anchorStatement = RefactoringUtil.getParentStatement(physicalElement != null ? physicalElement : expr, false);
if (anchorStatement == null) {
return parentStatementNotFound(project, editor);
@@ -388,7 +400,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
}
}
PsiElement tempContainer = anchorStatement.getParent();
final PsiElement tempContainer = anchorStatement.getParent();
if (!(tempContainer instanceof PsiCodeBlock) && !isLoopOrIf(tempContainer)) {
String message = RefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", REFACTORING_NAME);
@@ -418,38 +430,66 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
}
}
ExpressionOccurenceManager occurenceManager = new ExpressionOccurenceManager(expr, lastScope,
final ExpressionOccurenceManager occurenceManager = new ExpressionOccurenceManager(expr, lastScope,
NotInSuperCallOccurenceFilter.INSTANCE);
final PsiExpression[] occurrences = occurenceManager.getOccurences();
final PsiElement anchorStatementIfAll = occurenceManager.getAnchorStatementForAll();
boolean declareFinalIfAll = occurenceManager.isInFinalContext();
final LinkedHashMap<OccurrencesChooser.ReplaceChoice, PsiExpression[]> occurrencesMap =
new LinkedHashMap<OccurrencesChooser.ReplaceChoice, PsiExpression[]>();
boolean anyAssignmentLHS = false;
for (PsiExpression occurrence : occurrences) {
if (RefactoringUtil.isAssignmentLHS(occurrence)) {
anyAssignmentLHS = true;
break;
final boolean hasWriteAccess = OccurrencesChooser.fillChoices(expr, occurrences, occurrencesMap);
final boolean isInplaceAvailableOnDataContext =
new VariableInplaceRenameHandler().isAvailableOnDataContext(DataManager.getInstance().getDataContext()) &&
!ApplicationManager.getApplication().isUnitTestMode();
final boolean inFinalContext = occurenceManager.isInFinalContext();
final InputValidator validator = new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurenceManager);
final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, originalType, expr, occurrences);
final Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() {
@Override
public void pass(OccurrencesChooser.ReplaceChoice choice) {
final Ref<SmartPsiElementPointer<PsiVariable>> variable = new Ref<SmartPsiElementPointer<PsiVariable>>();
final IntroduceVariableSettings settings =
getSettings(project, editor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, choice);
final Runnable runnable =
introduce(project, expr, editor, anchorStatement, tempContainer, occurrences, anchorStatementIfAll, settings, variable);
CommandProcessor.getInstance().executeCommand(
project,
new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(runnable);
if (isInplaceAvailableOnDataContext) {
PsiVariable elementToRename = variable.get().getElement();
if (elementToRename != null) {
new VariableInplaceRenamer(elementToRename, editor).performInplaceRename(false);
}
}
}
}, REFACTORING_NAME, null);
}
};
if (!isInplaceAvailableOnDataContext) {
callback.pass(null);
}
IntroduceVariableSettings settings = getSettings(project, editor, expr, occurrences, anyAssignmentLHS, declareFinalIfAll,
originalType,
new TypeSelectorManagerImpl(project, originalType, expr, occurrences),
new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurenceManager));
if (!settings.isOK()) {
return false;
else {
new OccurrencesChooser(editor).showChooser(callback, occurrencesMap);
}
return true;
}
final String variableName = settings.getEnteredName();
final PsiType type = settings.getSelectedType();
final boolean replaceAll = settings.isReplaceAllOccurrences();
final boolean replaceWrite = settings.isReplaceLValues();
final boolean declareFinal = replaceAll && declareFinalIfAll || settings.isDeclareFinal();
if (replaceAll) {
private static Runnable introduce(final Project project,
final PsiExpression expr,
final Editor editor,
PsiElement anchorStatement,
PsiElement tempContainer,
final PsiExpression[] occurrences,
PsiElement anchorStatementIfAll,
final IntroduceVariableSettings settings,
final Ref<SmartPsiElementPointer<PsiVariable>> variable) {
if (settings.isReplaceAllOccurrences()) {
anchorStatement = anchorStatementIfAll;
tempContainer = anchorStatement.getParent();
}
@@ -463,7 +503,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
final PsiElement anchor = child == null ? anchorStatement : child;
boolean tempDeleteSelf = false;
final boolean replaceSelf = replaceWrite || !RefactoringUtil.isAssignmentLHS(expr);
final boolean replaceSelf = settings.isReplaceLValues() || !RefactoringUtil.isAssignmentLHS(expr);
if (!isLoopOrIf(container)) {
if (expr.getParent() instanceof PsiExpressionStatement && anchor.equals(anchorStatement)) {
PsiStatement statement = (PsiStatement) expr.getParent();
@@ -489,10 +529,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
}
final PsiCodeBlock newDeclarationScope = PsiTreeUtil.getParentOfType(container, PsiCodeBlock.class, false);
final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(variableName, newDeclarationScope);
final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(settings.getEnteredName(), newDeclarationScope);
final PsiElement finalAnchorStatement = anchorStatement;
final Runnable runnable = new Runnable() {
return new Runnable() {
public void run() {
try {
PsiStatement statement = null;
@@ -500,6 +539,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
if (!isInsideLoop && deleteSelf) {
statement = (PsiStatement) expr.getParent();
}
final PsiExpression expr1 = fieldConflictsResolver.fixInitializer(expr);
PsiExpression initializer = RefactoringUtil.unparenthesizeExpression(expr1);
if (expr1 instanceof PsiNewExpression) {
@@ -508,7 +548,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
initializer = newExpression.getArrayInitializer();
}
}
PsiDeclarationStatement declaration = factory.createVariableDeclarationStatement(variableName, type, initializer);
PsiDeclarationStatement declaration = JavaPsiFacade.getInstance(project).getElementFactory()
.createVariableDeclarationStatement(settings.getEnteredName(), settings.getSelectedType(), initializer);
if (!isInsideLoop) {
declaration = (PsiDeclarationStatement) container.addBefore(declaration, anchor);
LOG.assertTrue(expr1.isValid());
@@ -528,8 +569,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
}
}
PsiExpression ref = factory.createExpressionFromText(variableName, null);
if (replaceAll) {
PsiExpression ref = JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(settings.getEnteredName(), null);
if (settings.isReplaceAllOccurrences()) {
ArrayList<PsiElement> array = new ArrayList<PsiElement>();
for (PsiExpression occurrence : occurrences) {
if (deleteSelf && occurrence.equals(expr)) continue;
@@ -539,7 +580,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
if (occurrence != null) {
occurrence = RefactoringUtil.outermostParenthesizedExpression(occurrence);
}
if (replaceWrite || !RefactoringUtil.isAssignmentLHS(occurrence)) {
if (settings.isReplaceLValues() || !RefactoringUtil.isAssignmentLHS(occurrence)) {
array.add(replace(occurrence, ref, project));
}
}
@@ -557,23 +598,14 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
declaration = (PsiDeclarationStatement) putStatementInLoopBody(declaration, container, finalAnchorStatement);
declaration = (PsiDeclarationStatement)JavaCodeStyleManager.getInstance(project).shortenClassReferences(declaration);
PsiVariable var = (PsiVariable) declaration.getDeclaredElements()[0];
PsiUtil.setModifierProperty(var, PsiModifier.FINAL, declareFinal);
PsiUtil.setModifierProperty(var, PsiModifier.FINAL, settings.isDeclareFinal());
variable.set(SmartPointerManager.getInstance(project).createLazyPointer(var));
fieldConflictsResolver.fix();
} catch (IncorrectOperationException e) {
LOG.error(e);
}
}
};
CommandProcessor.getInstance().executeCommand(
project,
new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(runnable);
}
}, REFACTORING_NAME, null);
return true;
}
public static PsiElement replace(final PsiExpression expr1, final PsiExpression ref, final Project project)
@@ -662,11 +694,15 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
return child;
}
protected abstract void highlightReplacedOccurences(Project project, Editor editor, PsiElement[] replacedOccurences);
protected abstract IntroduceVariableSettings getSettings(Project project, Editor editor, PsiExpression expr, final PsiElement[] occurrences,
boolean anyAssignmentLHS, final boolean declareFinalIfAll, final PsiType type,
TypeSelectorManagerImpl typeSelectorManager, InputValidator validator);
protected static void highlightReplacedOccurences(Project project, Editor editor, PsiElement[] replacedOccurences){
if (editor == null) return;
if (ApplicationManager.getApplication().isUnitTestMode()) return;
HighlightManager highlightManager = HighlightManager.getInstance(project);
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
highlightManager.addOccurrenceHighlights(editor, replacedOccurences, attributes, true, null);
WindowManager.getInstance().getStatusBar(project).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting"));
}
protected abstract void showErrorMessage(Project project, Editor editor, String message);
@@ -695,13 +731,65 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
return element instanceof PsiLoopStatement || element instanceof PsiIfStatement;
}
protected boolean reportConflicts(MultiMap<PsiElement,String> conflicts, Project project, IntroduceVariableSettings settings){
return false;
}
public IntroduceVariableSettings getSettings(Project project, Editor editor,
PsiExpression expr, PsiExpression[] occurrences,
final TypeSelectorManagerImpl typeSelectorManager,
boolean declareFinalIfAll,
boolean anyAssignmentLHS,
final InputValidator validator,
final OccurrencesChooser.ReplaceChoice replaceChoice) {
final SuggestedNameInfo suggestedName = getSuggestedName(typeSelectorManager.getDefaultType(), expr);
final String variableName = suggestedName.names[0];
final Boolean generateFinals = JavaRefactoringSettings.getInstance().INTRODUCE_LOCAL_CREATE_FINALS;
final boolean replaceAll =
replaceChoice == OccurrencesChooser.ReplaceChoice.ALL || replaceChoice == OccurrencesChooser.ReplaceChoice.NO_WRITE;
final boolean declareFinal =
!anyAssignmentLHS && (replaceAll &&
declareFinalIfAll || generateFinals == null ?
CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS :
generateFinals.booleanValue());
final boolean replaceWrite = anyAssignmentLHS && replaceChoice == OccurrencesChooser.ReplaceChoice.ALL;
return new IntroduceVariableSettings() {
@Override
public String getEnteredName() {
return variableName;
}
@Override
public boolean isReplaceAllOccurrences() {
return replaceAll;
}
@Override
public boolean isDeclareFinal() {
return declareFinal;
}
@Override
public boolean isReplaceLValues() {
return replaceWrite;
}
@Override
public PsiType getSelectedType() {
return typeSelectorManager.getDefaultType();
}
@Override
public boolean isOK() {
return true;
}
};
}
public interface Validator {
boolean isOK(IntroduceVariableSettings dialog);
}
protected abstract boolean reportConflicts(MultiMap<PsiElement,String> conflicts, final Project project, IntroduceVariableSettings dialog);
public static void checkInLoopCondition(PsiExpression occurence, MultiMap<PsiElement, String> conflicts) {
final PsiElement loopForLoopCondition = RefactoringUtil.getLoopForLoopCondition(occurence);
if (loopForLoopCondition == null) return;
@@ -721,6 +809,4 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
conflicts.putValue(occurence, RefactoringBundle.message("introducing.variable.may.break.code.logic"));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2010 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.
@@ -22,11 +22,10 @@ import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.ui.ConflictsDialog;
@@ -38,11 +37,19 @@ import java.util.ArrayList;
public class IntroduceVariableHandler extends IntroduceVariableBase {
protected IntroduceVariableSettings getSettings(final Project project, Editor editor, PsiExpression expr,
PsiElement[] occurrences, boolean anyAssignmentLHS,
boolean declareFinalIfAll, PsiType type,
TypeSelectorManagerImpl typeSelectorManager,
InputValidator validator) {
@Override
public IntroduceVariableSettings getSettings(Project project, Editor editor,
PsiExpression expr, PsiExpression[] occurrences,
TypeSelectorManagerImpl typeSelectorManager,
boolean declareFinalIfAll,
boolean anyAssignmentLHS,
final InputValidator validator,
final OccurrencesChooser.ReplaceChoice replaceChoice) {
if (replaceChoice != null) {
return super.getSettings(project, editor, expr, occurrences, typeSelectorManager, declareFinalIfAll, anyAssignmentLHS, validator,
replaceChoice);
}
ArrayList<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>();
HighlightManager highlightManager = null;
if (editor != null) {
@@ -78,15 +85,6 @@ public class IntroduceVariableHandler extends IntroduceVariableBase {
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INTRODUCE_VARIABLE);
}
protected void highlightReplacedOccurences(final Project project, Editor editor, final PsiElement[] replacedOccurences) {
if (editor == null) return;
HighlightManager highlightManager = HighlightManager.getInstance(project);
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
highlightManager.addOccurrenceHighlights(editor, replacedOccurences, attributes, true, null);
WindowManager.getInstance().getStatusBar(project).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting"));
}
protected boolean reportConflicts(final MultiMap<PsiElement,String> conflicts, final Project project, IntroduceVariableSettings dialog) {
ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts);
conflictsDialog.show();
@@ -0,0 +1,161 @@
/*
* Copyright 2000-2010 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.introduceVariable;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiExpression;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.ui.components.JBList;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* User: anna
* Date: 10/14/10
*/
public class OccurrencesChooser {
public static enum ReplaceChoice {
NO("Do not replace"), NO_WRITE("Replace all but write"), ALL("Replace all occurrences");
private String myDescription;
ReplaceChoice(String description) {
myDescription = description;
}
public String getDescription() {
return myDescription;
}
}
private final Set<RangeHighlighter> myRangeHighlighters = new HashSet<RangeHighlighter>();
private final Editor myEditor;
private final TextAttributes myAttributes;
public OccurrencesChooser(Editor editor) {
myEditor = editor;
myAttributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
}
public void showChooser(final Pass<ReplaceChoice> callback,
final Map<ReplaceChoice, PsiExpression[]> occurrencesMap) {
if (occurrencesMap.size() == 1) {
callback.pass(occurrencesMap.keySet().iterator().next());
return;
}
final DefaultListModel model = new DefaultListModel();
for (ReplaceChoice choice : occurrencesMap.keySet()) {
model.addElement(choice);
}
final JList list = new JBList(model);
list.setCellRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(final JList list,
final Object value,
final int index,
final boolean isSelected,
final boolean cellHasFocus) {
final Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
final ReplaceChoice choices = (ReplaceChoice)value;
if (choices != null) {
setText(choices.getDescription());
}
return rendererComponent;
}
});
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(final ListSelectionEvent e) {
final ReplaceChoice value = (ReplaceChoice)list.getSelectedValue();
if (value == null) return;
dropHighlighters();
final MarkupModel markupModel = myEditor.getMarkupModel();
final PsiExpression[] psiExpressions = occurrencesMap.get(value);
for (PsiExpression psiExpression : psiExpressions) {
final TextRange textRange = psiExpression.getTextRange();
final RangeHighlighter rangeHighlighter = markupModel.addRangeHighlighter(
textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.SELECTION - 1, myAttributes,
HighlighterTargetArea.EXACT_RANGE);
myRangeHighlighters.add(rangeHighlighter);
}
}
});
JBPopupFactory.getInstance().createListPopupBuilder(list)
.setTitle("Multiple occurrences found")
.setMovable(false)
.setResizable(false)
.setRequestFocus(true)
.setItemChoosenCallback(new Runnable() {
public void run() {
callback.pass((ReplaceChoice)list.getSelectedValue());
}
})
.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
dropHighlighters();
}
})
.createPopup().showInBestPositionFor(myEditor);
}
/**
* @return true if write usages found
*/
static boolean fillChoices(final PsiExpression expr,
final PsiExpression[] occurrences,
final LinkedHashMap<ReplaceChoice, PsiExpression[]> occurrencesMap) {
occurrencesMap.put(ReplaceChoice.NO, new PsiExpression[]{expr});
final List<PsiExpression> nonWrite = new ArrayList<PsiExpression>();
for (PsiExpression occurrence : occurrences) {
if (!RefactoringUtil.isAssignmentLHS(occurrence)) {
nonWrite.add(occurrence);
}
}
final boolean hasWriteAccess = occurrences.length > nonWrite.size() && occurrences.length > 1;
if (hasWriteAccess) {
occurrencesMap.put(ReplaceChoice.NO_WRITE, nonWrite.toArray(new PsiExpression[nonWrite.size()]));
}
if (occurrences.length > 1) {
occurrencesMap.put(ReplaceChoice.ALL, occurrences);
}
return hasWriteAccess;
}
private void dropHighlighters() {
final MarkupModel markupModel = myEditor.getMarkupModel();
for (RangeHighlighter highlight : myRangeHighlighters) {
markupModel.removeHighlighter(highlight);
}
myRangeHighlighters.clear();
}
}
@@ -71,6 +71,8 @@ class JavaResolveSnapshot extends ResolveSnapshotProvider.ResolveSnapshot {
if (referent instanceof PsiReferenceExpression && referee instanceof PsiField) {
PsiReferenceExpression ref = ((PsiReferenceExpression) referent);
if (!ref.isQualified() && hidingLocalName.equals(ref.getReferenceName())) {
final PsiElement newlyResolved = ref.resolve();
if (referee.getManager().areElementsEquivalent(newlyResolved, referee)) return;
PsiClass refereeClass = ((PsiField) referee).getContainingClass();
PsiClass referentClass = PsiTreeUtil.getParentOfType(referent, PsiClass.class);
if (refereeClass != null && referentClass != null &&
@@ -1,6 +1,6 @@
class Test {
int myI;
void foo(int i){
this.myI = i;
myI = i;
}
}
@@ -11,6 +11,7 @@ import com.intellij.psi.PsiType;
import com.intellij.refactoring.introduceVariable.InputValidator;
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
import com.intellij.refactoring.introduceVariable.IntroduceVariableSettings;
import com.intellij.refactoring.introduceVariable.OccurrencesChooser;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.testFramework.LightCodeInsightTestCase;
import com.intellij.util.containers.MultiMap;
@@ -225,17 +226,17 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
public void testSiblingInnerClassType() throws Exception {
doTest(new MockIntroduceVariableHandler("vari", true, false, false, "A.B"){
@Override
protected IntroduceVariableSettings getSettings(Project project,
Editor editor,
PsiExpression expr,
PsiElement[] occurrences,
boolean anyAssignmentLHS,
boolean declareFinalIfAll,
PsiType type,
TypeSelectorManagerImpl typeSelectorManager,
InputValidator validator) {
public IntroduceVariableSettings getSettings(Project project, Editor editor,
PsiExpression expr, PsiExpression[] occurrences,
TypeSelectorManagerImpl typeSelectorManager,
boolean declareFinalIfAll,
boolean anyAssignmentLHS,
InputValidator validator,
final OccurrencesChooser.ReplaceChoice replaceChoice) {
final PsiType type = typeSelectorManager.getDefaultType();
Assert.assertTrue(type.getPresentableText(), type.getPresentableText().equals("B"));
return super.getSettings(project, editor, expr, occurrences, anyAssignmentLHS, declareFinalIfAll, type, typeSelectorManager, validator);
return super.getSettings(project, editor, expr, occurrences, typeSelectorManager, declareFinalIfAll, anyAssignmentLHS,
validator, replaceChoice);
}
});
}
@@ -2,12 +2,11 @@ package com.intellij.refactoring;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import com.intellij.refactoring.introduceVariable.InputValidator;
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
import com.intellij.refactoring.introduceVariable.IntroduceVariableSettings;
import com.intellij.refactoring.introduceVariable.OccurrencesChooser;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.util.containers.MultiMap;
import junit.framework.Assert;
@@ -36,9 +35,14 @@ class MockIntroduceVariableHandler extends IntroduceVariableBase {
@Override
protected IntroduceVariableSettings getSettings(Project project, Editor editor, PsiExpression expr, final PsiElement[] occurrences,
boolean anyAssignmentLHS, final boolean declareFinalIfAll, final PsiType type,
TypeSelectorManagerImpl typeSelectorManager, InputValidator validator) {
public IntroduceVariableSettings getSettings(Project project, Editor editor,
PsiExpression expr, final PsiExpression[] occurrences,
TypeSelectorManagerImpl typeSelectorManager,
final boolean declareFinalIfAll,
boolean anyAssignmentLHS,
InputValidator validator,
final OccurrencesChooser.ReplaceChoice replaceChoice) {
final PsiType type = typeSelectorManager.getDefaultType();
Assert.assertTrue(type.getCanonicalText(), type.equalsToText(myExpectedTypeCanonicalName));
IntroduceVariableSettings introduceVariableSettings = new IntroduceVariableSettings() {
@Override
@@ -85,11 +89,6 @@ class MockIntroduceVariableHandler extends IntroduceVariableBase {
throw new RuntimeException("Error message:" + message);
}
@Override
protected void highlightReplacedOccurences(final Project project, Editor editor, final PsiElement[] replacedOccurences) {
}
@Override
protected boolean reportConflicts(final MultiMap<PsiElement,String> conflicts, final Project project, IntroduceVariableSettings dialog) {
return false;
@@ -73,7 +73,7 @@ public class RenameLocalTest extends LightCodeInsightTestCase {
ResolveSnapshotProvider resolveSnapshotProvider = VariableInplaceRenamer.INSTANCE.forLanguage(getFile().getLanguage());
assertNotNull(resolveSnapshotProvider);
final ResolveSnapshotProvider.ResolveSnapshot snapshot = resolveSnapshotProvider.createSnapshot(methodScope);
final ResolveSnapshotProvider.ResolveSnapshot snapshot = resolveSnapshotProvider.createSnapshot(methodScope.getBody());
assertNotNull(snapshot);
final int offset = element.getTextOffset();
@@ -97,9 +97,17 @@ public class VariableInplaceRenameHandler implements RenameHandler {
@Nullable
public VariableInplaceRenamer doRename(final PsiElement elementToRename, final Editor editor, final DataContext dataContext) {
return doRename(elementToRename, editor, dataContext, true);
}
@Nullable
public VariableInplaceRenamer doRename(final PsiElement elementToRename,
final Editor editor,
final DataContext dataContext,
boolean processTextOccurrences) {
VariableInplaceRenamer renamer = createRenamer(elementToRename, editor);
boolean startedRename = renamer == null ? false : renamer.performInplaceRename();
boolean startedRename = renamer == null ? false : renamer.performInplaceRename(processTextOccurrences);
if (!startedRename) {
try {
@@ -94,6 +94,10 @@ public class VariableInplaceRenamer {
}
public boolean performInplaceRename() {
return performInplaceRename(true);
}
public boolean performInplaceRename(boolean processTextOccurrences) {
if (InjectedLanguageUtil.isInInjectedLanguagePrefixSuffix(myElementToRename)) {
return false;
}
@@ -146,7 +150,8 @@ public class VariableInplaceRenamer {
}
String stringToSearch = myElementToRename.getName();
if (stringToSearch != null &&
if (processTextOccurrences &&
stringToSearch != null &&
!TextOccurrencesUtil.processUsagesInStringsAndComments(myElementToRename, stringToSearch, true, new PairProcessor<PsiElement, TextRange>() {
public boolean process(PsiElement psiElement, TextRange textRange) {
return false;