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 a6f499f28ecc..e4158eb5f8fc 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -28,8 +28,11 @@ import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.highlighting.HighlightManager; import com.intellij.codeInsight.intention.impl.TypeExpression; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.template.*; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TextExpression; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.util.PropertiesComponent; import com.intellij.lang.LanguageRefactoringSupport; @@ -49,6 +52,8 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; import com.intellij.psi.codeStyle.*; +import com.intellij.psi.impl.PsiVariableEx; +import com.intellij.psi.impl.java.stubs.PsiModifierListStub; import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -487,26 +492,37 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme editor.putUserData(ReassignVariableUtil.DECLARATION_KEY, declarationStatement); editor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, occurrenceMarkers.toArray(new RangeMarker[occurrenceMarkers.size()])); + final boolean cantChangeFinalModifier = hasWriteAccess || (inFinalContext && choice == OccurrencesChooser.ReplaceChoice.ALL); final VariableInplaceRenamer renamer = new VariableInplaceRenamer(elementToRename, editor){ @Override protected void addAdditionalVariables(TemplateBuilderImpl builder) { final PsiTypeElement typeElement = elementToRename.getTypeElement(); builder.replaceElement(typeElement, "Variable_Type", - ReassignVariableUtil.createExpression(expression, typeElement.getText()), false, true); + ReassignVariableUtil.createExpression(expression, typeElement.getText(), !cantChangeFinalModifier), false, true); + if (!cantChangeFinalModifier) { + builder.replaceElement(elementToRename.getModifierList(), "_FINAL_", new FinalExpression(project), false, true); + } } }; renamer.setAdvertisementText( - ReassignVariableUtil.getAdvertisementText(editor, declarationStatement, elementToRename.getType(), typeSelectorManager.getTypesForAll())); + ReassignVariableUtil.getAdvertisementText(editor, declarationStatement, elementToRename.getType(), typeSelectorManager.getTypesForAll(), !cantChangeFinalModifier)); renamer.performInplaceRename(false, new LinkedHashSet(Arrays.asList(suggestedName.names)), new Consumer() { @Override public void consume(Boolean apply) { if (apply) { + final Document document = editor.getDocument(); + final PsiVariable psiVariable = + PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PsiVariable.class); + if (psiVariable != null) { + JavaRefactoringSettings.getInstance().INTRODUCE_LOCAL_CREATE_FINALS = psiVariable.hasModifierProperty(PsiModifier.FINAL); + FinalExpression.adjustLine(psiVariable, document); + } int startOffset = exprMarker.getStartOffset(); final PsiReference referenceAt = file.findReferenceAt(startOffset); if (referenceAt != null && referenceAt.resolve() instanceof PsiLocalVariable) { startOffset = referenceAt.getElement().getTextRange().getEndOffset(); } else { - startOffset = editor.getDocument().getLineEndOffset(editor.getDocument().getLineNumber(startOffset)); + startOffset = document.getLineEndOffset(document.getLineNumber(startOffset)); } editor.getCaretModel().moveToOffset(startOffset); typeSelectorManager.typeSelected(ReassignVariableUtil.getVariableType(declarationStatement)); @@ -803,8 +819,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme replaceChoice == OccurrencesChooser.ReplaceChoice.ALL || replaceChoice == OccurrencesChooser.ReplaceChoice.NO_WRITE; final boolean declareFinal = !anyAssignmentLHS && (replaceAll && - declareFinalIfAll || - CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS); + declareFinalIfAll || createFinals(project)); final boolean replaceWrite = anyAssignmentLHS && replaceChoice == OccurrencesChooser.ReplaceChoice.ALL; return new IntroduceVariableSettings() { @Override @@ -840,6 +855,11 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme }; } + private 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 interface Validator { boolean isOK(IntroduceVariableSettings dialog); } @@ -863,4 +883,40 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme conflicts.putValue(occurence, RefactoringBundle.message("introducing.variable.may.break.code.logic")); } } + + private static class FinalExpression extends Expression { + private final Project myProject; + + public FinalExpression(Project project) { + myProject = project; + } + + @Override + public Result calculateResult(ExpressionContext context) { + return new TextResult(createFinals(myProject) ? PsiKeyword.FINAL : ""); + } + + @Override + public Result calculateQuickResult(ExpressionContext context) { + return calculateResult(context); + } + + @Override + public LookupElement[] calculateLookupItems(ExpressionContext context) { + LookupElement[] lookupElements = new LookupElement[2]; + lookupElements[0] = LookupElementBuilder.create(""); + lookupElements[1] = LookupElementBuilder.create(PsiModifier.FINAL + " "); + return lookupElements; + } + + public static void adjustLine(final PsiVariable psiVariable, final Document document) { + final int modifierListOffset = psiVariable.getTextRange().getStartOffset(); + final int varLineNumber = document.getLineNumber(modifierListOffset); + ApplicationManager.getApplication().runWriteAction(new Runnable() { //adjust line indent if final was inserted and then deleted + public void run() { + CodeStyleManager.getInstance(psiVariable.getProject()).adjustLineIndent(document, document.getLineStartOffset(varLineNumber)); + } + }); + } + } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java index a812ec211c41..f3c1f4b9006d 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java @@ -174,7 +174,7 @@ public class ReassignVariableUtil { } @Nullable - static String getAdvertisementText(Editor editor, PsiDeclarationStatement declaration, PsiType type, PsiType[] typesForAll) { + static String getAdvertisementText(Editor editor, PsiDeclarationStatement declaration, PsiType type, PsiType[] typesForAll, boolean canAdjustFinal) { final VariablesProcessor processor = findVariablesOfType(editor, declaration, type); final Keymap keymap = KeymapManager.getInstance().getActiveKeymap(); if (processor.size() > 0) { @@ -189,10 +189,21 @@ public class ReassignVariableUtil { return "Press " + shortcuts[0] + " to change type"; } } + return adjustFinalText(canAdjustFinal); + } + + @Nullable + private static String adjustFinalText(boolean canBeFinalAdjusted) { + if (canBeFinalAdjusted) { + final Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts("PreviousTemplateVariable"); + if (shortcuts.length > 0) { + return "Press " + shortcuts[0] + " to adjust final modifier"; + } + } return null; } - public static Expression createExpression(final TypeExpression expression, final String defaultType) { + public static Expression createExpression(final TypeExpression expression, final String defaultType, final boolean canBeFinalAdjusted) { return new Expression() { @Override public com.intellij.codeInsight.template.Result calculateResult(ExpressionContext context) { @@ -208,6 +219,11 @@ public class ReassignVariableUtil { public LookupElement[] calculateLookupItems(ExpressionContext context) { return expression.calculateLookupItems(context); } + + @Override + public String getAdvertisingText() { + return adjustFinalText(canBeFinalAdjusted); + } }; } }