blob: 16fc097bc6122560e31b3d1ce4220f2ce05a5f0f [file] [log] [blame]
/*
* 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.
* 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.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;
import com.intellij.featureStatistics.ProductivityFeatureNames;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.lang.LanguageRefactoringSupport;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
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.Key;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock;
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil;
import com.intellij.psi.scope.processor.VariablesProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.util.*;
import com.intellij.refactoring.*;
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.refactoring.listeners.RefactoringEventData;
import com.intellij.refactoring.listeners.RefactoringEventListener;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.FieldConflictsResolver;
import com.intellij.refactoring.util.RefactoringUIUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.occurrences.ExpressionOccurrenceManager;
import com.intellij.refactoring.util.occurrences.NotInSuperCallOccurrenceFilter;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author dsl
* Date: Nov 15, 2002
*/
public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceVariable.IntroduceVariableBase");
@NonNls private static final String PREFER_STATEMENTS_OPTION = "introduce.variable.prefer.statements";
@NonNls private static final String REFACTORING_ID = "refactoring.extractVariable";
protected static final String REFACTORING_NAME = RefactoringBundle.message("introduce.variable.title");
public static final Key<Boolean> NEED_PARENTHESIS = Key.create("NEED_PARENTHESIS");
public static SuggestedNameInfo getSuggestedName(@Nullable PsiType type, @NotNull final PsiExpression expression) {
return getSuggestedName(type, expression, expression);
}
public static SuggestedNameInfo getSuggestedName(@Nullable PsiType type,
@NotNull final PsiExpression expression,
final PsiElement anchor) {
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, anchor, true);
}
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, DataContext dataContext) {
final SelectionModel selectionModel = editor.getSelectionModel();
if (!selectionModel.hasSelection()) {
final int offset = editor.getCaretModel().getOffset();
final PsiElement[] statementsInRange = findStatementsAtOffset(editor, file, offset);
//try line selection
if (statementsInRange.length == 1 && selectLineAtCaret(offset, statementsInRange)) {
selectionModel.selectLineAtCaret();
final PsiExpression expressionInRange =
findExpressionInRange(project, file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
if (expressionInRange == null || getErrorMessage(expressionInRange) != null) {
selectionModel.removeSelection();
}
}
if (!selectionModel.hasSelection()) {
final List<PsiExpression> expressions = collectExpressions(file, editor, offset);
if (expressions.isEmpty()) {
selectionModel.selectLineAtCaret();
} else if (expressions.size() == 1) {
final TextRange textRange = expressions.get(0).getTextRange();
selectionModel.setSelection(textRange.getStartOffset(), textRange.getEndOffset());
}
else {
IntroduceTargetChooser.showChooser(editor, expressions,
new Pass<PsiExpression>(){
public void pass(final PsiExpression selectedValue) {
invoke(project, editor, file, selectedValue.getTextRange().getStartOffset(), selectedValue.getTextRange().getEndOffset());
}
},
new PsiExpressionTrimRenderer.RenderFunction(), "Expressions", preferredSelection(statementsInRange, expressions), ScopeHighlighter.NATURAL_RANGER);
return;
}
}
}
if (invoke(project, editor, file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) &&
LookupManager.getActiveLookup(editor) == null) {
selectionModel.removeSelection();
}
}
public static boolean selectLineAtCaret(int offset, PsiElement[] statementsInRange) {
return !PsiUtil.isStatement(statementsInRange[0]) ||
statementsInRange[0].getTextRange().getStartOffset() > offset ||
statementsInRange[0].getTextRange().getEndOffset() < offset ||
isPreferStatements();
}
public static int preferredSelection(PsiElement[] statementsInRange, List<PsiExpression> expressions) {
int selection;
if (statementsInRange.length == 1 &&
statementsInRange[0] instanceof PsiExpressionStatement &&
PsiUtilCore.hasErrorElementChild(statementsInRange[0])) {
selection = expressions.indexOf(((PsiExpressionStatement)statementsInRange[0]).getExpression());
} else {
PsiExpression expression = expressions.get(0);
if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() instanceof PsiLocalVariable) {
selection = 1;
}
else {
selection = -1;
}
}
return selection;
}
public static boolean isPreferStatements() {
return Boolean.valueOf(PropertiesComponent.getInstance().getOrInit(PREFER_STATEMENTS_OPTION, "false")).booleanValue() || Registry.is(PREFER_STATEMENTS_OPTION, false);
}
public static List<PsiExpression> collectExpressions(final PsiFile file,
final Editor editor,
final int offset) {
return collectExpressions(file, editor, offset, false);
}
public static List<PsiExpression> collectExpressions(final PsiFile file,
final Editor editor,
final int offset,
boolean acceptVoid) {
return collectExpressions(file, editor.getDocument(), offset, acceptVoid);
}
public static List<PsiExpression> collectExpressions(final PsiFile file,
final Document document,
final int offset,
boolean acceptVoid) {
CharSequence text = document.getCharsSequence();
int correctedOffset = offset;
int textLength = document.getTextLength();
if (offset >= textLength) {
correctedOffset = textLength - 1;
}
else if (!Character.isJavaIdentifierPart(text.charAt(offset))) {
correctedOffset--;
}
if (correctedOffset < 0) {
correctedOffset = offset;
}
else if (!Character.isJavaIdentifierPart(text.charAt(correctedOffset))) {
if (text.charAt(correctedOffset) == ';') {//initially caret on the end of line
correctedOffset--;
}
if (correctedOffset < 0 || text.charAt(correctedOffset) != ')') {
correctedOffset = offset;
}
}
final PsiElement elementAtCaret = file.findElementAt(correctedOffset);
final List<PsiExpression> expressions = new ArrayList<PsiExpression>();
/*for (PsiElement element : statementsInRange) {
if (element instanceof PsiExpressionStatement) {
final PsiExpression expression = ((PsiExpressionStatement)element).getExpression();
if (expression.getType() != PsiType.VOID) {
expressions.add(expression);
}
}
}*/
PsiExpression expression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class);
while (expression != null) {
if (!expressions.contains(expression) && !(expression instanceof PsiParenthesizedExpression) && !(expression instanceof PsiSuperExpression) &&
(acceptVoid || expression.getType() != PsiType.VOID)) {
if (expression instanceof PsiMethodReferenceExpression) {
expressions.add(expression);
}
else if (!(expression instanceof PsiAssignmentExpression)) {
if (!(expression instanceof PsiReferenceExpression)) {
expressions.add(expression);
}
else {
if (!(expression.getParent() instanceof PsiMethodCallExpression)) {
final PsiElement resolve = ((PsiReferenceExpression)expression).resolve();
if (!(resolve instanceof PsiClass) && !(resolve instanceof PsiPackage)) {
expressions.add(expression);
}
}
}
}
}
expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class);
}
return expressions;
}
public static PsiElement[] findStatementsAtOffset(final Editor editor, final PsiFile file, final int offset) {
final Document document = editor.getDocument();
final int lineNumber = document.getLineNumber(offset);
final int lineStart = document.getLineStartOffset(lineNumber);
final int lineEnd = document.getLineEndOffset(lineNumber);
return CodeInsightUtil.findStatementsInRange(file, lineStart, lineEnd);
}
private boolean invoke(final Project project, final Editor editor, PsiFile file, int startOffset, int endOffset) {
FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.REFACTORING_INTRODUCE_VARIABLE);
PsiDocumentManager.getInstance(project).commitAllDocuments();
return invokeImpl(project, findExpressionInRange(project, file, startOffset, endOffset), editor);
}
private static PsiExpression findExpressionInRange(Project project, PsiFile file, int startOffset, int endOffset) {
PsiExpression tempExpr = CodeInsightUtil.findExpressionInRange(file, startOffset, endOffset);
if (tempExpr == null) {
PsiElement[] statements = CodeInsightUtil.findStatementsInRange(file, startOffset, endOffset);
if (statements.length == 1) {
if (statements[0] instanceof PsiExpressionStatement) {
tempExpr = ((PsiExpressionStatement) statements[0]).getExpression();
} else if (statements[0] instanceof PsiReturnStatement) {
tempExpr = ((PsiReturnStatement)statements[0]).getReturnValue();
}
}
}
if (tempExpr == null) {
tempExpr = getSelectedExpression(project, file, startOffset, endOffset);
}
return tempExpr;
}
/**
* @return can return NotNull value although extraction will fail: reason could be retrieved from {@link #getErrorMessage(PsiExpression)}
*/
public static PsiExpression getSelectedExpression(final Project project, PsiFile file, int startOffset, int endOffset) {
final InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(project);
PsiElement elementAtStart = file.findElementAt(startOffset);
if (elementAtStart == null || elementAtStart instanceof PsiWhiteSpace || elementAtStart instanceof PsiComment) {
elementAtStart = PsiTreeUtil.skipSiblingsForward(elementAtStart, PsiWhiteSpace.class, PsiComment.class);
if (elementAtStart == null) {
if (injectedLanguageManager.isInjectedFragment(file)) {
return getSelectionFromInjectedHost(project, file, injectedLanguageManager, startOffset, endOffset);
} else {
return null;
}
}
startOffset = elementAtStart.getTextOffset();
}
PsiElement elementAtEnd = file.findElementAt(endOffset - 1);
if (elementAtEnd == null || elementAtEnd instanceof PsiWhiteSpace || elementAtEnd instanceof PsiComment) {
elementAtEnd = PsiTreeUtil.skipSiblingsBackward(elementAtEnd, PsiWhiteSpace.class, PsiComment.class);
if (elementAtEnd == null) return null;
endOffset = elementAtEnd.getTextRange().getEndOffset();
}
if (endOffset <= startOffset) return null;
PsiElement elementAt = PsiTreeUtil.findCommonParent(elementAtStart, elementAtEnd);
if (PsiTreeUtil.getParentOfType(elementAt, PsiExpression.class, false) == null) {
if (injectedLanguageManager.isInjectedFragment(file)) {
return getSelectionFromInjectedHost(project, file, injectedLanguageManager, startOffset, endOffset);
}
elementAt = null;
}
final PsiLiteralExpression literalExpression = PsiTreeUtil.getParentOfType(elementAt, PsiLiteralExpression.class);
final PsiLiteralExpression startLiteralExpression = PsiTreeUtil.getParentOfType(elementAtStart, PsiLiteralExpression.class);
final PsiLiteralExpression endLiteralExpression = PsiTreeUtil.getParentOfType(file.findElementAt(endOffset), PsiLiteralExpression.class);
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
String text = null;
PsiExpression tempExpr;
try {
text = file.getText().subSequence(startOffset, endOffset).toString();
String prefix = null;
String stripped = text;
if (startLiteralExpression != null) {
final int startExpressionOffset = startLiteralExpression.getTextOffset();
if (startOffset == startExpressionOffset) {
if (StringUtil.startsWithChar(text, '\"') || StringUtil.startsWithChar(text, '\'')) {
stripped = text.substring(1);
}
} else if (startOffset == startExpressionOffset + 1) {
text = "\"" + text;
} else if (startOffset > startExpressionOffset + 1){
prefix = "\" + ";
text = "\"" + text;
}
}
String suffix = null;
if (endLiteralExpression != null) {
final int endExpressionOffset = endLiteralExpression.getTextOffset() + endLiteralExpression.getTextLength();
if (endOffset == endExpressionOffset ) {
if (StringUtil.endsWithChar(stripped, '\"') || StringUtil.endsWithChar(stripped, '\'')) {
stripped = stripped.substring(0, stripped.length() - 1);
}
} else if (endOffset == endExpressionOffset - 1) {
text += "\"";
} else if (endOffset < endExpressionOffset - 1) {
suffix = " + \"";
text += "\"";
}
}
boolean primitive = false;
if (stripped.equals("true") || stripped.equals("false")) {
primitive = true;
}
else {
try {
Integer.parseInt(stripped);
primitive = true;
}
catch (NumberFormatException e1) {
//then not primitive
}
}
if (primitive) {
text = stripped;
}
if (literalExpression != null && text.equals(literalExpression.getText())) return literalExpression;
final PsiElement parent = literalExpression != null ? literalExpression : elementAt;
tempExpr = elementFactory.createExpressionFromText(text, parent);
final boolean [] hasErrors = new boolean[1];
final JavaRecursiveElementWalkingVisitor errorsVisitor = new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitElement(final PsiElement element) {
if (hasErrors[0]) {
return;
}
super.visitElement(element);
}
@Override
public void visitErrorElement(final PsiErrorElement element) {
hasErrors[0] = true;
}
};
tempExpr.accept(errorsVisitor);
if (hasErrors[0]) return null;
tempExpr.putUserData(ElementToWorkOn.PREFIX, prefix);
tempExpr.putUserData(ElementToWorkOn.SUFFIX, suffix);
final RangeMarker rangeMarker =
FileDocumentManager.getInstance().getDocument(file.getVirtualFile()).createRangeMarker(startOffset, endOffset);
tempExpr.putUserData(ElementToWorkOn.TEXT_RANGE, rangeMarker);
if (parent != null) {
tempExpr.putUserData(ElementToWorkOn.PARENT, parent);
}
else {
PsiErrorElement errorElement = elementAtStart instanceof PsiErrorElement
? (PsiErrorElement)elementAtStart
: PsiTreeUtil.getNextSiblingOfType(elementAtStart, PsiErrorElement.class);
if (errorElement == null) {
errorElement = PsiTreeUtil.getParentOfType(elementAtStart, PsiErrorElement.class);
}
if (errorElement == null) return null;
if (!(errorElement.getParent() instanceof PsiClass)) return null;
tempExpr.putUserData(ElementToWorkOn.PARENT, errorElement);
tempExpr.putUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK, Boolean.TRUE);
}
final String fakeInitializer = "intellijidearulezzz";
final int[] refIdx = new int[1];
final PsiExpression toBeExpression = createReplacement(fakeInitializer, project, prefix, suffix, parent, rangeMarker, refIdx);
toBeExpression.accept(errorsVisitor);
if (hasErrors[0]) return null;
if (literalExpression != null) {
PsiType type = toBeExpression.getType();
if (type != null && !type.equals(literalExpression.getType())) {
return null;
}
}
final PsiReferenceExpression refExpr = PsiTreeUtil.getParentOfType(toBeExpression.findElementAt(refIdx[0]), PsiReferenceExpression.class);
if (refExpr == null) return null;
if (toBeExpression == refExpr && refIdx[0] > 0) {
return null;
}
if (ReplaceExpressionUtil.isNeedParenthesis(refExpr.getNode(), tempExpr.getNode())) {
tempExpr.putCopyableUserData(NEED_PARENTHESIS, Boolean.TRUE);
return tempExpr;
}
}
catch (IncorrectOperationException e) {
if (elementAt instanceof PsiExpressionList) {
final PsiElement parent = elementAt.getParent();
return parent instanceof PsiCallExpression ? createArrayCreationExpression(text, startOffset, endOffset, (PsiCallExpression)parent) : null;
}
return null;
}
return tempExpr;
}
private static PsiExpression getSelectionFromInjectedHost(Project project,
PsiFile file,
InjectedLanguageManager injectedLanguageManager, int startOffset, int endOffset) {
final PsiLanguageInjectionHost injectionHost = injectedLanguageManager.getInjectionHost(file);
return getSelectedExpression(project, injectionHost.getContainingFile(), injectedLanguageManager.injectedToHost(file, startOffset), injectedLanguageManager.injectedToHost(file, endOffset));
}
@Nullable
public static String getErrorMessage(PsiExpression expr) {
final Boolean needParenthesis = expr.getCopyableUserData(NEED_PARENTHESIS);
if (needParenthesis != null && needParenthesis.booleanValue()) {
return "Extracting selected expression would change the semantic of the whole expression.";
}
return null;
}
private static PsiExpression createArrayCreationExpression(String text, int startOffset, int endOffset, PsiCallExpression parent) {
if (text == null || parent == null) return null;
final String[] varargsExpressions = text.split("s*,s*");
if (varargsExpressions.length > 1) {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(parent.getProject());
final JavaResolveResult resolveResult = parent.resolveMethodGenerics();
final PsiMethod psiMethod = (PsiMethod)resolveResult.getElement();
if (psiMethod == null || !psiMethod.isVarArgs()) return null;
final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
final PsiParameter varargParameter = parameters[parameters.length - 1];
final PsiType type = varargParameter.getType();
LOG.assertTrue(type instanceof PsiEllipsisType);
final PsiArrayType psiType = (PsiArrayType)((PsiEllipsisType)type).toArrayType();
final PsiExpression[] args = parent.getArgumentList().getExpressions();
final PsiSubstitutor psiSubstitutor = resolveResult.getSubstitutor();
if (args.length < parameters.length || startOffset < args[parameters.length - 1].getTextRange().getStartOffset()) return null;
final PsiFile containingFile = parent.getContainingFile();
PsiElement startElement = containingFile.findElementAt(startOffset);
while (startElement != null && startElement.getParent() != parent.getArgumentList()) {
startElement = startElement.getParent();
}
if (startElement == null || startOffset > startElement.getTextOffset()) return null;
PsiElement endElement = containingFile.findElementAt(endOffset - 1);
while (endElement != null && endElement.getParent() != parent.getArgumentList()) {
endElement = endElement.getParent();
}
if (endElement == null || endOffset < endElement.getTextRange().getEndOffset()) return null;
final PsiType componentType = TypeConversionUtil.erasure(psiSubstitutor.substitute(psiType.getComponentType()));
try {
final PsiExpression expressionFromText =
elementFactory.createExpressionFromText("new " + componentType.getCanonicalText() + "[]{" + text + "}", parent);
final RangeMarker rangeMarker =
FileDocumentManager.getInstance().getDocument(containingFile.getVirtualFile()).createRangeMarker(startOffset, endOffset);
expressionFromText.putUserData(ElementToWorkOn.TEXT_RANGE, rangeMarker);
expressionFromText.putUserData(ElementToWorkOn.PARENT, parent);
return expressionFromText;
}
catch (IncorrectOperationException e) {
return null;
}
}
return null;
}
protected boolean invokeImpl(final Project project, final PsiExpression expr,
final Editor editor) {
if (expr != null) {
final String errorMessage = getErrorMessage(expr);
if (errorMessage != null) {
showErrorMessage(project, editor, RefactoringBundle.getCannotRefactorMessage(errorMessage));
return false;
}
}
if (expr != null && expr.getParent() instanceof PsiExpressionStatement) {
FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.introduceVariable.incompleteStatement");
}
if (LOG.isDebugEnabled()) {
LOG.debug("expression:" + expr);
}
if (expr == null || !expr.isPhysical()) {
if (ReassignVariableUtil.reassign(editor)) return false;
if (expr == null) {
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("selected.block.should.represent.an.expression"));
showErrorMessage(project, editor, message);
return false;
}
}
final PsiType originalType = RefactoringUtil.getTypeByExpressionWithExpectedType(expr);
if (originalType == null || LambdaUtil.notInferredType(originalType)) {
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("unknown.expression.type"));
showErrorMessage(project, editor, message);
return false;
}
if (PsiType.VOID.equals(originalType)) {
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("selected.expression.has.void.type"));
showErrorMessage(project, editor, message);
return false;
}
final PsiElement physicalElement = expr.getUserData(ElementToWorkOn.PARENT);
final PsiElement anchorStatement = RefactoringUtil.getParentStatement(physicalElement != null ? physicalElement : expr, false);
if (anchorStatement == null) {
return parentStatementNotFound(project, editor);
}
if (checkAnchorBeforeThisOrSuper(project, editor, anchorStatement, REFACTORING_NAME, HelpID.INTRODUCE_VARIABLE)) return false;
final PsiElement tempContainer = anchorStatement.getParent();
if (!(tempContainer instanceof PsiCodeBlock) && !RefactoringUtil.isLoopOrIf(tempContainer) && (tempContainer.getParent() instanceof PsiLambdaExpression)) {
String message = RefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", REFACTORING_NAME);
showErrorMessage(project, editor, message);
return false;
}
if(!NotInSuperCallOccurrenceFilter.INSTANCE.isOK(expr)) {
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("cannot.introduce.variable.in.super.constructor.call"));
showErrorMessage(project, editor, message);
return false;
}
final PsiFile file = anchorStatement.getContainingFile();
LOG.assertTrue(file != null, "expr.getContainingFile() == null");
final PsiElement nameSuggestionContext = editor == null ? null : file.findElementAt(editor.getCaretModel().getOffset());
final RefactoringSupportProvider supportProvider = LanguageRefactoringSupport.INSTANCE.forLanguage(expr.getLanguage());
final boolean isInplaceAvailableOnDataContext =
supportProvider != null &&
editor.getSettings().isVariableInplaceRenameEnabled() &&
supportProvider.isInplaceIntroduceAvailable(expr, nameSuggestionContext) &&
(!ApplicationManager.getApplication().isUnitTestMode() || isInplaceAvailableInTestMode()) &&
!isInJspHolderMethod(expr);
if (isInplaceAvailableOnDataContext) {
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
checkInLoopCondition(expr, conflicts);
if (!conflicts.isEmpty()) {
showErrorMessage(project, editor, StringUtil.join(conflicts.values(), "<br>"));
return false;
}
}
final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, tempContainer);
final PsiExpression[] occurrences = occurrenceManager.getOccurrences();
final PsiElement anchorStatementIfAll = occurrenceManager.getAnchorStatementForAll();
final List<PsiExpression> nonWrite = new ArrayList<PsiExpression>();
boolean cantReplaceAll = false;
boolean cantReplaceAllButWrite = false;
for (PsiExpression occurrence : occurrences) {
if (!RefactoringUtil.isAssignmentLHS(occurrence)) {
nonWrite.add(occurrence);
} else if (isFinalVariableOnLHS(occurrence)) {
cantReplaceAll = true;
} else if (!nonWrite.isEmpty()){
cantReplaceAllButWrite = true;
cantReplaceAll = true;
}
}
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return false;
final LinkedHashMap<OccurrencesChooser.ReplaceChoice, List<PsiExpression>> occurrencesMap = ContainerUtil.newLinkedHashMap();
occurrencesMap.put(OccurrencesChooser.ReplaceChoice.NO, Collections.singletonList(expr));
final boolean hasWriteAccess = occurrences.length > nonWrite.size() && occurrences.length > 1;
if (hasWriteAccess && !cantReplaceAllButWrite) {
occurrencesMap.put(OccurrencesChooser.ReplaceChoice.NO_WRITE, nonWrite);
}
if (occurrences.length > 1 && !cantReplaceAll) {
occurrencesMap.put(OccurrencesChooser.ReplaceChoice.ALL, Arrays.asList(occurrences));
}
final boolean inFinalContext = occurrenceManager.isInFinalContext();
final InputValidator validator = new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurrenceManager);
final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, originalType, expr, occurrences);
final boolean[] wasSucceed = new boolean[]{true};
final Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() {
@Override
public void pass(final OccurrencesChooser.ReplaceChoice choice) {
final boolean allOccurences = choice == OccurrencesChooser.ReplaceChoice.ALL || choice == OccurrencesChooser.ReplaceChoice.NO_WRITE;
final Ref<SmartPsiElementPointer<PsiVariable>> variable = new Ref<SmartPsiElementPointer<PsiVariable>>();
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<RangeMarker> occurrenceMarkers = new ArrayList<RangeMarker>();
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 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() {
try {
ApplicationManager.getApplication().runWriteAction(runnable);
}
finally {
final RefactoringEventData afterData = new RefactoringEventData();
final SmartPsiElementPointer<PsiVariable> pointer = variable.get();
afterData.addElement(pointer != null ? pointer.getElement() : null);
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<String>(Arrays.asList(suggestedName.names)));
}
}
}
}, REFACTORING_NAME, null);
}
};
if (!isInplaceAvailableOnDataContext) {
callback.pass(null);
}
else {
OccurrencesChooser.<PsiExpression>simpleChooser(editor).showChooser(callback, occurrencesMap);
}
return wasSucceed[0];
}
protected PsiElement chooseAnchor(boolean allOccurences,
boolean hasWriteAccess,
List<PsiExpression> nonWrite,
PsiElement anchorStatementIfAll,
PsiElement anchorStatement) {
if (allOccurences) {
if (hasWriteAccess) {
return RefactoringUtil.getAnchorElementForMultipleExpressions(nonWrite.toArray(new PsiExpression[nonWrite.size()]), null);
}
else {
return anchorStatementIfAll;
}
}
else {
return anchorStatement;
}
}
protected boolean isInplaceAvailableInTestMode() {
return false;
}
private static ExpressionOccurrenceManager createOccurrenceManager(PsiExpression expr, PsiElement tempContainer) {
boolean skipForStatement = true;
final PsiForStatement forStatement = PsiTreeUtil.getParentOfType(expr, PsiForStatement.class);
if (forStatement != null) {
final VariablesProcessor variablesProcessor = new VariablesProcessor(false) {
@Override
protected boolean check(PsiVariable var, ResolveState state) {
return PsiTreeUtil.isAncestor(forStatement.getInitialization(), var, true);
}
};
PsiScopesUtil.treeWalkUp(variablesProcessor, expr, null);
skipForStatement = variablesProcessor.size() == 0;
}
PsiElement containerParent = tempContainer;
PsiElement lastScope = tempContainer;
while (true) {
if (containerParent instanceof PsiFile) break;
if (containerParent instanceof PsiMethod) break;
if (containerParent instanceof PsiLambdaExpression) break;
if (!skipForStatement && containerParent instanceof PsiForStatement) break;
containerParent = containerParent.getParent();
if (containerParent instanceof PsiCodeBlock) {
lastScope = containerParent;
}
}
return new ExpressionOccurrenceManager(expr, lastScope, NotInSuperCallOccurrenceFilter.INSTANCE);
}
private static boolean isInJspHolderMethod(PsiExpression expr) {
final PsiElement parent1 = expr.getParent();
if (parent1 == null) {
return false;
}
final PsiElement parent2 = parent1.getParent();
if (!(parent2 instanceof JspCodeBlock)) return false;
final PsiElement parent3 = parent2.getParent();
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<SmartPsiElementPointer<PsiVariable>> variable) {
final PsiElement container = anchorStatement.getParent();
PsiElement child = anchorStatement;
if (!RefactoringUtil.isLoopOrIf(container)) {
child = locateAnchor(child);
if (isFinalVariableOnLHS(expr)) {
child = child.getNextSibling();
}
}
final PsiElement anchor = child == null ? anchorStatement : child;
boolean tempDeleteSelf = false;
final boolean replaceSelf = settings.isReplaceLValues() || !RefactoringUtil.isAssignmentLHS(expr);
if (!RefactoringUtil.isLoopOrIf(container)) {
if (expr.getParent() instanceof PsiExpressionStatement && anchor.equals(anchorStatement)) {
PsiStatement statement = (PsiStatement) expr.getParent();
PsiElement parent = statement.getParent();
if (parent instanceof PsiCodeBlock ||
//fabrique
parent instanceof PsiCodeFragment) {
tempDeleteSelf = true;
}
}
tempDeleteSelf &= replaceSelf;
}
final boolean deleteSelf = tempDeleteSelf;
final int col = editor != null ? editor.getCaretModel().getLogicalPosition().column : 0;
final int line = editor != null ? editor.getCaretModel().getLogicalPosition().line : 0;
if (deleteSelf) {
if (editor != null) {
LogicalPosition pos = new LogicalPosition(line, col);
editor.getCaretModel().moveToLogicalPosition(pos);
}
}
final PsiCodeBlock newDeclarationScope = PsiTreeUtil.getParentOfType(container, PsiCodeBlock.class, false);
final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(settings.getEnteredName(), newDeclarationScope);
return new Runnable() {
public void run() {
try {
PsiStatement statement = null;
final boolean isInsideLoop = RefactoringUtil.isLoopOrIf(container);
if (!isInsideLoop && deleteSelf) {
statement = (PsiStatement) expr.getParent();
}
final PsiExpression expr1 = fieldConflictsResolver.fixInitializer(expr);
PsiExpression initializer = RefactoringUtil.unparenthesizeExpression(expr1);
final SmartTypePointer selectedType = SmartTypePointerManager.getInstance(project).createSmartTypePointer(
settings.getSelectedType());
if (expr1 instanceof PsiNewExpression) {
final PsiNewExpression newExpression = (PsiNewExpression)expr1;
if (newExpression.getArrayInitializer() != null) {
initializer = newExpression.getArrayInitializer();
}
initializer = replaceExplicitWithDiamondWhenApplicable(initializer, selectedType.getType());
}
PsiDeclarationStatement declaration = JavaPsiFacade.getInstance(project).getElementFactory()
.createVariableDeclarationStatement(settings.getEnteredName(), selectedType.getType(), initializer);
if (!isInsideLoop) {
declaration = addDeclaration(declaration, initializer);
LOG.assertTrue(expr1.isValid());
if (deleteSelf) { // never true
final PsiElement lastChild = statement.getLastChild();
if (lastChild instanceof PsiComment) { // keep trailing comment
declaration.addBefore(lastChild, null);
}
statement.delete();
if (editor != null) {
LogicalPosition pos = new LogicalPosition(line, col);
editor.getCaretModel().moveToLogicalPosition(pos);
editor.getCaretModel().moveToOffset(declaration.getTextRange().getEndOffset());
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
editor.getSelectionModel().removeSelection();
}
}
}
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;
if (occurrence.equals(expr)) {
occurrence = expr1;
}
if (occurrence != null) {
occurrence = RefactoringUtil.outermostParenthesizedExpression(occurrence);
}
if (settings.isReplaceLValues() || !RefactoringUtil.isAssignmentLHS(occurrence)) {
array.add(replace(occurrence, ref, project));
}
}
if (!deleteSelf && replaceSelf && expr1 instanceof PsiPolyadicExpression && expr1.isValid() && !expr1.isPhysical() ) {
array.add(replace(expr1, ref, project));
}
if (editor != null) {
final PsiElement[] replacedOccurences = PsiUtilCore.toPsiElementArray(array);
highlightReplacedOccurences(project, editor, replacedOccurences);
}
} else {
if (!deleteSelf && replaceSelf) {
replace(expr1, ref, project);
}
}
declaration = (PsiDeclarationStatement) RefactoringUtil.putStatementInLoopBody(declaration, container, anchorStatement);
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();
} catch (IncorrectOperationException e) {
LOG.error(e);
}
}
private PsiDeclarationStatement addDeclaration(PsiDeclarationStatement declaration, PsiExpression initializer) {
if (anchor instanceof PsiDeclarationStatement) {
final PsiElement[] declaredElements = ((PsiDeclarationStatement)anchor).getDeclaredElements();
if (declaredElements.length > 1) {
final int [] usedFirstVar = new int[] {-1};
initializer.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
final int i = ArrayUtilRt.find(declaredElements, expression.resolve());
if (i > -1) {
usedFirstVar[0] = Math.max(i, usedFirstVar[0]);
}
super.visitReferenceExpression(expression);
}
});
if (usedFirstVar[0] > -1) {
final PsiVariable psiVariable = (PsiVariable)declaredElements[usedFirstVar[0]];
psiVariable.normalizeDeclaration();
final PsiDeclarationStatement parDeclarationStatement = PsiTreeUtil.getParentOfType(psiVariable, PsiDeclarationStatement.class);
return (PsiDeclarationStatement)container.addAfter(declaration, parDeclarationStatement);
}
}
}
return (PsiDeclarationStatement) container.addBefore(declaration, anchor);
}
};
}
private static boolean isFinalVariableOnLHS(PsiExpression expr) {
if (expr instanceof PsiReferenceExpression && RefactoringUtil.isAssignmentLHS(expr)) {
final PsiElement resolve = ((PsiReferenceExpression)expr).resolve();
if (resolve instanceof PsiVariable &&
((PsiVariable)resolve).hasModifierProperty(PsiModifier.FINAL)) { //should be inserted after assignment
return true;
}
}
return false;
}
public static PsiExpression replaceExplicitWithDiamondWhenApplicable(final PsiExpression initializer,
final PsiType expectedType) {
if (initializer instanceof PsiNewExpression) {
final PsiNewExpression newExpression = (PsiNewExpression)initializer;
final PsiExpression tryToDetectDiamondNewExpr = ((PsiVariable)JavaPsiFacade.getElementFactory(initializer.getProject())
.createVariableDeclarationStatement("x", expectedType, initializer).getDeclaredElements()[0])
.getInitializer();
if (tryToDetectDiamondNewExpr instanceof PsiNewExpression &&
PsiDiamondTypeUtil.canCollapseToDiamond((PsiNewExpression)tryToDetectDiamondNewExpr,
(PsiNewExpression)tryToDetectDiamondNewExpr,
expectedType)) {
final PsiElement paramList = PsiDiamondTypeUtil
.replaceExplicitWithDiamond(newExpression.getClassOrAnonymousClassReference().getParameterList());
return PsiTreeUtil.getParentOfType(paramList, PsiNewExpression.class);
}
}
return initializer;
}
public static PsiElement replace(final PsiExpression expr1, final PsiExpression ref, final Project project)
throws IncorrectOperationException {
final PsiExpression expr2;
if (expr1 instanceof PsiArrayInitializerExpression &&
expr1.getParent() instanceof PsiNewExpression) {
expr2 = (PsiNewExpression) expr1.getParent();
} else {
expr2 = RefactoringUtil.outermostParenthesizedExpression(expr1);
}
if (expr2.isPhysical()) {
return expr2.replace(ref);
}
else {
final String prefix = expr1.getUserData(ElementToWorkOn.PREFIX);
final String suffix = expr1.getUserData(ElementToWorkOn.SUFFIX);
final PsiElement parent = expr1.getUserData(ElementToWorkOn.PARENT);
final RangeMarker rangeMarker = expr1.getUserData(ElementToWorkOn.TEXT_RANGE);
LOG.assertTrue(parent != null, expr1);
return parent.replace(createReplacement(ref.getText(), project, prefix, suffix, parent, rangeMarker, new int[1]));
}
}
private static PsiExpression createReplacement(final String refText, final Project project,
final String prefix,
final String suffix,
final PsiElement parent, final RangeMarker rangeMarker, int[] refIdx) {
String text = refText;
if (parent != null) {
final String allText = parent.getContainingFile().getText();
final TextRange parentRange = parent.getTextRange();
LOG.assertTrue(parentRange.getStartOffset() <= rangeMarker.getStartOffset(), parent + "; prefix:" + prefix + "; suffix:" + suffix);
String beg = allText.substring(parentRange.getStartOffset(), rangeMarker.getStartOffset());
if (StringUtil.stripQuotesAroundValue(beg).trim().length() == 0 && prefix == null) beg = "";
LOG.assertTrue(rangeMarker.getEndOffset() <= parentRange.getEndOffset(), parent + "; prefix:" + prefix + "; suffix:" + suffix);
String end = allText.substring(rangeMarker.getEndOffset(), parentRange.getEndOffset());
if (StringUtil.stripQuotesAroundValue(end).trim().length() == 0 && suffix == null) end = "";
final String start = beg + (prefix != null ? prefix : "");
refIdx[0] = start.length();
text = start + refText + (suffix != null ? suffix : "") + end;
}
return JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(text, parent);
}
private boolean parentStatementNotFound(final Project project, Editor editor) {
String message = RefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", REFACTORING_NAME);
showErrorMessage(project, editor, message);
return false;
}
protected boolean invokeImpl(Project project, PsiLocalVariable localVariable, Editor editor) {
throw new UnsupportedOperationException();
}
private static PsiElement locateAnchor(PsiElement child) {
while (child != null) {
PsiElement prev = child.getPrevSibling();
if (prev instanceof PsiStatement) break;
if (prev instanceof PsiJavaToken && ((PsiJavaToken)prev).getTokenType() == JavaTokenType.LBRACE) break;
child = prev;
}
while (child instanceof PsiWhiteSpace || child instanceof PsiComment) {
child = child.getNextSibling();
}
return child;
}
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);
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,
PsiElement anchor,
final OccurrencesChooser.ReplaceChoice replaceChoice) {
final boolean replaceAll =
replaceChoice == OccurrencesChooser.ReplaceChoice.ALL || replaceChoice == OccurrencesChooser.ReplaceChoice.NO_WRITE;
final SuggestedNameInfo suggestedName = getSuggestedName(typeSelectorManager.getDefaultType(), expr, anchor);
final String variableName = suggestedName.names.length > 0 ? suggestedName.names[0] : "";
final boolean declareFinal = replaceAll && declareFinalIfAll || !anyAssignmentLHS && createFinals(project);
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() {
final PsiType selectedType = typeSelectorManager.getTypeSelector().getSelectedType();
return selectedType != null ? selectedType : typeSelectorManager.getDefaultType();
}
@Override
public boolean isOK() {
return true;
}
};
}
public static boolean createFinals(Project project) {
final Boolean createFinals = JavaRefactoringSettings.getInstance().INTRODUCE_LOCAL_CREATE_FINALS;
return createFinals == null ? CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS : createFinals.booleanValue();
}
public static boolean checkAnchorBeforeThisOrSuper(final Project project,
final Editor editor,
final PsiElement tempAnchorElement,
final String refactoringName,
final String helpID) {
if (tempAnchorElement instanceof PsiExpressionStatement) {
PsiExpression enclosingExpr = ((PsiExpressionStatement)tempAnchorElement).getExpression();
if (enclosingExpr instanceof PsiMethodCallExpression) {
PsiMethod method = ((PsiMethodCallExpression)enclosingExpr).resolveMethod();
if (method != null && method.isConstructor()) {
//This is either 'this' or 'super', both must be the first in the respective contructor
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("invalid.expression.context"));
CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpID);
return true;
}
}
}
return false;
}
public interface Validator {
boolean isOK(IntroduceVariableSettings dialog);
}
public static void checkInLoopCondition(PsiExpression occurence, MultiMap<PsiElement, String> conflicts) {
final PsiElement loopForLoopCondition = RefactoringUtil.getLoopForLoopCondition(occurence);
if (loopForLoopCondition == null) return;
final List<PsiVariable> referencedVariables = RefactoringUtil.collectReferencedVariables(occurence);
final List<PsiVariable> modifiedInBody = new ArrayList<PsiVariable>();
for (PsiVariable psiVariable : referencedVariables) {
if (RefactoringUtil.isModifiedInScope(psiVariable, loopForLoopCondition)) {
modifiedInBody.add(psiVariable);
}
}
if (!modifiedInBody.isEmpty()) {
for (PsiVariable variable : modifiedInBody) {
final String message = RefactoringBundle.message("is.modified.in.loop.body", RefactoringUIUtil.getDescription(variable, false));
conflicts.putValue(variable, CommonRefactoringUtil.capitalize(message));
}
conflicts.putValue(occurence, RefactoringBundle.message("introducing.variable.may.break.code.logic"));
}
}
@Override
public AbstractInplaceIntroducer getInplaceIntroducer() {
return null;
}
}