From 55b9d207fcef755250accce6d3184be95090c4bc Mon Sep 17 00:00:00 2001 From: UNV Date: Tue, 9 Dec 2025 03:54:30 +0300 Subject: [PATCH] Localizing refactoring conflicts gathering (part 5). --- .../extractMethod/ExtractMethodHandler.java | 2 +- .../ExtractSuperClassUtil.java | 4 +- .../BaseExpressionToFieldHandler.java | 2 +- .../introduceVariable/InputValidator.java | 109 +- .../IntroduceVariableBase.java | 2019 ++++++++------- .../makeStatic/MakeClassStaticProcessor.java | 671 ++--- .../makeStatic/MakeMethodStaticProcessor.java | 387 +-- .../memberPullUp/JavaPullUpHandler.java | 431 ++-- .../memberPullUp/PullUpConflictsUtil.java | 657 ++--- .../memberPullUp/PullUpDialog.java | 386 +-- .../memberPushDown/PushDownConflicts.java | 315 +-- .../moveMembers/MoveJavaMemberHandler.java | 488 ++-- .../move/moveMembers/MoveMembersDialog.java | 113 +- .../move/moveMembers/MoveMembersImpl.java | 158 +- .../rename/RenameJavaClassProcessor.java | 502 ++-- .../rename/RenameJavaMethodProcessor.java | 632 ++--- .../rename/RenameJavaVariableProcessor.java | 3 +- .../tempWithQuery/TempWithQueryHandler.java | 249 +- .../typeMigration/TypeMigrationLabeler.java | 2227 +++++++++-------- .../impl/refactoring/util/ConflictsUtil.java | 196 +- .../util/RefactoringConflictsUtil.java | 548 ++-- 21 files changed, 5316 insertions(+), 4783 deletions(-) diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethod/ExtractMethodHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethod/ExtractMethodHandler.java index 68265e7cf6..9614724112 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethod/ExtractMethodHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethod/ExtractMethodHandler.java @@ -202,7 +202,7 @@ private static ExtractMethodProcessor getProcessor( } final ExtractMethodProcessor processor = - new ExtractMethodProcessor(project, editor, elements, null, REFACTORING_NAME, "", HelpID.EXTRACT_METHOD); + new ExtractMethodProcessor(project, editor, elements, null, REFACTORING_NAME.get(), "", HelpID.EXTRACT_METHOD); processor.setShowErrorDialogs(showErrorMessages); try { if (!processor.prepare(pass)) { diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractSuperclass/ExtractSuperClassUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractSuperclass/ExtractSuperClassUtil.java index 54c27411e2..e944f352e6 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractSuperclass/ExtractSuperClassUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractSuperclass/ExtractSuperClassUtil.java @@ -241,7 +241,7 @@ public static PsiTypeParameter findTypeParameterInDerived(final PsiClass aClass, return null; } - public static void checkSuperAccessible(PsiDirectory targetDirectory, MultiMap conflicts, final PsiClass subclass) { + public static void checkSuperAccessible(PsiDirectory targetDirectory, MultiMap conflicts, PsiClass subclass) { final VirtualFile virtualFile = subclass.getContainingFile().getVirtualFile(); if (virtualFile != null) { final boolean inTestSourceContent = @@ -251,7 +251,7 @@ public static void checkSuperAccessible(PsiDirectory targetDirectory, MultiMap

conflicts = new MultiMap(); - final HashSet reportedVariables = new HashSet(); - JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor visitor = new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() { - public void visitCollidingElement(PsiVariable collidingVariable) { - if (!reportedVariables.contains(collidingVariable)) { - reportedVariables.add(collidingVariable); - LocalizeValue message = - RefactoringLocalize.introducedVariableWillConflictWith0(RefactoringUIUtil.getDescription(collidingVariable, true)); - conflicts.putValue(collidingVariable, message.get()); + @Override + public boolean isOK(IntroduceVariableSettings settings) { + String name = settings.getEnteredName(); + PsiElement anchor; + boolean replaceAllOccurrences = settings.isReplaceAllOccurrences(); + if (replaceAllOccurrences) { + anchor = myAnchorStatementIfAll; + } + else { + anchor = myAnchorStatement; + } + PsiElement scope = anchor.getParent(); + if (scope == null) { + return true; + } + MultiMap conflicts = new MultiMap<>(); + Set reportedVariables = new HashSet<>(); + JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor visitor = collidingVariable -> { + if (!reportedVariables.contains(collidingVariable)) { + reportedVariables.add(collidingVariable); + LocalizeValue message = + RefactoringLocalize.introducedVariableWillConflictWith0(RefactoringUIUtil.getDescription( + collidingVariable, + true + )); + conflicts.putValue(collidingVariable, message); + } + }; + JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(anchor, name, scope, anchor, visitor); + if (replaceAllOccurrences) { + for (PsiExpression occurrence : myOccurrenceManager.getOccurrences()) { + IntroduceVariableBase.checkInLoopCondition(occurrence, conflicts); + } + } + else { + IntroduceVariableBase.checkInLoopCondition(myOccurrenceManager.getMainOccurence(), conflicts); } - } - }; - JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(anchor, name, scope, anchor, visitor); - if (replaceAllOccurrences) { - final PsiExpression[] occurences = myOccurenceManager.getOccurrences(); - for (PsiExpression occurence : occurences) { - IntroduceVariableBase.checkInLoopCondition(occurence, conflicts); - } - } else { - IntroduceVariableBase.checkInLoopCondition(myOccurenceManager.getMainOccurence(), conflicts); - } - if (conflicts.size() > 0) { - return myIntroduceVariableBase.reportConflicts(conflicts, myProject, settings); - } else { - return true; + return conflicts.size() <= 0 || myIntroduceVariableBase.reportConflicts(conflicts, myProject, settings); } - } - - public InputValidator(final IntroduceVariableBase introduceVariableBase, - Project project, - PsiElement anchorStatementIfAll, - PsiElement anchorStatement, - ExpressionOccurrenceManager occurenceManager) { - myIntroduceVariableBase = introduceVariableBase; - myProject = project; - myAnchorStatementIfAll = anchorStatementIfAll; - myAnchorStatement = anchorStatement; - myOccurenceManager = occurenceManager; - } + public InputValidator( + IntroduceVariableBase introduceVariableBase, + Project project, + PsiElement anchorStatementIfAll, + PsiElement anchorStatement, + ExpressionOccurrenceManager occurrenceManager + ) { + myIntroduceVariableBase = introduceVariableBase; + myProject = project; + myAnchorStatementIfAll = anchorStatementIfAll; + myAnchorStatement = anchorStatement; + myOccurrenceManager = occurrenceManager; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceVariable/IntroduceVariableBase.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceVariable/IntroduceVariableBase.java index 1647a1156e..b1ed4ccac9 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceVariable/IntroduceVariableBase.java @@ -51,7 +51,6 @@ import consulo.language.editor.completion.lookup.LookupManager; import consulo.language.editor.highlight.HighlightManager; import consulo.language.editor.inject.EditorWindow; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.RefactoringSupportProvider; import consulo.language.editor.refactoring.introduce.IntroduceTargetChooser; import consulo.language.editor.refactoring.introduce.inplace.AbstractInplaceIntroducer; @@ -85,119 +84,147 @@ /** * @author dsl - * Date: Nov 15, 2002 + * @since 2002-11-15 */ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { - private static final Logger LOG = Logger.getInstance(IntroduceVariableBase.class); - @NonNls - private static final String PREFER_STATEMENTS_OPTION = "introduce.variable.prefer.statements"; - - protected static final String REFACTORING_NAME = RefactoringBundle.message("introduce.variable.title"); - public static final Key NEED_PARENTHESIS = Key.create("NEED_PARENTHESIS"); - - public static SuggestedNameInfo getSuggestedName(@Nullable PsiType type, @Nonnull final PsiExpression expression) { - return getSuggestedName(type, expression, expression); - } - - public static SuggestedNameInfo getSuggestedName(@Nullable PsiType type, @Nonnull 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(@Nonnull 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 && (!PsiUtil.isStatement(statementsInRange[0]) || - statementsInRange[0].getTextRange().getStartOffset() > offset || - statementsInRange[0].getTextRange().getEndOffset() < offset || - isPreferStatements())) { - selectionModel.selectLineAtCaret(); - final PsiExpression expressionInRange = findExpressionInRange(project, file, selectionModel.getSelectionStart(), - selectionModel.getSelectionEnd()); - if (expressionInRange == null || getErrorMessage(expressionInRange) != null) { - selectionModel.removeSelection(); - } - } + private static final Logger LOG = Logger.getInstance(IntroduceVariableBase.class); + @NonNls + private static final String PREFER_STATEMENTS_OPTION = "introduce.variable.prefer.statements"; + + protected static final LocalizeValue REFACTORING_NAME = RefactoringLocalize.introduceVariableTitle(); + public static final Key NEED_PARENTHESIS = Key.create("NEED_PARENTHESIS"); + + public static SuggestedNameInfo getSuggestedName(@Nullable PsiType type, @Nonnull final PsiExpression expression) { + return getSuggestedName(type, expression, expression); + } + + public static SuggestedNameInfo getSuggestedName( + @Nullable PsiType type, + @Nonnull 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(@Nonnull 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 && (!PsiUtil.isStatement(statementsInRange[0]) || + statementsInRange[0].getTextRange().getStartOffset() > offset || + statementsInRange[0].getTextRange().getEndOffset() < offset || + isPreferStatements())) { + 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 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 { - 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; - } - } - IntroduceTargetChooser.showChooser(editor, expressions, new Consumer() { - public void accept(final PsiExpression selectedValue) { - invoke(project, editor, file, selectedValue.getTextRange().getStartOffset(), selectedValue.getTextRange().getEndOffset - ()); - } - }, new PsiExpressionTrimRenderer.RenderFunction(), "Expressions", selection, ScopeHighlighter.NATURAL_RANGER); - return; + if (!selectionModel.hasSelection()) { + final List 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 { + 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; + } + } + IntroduceTargetChooser.showChooser(editor, expressions, new Consumer() { + public void accept(final PsiExpression selectedValue) { + invoke( + project, + editor, + file, + selectedValue.getTextRange().getStartOffset(), + selectedValue.getTextRange().getEndOffset + () + ); + } + }, new PsiExpressionTrimRenderer.RenderFunction(), "Expressions", selection, ScopeHighlighter.NATURAL_RANGER); + return; + } + } + } + if (invoke( + project, + editor, + file, + selectionModel.getSelectionStart(), + selectionModel.getSelectionEnd() + ) && LookupManager.getActiveLookup + (editor) == null) { + selectionModel.removeSelection(); } - } } - if (invoke(project, editor, file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) && LookupManager.getActiveLookup - (editor) == null) { - selectionModel.removeSelection(); + + public static boolean isPreferStatements() { + return ApplicationPropertiesComponent.getInstance().getBoolean(PREFER_STATEMENTS_OPTION, false); } - } - - public static boolean isPreferStatements() { - return ApplicationPropertiesComponent.getInstance().getBoolean(PREFER_STATEMENTS_OPTION, false); - } - - public static List collectExpressions(final PsiFile file, final Editor editor, final int offset) { - return collectExpressions(file, editor, offset, false); - } - - public static List collectExpressions(final PsiFile file, final Editor editor, final int offset, boolean acceptVoid) { - return collectExpressions(file, editor.getDocument(), offset, acceptVoid); - } - - public static List 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--; + + public static List collectExpressions(final PsiFile file, final Editor editor, final int offset) { + return collectExpressions(file, editor, offset, false); } - 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; - } + + public static List collectExpressions(final PsiFile file, final Editor editor, final int offset, boolean acceptVoid) { + return collectExpressions(file, editor.getDocument(), offset, acceptVoid); } - final PsiElement elementAtCaret = file.findElementAt(correctedOffset); - final List expressions = new ArrayList(); + + public static List 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 expressions = new ArrayList(); /*for (PsiElement element : statementsInRange) { if (element instanceof PsiExpressionStatement) { final PsiExpression expression = ((PsiExpressionStatement)element).getExpression(); @@ -206,959 +233,1041 @@ public static List collectExpressions(final PsiFile file, final D } } }*/ - PsiExpression expression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); - while (expression != null) { - if (!expressions.contains(expression) && !(expression instanceof PsiParenthesizedExpression) && !(expression instanceof - PsiSuperExpression) && - (acceptVoid || !PsiType.VOID.equals(expression.getType()))) { - 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); - } - } - } + PsiExpression expression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); + while (expression != null) { + if (!expressions.contains(expression) && !(expression instanceof PsiParenthesizedExpression) && !(expression instanceof + PsiSuperExpression) && + (acceptVoid || !PsiType.VOID.equals(expression.getType()))) { + 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); } - } - expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class); + return expressions; } - 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(); - } - } + + 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); } - if (tempExpr == null) { - tempExpr = getSelectedExpression(project, file, startOffset, endOffset); + 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); } - 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; + + 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(); + } + } } - } - 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; + if (tempExpr == null) { + tempExpr = getSelectedExpression(project, file, startOffset, endOffset); + } + return tempExpr; } - 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; + /** + * @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(); } - } - 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 += "\""; + if (endOffset <= startOffset) { + return null; } - } - 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 + 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); - if (primitive) { - text = stripped; - } + final PsiLiteralExpression startLiteralExpression = PsiTreeUtil.getParentOfType(elementAtStart, PsiLiteralExpression.class); + final PsiLiteralExpression endLiteralExpression = + PsiTreeUtil.getParentOfType(file.findElementAt(endOffset), PsiLiteralExpression.class); - if (literalExpression != null && text.equals(literalExpression.getText())) { - return literalExpression; - } + 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; + } + } - final PsiElement parent = literalExpression != null ? literalExpression : elementAt; - tempExpr = elementFactory.createExpressionFromText(text, parent); + 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 += "\""; + } + } - 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); - } + 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 + } + } - @Override - public void visitErrorElement(final PsiErrorElement element) { - hasErrors[0] = true; - } - }; - tempExpr.accept(errorsVisitor); - if (hasErrors[0]) { - return null; - } + if (primitive) { + text = stripped; + } - tempExpr.putUserData(ElementToWorkOn.PREFIX, prefix); - tempExpr.putUserData(ElementToWorkOn.SUFFIX, suffix); + if (literalExpression != null && text.equals(literalExpression.getText())) { + return literalExpression; + } - final RangeMarker rangeMarker = FileDocumentManager.getInstance().getDocument(file.getVirtualFile()).createRangeMarker(startOffset, - endOffset); - tempExpr.putUserData(ElementToWorkOn.TEXT_RANGE, rangeMarker); + 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); + } - 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); - } + @Override + public void visitErrorElement(final PsiErrorElement element) { + hasErrors[0] = true; + } + }; + tempExpr.accept(errorsVisitor); + if (hasErrors[0]) { + return null; + } - 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; + 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; } - } - 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."; + 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) + ); } - 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()) { + @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; - } + } - final PsiFile containingFile = parent.getContainingFile(); + 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; + } - PsiElement startElement = containingFile.findElementAt(startOffset); - while (startElement != null && startElement.getParent() != parent.getArgumentList()) { - startElement = startElement.getParent(); - } - if (startElement == null || startOffset > startElement.getTextOffset()) { - return null; - } + final PsiFile containingFile = parent.getContainingFile(); - 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; - } + PsiElement startElement = containingFile.findElementAt(startOffset); + while (startElement != null && startElement.getParent() != parent.getArgumentList()) { + startElement = startElement.getParent(); + } + if (startElement == null || startOffset > startElement.getTextOffset()) { + 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) { + 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; - } - } - 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, RefactoringLocalize.cannotPerformRefactoringWithReason(errorMessage).get()); - return false; - } } - if (expr != null && expr.getParent() instanceof PsiExpressionStatement) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.introduceVariable.incompleteStatement"); - } - if (LOG.isDebugEnabled()) { - LOG.debug("expression:" + expr); - } + protected boolean invokeImpl(@Nonnull Project project, final PsiExpression expr, final Editor editor) { + if (expr != null) { + final String errorMessage = getErrorMessage(expr); + if (errorMessage != null) { + showErrorMessage(project, editor, RefactoringLocalize.cannotPerformRefactoringWithReason(errorMessage)); + return false; + } + } - if (expr == null || !expr.isPhysical()) { - if (ReassignVariableUtil.reassign(editor)) { - return false; - } - if (expr == null) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedBlockShouldRepresentAnExpression()); - showErrorMessage(project, editor, message.get()); - 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) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedBlockShouldRepresentAnExpression()); + showErrorMessage(project, editor, message); + return false; + } + } - PsiType originalType = RefactoringUtil.getTypeByExpressionWithExpectedType(expr); - if (originalType == null || LambdaUtil.notInferredType(originalType)) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.unknownExpressionType()); - showErrorMessage(project, editor, message.get()); - return false; - } + PsiType originalType = RefactoringUtil.getTypeByExpressionWithExpectedType(expr); + if (originalType == null || LambdaUtil.notInferredType(originalType)) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.unknownExpressionType()); + showErrorMessage(project, editor, message); + return false; + } - if (PsiType.VOID.equals(originalType)) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedExpressionHasVoidType()); - showErrorMessage(project, editor, message.get()); - return false; - } + if (PsiType.VOID.equals(originalType)) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedExpressionHasVoidType()); + showErrorMessage(project, editor, message); + return false; + } - final PsiElement physicalElement = expr.getUserData(ElementToWorkOn.PARENT); + final PsiElement physicalElement = expr.getUserData(ElementToWorkOn.PARENT); - final 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); - } - if (checkAnchorBeforeThisOrSuper(project, editor, anchorStatement, REFACTORING_NAME, HelpID.INTRODUCE_VARIABLE)) { - return false; - } + if (anchorStatement == null) { + return parentStatementNotFound(project, editor); + } + if (checkAnchorBeforeThisOrSuper(project, editor, anchorStatement, REFACTORING_NAME.get(), HelpID.INTRODUCE_VARIABLE)) { + return false; + } - final PsiElement tempContainer = anchorStatement.getParent(); + final PsiElement tempContainer = anchorStatement.getParent(); - if (!(tempContainer instanceof PsiCodeBlock) && !RefactoringUtil.isLoopOrIf(tempContainer) && (tempContainer.getParent() instanceof - PsiLambdaExpression)) { - String message = RefactoringLocalize.refactoringIsNotSupportedInTheCurrentContext(REFACTORING_NAME).get(); - showErrorMessage(project, editor, message); - return false; - } + if (!(tempContainer instanceof PsiCodeBlock) && !RefactoringUtil.isLoopOrIf(tempContainer) && (tempContainer.getParent() instanceof + PsiLambdaExpression)) { + LocalizeValue message = RefactoringLocalize.refactoringIsNotSupportedInTheCurrentContext(REFACTORING_NAME); + showErrorMessage(project, editor, message); + return false; + } - if (!NotInSuperCallOccurrenceFilter.INSTANCE.isOK(expr)) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.cannotIntroduceVariableInSuperConstructorCall()); - showErrorMessage(project, editor, message.get()); - return false; - } + if (!NotInSuperCallOccurrenceFilter.INSTANCE.isOK(expr)) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.cannotIntroduceVariableInSuperConstructorCall()); + 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 = RefactoringSupportProvider.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 conflicts = new MultiMap(); - checkInLoopCondition(expr, conflicts); - if (!conflicts.isEmpty()) { - showErrorMessage(project, editor, StringUtil.join(conflicts.values(), "
")); - 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 = RefactoringSupportProvider.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 conflicts = new MultiMap<>(); + checkInLoopCondition(expr, conflicts); + if (!conflicts.isEmpty()) { + showErrorMessage(project, editor, LocalizeValue.localizeTODO(StringUtil.join(conflicts.values(), "
"))); + return false; + } + } - final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, tempContainer); - final PsiExpression[] occurrences = occurrenceManager.getOccurrences(); - final PsiElement anchorStatementIfAll = occurrenceManager.getAnchorStatementForAll(); - - - final List nonWrite = new ArrayList(); - 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 ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, tempContainer); + final PsiExpression[] occurrences = occurrenceManager.getOccurrences(); + final PsiElement anchorStatementIfAll = occurrenceManager.getAnchorStatementForAll(); - final LinkedHashMap> occurrencesMap = new LinkedHashMap<>(); - 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 List nonWrite = new ArrayList(); + 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 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 Consumer callback = new Consumer() { - @Override - public void accept(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 = EditorWindow.getTopLevelEditor(editor); - } else { - topLevelEditor = editor; + final LinkedHashMap> occurrencesMap = new LinkedHashMap<>(); + 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); } - 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 (occurrences.length > 1 && !cantReplaceAll) { + occurrencesMap.put(OccurrencesChooser.ReplaceChoice.ALL, Arrays.asList(occurrences)); } - if (!settings.isOK()) { - wasSucceed[0] = false; - return; + + 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 Consumer callback = new Consumer() { + @Override + public void accept(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 = EditorWindow.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 String expressionText = expr.getText(); + final Runnable runnable = introduce(project, expr, topLevelEditor, chosenAnchor, occurrences, settings, variable); + CommandProcessor.getInstance().newCommand() + .project(project) + .name(REFACTORING_NAME) + .run(() -> { + project.getApplication().runWriteAction(runnable); + if (isInplaceAvailableOnDataContext) { + PsiVariable elementToRename = variable.get().getElement(); + if (elementToRename != null) { + topLevelEditor.getCaretModel().moveToOffset(elementToRename.getTextOffset()); + boolean cantChangeFinalModifier = (hasWriteAccess || inFinalContext) + && choice == OccurrencesChooser.ReplaceChoice.ALL; + JavaVariableInplaceIntroducer renamer = new JavaVariableInplaceIntroducer( + project, + expression, + topLevelEditor, + elementToRename, + cantChangeFinalModifier, + typeSelectorManager.getTypesForAll().length > 1, + exprMarker, + occurrenceMarkers, + REFACTORING_NAME.get() + ); + renamer.initInitialText(expressionText); + PsiDocumentManager.getInstance(project) + .doPostponedOperationsAndUnblockDocument(topLevelEditor.getDocument()); + renamer.performInplaceRefactoring(new LinkedHashSet<>(Arrays.asList(suggestedName.names))); + } + } + }); + } + }; + + if (!isInplaceAvailableOnDataContext) { + callback.accept(null); } - 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())); - } + else { + OccurrencesChooser.simpleChooser(editor).showChooser(callback, occurrencesMap); } - 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() { - ApplicationManager.getApplication().runWriteAction(runnable); - 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); - } - }; - - if (!isInplaceAvailableOnDataContext) { - callback.accept(null); - } else { - OccurrencesChooser.simpleChooser(editor).showChooser(callback, occurrencesMap); + return wasSucceed[0]; } - return wasSucceed[0]; - } - - protected 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); - } 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); + + protected 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); + } + else { + return anchorStatementIfAll; + } + } + else { + return anchorStatement; } - }; - 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; - } + protected boolean isInplaceAvailableInTestMode() { + return false; } - return new ExpressionOccurrenceManager(expr, lastScope, NotInSuperCallOccurrenceFilter.INSTANCE); - } + 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; + } - private static boolean isInJspHolderMethod(PsiExpression expr) { - /*final PsiElement parent1 = expr.getParent(); - if(parent1 == null) */ - { - return false; + 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); } - /*final PsiElement parent2 = parent1.getParent(); - if(!(parent2 instanceof JspCodeBlock)) + + 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> variable) { - final PsiElement container = anchorStatement.getParent(); - PsiElement child = anchorStatement; - if (!RefactoringUtil.isLoopOrIf(container)) { - child = locateAnchor(child); - if (isFinalVariableOnLHS(expr)) { - child = child.getNextSibling(); - } + /*final PsiElement parent3 = parent2.getParent(); + return parent3 instanceof JspHolderMethod; */ } - 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; + 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 + ) { + 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) { + 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); - 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 array = new ArrayList(); - 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 = ArrayUtil.find(declaredElements, expression.resolve()); - if (i > -1) { - usedFirstVar[0] = Math.max(i, usedFirstVar[0]); + 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 array = new ArrayList(); + 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(); } - 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; - } + 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 = ArrayUtil.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); + } + }; } - 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); - } + + 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; } - 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); + + 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; } - 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])); + + 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 = ""; - } + 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; + 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); } - return JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(text, parent); - } - - private boolean parentStatementNotFound(final Project project, Editor editor) { - LocalizeValue message = RefactoringLocalize.refactoringIsNotSupportedInTheCurrentContext(REFACTORING_NAME); - showErrorMessage(project, editor, message.get()); - 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; + + private boolean parentStatementNotFound(final Project project, Editor editor) { + LocalizeValue message = RefactoringLocalize.refactoringIsNotSupportedInTheCurrentContext(REFACTORING_NAME); + showErrorMessage(project, editor, message); + return false; } - while (child instanceof PsiWhiteSpace || child instanceof PsiComment) { - child = child.getNextSibling(); + protected boolean invokeImpl(Project project, PsiLocalVariable localVariable, Editor editor) { + throw new UnsupportedOperationException(); } - return child; - } - protected static void highlightReplacedOccurences(Project project, Editor editor, PsiElement[] replacedOccurences) { - if (editor == null) { - return; + 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; } - if (ApplicationManager.getApplication().isUnitTestMode()) { - return; + + protected static void highlightReplacedOccurences(Project project, Editor editor, PsiElement[] replacedOccurences) { + if (editor == null) { + return; + } + if (ApplicationManager.getApplication().isUnitTestMode()) { + return; + } + HighlightManager highlightManager = HighlightManager.getInstance(project); + highlightManager.addOccurrenceHighlights(editor, replacedOccurences, EditorColors.SEARCH_RESULT_ATTRIBUTES, true, null); } - HighlightManager highlightManager = HighlightManager.getInstance(project); - highlightManager.addOccurrenceHighlights(editor, replacedOccurences, EditorColors.SEARCH_RESULT_ATTRIBUTES, true, null); - } - - protected abstract void showErrorMessage(Project project, Editor editor, String message); - - - protected boolean reportConflicts(MultiMap 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; - } + protected abstract void showErrorMessage(Project project, Editor editor, LocalizeValue message); - @Override - public boolean isDeclareFinal() { - return declareFinal; - } + protected boolean reportConflicts(MultiMap conflicts, Project project, IntroduceVariableSettings settings) { + return false; + } - @Override - public boolean isReplaceLValues() { - return replaceWrite; - } + 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 PsiType getSelectedType() { - final PsiType selectedType = typeSelectorManager.getTypeSelector().getSelectedType(); - return selectedType != null ? selectedType : typeSelectorManager.getDefaultType(); - } + @Override + public boolean isReplaceAllOccurrences() { + return replaceAll; + } - @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 - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.invalidExpressionContext()); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), refactoringName, helpID); - return true; - } - } + @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; + } + }; } - return false; - } - public interface Validator { - boolean isOK(IntroduceVariableSettings dialog); - } + 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 void checkInLoopCondition(PsiExpression occurence, MultiMap conflicts) { - final PsiElement loopForLoopCondition = RefactoringUtil.getLoopForLoopCondition(occurence); - if (loopForLoopCondition == null) { - return; + 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 + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.invalidExpressionContext()); + CommonRefactoringUtil.showErrorHint(project, editor, message.get(), refactoringName, helpID); + return true; + } + } + } + return false; } - final List referencedVariables = RefactoringUtil.collectReferencedVariables(occurence); - final List modifiedInBody = new ArrayList(); - for (PsiVariable psiVariable : referencedVariables) { - if (RefactoringUtil.isModifiedInScope(psiVariable, loopForLoopCondition)) { - modifiedInBody.add(psiVariable); - } + + public interface Validator { + boolean isOK(IntroduceVariableSettings dialog); } - if (!modifiedInBody.isEmpty()) { - for (PsiVariable variable : modifiedInBody) { - final LocalizeValue message = RefactoringLocalize.isModifiedInLoopBody(RefactoringUIUtil.getDescription(variable, false)); - conflicts.putValue(variable, CommonRefactoringUtil.capitalize(message.get())); - } - conflicts.putValue(occurence, RefactoringLocalize.introducingVariableMayBreakCodeLogic().get()); + public static void checkInLoopCondition(PsiExpression occurence, MultiMap conflicts) { + final PsiElement loopForLoopCondition = RefactoringUtil.getLoopForLoopCondition(occurence); + if (loopForLoopCondition == null) { + return; + } + final List referencedVariables = RefactoringUtil.collectReferencedVariables(occurence); + final List modifiedInBody = new ArrayList(); + for (PsiVariable psiVariable : referencedVariables) { + if (RefactoringUtil.isModifiedInScope(psiVariable, loopForLoopCondition)) { + modifiedInBody.add(psiVariable); + } + } + + if (!modifiedInBody.isEmpty()) { + for (PsiVariable variable : modifiedInBody) { + final LocalizeValue message = RefactoringLocalize.isModifiedInLoopBody(RefactoringUIUtil.getDescription(variable, false)); + conflicts.putValue(variable, message.capitalize()); + } + conflicts.putValue(occurence, RefactoringLocalize.introducingVariableMayBreakCodeLogic()); + } } - } - @Override - public AbstractInplaceIntroducer getInplaceIntroducer() { - return null; - } + @Override + public AbstractInplaceIntroducer getInplaceIntroducer() { + return null; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeClassStaticProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeClassStaticProcessor.java index 636b9359c6..92fcfc1433 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeClassStaticProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeClassStaticProcessor.java @@ -24,6 +24,7 @@ import com.intellij.java.language.psi.codeStyle.VariableKind; import com.intellij.java.language.psi.javadoc.PsiDocTag; import com.intellij.java.language.psi.util.PsiUtil; +import consulo.annotation.access.RequiredReadAction; import consulo.language.codeStyle.CodeStyleManager; import consulo.language.codeStyle.CodeStyleSettingsManager; import consulo.language.editor.refactoring.localize.RefactoringLocalize; @@ -48,375 +49,399 @@ * @author ven */ public class MakeClassStaticProcessor extends MakeMethodOrClassStaticProcessor { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeClassStaticProcessor"); - private List myFieldsToSplit = new ArrayList(); - - public MakeClassStaticProcessor(final Project project, final PsiClass aClass, final Settings settings) { - super(project, aClass, settings); - } - - protected void changeSelf(final PsiElementFactory factory, final UsageInfo[] usages) throws IncorrectOperationException { - PsiClass containingClass = myMember.getContainingClass(); - - //Add fields - if (mySettings.isMakeClassParameter()) { - PsiType type = factory.createType(containingClass, PsiSubstitutor.EMPTY); - final String classParameterName = mySettings.getClassParameterName(); - final String fieldName = convertToFieldName(classParameterName); - myMember.add(factory.createField(fieldName, type)); + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeClassStaticProcessor"); + private List myFieldsToSplit = new ArrayList(); + + public MakeClassStaticProcessor(final Project project, final PsiClass aClass, final Settings settings) { + super(project, aClass, settings); } - if (mySettings.isMakeFieldParameters()) { - List parameters = mySettings.getParameterOrderList(); + protected void changeSelf(final PsiElementFactory factory, final UsageInfo[] usages) throws IncorrectOperationException { + PsiClass containingClass = myMember.getContainingClass(); - for (Settings.FieldParameter fieldParameter : parameters) { - final PsiType type = fieldParameter.type; - final PsiField field = factory.createField(convertToFieldName(fieldParameter.name), type); - myMember.add(field); - } - } + //Add fields + if (mySettings.isMakeClassParameter()) { + PsiType type = factory.createType(containingClass, PsiSubstitutor.EMPTY); + final String classParameterName = mySettings.getClassParameterName(); + final String fieldName = convertToFieldName(classParameterName); + myMember.add(factory.createField(fieldName, type)); + } + if (mySettings.isMakeFieldParameters()) { + List parameters = mySettings.getParameterOrderList(); - PsiMethod[] constructors = myMember.getConstructors(); + for (Settings.FieldParameter fieldParameter : parameters) { + final PsiType type = fieldParameter.type; + final PsiField field = factory.createField(convertToFieldName(fieldParameter.name), type); + myMember.add(field); + } + } - if (constructors.length == 0) { - final PsiMethod defConstructor = (PsiMethod)myMember.add(factory.createConstructor()); - constructors = new PsiMethod[]{defConstructor}; - } - boolean generateFinalParams = CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS; - for (PsiMethod constructor : constructors) { - final MethodJavaDocHelper javaDocHelper = new MethodJavaDocHelper(constructor); - PsiParameterList paramList = constructor.getParameterList(); - PsiElement addParameterAfter = null; - PsiDocTag anchor = null; - - if (mySettings.isMakeClassParameter()) { - // Add parameter for object - PsiType parameterType = factory.createType(containingClass, PsiSubstitutor.EMPTY); - final String classParameterName = mySettings.getClassParameterName(); - PsiParameter parameter = factory.createParameter(classParameterName, parameterType); - PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, makeClassParameterFinal(usages) || generateFinalParams); - addParameterAfter = paramList.addAfter(parameter, null); - anchor = javaDocHelper.addParameterAfter(classParameterName, anchor); - - addAssignmentToField(classParameterName, constructor); - - } - - if (mySettings.isMakeFieldParameters()) { - List parameters = mySettings.getParameterOrderList(); - - for (Settings.FieldParameter fieldParameter : parameters) { - final PsiType fieldParameterType = fieldParameter.field.getType(); - final PsiParameter parameter = factory.createParameter(fieldParameter.name, fieldParameterType); - PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, - makeFieldParameterFinal(fieldParameter.field, usages) || generateFinalParams); - addParameterAfter = paramList.addAfter(parameter, addParameterAfter); - anchor = javaDocHelper.addParameterAfter(fieldParameter.name, anchor); - addAssignmentToField(fieldParameter.name, constructor); + PsiMethod[] constructors = myMember.getConstructors(); + + if (constructors.length == 0) { + final PsiMethod defConstructor = (PsiMethod) myMember.add(factory.createConstructor()); + constructors = new PsiMethod[]{defConstructor}; } - for (UsageInfo usage : usages) { - if (usage instanceof InternalUsageInfo) { - final PsiElement element = usage.getElement(); - final PsiElement referencedElement = ((InternalUsageInfo)usage).getReferencedElement(); - if (referencedElement instanceof PsiField && mySettings.getNameForField((PsiField)referencedElement) != null) { - final PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class); - if (field != null) { + + boolean generateFinalParams = CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS; + for (PsiMethod constructor : constructors) { + final MethodJavaDocHelper javaDocHelper = new MethodJavaDocHelper(constructor); + PsiParameterList paramList = constructor.getParameterList(); + PsiElement addParameterAfter = null; + PsiDocTag anchor = null; + + if (mySettings.isMakeClassParameter()) { + // Add parameter for object + PsiType parameterType = factory.createType(containingClass, PsiSubstitutor.EMPTY); + final String classParameterName = mySettings.getClassParameterName(); + PsiParameter parameter = factory.createParameter(classParameterName, parameterType); + PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, makeClassParameterFinal(usages) || generateFinalParams); + addParameterAfter = paramList.addAfter(parameter, null); + anchor = javaDocHelper.addParameterAfter(classParameterName, anchor); + + addAssignmentToField(classParameterName, constructor); + + } + + if (mySettings.isMakeFieldParameters()) { + List parameters = mySettings.getParameterOrderList(); + + for (Settings.FieldParameter fieldParameter : parameters) { + final PsiType fieldParameterType = fieldParameter.field.getType(); + final PsiParameter parameter = factory.createParameter(fieldParameter.name, fieldParameterType); + PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, + makeFieldParameterFinal(fieldParameter.field, usages) || generateFinalParams + ); + addParameterAfter = paramList.addAfter(parameter, addParameterAfter); + anchor = javaDocHelper.addParameterAfter(fieldParameter.name, anchor); + addAssignmentToField(fieldParameter.name, constructor); + } + for (UsageInfo usage : usages) { + if (usage instanceof InternalUsageInfo) { + final PsiElement element = usage.getElement(); + final PsiElement referencedElement = ((InternalUsageInfo) usage).getReferencedElement(); + if (referencedElement instanceof PsiField && mySettings.getNameForField((PsiField) referencedElement) != null) { + final PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class); + if (field != null) { + MoveInstanceMembersUtil.moveInitializerToConstructor(factory, constructor, field); + } + } + } + } + } + for (PsiField field : myFieldsToSplit) { MoveInstanceMembersUtil.moveInitializerToConstructor(factory, constructor, field); - } } - } } - } - for (PsiField field : myFieldsToSplit) { - MoveInstanceMembersUtil.moveInitializerToConstructor(factory, constructor, field); - } - } - setupTypeParameterList(); - - // Add static modifier - final PsiModifierList modifierList = myMember.getModifierList(); - modifierList.setModifierProperty(PsiModifier.STATIC, true); - modifierList.setModifierProperty(PsiModifier.FINAL, false); - } - - private void addAssignmentToField(final String parameterName, final PsiMethod constructor) { - @NonNls String fieldName = convertToFieldName(parameterName); - final PsiManager manager = PsiManager.getInstance(myProject); - PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - final PsiCodeBlock body = constructor.getBody(); - if (body != null) { - try { - final PsiReferenceExpression refExpr = (PsiReferenceExpression)factory.createExpressionFromText(fieldName, body); - if (refExpr.resolve() != null) fieldName = "this." + fieldName; - PsiStatement statement = factory.createStatementFromText(fieldName + "=" + parameterName + ";", null); - statement = (PsiStatement)CodeStyleManager.getInstance(manager.getProject()).reformat(statement); - body.add(statement); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - - private String convertToFieldName(final String parameterName) { - JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(myProject); - final String propertyName = manager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER); - final String fieldName = manager.propertyNameToVariableName(propertyName, VariableKind.FIELD); - return fieldName; - } - - protected void changeSelfUsage(final SelfUsageInfo usageInfo) throws IncorrectOperationException { - PsiElement parent = usageInfo.getElement().getParent(); - LOG.assertTrue(parent instanceof PsiCallExpression); //either this() or new() - PsiCallExpression call = (PsiCallExpression) parent; - PsiElementFactory factory = JavaPsiFacade.getInstance(call.getProject()).getElementFactory(); - PsiExpressionList args = call.getArgumentList(); - PsiElement addParameterAfter = null; - - if(mySettings.isMakeClassParameter()) { - PsiElement arg = factory.createExpressionFromText(convertToFieldName(mySettings.getClassParameterName()), null); - addParameterAfter = args.addAfter(arg, null); + setupTypeParameterList(); + + // Add static modifier + final PsiModifierList modifierList = myMember.getModifierList(); + modifierList.setModifierProperty(PsiModifier.STATIC, true); + modifierList.setModifierProperty(PsiModifier.FINAL, false); } - if(mySettings.isMakeFieldParameters()) { - List parameters = mySettings.getParameterOrderList(); - for (Settings.FieldParameter fieldParameter : parameters) { - PsiElement arg = factory.createExpressionFromText(convertToFieldName(fieldParameter.name), null); - if (addParameterAfter == null) { - addParameterAfter = args.addAfter(arg, null); - } - else { - addParameterAfter = args.addAfter(arg, addParameterAfter); + private void addAssignmentToField(final String parameterName, final PsiMethod constructor) { + @NonNls String fieldName = convertToFieldName(parameterName); + final PsiManager manager = PsiManager.getInstance(myProject); + PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + final PsiCodeBlock body = constructor.getBody(); + if (body != null) { + try { + final PsiReferenceExpression refExpr = (PsiReferenceExpression) factory.createExpressionFromText(fieldName, body); + if (refExpr.resolve() != null) { + fieldName = "this." + fieldName; + } + PsiStatement statement = factory.createStatementFromText(fieldName + "=" + parameterName + ";", null); + statement = (PsiStatement) CodeStyleManager.getInstance(manager.getProject()).reformat(statement); + body.add(statement); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - } } - } - protected void changeInternalUsage(final InternalUsageInfo usage, final PsiElementFactory factory) throws IncorrectOperationException { - if (!mySettings.isChangeSignature()) return; - - PsiElement element = usage.getElement(); + private String convertToFieldName(final String parameterName) { + JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(myProject); + final String propertyName = manager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER); + final String fieldName = manager.propertyNameToVariableName(propertyName, VariableKind.FIELD); + return fieldName; + } - if (element instanceof PsiReferenceExpression) { - PsiReferenceExpression newRef = null; + protected void changeSelfUsage(final SelfUsageInfo usageInfo) throws IncorrectOperationException { + PsiElement parent = usageInfo.getElement().getParent(); + LOG.assertTrue(parent instanceof PsiCallExpression); //either this() or new() + PsiCallExpression call = (PsiCallExpression) parent; + PsiElementFactory factory = JavaPsiFacade.getInstance(call.getProject()).getElementFactory(); + PsiExpressionList args = call.getArgumentList(); + PsiElement addParameterAfter = null; + + if (mySettings.isMakeClassParameter()) { + PsiElement arg = factory.createExpressionFromText(convertToFieldName(mySettings.getClassParameterName()), null); + addParameterAfter = args.addAfter(arg, null); + } - if (mySettings.isMakeFieldParameters()) { - PsiElement resolved = ((PsiReferenceExpression) element).resolve(); - if (resolved instanceof PsiField) { - String name = mySettings.getNameForField((PsiField)resolved); - if (name != null) { - name = convertToFieldName(name); - if (name != null) { - newRef = (PsiReferenceExpression) factory.createExpressionFromText(name, null); + if (mySettings.isMakeFieldParameters()) { + List parameters = mySettings.getParameterOrderList(); + for (Settings.FieldParameter fieldParameter : parameters) { + PsiElement arg = factory.createExpressionFromText(convertToFieldName(fieldParameter.name), null); + if (addParameterAfter == null) { + addParameterAfter = args.addAfter(arg, null); + } + else { + addParameterAfter = args.addAfter(arg, addParameterAfter); + } } - } } - } - - if (newRef == null && mySettings.isMakeClassParameter()) { - newRef = - (PsiReferenceExpression) factory.createExpressionFromText( - convertToFieldName(mySettings.getClassParameterName()) + "." + element.getText(), null); - } - - if (newRef != null) { - CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject); - newRef = (PsiReferenceExpression) codeStyleManager.reformat(newRef); - element.replace(newRef); - } - } - else if (mySettings.isMakeClassParameter() && (element instanceof PsiThisExpression || element instanceof PsiSuperExpression)) { - final PsiElement replace = - element.replace(factory.createExpressionFromText(convertToFieldName(mySettings.getClassParameterName()), null)); - final PsiField field = PsiTreeUtil.getParentOfType(replace, PsiField.class); - if (field != null) { - myFieldsToSplit.add(field); - } } - else if (element instanceof PsiNewExpression && mySettings.isMakeClassParameter()) { - final PsiNewExpression newExpression = ((PsiNewExpression)element); - LOG.assertTrue(newExpression.getQualifier() == null); - final String newText = convertToFieldName(mySettings.getClassParameterName()) + "." + newExpression.getText(); - final PsiExpression expr = factory.createExpressionFromText(newText, null); - element.replace(expr); - } - } - protected void changeExternalUsage(final UsageInfo usage, final PsiElementFactory factory) throws IncorrectOperationException { - final PsiElement element = usage.getElement(); - if (!(element instanceof PsiJavaCodeReferenceElement)) return; + protected void changeInternalUsage(final InternalUsageInfo usage, final PsiElementFactory factory) throws IncorrectOperationException { + if (!mySettings.isChangeSignature()) { + return; + } + + PsiElement element = usage.getElement(); + + if (element instanceof PsiReferenceExpression) { + PsiReferenceExpression newRef = null; + + if (mySettings.isMakeFieldParameters()) { + PsiElement resolved = ((PsiReferenceExpression) element).resolve(); + if (resolved instanceof PsiField) { + String name = mySettings.getNameForField((PsiField) resolved); + if (name != null) { + name = convertToFieldName(name); + if (name != null) { + newRef = (PsiReferenceExpression) factory.createExpressionFromText(name, null); + } + } + } + } - PsiJavaCodeReferenceElement methodRef = (PsiJavaCodeReferenceElement)element; - PsiElement parent = methodRef.getParent(); - if (parent instanceof PsiAnonymousClass) { - parent = parent.getParent(); - } - LOG.assertTrue(parent instanceof PsiCallExpression, "call expression expected, found " + parent); - - PsiCallExpression call = (PsiCallExpression)parent; - - PsiExpression instanceRef; - - instanceRef = call instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression)call).getMethodExpression().getQualifierExpression() : - ((PsiNewExpression)call).getQualifier(); - PsiElement newQualifier; - - if (instanceRef == null || instanceRef instanceof PsiSuperExpression) { - final PsiClass thisClass = RefactoringChangeUtil.getThisClass(element); - @NonNls String thisText; - if (thisClass.getManager().areElementsEquivalent(thisClass, myMember.getContainingClass())) { - thisText = "this"; - } - else { - thisText = myMember.getContainingClass().getName() + ".this"; - } - instanceRef = factory.createExpressionFromText(thisText, null); - newQualifier = null; - } - else { - newQualifier = factory.createReferenceExpression(myMember.getContainingClass()); - } + if (newRef == null && mySettings.isMakeClassParameter()) { + newRef = + (PsiReferenceExpression) factory.createExpressionFromText( + convertToFieldName(mySettings.getClassParameterName()) + "." + element.getText(), null); + } - if (mySettings.getNewParametersNumber() > 1) { - int copyingSafetyLevel = RefactoringUtil.verifySafeCopyExpression(instanceRef); - if (copyingSafetyLevel == RefactoringUtil.EXPR_COPY_PROHIBITED) { - String tempVar = RefactoringUtil.createTempVar(instanceRef, call, true); - instanceRef = factory.createExpressionFromText(tempVar, null); - } + if (newRef != null) { + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject); + newRef = (PsiReferenceExpression) codeStyleManager.reformat(newRef); + element.replace(newRef); + } + } + else if (mySettings.isMakeClassParameter() && (element instanceof PsiThisExpression || element instanceof PsiSuperExpression)) { + final PsiElement replace = + element.replace(factory.createExpressionFromText(convertToFieldName(mySettings.getClassParameterName()), null)); + final PsiField field = PsiTreeUtil.getParentOfType(replace, PsiField.class); + if (field != null) { + myFieldsToSplit.add(field); + } + } + else if (element instanceof PsiNewExpression && mySettings.isMakeClassParameter()) { + final PsiNewExpression newExpression = ((PsiNewExpression) element); + LOG.assertTrue(newExpression.getQualifier() == null); + final String newText = convertToFieldName(mySettings.getClassParameterName()) + "." + newExpression.getText(); + final PsiExpression expr = factory.createExpressionFromText(newText, null); + element.replace(expr); + } } + protected void changeExternalUsage(final UsageInfo usage, final PsiElementFactory factory) throws IncorrectOperationException { + final PsiElement element = usage.getElement(); + if (!(element instanceof PsiJavaCodeReferenceElement)) { + return; + } - PsiElement anchor = null; - PsiExpressionList argList = call.getArgumentList(); - PsiExpression[] exprs = argList.getExpressions(); - if (mySettings.isMakeClassParameter()) { - if (exprs.length > 0) { - anchor = argList.addBefore(instanceRef, exprs[0]); - } - else { - anchor = argList.add(instanceRef); - } - } + PsiJavaCodeReferenceElement methodRef = (PsiJavaCodeReferenceElement) element; + PsiElement parent = methodRef.getParent(); + if (parent instanceof PsiAnonymousClass) { + parent = parent.getParent(); + } + LOG.assertTrue(parent instanceof PsiCallExpression, "call expression expected, found " + parent); + PsiCallExpression call = (PsiCallExpression) parent; - if (mySettings.isMakeFieldParameters()) { - List parameters = mySettings.getParameterOrderList(); + PsiExpression instanceRef; - for (Settings.FieldParameter fieldParameter : parameters) { - PsiReferenceExpression fieldRef; - final String fieldName = fieldParameter.field.getName(); - if (newQualifier != null) { - fieldRef = (PsiReferenceExpression)factory.createExpressionFromText( - "a." + fieldName, null); - fieldRef.getQualifierExpression().replace(instanceRef); + instanceRef = + call instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression) call).getMethodExpression().getQualifierExpression() : + ((PsiNewExpression) call).getQualifier(); + PsiElement newQualifier; + + if (instanceRef == null || instanceRef instanceof PsiSuperExpression) { + final PsiClass thisClass = RefactoringChangeUtil.getThisClass(element); + @NonNls String thisText; + if (thisClass.getManager().areElementsEquivalent(thisClass, myMember.getContainingClass())) { + thisText = "this"; + } + else { + thisText = myMember.getContainingClass().getName() + ".this"; + } + instanceRef = factory.createExpressionFromText(thisText, null); + newQualifier = null; } else { - fieldRef = (PsiReferenceExpression)factory.createExpressionFromText(fieldName, null); + newQualifier = factory.createReferenceExpression(myMember.getContainingClass()); } - if (anchor != null) { - anchor = argList.addAfter(fieldRef, anchor); + if (mySettings.getNewParametersNumber() > 1) { + int copyingSafetyLevel = RefactoringUtil.verifySafeCopyExpression(instanceRef); + if (copyingSafetyLevel == RefactoringUtil.EXPR_COPY_PROHIBITED) { + String tempVar = RefactoringUtil.createTempVar(instanceRef, call, true); + instanceRef = factory.createExpressionFromText(tempVar, null); + } } - else { - if (exprs.length > 0) { - anchor = argList.addBefore(fieldRef, exprs[0]); - } - else { - anchor = argList.add(fieldRef); - } + + + PsiElement anchor = null; + PsiExpressionList argList = call.getArgumentList(); + PsiExpression[] exprs = argList.getExpressions(); + if (mySettings.isMakeClassParameter()) { + if (exprs.length > 0) { + anchor = argList.addBefore(instanceRef, exprs[0]); + } + else { + anchor = argList.add(instanceRef); + } } - } - } - if (newQualifier != null) { - if (call instanceof PsiMethodCallExpression) { - instanceRef.replace(newQualifier); - } else { - final PsiAnonymousClass anonymousClass = ((PsiNewExpression)call).getAnonymousClass(); - if (anonymousClass != null) { - ((PsiNewExpression)call).getQualifier().delete(); - final PsiJavaCodeReferenceElement baseClassReference = anonymousClass.getBaseClassReference(); - baseClassReference.replace(((PsiNewExpression)factory.createExpressionFromText("new " + newQualifier.getText() + "." + baseClassReference.getText() + "()", baseClassReference)).getClassReference()); - } else { - PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)call).getClassReference(); - LOG.assertTrue(classReference != null); - final PsiNewExpression newExpr = - (PsiNewExpression)factory.createExpressionFromText("new " + newQualifier.getText() + "." + classReference.getText() + "()", classReference); - final PsiExpressionList callArgs = call.getArgumentList(); - if (callArgs != null) { - final PsiExpressionList argumentList = newExpr.getArgumentList(); - LOG.assertTrue(argumentList != null); - argumentList.replace(callArgs); - } - call.replace(newExpr); + + if (mySettings.isMakeFieldParameters()) { + List parameters = mySettings.getParameterOrderList(); + + for (Settings.FieldParameter fieldParameter : parameters) { + PsiReferenceExpression fieldRef; + final String fieldName = fieldParameter.field.getName(); + if (newQualifier != null) { + fieldRef = (PsiReferenceExpression) factory.createExpressionFromText( + "a." + fieldName, null); + fieldRef.getQualifierExpression().replace(instanceRef); + } + else { + fieldRef = (PsiReferenceExpression) factory.createExpressionFromText(fieldName, null); + } + + if (anchor != null) { + anchor = argList.addAfter(fieldRef, anchor); + } + else { + if (exprs.length > 0) { + anchor = argList.addBefore(fieldRef, exprs[0]); + } + else { + anchor = argList.add(fieldRef); + } + } + } + } + + if (newQualifier != null) { + if (call instanceof PsiMethodCallExpression) { + instanceRef.replace(newQualifier); + } + else { + final PsiAnonymousClass anonymousClass = ((PsiNewExpression) call).getAnonymousClass(); + if (anonymousClass != null) { + ((PsiNewExpression) call).getQualifier().delete(); + final PsiJavaCodeReferenceElement baseClassReference = anonymousClass.getBaseClassReference(); + baseClassReference.replace(((PsiNewExpression) factory.createExpressionFromText( + "new " + newQualifier.getText() + "." + baseClassReference.getText() + "()", + baseClassReference + )).getClassReference()); + } + else { + PsiJavaCodeReferenceElement classReference = ((PsiNewExpression) call).getClassReference(); + LOG.assertTrue(classReference != null); + final PsiNewExpression newExpr = + (PsiNewExpression) factory.createExpressionFromText( + "new " + newQualifier.getText() + "." + classReference.getText() + "()", + classReference + ); + final PsiExpressionList callArgs = call.getArgumentList(); + if (callArgs != null) { + final PsiExpressionList argumentList = newExpr.getArgumentList(); + LOG.assertTrue(argumentList != null); + argumentList.replace(callArgs); + } + call.replace(newExpr); + } + } } - } - } - } - - protected MultiMap getConflictDescriptions(final UsageInfo[] usages) { - final MultiMap conflicts = super.getConflictDescriptions(usages); - - //Check fields already exist - if (mySettings.isMakeClassParameter()) { - final String fieldName = convertToFieldName(mySettings.getClassParameterName()); - final PsiField existing = myMember.findFieldByName(fieldName, false); - if (existing != null) { - LocalizeValue message = RefactoringLocalize.thereIsAlreadyA0In1( - RefactoringUIUtil.getDescription(existing, false), - RefactoringUIUtil.getDescription(myMember, false) - ); - conflicts.putValue(existing, message.get()); - } } - if (mySettings.isMakeFieldParameters()) { - final List parameterOrderList = mySettings.getParameterOrderList(); - for (Settings.FieldParameter parameter : parameterOrderList) { - final String fieldName = convertToFieldName(parameter.name); - final PsiField existing = myMember.findFieldByName(fieldName, false); - - if (existing != null) { - LocalizeValue message = RefactoringLocalize.thereIsAlreadyA0In1( - RefactoringUIUtil.getDescription(existing, false), - RefactoringUIUtil.getDescription(myMember, false) - ); - conflicts.putValue(existing, message.get()); + @Override + @RequiredReadAction + protected MultiMap getConflictDescriptions(UsageInfo[] usages) { + MultiMap conflicts = super.getConflictDescriptions(usages); + + //Check fields already exist + if (mySettings.isMakeClassParameter()) { + final String fieldName = convertToFieldName(mySettings.getClassParameterName()); + final PsiField existing = myMember.findFieldByName(fieldName, false); + if (existing != null) { + LocalizeValue message = RefactoringLocalize.thereIsAlreadyA0In1( + RefactoringUIUtil.getDescription(existing, false), + RefactoringUIUtil.getDescription(myMember, false) + ); + conflicts.putValue(existing, message); + } } - } + + if (mySettings.isMakeFieldParameters()) { + final List parameterOrderList = mySettings.getParameterOrderList(); + for (Settings.FieldParameter parameter : parameterOrderList) { + final String fieldName = convertToFieldName(parameter.name); + final PsiField existing = myMember.findFieldByName(fieldName, false); + + if (existing != null) { + LocalizeValue message = RefactoringLocalize.thereIsAlreadyA0In1( + RefactoringUIUtil.getDescription(existing, false), + RefactoringUIUtil.getDescription(myMember, false) + ); + conflicts.putValue(existing, message); + } + } + } + + return conflicts; } - return conflicts; - } - - protected void findExternalUsages(final ArrayList result) { - PsiMethod[] constructors = myMember.getConstructors(); - if (constructors.length > 0) { - for (PsiMethod constructor : constructors) { - findExternalReferences(constructor, result); - } - } else { - findDefaultConstructorReferences(result); + @Override + @RequiredReadAction + protected void findExternalUsages(List result) { + PsiMethod[] constructors = myMember.getConstructors(); + if (constructors.length > 0) { + for (PsiMethod constructor : constructors) { + findExternalReferences(constructor, result); + } + } + else { + findDefaultConstructorReferences(result); + } } - } - - private void findDefaultConstructorReferences(final ArrayList result) { - for (PsiReference ref : ReferencesSearch.search(myMember)) { - PsiElement element = ref.getElement(); - if (element.getParent() instanceof PsiNewExpression) { - PsiNewExpression newExpression = (PsiNewExpression)element.getParent(); - PsiElement qualifier = newExpression.getQualifier(); - if (qualifier instanceof PsiThisExpression) qualifier = null; - if (!PsiTreeUtil.isAncestor(myMember, element, true) || qualifier != null) { - result.add(new UsageInfo(element)); - } else { - result.add(new InternalUsageInfo(element, myMember)); + + private void findDefaultConstructorReferences(List result) { + for (PsiReference ref : ReferencesSearch.search(myMember)) { + PsiElement element = ref.getElement(); + if (element.getParent() instanceof PsiNewExpression) { + PsiNewExpression newExpression = (PsiNewExpression) element.getParent(); + PsiElement qualifier = newExpression.getQualifier(); + if (qualifier instanceof PsiThisExpression) { + qualifier = null; + } + if (!PsiTreeUtil.isAncestor(myMember, element, true) || qualifier != null) { + result.add(new UsageInfo(element)); + } + else { + result.add(new InternalUsageInfo(element, myMember)); + } + } } - } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodStaticProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodStaticProcessor.java index f9a9704418..cdbcb531f7 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodStaticProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodStaticProcessor.java @@ -21,6 +21,8 @@ import com.intellij.java.language.psi.javadoc.PsiDocTag; import com.intellij.java.language.psi.util.InheritanceUtil; import com.intellij.java.language.psi.util.PsiUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.codeStyle.CodeStyleManager; import consulo.language.psi.PsiElement; import consulo.language.psi.util.PsiTreeUtil; @@ -36,218 +38,225 @@ * @author dsl */ public class MakeMethodStaticProcessor extends MakeMethodOrClassStaticProcessor { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeMethodStaticProcessor"); - - public MakeMethodStaticProcessor(final Project project, final PsiMethod method, final Settings settings) { - super(project, method, settings); - } - - protected void changeSelfUsage(SelfUsageInfo usageInfo) throws IncorrectOperationException { - PsiElement parent = usageInfo.getElement().getParent(); - LOG.assertTrue(parent instanceof PsiMethodCallExpression); - PsiMethodCallExpression methodCall = (PsiMethodCallExpression) parent; - final PsiExpression qualifier = methodCall.getMethodExpression().getQualifierExpression(); - if (qualifier != null) qualifier.delete(); - - PsiElementFactory factory = JavaPsiFacade.getInstance(methodCall.getProject()).getElementFactory(); - PsiExpressionList args = methodCall.getArgumentList(); - PsiElement addParameterAfter = null; - - if(mySettings.isMakeClassParameter()) { - PsiElement arg = factory.createExpressionFromText(mySettings.getClassParameterName(), null); - addParameterAfter = args.addAfter(arg, null); + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeMethodStaticProcessor"); + + public MakeMethodStaticProcessor(Project project, PsiMethod method, Settings settings) { + super(project, method, settings); } - if(mySettings.isMakeFieldParameters()) { - List parameters = mySettings.getParameterOrderList(); - for (Settings.FieldParameter fieldParameter : parameters) { - PsiElement arg = factory.createExpressionFromText(fieldParameter.name, null); - if (addParameterAfter == null) { - addParameterAfter = args.addAfter(arg, null); - } - else { - addParameterAfter = args.addAfter(arg, addParameterAfter); + @Override + @RequiredWriteAction + protected void changeSelfUsage(SelfUsageInfo usageInfo) throws IncorrectOperationException { + PsiElement parent = usageInfo.getElement().getParent(); + LOG.assertTrue(parent instanceof PsiMethodCallExpression); + PsiMethodCallExpression methodCall = (PsiMethodCallExpression) parent; + PsiExpression qualifier = methodCall.getMethodExpression().getQualifierExpression(); + if (qualifier != null) { + qualifier.delete(); } - } - } - } - - protected void changeSelf(PsiElementFactory factory, UsageInfo[] usages) - throws IncorrectOperationException { - final MethodJavaDocHelper javaDocHelper = new MethodJavaDocHelper(myMember); - PsiParameterList paramList = myMember.getParameterList(); - PsiElement addParameterAfter = null; - PsiDocTag anchor = null; - List addedTypes = new ArrayList(); - - if (mySettings.isMakeClassParameter()) { - // Add parameter for object - PsiType parameterType = factory.createType(myMember.getContainingClass(), PsiSubstitutor.EMPTY); - addedTypes.add(parameterType); - - final String classParameterName = mySettings.getClassParameterName(); - PsiParameter parameter = factory.createParameter(classParameterName, parameterType); - if(makeClassParameterFinal(usages)) { - PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, true); - } - addParameterAfter = paramList.addAfter(parameter, null); - anchor = javaDocHelper.addParameterAfter(classParameterName, anchor); - } - if (mySettings.isMakeFieldParameters()) { - List parameters = mySettings.getParameterOrderList(); + PsiElementFactory factory = JavaPsiFacade.getInstance(methodCall.getProject()).getElementFactory(); + PsiExpressionList args = methodCall.getArgumentList(); + PsiElement addParameterAfter = null; - for (Settings.FieldParameter fieldParameter : parameters) { - final PsiType fieldParameterType = fieldParameter.field.getType(); - final PsiParameter parameter = factory.createParameter(fieldParameter.name, fieldParameterType); - addedTypes.add(fieldParameterType); - if (makeFieldParameterFinal(fieldParameter.field, usages)) { - PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, true); + if (mySettings.isMakeClassParameter()) { + PsiElement arg = factory.createExpressionFromText(mySettings.getClassParameterName(), null); + addParameterAfter = args.addAfter(arg, null); + } + + if (mySettings.isMakeFieldParameters()) { + List parameters = mySettings.getParameterOrderList(); + for (Settings.FieldParameter fieldParameter : parameters) { + PsiElement arg = factory.createExpressionFromText(fieldParameter.name, null); + if (addParameterAfter == null) { + addParameterAfter = args.addAfter(arg, null); + } + else { + addParameterAfter = args.addAfter(arg, addParameterAfter); + } + } } - addParameterAfter = paramList.addAfter(parameter, addParameterAfter); - anchor = javaDocHelper.addParameterAfter(fieldParameter.name, anchor); - } - } - setupTypeParameterList(); - // Add static modifier - final PsiModifierList modifierList = myMember.getModifierList(); - modifierList.setModifierProperty(PsiModifier.STATIC, true); - modifierList.setModifierProperty(PsiModifier.FINAL, false); - } - - protected void changeInternalUsage(InternalUsageInfo usage, PsiElementFactory factory) - throws IncorrectOperationException { - if (!mySettings.isChangeSignature()) return; - - PsiElement element = usage.getElement(); - - if (element instanceof PsiReferenceExpression) { - PsiReferenceExpression newRef = null; - - if (mySettings.isMakeFieldParameters()) { - PsiElement resolved = ((PsiReferenceExpression) element).resolve(); - if (resolved instanceof PsiField) { - String name = mySettings.getNameForField((PsiField) resolved); - if (name != null) { - newRef = (PsiReferenceExpression) factory.createExpressionFromText(name, null); - } - } - } - - if (newRef == null && mySettings.isMakeClassParameter()) { - newRef = - (PsiReferenceExpression) factory.createExpressionFromText( - mySettings.getClassParameterName() + "." + element.getText(), null); - } - - if (newRef != null) { - CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject); - newRef = (PsiReferenceExpression) codeStyleManager.reformat(newRef); - element.replace(newRef); - } - } - else if (element instanceof PsiThisExpression && mySettings.isMakeClassParameter()) { - element.replace(factory.createExpressionFromText(mySettings.getClassParameterName(), null)); - } - else if (element instanceof PsiSuperExpression && mySettings.isMakeClassParameter()) { - element.replace(factory.createExpressionFromText(mySettings.getClassParameterName(), null)); - } - else if (element instanceof PsiNewExpression && mySettings.isMakeClassParameter()) { - final PsiNewExpression newExpression = ((PsiNewExpression)element); - LOG.assertTrue(newExpression.getQualifier() == null); - final String newText = mySettings.getClassParameterName() + "." + newExpression.getText(); - final PsiExpression expr = factory.createExpressionFromText(newText, null); - element.replace(expr); - } - } - - protected void changeExternalUsage(UsageInfo usage, PsiElementFactory factory) - throws IncorrectOperationException { - final PsiElement element = usage.getElement(); - if (!(element instanceof PsiReferenceExpression)) return; - - PsiReferenceExpression methodRef = (PsiReferenceExpression) element; - PsiElement parent = methodRef.getParent(); - - PsiExpression instanceRef; - - instanceRef = methodRef.getQualifierExpression(); - PsiElement newQualifier; - - final PsiClass memberClass = myMember.getContainingClass(); - if (instanceRef == null || instanceRef instanceof PsiSuperExpression) { - PsiClass contextClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); - if (!InheritanceUtil.isInheritorOrSelf(contextClass, memberClass, true)) { - instanceRef = factory.createExpressionFromText(memberClass.getQualifiedName() + ".this", null); - } else { - instanceRef = factory.createExpressionFromText("this", null); - } - newQualifier = null; - } - else { - newQualifier = factory.createReferenceExpression(memberClass); } - if (mySettings.getNewParametersNumber() > 1) { - int copyingSafetyLevel = RefactoringUtil.verifySafeCopyExpression(instanceRef); - if (copyingSafetyLevel == RefactoringUtil.EXPR_COPY_PROHIBITED) { - String tempVar = RefactoringUtil.createTempVar(instanceRef, parent, true); - instanceRef = factory.createExpressionFromText(tempVar, null); - } + @Override + @RequiredWriteAction + protected void changeSelf(PsiElementFactory factory, UsageInfo[] usages) + throws IncorrectOperationException { + MethodJavaDocHelper javaDocHelper = new MethodJavaDocHelper(myMember); + PsiParameterList paramList = myMember.getParameterList(); + PsiElement addParameterAfter = null; + PsiDocTag anchor = null; + List addedTypes = new ArrayList<>(); + + if (mySettings.isMakeClassParameter()) { + // Add parameter for object + PsiType parameterType = factory.createType(myMember.getContainingClass(), PsiSubstitutor.EMPTY); + addedTypes.add(parameterType); + + String classParameterName = mySettings.getClassParameterName(); + PsiParameter parameter = factory.createParameter(classParameterName, parameterType); + if (makeClassParameterFinal(usages)) { + PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, true); + } + addParameterAfter = paramList.addAfter(parameter, null); + anchor = javaDocHelper.addParameterAfter(classParameterName, anchor); + } + + if (mySettings.isMakeFieldParameters()) { + List parameters = mySettings.getParameterOrderList(); + + for (Settings.FieldParameter fieldParameter : parameters) { + PsiType fieldParameterType = fieldParameter.field.getType(); + PsiParameter parameter = factory.createParameter(fieldParameter.name, fieldParameterType); + addedTypes.add(fieldParameterType); + if (makeFieldParameterFinal(fieldParameter.field, usages)) { + PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, true); + } + addParameterAfter = paramList.addAfter(parameter, addParameterAfter); + anchor = javaDocHelper.addParameterAfter(fieldParameter.name, anchor); + } + } + setupTypeParameterList(); + // Add static modifier + PsiModifierList modifierList = myMember.getModifierList(); + modifierList.setModifierProperty(PsiModifier.STATIC, true); + modifierList.setModifierProperty(PsiModifier.FINAL, false); } + @Override + @RequiredWriteAction + protected void changeInternalUsage(InternalUsageInfo usage, PsiElementFactory factory) + throws IncorrectOperationException { + if (!mySettings.isChangeSignature()) { + return; + } - PsiElement anchor = null; - PsiExpressionList argList = null; - PsiExpression[] exprs = new PsiExpression[0]; - if (parent instanceof PsiMethodCallExpression) { - argList = ((PsiMethodCallExpression)parent).getArgumentList(); - exprs = argList.getExpressions(); - if (mySettings.isMakeClassParameter()) { - if (exprs.length > 0) { - anchor = argList.addBefore(instanceRef, exprs[0]); + PsiElement element = usage.getElement(); + + if (element instanceof PsiReferenceExpression refExpr) { + PsiReferenceExpression newRef = null; + + if (mySettings.isMakeFieldParameters() && refExpr.resolve() instanceof PsiField field) { + String name = mySettings.getNameForField(field); + if (name != null) { + newRef = (PsiReferenceExpression) factory.createExpressionFromText(name, null); + } + } + + if (newRef == null && mySettings.isMakeClassParameter()) { + newRef = + (PsiReferenceExpression) factory.createExpressionFromText( + mySettings.getClassParameterName() + "." + refExpr.getText(), null); + } + + if (newRef != null) { + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject); + newRef = (PsiReferenceExpression) codeStyleManager.reformat(newRef); + element.replace(newRef); + } } - else { - anchor = argList.add(instanceRef); + else if (element instanceof PsiThisExpression && mySettings.isMakeClassParameter()) { + element.replace(factory.createExpressionFromText(mySettings.getClassParameterName(), null)); + } + else if (element instanceof PsiSuperExpression && mySettings.isMakeClassParameter()) { + element.replace(factory.createExpressionFromText(mySettings.getClassParameterName(), null)); + } + else if (element instanceof PsiNewExpression newExpression && mySettings.isMakeClassParameter()) { + LOG.assertTrue(newExpression.getQualifier() == null); + String newText = mySettings.getClassParameterName() + "." + newExpression.getText(); + PsiExpression expr = factory.createExpressionFromText(newText, null); + newExpression.replace(expr); } - } } + @Override + @RequiredWriteAction + protected void changeExternalUsage(UsageInfo usage, PsiElementFactory factory) + throws IncorrectOperationException { + if (!(usage.getElement() instanceof PsiReferenceExpression methodRef)) { + return; + } + + PsiElement parent = methodRef.getParent(); - if (mySettings.isMakeFieldParameters()) { - List parameters = mySettings.getParameterOrderList(); + PsiExpression instanceRef; - for (Settings.FieldParameter fieldParameter : parameters) { - PsiReferenceExpression fieldRef; - if (newQualifier != null) { - fieldRef = (PsiReferenceExpression)factory.createExpressionFromText( - "a." + fieldParameter.field.getName(), null); - fieldRef.getQualifierExpression().replace(instanceRef); + instanceRef = methodRef.getQualifierExpression(); + PsiElement newQualifier; + + PsiClass memberClass = myMember.getContainingClass(); + if (instanceRef == null || instanceRef instanceof PsiSuperExpression) { + PsiClass contextClass = PsiTreeUtil.getParentOfType(methodRef, PsiClass.class); + if (!InheritanceUtil.isInheritorOrSelf(contextClass, memberClass, true)) { + instanceRef = factory.createExpressionFromText(memberClass.getQualifiedName() + ".this", null); + } + else { + instanceRef = factory.createExpressionFromText("this", null); + } + newQualifier = null; } else { - fieldRef = (PsiReferenceExpression)factory.createExpressionFromText(fieldParameter.field.getName(), null); + newQualifier = factory.createReferenceExpression(memberClass); } - if (anchor != null) { - anchor = argList.addAfter(fieldRef, anchor); + if (mySettings.getNewParametersNumber() > 1) { + int copyingSafetyLevel = RefactoringUtil.verifySafeCopyExpression(instanceRef); + if (copyingSafetyLevel == RefactoringUtil.EXPR_COPY_PROHIBITED) { + String tempVar = RefactoringUtil.createTempVar(instanceRef, parent, true); + instanceRef = factory.createExpressionFromText(tempVar, null); + } + } + + PsiElement anchor = null; + PsiExpressionList argList = null; + PsiExpression[] exprs = new PsiExpression[0]; + if (parent instanceof PsiMethodCallExpression call) { + argList = call.getArgumentList(); + exprs = argList.getExpressions(); + if (mySettings.isMakeClassParameter()) { + if (exprs.length > 0) { + anchor = argList.addBefore(instanceRef, exprs[0]); + } + else { + anchor = argList.add(instanceRef); + } + } + } + + if (mySettings.isMakeFieldParameters()) { + List parameters = mySettings.getParameterOrderList(); + + for (Settings.FieldParameter fieldParameter : parameters) { + PsiReferenceExpression fieldRef; + if (newQualifier != null) { + fieldRef = (PsiReferenceExpression) factory.createExpressionFromText( + "a." + fieldParameter.field.getName(), null); + fieldRef.getQualifierExpression().replace(instanceRef); + } + else { + fieldRef = (PsiReferenceExpression) factory.createExpressionFromText(fieldParameter.field.getName(), null); + } + + if (anchor != null) { + anchor = argList.addAfter(fieldRef, anchor); + } + else if (exprs.length > 0) { + anchor = argList.addBefore(fieldRef, exprs[0]); + } + else { + anchor = argList.add(fieldRef); + } + } } - else { - if (exprs.length > 0) { - anchor = argList.addBefore(fieldRef, exprs[0]); - } - else { - anchor = argList.add(fieldRef); - } - } - } - } - if (newQualifier != null) { - methodRef.getQualifierExpression().replace(newQualifier); + if (newQualifier != null) { + methodRef.getQualifierExpression().replace(newQualifier); + } } - } - protected void findExternalUsages(final ArrayList result) { - findExternalReferences(myMember, result); - } + @Override + @RequiredReadAction + protected void findExternalUsages(List result) { + findExternalReferences(myMember, result); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHandler.java index e6b9a2b7fa..a5ddcb6f69 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHandler.java @@ -13,252 +13,223 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * Created by IntelliJ IDEA. - * User: dsl - * Date: 18.06.2002 - * Time: 12:45:30 - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.java.impl.refactoring.memberPullUp; -import java.util.ArrayList; -import java.util.List; - -import consulo.application.Application; -import consulo.language.editor.refactoring.localize.RefactoringLocalize; -import consulo.localize.LocalizeValue; -import jakarta.annotation.Nonnull; - +import com.intellij.java.impl.refactoring.HelpID; +import com.intellij.java.impl.refactoring.util.RefactoringHierarchyUtil; +import com.intellij.java.impl.refactoring.util.classMembers.MemberInfo; +import com.intellij.java.impl.refactoring.util.classMembers.MemberInfoStorage; import com.intellij.java.language.psi.*; -import consulo.dataContext.DataContext; +import consulo.application.Application; +import consulo.application.progress.ProgressManager; import consulo.codeEditor.Editor; import consulo.codeEditor.ScrollType; -import consulo.application.progress.ProgressManager; -import consulo.project.Project; -import consulo.ui.ex.awt.DialogWrapper; -import consulo.language.psi.*; -import com.intellij.java.impl.refactoring.HelpID; +import consulo.dataContext.DataContext; +import consulo.language.editor.refactoring.ElementsHandler; import consulo.language.editor.refactoring.action.RefactoringActionHandler; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.classMember.MemberInfoBase; -import consulo.language.editor.refactoring.ElementsHandler; +import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.ui.ConflictsDialog; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; -import com.intellij.java.impl.refactoring.util.RefactoringHierarchyUtil; -import com.intellij.java.impl.refactoring.util.classMembers.MemberInfo; -import com.intellij.java.impl.refactoring.util.classMembers.MemberInfoStorage; +import consulo.language.psi.PsiDirectory; +import consulo.language.psi.PsiElement; +import consulo.language.psi.PsiFile; +import consulo.language.psi.PsiManager; +import consulo.localize.LocalizeValue; +import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; +import consulo.ui.ex.awt.DialogWrapper; import consulo.util.collection.MultiMap; -import consulo.logging.Logger; - -public class JavaPullUpHandler implements RefactoringActionHandler, PullUpDialog.Callback, ElementsHandler -{ - private static final Logger LOG = Logger.getInstance(JavaPullUpHandler.class); - public static final String REFACTORING_NAME = RefactoringBundle.message("pull.members.up.title"); - private PsiClass mySubclass; - private Project myProject; - - @Override - public void invoke(@Nonnull Project project, Editor editor, PsiFile file, DataContext dataContext) - { - int offset = editor.getCaretModel().getOffset(); - editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - PsiElement element = file.findElementAt(offset); - - while (true) - { - if (element == null || element instanceof PsiFile) - { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.theCaretShouldBePositionedInsideAClassToPullMembersFrom() - ); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.MEMBERS_PULL_UP); - return; - } - - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, element)) - { - return; - } - - if (element instanceof PsiClass || element instanceof PsiField || element instanceof PsiMethod) - { - invoke(project, new PsiElement[]{element}, dataContext); - return; - } - element = element.getParent(); - } - } - - @Override - public void invoke(@Nonnull final Project project, @Nonnull PsiElement[] elements, DataContext dataContext) - { - if (elements.length != 1) - { - return; - } - myProject = project; - - PsiElement element = elements[0]; - PsiClass aClass; - PsiElement aMember = null; - - if (element instanceof PsiClass psiClass) - { - aClass = psiClass; - } - else if (element instanceof PsiMethod method) - { - aClass = method.getContainingClass(); - aMember = element; - } - else if (element instanceof PsiField field) - { - aClass = field.getContainingClass(); - aMember = element; - } - else - { - return; - } - - invoke(project, dataContext, aClass, aMember); - } - - private void invoke(Project project, DataContext dataContext, PsiClass aClass, PsiElement aMember) - { - final Editor editor = dataContext != null ? dataContext.getData(Editor.KEY) : null; - if (aClass == null) - { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.isNotSupportedInTheCurrentContext(REFACTORING_NAME) - ); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.MEMBERS_PULL_UP); - return; - } - - ArrayList bases = RefactoringHierarchyUtil.createBasesList(aClass, false, true); - - if (bases.isEmpty()) - { - final PsiClass containingClass = aClass.getContainingClass(); - if (containingClass != null) - { - invoke(project, dataContext, containingClass, aClass); - return; - } - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.classDoesNotHaveBaseClassesInterfacesInCurrentProject(aClass.getQualifiedName()) - ); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.MEMBERS_PULL_UP); - return; - } - - - mySubclass = aClass; - MemberInfoStorage memberInfoStorage = new MemberInfoStorage(mySubclass, element -> true); - List members = memberInfoStorage.getClassMemberInfos(mySubclass); - PsiManager manager = mySubclass.getManager(); +import jakarta.annotation.Nonnull; - for (MemberInfoBase member : members) - { - if (manager.areElementsEquivalent(member.getMember(), aMember)) - { - member.setChecked(true); - break; - } - } +import java.util.ArrayList; +import java.util.List; - final PullUpDialog dialog = new PullUpDialog(project, aClass, bases, memberInfoStorage, this); +/** + * @author dsl + * @since 2002-06-18 + */ +public class JavaPullUpHandler implements RefactoringActionHandler, PullUpDialog.Callback, ElementsHandler { + public static final LocalizeValue REFACTORING_NAME = RefactoringLocalize.pullMembersUpTitle(); + private PsiClass mySubclass; + private Project myProject; + + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, Editor editor, PsiFile file, DataContext dataContext) { + int offset = editor.getCaretModel().getOffset(); + editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + PsiElement element = file.findElementAt(offset); + + while (true) { + if (element == null || element instanceof PsiFile) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.theCaretShouldBePositionedInsideAClassToPullMembersFrom() + ); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.MEMBERS_PULL_UP); + return; + } + + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, element)) { + return; + } + + if (element instanceof PsiClass || element instanceof PsiField || element instanceof PsiMethod) { + invoke(project, new PsiElement[]{element}, dataContext); + return; + } + element = element.getParent(); + } + } - dialog.show(); - } + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { + if (elements.length != 1) { + return; + } + myProject = project; + + PsiElement element = elements[0]; + PsiClass aClass; + PsiElement aMember = null; + + if (element instanceof PsiClass psiClass) { + aClass = psiClass; + } + else if (element instanceof PsiMethod method) { + aClass = method.getContainingClass(); + aMember = element; + } + else if (element instanceof PsiField field) { + aClass = field.getContainingClass(); + aMember = element; + } + else { + return; + } + + invoke(project, dataContext, aClass, aMember); + } - @Override - public boolean checkConflicts(final PullUpDialog dialog) - { - final List infos = dialog.getSelectedMemberInfos(); - final MemberInfo[] memberInfos = infos.toArray(new MemberInfo[infos.size()]); - final PsiClass superClass = dialog.getSuperClass(); - if (!checkWritable(superClass, memberInfos)) - { - return false; - } - final MultiMap conflicts = new MultiMap<>(); - if (!ProgressManager.getInstance().runProcessWithProgressSynchronously( - () -> Application.get().runReadAction(() -> { - final PsiDirectory targetDirectory = superClass.getContainingFile().getContainingDirectory(); - final PsiJavaPackage targetPackage = - targetDirectory != null ? JavaDirectoryService.getInstance().getPackage(targetDirectory) : null; - conflicts.putAllValues(PullUpConflictsUtil.checkConflicts( - memberInfos, - mySubclass, - superClass, - targetPackage, - targetDirectory, - dialog.getContainmentVerifier() - )); - }), - RefactoringLocalize.detectingPossibleConflicts().get(), - true, - myProject - )) - { - return false; - } - if (!conflicts.isEmpty()) - { - ConflictsDialog conflictsDialog = new ConflictsDialog(myProject, conflicts); - conflictsDialog.show(); - final boolean ok = conflictsDialog.isOK(); - if (!ok && conflictsDialog.isShowConflicts()) - { - dialog.close(DialogWrapper.CANCEL_EXIT_CODE); - } - return ok; - } - return true; - } + @RequiredUIAccess + private void invoke(Project project, DataContext dataContext, PsiClass aClass, PsiElement aMember) { + Editor editor = dataContext != null ? dataContext.getData(Editor.KEY) : null; + if (aClass == null) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.isNotSupportedInTheCurrentContext(REFACTORING_NAME) + ); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.MEMBERS_PULL_UP); + return; + } + + List bases = RefactoringHierarchyUtil.createBasesList(aClass, false, true); + + if (bases.isEmpty()) { + PsiClass containingClass = aClass.getContainingClass(); + if (containingClass != null) { + invoke(project, dataContext, containingClass, aClass); + return; + } + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.classDoesNotHaveBaseClassesInterfacesInCurrentProject(aClass.getQualifiedName()) + ); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.MEMBERS_PULL_UP); + return; + } + + + mySubclass = aClass; + MemberInfoStorage memberInfoStorage = new MemberInfoStorage(mySubclass, element -> true); + List members = memberInfoStorage.getClassMemberInfos(mySubclass); + PsiManager manager = mySubclass.getManager(); + + for (MemberInfoBase member : members) { + if (manager.areElementsEquivalent(member.getMember(), aMember)) { + member.setChecked(true); + break; + } + } + + PullUpDialog dialog = new PullUpDialog(project, aClass, bases, memberInfoStorage, this); + + dialog.show(); + } - private boolean checkWritable(PsiClass superClass, MemberInfo[] infos) - { - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, superClass)) - { - return false; - } - for (MemberInfo info : infos) - { - if (info.getMember() instanceof PsiClass && info.getOverrides() != null) - { - continue; - } - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, info.getMember())) - { - return false; - } - } - return true; - } + @Override + @RequiredUIAccess + public boolean checkConflicts(PullUpDialog dialog) { + List infos = dialog.getSelectedMemberInfos(); + MemberInfo[] memberInfos = infos.toArray(new MemberInfo[infos.size()]); + PsiClass superClass = dialog.getSuperClass(); + if (!checkWritable(superClass, memberInfos)) { + return false; + } + MultiMap conflicts = new MultiMap<>(); + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously( + () -> Application.get().runReadAction(() -> { + PsiDirectory targetDirectory = superClass.getContainingFile().getContainingDirectory(); + PsiJavaPackage targetPackage = + targetDirectory != null ? JavaDirectoryService.getInstance().getPackage(targetDirectory) : null; + conflicts.putAllValues(PullUpConflictsUtil.checkConflicts( + memberInfos, + mySubclass, + superClass, + targetPackage, + targetDirectory, + dialog.getContainmentVerifier() + )); + }), + RefactoringLocalize.detectingPossibleConflicts(), + true, + myProject + )) { + return false; + } + if (!conflicts.isEmpty()) { + ConflictsDialog conflictsDialog = new ConflictsDialog(myProject, conflicts); + conflictsDialog.show(); + boolean ok = conflictsDialog.isOK(); + if (!ok && conflictsDialog.isShowConflicts()) { + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } + return ok; + } + return true; + } - @Override - public boolean isEnabledOnElements(PsiElement[] elements) - { - /* - if (elements.length == 1) { - return elements[0] instanceof PsiClass || elements[0] instanceof PsiField || elements[0] instanceof PsiMethod; + @RequiredUIAccess + private boolean checkWritable(PsiClass superClass, MemberInfo[] infos) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, superClass)) { + return false; + } + for (MemberInfo info : infos) { + if (info.getMember() instanceof PsiClass && info.getOverrides() != null) { + continue; + } + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, info.getMember())) { + return false; + } + } + return true; } - else if (elements.length > 1){ - for (int idx = 0; idx < elements.length; idx++) { - PsiElement element = elements[idx]; - if (!(element instanceof PsiField || element instanceof PsiMethod)) return false; - } - return true; + + @Override + public boolean isEnabledOnElements(PsiElement[] elements) { + /* + if (elements.length == 1) { + return elements[0] instanceof PsiClass || elements[0] instanceof PsiField || elements[0] instanceof PsiMethod; + } + else if (elements.length > 1){ + for (int idx = 0; idx < elements.length; idx++) { + PsiElement element = elements[idx]; + if (!(element instanceof PsiField || element instanceof PsiMethod)) return false; + } + return true; + } + return false; + */ + // todo: multiple selection etc + return elements.length == 1 && elements[0] instanceof PsiClass; } - return false; - */ - // todo: multiple selection etc - return elements.length == 1 && elements[0] instanceof PsiClass; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpConflictsUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpConflictsUtil.java index dcfa405410..b7f72c20bd 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpConflictsUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpConflictsUtil.java @@ -13,15 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * Created by IntelliJ IDEA. - * User: dsl - * Date: 17.06.2002 - * Time: 15:40:16 - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.java.impl.refactoring.memberPullUp; import com.intellij.java.impl.refactoring.util.RefactoringConflictsUtil; @@ -57,336 +48,408 @@ import java.util.List; import java.util.Set; +/** + * @author dsl + * @since 2002-06-17 + */ public class PullUpConflictsUtil { - private PullUpConflictsUtil() {} - - public static MultiMap checkConflicts(final MemberInfo[] infos, - PsiClass subclass, - @Nullable PsiClass superClass, - @Nonnull PsiJavaPackage targetPackage, - @Nonnull PsiDirectory targetDirectory, - final InterfaceContainmentVerifier interfaceContainmentVerifier) { - return checkConflicts(infos, subclass, superClass, targetPackage, targetDirectory, interfaceContainmentVerifier, true); - } - - public static MultiMap checkConflicts(final MemberInfo[] infos, - @Nonnull final PsiClass subclass, - @Nullable PsiClass superClass, - @Nonnull final PsiJavaPackage targetPackage, - @Nonnull PsiDirectory targetDirectory, - final InterfaceContainmentVerifier interfaceContainmentVerifier, - boolean movedMembers2Super) { - final Set movedMembers = new HashSet(); - final Set abstractMethods = new HashSet(); - final boolean isInterfaceTarget; - final PsiElement targetRepresentativeElement; - if (superClass != null) { - isInterfaceTarget = superClass.isInterface(); - targetRepresentativeElement = superClass; + private PullUpConflictsUtil() { } - else { - isInterfaceTarget = false; - targetRepresentativeElement = targetDirectory; + + public static MultiMap checkConflicts( + final MemberInfo[] infos, + PsiClass subclass, + @Nullable PsiClass superClass, + @Nonnull PsiJavaPackage targetPackage, + @Nonnull PsiDirectory targetDirectory, + final InterfaceContainmentVerifier interfaceContainmentVerifier + ) { + return checkConflicts(infos, subclass, superClass, targetPackage, targetDirectory, interfaceContainmentVerifier, true); } - for (MemberInfo info : infos) { - PsiMember member = info.getMember(); - if (member instanceof PsiMethod) { - if (!info.isToAbstract() && !isInterfaceTarget) { - movedMembers.add(member); + + public static MultiMap checkConflicts( + final MemberInfo[] infos, + @Nonnull final PsiClass subclass, + @Nullable PsiClass superClass, + @Nonnull final PsiJavaPackage targetPackage, + @Nonnull PsiDirectory targetDirectory, + final InterfaceContainmentVerifier interfaceContainmentVerifier, + boolean movedMembers2Super + ) { + final Set movedMembers = new HashSet(); + final Set abstractMethods = new HashSet(); + final boolean isInterfaceTarget; + final PsiElement targetRepresentativeElement; + if (superClass != null) { + isInterfaceTarget = superClass.isInterface(); + targetRepresentativeElement = superClass; } else { - abstractMethods.add((PsiMethod)member); + isInterfaceTarget = false; + targetRepresentativeElement = targetDirectory; } - } - else { - movedMembers.add(member); - } - } - final MultiMap conflicts = new MultiMap(); - final Set abstrMethods = new HashSet(abstractMethods); - if (superClass != null) { - for (PsiMethod method : subclass.getMethods()) { - if (!movedMembers.contains(method) && !method.hasModifierProperty(PsiModifier.PRIVATE)) { - if (method.findSuperMethods(superClass).length > 0) { - abstrMethods.add(method); - } + for (MemberInfo info : infos) { + PsiMember member = info.getMember(); + if (member instanceof PsiMethod) { + if (!info.isToAbstract() && !isInterfaceTarget) { + movedMembers.add(member); + } + else { + abstractMethods.add((PsiMethod) member); + } + } + else { + movedMembers.add(member); + } } - } - } - RefactoringConflictsUtil.analyzeAccessibilityConflicts(movedMembers, superClass, conflicts, VisibilityUtil.ESCALATE_VISIBILITY, targetRepresentativeElement, abstrMethods); - if (superClass != null) { - if (movedMembers2Super) { - checkSuperclassMembers(superClass, infos, conflicts); - if (isInterfaceTarget) { - checkInterfaceTarget(infos, conflicts); + final MultiMap conflicts = new MultiMap<>(); + final Set abstrMethods = new HashSet(abstractMethods); + if (superClass != null) { + for (PsiMethod method : subclass.getMethods()) { + if (!movedMembers.contains(method) && !method.hasModifierProperty(PsiModifier.PRIVATE)) { + if (method.findSuperMethods(superClass).length > 0) { + abstrMethods.add(method); + } + } + } } - } else { - final String qualifiedName = superClass.getQualifiedName(); - assert qualifiedName != null; - if (superClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { - if (!Comparing.strEqual(StringUtil.getPackageName(qualifiedName), targetPackage.getQualifiedName())) { - conflicts.putValue(superClass, RefactoringUIUtil.getDescription(superClass, true) + " won't be accessible from " +RefactoringUIUtil.getDescription(targetPackage, true)); - } + RefactoringConflictsUtil.analyzeAccessibilityConflicts( + movedMembers, + superClass, + conflicts, + VisibilityUtil.ESCALATE_VISIBILITY, + targetRepresentativeElement, + abstrMethods + ); + if (superClass != null) { + if (movedMembers2Super) { + checkSuperclassMembers(superClass, infos, conflicts); + if (isInterfaceTarget) { + checkInterfaceTarget(infos, conflicts); + } + } + else { + final String qualifiedName = superClass.getQualifiedName(); + assert qualifiedName != null; + if (superClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { + if (!Comparing.strEqual(StringUtil.getPackageName(qualifiedName), targetPackage.getQualifiedName())) { + conflicts.putValue( + superClass, + LocalizeValue.localizeTODO( + RefactoringUIUtil.getDescription(superClass, true) + " won't be accessible from " + + RefactoringUIUtil.getDescription(targetPackage, true) + ) + ); + } + } + } } - } - } - // check if moved methods use other members in the classes between Subclass and Superclass - List checkModuleConflictsList = new ArrayList(); - for (PsiMember member : movedMembers) { - if (member instanceof PsiMethod || member instanceof PsiClass && !(member instanceof PsiCompiledElement)) { - ClassMemberReferencesVisitor visitor = - movedMembers2Super? new ConflictingUsagesOfSubClassMembers(member, movedMembers, abstractMethods, subclass, superClass, - superClass != null ? null : targetPackage, conflicts, - interfaceContainmentVerifier) - : new ConflictingUsagesOfSuperClassMemebers(member, subclass, targetPackage, movedMembers, conflicts); - member.accept(visitor); - } - checkModuleConflictsList.add(member); - } - for (final PsiMethod method : abstractMethods) { - checkModuleConflictsList.add(method.getParameterList()); - checkModuleConflictsList.add(method.getReturnTypeElement()); - checkModuleConflictsList.add(method.getTypeParameterList()); - } - RefactoringConflictsUtil.analyzeModuleConflicts(subclass.getProject(), checkModuleConflictsList, - new UsageInfo[0], targetRepresentativeElement, conflicts); - final String fqName = subclass.getQualifiedName(); - final String packageName; - if (fqName != null) { - packageName = StringUtil.getPackageName(fqName); - } else { - final PsiFile psiFile = PsiTreeUtil.getParentOfType(subclass, PsiFile.class); - if (psiFile instanceof PsiClassOwner) { - packageName = ((PsiClassOwner)psiFile).getPackageName(); - } else { - packageName = null; - } - } - final boolean toDifferentPackage = !Comparing.strEqual(targetPackage.getQualifiedName(), packageName); - for (final PsiMethod abstractMethod : abstractMethods) { - abstractMethod.accept(new ClassMemberReferencesVisitor(subclass) { - @Override - protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { - if (classMember != null && willBeMoved(classMember, movedMembers)) { - boolean isAccessible = false; - if (classMember.hasModifierProperty(PsiModifier.PRIVATE)) { - isAccessible = true; + // check if moved methods use other members in the classes between Subclass and Superclass + List checkModuleConflictsList = new ArrayList(); + for (PsiMember member : movedMembers) { + if (member instanceof PsiMethod || member instanceof PsiClass && !(member instanceof PsiCompiledElement)) { + ClassMemberReferencesVisitor visitor = movedMembers2Super + ? new ConflictingUsagesOfSubClassMembers( + member, + movedMembers, + abstractMethods, + subclass, + superClass, + superClass != null ? null : targetPackage, conflicts, + interfaceContainmentVerifier + ) + : new ConflictingUsagesOfSuperClassMembers(member, subclass, targetPackage, movedMembers, conflicts); + member.accept(visitor); } - else if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && - toDifferentPackage) { - isAccessible = true; + checkModuleConflictsList.add(member); + } + for (final PsiMethod method : abstractMethods) { + checkModuleConflictsList.add(method.getParameterList()); + checkModuleConflictsList.add(method.getReturnTypeElement()); + checkModuleConflictsList.add(method.getTypeParameterList()); + } + RefactoringConflictsUtil.analyzeModuleConflicts( + subclass.getProject(), + checkModuleConflictsList, + new UsageInfo[0], + targetRepresentativeElement, + conflicts + ); + final String fqName = subclass.getQualifiedName(); + final String packageName; + if (fqName != null) { + packageName = StringUtil.getPackageName(fqName); + } + else { + final PsiFile psiFile = PsiTreeUtil.getParentOfType(subclass, PsiFile.class); + if (psiFile instanceof PsiClassOwner) { + packageName = ((PsiClassOwner) psiFile).getPackageName(); } - if (isAccessible) { - String message = RefactoringUIUtil.getDescription(abstractMethod, false) + - " uses " + - RefactoringUIUtil.getDescription(classMember, true) + - " which won't be accessible from the subclass."; - conflicts.putValue(classMember, CommonRefactoringUtil.capitalize(message)); + else { + packageName = null; } - } } - }); - if (abstractMethod.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && toDifferentPackage) { - if (!isInterfaceTarget) { - String message = "Can't make " + RefactoringUIUtil.getDescription(abstractMethod, false) + - " abstract as it won't be accessible from the subclass."; - conflicts.putValue(abstractMethod, CommonRefactoringUtil.capitalize(message)); + final boolean toDifferentPackage = !Comparing.strEqual(targetPackage.getQualifiedName(), packageName); + for (final PsiMethod abstractMethod : abstractMethods) { + abstractMethod.accept(new ClassMemberReferencesVisitor(subclass) { + @Override + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if (classMember != null && willBeMoved(classMember, movedMembers)) { + boolean isAccessible = false; + if (classMember.hasModifierProperty(PsiModifier.PRIVATE)) { + isAccessible = true; + } + else if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && + toDifferentPackage) { + isAccessible = true; + } + if (isAccessible) { + String message = RefactoringUIUtil.getDescription(abstractMethod, false) + + " uses " + + RefactoringUIUtil.getDescription(classMember, true) + + " which won't be accessible from the subclass."; + conflicts.putValue(classMember, LocalizeValue.localizeTODO(CommonRefactoringUtil.capitalize(message))); + } + } + } + }); + if (abstractMethod.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && toDifferentPackage) { + if (!isInterfaceTarget) { + String message = "Can't make " + RefactoringUIUtil.getDescription(abstractMethod, false) + + " abstract as it won't be accessible from the subclass."; + conflicts.putValue(abstractMethod, LocalizeValue.localizeTODO(CommonRefactoringUtil.capitalize(message))); + } + } } - } + return conflicts; } - return conflicts; - } - private static void checkInterfaceTarget(MemberInfo[] infos, MultiMap conflictsList) { - for (MemberInfo info : infos) { - PsiElement member = info.getMember(); + private static void checkInterfaceTarget(MemberInfo[] infos, MultiMap conflictsList) { + for (MemberInfo info : infos) { + PsiElement member = info.getMember(); - if (member instanceof PsiField || member instanceof PsiClass) { + if (member instanceof PsiField || member instanceof PsiClass) { - if (!((PsiModifierListOwner)member).hasModifierProperty(PsiModifier.STATIC) - && !(member instanceof PsiClass && ((PsiClass)member).isInterface())) { - LocalizeValue message = - RefactoringLocalize.zeroIsNotStaticItCannotBeMovedToTheInterface(RefactoringUIUtil.getDescription(member, false)); - conflictsList.putValue(member, CommonRefactoringUtil.capitalize(message.get())); - } - } + if (!((PsiModifierListOwner) member).hasModifierProperty(PsiModifier.STATIC) + && !(member instanceof PsiClass && ((PsiClass) member).isInterface())) { + LocalizeValue message = + RefactoringLocalize.zeroIsNotStaticItCannotBeMovedToTheInterface(RefactoringUIUtil.getDescription(member, false)); + conflictsList.putValue(member, message.capitalize()); + } + } - if (member instanceof PsiField && ((PsiField)member).getInitializer() == null) { - LocalizeValue message = RefactoringLocalize.zeroIsNotInitializedInDeclarationSuchFieldsAreNotAllowedInInterfaces( - RefactoringUIUtil.getDescription(member, false) - ); - conflictsList.putValue(member, CommonRefactoringUtil.capitalize(message.get())); - } + if (member instanceof PsiField && ((PsiField) member).getInitializer() == null) { + LocalizeValue message = RefactoringLocalize.zeroIsNotInitializedInDeclarationSuchFieldsAreNotAllowedInInterfaces( + RefactoringUIUtil.getDescription(member, false) + ); + conflictsList.putValue(member, message.capitalize()); + } + } } - } - private static void checkSuperclassMembers(PsiClass superClass, - MemberInfo[] infos, - MultiMap conflictsList) { - for (MemberInfo info : infos) { - PsiMember member = info.getMember(); - boolean isConflict = false; - if (member instanceof PsiField) { - String name = member.getName(); + private static void checkSuperclassMembers( + PsiClass superClass, + MemberInfo[] infos, + MultiMap conflictsList + ) { + for (MemberInfo info : infos) { + PsiMember member = info.getMember(); + boolean isConflict = false; + if (member instanceof PsiField) { + String name = member.getName(); - isConflict = superClass.findFieldByName(name, false) != null; - } - else if (member instanceof PsiMethod) { - PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, member.getContainingClass(), PsiSubstitutor.EMPTY); - MethodSignature signature = ((PsiMethod) member).getSignature(superSubstitutor); - final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(superClass, signature, false); - isConflict = superClassMethod != null; - } + isConflict = superClass.findFieldByName(name, false) != null; + } + else if (member instanceof PsiMethod) { + PsiSubstitutor superSubstitutor = + TypeConversionUtil.getSuperClassSubstitutor(superClass, member.getContainingClass(), PsiSubstitutor.EMPTY); + MethodSignature signature = ((PsiMethod) member).getSignature(superSubstitutor); + final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(superClass, signature, false); + isConflict = superClassMethod != null; + } - if (isConflict) { - LocalizeValue message = RefactoringLocalize.zeroAlreadyContainsA1( - RefactoringUIUtil.getDescription(superClass, false), - RefactoringUIUtil.getDescription(member, false) - ); - conflictsList.putValue(superClass, CommonRefactoringUtil.capitalize(message.get())); - } + if (isConflict) { + LocalizeValue message = RefactoringLocalize.zeroAlreadyContainsA1( + RefactoringUIUtil.getDescription(superClass, false), + RefactoringUIUtil.getDescription(member, false) + ); + conflictsList.putValue(superClass, message.capitalize()); + } - if (member instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)member; - final PsiModifierList modifierList = method.getModifierList(); - if (!modifierList.hasModifierProperty(PsiModifier.PRIVATE)) { - for (PsiClass subClass : ClassInheritorsSearch.search(superClass)) { - if (method.getContainingClass() != subClass) { - MethodSignature signature = ((PsiMethod) member).getSignature(TypeConversionUtil.getSuperClassSubstitutor(superClass, subClass, PsiSubstitutor.EMPTY)); - final PsiMethod wouldBeOverriden = MethodSignatureUtil.findMethodBySignature(subClass, signature, false); - if (wouldBeOverriden != null && VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(wouldBeOverriden.getModifierList()), - VisibilityUtil.getVisibilityModifier(modifierList)) > 0) { - conflictsList.putValue(wouldBeOverriden, CommonRefactoringUtil.capitalize(RefactoringUIUtil.getDescription(method, true) + " in super class would clash with local method from " + RefactoringUIUtil.getDescription(subClass, true))); - } + if (member instanceof PsiMethod) { + final PsiMethod method = (PsiMethod) member; + final PsiModifierList modifierList = method.getModifierList(); + if (!modifierList.hasModifierProperty(PsiModifier.PRIVATE)) { + for (PsiClass subClass : ClassInheritorsSearch.search(superClass)) { + if (method.getContainingClass() != subClass) { + MethodSignature signature = ((PsiMethod) member).getSignature(TypeConversionUtil.getSuperClassSubstitutor( + superClass, + subClass, + PsiSubstitutor.EMPTY + )); + final PsiMethod wouldBeOverriden = MethodSignatureUtil.findMethodBySignature(subClass, signature, false); + if (wouldBeOverriden != null && VisibilityUtil.compare( + VisibilityUtil.getVisibilityModifier(wouldBeOverriden.getModifierList()), + VisibilityUtil.getVisibilityModifier(modifierList) + ) > 0) { + conflictsList.putValue( + wouldBeOverriden, + LocalizeValue.localizeTODO(CommonRefactoringUtil.capitalize( + RefactoringUIUtil.getDescription(method, true) + " in super class would clash " + + "with local method from " + RefactoringUIUtil.getDescription(subClass, true) + )) + ); + } + } + } + } } - } } - } } - } - - private static boolean willBeMoved(PsiElement element, Set movedMembers) { - PsiElement parent = element; - while (parent != null) { - if (movedMembers.contains(parent)) return true; - parent = parent.getParent(); + private static boolean willBeMoved(PsiElement element, Set movedMembers) { + PsiElement parent = element; + while (parent != null) { + if (movedMembers.contains(parent)) { + return true; + } + parent = parent.getParent(); + } + return false; } - return false; - } - - private static class ConflictingUsagesOfSuperClassMemebers extends ClassMemberReferencesVisitor { - private PsiMember myMember; - private PsiClass mySubClass; - private PsiJavaPackage myTargetPackage; - private Set myMovedMembers; - private MultiMap myConflicts; + private static class ConflictingUsagesOfSuperClassMembers extends ClassMemberReferencesVisitor { + private PsiMember myMember; + private PsiClass mySubClass; + private PsiJavaPackage myTargetPackage; + private Set myMovedMembers; + private MultiMap myConflicts; - public ConflictingUsagesOfSuperClassMemebers(PsiMember member, PsiClass aClass, - PsiJavaPackage targetPackage, - Set movedMembers, - MultiMap conflicts) { - super(aClass); - myMember = member; - mySubClass = aClass; - myTargetPackage = targetPackage; - myMovedMembers = movedMembers; - myConflicts = conflicts; - } + public ConflictingUsagesOfSuperClassMembers( + PsiMember member, + PsiClass aClass, + PsiJavaPackage targetPackage, + Set movedMembers, + MultiMap conflicts + ) { + super(aClass); + myMember = member; + mySubClass = aClass; + myTargetPackage = targetPackage; + myMovedMembers = movedMembers; + myConflicts = conflicts; + } - @Override - protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { - if (classMember != null && !willBeMoved(classMember, myMovedMembers)) { - final PsiClass containingClass = classMember.getContainingClass(); - if (containingClass != null) { - if (!PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage)) { - if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { - myConflicts.putValue(myMember, RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible"); - } - else if (classMember.hasModifierProperty(PsiModifier.PROTECTED) && !mySubClass.isInheritor(containingClass, true)) { - myConflicts.putValue(myMember, RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible"); + @Override + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if (classMember != null && !willBeMoved(classMember, myMovedMembers)) { + final PsiClass containingClass = classMember.getContainingClass(); + if (containingClass != null) { + if (!PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage)) { + if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { + myConflicts.putValue( + myMember, + LocalizeValue.localizeTODO(RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible") + ); + } + else if (classMember.hasModifierProperty(PsiModifier.PROTECTED) && !mySubClass.isInheritor(containingClass, true)) { + myConflicts.putValue( + myMember, + LocalizeValue.localizeTODO(RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible") + ); + } + } + } } - } } - } } - } - private static class ConflictingUsagesOfSubClassMembers extends ClassMemberReferencesVisitor { - private final PsiElement myScope; - private final Set myMovedMembers; - private final Set myAbstractMethods; - private final PsiClass mySubclass; - private final PsiClass mySuperClass; - private final PsiJavaPackage myTargetPackage; - private final MultiMap myConflictsList; - private final InterfaceContainmentVerifier myInterfaceContainmentVerifier; + private static class ConflictingUsagesOfSubClassMembers extends ClassMemberReferencesVisitor { + private final PsiElement myScope; + private final Set myMovedMembers; + private final Set myAbstractMethods; + private final PsiClass mySubclass; + private final PsiClass mySuperClass; + private final PsiJavaPackage myTargetPackage; + private final MultiMap myConflictsList; + private final InterfaceContainmentVerifier myInterfaceContainmentVerifier; - ConflictingUsagesOfSubClassMembers(PsiElement scope, - Set movedMembers, Set abstractMethods, - PsiClass subclass, PsiClass superClass, - PsiJavaPackage targetPackage, MultiMap conflictsList, - InterfaceContainmentVerifier interfaceContainmentVerifier) { - super(subclass); - myScope = scope; - myMovedMembers = movedMembers; - myAbstractMethods = abstractMethods; - mySubclass = subclass; - mySuperClass = superClass; - myTargetPackage = targetPackage; - myConflictsList = conflictsList; - myInterfaceContainmentVerifier = interfaceContainmentVerifier; - } - - protected void visitClassMemberReferenceElement(PsiMember classMember, - PsiJavaCodeReferenceElement classMemberReference) { - if (classMember != null - && RefactoringHierarchyUtil.isMemberBetween(mySuperClass, mySubclass, classMember)) { - if (classMember.hasModifierProperty(PsiModifier.STATIC) - && !willBeMoved(classMember, myMovedMembers)) { - final boolean isAccessible; - if (mySuperClass != null) { - isAccessible = PsiUtil.isAccessible(classMember, mySuperClass, null); - } - else if (myTargetPackage != null) { - isAccessible = PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage); - } - else { - isAccessible = classMember.hasModifierProperty(PsiModifier.PUBLIC); - } - if (!isAccessible) { - LocalizeValue message = RefactoringLocalize.zeroUses1WhichIsNotAccessibleFromTheSuperclass( - RefactoringUIUtil.getDescription(myScope, false), - RefactoringUIUtil.getDescription(classMember, true) - ); - myConflictsList.putValue(classMember, CommonRefactoringUtil.capitalize(message.get())); - } - return; - } - if (!myAbstractMethods.contains(classMember) && !willBeMoved(classMember, myMovedMembers)) { - if (!existsInSuperClass(classMember)) { - LocalizeValue message = RefactoringLocalize.zeroUses1WhichIsNotMovedToTheSuperclass( - RefactoringUIUtil.getDescription(myScope, false), - RefactoringUIUtil.getDescription(classMember, true) - ); - myConflictsList.putValue(classMember, CommonRefactoringUtil.capitalize(message.get())); - } + ConflictingUsagesOfSubClassMembers( + PsiElement scope, + Set movedMembers, + Set abstractMethods, + PsiClass subclass, + PsiClass superClass, + PsiJavaPackage targetPackage, + MultiMap conflictsList, + InterfaceContainmentVerifier interfaceContainmentVerifier + ) { + super(subclass); + myScope = scope; + myMovedMembers = movedMembers; + myAbstractMethods = abstractMethods; + mySubclass = subclass; + mySuperClass = superClass; + myTargetPackage = targetPackage; + myConflictsList = conflictsList; + myInterfaceContainmentVerifier = interfaceContainmentVerifier; } - } - } + protected void visitClassMemberReferenceElement( + PsiMember classMember, + PsiJavaCodeReferenceElement classMemberReference + ) { + if (classMember != null + && RefactoringHierarchyUtil.isMemberBetween(mySuperClass, mySubclass, classMember)) { + if (classMember.hasModifierProperty(PsiModifier.STATIC) + && !willBeMoved(classMember, myMovedMembers)) { + final boolean isAccessible; + if (mySuperClass != null) { + isAccessible = PsiUtil.isAccessible(classMember, mySuperClass, null); + } + else if (myTargetPackage != null) { + isAccessible = PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage); + } + else { + isAccessible = classMember.hasModifierProperty(PsiModifier.PUBLIC); + } + if (!isAccessible) { + LocalizeValue message = RefactoringLocalize.zeroUses1WhichIsNotAccessibleFromTheSuperclass( + RefactoringUIUtil.getDescription(myScope, false), + RefactoringUIUtil.getDescription(classMember, true) + ); + myConflictsList.putValue(classMember, message.capitalize()); + } + return; + } + if (!myAbstractMethods.contains(classMember) && !willBeMoved(classMember, myMovedMembers)) { + if (!existsInSuperClass(classMember)) { + LocalizeValue message = RefactoringLocalize.zeroUses1WhichIsNotMovedToTheSuperclass( + RefactoringUIUtil.getDescription(myScope, false), + RefactoringUIUtil.getDescription(classMember, true) + ); + myConflictsList.putValue(classMember, message.capitalize()); + } + } + } + } - private boolean existsInSuperClass(PsiElement classMember) { - if (!(classMember instanceof PsiMethod)) return false; - final PsiMethod method = ((PsiMethod)classMember); - if (myInterfaceContainmentVerifier.checkedInterfacesContain(method)) return true; - if (mySuperClass == null) return false; - final PsiMethod methodBySignature = mySuperClass.findMethodBySignature(method, true); - return methodBySignature != null; + private boolean existsInSuperClass(PsiElement classMember) { + if (!(classMember instanceof PsiMethod)) { + return false; + } + final PsiMethod method = ((PsiMethod) classMember); + if (myInterfaceContainmentVerifier.checkedInterfacesContain(method)) { + return true; + } + if (mySuperClass == null) { + return false; + } + final PsiMethod methodBySignature = mySuperClass.findMethodBySignature(method, true); + return methodBySignature != null; + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpDialog.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpDialog.java index 9ac3d358d3..6704e36e8f 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpDialog.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpDialog.java @@ -53,230 +53,236 @@ /** * @author dsl - * Date: 18.06.2002 + * @since 2002-06-18 */ public class PullUpDialog extends PullUpDialogBase { - private final Callback myCallback; - private DocCommentPanel myJavaDocPanel; + private final Callback myCallback; + private DocCommentPanel myJavaDocPanel; - private final InterfaceContainmentVerifier myInterfaceContainmentVerifier = new InterfaceContainmentVerifier() { - public boolean checkedInterfacesContain(PsiMethod psiMethod) { - return PullUpProcessor.checkedInterfacesContain(myMemberInfos, psiMethod); - } - }; - - private static final String PULL_UP_STATISTICS_KEY = "pull.up##"; - - public interface Callback { - boolean checkConflicts(PullUpDialog dialog); - } - - public PullUpDialog(Project project, - PsiClass aClass, - List superClasses, - MemberInfoStorage memberInfoStorage, - Callback callback) { - super(project, aClass, superClasses, memberInfoStorage, JavaPullUpHandler.REFACTORING_NAME); - myCallback = callback; - - init(); - } - - public int getJavaDocPolicy() { - return myJavaDocPanel.getPolicy(); - } + private final InterfaceContainmentVerifier myInterfaceContainmentVerifier = new InterfaceContainmentVerifier() { + public boolean checkedInterfacesContain(PsiMethod psiMethod) { + return PullUpProcessor.checkedInterfacesContain(myMemberInfos, psiMethod); + } + }; - protected String getDimensionServiceKey() { - return "#com.intellij.refactoring.memberPullUp.PullUpDialog"; - } + private static final String PULL_UP_STATISTICS_KEY = "pull.up##"; - InterfaceContainmentVerifier getContainmentVerifier() { - return myInterfaceContainmentVerifier; - } + public interface Callback { + boolean checkConflicts(PullUpDialog dialog); + } - @Override - protected void initClassCombo(JComboBox classCombo) { - classCombo.setRenderer(new ClassCellRenderer(classCombo.getRenderer())); - classCombo.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - if (myMemberSelectionPanel != null) { - ((MyMemberInfoModel) myMemberInfoModel).setSuperClass(getSuperClass()); - myMemberSelectionPanel.getTable().setMemberInfos(myMemberInfos); - myMemberSelectionPanel.getTable().fireExternalDataChange(); - } - } - } - }); - } + public PullUpDialog( + Project project, + PsiClass aClass, + List superClasses, + MemberInfoStorage memberInfoStorage, + Callback callback + ) { + super(project, aClass, superClasses, memberInfoStorage, JavaPullUpHandler.REFACTORING_NAME.get()); + myCallback = callback; - protected PsiClass getPreselection() { - PsiClass preselection = RefactoringHierarchyUtil.getNearestBaseClass(myClass, false); + init(); + } - final String statKey = PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(); - for (StatisticsInfo info : StatisticsManager.getInstance().getAllValues(statKey)) { - final String superClassName = info.getValue(); - PsiClass superClass = null; - for (PsiClass aClass : mySuperClasses) { - if (Comparing.strEqual(superClassName, aClass.getQualifiedName())) { - superClass = aClass; - break; - } - } - if (superClass != null && StatisticsManager.getInstance().getUseCount(info) > 0) { - preselection = superClass; - break; - } + public int getJavaDocPolicy() { + return myJavaDocPanel.getPolicy(); } - return preselection; - } - protected void doHelpAction() { - HelpManager.getInstance().invokeHelp(HelpID.MEMBERS_PULL_UP); - } + protected String getDimensionServiceKey() { + return "#com.intellij.refactoring.memberPullUp.PullUpDialog"; + } - protected void doAction() { - if (!myCallback.checkConflicts(this)) { - return; + InterfaceContainmentVerifier getContainmentVerifier() { + return myInterfaceContainmentVerifier; } - JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC = myJavaDocPanel.getPolicy(); - final PsiClass superClass = getSuperClass(); - String name = superClass.getQualifiedName(); - if (name != null) { - StatisticsManager.getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass - .getQualifiedName(), name)); + + @Override + protected void initClassCombo(JComboBox classCombo) { + classCombo.setRenderer(new ClassCellRenderer(classCombo.getRenderer())); + classCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + if (myMemberSelectionPanel != null) { + ((MyMemberInfoModel) myMemberInfoModel).setSuperClass(getSuperClass()); + myMemberSelectionPanel.getTable().setMemberInfos(myMemberInfos); + myMemberSelectionPanel.getTable().fireExternalDataChange(); + } + } + } + }); } - List infos = getSelectedMemberInfos(); - invokeRefactoring(new PullUpProcessor(myClass, superClass, infos.toArray(new MemberInfo[infos.size()]), - new DocCommentPolicy(getJavaDocPolicy()))); - close(OK_EXIT_CODE); - } + protected PsiClass getPreselection() { + PsiClass preselection = RefactoringHierarchyUtil.getNearestBaseClass(myClass, false); - @Override - protected void addCustomElementsToCentralPanel(JPanel panel) { - myJavaDocPanel = new DocCommentPanel(RefactoringLocalize.javadocForAbstracts()); - myJavaDocPanel.setPolicy(JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC); - boolean hasJavadoc = false; - for (MemberInfo info : myMemberInfos) { - final PsiMember member = info.getMember(); - if (myMemberInfoModel.isAbstractEnabled(info)) { - info.setToAbstract(myMemberInfoModel.isAbstractWhenDisabled(info)); - if (!hasJavadoc && - member instanceof PsiDocCommentOwner && - ((PsiDocCommentOwner) member).getDocComment() != null) { - hasJavadoc = true; + final String statKey = PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(); + for (StatisticsInfo info : StatisticsManager.getInstance().getAllValues(statKey)) { + final String superClassName = info.getValue(); + PsiClass superClass = null; + for (PsiClass aClass : mySuperClasses) { + if (Comparing.strEqual(superClassName, aClass.getQualifiedName())) { + superClass = aClass; + break; + } + } + if (superClass != null && StatisticsManager.getInstance().getUseCount(info) > 0) { + preselection = superClass; + break; + } } - } + return preselection; } - Component component = myJavaDocPanel.getComponent(); - component.setEnabledRecursive(hasJavadoc); - panel.add(TargetAWT.to(component), BorderLayout.EAST); - } - - @Override - protected AbstractMemberSelectionTable createMemberSelectionTable(List infos) { - return new MemberSelectionTable(infos, RefactoringLocalize.makeAbstract().get()); - } + protected void doHelpAction() { + HelpManager.getInstance().invokeHelp(HelpID.MEMBERS_PULL_UP); + } - @Override - protected MemberInfoModel createMemberInfoModel() { - return new MyMemberInfoModel(); - } + protected void doAction() { + if (!myCallback.checkConflicts(this)) { + return; + } + JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC = myJavaDocPanel.getPolicy(); + final PsiClass superClass = getSuperClass(); + String name = superClass.getQualifiedName(); + if (name != null) { + StatisticsManager.getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass + .getQualifiedName(), name)); + } - private class MyMemberInfoModel extends UsesAndInterfacesDependencyMemberInfoModel { - public MyMemberInfoModel() { - super(myClass, getSuperClass(), false, myInterfaceContainmentVerifier); + List infos = getSelectedMemberInfos(); + invokeRefactoring(new PullUpProcessor(myClass, superClass, infos.toArray(new MemberInfo[infos.size()]), + new DocCommentPolicy(getJavaDocPolicy()) + )); + close(OK_EXIT_CODE); } @Override - public boolean isMemberEnabled(MemberInfo member) { - final PsiClass currentSuperClass = getSuperClass(); - if (currentSuperClass == null) { - return true; - } - if (myMemberInfoStorage.getDuplicatedMemberInfos(currentSuperClass).contains(member)) { - return false; - } - if (myMemberInfoStorage.getExtending(currentSuperClass).contains(member.getMember())) { - return false; - } - final boolean isInterface = currentSuperClass.isInterface(); - if (!isInterface) { - return true; - } - - PsiElement element = member.getMember(); - if (element instanceof PsiClass && ((PsiClass) element).isInterface()) { - return true; - } - if (element instanceof PsiField) { - return ((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC); - } - if (element instanceof PsiMethod) { - final PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(currentSuperClass, - myClass, PsiSubstitutor.EMPTY); - final MethodSignature signature = ((PsiMethod) element).getSignature(superSubstitutor); - final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(currentSuperClass, - signature, false); - if (superClassMethod != null && !PsiUtil.isLanguageLevel8OrHigher(currentSuperClass)) { - return false; + protected void addCustomElementsToCentralPanel(JPanel panel) { + myJavaDocPanel = new DocCommentPanel(RefactoringLocalize.javadocForAbstracts()); + myJavaDocPanel.setPolicy(JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC); + boolean hasJavadoc = false; + for (MemberInfo info : myMemberInfos) { + final PsiMember member = info.getMember(); + if (myMemberInfoModel.isAbstractEnabled(info)) { + info.setToAbstract(myMemberInfoModel.isAbstractWhenDisabled(info)); + if (!hasJavadoc && + member instanceof PsiDocCommentOwner && + ((PsiDocCommentOwner) member).getDocComment() != null) { + hasJavadoc = true; + } + } } - return !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC) || PsiUtil - .isLanguageLevel8OrHigher(currentSuperClass); - } - return true; + + Component component = myJavaDocPanel.getComponent(); + component.setEnabledRecursive(hasJavadoc); + panel.add(TargetAWT.to(component), BorderLayout.EAST); } @Override - public boolean isAbstractEnabled(MemberInfo member) { - PsiClass currentSuperClass = getSuperClass(); - if (currentSuperClass == null || !currentSuperClass.isInterface()) { - return true; - } - if (PsiUtil.isLanguageLevel8OrHigher(currentSuperClass)) { - return true; - } - return false; + protected AbstractMemberSelectionTable createMemberSelectionTable(List infos) { + return new MemberSelectionTable(infos, RefactoringLocalize.makeAbstract().get()); } @Override - public boolean isAbstractWhenDisabled(MemberInfo member) { - PsiClass currentSuperClass = getSuperClass(); - if (currentSuperClass == null) { - return false; - } - if (currentSuperClass.isInterface()) { - final PsiMember psiMember = member.getMember(); - if (psiMember instanceof PsiMethod) { - return !psiMember.hasModifierProperty(PsiModifier.STATIC); - } - } - return false; + protected MemberInfoModel createMemberInfoModel() { + return new MyMemberInfoModel(); } - @Override - public int checkForProblems(@Nonnull MemberInfo member) { - if (member.isChecked()) { - return OK; - } - PsiClass currentSuperClass = getSuperClass(); + private class MyMemberInfoModel extends UsesAndInterfacesDependencyMemberInfoModel { + public MyMemberInfoModel() { + super(myClass, getSuperClass(), false, myInterfaceContainmentVerifier); + } + + @Override + public boolean isMemberEnabled(MemberInfo member) { + final PsiClass currentSuperClass = getSuperClass(); + if (currentSuperClass == null) { + return true; + } + if (myMemberInfoStorage.getDuplicatedMemberInfos(currentSuperClass).contains(member)) { + return false; + } + if (myMemberInfoStorage.getExtending(currentSuperClass).contains(member.getMember())) { + return false; + } + final boolean isInterface = currentSuperClass.isInterface(); + if (!isInterface) { + return true; + } - if (currentSuperClass != null && currentSuperClass.isInterface()) { - PsiMember element = member.getMember(); - if (element.hasModifierProperty(PsiModifier.STATIC)) { - return super.checkForProblems(member); + PsiElement element = member.getMember(); + if (element instanceof PsiClass && ((PsiClass) element).isInterface()) { + return true; + } + if (element instanceof PsiField) { + return ((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC); + } + if (element instanceof PsiMethod) { + final PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(currentSuperClass, + myClass, PsiSubstitutor.EMPTY + ); + final MethodSignature signature = ((PsiMethod) element).getSignature(superSubstitutor); + final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(currentSuperClass, + signature, false + ); + if (superClassMethod != null && !PsiUtil.isLanguageLevel8OrHigher(currentSuperClass)) { + return false; + } + return !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC) || PsiUtil + .isLanguageLevel8OrHigher(currentSuperClass); + } + return true; } - return OK; - } else { - return super.checkForProblems(member); - } - } - @Override - public Boolean isFixedAbstract(MemberInfo member) { - return Boolean.TRUE; + @Override + public boolean isAbstractEnabled(MemberInfo member) { + PsiClass currentSuperClass = getSuperClass(); + if (currentSuperClass == null || !currentSuperClass.isInterface()) { + return true; + } + if (PsiUtil.isLanguageLevel8OrHigher(currentSuperClass)) { + return true; + } + return false; + } + + @Override + public boolean isAbstractWhenDisabled(MemberInfo member) { + PsiClass currentSuperClass = getSuperClass(); + if (currentSuperClass == null) { + return false; + } + if (currentSuperClass.isInterface()) { + final PsiMember psiMember = member.getMember(); + if (psiMember instanceof PsiMethod) { + return !psiMember.hasModifierProperty(PsiModifier.STATIC); + } + } + return false; + } + + @Override + public int checkForProblems(@Nonnull MemberInfo member) { + if (member.isChecked()) { + return OK; + } + PsiClass currentSuperClass = getSuperClass(); + + if (currentSuperClass != null && currentSuperClass.isInterface()) { + PsiMember element = member.getMember(); + if (element.hasModifierProperty(PsiModifier.STATIC)) { + return super.checkForProblems(member); + } + return OK; + } + else { + return super.checkForProblems(member); + } + } + + @Override + public Boolean isFixedAbstract(MemberInfo member) { + return Boolean.TRUE; + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownConflicts.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownConflicts.java index 166f9dd5e3..d03c96d0a9 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownConflicts.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownConflicts.java @@ -20,6 +20,8 @@ import com.intellij.java.impl.refactoring.util.classMembers.MemberInfo; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.InheritanceUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.application.progress.ProgressManager; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.ui.RefactoringUIUtil; @@ -29,183 +31,190 @@ import consulo.language.psi.search.ReferencesSearch; import consulo.localize.LocalizeValue; import consulo.util.collection.MultiMap; +import jakarta.annotation.Nonnull; import java.util.HashSet; import java.util.Set; public class PushDownConflicts { - private final PsiClass myClass; - private final Set myMovedMembers; - private final Set myAbstractMembers; - private final MultiMap myConflicts; - - - public PushDownConflicts(PsiClass aClass, MemberInfo[] memberInfos) { - myClass = aClass; - - myMovedMembers = new HashSet(); - myAbstractMembers = new HashSet(); - for (MemberInfo memberInfo : memberInfos) { - final PsiMember member = memberInfo.getMember(); - if (memberInfo.isChecked() && (!(memberInfo.getMember() instanceof PsiClass) || memberInfo.getOverrides() == null)) { - myMovedMembers.add(member); - if (memberInfo.isToAbstract()) { - myAbstractMembers.add((PsiMethod)member); + private final PsiClass myClass; + private final Set myMovedMembers; + private final Set myAbstractMembers; + private final MultiMap myConflicts; + + public PushDownConflicts(PsiClass aClass, MemberInfo[] memberInfos) { + myClass = aClass; + + myMovedMembers = new HashSet<>(); + myAbstractMembers = new HashSet<>(); + for (MemberInfo memberInfo : memberInfos) { + PsiMember member = memberInfo.getMember(); + if (memberInfo.isChecked() && (!(memberInfo.getMember() instanceof PsiClass) || memberInfo.getOverrides() == null)) { + myMovedMembers.add(member); + if (memberInfo.isToAbstract()) { + myAbstractMembers.add((PsiMethod) member); + } + } } - } - } - myConflicts = new MultiMap(); - } + myConflicts = new MultiMap<>(); + } - public boolean isAnyConflicts() { - return !myConflicts.isEmpty(); - } + public boolean isAnyConflicts() { + return !myConflicts.isEmpty(); + } - public MultiMap getConflicts() { - return myConflicts; - } + public MultiMap getConflicts() { + return myConflicts; + } - public void checkSourceClassConflicts() { - final PsiElement[] children = myClass.getChildren(); - for (PsiElement child : children) { - if (child instanceof PsiMember && !myMovedMembers.contains(child)) { - child.accept(new UsedMovedMembersConflictsCollector(child)); - } + @RequiredReadAction + public void checkSourceClassConflicts() { + PsiElement[] children = myClass.getChildren(); + for (PsiElement child : children) { + if (child instanceof PsiMember && !myMovedMembers.contains(child)) { + child.accept(new UsedMovedMembersConflictsCollector(child)); + } + } } - } - - public boolean checkTargetClassConflicts(final PsiClass targetClass, final boolean checkStatic, final PsiElement context) { - if (targetClass != null) { - for (final PsiMember movedMember : myMovedMembers) { - checkMemberPlacementInTargetClassConflict(targetClass, movedMember); - movedMember.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - super.visitMethodCallExpression(expression); - if (expression.getMethodExpression().getQualifierExpression() instanceof PsiSuperExpression) { - final PsiMethod resolvedMethod = expression.resolveMethod(); - if (resolvedMethod != null) { - final PsiClass resolvedClass = resolvedMethod.getContainingClass(); - if (resolvedClass != null) { - if (myClass.isInheritor(resolvedClass, true)) { - final PsiMethod methodBySignature = myClass.findMethodBySignature(resolvedMethod, false); - if (methodBySignature != null && !myMovedMembers.contains(methodBySignature)) { - myConflicts.putValue(expression, "Super method call will resolve to another method"); + + @RequiredReadAction + public boolean checkTargetClassConflicts(PsiClass targetClass, boolean checkStatic, PsiElement context) { + if (targetClass != null) { + for (PsiMember movedMember : myMovedMembers) { + checkMemberPlacementInTargetClassConflict(targetClass, movedMember); + movedMember.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitMethodCallExpression(@Nonnull PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (expression.getMethodExpression().getQualifierExpression() instanceof PsiSuperExpression) { + PsiMethod resolvedMethod = expression.resolveMethod(); + if (resolvedMethod != null) { + PsiClass resolvedClass = resolvedMethod.getContainingClass(); + if (resolvedClass != null && myClass.isInheritor(resolvedClass, true)) { + PsiMethod methodBySignature = myClass.findMethodBySignature(resolvedMethod, false); + if (methodBySignature != null && !myMovedMembers.contains(methodBySignature)) { + myConflicts.putValue( + expression, + LocalizeValue.localizeTODO("Super method call will resolve to another method") + ); + } + } + } + } + } + }); + } + } + @RequiredWriteAction + Runnable searchConflictsRunnable = () -> { + Members: + for (PsiMember member : myMovedMembers) { + for (PsiReference ref : ReferencesSearch.search(member, member.getResolveScope(), false)) { + if (ref.getElement() instanceof PsiReferenceExpression refExpr) { + PsiExpression qualifier = refExpr.getQualifierExpression(); + if (qualifier != null) { + PsiClass aClass = null; + if (qualifier.getType() instanceof PsiClassType classType) { + aClass = classType.resolve(); + } + else if (!checkStatic) { + continue; + } + else if (qualifier instanceof PsiReferenceExpression qRefExpr + && qRefExpr.resolve() instanceof PsiClass psiClass) { + aClass = psiClass; + } + + if (!InheritanceUtil.isInheritorOrSelf(aClass, targetClass, true)) { + myConflicts.putValue( + refExpr, + RefactoringLocalize.pushedMembersWillNotBeVisibleFromCertainCallSites() + ); + break Members; + } + } } - } } - } } - } - }); - } + RefactoringConflictsUtil.analyzeAccessibilityConflicts( + myMovedMembers, + targetClass, + myConflicts, + null, + context, + myAbstractMembers + ); + }; + return !ProgressManager.getInstance().runProcessWithProgressSynchronously( + searchConflictsRunnable, + RefactoringLocalize.detectingPossibleConflicts(), + false, + context.getProject() + ); } - Runnable searchConflictsRunnable = new Runnable() { - public void run() { - Members: - for (PsiMember member : myMovedMembers) { - for (PsiReference ref : ReferencesSearch.search(member, member.getResolveScope(), false)) { - final PsiElement element = ref.getElement(); - if (element instanceof PsiReferenceExpression) { - final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)element; - final PsiExpression qualifier = referenceExpression.getQualifierExpression(); - if (qualifier != null) { - final PsiType qualifierType = qualifier.getType(); - PsiClass aClass = null; - if (qualifierType instanceof PsiClassType) { - aClass = ((PsiClassType)qualifierType).resolve(); + + @RequiredReadAction + public void checkMemberPlacementInTargetClassConflict(PsiClass targetClass, PsiMember movedMember) { + if (movedMember instanceof PsiField movedField) { + String name = movedField.getName(); + PsiField field = targetClass.findFieldByName(name, false); + if (field != null) { + LocalizeValue message = RefactoringLocalize.zeroAlreadyContainsField1( + RefactoringUIUtil.getDescription(targetClass, false), + CommonRefactoringUtil.htmlEmphasize(name) + ); + myConflicts.putValue(field, message.capitalize()); + } + } + else if (movedMember instanceof PsiMethod movedMethod) { + if (!movedMethod.isAbstract()) { + PsiMethod overrider = targetClass.findMethodBySignature(movedMethod, false); + if (overrider != null) { + LocalizeValue message = RefactoringLocalize.zeroIsAlreadyOverriddenIn1( + RefactoringUIUtil.getDescription(movedMethod, true), + RefactoringUIUtil.getDescription(targetClass, false) + ); + myConflicts.putValue(overrider, message.capitalize()); } - else { - if (!checkStatic) continue; - if (qualifier instanceof PsiReferenceExpression) { - final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve(); - if (resolved instanceof PsiClass) { - aClass = (PsiClass)resolved; - } - } + } + } + else if (movedMember instanceof PsiClass movedClass) { + String name = movedClass.getName(); + PsiClass[] allInnerClasses = targetClass.getAllInnerClasses(); + for (PsiClass innerClass : allInnerClasses) { + if (innerClass.equals(movedClass)) { + continue; } - if (!InheritanceUtil.isInheritorOrSelf(aClass, targetClass, true)) { - myConflicts.putValue(referenceExpression, RefactoringLocalize.pushedMembersWillNotBeVisibleFromCertainCallSites().get()); - break Members; + if (name.equals(innerClass.getName())) { + LocalizeValue message = RefactoringLocalize.zeroAlreadyContainsInnerClassNamed1( + RefactoringUIUtil.getDescription(targetClass, false), + CommonRefactoringUtil.htmlEmphasize(name) + ); + myConflicts.putValue(innerClass, message); } - } } - } - } - RefactoringConflictsUtil.analyzeAccessibilityConflicts(myMovedMembers, targetClass, myConflicts, null, context, myAbstractMembers); - } - }; - return !ProgressManager.getInstance().runProcessWithProgressSynchronously( - searchConflictsRunnable, - RefactoringLocalize.detectingPossibleConflicts().get(), - false, - context.getProject() - ); - } - - public void checkMemberPlacementInTargetClassConflict(final PsiClass targetClass, final PsiMember movedMember) { - if (movedMember instanceof PsiField) { - String name = movedMember.getName(); - final PsiField field = targetClass.findFieldByName(name, false); - if (field != null) { - LocalizeValue message = RefactoringLocalize.zeroAlreadyContainsField1( - RefactoringUIUtil.getDescription(targetClass, false), - CommonRefactoringUtil.htmlEmphasize(name) - ); - myConflicts.putValue(field, CommonRefactoringUtil.capitalize(message.get())); - } - } - else if (movedMember instanceof PsiMethod) { - final PsiModifierList modifierList = movedMember.getModifierList(); - assert modifierList != null; - if (!modifierList.hasModifierProperty(PsiModifier.ABSTRACT)) { - PsiMethod method = (PsiMethod)movedMember; - final PsiMethod overrider = targetClass.findMethodBySignature(method, false); - if (overrider != null) { - LocalizeValue message = RefactoringLocalize.zeroIsAlreadyOverriddenIn1( - RefactoringUIUtil.getDescription(method, true), - RefactoringUIUtil.getDescription(targetClass, false) - ); - myConflicts.putValue(overrider, CommonRefactoringUtil.capitalize(message.get())); } - } } - else if (movedMember instanceof PsiClass) { - PsiClass aClass = (PsiClass)movedMember; - final String name = aClass.getName(); - final PsiClass[] allInnerClasses = targetClass.getAllInnerClasses(); - for (PsiClass innerClass : allInnerClasses) { - if (innerClass.equals(movedMember)) continue; - - if (name.equals(innerClass.getName())) { - LocalizeValue message = RefactoringLocalize.zeroAlreadyContainsInnerClassNamed1( - RefactoringUIUtil.getDescription(targetClass, false), - CommonRefactoringUtil.htmlEmphasize(name) - ); - myConflicts.putValue(innerClass, message.get()); - } - } - } - } - private class UsedMovedMembersConflictsCollector extends ClassMemberReferencesVisitor { - private final PsiElement mySource; + private class UsedMovedMembersConflictsCollector extends ClassMemberReferencesVisitor { + private final PsiElement mySource; - public UsedMovedMembersConflictsCollector(PsiElement source) { - super(myClass); - mySource = source; - } + public UsedMovedMembersConflictsCollector(PsiElement source) { + super(myClass); + mySource = source; + } - protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { - if(myMovedMembers.contains(classMember) && !myAbstractMembers.contains(classMember)) { - LocalizeValue message = RefactoringLocalize.zeroUses1WhichIsPushedDown( - RefactoringUIUtil.getDescription(mySource, false), - RefactoringUIUtil.getDescription(classMember, false) - ); - myConflicts.putValue(mySource, CommonRefactoringUtil.capitalize(message.get())); - } + @Override + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if (myMovedMembers.contains(classMember) && !myAbstractMembers.contains(classMember)) { + LocalizeValue message = RefactoringLocalize.zeroUses1WhichIsPushedDown( + RefactoringUIUtil.getDescription(mySource, false), + RefactoringUIUtil.getDescription(classMember, false) + ); + myConflicts.putValue(mySource, message.capitalize()); + } + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveJavaMemberHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveJavaMemberHandler.java index 84487dd32f..1afb803468 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveJavaMemberHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveJavaMemberHandler.java @@ -50,248 +50,316 @@ */ @ExtensionImpl public class MoveJavaMemberHandler implements MoveMemberHandler { - @Override - @Nullable - public MoveMembersProcessor.MoveMembersUsageInfo getUsage(@Nonnull PsiMember member, @Nonnull PsiReference psiReference, - @Nonnull Set membersToMove, @Nonnull PsiClass targetClass) { - PsiElement ref = psiReference.getElement(); - if (ref instanceof PsiReferenceExpression) { - PsiReferenceExpression refExpr = (PsiReferenceExpression) ref; - PsiExpression qualifier = refExpr.getQualifierExpression(); - if (RefactoringHierarchyUtil.willBeInTargetClass(refExpr, membersToMove, targetClass, true)) { - // both member and the reference to it will be in target class - if (!RefactoringUtil.isInMovedElement(refExpr, membersToMove)) { - if (qualifier != null) { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, null, qualifier, psiReference); // remove qualifier - } - } else { - if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression) qualifier).isReferenceTo(member.getContainingClass - ())) { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, null, qualifier, psiReference); // change qualifier - } - } - } else { - // member in target class, the reference will be outside target class - if (qualifier == null) { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, targetClass, refExpr, psiReference); // add qualifier - } else { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, targetClass, qualifier, psiReference); // change qualifier + @Override + @Nullable + public MoveMembersProcessor.MoveMembersUsageInfo getUsage( + @Nonnull PsiMember member, @Nonnull PsiReference psiReference, + @Nonnull Set membersToMove, @Nonnull PsiClass targetClass + ) { + PsiElement ref = psiReference.getElement(); + if (ref instanceof PsiReferenceExpression) { + PsiReferenceExpression refExpr = (PsiReferenceExpression) ref; + PsiExpression qualifier = refExpr.getQualifierExpression(); + if (RefactoringHierarchyUtil.willBeInTargetClass(refExpr, membersToMove, targetClass, true)) { + // both member and the reference to it will be in target class + if (!RefactoringUtil.isInMovedElement(refExpr, membersToMove)) { + if (qualifier != null) { + return new MoveMembersProcessor.MoveMembersUsageInfo( + member, + refExpr, + null, + qualifier, + psiReference + ); // remove qualifier + } + } + else { + if (qualifier instanceof PsiReferenceExpression + && ((PsiReferenceExpression) qualifier).isReferenceTo(member.getContainingClass())) { + return new MoveMembersProcessor.MoveMembersUsageInfo( + member, + refExpr, + null, + qualifier, + psiReference + ); // change qualifier + } + } + } + else { + // member in target class, the reference will be outside target class + if (qualifier == null) { + return new MoveMembersProcessor.MoveMembersUsageInfo( + member, + refExpr, + targetClass, + refExpr, + psiReference + ); // add qualifier + } + else { + return new MoveMembersProcessor.MoveMembersUsageInfo( + member, + refExpr, + targetClass, + qualifier, + psiReference + ); // change qualifier + } + } } - } - } - return null; - } - - @Override - public void checkConflictsOnUsage(@Nonnull MoveMembersProcessor.MoveMembersUsageInfo usageInfo, @Nullable String newVisibility, - @Nullable PsiModifierList modifierListCopy, @Nonnull PsiClass targetClass, @Nonnull Set membersToMove, - @Nonnull MultiMap conflicts) { - final PsiElement element = usageInfo.getElement(); - if (element == null) { - return; + return null; } - final PsiMember member = usageInfo.member; - if (element instanceof PsiReferenceExpression) { - PsiExpression qualifier = ((PsiReferenceExpression) element).getQualifierExpression(); - PsiClass accessObjectClass = null; - if (qualifier != null) { - accessObjectClass = (PsiClass) PsiUtil.getAccessObjectClass(qualifier).getElement(); - } + @Override + public void checkConflictsOnUsage( + @Nonnull MoveMembersProcessor.MoveMembersUsageInfo usageInfo, + @Nullable String newVisibility, + @Nullable PsiModifierList modifierListCopy, + @Nonnull PsiClass targetClass, + @Nonnull Set membersToMove, + @Nonnull MultiMap conflicts + ) { + final PsiElement element = usageInfo.getElement(); + if (element == null) { + return; + } - if (!JavaResolveUtil.isAccessible(member, targetClass, modifierListCopy, element, accessObjectClass, null)) { - String visibility = newVisibility != null ? newVisibility : VisibilityUtil.getVisibilityStringToDisplay(member); - LocalizeValue message = RefactoringLocalize.zeroWith1VisibilityIsNotAccessibleFrom2( - RefactoringUIUtil.getDescription(member, false), - visibility, - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) - ); - conflicts.putValue(member, CommonRefactoringUtil.capitalize(message.get())); - } - } + final PsiMember member = usageInfo.member; + if (element instanceof PsiReferenceExpression) { + PsiExpression qualifier = ((PsiReferenceExpression) element).getQualifierExpression(); + PsiClass accessObjectClass = null; + if (qualifier != null) { + accessObjectClass = (PsiClass) PsiUtil.getAccessObjectClass(qualifier).getElement(); + } - if (member instanceof PsiField && targetClass.isInterface()) { - ReadWriteAccessDetector accessDetector = ReadWriteAccessDetector.findDetector(member); - if (accessDetector != null) { - ReadWriteAccessDetector.Access access = accessDetector.getExpressionAccess(element); - if (access != ReadWriteAccessDetector.Access.Read) { - String message = RefactoringUIUtil.getDescription(member, true) + " has write access but is moved to an interface"; - conflicts.putValue(element, CommonRefactoringUtil.capitalize(message)); + if (!JavaResolveUtil.isAccessible(member, targetClass, modifierListCopy, element, accessObjectClass, null)) { + String visibility = newVisibility != null ? newVisibility : VisibilityUtil.getVisibilityStringToDisplay(member); + LocalizeValue message = RefactoringLocalize.zeroWith1VisibilityIsNotAccessibleFrom2( + RefactoringUIUtil.getDescription(member, false), + visibility, + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true) + ); + conflicts.putValue(member, message.capitalize()); + } } - } - } - final PsiReference reference = usageInfo.getReference(); - if (reference != null) { - RefactoringConflictsUtil.checkAccessibilityConflicts(reference, member, modifierListCopy, targetClass, membersToMove, conflicts); - } - } + if (member instanceof PsiField && targetClass.isInterface()) { + ReadWriteAccessDetector accessDetector = ReadWriteAccessDetector.findDetector(member); + if (accessDetector != null) { + ReadWriteAccessDetector.Access access = accessDetector.getExpressionAccess(element); + if (access != ReadWriteAccessDetector.Access.Read) { + String message = RefactoringUIUtil.getDescription(member, true) + " has write access but is moved to an interface"; + conflicts.putValue(element, LocalizeValue.localizeTODO(CommonRefactoringUtil.capitalize(message))); + } + } + } - @Override - public void checkConflictsOnMember(@Nonnull PsiMember member, @Nullable String newVisibility, @Nullable PsiModifierList modifierListCopy, - @Nonnull PsiClass targetClass, @Nonnull Set membersToMove, @Nonnull MultiMap conflicts) { - if (member instanceof PsiMethod && hasMethod(targetClass, (PsiMethod) member) || member instanceof PsiField && hasField(targetClass, - (PsiField) member)) { - LocalizeValue message = - RefactoringLocalize.zeroAlreadyExistsInTheTargetClass(RefactoringUIUtil.getDescription(member, false)); - conflicts.putValue(member, CommonRefactoringUtil.capitalize(message.get())); + final PsiReference reference = usageInfo.getReference(); + if (reference != null) { + RefactoringConflictsUtil.checkAccessibilityConflicts( + reference, + member, + modifierListCopy, + targetClass, + membersToMove, + conflicts + ); + } } - RefactoringConflictsUtil.checkUsedElements(member, member, membersToMove, null, targetClass, targetClass, conflicts); - } + @Override + public void checkConflictsOnMember( + @Nonnull PsiMember member, + @Nullable String newVisibility, + @Nullable PsiModifierList modifierListCopy, + @Nonnull PsiClass targetClass, + @Nonnull Set membersToMove, + @Nonnull MultiMap conflicts + ) { + if (member instanceof PsiMethod && hasMethod(targetClass, (PsiMethod) member) + || member instanceof PsiField && hasField(targetClass, (PsiField) member)) { + LocalizeValue message = + RefactoringLocalize.zeroAlreadyExistsInTheTargetClass(RefactoringUIUtil.getDescription(member, false)); + conflicts.putValue(member, message.capitalize()); + } - protected static boolean hasMethod(PsiClass targetClass, PsiMethod method) { - PsiMethod[] targetClassMethods = targetClass.getMethods(); - for (PsiMethod candidate : targetClassMethods) { - if (candidate != method && MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY), - candidate.getSignature(PsiSubstitutor.EMPTY))) { - return true; - } + RefactoringConflictsUtil.checkUsedElements(member, member, membersToMove, null, targetClass, targetClass, conflicts); } - return false; - } - protected static boolean hasField(PsiClass targetClass, PsiField field) { - String fieldName = field.getName(); - PsiField[] targetClassFields = targetClass.getFields(); - for (PsiField candidate : targetClassFields) { - if (candidate != field && fieldName.equals(candidate.getName())) { - return true; - } + protected static boolean hasMethod(PsiClass targetClass, PsiMethod method) { + PsiMethod[] targetClassMethods = targetClass.getMethods(); + for (PsiMethod candidate : targetClassMethods) { + if (candidate != method && MethodSignatureUtil.areSignaturesEqual( + method.getSignature(PsiSubstitutor.EMPTY), + candidate.getSignature(PsiSubstitutor.EMPTY) + )) { + return true; + } + } + return false; } - return false; - } - @Override - public boolean changeExternalUsage(@Nonnull MoveMembersOptions options, @Nonnull MoveMembersProcessor.MoveMembersUsageInfo usage) { - final PsiElement element = usage.getElement(); - if (element == null || !element.isValid()) { - return true; + protected static boolean hasField(PsiClass targetClass, PsiField field) { + String fieldName = field.getName(); + PsiField[] targetClassFields = targetClass.getFields(); + for (PsiField candidate : targetClassFields) { + if (candidate != field && fieldName.equals(candidate.getName())) { + return true; + } + } + return false; } - if (usage.reference instanceof PsiReferenceExpression) { - PsiReferenceExpression refExpr = (PsiReferenceExpression) usage.reference; - PsiExpression qualifier = refExpr.getQualifierExpression(); - if (qualifier != null) { - if (usage.qualifierClass != null && PsiTreeUtil.getParentOfType(refExpr, PsiSwitchLabelStatement.class) == null) { - changeQualifier(refExpr, usage.qualifierClass, usage.member); - } else { - final PsiReferenceParameterList parameterList = refExpr.getParameterList(); - if (parameterList != null && parameterList.getTypeArguments().length == 0) { - refExpr.setQualifierExpression(null); - } else { - final Project project = element.getProject(); - final PsiClass targetClass = JavaPsiFacade.getInstance(project).findClass(options.getTargetClassName(), - GlobalSearchScope.projectScope(project)); - if (targetClass != null) { - changeQualifier(refExpr, targetClass, usage.member); - } - } + @Override + public boolean changeExternalUsage(@Nonnull MoveMembersOptions options, @Nonnull MoveMembersProcessor.MoveMembersUsageInfo usage) { + final PsiElement element = usage.getElement(); + if (element == null || !element.isValid()) { + return true; } - } else { // no qualifier - if (usage.qualifierClass != null && PsiTreeUtil.getParentOfType(refExpr, PsiSwitchLabelStatement.class) == null) { - changeQualifier(refExpr, usage.qualifierClass, usage.member); + + if (usage.reference instanceof PsiReferenceExpression) { + PsiReferenceExpression refExpr = (PsiReferenceExpression) usage.reference; + PsiExpression qualifier = refExpr.getQualifierExpression(); + if (qualifier != null) { + if (usage.qualifierClass != null && PsiTreeUtil.getParentOfType(refExpr, PsiSwitchLabelStatement.class) == null) { + changeQualifier(refExpr, usage.qualifierClass, usage.member); + } + else { + final PsiReferenceParameterList parameterList = refExpr.getParameterList(); + if (parameterList != null && parameterList.getTypeArguments().length == 0) { + refExpr.setQualifierExpression(null); + } + else { + final Project project = element.getProject(); + final PsiClass targetClass = JavaPsiFacade.getInstance(project).findClass( + options.getTargetClassName(), + GlobalSearchScope.projectScope(project) + ); + if (targetClass != null) { + changeQualifier(refExpr, targetClass, usage.member); + } + } + } + } + else { // no qualifier + if (usage.qualifierClass != null && PsiTreeUtil.getParentOfType(refExpr, PsiSwitchLabelStatement.class) == null) { + changeQualifier(refExpr, usage.qualifierClass, usage.member); + } + } + return true; } - } - return true; + return false; } - return false; - } - protected static void changeQualifier(PsiReferenceExpression refExpr, PsiClass aClass, PsiMember member) throws IncorrectOperationException { - if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) { - refExpr.setQualifierExpression(null); - } else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)) { - PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory(); - refExpr.setQualifierExpression(factory.createReferenceExpression(aClass)); + protected static void changeQualifier( + PsiReferenceExpression refExpr, + PsiClass aClass, + PsiMember member + ) throws IncorrectOperationException { + if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) { + refExpr.setQualifierExpression(null); + } + else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)) { + PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory(); + refExpr.setQualifierExpression(factory.createReferenceExpression(aClass)); + } } - } - @Override - @Nonnull - public PsiMember doMove(@Nonnull MoveMembersOptions options, @Nonnull PsiMember member, PsiElement anchor, @Nonnull PsiClass targetClass) { - if (member instanceof PsiVariable) { - ((PsiVariable) member).normalizeDeclaration(); - } + @Override + @Nonnull + public PsiMember doMove( + @Nonnull MoveMembersOptions options, + @Nonnull PsiMember member, + PsiElement anchor, + @Nonnull PsiClass targetClass + ) { + if (member instanceof PsiVariable) { + ((PsiVariable) member).normalizeDeclaration(); + } - ChangeContextUtil.encodeContextInfo(member, true); + ChangeContextUtil.encodeContextInfo(member, true); - final PsiMember memberCopy; - if (options.makeEnumConstant() && - member instanceof PsiVariable && - EnumConstantsUtil.isSuitableForEnumConstant(((PsiVariable) member).getType(), targetClass)) { - memberCopy = EnumConstantsUtil.createEnumConstant(targetClass, member.getName(), ((PsiVariable) member).getInitializer()); - } else { - memberCopy = (PsiMember) member.copy(); - final PsiClass containingClass = member.getContainingClass(); - if (containingClass != null && containingClass.isInterface() && !targetClass.isInterface()) { - // might need to make modifiers explicit, see IDEADEV-11416 - final PsiModifierList list = memberCopy.getModifierList(); - assert list != null; - list.setModifierProperty(PsiModifier.STATIC, member.hasModifierProperty(PsiModifier.STATIC)); - list.setModifierProperty(PsiModifier.FINAL, member.hasModifierProperty(PsiModifier.FINAL)); - VisibilityUtil.setVisibility(list, VisibilityUtil.getVisibilityModifier(member.getModifierList())); - } + final PsiMember memberCopy; + if (options.makeEnumConstant() && + member instanceof PsiVariable && + EnumConstantsUtil.isSuitableForEnumConstant(((PsiVariable) member).getType(), targetClass)) { + memberCopy = EnumConstantsUtil.createEnumConstant(targetClass, member.getName(), ((PsiVariable) member).getInitializer()); + } + else { + memberCopy = (PsiMember) member.copy(); + final PsiClass containingClass = member.getContainingClass(); + if (containingClass != null && containingClass.isInterface() && !targetClass.isInterface()) { + // might need to make modifiers explicit, see IDEADEV-11416 + final PsiModifierList list = memberCopy.getModifierList(); + assert list != null; + list.setModifierProperty(PsiModifier.STATIC, member.hasModifierProperty(PsiModifier.STATIC)); + list.setModifierProperty(PsiModifier.FINAL, member.hasModifierProperty(PsiModifier.FINAL)); + VisibilityUtil.setVisibility(list, VisibilityUtil.getVisibilityModifier(member.getModifierList())); + } + } + member.delete(); + return anchor != null ? (PsiMember) targetClass.addAfter(memberCopy, anchor) : (PsiMember) targetClass.add(memberCopy); } - member.delete(); - return anchor != null ? (PsiMember) targetClass.addAfter(memberCopy, anchor) : (PsiMember) targetClass.add(memberCopy); - } - @Override - public void decodeContextInfo(@Nonnull PsiElement scope) { - ChangeContextUtil.decodeContextInfo(scope, null, null); - } + @Override + public void decodeContextInfo(@Nonnull PsiElement scope) { + ChangeContextUtil.decodeContextInfo(scope, null, null); + } - @Override - @Nullable - public PsiElement getAnchor(@Nonnull final PsiMember member, @Nonnull final PsiClass targetClass, final Set membersToMove) { - if (member instanceof PsiField && member.hasModifierProperty(PsiModifier.STATIC)) { - final List afterFields = new ArrayList(); - final PsiExpression psiExpression = ((PsiField) member).getInitializer(); - if (psiExpression != null) { - psiExpression.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceExpression(final PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement psiElement = expression.resolve(); - if (psiElement instanceof PsiField) { - final PsiField psiField = (PsiField) psiElement; - if ((psiField.getContainingClass() == targetClass || membersToMove.contains(psiField)) && !afterFields.contains(psiField)) { - afterFields.add(psiField); - } + @Override + @Nullable + public PsiElement getAnchor(@Nonnull final PsiMember member, @Nonnull final PsiClass targetClass, final Set membersToMove) { + if (member instanceof PsiField && member.hasModifierProperty(PsiModifier.STATIC)) { + final List afterFields = new ArrayList(); + final PsiExpression psiExpression = ((PsiField) member).getInitializer(); + if (psiExpression != null) { + psiExpression.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(final PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement psiElement = expression.resolve(); + if (psiElement instanceof PsiField) { + final PsiField psiField = (PsiField) psiElement; + if ((psiField.getContainingClass() == targetClass || membersToMove.contains(psiField)) && !afterFields.contains( + psiField)) { + afterFields.add(psiField); + } + } + } + }); } - } - }); - } - if (!afterFields.isEmpty()) { - Collections.sort(afterFields, new Comparator() { - @Override - public int compare(final PsiField o1, final PsiField o2) { - return -PsiUtilCore.compareElementsByPosition(o1, o2); - } - }); - return afterFields.get(0); - } + if (!afterFields.isEmpty()) { + Collections.sort(afterFields, new Comparator() { + @Override + public int compare(final PsiField o1, final PsiField o2) { + return -PsiUtilCore.compareElementsByPosition(o1, o2); + } + }); + return afterFields.get(0); + } - final List beforeFields = new ArrayList(); - for (PsiReference psiReference : ReferencesSearch.search(member, new LocalSearchScope(targetClass))) { - final PsiField fieldWithReference = PsiTreeUtil.getParentOfType(psiReference.getElement(), PsiField.class); - if (fieldWithReference != null && !afterFields.contains(fieldWithReference) && fieldWithReference.getContainingClass() == targetClass) { - beforeFields.add(fieldWithReference); + final List beforeFields = new ArrayList(); + for (PsiReference psiReference : ReferencesSearch.search(member, new LocalSearchScope(targetClass))) { + final PsiField fieldWithReference = PsiTreeUtil.getParentOfType(psiReference.getElement(), PsiField.class); + if (fieldWithReference != null + && !afterFields.contains(fieldWithReference) + && fieldWithReference.getContainingClass() == targetClass) { + beforeFields.add(fieldWithReference); + } + } + Collections.sort(beforeFields, PsiUtil.BY_POSITION); + if (!beforeFields.isEmpty()) { + return beforeFields.get(0).getPrevSibling(); + } } - } - Collections.sort(beforeFields, PsiUtil.BY_POSITION); - if (!beforeFields.isEmpty()) { - return beforeFields.get(0).getPrevSibling(); - } + return null; } - return null; - } - @Nonnull - @Override - public Language getLanguage() { - return JavaLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return JavaLanguage.INSTANCE; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersDialog.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersDialog.java index 1bf1e44506..934be4f922 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersDialog.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersDialog.java @@ -28,8 +28,8 @@ import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.util.TreeClassChooser; import com.intellij.java.language.util.TreeClassChooserFactory; +import consulo.annotation.access.RequiredReadAction; import consulo.application.HelpManager; -import consulo.application.util.function.Computable; import consulo.configurable.ConfigurationException; import consulo.document.event.DocumentAdapter; import consulo.document.event.DocumentEvent; @@ -56,9 +56,8 @@ import consulo.ui.ex.awtUnsafe.TargetAWT; import consulo.undoRedo.CommandProcessor; import consulo.usage.UsageViewUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nullable; -import org.jetbrains.annotations.NonNls; import javax.swing.*; import java.awt.*; @@ -68,9 +67,9 @@ import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.function.Supplier; public class MoveMembersDialog extends RefactoringDialog implements MoveMembersOptions { - @NonNls private static final String RECENTS_KEY = "MoveMembersDialog.RECENTS_KEY"; private MyMemberInfoModel myMemberInfoModel; @@ -85,10 +84,11 @@ public class MoveMembersDialog extends RefactoringDialog implements MoveMembersO JavaVisibilityPanel myVisibilityPanel; private final CheckBox myIntroduceEnumConstants = CheckBox.create(RefactoringLocalize.moveEnumConstantCb(), true); + @RequiredUIAccess public MoveMembersDialog( Project project, PsiClass sourceClass, - final PsiClass initialTargetClass, + PsiClass initialTargetClass, Set preselectMembers, MoveCallback moveCallback ) { @@ -103,10 +103,10 @@ public MoveMembersDialog( PsiField[] fields = mySourceClass.getFields(); PsiMethod[] methods = mySourceClass.getMethods(); PsiClass[] innerClasses = mySourceClass.getInnerClasses(); - ArrayList memberList = new ArrayList<>(fields.length + methods.length); + List memberList = new ArrayList<>(fields.length + methods.length); for (PsiClass innerClass : innerClasses) { - if (!innerClass.hasModifierProperty(PsiModifier.STATIC)) { + if (!innerClass.isStatic()) { continue; } MemberInfo info = new MemberInfo(innerClass); @@ -117,7 +117,7 @@ public MoveMembersDialog( } boolean hasConstantFields = false; for (PsiField field : fields) { - if (field.hasModifierProperty(PsiModifier.STATIC)) { + if (field.isStatic()) { MemberInfo info = new MemberInfo(field); if (preselectMembers.contains(field)) { info.setChecked(true); @@ -130,7 +130,7 @@ public MoveMembersDialog( myIntroduceEnumConstants.setVisible(false); } for (PsiMethod method : methods) { - if (method.hasModifierProperty(PsiModifier.STATIC)) { + if (method.isStatic()) { MemberInfo info = new MemberInfo(method); if (preselectMembers.contains(method)) { info.setChecked(true); @@ -152,8 +152,9 @@ public MoveMembersDialog( init(); } - @Override @Nullable + @Override + @RequiredUIAccess public String getMemberVisibility() { return myVisibilityPanel.getVisibility(); } @@ -196,6 +197,7 @@ protected JComponent createNorthPanel() { myTfTargetClassName.setButtonIcon(PlatformIconGroup.nodesClass()); myTfTargetClassName.getChildComponent().getDocument().addDocumentListener(new DocumentAdapter() { @Override + @RequiredUIAccess public void documentChanged(DocumentEvent e) { myMemberInfoModel.updateTargetClass(); validateButtons(); @@ -213,8 +215,8 @@ public void documentChanged(DocumentEvent e) { @SuppressWarnings("unchecked") protected JComponent createCenterPanel() { JPanel panel = new JPanel(new BorderLayout()); - final LocalizeValue title = RefactoringLocalize.moveMembersMembersToBeMovedBorderTitle(); - final MemberSelectionPanel selectionPanel = new MemberSelectionPanel(title.get(), myMemberInfos, null); + LocalizeValue title = RefactoringLocalize.moveMembersMembersToBeMovedBorderTitle(); + MemberSelectionPanel selectionPanel = new MemberSelectionPanel(title.get(), myMemberInfos, null); myTable = selectionPanel.getTable(); myMemberInfoModel = new MyMemberInfoModel(); myMemberInfoModel.memberInfoChanged(new MemberInfoChange<>(myMemberInfos)); @@ -230,14 +232,15 @@ protected JComponent createCenterPanel() { } @Override + @RequiredUIAccess public JComponent getPreferredFocusedComponent() { return myTfTargetClassName.getChildComponent(); } @Override public PsiMember[] getSelectedMembers() { - final Collection selectedMemberInfos = myTable.getSelectedMemberInfos(); - ArrayList list = new ArrayList<>(); + Collection selectedMemberInfos = myTable.getSelectedMemberInfos(); + List list = new ArrayList<>(); for (MemberInfo selectedMemberInfo : selectedMemberInfos) { list.add(selectedMemberInfo.getMember()); } @@ -250,11 +253,12 @@ public String getTargetClassName() { } @Override + @RequiredUIAccess protected void doAction() { - String message = validateInputData(); + LocalizeValue message = validateInputData(); if (message != null) { - if (message.length() != 0) { + if (message != LocalizeValue.empty()) { CommonRefactoringUtil.showErrorMessage( MoveMembersImpl.REFACTORING_NAME, message, @@ -267,6 +271,7 @@ protected void doAction() { invokeRefactoring(new MoveMembersProcessor(getProject(), myMoveCallback, new MoveMembersOptions() { @Override + @RequiredUIAccess public String getMemberVisibility() { return MoveMembersDialog.this.getMemberVisibility(); } @@ -297,45 +302,49 @@ protected void canRun() throws ConfigurationException { @Nullable @RequiredUIAccess - private String validateInputData() { - final PsiManager manager = PsiManager.getInstance(myProject); - final String fqName = getTargetClassName(); + private LocalizeValue validateInputData() { + PsiManager manager = PsiManager.getInstance(myProject); + String fqName = getTargetClassName(); if (fqName != null && fqName.isEmpty()) { - return RefactoringLocalize.noDestinationClassSpecified().get(); + return RefactoringLocalize.noDestinationClassSpecified(); } else { if (!PsiNameHelper.getInstance(manager.getProject()).isQualifiedName(fqName)) { - return RefactoringLocalize.zeroIsNotALegalFqName(fqName).get(); + return RefactoringLocalize.zeroIsNotALegalFqName(fqName); } else { RecentsManager.getInstance(myProject).registerRecentEntry(RECENTS_KEY, fqName); - final PsiClass[] targetClass = new PsiClass[]{null}; - CommandProcessor.getInstance().executeCommand(myProject, () -> { - try { - targetClass[0] = findOrCreateTargetClass(manager, fqName); - } - catch (IncorrectOperationException e) { - CommonRefactoringUtil.showErrorMessage( - MoveMembersImpl.REFACTORING_NAME, - e.getMessage(), - HelpID.MOVE_MEMBERS, - myProject); - } - }, RefactoringLocalize.createClassCommand(fqName).get(), null); + PsiClass[] targetClass = new PsiClass[]{null}; + CommandProcessor.getInstance().newCommand() + .project(myProject) + .name(RefactoringLocalize.createClassCommand(fqName)) + .run(() -> { + try { + targetClass[0] = findOrCreateTargetClass(manager, fqName); + } + catch (IncorrectOperationException e) { + CommonRefactoringUtil.showErrorMessage( + MoveMembersImpl.REFACTORING_NAME, + LocalizeValue.ofNullable(e.getMessage()), + HelpID.MOVE_MEMBERS, + myProject + ); + } + }); if (targetClass[0] == null) { - return ""; + return LocalizeValue.empty(); } if (mySourceClass.equals(targetClass[0])) { - return RefactoringLocalize.sourceAndDestinationClassesShouldBeDifferent().get(); + return RefactoringLocalize.sourceAndDestinationClassesShouldBeDifferent(); } else if (!mySourceClass.getLanguage().equals(targetClass[0].getLanguage())) { return RefactoringLocalize.moveToDifferentLanguage( UsageViewUtil.getType(mySourceClass), mySourceClass.getQualifiedName(), targetClass[0].getQualifiedName() - ).get(); + ); } else { for (MemberInfo info : myMemberInfos) { @@ -343,13 +352,13 @@ else if (!mySourceClass.getLanguage().equals(targetClass[0].getLanguage())) { continue; } if (PsiTreeUtil.isAncestor(info.getMember(), targetClass[0], false)) { - return RefactoringLocalize.cannotMoveInnerClass0IntoItself(info.getDisplayName()).get(); + return RefactoringLocalize.cannotMoveInnerClass0IntoItself(info.getDisplayName()); } } if (!targetClass[0].isWritable()) { CommonRefactoringUtil.checkReadOnlyStatus(myProject, targetClass[0]); - return ""; + return LocalizeValue.empty(); } return null; @@ -360,9 +369,9 @@ else if (!mySourceClass.getLanguage().equals(targetClass[0].getLanguage())) { @Nullable @RequiredUIAccess - private PsiClass findOrCreateTargetClass(final PsiManager manager, final String fqName) throws IncorrectOperationException { - final String className; - final String packageName; + private PsiClass findOrCreateTargetClass(PsiManager manager, String fqName) throws IncorrectOperationException { + String className; + String packageName; int dotIndex = fqName.lastIndexOf('.'); if (dotIndex >= 0) { packageName = fqName.substring(0, dotIndex); @@ -378,7 +387,7 @@ private PsiClass findOrCreateTargetClass(final PsiManager manager, final String return aClass; } - final PsiDirectory directory = PackageUtil.findOrCreateDirectoryForPackage( + PsiDirectory directory = PackageUtil.findOrCreateDirectoryForPackage( myProject, packageName, mySourceClass.getContainingFile().getContainingDirectory(), @@ -392,14 +401,14 @@ private PsiClass findOrCreateTargetClass(final PsiManager manager, final String int answer = Messages.showYesNoDialog( myProject, RefactoringLocalize.class0DoesNotExist(fqName).get(), - MoveMembersImpl.REFACTORING_NAME, + MoveMembersImpl.REFACTORING_NAME.get(), UIUtil.getQuestionIcon() ); if (answer != 0) { return null; } - final Ref eRef = new Ref<>(); - final PsiClass newClass = myProject.getApplication().runWriteAction((Computable) () -> { + SimpleReference eRef = new SimpleReference<>(); + PsiClass newClass = myProject.getApplication().runWriteAction((Supplier) () -> { try { return JavaDirectoryService.getInstance().createClass(directory, className); } @@ -415,22 +424,24 @@ private PsiClass findOrCreateTargetClass(final PsiManager manager, final String } @Override + @RequiredUIAccess protected void doHelpAction() { HelpManager.getInstance().invokeHelp(HelpID.MOVE_MEMBERS); } private class ChooseClassAction implements ActionListener { @Override + @RequiredUIAccess public void actionPerformed(ActionEvent e) { TreeClassChooser chooser = TreeClassChooserFactory.getInstance(myProject).createWithInnerClassesScopeChooser( RefactoringLocalize.chooseDestinationClass().get(), GlobalSearchScope.projectScope(myProject), - aClass -> aClass.getParent() instanceof PsiFile || aClass.hasModifierProperty(PsiModifier.STATIC), + aClass -> aClass.getParent() instanceof PsiFile || aClass.isStatic(), null ); - final String targetClassName = getTargetClassName(); + String targetClassName = getTargetClassName(); if (targetClassName != null) { - final PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(targetClassName, GlobalSearchScope.allScope(myProject)); + PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(targetClassName, GlobalSearchScope.allScope(myProject)); if (aClass != null) { chooser.selectDirectory(aClass.getContainingFile().getContainingDirectory()); } @@ -464,6 +475,7 @@ public boolean isCheckedWhenDisabled(MemberInfo member) { return false; } + @RequiredReadAction public boolean isMemberEnabled(MemberInfo member) { if (myTargetClass != null && myTargetClass.isInterface() && !PsiUtil.isLanguageLevel8OrHigher(myTargetClass)) { return !(member.getMember() instanceof PsiMethod); @@ -471,8 +483,9 @@ public boolean isMemberEnabled(MemberInfo member) { return super.isMemberEnabled(member); } + @RequiredUIAccess public void updateTargetClass() { - final PsiManager manager = PsiManager.getInstance(myProject); + PsiManager manager = PsiManager.getInstance(myProject); myTargetClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(getTargetClassName(), GlobalSearchScope.projectScope(myProject)); myTable.fireExternalDataChange(); diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersImpl.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersImpl.java index e75d1538b6..f04fefbd8d 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersImpl.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersImpl.java @@ -14,16 +14,11 @@ * limitations under the License. */ -/** - * created at Nov 21, 2001 - * @author Jeka - */ package com.intellij.java.impl.refactoring.move.moveMembers; import com.intellij.java.impl.refactoring.HelpID; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiFormatUtil; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.move.MoveCallback; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; @@ -35,90 +30,95 @@ import java.util.HashSet; import java.util.Set; +/** + * @author Jeka + * @since 2001-11-21 + */ public class MoveMembersImpl { - public static final String REFACTORING_NAME = RefactoringBundle.message("move.members.title"); - - /** - * element should be either not anonymous PsiClass whose members should be moved - * or PsiMethod of a non-anonymous PsiClass - * or PsiField of a non-anonymous PsiClass - * or Inner PsiClass - */ - @RequiredUIAccess - public static void doMove(final Project project, PsiElement[] elements, PsiElement targetContainer, MoveCallback moveCallback) { - if (elements.length == 0) { - return; - } + public static final LocalizeValue REFACTORING_NAME = RefactoringLocalize.moveMembersTitle(); - final PsiClass sourceClass; - final PsiElement first = elements[0]; - if (first instanceof PsiMember && ((PsiMember)first).getContainingClass() != null) { - sourceClass = ((PsiMember)first).getContainingClass(); - } else { - return; - } - - final Set preselectMembers = new HashSet(); - for (PsiElement element : elements) { - if (element instanceof PsiMember && !sourceClass.equals(((PsiMember)element).getContainingClass())) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.membersToBeMovedShouldBelongToTheSameClass()); - CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message.get(), HelpID.MOVE_MEMBERS, project); - return; - } - if (element instanceof PsiField) { - PsiField field = (PsiField)element; - if (!field.hasModifierProperty(PsiModifier.STATIC)) { - String fieldName = PsiFormatUtil.formatVariable( - field, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER, - PsiSubstitutor.EMPTY); - LocalizeValue message = RefactoringLocalize.field0IsNotStatic(fieldName, REFACTORING_NAME); - CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message.get(), HelpID.MOVE_MEMBERS, project); - return; + /** + * element should be either not anonymous PsiClass whose members should be moved + * or PsiMethod of a non-anonymous PsiClass + * or PsiField of a non-anonymous PsiClass + * or Inner PsiClass + */ + @RequiredUIAccess + public static void doMove(Project project, PsiElement[] elements, PsiElement targetContainer, MoveCallback moveCallback) { + if (elements.length == 0) { + return; } - preselectMembers.add(field); - } - else if (element instanceof PsiMethod) { - PsiMethod method = (PsiMethod)element; - String methodName = PsiFormatUtil.formatMethod( - method, - PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_TYPE - ); - if (method.isConstructor()) { - LocalizeValue message = RefactoringLocalize.zeroRefactoringCannotBeAppliedToConstructors(REFACTORING_NAME); - CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message.get(), HelpID.MOVE_MEMBERS, project); - return; + + PsiClass sourceClass; + if (elements[0] instanceof PsiMember firstMember && firstMember.getContainingClass() != null) { + sourceClass = firstMember.getContainingClass(); } - if (!method.hasModifierProperty(PsiModifier.STATIC)) { - LocalizeValue message = RefactoringLocalize.method0IsNotStatic(methodName, REFACTORING_NAME); - CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message.get(), HelpID.MOVE_MEMBERS, project); - return; + else { + return; } - preselectMembers.add(method); - } - else if (element instanceof PsiClass) { - PsiClass aClass = (PsiClass)element; - if (!aClass.hasModifierProperty(PsiModifier.STATIC)) { - LocalizeValue message = RefactoringLocalize.innerClass0IsNotStatic(aClass.getQualifiedName(), REFACTORING_NAME); - CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message.get(), HelpID.MOVE_MEMBERS, project); - return; + + Set preselectMembers = new HashSet<>(); + for (PsiElement element : elements) { + if (element instanceof PsiMember member && !sourceClass.equals(member.getContainingClass())) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.membersToBeMovedShouldBelongToTheSameClass()); + CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message, HelpID.MOVE_MEMBERS, project); + return; + } + if (element instanceof PsiField field) { + if (!field.isStatic()) { + String fieldName = PsiFormatUtil.formatVariable( + field, + PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER, + PsiSubstitutor.EMPTY + ); + LocalizeValue message = RefactoringLocalize.field0IsNotStatic(fieldName, REFACTORING_NAME); + CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message, HelpID.MOVE_MEMBERS, project); + return; + } + preselectMembers.add(field); + } + else if (element instanceof PsiMethod method) { + String methodName = PsiFormatUtil.formatMethod( + method, + PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS, + PsiFormatUtil.SHOW_TYPE + ); + if (method.isConstructor()) { + LocalizeValue message = RefactoringLocalize.zeroRefactoringCannotBeAppliedToConstructors(REFACTORING_NAME); + CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message, HelpID.MOVE_MEMBERS, project); + return; + } + if (!method.isStatic()) { + LocalizeValue message = RefactoringLocalize.method0IsNotStatic(methodName, REFACTORING_NAME); + CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message, HelpID.MOVE_MEMBERS, project); + return; + } + preselectMembers.add(method); + } + else if (element instanceof PsiClass aClass) { + if (!aClass.isStatic()) { + LocalizeValue message = RefactoringLocalize.innerClass0IsNotStatic(aClass.getQualifiedName(), REFACTORING_NAME); + CommonRefactoringUtil.showErrorMessage(REFACTORING_NAME, message, HelpID.MOVE_MEMBERS, project); + return; + } + preselectMembers.add(aClass); + } } - preselectMembers.add(aClass); - } - } - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, sourceClass)) return; + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, sourceClass)) { + return; + } - final PsiClass initialTargerClass = targetContainer instanceof PsiClass? (PsiClass) targetContainer : null; + PsiClass initialTargetClass = targetContainer instanceof PsiClass targetClass ? targetClass : null; - MoveMembersDialog dialog = new MoveMembersDialog( + MoveMembersDialog dialog = new MoveMembersDialog( project, sourceClass, - initialTargerClass, + initialTargetClass, preselectMembers, - moveCallback); - dialog.show(); - } + moveCallback + ); + dialog.show(); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaClassProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaClassProcessor.java index 7a6c1555c1..7eba7f20a0 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaClassProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaClassProcessor.java @@ -37,6 +37,7 @@ import consulo.language.psi.search.ReferencesSearch; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; import consulo.usage.MoveRenameUsageInfo; @@ -57,55 +58,66 @@ */ @ExtensionImpl public class RenameJavaClassProcessor extends RenamePsiElementProcessor { - private static final Logger LOG = Logger.getInstance(RenameJavaClassProcessor.class); + private static final Logger LOG = Logger.getInstance(RenameJavaClassProcessor.class); - public boolean canProcessElement(@Nonnull final PsiElement element) { - return element instanceof PsiClass; - } + public boolean canProcessElement(@Nonnull final PsiElement element) { + return element instanceof PsiClass; + } - public void renameElement(final PsiElement element, - final String newName, - final UsageInfo[] usages, - @Nullable RefactoringElementListener listener) throws IncorrectOperationException { - PsiClass aClass = (PsiClass) element; - ArrayList postponedCollisions = new ArrayList(); - List hidesOut = new ArrayList(); - // rename all references - for (final UsageInfo usage : usages) { - if (usage instanceof ResolvableCollisionUsageInfo) { - if (usage instanceof CollidingClassImportUsageInfo) { - ((CollidingClassImportUsageInfo) usage).getImportStatement().delete(); - } else if (usage instanceof MemberHidesOuterMemberUsageInfo) { - hidesOut.add((MemberHidesOuterMemberUsageInfo) usage); - } else { - postponedCollisions.add(usage); + public void renameElement( + final PsiElement element, + final String newName, + final UsageInfo[] usages, + @Nullable RefactoringElementListener listener + ) throws IncorrectOperationException { + PsiClass aClass = (PsiClass) element; + ArrayList postponedCollisions = new ArrayList(); + List hidesOut = new ArrayList(); + // rename all references + for (final UsageInfo usage : usages) { + if (usage instanceof ResolvableCollisionUsageInfo) { + if (usage instanceof CollidingClassImportUsageInfo) { + ((CollidingClassImportUsageInfo) usage).getImportStatement().delete(); + } + else if (usage instanceof MemberHidesOuterMemberUsageInfo) { + hidesOut.add((MemberHidesOuterMemberUsageInfo) usage); + } + else { + postponedCollisions.add(usage); + } + } } - } - } - // do actual rename - ChangeContextUtil.encodeContextInfo(aClass.getContainingFile(), true, false); - aClass.setName(newName); + // do actual rename + ChangeContextUtil.encodeContextInfo(aClass.getContainingFile(), true, false); + aClass.setName(newName); - for (UsageInfo usage : usages) { - if (!(usage instanceof ResolvableCollisionUsageInfo)) { - final PsiReference ref = usage.getReference(); - if (ref == null) continue; - try { - ref.bindToElement(aClass); - } catch (IncorrectOperationException e) {//fall back to old scheme - ref.handleElementRename(newName); + for (UsageInfo usage : usages) { + if (!(usage instanceof ResolvableCollisionUsageInfo)) { + final PsiReference ref = usage.getReference(); + if (ref == null) { + continue; + } + try { + ref.bindToElement(aClass); + } + catch (IncorrectOperationException e) {//fall back to old scheme + ref.handleElementRename(newName); + } + } } - } - } - ChangeContextUtil.decodeContextInfo(aClass.getContainingFile(), null, null); //to make refs to other classes from this one resolve to their old referent + ChangeContextUtil.decodeContextInfo( + aClass.getContainingFile(), + null, + null + ); //to make refs to other classes from this one resolve to their old referent - // resolve collisions - for (UsageInfo postponedCollision : postponedCollisions) { - ClassHidesImportedClassUsageInfo collision = (ClassHidesImportedClassUsageInfo) postponedCollision; - collision.resolveCollision(); - } + // resolve collisions + for (UsageInfo postponedCollision : postponedCollisions) { + ClassHidesImportedClassUsageInfo collision = (ClassHidesImportedClassUsageInfo) postponedCollision; + collision.resolveCollision(); + } /*for (MemberHidesOuterMemberUsageInfo usage : hidesOut) { PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement)usage.getElement(); @@ -114,227 +126,259 @@ public void renameElement(final PsiElement element, }*/ - if (listener != null) { - listener.elementRenamed(aClass); + if (listener != null) { + listener.elementRenamed(aClass); + } } - } - @Nullable - public Pair getTextOccurrenceSearchStrings(@Nonnull final PsiElement element, @Nonnull final String newName) { - if (element instanceof PsiClass) { - final PsiClass aClass = (PsiClass) element; - if (aClass.getParent() instanceof PsiClass) { - final String dollaredStringToSearch = ClassUtil.getJVMClassName(aClass); - final String dollaredStringToReplace = dollaredStringToSearch == null ? null : RefactoringUtil.getNewInnerClassName(aClass, dollaredStringToSearch, newName); - if (dollaredStringToReplace != null) { - return new Pair(dollaredStringToSearch, dollaredStringToReplace); + @Nullable + public Pair getTextOccurrenceSearchStrings(@Nonnull final PsiElement element, @Nonnull final String newName) { + if (element instanceof PsiClass) { + final PsiClass aClass = (PsiClass) element; + if (aClass.getParent() instanceof PsiClass) { + final String dollaredStringToSearch = ClassUtil.getJVMClassName(aClass); + final String dollaredStringToReplace = + dollaredStringToSearch == null ? null : RefactoringUtil.getNewInnerClassName(aClass, dollaredStringToSearch, newName); + if (dollaredStringToReplace != null) { + return new Pair(dollaredStringToSearch, dollaredStringToReplace); + } + } } - } + return null; } - return null; - } - public String getQualifiedNameAfterRename(final PsiElement element, final String newName, final boolean nonJava) { - if (nonJava) { - final PsiClass aClass = (PsiClass) element; - return PsiUtilCore.getQualifiedNameAfterRename(aClass.getQualifiedName(), newName); - } else { - return newName; + public String getQualifiedNameAfterRename(final PsiElement element, final String newName, final boolean nonJava) { + if (nonJava) { + final PsiClass aClass = (PsiClass) element; + return PsiUtilCore.getQualifiedNameAfterRename(aClass.getQualifiedName(), newName); + } + else { + return newName; + } } - } - @Override - public void prepareRenaming(PsiElement element, String newName, Map allRenames, SearchScope scope) { - final PsiMethod[] constructors = ((PsiClass) element).getConstructors(); - for (PsiMethod constructor : constructors) { - if (constructor instanceof PsiMirrorElement) { - final PsiElement prototype = ((PsiMirrorElement) constructor).getPrototype(); - if (prototype instanceof PsiNamedElement) { - allRenames.put(prototype, newName); + @Override + public void prepareRenaming(PsiElement element, String newName, Map allRenames, SearchScope scope) { + final PsiMethod[] constructors = ((PsiClass) element).getConstructors(); + for (PsiMethod constructor : constructors) { + if (constructor instanceof PsiMirrorElement) { + final PsiElement prototype = ((PsiMirrorElement) constructor).getPrototype(); + if (prototype instanceof PsiNamedElement) { + allRenames.put(prototype, newName); + } + } + else if (!(constructor instanceof LightElement)) { + allRenames.put(constructor, newName); + } } - } else if (!(constructor instanceof LightElement)) { - allRenames.put(constructor, newName); - } } - } - public void findCollisions(final PsiElement element, final String newName, final Map allRenames, final List result) { - final PsiClass aClass = (PsiClass) element; - final ClassCollisionsDetector classCollisionsDetector = new ClassCollisionsDetector(aClass); - Collection initialResults = new ArrayList(result); - for (UsageInfo usageInfo : initialResults) { - if (usageInfo instanceof MoveRenameUsageInfo) { - classCollisionsDetector.addClassCollisions(usageInfo.getElement(), newName, result); - } - } - findSubmemberHidesMemberCollisions(aClass, newName, result); + public void findCollisions( + final PsiElement element, + final String newName, + final Map allRenames, + final List result + ) { + final PsiClass aClass = (PsiClass) element; + final ClassCollisionsDetector classCollisionsDetector = new ClassCollisionsDetector(aClass); + Collection initialResults = new ArrayList(result); + for (UsageInfo usageInfo : initialResults) { + if (usageInfo instanceof MoveRenameUsageInfo) { + classCollisionsDetector.addClassCollisions(usageInfo.getElement(), newName, result); + } + } + findSubmemberHidesMemberCollisions(aClass, newName, result); - if (aClass instanceof PsiTypeParameter) { - final PsiTypeParameterListOwner owner = ((PsiTypeParameter) aClass).getOwner(); - if (owner != null) { - for (PsiTypeParameter typeParameter : owner.getTypeParameters()) { - if (Comparing.equal(newName, typeParameter.getName())) { - result.add(new UnresolvableCollisionUsageInfo(aClass, typeParameter) { - @Override - public String getDescription() { - return "There is already type parameter in " + RefactoringUIUtil.getDescription(aClass, false) + " with name " + newName; - } - }); - } + if (aClass instanceof PsiTypeParameter) { + final PsiTypeParameterListOwner owner = ((PsiTypeParameter) aClass).getOwner(); + if (owner != null) { + for (PsiTypeParameter typeParameter : owner.getTypeParameters()) { + if (Comparing.equal(newName, typeParameter.getName())) { + result.add(new UnresolvableCollisionUsageInfo(aClass, typeParameter) { + @Override + public String getDescription() { + return "There is already type parameter in " + RefactoringUIUtil.getDescription( + aClass, + false + ) + " with name " + newName; + } + }); + } + } + } } - } } - } - public static void findSubmemberHidesMemberCollisions(final PsiClass aClass, final String newName, final List result) { - if (aClass.getParent() instanceof PsiClass) { - PsiClass parent = (PsiClass) aClass.getParent(); - Collection inheritors = ClassInheritorsSearch.search(parent, true).findAll(); - for (PsiClass inheritor : inheritors) { - if (newName.equals(inheritor.getName())) { - final ClassCollisionsDetector classCollisionsDetector = new ClassCollisionsDetector(aClass); - for (PsiReference reference : ReferencesSearch.search(inheritor, new LocalSearchScope(inheritor))) { - classCollisionsDetector.addClassCollisions(reference.getElement(), newName, result); - } - } - PsiClass[] inners = inheritor.getInnerClasses(); - for (PsiClass inner : inners) { - if (newName.equals(inner.getName())) { - result.add(new SubmemberHidesMemberUsageInfo(inner, aClass)); - } - } - } - } else if (aClass instanceof PsiTypeParameter) { - final PsiTypeParameterListOwner owner = ((PsiTypeParameter) aClass).getOwner(); - if (owner instanceof PsiClass) { - final PsiClass[] supers = ((PsiClass) owner).getSupers(); - for (PsiClass superClass : supers) { - if (newName.equals(superClass.getName())) { - final ClassCollisionsDetector classCollisionsDetector = new ClassCollisionsDetector(aClass); - for (PsiReference reference : ReferencesSearch.search(superClass, new LocalSearchScope(superClass))) { - classCollisionsDetector.addClassCollisions(reference.getElement(), newName, result); + public static void findSubmemberHidesMemberCollisions(final PsiClass aClass, final String newName, final List result) { + if (aClass.getParent() instanceof PsiClass) { + PsiClass parent = (PsiClass) aClass.getParent(); + Collection inheritors = ClassInheritorsSearch.search(parent, true).findAll(); + for (PsiClass inheritor : inheritors) { + if (newName.equals(inheritor.getName())) { + final ClassCollisionsDetector classCollisionsDetector = new ClassCollisionsDetector(aClass); + for (PsiReference reference : ReferencesSearch.search(inheritor, new LocalSearchScope(inheritor))) { + classCollisionsDetector.addClassCollisions(reference.getElement(), newName, result); + } + } + PsiClass[] inners = inheritor.getInnerClasses(); + for (PsiClass inner : inners) { + if (newName.equals(inner.getName())) { + result.add(new SubmemberHidesMemberUsageInfo(inner, aClass)); + } + } } - } - PsiClass[] inners = superClass.getInnerClasses(); - for (final PsiClass inner : inners) { - if (newName.equals(inner.getName())) { - ReferencesSearch.search(inner).forEach(new Processor() { - public boolean process(final PsiReference reference) { - PsiElement refElement = reference.getElement(); - if (refElement instanceof PsiReferenceExpression && ((PsiReferenceExpression) refElement).isQualified()) - return true; - MemberHidesOuterMemberUsageInfo info = new MemberHidesOuterMemberUsageInfo(refElement, aClass); - result.add(info); - return true; + } + else if (aClass instanceof PsiTypeParameter) { + final PsiTypeParameterListOwner owner = ((PsiTypeParameter) aClass).getOwner(); + if (owner instanceof PsiClass) { + final PsiClass[] supers = ((PsiClass) owner).getSupers(); + for (PsiClass superClass : supers) { + if (newName.equals(superClass.getName())) { + final ClassCollisionsDetector classCollisionsDetector = new ClassCollisionsDetector(aClass); + for (PsiReference reference : ReferencesSearch.search(superClass, new LocalSearchScope(superClass))) { + classCollisionsDetector.addClassCollisions(reference.getElement(), newName, result); + } + } + PsiClass[] inners = superClass.getInnerClasses(); + for (final PsiClass inner : inners) { + if (newName.equals(inner.getName())) { + ReferencesSearch.search(inner).forEach(new Processor() { + public boolean process(final PsiReference reference) { + PsiElement refElement = reference.getElement(); + if (refElement instanceof PsiReferenceExpression && ((PsiReferenceExpression) refElement).isQualified()) { + return true; + } + MemberHidesOuterMemberUsageInfo info = new MemberHidesOuterMemberUsageInfo(refElement, aClass); + result.add(info); + return true; + } + }); + } + } } - }); } - } } - } } - } - - private static class ClassCollisionsDetector { - final HashSet myProcessedFiles = new HashSet(); - final PsiClass myRenamedClass; - private final String myRenamedClassQualifiedName; - public ClassCollisionsDetector(PsiClass renamedClass) { - myRenamedClass = renamedClass; - myRenamedClassQualifiedName = myRenamedClass.getQualifiedName(); - } + private static class ClassCollisionsDetector { + final HashSet myProcessedFiles = new HashSet(); + final PsiClass myRenamedClass; + private final String myRenamedClassQualifiedName; - public void addClassCollisions(PsiElement referenceElement, String newName, List results) { - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(referenceElement.getProject()).getResolveHelper(); - final PsiClass aClass = resolveHelper.resolveReferencedClass(newName, referenceElement); - if (aClass == null) return; - if (aClass instanceof PsiTypeParameter && myRenamedClass instanceof PsiTypeParameter) { - final PsiTypeParameterListOwner member = PsiTreeUtil.getParentOfType(referenceElement, PsiTypeParameterListOwner.class); - if (member != null) { - final PsiTypeParameterList typeParameterList = member.getTypeParameterList(); - if (typeParameterList != null && ArrayUtil.find(typeParameterList.getTypeParameters(), myRenamedClass) > -1) { - if (member.hasModifierProperty(PsiModifier.STATIC)) return; - } + public ClassCollisionsDetector(PsiClass renamedClass) { + myRenamedClass = renamedClass; + myRenamedClassQualifiedName = myRenamedClass.getQualifiedName(); } - } - final PsiFile containingFile = referenceElement.getContainingFile(); - final String text = referenceElement.getText(); - if (Comparing.equal(myRenamedClassQualifiedName, removeSpaces(text))) return; - if (myProcessedFiles.contains(containingFile)) return; - for (PsiReference reference : ReferencesSearch.search(aClass, new LocalSearchScope(containingFile))) { - final PsiElement collisionReferenceElement = reference.getElement(); - if (collisionReferenceElement instanceof PsiJavaCodeReferenceElement) { - final PsiElement parent = collisionReferenceElement.getParent(); - if (parent instanceof PsiImportStatement) { - results.add(new CollidingClassImportUsageInfo((PsiImportStatement) parent, myRenamedClass)); - } else { - if (aClass.getQualifiedName() != null) { - results.add(new ClassHidesImportedClassUsageInfo((PsiJavaCodeReferenceElement) collisionReferenceElement, - myRenamedClass, aClass)); - } else { - results.add(new ClassHidesUnqualifiableClassUsageInfo((PsiJavaCodeReferenceElement) collisionReferenceElement, - myRenamedClass, aClass)); + + public void addClassCollisions(PsiElement referenceElement, String newName, List results) { + final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(referenceElement.getProject()).getResolveHelper(); + final PsiClass aClass = resolveHelper.resolveReferencedClass(newName, referenceElement); + if (aClass == null) { + return; + } + if (aClass instanceof PsiTypeParameter && myRenamedClass instanceof PsiTypeParameter) { + final PsiTypeParameterListOwner member = PsiTreeUtil.getParentOfType(referenceElement, PsiTypeParameterListOwner.class); + if (member != null) { + final PsiTypeParameterList typeParameterList = member.getTypeParameterList(); + if (typeParameterList != null && ArrayUtil.find(typeParameterList.getTypeParameters(), myRenamedClass) > -1) { + if (member.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + } + } + } + final PsiFile containingFile = referenceElement.getContainingFile(); + final String text = referenceElement.getText(); + if (Comparing.equal(myRenamedClassQualifiedName, removeSpaces(text))) { + return; + } + if (myProcessedFiles.contains(containingFile)) { + return; + } + for (PsiReference reference : ReferencesSearch.search(aClass, new LocalSearchScope(containingFile))) { + final PsiElement collisionReferenceElement = reference.getElement(); + if (collisionReferenceElement instanceof PsiJavaCodeReferenceElement) { + final PsiElement parent = collisionReferenceElement.getParent(); + if (parent instanceof PsiImportStatement) { + results.add(new CollidingClassImportUsageInfo((PsiImportStatement) parent, myRenamedClass)); + } + else { + if (aClass.getQualifiedName() != null) { + results.add(new ClassHidesImportedClassUsageInfo((PsiJavaCodeReferenceElement) collisionReferenceElement, + myRenamedClass, aClass + )); + } + else { + results.add(new ClassHidesUnqualifiableClassUsageInfo((PsiJavaCodeReferenceElement) collisionReferenceElement, + myRenamedClass, aClass + )); + } + } + } } - } + myProcessedFiles.add(containingFile); } - } - myProcessedFiles.add(containingFile); } - } - @NonNls - private static final Pattern WHITE_SPACE_PATTERN = Pattern.compile("\\s"); + @NonNls + private static final Pattern WHITE_SPACE_PATTERN = Pattern.compile("\\s"); - private static String removeSpaces(String s) { - return WHITE_SPACE_PATTERN.matcher(s).replaceAll(""); - } + private static String removeSpaces(String s) { + return WHITE_SPACE_PATTERN.matcher(s).replaceAll(""); + } - public void findExistingNameConflicts(final PsiElement element, final String newName, final MultiMap conflicts) { - if (element instanceof PsiCompiledElement) return; - final PsiClass aClass = (PsiClass) element; - if (newName.equals(aClass.getName())) return; - final PsiClass containingClass = aClass.getContainingClass(); - if (containingClass != null) { // innerClass - PsiClass[] innerClasses = containingClass.getInnerClasses(); - for (PsiClass innerClass : innerClasses) { - if (newName.equals(innerClass.getName())) { - conflicts.putValue(innerClass, - RefactoringLocalize.innerClass0IsAlreadyDefinedInClass1(newName, containingClass.getQualifiedName()).get() - ); - break; + @Override + public void findExistingNameConflicts(PsiElement element, String newName, MultiMap conflicts) { + if (element instanceof PsiCompiledElement) { + return; + } + final PsiClass aClass = (PsiClass) element; + if (newName.equals(aClass.getName())) { + return; + } + final PsiClass containingClass = aClass.getContainingClass(); + if (containingClass != null) { // innerClass + PsiClass[] innerClasses = containingClass.getInnerClasses(); + for (PsiClass innerClass : innerClasses) { + if (newName.equals(innerClass.getName())) { + conflicts.putValue( + innerClass, + RefactoringLocalize.innerClass0IsAlreadyDefinedInClass1(newName, containingClass.getQualifiedName()) + ); + break; + } + } + } + else if (!(aClass instanceof PsiTypeParameter)) { + final String qualifiedNameAfterRename = PsiUtilCore.getQualifiedNameAfterRename(aClass.getQualifiedName(), newName); + Project project = element.getProject(); + final PsiClass conflictingClass = + JavaPsiFacade.getInstance(project).findClass(qualifiedNameAfterRename, GlobalSearchScope.allScope(project)); + if (conflictingClass != null) { + conflicts.putValue(conflictingClass, RefactoringLocalize.class0AlreadyExists(qualifiedNameAfterRename)); + } } - } - } else if (!(aClass instanceof PsiTypeParameter)) { - final String qualifiedNameAfterRename = PsiUtilCore.getQualifiedNameAfterRename(aClass.getQualifiedName(), newName); - Project project = element.getProject(); - final PsiClass conflictingClass = - JavaPsiFacade.getInstance(project).findClass(qualifiedNameAfterRename, GlobalSearchScope.allScope(project)); - if (conflictingClass != null) { - conflicts.putValue(conflictingClass, RefactoringLocalize.class0AlreadyExists(qualifiedNameAfterRename).get()); - } } - } - @Nullable - @NonNls - public String getHelpID(final PsiElement element) { - return HelpID.RENAME_CLASS; - } + @Nullable + @NonNls + public String getHelpID(final PsiElement element) { + return HelpID.RENAME_CLASS; + } - public boolean isToSearchInComments(final PsiElement psiElement) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS; - } + public boolean isToSearchInComments(final PsiElement psiElement) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS; + } - public void setToSearchInComments(final PsiElement element, final boolean enabled) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS = enabled; - } + public void setToSearchInComments(final PsiElement element, final boolean enabled) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS = enabled; + } - public boolean isToSearchForTextOccurrences(final PsiElement element) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS; - } + public boolean isToSearchForTextOccurrences(final PsiElement element) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS; + } - public void setToSearchForTextOccurrences(final PsiElement element, final boolean enabled) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS = enabled; - } + public void setToSearchForTextOccurrences(final PsiElement element, final boolean enabled) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS = enabled; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaMethodProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaMethodProcessor.java index 6a0ada6d22..a8141a6698 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaMethodProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaMethodProcessor.java @@ -42,6 +42,7 @@ import consulo.language.psi.scope.GlobalSearchScope; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.usage.MoveRenameUsageInfo; import consulo.usage.UsageInfo; @@ -56,318 +57,373 @@ @ExtensionImpl(id = "javamethod") public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { - private static final Logger LOG = Logger.getInstance(RenameJavaMethodProcessor.class); - - public boolean canProcessElement(@Nonnull final PsiElement element) { - return element instanceof PsiMethod; - } - - public void renameElement(final PsiElement psiElement, - final String newName, - final UsageInfo[] usages, - @Nullable RefactoringElementListener listener) throws IncorrectOperationException { - PsiMethod method = (PsiMethod) psiElement; - Set methodAndOverriders = new HashSet(); - Set containingClasses = new HashSet(); - LinkedHashSet renamedReferences = new LinkedHashSet(); - List outerHides = new ArrayList(); - List staticImportHides = new ArrayList(); - - methodAndOverriders.add(method); - containingClasses.add(method.getContainingClass()); - - // do actual rename of overriding/implementing methods and of references to all them - for (UsageInfo usage : usages) { - PsiElement element = usage.getElement(); - if (element == null) continue; - - if (usage instanceof MemberHidesStaticImportUsageInfo) { - staticImportHides.add((MemberHidesStaticImportUsageInfo) usage); - } else if (usage instanceof MemberHidesOuterMemberUsageInfo) { - PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement) element; - PsiMethod resolved = (PsiMethod) collidingRef.resolve(); - outerHides.add(new MemberHidesOuterMemberUsageInfo(element, resolved)); - } else if (!(element instanceof PsiMethod)) { - final PsiReference ref; - if (usage instanceof MoveRenameUsageInfo) { - ref = usage.getReference(); - } else { - ref = element.getReference(); + private static final Logger LOG = Logger.getInstance(RenameJavaMethodProcessor.class); + + public boolean canProcessElement(@Nonnull final PsiElement element) { + return element instanceof PsiMethod; + } + + public void renameElement( + final PsiElement psiElement, + final String newName, + final UsageInfo[] usages, + @Nullable RefactoringElementListener listener + ) throws IncorrectOperationException { + PsiMethod method = (PsiMethod) psiElement; + Set methodAndOverriders = new HashSet(); + Set containingClasses = new HashSet(); + LinkedHashSet renamedReferences = new LinkedHashSet(); + List outerHides = new ArrayList(); + List staticImportHides = new ArrayList(); + + methodAndOverriders.add(method); + containingClasses.add(method.getContainingClass()); + + // do actual rename of overriding/implementing methods and of references to all them + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element == null) { + continue; + } + + if (usage instanceof MemberHidesStaticImportUsageInfo) { + staticImportHides.add((MemberHidesStaticImportUsageInfo) usage); + } + else if (usage instanceof MemberHidesOuterMemberUsageInfo) { + PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement) element; + PsiMethod resolved = (PsiMethod) collidingRef.resolve(); + outerHides.add(new MemberHidesOuterMemberUsageInfo(element, resolved)); + } + else if (!(element instanceof PsiMethod)) { + final PsiReference ref; + if (usage instanceof MoveRenameUsageInfo) { + ref = usage.getReference(); + } + else { + ref = element.getReference(); + } + if (ref instanceof PsiImportStaticReferenceElement && ((PsiImportStaticReferenceElement) ref).multiResolve(false).length > 1) { + continue; + } + if (ref != null) { + PsiElement e = processRef(ref, newName); + if (e != null) { + renamedReferences.add(e); + } + } + } + else { + PsiMethod overrider = (PsiMethod) element; + methodAndOverriders.add(overrider); + containingClasses.add(overrider.getContainingClass()); + } } - if (ref instanceof PsiImportStaticReferenceElement && ((PsiImportStaticReferenceElement) ref).multiResolve(false).length > 1) { - continue; + + // do actual rename of method + method.setName(newName); + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element instanceof PsiMethod) { + ((PsiMethod) element).setName(newName); + } } - if (ref != null) { - PsiElement e = processRef(ref, newName); - if (e != null) { - renamedReferences.add(e); - } + if (listener != null) { + listener.elementRenamed(method); } - } else { - PsiMethod overrider = (PsiMethod) element; - methodAndOverriders.add(overrider); - containingClasses.add(overrider.getContainingClass()); - } - } - // do actual rename of method - method.setName(newName); - for (UsageInfo usage : usages) { - PsiElement element = usage.getElement(); - if (element instanceof PsiMethod) { - ((PsiMethod) element).setName(newName); - } - } - if (listener != null) { - listener.elementRenamed(method); + for (PsiElement element : renamedReferences) { + fixNameCollisionsWithInnerClassMethod(element, newName, methodAndOverriders, containingClasses, + method.hasModifierProperty(PsiModifier.STATIC) + ); + } + qualifyOuterMemberReferences(outerHides); + qualifyStaticImportReferences(staticImportHides); } - for (PsiElement element : renamedReferences) { - fixNameCollisionsWithInnerClassMethod(element, newName, methodAndOverriders, containingClasses, - method.hasModifierProperty(PsiModifier.STATIC)); + /** + * handles rename of refs + * + * @param ref + * @param newName + * @return + */ + @Nullable + protected PsiElement processRef(PsiReference ref, String newName) { + return ref.handleElementRename(newName); } - qualifyOuterMemberReferences(outerHides); - qualifyStaticImportReferences(staticImportHides); - } - - /** - * handles rename of refs - * - * @param ref - * @param newName - * @return - */ - @Nullable - protected PsiElement processRef(PsiReference ref, String newName) { - return ref.handleElementRename(newName); - } - - private static void fixNameCollisionsWithInnerClassMethod(final PsiElement element, final String newName, - final Set methodAndOverriders, final Set containingClasses, - final boolean isStatic) throws IncorrectOperationException { - if (!(element instanceof PsiReferenceExpression)) return; - PsiElement elem = ((PsiReferenceExpression) element).resolve(); - - if (elem instanceof PsiMethod) { - PsiMethod actualMethod = (PsiMethod) elem; - if (!methodAndOverriders.contains(actualMethod)) { - PsiClass outerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); - while (outerClass != null) { - if (containingClasses.contains(outerClass)) { - qualifyMember(element, newName, outerClass, isStatic); - break; - } - outerClass = PsiTreeUtil.getParentOfType(outerClass, PsiClass.class); + + private static void fixNameCollisionsWithInnerClassMethod( + final PsiElement element, final String newName, + final Set methodAndOverriders, final Set containingClasses, + final boolean isStatic + ) throws IncorrectOperationException { + if (!(element instanceof PsiReferenceExpression)) { + return; + } + PsiElement elem = ((PsiReferenceExpression) element).resolve(); + + if (elem instanceof PsiMethod) { + PsiMethod actualMethod = (PsiMethod) elem; + if (!methodAndOverriders.contains(actualMethod)) { + PsiClass outerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + while (outerClass != null) { + if (containingClasses.contains(outerClass)) { + qualifyMember(element, newName, outerClass, isStatic); + break; + } + outerClass = PsiTreeUtil.getParentOfType(outerClass, PsiClass.class); + } + } } - } } - } - - @Nonnull - public Collection findReferences(final PsiElement element) { - GlobalSearchScope projectScope = GlobalSearchScope.projectScope(element.getProject()); - return MethodReferencesSearch.search((PsiMethod) element, projectScope, true).findAll(); - } - - public void findCollisions(final PsiElement element, final String newName, final Map allRenames, - final List result) { - final PsiMethod methodToRename = (PsiMethod) element; - findSubmemberHidesMemberCollisions(methodToRename, newName, result); - findMemberHidesOuterMemberCollisions((PsiMethod) element, newName, result); - findCollisionsAgainstNewName(methodToRename, newName, result); - findHidingMethodWithOtherSignature(methodToRename, newName, result); - final PsiClass containingClass = methodToRename.getContainingClass(); - if (containingClass != null) { - final PsiMethod patternMethod = (PsiMethod) methodToRename.copy(); - try { - patternMethod.setName(newName); - final PsiMethod methodInBaseClass = containingClass.findMethodBySignature(patternMethod, true); - if (methodInBaseClass != null && methodInBaseClass.getContainingClass() != containingClass) { - if (methodInBaseClass.hasModifierProperty(PsiModifier.FINAL)) { - result.add(new UnresolvableCollisionUsageInfo(methodInBaseClass, methodToRename) { - @Override - public String getDescription() { - return "Renaming method will override final \"" + RefactoringUIUtil.getDescription(methodInBaseClass, true) + "\""; - } - }); - } + + @Nonnull + public Collection findReferences(final PsiElement element) { + GlobalSearchScope projectScope = GlobalSearchScope.projectScope(element.getProject()); + return MethodReferencesSearch.search((PsiMethod) element, projectScope, true).findAll(); + } + + public void findCollisions( + final PsiElement element, + final String newName, + final Map allRenames, + final List result + ) { + final PsiMethod methodToRename = (PsiMethod) element; + findSubmemberHidesMemberCollisions(methodToRename, newName, result); + findMemberHidesOuterMemberCollisions((PsiMethod) element, newName, result); + findCollisionsAgainstNewName(methodToRename, newName, result); + findHidingMethodWithOtherSignature(methodToRename, newName, result); + final PsiClass containingClass = methodToRename.getContainingClass(); + if (containingClass != null) { + final PsiMethod patternMethod = (PsiMethod) methodToRename.copy(); + try { + patternMethod.setName(newName); + final PsiMethod methodInBaseClass = containingClass.findMethodBySignature(patternMethod, true); + if (methodInBaseClass != null && methodInBaseClass.getContainingClass() != containingClass) { + if (methodInBaseClass.hasModifierProperty(PsiModifier.FINAL)) { + result.add(new UnresolvableCollisionUsageInfo(methodInBaseClass, methodToRename) { + @Override + public String getDescription() { + return "Renaming method will override final \"" + RefactoringUIUtil.getDescription( + methodInBaseClass, + true + ) + "\""; + } + }); + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - } catch (IncorrectOperationException e) { - LOG.error(e); - } } - } - - private void findHidingMethodWithOtherSignature(final PsiMethod methodToRename, final String newName, final List result) { - final PsiClass containingClass = methodToRename.getContainingClass(); - if (containingClass != null) { - final PsiMethod prototype = getPrototypeWithNewName(methodToRename, newName); - if (prototype == null || containingClass.findMethodBySignature(prototype, true) != null) return; - - final PsiMethod[] methodsByName = containingClass.findMethodsByName(newName, true); - if (methodsByName.length > 0) { - - for (UsageInfo info : result) { - final PsiElement element = info.getElement(); - if (element instanceof PsiReferenceExpression) { - if (((PsiReferenceExpression) element).resolve() == methodToRename) { - final PsiMethodCallExpression copy = (PsiMethodCallExpression) JavaPsiFacade.getElementFactory(element.getProject()) - .createExpressionFromText(element.getParent().getText(), element); - final PsiReferenceExpression expression = (PsiReferenceExpression) processRef(copy.getMethodExpression(), newName); - if (expression == null) continue; - final JavaResolveResult resolveResult = expression.advancedResolve(true); - final PsiMember resolveResultElement = (PsiMember) resolveResult.getElement(); - if (resolveResult.isValidResult() && resolveResultElement != null) { - result.add(new UnresolvableCollisionUsageInfo(element, methodToRename) { - @Override - public String getDescription() { - return "Method call would be linked to \"" + RefactoringUIUtil.getDescription(resolveResultElement, true) + - "\" after rename"; - } - }); - break; - } + + private void findHidingMethodWithOtherSignature(final PsiMethod methodToRename, final String newName, final List result) { + final PsiClass containingClass = methodToRename.getContainingClass(); + if (containingClass != null) { + final PsiMethod prototype = getPrototypeWithNewName(methodToRename, newName); + if (prototype == null || containingClass.findMethodBySignature(prototype, true) != null) { + return; + } + + final PsiMethod[] methodsByName = containingClass.findMethodsByName(newName, true); + if (methodsByName.length > 0) { + + for (UsageInfo info : result) { + final PsiElement element = info.getElement(); + if (element instanceof PsiReferenceExpression) { + if (((PsiReferenceExpression) element).resolve() == methodToRename) { + final PsiMethodCallExpression copy = + (PsiMethodCallExpression) JavaPsiFacade.getElementFactory(element.getProject()) + .createExpressionFromText(element.getParent().getText(), element); + final PsiReferenceExpression expression = + (PsiReferenceExpression) processRef(copy.getMethodExpression(), newName); + if (expression == null) { + continue; + } + final JavaResolveResult resolveResult = expression.advancedResolve(true); + final PsiMember resolveResultElement = (PsiMember) resolveResult.getElement(); + if (resolveResult.isValidResult() && resolveResultElement != null) { + result.add(new UnresolvableCollisionUsageInfo(element, methodToRename) { + @Override + public String getDescription() { + return "Method call would be linked to \"" + RefactoringUIUtil.getDescription( + resolveResultElement, + true + ) + + "\" after rename"; + } + }); + break; + } + } + } + } } - } } - } } - } - - private static PsiMethod getPrototypeWithNewName(PsiMethod methodToRename, String newName) { - final PsiMethod prototype = (PsiMethod) methodToRename.copy(); - try { - prototype.setName(newName); - } catch (IncorrectOperationException e) { - LOG.error(e); - return null; + + private static PsiMethod getPrototypeWithNewName(PsiMethod methodToRename, String newName) { + final PsiMethod prototype = (PsiMethod) methodToRename.copy(); + try { + prototype.setName(newName); + } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; + } + return prototype; } - return prototype; - } - - public void findExistingNameConflicts(final PsiElement element, final String newName, final MultiMap conflicts) { - if (element instanceof PsiCompiledElement) return; - final PsiMethod refactoredMethod = (PsiMethod) element; - if (newName.equals(refactoredMethod.getName())) return; - final PsiMethod prototype = getPrototypeWithNewName(refactoredMethod, newName); - if (prototype == null) return; - - ConflictsUtil.checkMethodConflicts( - refactoredMethod.getContainingClass(), - refactoredMethod, - prototype, - conflicts); - } - - @Override - public void prepareRenaming(PsiElement element, final String newName, final Map allRenames, SearchScope scope) { - final PsiMethod method = (PsiMethod) element; - OverridingMethodsSearch.search(method, scope, true).forEach(new Processor() { - public boolean process(PsiMethod overrider) { - if (overrider instanceof PsiMirrorElement) { - final PsiElement prototype = ((PsiMirrorElement) overrider).getPrototype(); - if (prototype instanceof PsiMethod) { - overrider = (PsiMethod) prototype; - } + + @Override + public void findExistingNameConflicts(PsiElement element, String newName, MultiMap conflicts) { + if (element instanceof PsiCompiledElement) { + return; + } + final PsiMethod refactoredMethod = (PsiMethod) element; + if (newName.equals(refactoredMethod.getName())) { + return; + } + final PsiMethod prototype = getPrototypeWithNewName(refactoredMethod, newName); + if (prototype == null) { + return; } - if (overrider instanceof SyntheticElement) return true; + ConflictsUtil.checkMethodConflicts( + refactoredMethod.getContainingClass(), + refactoredMethod, + prototype, + conflicts + ); + } - final String overriderName = overrider.getName(); - final String baseName = method.getName(); - final String newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName); - if (newOverriderName != null) { - RenameProcessor.assertNonCompileElement(overrider); - allRenames.put(overrider, newOverriderName); - } - return true; - } - }); - } - - @NonNls - public String getHelpID(final PsiElement element) { - return HelpID.RENAME_METHOD; - } - - public boolean isToSearchInComments(final PsiElement psiElement) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD; - } - - public void setToSearchInComments(final PsiElement element, final boolean enabled) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled; - } - - @Nullable - public PsiElement substituteElementToRename(PsiElement element, Editor editor) { - PsiMethod psiMethod = (PsiMethod) element; - if (psiMethod.isConstructor()) { - PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass == null) return null; - if (Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { - element = containingClass; - if (!PsiElementRenameHandler.canRename(element.getProject(), editor, element)) { - return null; + @Override + public void prepareRenaming(PsiElement element, final String newName, final Map allRenames, SearchScope scope) { + final PsiMethod method = (PsiMethod) element; + OverridingMethodsSearch.search(method, scope, true).forEach(new Processor() { + public boolean process(PsiMethod overrider) { + if (overrider instanceof PsiMirrorElement) { + final PsiElement prototype = ((PsiMirrorElement) overrider).getPrototype(); + if (prototype instanceof PsiMethod) { + overrider = (PsiMethod) prototype; + } + } + + if (overrider instanceof SyntheticElement) { + return true; + } + + final String overriderName = overrider.getName(); + final String baseName = method.getName(); + final String newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName); + if (newOverriderName != null) { + RenameProcessor.assertNonCompileElement(overrider); + allRenames.put(overrider, newOverriderName); + } + return true; + } + }); + } + + @NonNls + public String getHelpID(final PsiElement element) { + return HelpID.RENAME_METHOD; + } + + public boolean isToSearchInComments(final PsiElement psiElement) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD; + } + + public void setToSearchInComments(final PsiElement element, final boolean enabled) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled; + } + + @Nullable + public PsiElement substituteElementToRename(PsiElement element, Editor editor) { + PsiMethod psiMethod = (PsiMethod) element; + if (psiMethod.isConstructor()) { + PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass == null) { + return null; + } + if (Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { + element = containingClass; + if (!PsiElementRenameHandler.canRename(element.getProject(), editor, element)) { + return null; + } + return element; + } } - return element; - } + return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringLocalize.toRename().get()); } - return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringLocalize.toRename().get()); - } - - @Override - public void substituteElementToRename(@Nonnull PsiElement element, - @Nonnull final Editor editor, - @Nonnull final Consumer renameCallback) { - final PsiMethod psiMethod = (PsiMethod) element; - if (psiMethod.isConstructor()) { - final PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass == null) return; - if (!Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { - renameCallback.accept(psiMethod); - return; - } - super.substituteElementToRename(element, editor, renameCallback); - } else { - SuperMethodWarningUtil.checkSuperMethod(psiMethod, "Rename", new PsiElementProcessor() { - @Override - public boolean execute(@Nonnull PsiMethod method) { - if (!PsiElementRenameHandler.canRename(method.getProject(), editor, method)) return false; - renameCallback.accept(method); - return false; + + @Override + public void substituteElementToRename( + @Nonnull PsiElement element, + @Nonnull final Editor editor, + @Nonnull final Consumer renameCallback + ) { + final PsiMethod psiMethod = (PsiMethod) element; + if (psiMethod.isConstructor()) { + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass == null) { + return; + } + if (!Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { + renameCallback.accept(psiMethod); + return; + } + super.substituteElementToRename(element, editor, renameCallback); + } + else { + SuperMethodWarningUtil.checkSuperMethod(psiMethod, "Rename", new PsiElementProcessor() { + @Override + public boolean execute(@Nonnull PsiMethod method) { + if (!PsiElementRenameHandler.canRename(method.getProject(), editor, method)) { + return false; + } + renameCallback.accept(method); + return false; + } + }, editor); } - }, editor); } - } - - private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List result) { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass == null) return; - if (method.hasModifierProperty(PsiModifier.PRIVATE)) return; - Collection inheritors = ClassInheritorsSearch.search(containingClass, true).findAll(); - - MethodSignature oldSignature = method.getSignature(PsiSubstitutor.EMPTY); - MethodSignature newSignature = MethodSignatureUtil.createMethodSignature(newName, oldSignature.getParameterTypes(), - oldSignature.getTypeParameters(), - oldSignature.getSubstitutor(), - method.isConstructor()); - for (PsiClass inheritor : inheritors) { - PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY); - final PsiMethod[] methodsByName = inheritor.findMethodsByName(newName, false); - for (PsiMethod conflictingMethod : methodsByName) { - if (newSignature.equals(conflictingMethod.getSignature(superSubstitutor))) { - result.add(new SubmemberHidesMemberUsageInfo(conflictingMethod, method)); - break; + + private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List result) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (method.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + Collection inheritors = ClassInheritorsSearch.search(containingClass, true).findAll(); + + MethodSignature oldSignature = method.getSignature(PsiSubstitutor.EMPTY); + MethodSignature newSignature = MethodSignatureUtil.createMethodSignature(newName, oldSignature.getParameterTypes(), + oldSignature.getTypeParameters(), + oldSignature.getSubstitutor(), + method.isConstructor() + ); + for (PsiClass inheritor : inheritors) { + PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY); + final PsiMethod[] methodsByName = inheritor.findMethodsByName(newName, false); + for (PsiMethod conflictingMethod : methodsByName) { + if (newSignature.equals(conflictingMethod.getSignature(superSubstitutor))) { + result.add(new SubmemberHidesMemberUsageInfo(conflictingMethod, method)); + break; + } + } } - } } - } - public boolean isToSearchForTextOccurrences(final PsiElement element) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD; - } + public boolean isToSearchForTextOccurrences(final PsiElement element) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD; + } - public void setToSearchForTextOccurrences(final PsiElement element, final boolean enabled) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled; - } + public void setToSearchForTextOccurrences(final PsiElement element, final boolean enabled) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaVariableProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaVariableProcessor.java index 39c477e516..1b46ed5528 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaVariableProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/rename/RenameJavaVariableProcessor.java @@ -38,6 +38,7 @@ import consulo.language.psi.PsiElement; import consulo.language.psi.PsiReference; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; import consulo.ui.ex.awt.Messages; @@ -265,7 +266,7 @@ public void findCollisions(final PsiElement element, final String newName, final } @Override - public void findExistingNameConflicts(PsiElement element, String newName, MultiMap conflicts) { + public void findExistingNameConflicts(PsiElement element, String newName, MultiMap conflicts) { if (element instanceof PsiCompiledElement) return; if (element instanceof PsiField) { PsiField refactoredField = (PsiField) element; diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/tempWithQuery/TempWithQueryHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/tempWithQuery/TempWithQueryHandler.java index 8ff6a5095f..3587955ec2 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/tempWithQuery/TempWithQueryHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/tempWithQuery/TempWithQueryHandler.java @@ -33,7 +33,6 @@ import consulo.language.editor.TargetElementUtil; import consulo.language.editor.TargetElementUtilExtender; import consulo.language.editor.highlight.HighlightManager; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.action.RefactoringActionHandler; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; @@ -46,140 +45,158 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; -import consulo.project.ui.wm.WindowManager; import consulo.ui.annotation.RequiredUIAccess; import consulo.undoRedo.CommandProcessor; import jakarta.annotation.Nonnull; import java.util.ArrayList; +import java.util.List; import java.util.Set; public class TempWithQueryHandler implements RefactoringActionHandler { - private static final Logger LOG = Logger.getInstance(TempWithQueryHandler.class); - - private static final String REFACTORING_NAME = RefactoringBundle.message("replace.temp.with.query.title"); - - @RequiredUIAccess - public void invoke(@Nonnull final Project project, final Editor editor, PsiFile file, DataContext dataContext) { - Set flags = Set.of( - TargetElementUtilExtender.ELEMENT_NAME_ACCEPTED, - TargetElementUtilExtender.REFERENCED_ELEMENT_ACCEPTED, - TargetElementUtilExtender.LOOKUP_ITEM_ACCEPTED - ); - PsiElement element = TargetElementUtil.findTargetElement(editor, flags); - editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - if (!(element instanceof PsiLocalVariable)) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.errorWrongCaretPositionLocalName()); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); - return; - } - - invokeOnVariable(file, project, (PsiLocalVariable) element, editor); - } - - @RequiredUIAccess - private static void invokeOnVariable(final PsiFile file, final Project project, final PsiLocalVariable local, final Editor editor) { - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { - return; - } + private static final Logger LOG = Logger.getInstance(TempWithQueryHandler.class); + + private static final LocalizeValue REFACTORING_NAME = RefactoringLocalize.replaceTempWithQueryTitle(); + + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, Editor editor, PsiFile file, DataContext dataContext) { + Set flags = Set.of( + TargetElementUtilExtender.ELEMENT_NAME_ACCEPTED, + TargetElementUtilExtender.REFERENCED_ELEMENT_ACCEPTED, + TargetElementUtilExtender.LOOKUP_ITEM_ACCEPTED + ); + PsiElement element = TargetElementUtil.findTargetElement(editor, flags); + editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + if (!(element instanceof PsiLocalVariable localVar)) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.errorWrongCaretPositionLocalName()); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); + return; + } - String localName = local.getName(); - final PsiExpression initializer = local.getInitializer(); - if (initializer == null) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.variableHasNoInitializer(localName)); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); - return; + invokeOnVariable(file, project, localVar, editor); } - final PsiReference[] refs = ReferencesSearch.search(local, GlobalSearchScope.projectScope(project), false) - .toArray(new PsiReference[0]); + @RequiredUIAccess + private static void invokeOnVariable(PsiFile file, Project project, PsiLocalVariable local, Editor editor) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { + return; + } - if (refs.length == 0) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.variableIsNeverUsed(localName)); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); - return; - } + String localName = local.getName(); + PsiExpression initializer = local.getInitializer(); + if (initializer == null) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.variableHasNoInitializer(localName)); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); + return; + } - final HighlightManager highlightManager = HighlightManager.getInstance(project); - ArrayList array = new ArrayList<>(); - for (PsiReference ref : refs) { - PsiElement refElement = ref.getElement(); - if (PsiUtil.isAccessedForWriting((PsiExpression) refElement)) { - array.add(ref); - } - if (!array.isEmpty()) { - PsiReference[] refsForWriting = array.toArray(new PsiReference[array.size()]); - highlightManager.addOccurrenceHighlights(editor, refsForWriting, EditorColors.SEARCH_RESULT_ATTRIBUTES, true, null); - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.variableIsAccessedForWriting(localName)); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); - return; - } - } + PsiReference[] refs = ReferencesSearch.search(local, GlobalSearchScope.projectScope(project), false).toArray(new PsiReference[0]); - final ExtractMethodProcessor processor = new ExtractMethodProcessor(project, editor, new PsiElement[]{initializer}, local.getType(), - REFACTORING_NAME, localName, HelpID.REPLACE_TEMP_WITH_QUERY); - - try { - if (!processor.prepare()) { - return; - } - } catch (PrepareFailedException e) { - CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); - ExtractMethodHandler.highlightPrepareError(e, file, editor, project); - return; - } - final PsiClass targetClass = processor.getTargetClass(); - if (targetClass != null && targetClass.isInterface()) { - LocalizeValue message = RefactoringLocalize.cannotReplaceTempWithQueryInInterface(); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); - return; - } + if (refs.length == 0) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.variableIsNeverUsed(localName)); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); + return; + } - if (processor.showDialog()) { - CommandProcessor.getInstance().executeCommand(project, () -> { - final Runnable action = () -> { - try { - processor.doRefactoring(); + HighlightManager highlightManager = HighlightManager.getInstance(project); + List array = new ArrayList<>(); + for (PsiReference ref : refs) { + PsiElement refElement = ref.getElement(); + if (PsiUtil.isAccessedForWriting((PsiExpression) refElement)) { + array.add(ref); + } + if (!array.isEmpty()) { + PsiReference[] refsForWriting = array.toArray(new PsiReference[array.size()]); + highlightManager.addOccurrenceHighlights(editor, refsForWriting, EditorColors.SEARCH_RESULT_ATTRIBUTES, true, null); + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.variableIsAccessedForWriting(localName)); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); + return; + } + } - local.normalizeDeclaration(); + ExtractMethodProcessor processor = new ExtractMethodProcessor( + project, + editor, + new PsiElement[]{initializer}, + local.getType(), + REFACTORING_NAME.get(), + localName, + HelpID.REPLACE_TEMP_WITH_QUERY + ); + + try { + if (!processor.prepare()) { + return; + } + } + catch (PrepareFailedException e) { + CommonRefactoringUtil.showErrorHint( + project, + editor, + LocalizeValue.ofNullable(e.getMessage()), + REFACTORING_NAME, + HelpID.REPLACE_TEMP_WITH_QUERY + ); + ExtractMethodHandler.highlightPrepareError(e, file, editor, project); + return; + } + PsiClass targetClass = processor.getTargetClass(); + if (targetClass != null && targetClass.isInterface()) { + LocalizeValue message = RefactoringLocalize.cannotReplaceTempWithQueryInInterface(); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.REPLACE_TEMP_WITH_QUERY); + return; + } - PsiExpression initializer1 = local.getInitializer(); + if (processor.showDialog()) { + CommandProcessor.getInstance().newCommand() + .project(project) + .name(REFACTORING_NAME) + .run(() -> { + Runnable action = () -> { + try { + processor.doRefactoring(); + + local.normalizeDeclaration(); + + PsiExpression initializer1 = local.getInitializer(); + + PsiExpression[] exprs = new PsiExpression[refs.length]; + for (int idx = 0; idx < refs.length; idx++) { + PsiElement ref = refs[idx].getElement(); + exprs[idx] = (PsiExpression) ref.replace(initializer1); + } + PsiDeclarationStatement declaration = (PsiDeclarationStatement) local.getParent(); + declaration.delete(); + + highlightManager.addOccurrenceHighlights(editor, exprs, EditorColors.SEARCH_RESULT_ATTRIBUTES, true, null); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + }; + + PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(() -> { + project.getApplication().runWriteAction(action); + DuplicatesImpl.processDuplicates(processor, project, editor); + }); + }); + } + } - PsiExpression[] exprs = new PsiExpression[refs.length]; - for (int idx = 0; idx < refs.length; idx++) { - PsiElement ref = refs[idx].getElement(); - exprs[idx] = (PsiExpression) ref.replace(initializer1); + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { + if (elements.length == 1 && elements[0] instanceof PsiLocalVariable localVar && dataContext != null) { + PsiFile file = dataContext.getData(PsiFile.KEY); + Editor editor = dataContext.getData(Editor.KEY); + if (file != null && editor != null) { + invokeOnVariable(file, project, localVar, editor); } - PsiDeclarationStatement declaration = (PsiDeclarationStatement) local.getParent(); - declaration.delete(); - - highlightManager.addOccurrenceHighlights(editor, exprs, EditorColors.SEARCH_RESULT_ATTRIBUTES, true, null); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - }; - - PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(() -> { - project.getApplication().runWriteAction(action); - DuplicatesImpl.processDuplicates(processor, project, editor); - }); - }, REFACTORING_NAME, null); - } - } - - @RequiredUIAccess - public void invoke(@Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { - if (elements.length == 1 && elements[0] instanceof PsiLocalVariable) { - if (dataContext != null) { - final PsiFile file = dataContext.getData(PsiFile.KEY); - final Editor editor = dataContext.getData(Editor.KEY); - if (file != null && editor != null) { - invokeOnVariable(file, project, (PsiLocalVariable) elements[0], editor); } - } } - } } \ No newline at end of file diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationLabeler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationLabeler.java index 3511483241..6bb9504321 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationLabeler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/typeMigration/TypeMigrationLabeler.java @@ -31,6 +31,7 @@ import consulo.language.psi.search.ReferencesSearch; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; import consulo.ui.annotation.RequiredUIAccess; @@ -57,1204 +58,1282 @@ * @author db */ public class TypeMigrationLabeler { - private static final Logger LOG = Logger.getInstance(TypeMigrationLabeler.class); - private boolean myShowWarning = true; - private volatile MigrateException myException; - private final Semaphore myDialogSemaphore = new Semaphore(); - private final Project myProject; - - public TypeMigrationRules getRules() { - return myRules; - } - - private final TypeMigrationRules myRules; - private final Function myMigrationRootTypeFunction; - @Nullable - private final Set myAllowedRoots; - private TypeEvaluator myTypeEvaluator; - private final LinkedHashMap myConversions; - private final Map, PsiType>, TypeMigrationUsageInfo> myFailedConversions; - private LinkedList> myMigrationRoots; - private final LinkedHashMap myNewExpressionTypeChange; - private final LinkedHashMap myClassTypeArgumentsChange; - - private TypeMigrationUsageInfo[] myMigratedUsages; - - private TypeMigrationUsageInfo myCurrentRoot; - private final Map>> myRootsTree = new HashMap<>(); - private final Map, Set> myRootUsagesTree = new HashMap<>(); - private final Set myProcessedRoots = new HashSet<>(); - private final Set myDisappearedTypeParameters = new HashSet<>(); - - public TypeMigrationLabeler(TypeMigrationRules rules, PsiType rootType, Project project) { - this(rules, Functions.constant(rootType), null, project); - } - - /** - * @param allowedRoots any root accepted if null - */ - public TypeMigrationLabeler(TypeMigrationRules rules, Function migrationRootTypeFunction, @Nullable PsiElement[] allowedRoots, Project project) { - myRules = rules; - myMigrationRootTypeFunction = migrationRootTypeFunction; - myAllowedRoots = allowedRoots == null ? null : Set.of(allowedRoots); - - myConversions = new LinkedHashMap<>(); - myFailedConversions = new LinkedHashMap<>(); - myNewExpressionTypeChange = new LinkedHashMap<>(); - myClassTypeArgumentsChange = new LinkedHashMap<>(); - myProject = project; - } - - public boolean hasFailedConversions() { - return myFailedConversions.size() > 0; - } - - public Function getMigrationRootTypeFunction() { - return myMigrationRootTypeFunction; - } - - @RequiredReadAction - public String[] getFailedConversionsReport() { - final String[] report = new String[myFailedConversions.size()]; - int j = 0; - - for (final Pair, PsiType> p : myFailedConversions.keySet()) { - final PsiExpression element = p.getFirst().getElement(); - LOG.assertTrue(element != null); - final PsiType type = element.getType(); - report[j++] = "Cannot convert type of expression " + StringUtil.escapeXml(element.getText()) + "" + - (type != null ? " from " + StringUtil.escapeXml(type.getCanonicalText()) + - "" + " to " + StringUtil.escapeXml(p.getSecond().getCanonicalText()) + "" : "") + "
"; + private static final Logger LOG = Logger.getInstance(TypeMigrationLabeler.class); + private boolean myShowWarning = true; + private volatile MigrateException myException; + private final Semaphore myDialogSemaphore = new Semaphore(); + private final Project myProject; + + public TypeMigrationRules getRules() { + return myRules; } - return report; - } - - @RequiredReadAction - public UsageInfo[] getFailedUsages(final TypeMigrationUsageInfo root) { - return map2Usages(ContainerUtil.mapNotNull( - myFailedConversions.entrySet(), - entry -> entry.getValue().equals(root) ? entry.getKey() : null - )); - } - - @RequiredReadAction - public UsageInfo[] getFailedUsages() { - return map2Usages(myFailedConversions.keySet()); - } - - @Nonnull - @RequiredReadAction - private static UsageInfo[] map2Usages(Collection, PsiType>> usages) { - return ContainerUtil.map2Array(usages, new UsageInfo[usages.size()], pair -> - { - final PsiExpression expr = pair.getFirst().getElement(); - LOG.assertTrue(expr != null); - return new UsageInfo(expr) { - @Override - @Nullable - public String getTooltipText() { - final PsiType type = expr.isValid() ? expr.getType() : null; - if (type == null) { - return null; - } - return "Cannot convert type of the expression from " + type.getCanonicalText() + " to " + pair.getSecond().getCanonicalText(); - } - }; - }); - } - - public TypeMigrationUsageInfo[] getMigratedUsages() { - final LinkedList> declarations = getTypeEvaluator().getMigratedDeclarations(); - int index = declarations.size() + myConversions.size() + myNewExpressionTypeChange.size() + myClassTypeArgumentsChange.size(); - final TypeMigrationUsageInfo[] usages = new TypeMigrationUsageInfo[index]; - - int j = 0; - - for (final PsiElement element : myConversions.keySet()) { - final Object conv = myConversions.get(element); - usages[j++] = new TypeMigrationUsageInfo(element) { - @Override - @RequiredReadAction - public String getTooltipText() { - if (conv instanceof String) { //todo - final String conversion = (String) conv; - return "Replaced with " + conversion.replaceAll("\\$", element.getText()); - } else { - return "Replaced with " + conv.toString(); - } - } - - @Override - public boolean isExcluded() { - if (conv instanceof TypeConversionDescriptorBase) { - return ((TypeConversionDescriptorBase) conv).getRoot().isExcluded(); - } - return super.isExcluded(); - } - - @Override - public TypeMigrationUsageInfo getOwnerRoot() { - return conv instanceof TypeConversionDescriptorBase ? ((TypeConversionDescriptorBase) conv).getRoot() : null; - } - }; + private final TypeMigrationRules myRules; + private final Function myMigrationRootTypeFunction; + @Nullable + private final Set myAllowedRoots; + private TypeEvaluator myTypeEvaluator; + private final LinkedHashMap myConversions; + private final Map, PsiType>, TypeMigrationUsageInfo> myFailedConversions; + private LinkedList> myMigrationRoots; + private final LinkedHashMap myNewExpressionTypeChange; + private final LinkedHashMap myClassTypeArgumentsChange; + + private TypeMigrationUsageInfo[] myMigratedUsages; + + private TypeMigrationUsageInfo myCurrentRoot; + private final Map>> myRootsTree = new HashMap<>(); + private final Map, Set> myRootUsagesTree = new HashMap<>(); + private final Set myProcessedRoots = new HashSet<>(); + private final Set myDisappearedTypeParameters = new HashSet<>(); + + public TypeMigrationLabeler(TypeMigrationRules rules, PsiType rootType, Project project) { + this(rules, Functions.constant(rootType), null, project); } - for (final Pair p : declarations) { - final TypeMigrationUsageInfo element = p.getFirst(); - usages[j++] = element; + /** + * @param allowedRoots any root accepted if null + */ + public TypeMigrationLabeler( + TypeMigrationRules rules, + Function migrationRootTypeFunction, + @Nullable PsiElement[] allowedRoots, + Project project + ) { + myRules = rules; + myMigrationRootTypeFunction = migrationRootTypeFunction; + myAllowedRoots = allowedRoots == null ? null : Set.of(allowedRoots); + + myConversions = new LinkedHashMap<>(); + myFailedConversions = new LinkedHashMap<>(); + myNewExpressionTypeChange = new LinkedHashMap<>(); + myClassTypeArgumentsChange = new LinkedHashMap<>(); + myProject = project; } - for (TypeMigrationUsageInfo info : myClassTypeArgumentsChange.keySet()) { - usages[j++] = info; + public boolean hasFailedConversions() { + return myFailedConversions.size() > 0; } - for (final TypeMigrationUsageInfo expr : myNewExpressionTypeChange.keySet()) { - usages[j++] = expr; + public Function getMigrationRootTypeFunction() { + return myMigrationRootTypeFunction; } - return sortMigratedUsages(usages); - } - - @RequiredReadAction - private TypeMigrationUsageInfo[] sortMigratedUsages(TypeMigrationUsageInfo[] infos) { - final DFSTBuilder builder = new DFSTBuilder<>( - GraphGenerator.generate(new InboundSemiGraph() { - @Override - public Collection getNodes() { - final Set infos = new HashSet<>(); - for (Map.Entry>> entry : myRootsTree.entrySet()) { - infos.add(entry.getKey()); - infos.addAll(ContainerUtil.map(entry.getValue(), pair -> pair.getFirst())); - } - return infos; - } - - @Override - public Iterator getIn(TypeMigrationUsageInfo n) { - final HashSet> rawNodes = myRootsTree.get(n); - if (rawNodes == null) { - return Collections.emptyList().iterator(); - } - final List in = ContainerUtil.map(rawNodes, pair -> pair.getFirst()); - return in.iterator(); - } - }) - ); - final Comparator cmp = builder.comparator(); - - Arrays.sort(infos, (info1, info2) -> - { - final TypeMigrationUsageInfo i1 = info1.getOwnerRoot(); - final TypeMigrationUsageInfo i2 = info2.getOwnerRoot(); - if (i1 == null && i2 == null) { - return 0; - } - if (i1 == null) { - return 1; - } - if (i2 == null) { - return -1; - } - final PsiElement element1 = info1.getElement(); - final PsiElement element2 = info2.getElement(); - LOG.assertTrue(element1 != null && element2 != null); - if (element1.equals(element2)) { - return 0; - } - final TextRange range1 = element1.getTextRange(); - final TextRange range2 = element2.getTextRange(); - if (range1.contains(range2)) { - return 1; - } - if (range2.contains(range1)) { - return -1; - } - - final int res = cmp.compare(i1, i2); - if (res != 0) { - return res; - } - return range2.getStartOffset() - range1.getStartOffset(); - }); - - return infos; - } - - MigrationProducer createMigratorFor(UsageInfo[] usages) { - final Map conversions = new HashMap<>(); - for (UsageInfo usage : usages) { - final Object conversion = getConversion(usage.getElement()); - if (conversion != null) { - conversions.put(usage, conversion); - } + + @RequiredReadAction + public LocalizeValue[] getFailedConversionsReport() { + final LocalizeValue[] report = new LocalizeValue[myFailedConversions.size()]; + int j = 0; + + for (final Pair, PsiType> p : myFailedConversions.keySet()) { + final PsiExpression element = p.getFirst().getElement(); + LOG.assertTrue(element != null); + final PsiType type = element.getType(); + report[j++] = LocalizeValue.localizeTODO( + "Cannot convert type of expression " + StringUtil.escapeXml(element.getText()) + "" + + (type != null ? " from " + StringUtil.escapeXml(type.getCanonicalText()) + + "" + " to " + StringUtil.escapeXml(p.getSecond().getCanonicalText()) + "" : "") + "
" + ); + } + + return report; } - return new MigrationProducer(conversions); - } - @Nullable - public T getSettings(Class aClass) { - return myRules.getConversionSettings(aClass); - } + @RequiredReadAction + public UsageInfo[] getFailedUsages(final TypeMigrationUsageInfo root) { + return map2Usages(ContainerUtil.mapNotNull( + myFailedConversions.entrySet(), + entry -> entry.getValue().equals(root) ? entry.getKey() : null + )); + } - class MigrationProducer { - private final Map myRemainConversions; - private final MultiMap myVariableMigration = new MultiMap<>(); + @RequiredReadAction + public UsageInfo[] getFailedUsages() { + return map2Usages(myFailedConversions.keySet()); + } - private MigrationProducer(Map conversions) { - myRemainConversions = conversions; + @Nonnull + @RequiredReadAction + private static UsageInfo[] map2Usages(Collection, PsiType>> usages) { + return ContainerUtil.map2Array(usages, new UsageInfo[usages.size()], pair -> + { + final PsiExpression expr = pair.getFirst().getElement(); + LOG.assertTrue(expr != null); + return new UsageInfo(expr) { + @Override + @Nullable + public String getTooltipText() { + final PsiType type = expr.isValid() ? expr.getType() : null; + if (type == null) { + return null; + } + return "Cannot convert type of the expression from " + type.getCanonicalText() + " to " + pair.getSecond() + .getCanonicalText(); + } + }; + }); } - public void change(@Nonnull final TypeMigrationUsageInfo usageInfo, @Nonnull Consumer consumer) { - final PsiElement element = usageInfo.getElement(); - if (element == null) { - return; - } - final Project project = element.getProject(); - if (element instanceof PsiExpression) { - final PsiExpression expression = (PsiExpression) element; - if (element instanceof PsiNewExpression) { - for (Map.Entry info : myNewExpressionTypeChange.entrySet()) { - final PsiElement expressionToReplace = info.getKey().getElement(); - if (expression.equals(expressionToReplace)) { - final PsiNewExpression newExpression = - TypeMigrationReplacementUtil.replaceNewExpressionType(project, (PsiNewExpression)expressionToReplace, info); - if (newExpression != null) { - consumer.accept(newExpression); - } - } - } + public TypeMigrationUsageInfo[] getMigratedUsages() { + final LinkedList> declarations = getTypeEvaluator().getMigratedDeclarations(); + int index = declarations.size() + myConversions.size() + myNewExpressionTypeChange.size() + myClassTypeArgumentsChange.size(); + final TypeMigrationUsageInfo[] usages = new TypeMigrationUsageInfo[index]; + + int j = 0; + + for (final PsiElement element : myConversions.keySet()) { + final Object conv = myConversions.get(element); + usages[j++] = new TypeMigrationUsageInfo(element) { + @Override + @RequiredReadAction + public String getTooltipText() { + if (conv instanceof String) { //todo + final String conversion = (String) conv; + return "Replaced with " + conversion.replaceAll("\\$", element.getText()); + } + else { + return "Replaced with " + conv.toString(); + } + } + + @Override + public boolean isExcluded() { + if (conv instanceof TypeConversionDescriptorBase) { + return ((TypeConversionDescriptorBase) conv).getRoot().isExcluded(); + } + return super.isExcluded(); + } + + @Override + public TypeMigrationUsageInfo getOwnerRoot() { + return conv instanceof TypeConversionDescriptorBase ? ((TypeConversionDescriptorBase) conv).getRoot() : null; + } + }; + } + + for (final Pair p : declarations) { + final TypeMigrationUsageInfo element = p.getFirst(); + usages[j++] = element; } - final Object conversion = myRemainConversions.get(usageInfo); - if (conversion != null) { - myRemainConversions.remove(usageInfo); - TypeMigrationReplacementUtil.replaceExpression(expression, project, conversion, myTypeEvaluator); + + for (TypeMigrationUsageInfo info : myClassTypeArgumentsChange.keySet()) { + usages[j++] = info; } - } else if (element instanceof PsiReferenceParameterList) { - for (Map.Entry entry : myClassTypeArgumentsChange.entrySet()) { - if (element.equals(entry.getKey().getElement())) { //todo check null - final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); - try { - element.getParent().replace(factory.createReferenceElementByType(entry.getValue())); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - } else if ((element instanceof PsiField || element instanceof PsiLocalVariable) && isMultiVariableDeclaration((PsiVariable) element)) { - final PsiTypeElement typeElement = ((PsiVariable) element).getTypeElement(); - myVariableMigration.putValue(typeElement, usageInfo); - } else { - TypeMigrationReplacementUtil.migrateMemberOrVariableType(element, project, getTypeEvaluator().getType(usageInfo)); - if (usageInfo instanceof OverriddenUsageInfo overriddenUsageInfo) { - final String migrationName = overriddenUsageInfo.getMigrateMethodName(); - if (migrationName != null) { - project.getApplication().invokeLater(() -> - { - if (element.isValid()) { - new RenameProcessor(project, element, migrationName, false, false).run(); - } - }); - } + + for (final TypeMigrationUsageInfo expr : myNewExpressionTypeChange.keySet()) { + usages[j++] = expr; } - } + return sortMigratedUsages(usages); } - public void flush() { - for (Map.Entry> entry : myVariableMigration.entrySet()) { - final PsiTypeElement typeElement = entry.getKey(); - if (!typeElement.isValid()) { - continue; - } - final Collection migrations = entry.getValue(); - if (migrations.size() != 1) { - MultiMap variablesByMigrationType = new MultiMap<>(); - for (TypeMigrationUsageInfo migration : migrations) { - final PsiElement var = migration.getElement(); - if (!(var instanceof PsiLocalVariable || var instanceof PsiField)) { - continue; + @RequiredReadAction + private TypeMigrationUsageInfo[] sortMigratedUsages(TypeMigrationUsageInfo[] infos) { + final DFSTBuilder builder = new DFSTBuilder<>( + GraphGenerator.generate(new InboundSemiGraph() { + @Override + public Collection getNodes() { + final Set infos = new HashSet<>(); + for (Map.Entry>> entry : myRootsTree.entrySet()) { + infos.add(entry.getKey()); + infos.addAll(ContainerUtil.map(entry.getValue(), pair -> pair.getFirst())); + } + return infos; + } + + @Override + public Iterator getIn(TypeMigrationUsageInfo n) { + final HashSet> rawNodes = myRootsTree.get(n); + if (rawNodes == null) { + return Collections.emptyList().iterator(); + } + final List in = ContainerUtil.map(rawNodes, pair -> pair.getFirst()); + return in.iterator(); + } + }) + ); + final Comparator cmp = builder.comparator(); + + Arrays.sort(infos, (info1, info2) -> + { + final TypeMigrationUsageInfo i1 = info1.getOwnerRoot(); + final TypeMigrationUsageInfo i2 = info2.getOwnerRoot(); + if (i1 == null && i2 == null) { + return 0; } - final PsiType type = getTypeEvaluator().getType(migration); - variablesByMigrationType.putValue(type, (PsiVariable) var); - } - if (variablesByMigrationType.size() == 1) { - final Map.Entry> migrationTypeAndVariables = - ContainerUtil.getFirstItem(variablesByMigrationType.entrySet()); - LOG.assertTrue(migrationTypeAndVariables != null); - final PsiVariable[] variables = PsiTreeUtil.getChildrenOfType(typeElement.getParent().getParent(), PsiVariable.class); - if (variables != null && variables.length == migrationTypeAndVariables.getValue().size()) { - try { - PsiType migrationType = migrationTypeAndVariables.getKey(); - final Project project = variables[0].getProject(); - migrationType = TypeMigrationReplacementUtil.revalidateType(migrationType, project); - typeElement.replace(JavaPsiFacade.getElementFactory(project).createTypeElement(migrationType)); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - continue; + if (i1 == null) { + return 1; + } + if (i2 == null) { + return -1; + } + final PsiElement element1 = info1.getElement(); + final PsiElement element2 = info2.getElement(); + LOG.assertTrue(element1 != null && element2 != null); + if (element1.equals(element2)) { + return 0; + } + final TextRange range1 = element1.getTextRange(); + final TextRange range2 = element2.getTextRange(); + if (range1.contains(range2)) { + return 1; + } + if (range2.contains(range1)) { + return -1; + } + + final int res = cmp.compare(i1, i2); + if (res != 0) { + return res; + } + return range2.getStartOffset() - range1.getStartOffset(); + }); + + return infos; + } + + MigrationProducer createMigratorFor(UsageInfo[] usages) { + final Map conversions = new HashMap<>(); + for (UsageInfo usage : usages) { + final Object conversion = getConversion(usage.getElement()); + if (conversion != null) { + conversions.put(usage, conversion); } - } - } - for (TypeMigrationUsageInfo info : entry.getValue()) { - migrateMultiDeclarationVariable(info); } - } + return new MigrationProducer(conversions); } - private void migrateMultiDeclarationVariable(TypeMigrationUsageInfo varUsageInfo) { - final PsiElement var = varUsageInfo.getElement(); - if (!(var instanceof PsiLocalVariable || var instanceof PsiField)) { - return; - } - ((PsiVariable) var).normalizeDeclaration(); - TypeMigrationReplacementUtil.migrateMemberOrVariableType(var, var.getProject(), getTypeEvaluator().getType(varUsageInfo)); + @Nullable + public T getSettings(Class aClass) { + return myRules.getConversionSettings(aClass); } - Object getConversion(UsageInfo info) { - return myRemainConversions.remove(info); + class MigrationProducer { + private final Map myRemainConversions; + private final MultiMap myVariableMigration = new MultiMap<>(); + + private MigrationProducer(Map conversions) { + myRemainConversions = conversions; + } + + public void change(@Nonnull final TypeMigrationUsageInfo usageInfo, @Nonnull Consumer consumer) { + final PsiElement element = usageInfo.getElement(); + if (element == null) { + return; + } + final Project project = element.getProject(); + if (element instanceof PsiExpression) { + final PsiExpression expression = (PsiExpression) element; + if (element instanceof PsiNewExpression) { + for (Map.Entry info : myNewExpressionTypeChange.entrySet()) { + final PsiElement expressionToReplace = info.getKey().getElement(); + if (expression.equals(expressionToReplace)) { + final PsiNewExpression newExpression = + TypeMigrationReplacementUtil.replaceNewExpressionType( + project, + (PsiNewExpression) expressionToReplace, + info + ); + if (newExpression != null) { + consumer.accept(newExpression); + } + } + } + } + final Object conversion = myRemainConversions.get(usageInfo); + if (conversion != null) { + myRemainConversions.remove(usageInfo); + TypeMigrationReplacementUtil.replaceExpression(expression, project, conversion, myTypeEvaluator); + } + } + else if (element instanceof PsiReferenceParameterList) { + for (Map.Entry entry : myClassTypeArgumentsChange.entrySet()) { + if (element.equals(entry.getKey().getElement())) { //todo check null + final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); + try { + element.getParent().replace(factory.createReferenceElementByType(entry.getValue())); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + } + else if ((element instanceof PsiField || element instanceof PsiLocalVariable) && isMultiVariableDeclaration((PsiVariable) element)) { + final PsiTypeElement typeElement = ((PsiVariable) element).getTypeElement(); + myVariableMigration.putValue(typeElement, usageInfo); + } + else { + TypeMigrationReplacementUtil.migrateMemberOrVariableType(element, project, getTypeEvaluator().getType(usageInfo)); + if (usageInfo instanceof OverriddenUsageInfo overriddenUsageInfo) { + final String migrationName = overriddenUsageInfo.getMigrateMethodName(); + if (migrationName != null) { + project.getApplication().invokeLater(() -> + { + if (element.isValid()) { + new RenameProcessor(project, element, migrationName, false, false).run(); + } + }); + } + } + } + } + + public void flush() { + for (Map.Entry> entry : myVariableMigration.entrySet()) { + final PsiTypeElement typeElement = entry.getKey(); + if (!typeElement.isValid()) { + continue; + } + final Collection migrations = entry.getValue(); + if (migrations.size() != 1) { + MultiMap variablesByMigrationType = new MultiMap<>(); + for (TypeMigrationUsageInfo migration : migrations) { + final PsiElement var = migration.getElement(); + if (!(var instanceof PsiLocalVariable || var instanceof PsiField)) { + continue; + } + final PsiType type = getTypeEvaluator().getType(migration); + variablesByMigrationType.putValue(type, (PsiVariable) var); + } + if (variablesByMigrationType.size() == 1) { + final Map.Entry> migrationTypeAndVariables = + ContainerUtil.getFirstItem(variablesByMigrationType.entrySet()); + LOG.assertTrue(migrationTypeAndVariables != null); + final PsiVariable[] variables = + PsiTreeUtil.getChildrenOfType(typeElement.getParent().getParent(), PsiVariable.class); + if (variables != null && variables.length == migrationTypeAndVariables.getValue().size()) { + try { + PsiType migrationType = migrationTypeAndVariables.getKey(); + final Project project = variables[0].getProject(); + migrationType = TypeMigrationReplacementUtil.revalidateType(migrationType, project); + typeElement.replace(JavaPsiFacade.getElementFactory(project).createTypeElement(migrationType)); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + continue; + } + } + } + for (TypeMigrationUsageInfo info : entry.getValue()) { + migrateMultiDeclarationVariable(info); + } + } + } + + private void migrateMultiDeclarationVariable(TypeMigrationUsageInfo varUsageInfo) { + final PsiElement var = varUsageInfo.getElement(); + if (!(var instanceof PsiLocalVariable || var instanceof PsiField)) { + return; + } + ((PsiVariable) var).normalizeDeclaration(); + TypeMigrationReplacementUtil.migrateMemberOrVariableType(var, var.getProject(), getTypeEvaluator().getType(varUsageInfo)); + } + + Object getConversion(UsageInfo info) { + return myRemainConversions.remove(info); + } + + private boolean isMultiVariableDeclaration(PsiVariable variable) { + final PsiElement parent = variable.getParent(); + LOG.assertTrue(parent != null); + final PsiVariable[] variables = PsiTreeUtil.getChildrenOfType(parent, PsiVariable.class); + LOG.assertTrue(variables != null); + return variables.length != 1; + } } - private boolean isMultiVariableDeclaration(PsiVariable variable) { - final PsiElement parent = variable.getParent(); - LOG.assertTrue(parent != null); - final PsiVariable[] variables = PsiTreeUtil.getChildrenOfType(parent, PsiVariable.class); - LOG.assertTrue(variables != null); - return variables.length != 1; + void postProcessNewExpression(@Nonnull PsiNewExpression expression) { + TypeMigrationReplacementUtil.tryToReplaceWithDiamond(expression, null); } - } - - void postProcessNewExpression(@Nonnull PsiNewExpression expression) { - TypeMigrationReplacementUtil.tryToReplaceWithDiamond(expression, null); - } - - @Nullable - Object getConversion(PsiElement element) { - return myConversions.get(element); - } - - @RequiredUIAccess - public TypeMigrationUsageInfo[] getMigratedUsages(boolean autoMigrate, final PsiElement... roots) { - if (myMigratedUsages == null) { - myShowWarning = autoMigrate; - migrate(autoMigrate, roots); - myMigratedUsages = getMigratedUsages(); + + @Nullable + Object getConversion(PsiElement element) { + return myConversions.get(element); } - return myMigratedUsages; - } - - @Nullable - public Set getTypeUsages(final TypeMigrationUsageInfo element, final TypeMigrationUsageInfo currentRoot) { - return myRootUsagesTree.get(Couple.of(element, currentRoot)); - } - - void convertExpression(final PsiExpression expr, final PsiType toType, final PsiType fromType, final boolean isCovariantPosition) { - final TypeConversionDescriptorBase conversion = myRules.findConversion(fromType, toType, expr instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression) expr).resolveMethod() : null, - expr, isCovariantPosition, this); - - if (conversion == null) { - markFailedConversion(Couple.of(fromType, toType), expr); - } else { - setConversionMapping(expr, conversion); + + @RequiredUIAccess + public TypeMigrationUsageInfo[] getMigratedUsages(boolean autoMigrate, final PsiElement... roots) { + if (myMigratedUsages == null) { + myShowWarning = autoMigrate; + migrate(autoMigrate, roots); + myMigratedUsages = getMigratedUsages(); + } + return myMigratedUsages; } - } - - @RequiredUIAccess - public void migrateExpressionType( - final PsiExpression expr, - final PsiType migrationType, - final PsiElement place, - boolean alreadyProcessed, - final boolean isCovariant - ) { - PsiType originalType = expr.getType(); - - if (originalType == null || originalType.equals(migrationType)) { - return; + + @Nullable + public Set getTypeUsages(final TypeMigrationUsageInfo element, final TypeMigrationUsageInfo currentRoot) { + return myRootUsagesTree.get(Couple.of(element, currentRoot)); } - if (originalType.equals(PsiType.NULL)) { - if (migrationType instanceof PsiPrimitiveType) { - markFailedConversion(Couple.of(originalType, migrationType), expr); - return; - } - if (place instanceof PsiVariable) { - PsiType type = ((PsiVariable) place).getType(); - if (((PsiVariable) place).getInitializer() == expr && myRules.shouldConvertNull(type, migrationType, expr)) { - convertExpression(expr, migrationType, type, isCovariant); - } - } - return; + void convertExpression(final PsiExpression expr, final PsiType toType, final PsiType fromType, final boolean isCovariantPosition) { + final TypeConversionDescriptorBase conversion = myRules.findConversion( + fromType, + toType, + expr instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression) expr).resolveMethod() : null, + expr, + isCovariantPosition, + this + ); + + if (conversion == null) { + markFailedConversion(Couple.of(fromType, toType), expr); + } + else { + setConversionMapping(expr, conversion); + } } - if (expr instanceof PsiConditionalExpression) { - final PsiConditionalExpression condExpr = (PsiConditionalExpression) expr; - for (PsiExpression e : ContainerUtil.newArrayList(condExpr.getThenExpression(), condExpr.getElseExpression())) { - if (e != null) { - migrateExpressionType(e, migrationType, place, alreadyProcessed, false); - } - } - getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), migrationType); - return; - } else if (expr instanceof PsiClassObjectAccessExpression) { - if (!TypeConversionUtil.isAssignable(migrationType, expr.getType())) { - markFailedConversion(Couple.of(expr.getType(), migrationType), expr); - return; - } - } else if (expr instanceof PsiArrayInitializerExpression && migrationType instanceof PsiArrayType) { - final PsiExpression[] initializers = ((PsiArrayInitializerExpression) expr).getInitializers(); - for (PsiExpression initializer : initializers) { - migrateExpressionType(initializer, ((PsiArrayType) migrationType).getComponentType(), expr, alreadyProcessed, true); - } - getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), migrationType); - return; - } else if (expr instanceof PsiArrayAccessExpression arrayAccessExpression) { - migrateExpressionType( - arrayAccessExpression.getArrayExpression(), - migrationType.createArrayType(), - place, - alreadyProcessed, - isCovariant - ); - return; - } else if (expr instanceof PsiReferenceExpression refExpr) { - final PsiElement resolved = refExpr.resolve(); - if (resolved != null) { - if (!addMigrationRoot(resolved, migrationType, place, alreadyProcessed, !isCovariant)) { - convertExpression(expr, migrationType, getTypeEvaluator().evaluateType(expr), isCovariant); - } - } - return; - } else if (expr instanceof PsiMethodCallExpression methodCall) { - final PsiMethod resolved = methodCall.resolveMethod(); - if (resolved != null) { - if (!addMigrationRoot(resolved, migrationType, place, alreadyProcessed, !isCovariant)) { - convertExpression(expr, migrationType, getTypeEvaluator().evaluateType(expr), isCovariant); - } - } - return; - } else if (expr instanceof PsiNewExpression) { - if (originalType.getArrayDimensions() == migrationType.getArrayDimensions()) { - if (migrationType.getArrayDimensions() > 0) { - final PsiType elementType = ((PsiArrayType) migrationType).getComponentType(); - - final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression) expr).getArrayInitializer(); - - if (arrayInitializer != null) { - final PsiExpression[] initializers = arrayInitializer.getInitializers(); - for (int i = initializers.length - 1; i >= 0; i--) { - migrateExpressionType(initializers[i], elementType, place, alreadyProcessed, true); + @RequiredUIAccess + public void migrateExpressionType( + final PsiExpression expr, + final PsiType migrationType, + final PsiElement place, + boolean alreadyProcessed, + final boolean isCovariant + ) { + PsiType originalType = expr.getType(); + + if (originalType == null || originalType.equals(migrationType)) { + return; + } + + if (originalType.equals(PsiType.NULL)) { + if (migrationType instanceof PsiPrimitiveType) { + markFailedConversion(Couple.of(originalType, migrationType), expr); + return; } - } + if (place instanceof PsiVariable) { + PsiType type = ((PsiVariable) place).getType(); + if (((PsiVariable) place).getInitializer() == expr && myRules.shouldConvertNull(type, migrationType, expr)) { + convertExpression(expr, migrationType, type, isCovariant); + } + } + return; + } - if (isGenericsArrayType(elementType)) { - markFailedConversion(Couple.of(originalType, migrationType), expr); + if (expr instanceof PsiConditionalExpression) { + final PsiConditionalExpression condExpr = (PsiConditionalExpression) expr; + for (PsiExpression e : ContainerUtil.newArrayList(condExpr.getThenExpression(), condExpr.getElseExpression())) { + if (e != null) { + migrateExpressionType(e, migrationType, place, alreadyProcessed, false); + } + } + getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), migrationType); return; - } - - final TypeMigrationUsageInfo usageInfo = new TypeMigrationUsageInfo(expr); - usageInfo.setOwnerRoot(myCurrentRoot); - myNewExpressionTypeChange.put(usageInfo, migrationType); - getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), migrationType); - return; - } else { - if (migrationType instanceof PsiClassType migrationClassType && originalType instanceof PsiClassType originalClassType - && migrationClassType.rawType().isAssignableFrom(originalClassType.rawType())) { - final PsiClass originalClass = PsiUtil.resolveClassInType(originalClassType); - if (originalClass instanceof PsiAnonymousClass anonymousClass) { - originalType = anonymousClass.getBaseClassType(); - originalClassType = (PsiClassType) originalType; + } + else if (expr instanceof PsiClassObjectAccessExpression) { + if (!TypeConversionUtil.isAssignable(migrationType, expr.getType())) { + markFailedConversion(Couple.of(expr.getType(), migrationType), expr); + return; + } + } + else if (expr instanceof PsiArrayInitializerExpression && migrationType instanceof PsiArrayType) { + final PsiExpression[] initializers = ((PsiArrayInitializerExpression) expr).getInitializers(); + for (PsiExpression initializer : initializers) { + migrateExpressionType(initializer, ((PsiArrayType) migrationType).getComponentType(), expr, alreadyProcessed, true); } - final PsiType type = TypeEvaluator.substituteType( - migrationClassType, - originalClassType, - true, - originalClassType.resolveGenerics().getElement(), - JavaPsiFacade.getElementFactory(expr.getProject()).createType(originalClassType.resolve(), PsiSubstitutor.EMPTY) + getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), migrationType); + return; + } + else if (expr instanceof PsiArrayAccessExpression arrayAccessExpression) { + migrateExpressionType( + arrayAccessExpression.getArrayExpression(), + migrationType.createArrayType(), + place, + alreadyProcessed, + isCovariant ); - if (type != null) { - final TypeMigrationUsageInfo usageInfo = new TypeMigrationUsageInfo(expr); - usageInfo.setOwnerRoot(myCurrentRoot); - myNewExpressionTypeChange.put(usageInfo, type); - getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), type); - return; + return; + } + else if (expr instanceof PsiReferenceExpression refExpr) { + final PsiElement resolved = refExpr.resolve(); + if (resolved != null) { + if (!addMigrationRoot(resolved, migrationType, place, alreadyProcessed, !isCovariant)) { + convertExpression(expr, migrationType, getTypeEvaluator().evaluateType(expr), isCovariant); + } } - } + return; + } + else if (expr instanceof PsiMethodCallExpression methodCall) { + final PsiMethod resolved = methodCall.resolveMethod(); + if (resolved != null) { + if (!addMigrationRoot(resolved, migrationType, place, alreadyProcessed, !isCovariant)) { + convertExpression(expr, migrationType, getTypeEvaluator().evaluateType(expr), isCovariant); + } + } + return; + } + else if (expr instanceof PsiNewExpression) { + if (originalType.getArrayDimensions() == migrationType.getArrayDimensions()) { + if (migrationType.getArrayDimensions() > 0) { + final PsiType elementType = ((PsiArrayType) migrationType).getComponentType(); + + final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression) expr).getArrayInitializer(); + + if (arrayInitializer != null) { + final PsiExpression[] initializers = arrayInitializer.getInitializers(); + for (int i = initializers.length - 1; i >= 0; i--) { + migrateExpressionType(initializers[i], elementType, place, alreadyProcessed, true); + } + } + + if (isGenericsArrayType(elementType)) { + markFailedConversion(Couple.of(originalType, migrationType), expr); + return; + } + + final TypeMigrationUsageInfo usageInfo = new TypeMigrationUsageInfo(expr); + usageInfo.setOwnerRoot(myCurrentRoot); + myNewExpressionTypeChange.put(usageInfo, migrationType); + getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), migrationType); + return; + } + else { + if (migrationType instanceof PsiClassType migrationClassType && originalType instanceof PsiClassType originalClassType + && migrationClassType.rawType().isAssignableFrom(originalClassType.rawType())) { + final PsiClass originalClass = PsiUtil.resolveClassInType(originalClassType); + if (originalClass instanceof PsiAnonymousClass anonymousClass) { + originalType = anonymousClass.getBaseClassType(); + originalClassType = (PsiClassType) originalType; + } + final PsiType type = TypeEvaluator.substituteType( + migrationClassType, + originalClassType, + true, + originalClassType.resolveGenerics().getElement(), + JavaPsiFacade.getElementFactory(expr.getProject()).createType(originalClassType.resolve(), PsiSubstitutor.EMPTY) + ); + if (type != null) { + final TypeMigrationUsageInfo usageInfo = new TypeMigrationUsageInfo(expr); + usageInfo.setOwnerRoot(myCurrentRoot); + myNewExpressionTypeChange.put(usageInfo, type); + getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), type); + return; + } + } + } + } + } + else if (expr instanceof PsiLambdaExpression) { + //TODO conversion of lambda expression now works incorrectly [Dmitry Batkovich] + return; } - } - } else if (expr instanceof PsiLambdaExpression) { - //TODO conversion of lambda expression now works incorrectly [Dmitry Batkovich] - return; - } - - convertExpression(expr, migrationType, originalType, isCovariant); - } - private static boolean isGenericsArrayType(final PsiType elementType) { - if (elementType instanceof PsiClassType && ((PsiClassType) elementType).hasParameters()) { - return true; - } else if (elementType instanceof PsiArrayType) { - final PsiType componentType = ((PsiArrayType) elementType).getComponentType(); - return isGenericsArrayType(componentType); - } - return false; - } - - @RequiredUIAccess - boolean addMigrationRoot( - PsiElement element, - PsiType type, - final PsiElement place, - boolean alreadyProcessed, - final boolean isContraVariantPosition - ) { - return addMigrationRoot(element, type, place, alreadyProcessed, isContraVariantPosition, false); - } - - @RequiredUIAccess - boolean addMigrationRoot( - PsiElement element, - PsiType type, - final PsiElement place, - boolean alreadyProcessed, - final boolean isContraVariantPosition, - final boolean userDefinedType - ) { - if (myAllowedRoots != null && !myAllowedRoots.contains(element)) { - return false; + convertExpression(expr, migrationType, originalType, isCovariant); } - if (type.equals(PsiType.NULL)) { - return false; - } - final PsiElement resolved = Util.normalizeElement(element); - if (!canBeRoot(resolved, myRules.getSearchScope())) { - return false; - } - final PsiType originalType = getElementType(resolved); - LOG.assertTrue(originalType != null); - type = userDefinedType ? type : TypeEvaluator.substituteType(type, originalType, isContraVariantPosition); - - if (userDefinedType) { - Set disappearedTypeParameters = getTypeParameters(originalType); - disappearedTypeParameters.removeAll(getTypeParameters(type)); - myDisappearedTypeParameters.addAll(disappearedTypeParameters); - } else if (typeContainsTypeParameters(originalType, getTypeParameters(type))) { - return false; + + private static boolean isGenericsArrayType(final PsiType elementType) { + if (elementType instanceof PsiClassType && ((PsiClassType) elementType).hasParameters()) { + return true; + } + else if (elementType instanceof PsiArrayType) { + final PsiType componentType = ((PsiArrayType) elementType).getComponentType(); + return isGenericsArrayType(componentType); + } + return false; } - if (type instanceof PsiCapturedWildcardType) { - return false; + @RequiredUIAccess + boolean addMigrationRoot( + PsiElement element, + PsiType type, + final PsiElement place, + boolean alreadyProcessed, + final boolean isContraVariantPosition + ) { + return addMigrationRoot(element, type, place, alreadyProcessed, isContraVariantPosition, false); } - if (resolved instanceof PsiMethod) { - final PsiMethod method = ((PsiMethod) resolved); - - final PsiClass containingClass = method.getContainingClass(); - if (containingClass instanceof PsiAnonymousClass containingAnonymousClass) { - final HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature(); - final List superSignatures = signature.getSuperSignatures(); - if (!superSignatures.isEmpty()) { - - final HierarchicalMethodSignature superSignature = superSignatures.get(0); - - final PsiSubstitutor substitutor = superSignature.getSubstitutor(); - if (!substitutor.getSubstitutionMap().isEmpty()) { - final PsiMethod superMethod = superSignature.getMethod(); - - final PsiType superReturnType = superMethod.getReturnType(); - if (superReturnType instanceof PsiClassType classType) { - final PsiClass resolvedClass = classType.resolve(); - if (resolvedClass instanceof PsiTypeParameter typeParameter) { - final PsiType expectedReturnType = substitutor.substitute(typeParameter); - if (Comparing.equal(expectedReturnType, method.getReturnType())) { - final PsiClassType baseClassType = containingAnonymousClass.getBaseClassType(); - final PsiClassType.ClassResolveResult result = baseClassType.resolveGenerics(); - final PsiClass anonymousBaseClass = result.getElement(); - - final PsiSubstitutor superHierarchySubstitutor = - TypeConversionUtil.getClassSubstitutor(superMethod.getContainingClass(), anonymousBaseClass, PsiSubstitutor.EMPTY); - final PsiType maybeType = superHierarchySubstitutor.substitute(typeParameter); - - if (maybeType instanceof PsiClassType maybeClassType - && maybeClassType.resolve() instanceof PsiTypeParameter maybeTypeParameter) { - final PsiSubstitutor newSubstitutor = result.getSubstitutor().put(maybeTypeParameter, type); - addRoot( - new TypeMigrationUsageInfo(containingAnonymousClass.getBaseClassReference().getParameterList()), - new PsiImmediateClassType(anonymousBaseClass, newSubstitutor), - place, - alreadyProcessed - ); - } + @RequiredUIAccess + boolean addMigrationRoot( + PsiElement element, + PsiType type, + final PsiElement place, + boolean alreadyProcessed, + final boolean isContraVariantPosition, + final boolean userDefinedType + ) { + if (myAllowedRoots != null && !myAllowedRoots.contains(element)) { + return false; + } + if (type.equals(PsiType.NULL)) { + return false; + } + final PsiElement resolved = Util.normalizeElement(element); + if (!canBeRoot(resolved, myRules.getSearchScope())) { + return false; + } + final PsiType originalType = getElementType(resolved); + LOG.assertTrue(originalType != null); + type = userDefinedType ? type : TypeEvaluator.substituteType(type, originalType, isContraVariantPosition); + + if (userDefinedType) { + Set disappearedTypeParameters = getTypeParameters(originalType); + disappearedTypeParameters.removeAll(getTypeParameters(type)); + myDisappearedTypeParameters.addAll(disappearedTypeParameters); + } + else if (typeContainsTypeParameters(originalType, getTypeParameters(type))) { + return false; + } + + if (type instanceof PsiCapturedWildcardType) { + return false; + } + + if (resolved instanceof PsiMethod) { + final PsiMethod method = ((PsiMethod) resolved); + + final PsiClass containingClass = method.getContainingClass(); + if (containingClass instanceof PsiAnonymousClass containingAnonymousClass) { + final HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature(); + final List superSignatures = signature.getSuperSignatures(); + if (!superSignatures.isEmpty()) { + + final HierarchicalMethodSignature superSignature = superSignatures.get(0); + + final PsiSubstitutor substitutor = superSignature.getSubstitutor(); + if (!substitutor.getSubstitutionMap().isEmpty()) { + final PsiMethod superMethod = superSignature.getMethod(); + + final PsiType superReturnType = superMethod.getReturnType(); + if (superReturnType instanceof PsiClassType classType) { + final PsiClass resolvedClass = classType.resolve(); + if (resolvedClass instanceof PsiTypeParameter typeParameter) { + final PsiType expectedReturnType = substitutor.substitute(typeParameter); + if (Comparing.equal(expectedReturnType, method.getReturnType())) { + final PsiClassType baseClassType = containingAnonymousClass.getBaseClassType(); + final PsiClassType.ClassResolveResult result = baseClassType.resolveGenerics(); + final PsiClass anonymousBaseClass = result.getElement(); + + final PsiSubstitutor superHierarchySubstitutor = + TypeConversionUtil.getClassSubstitutor( + superMethod.getContainingClass(), + anonymousBaseClass, + PsiSubstitutor.EMPTY + ); + final PsiType maybeType = superHierarchySubstitutor.substitute(typeParameter); + + if (maybeType instanceof PsiClassType maybeClassType + && maybeClassType.resolve() instanceof PsiTypeParameter maybeTypeParameter) { + final PsiSubstitutor newSubstitutor = result.getSubstitutor().put(maybeTypeParameter, type); + addRoot( + new TypeMigrationUsageInfo(containingAnonymousClass.getBaseClassReference().getParameterList()), + new PsiImmediateClassType(anonymousBaseClass, newSubstitutor), + place, + alreadyProcessed + ); + } + } + } + } + } } - } } - } - } - } - - final PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY); - final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length]; - for (int i = -1; i < methods.length; i++) { - final TypeMigrationUsageInfo m; - if (i < 0) { - final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method); - m = overriddenUsageInfo; - final String newMethodName = isMethodNameCanBeChanged(method); - if (newMethodName != null) { - final MigrateGetterNameSetting migrateGetterNameSetting = myRules.getConversionSettings(MigrateGetterNameSetting.class); - migrateGetterNameSetting.askUserIfNeed(overriddenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot)); - } - } else { - overriders[i] = new OverriderUsageInfo(methods[i], method); - m = overriders[i]; - } - - alreadyProcessed = addRoot(m, type, place, alreadyProcessed); - } - - return !alreadyProcessed; - } else if (resolved instanceof PsiParameter && ((PsiParameter) resolved).getDeclarationScope() instanceof PsiMethod) { - final PsiMethod method = (PsiMethod) ((PsiParameter) resolved).getDeclarationScope(); - - final int index = method.getParameterList().getParameterIndex(((PsiParameter) resolved)); - final PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY); - - final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length]; - final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method.getParameterList().getParameters()[index]); - for (int i = -1; i < methods.length; i++) { - final PsiMethod m = i < 0 ? method : methods[i]; - final PsiParameter p = m.getParameterList().getParameters()[index]; - final TypeMigrationUsageInfo paramUsageInfo; - if (i < 0) { - paramUsageInfo = overriddenUsageInfo; - } else { - overriders[i] = new OverriderUsageInfo(p, method); - paramUsageInfo = overriders[i]; - } - alreadyProcessed = addRoot(paramUsageInfo, type, place, alreadyProcessed); - } - - return !alreadyProcessed; - } else { - return !addRoot(new TypeMigrationUsageInfo(resolved), type, place, alreadyProcessed); - } - } - - @Nonnull - private static Set getTypeParameters(@Nonnull PsiType type) { - if (type instanceof PsiClassType) { - PsiTypesUtil.TypeParameterSearcher searcher = new PsiTypesUtil.TypeParameterSearcher(); - type.accept(searcher); - return searcher.getTypeParameters(); - } - return Collections.emptySet(); - } - @Nullable - private String isMethodNameCanBeChanged(PsiMethod method) { - if (myCurrentRoot == null) { - return null; - } - final PsiElement root = myCurrentRoot.getElement(); - if (!(root instanceof PsiField)) { - return null; - } - PsiField field = (PsiField) root; - final PsiType migrationType = myTypeEvaluator.getType(root); - if (migrationType == null) { - return null; - } - final PsiType sourceType = field.getType(); - if (TypeConversionUtil.isAssignable(migrationType, sourceType)) { - return null; - } - if (!(migrationType.equals(PsiType.BOOLEAN) || migrationType.equals(PsiType.BOOLEAN.getBoxedType(field))) - && !(sourceType.equals(PsiType.BOOLEAN) || sourceType.equals(PsiType.BOOLEAN.getBoxedType(field)))) { - return null; - } - final PsiMethod[] getters = - GetterSetterPrototypeProvider.findGetters(field.getContainingClass(), field.getName(), field.hasModifierProperty(PsiModifier.STATIC)); - if (getters != null) { - for (PsiMethod getter : getters) { - if (getter.isEquivalentTo(method)) { - final String suggestedName = GenerateMembersUtil.suggestGetterName(field.getName(), migrationType, method.getProject()); - if (!suggestedName.equals(method.getName())) { - if (getter.getContainingClass().findMethodsByName(suggestedName, true).length != 0) { - return null; + final PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY); + final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length]; + for (int i = -1; i < methods.length; i++) { + final TypeMigrationUsageInfo m; + if (i < 0) { + final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method); + m = overriddenUsageInfo; + final String newMethodName = isMethodNameCanBeChanged(method); + if (newMethodName != null) { + final MigrateGetterNameSetting migrateGetterNameSetting = + myRules.getConversionSettings(MigrateGetterNameSetting.class); + migrateGetterNameSetting.askUserIfNeed(overriddenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot)); + } + } + else { + overriders[i] = new OverriderUsageInfo(methods[i], method); + m = overriders[i]; + } + + alreadyProcessed = addRoot(m, type, place, alreadyProcessed); } - return suggestedName; - } - return null; + + return !alreadyProcessed; } - } - } - return null; - } + else if (resolved instanceof PsiParameter && ((PsiParameter) resolved).getDeclarationScope() instanceof PsiMethod) { + final PsiMethod method = (PsiMethod) ((PsiParameter) resolved).getDeclarationScope(); + + final int index = method.getParameterList().getParameterIndex(((PsiParameter) resolved)); + final PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY); + + final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length]; + final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method.getParameterList().getParameters()[index]); + for (int i = -1; i < methods.length; i++) { + final PsiMethod m = i < 0 ? method : methods[i]; + final PsiParameter p = m.getParameterList().getParameters()[index]; + final TypeMigrationUsageInfo paramUsageInfo; + if (i < 0) { + paramUsageInfo = overriddenUsageInfo; + } + else { + overriders[i] = new OverriderUsageInfo(p, method); + paramUsageInfo = overriders[i]; + } + alreadyProcessed = addRoot(paramUsageInfo, type, place, alreadyProcessed); + } - private boolean typeContainsTypeParameters(@Nullable PsiType type, @Nonnull Set excluded) { - if (!(type instanceof PsiClassType)) { - return false; + return !alreadyProcessed; + } + else { + return !addRoot(new TypeMigrationUsageInfo(resolved), type, place, alreadyProcessed); + } } - PsiTypesUtil.TypeParameterSearcher searcher = new PsiTypesUtil.TypeParameterSearcher(); - type.accept(searcher); - for (PsiTypeParameter parameter : searcher.getTypeParameters()) { - if (!excluded.contains(parameter) && !myDisappearedTypeParameters.contains(parameter)) { - return true; - } + + @Nonnull + private static Set getTypeParameters(@Nonnull PsiType type) { + if (type instanceof PsiClassType) { + PsiTypesUtil.TypeParameterSearcher searcher = new PsiTypesUtil.TypeParameterSearcher(); + type.accept(searcher); + return searcher.getTypeParameters(); + } + return Collections.emptySet(); } - return false; - } - - @Nullable - public static PsiType getElementType(final PsiElement resolved) { - if (resolved instanceof PsiVariable) { - return ((PsiVariable) resolved).getType(); - } else { - if (resolved instanceof PsiMethod) { - return (((PsiMethod) resolved).getReturnType()); - } else if (resolved instanceof PsiExpression) { - return (((PsiExpression) resolved).getType()); - } else if (resolved instanceof PsiReferenceParameterList) { - PsiElement parent = resolved.getParent(); - while (parent != null) { - LOG.assertTrue(parent instanceof PsiJavaCodeReferenceElement); - final PsiClass psiClass = (PsiClass) ((PsiJavaCodeReferenceElement) parent).resolve(); - final PsiClass containingClass = PsiTreeUtil.getParentOfType(parent, PsiClass.class); - if (psiClass != null && containingClass != null) { - final PsiSubstitutor classSubstitutor = TypeConversionUtil.getClassSubstitutor(psiClass, containingClass, PsiSubstitutor.EMPTY); - if (classSubstitutor != null) { - return JavaPsiFacade.getElementFactory(parent.getProject()).createType(psiClass, classSubstitutor); + + @Nullable + private String isMethodNameCanBeChanged(PsiMethod method) { + if (myCurrentRoot == null) { + return null; + } + final PsiElement root = myCurrentRoot.getElement(); + if (!(root instanceof PsiField)) { + return null; + } + PsiField field = (PsiField) root; + final PsiType migrationType = myTypeEvaluator.getType(root); + if (migrationType == null) { + return null; + } + final PsiType sourceType = field.getType(); + if (TypeConversionUtil.isAssignable(migrationType, sourceType)) { + return null; + } + if (!(migrationType.equals(PsiType.BOOLEAN) || migrationType.equals(PsiType.BOOLEAN.getBoxedType(field))) + && !(sourceType.equals(PsiType.BOOLEAN) || sourceType.equals(PsiType.BOOLEAN.getBoxedType(field)))) { + return null; + } + final PsiMethod[] getters = + GetterSetterPrototypeProvider.findGetters( + field.getContainingClass(), + field.getName(), + field.hasModifierProperty(PsiModifier.STATIC) + ); + if (getters != null) { + for (PsiMethod getter : getters) { + if (getter.isEquivalentTo(method)) { + final String suggestedName = GenerateMembersUtil.suggestGetterName(field.getName(), migrationType, method.getProject()); + if (!suggestedName.equals(method.getName())) { + if (getter.getContainingClass().findMethodsByName(suggestedName, true).length != 0) { + return null; + } + return suggestedName; + } + return null; + } } - } - parent = PsiTreeUtil.getParentOfType(parent, PsiJavaCodeReferenceElement.class, true); } - } else if (resolved instanceof PsiClass) { - return JavaPsiFacade.getElementFactory(resolved.getProject()).createType((PsiClass) resolved, PsiSubstitutor.EMPTY); - } + return null; } - return null; - } - - public void clearStopException() { - myException = null; - } - - @RequiredUIAccess - boolean addRoot(final TypeMigrationUsageInfo usageInfo, final PsiType type, final PsiElement place, boolean alreadyProcessed) { - if (myShowWarning && myMigrationRoots.size() > 10 && !myProject.getApplication().isUnitTestMode()) { - myShowWarning = false; - myDialogSemaphore.down(); - try { - final Runnable checkTimeToStopRunnable = () -> - { - if (Messages.showYesNoCancelDialog( - "Found more than 10 roots to migrate. Do you want to preview?", - "Type Migration", - UIUtil.getWarningIcon() - ) == Messages.YES) { - myException = new MigrateException(); - } - myDialogSemaphore.up(); - }; - SwingUtilities.invokeLater(checkTimeToStopRunnable); - } catch (Exception e) { - //do nothing - } + + private boolean typeContainsTypeParameters(@Nullable PsiType type, @Nonnull Set excluded) { + if (!(type instanceof PsiClassType)) { + return false; + } + PsiTypesUtil.TypeParameterSearcher searcher = new PsiTypesUtil.TypeParameterSearcher(); + type.accept(searcher); + for (PsiTypeParameter parameter : searcher.getTypeParameters()) { + if (!excluded.contains(parameter) && !myDisappearedTypeParameters.contains(parameter)) { + return true; + } + } + return false; } - checkInterrupted(); - rememberRootTrace(usageInfo, type, place, alreadyProcessed); - if (!alreadyProcessed && !(usageInfo.getElement() instanceof PsiExpression) && !getTypeEvaluator().setType(usageInfo, type)) { - alreadyProcessed = true; + + @Nullable + public static PsiType getElementType(final PsiElement resolved) { + if (resolved instanceof PsiVariable) { + return ((PsiVariable) resolved).getType(); + } + else { + if (resolved instanceof PsiMethod) { + return (((PsiMethod) resolved).getReturnType()); + } + else if (resolved instanceof PsiExpression) { + return (((PsiExpression) resolved).getType()); + } + else if (resolved instanceof PsiReferenceParameterList) { + PsiElement parent = resolved.getParent(); + while (parent != null) { + LOG.assertTrue(parent instanceof PsiJavaCodeReferenceElement); + final PsiClass psiClass = (PsiClass) ((PsiJavaCodeReferenceElement) parent).resolve(); + final PsiClass containingClass = PsiTreeUtil.getParentOfType(parent, PsiClass.class); + if (psiClass != null && containingClass != null) { + final PsiSubstitutor classSubstitutor = + TypeConversionUtil.getClassSubstitutor(psiClass, containingClass, PsiSubstitutor.EMPTY); + if (classSubstitutor != null) { + return JavaPsiFacade.getElementFactory(parent.getProject()).createType(psiClass, classSubstitutor); + } + } + parent = PsiTreeUtil.getParentOfType(parent, PsiJavaCodeReferenceElement.class, true); + } + } + else if (resolved instanceof PsiClass) { + return JavaPsiFacade.getElementFactory(resolved.getProject()).createType((PsiClass) resolved, PsiSubstitutor.EMPTY); + } + } + return null; } - if (!alreadyProcessed) { - myMigrationRoots.addFirst(Pair.create(usageInfo, type)); + public void clearStopException() { + myException = null; } - return alreadyProcessed; - } - private void checkInterrupted() { - if (myException != null) { - throw myException; + @RequiredUIAccess + boolean addRoot(final TypeMigrationUsageInfo usageInfo, final PsiType type, final PsiElement place, boolean alreadyProcessed) { + if (myShowWarning && myMigrationRoots.size() > 10 && !myProject.getApplication().isUnitTestMode()) { + myShowWarning = false; + myDialogSemaphore.down(); + try { + final Runnable checkTimeToStopRunnable = () -> + { + if (Messages.showYesNoCancelDialog( + "Found more than 10 roots to migrate. Do you want to preview?", + "Type Migration", + UIUtil.getWarningIcon() + ) == Messages.YES) { + myException = new MigrateException(); + } + myDialogSemaphore.up(); + }; + SwingUtilities.invokeLater(checkTimeToStopRunnable); + } + catch (Exception e) { + //do nothing + } + } + checkInterrupted(); + rememberRootTrace(usageInfo, type, place, alreadyProcessed); + if (!alreadyProcessed && !(usageInfo.getElement() instanceof PsiExpression) && !getTypeEvaluator().setType(usageInfo, type)) { + alreadyProcessed = true; + } + + if (!alreadyProcessed) { + myMigrationRoots.addFirst(Pair.create(usageInfo, type)); + } + return alreadyProcessed; } - } - - private void rememberRootTrace( - final TypeMigrationUsageInfo usageInfo, - final PsiType type, - final PsiElement place, - final boolean alreadyProcessed - ) { - if (myCurrentRoot != null) { - if (!alreadyProcessed) { - myProcessedRoots.add(usageInfo); - } - - if (myProcessedRoots.contains(usageInfo)) { - HashSet> infos = myRootsTree.get(myCurrentRoot); - if (infos == null) { - infos = new HashSet<>(); - myRootsTree.put(myCurrentRoot, infos); - } - infos.add(Pair.create(usageInfo, type)); - } - if (!(usageInfo instanceof OverriderUsageInfo)) { //hide the same usage for all overriders - setTypeUsage(usageInfo, place); - } + + private void checkInterrupted() { + if (myException != null) { + throw myException; + } } - } - - private void setTypeUsage(final TypeMigrationUsageInfo usageInfo, final PsiElement place) { - if (place != null) { - final Couple rooted = Couple.of(usageInfo, myCurrentRoot); - Set usages = myRootUsagesTree.get(rooted); - if (usages == null) { - usages = new HashSet<>(); - myRootUsagesTree.put(rooted, usages); - } - usages.add(place); + + private void rememberRootTrace( + final TypeMigrationUsageInfo usageInfo, + final PsiType type, + final PsiElement place, + final boolean alreadyProcessed + ) { + if (myCurrentRoot != null) { + if (!alreadyProcessed) { + myProcessedRoots.add(usageInfo); + } + + if (myProcessedRoots.contains(usageInfo)) { + HashSet> infos = myRootsTree.get(myCurrentRoot); + if (infos == null) { + infos = new HashSet<>(); + myRootsTree.put(myCurrentRoot, infos); + } + infos.add(Pair.create(usageInfo, type)); + } + if (!(usageInfo instanceof OverriderUsageInfo)) { //hide the same usage for all overriders + setTypeUsage(usageInfo, place); + } + } } - } - - public void setTypeUsage(final PsiElement element, final PsiElement place) { - setTypeUsage(new TypeMigrationUsageInfo(element), place); - } - - void markFailedConversion(final Pair typePair, final PsiExpression expression) { - LOG.assertTrue(typePair.getSecond() != null); - final Pair, PsiType> key = Pair.create(SmartPointerManager.getInstance(expression.getProject()).createSmartPsiElementPointer(expression), typePair - .getSecond()); - if (!myFailedConversions.containsKey(key)) { - myFailedConversions.put(key, getCurrentRoot()); + + private void setTypeUsage(final TypeMigrationUsageInfo usageInfo, final PsiElement place) { + if (place != null) { + final Couple rooted = Couple.of(usageInfo, myCurrentRoot); + Set usages = myRootUsagesTree.get(rooted); + if (usages == null) { + usages = new HashSet<>(); + myRootUsagesTree.put(rooted, usages); + } + usages.add(place); + } } - } - void setConversionMapping(final PsiExpression expression, final Object obj) { - if (myConversions.get(expression) != null) { - return; + public void setTypeUsage(final PsiElement element, final PsiElement place) { + setTypeUsage(new TypeMigrationUsageInfo(element), place); } - if (obj instanceof TypeConversionDescriptorBase) { - ((TypeConversionDescriptorBase) obj).setRoot(myCurrentRoot); + void markFailedConversion(final Pair typePair, final PsiExpression expression) { + LOG.assertTrue(typePair.getSecond() != null); + final Pair, PsiType> key = + Pair.create(SmartPointerManager.getInstance(expression.getProject()).createSmartPsiElementPointer(expression), typePair + .getSecond()); + if (!myFailedConversions.containsKey(key)) { + myFailedConversions.put(key, getCurrentRoot()); + } } - myConversions.put(expression, obj); - } - - @RequiredReadAction - public PsiReference[] markRootUsages(final PsiElement element, final PsiType migrationType) { - return markRootUsages( - element, - migrationType, - ReferencesSearch.search(element, myRules.getSearchScope(), false).toArray(PsiReference.EMPTY_ARRAY) - ); - } - - @RequiredReadAction - PsiReference[] markRootUsages(final PsiElement element, final PsiType migrationType, final PsiReference[] refs) { - final List validReferences = new ArrayList<>(); - for (PsiReference ref1 : refs) { - final PsiElement ref = ref1.getElement(); - - if (ref != null) { - if (element instanceof PsiMethod) { - final PsiElement parent = Util.getEssentialParent(ref); - - if (!(parent instanceof PsiMethodCallExpression)) { - continue; - } - - getTypeEvaluator().setType(new TypeMigrationUsageInfo(parent), migrationType); - } else if (element instanceof PsiVariable) { - if (ref instanceof PsiReferenceExpression) { - getTypeEvaluator().setType(new TypeMigrationUsageInfo(ref), PsiUtil.captureToplevelWildcards(migrationType, ref)); - } - } else { - LOG.error("Method call expression or reference expression expected but found " + element.getClass().getName()); - continue; - } - validReferences.add(ref1); - } + + void setConversionMapping(final PsiExpression expression, final Object obj) { + if (myConversions.get(expression) != null) { + return; + } + + if (obj instanceof TypeConversionDescriptorBase) { + ((TypeConversionDescriptorBase) obj).setRoot(myCurrentRoot); + } + myConversions.put(expression, obj); } - Collections.sort(validReferences, Comparator.comparingInt(o -> o.getElement().getTextOffset())); - - return validReferences.toArray(PsiReference.EMPTY_ARRAY); - } - - @RequiredUIAccess - public void setRootAndMigrate(final TypeMigrationUsageInfo newRootUsageInfo, final PsiType migrationType, final PsiReference[] usages) { - final TypeMigrationUsageInfo oldRoot = getCurrentRoot(); - myCurrentRoot = newRootUsageInfo; - PsiElement root = newRootUsageInfo.getElement(); - if (root instanceof PsiMethod method) { - migrateMethodReturnExpression(migrationType, method); - } else if (root instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiMethod) { - migrateMethodCallExpressions(migrationType, parameter, null); - } else if (root instanceof PsiVariable || root instanceof PsiExpression) { - final PsiElement element = getContainingStatement(root); - if (root instanceof PsiExpression expression) { - migrateExpressionType(expression, migrationType, element, false, true); - myTypeEvaluator.setType(newRootUsageInfo, migrationType); - } - element.accept(new TypeMigrationStatementProcessor(element, this)); - } else if (root instanceof PsiReferenceParameterList referenceParameterList) { - final TypeMigrationUsageInfo info = new TypeMigrationUsageInfo(root); - info.setOwnerRoot(oldRoot); - myClassTypeArgumentsChange.put(info, (PsiClassType) migrationType); - new ClassTypeArgumentMigrationProcessor(this).migrateClassTypeParameter(referenceParameterList, (PsiClassType) migrationType); + @RequiredReadAction + public PsiReference[] markRootUsages(final PsiElement element, final PsiType migrationType) { + return markRootUsages( + element, + migrationType, + ReferencesSearch.search(element, myRules.getSearchScope(), false).toArray(PsiReference.EMPTY_ARRAY) + ); } - final Set processed = new HashSet<>(); - for (PsiReference usage : usages) { - migrateRootUsageExpression(usage, processed); + @RequiredReadAction + PsiReference[] markRootUsages(final PsiElement element, final PsiType migrationType, final PsiReference[] refs) { + final List validReferences = new ArrayList<>(); + for (PsiReference ref1 : refs) { + final PsiElement ref = ref1.getElement(); + + if (ref != null) { + if (element instanceof PsiMethod) { + final PsiElement parent = Util.getEssentialParent(ref); + + if (!(parent instanceof PsiMethodCallExpression)) { + continue; + } + + getTypeEvaluator().setType(new TypeMigrationUsageInfo(parent), migrationType); + } + else if (element instanceof PsiVariable) { + if (ref instanceof PsiReferenceExpression) { + getTypeEvaluator().setType(new TypeMigrationUsageInfo(ref), PsiUtil.captureToplevelWildcards(migrationType, ref)); + } + } + else { + LOG.error("Method call expression or reference expression expected but found " + element.getClass().getName()); + continue; + } + validReferences.add(ref1); + } + } + + Collections.sort(validReferences, Comparator.comparingInt(o -> o.getElement().getTextOffset())); + + return validReferences.toArray(PsiReference.EMPTY_ARRAY); } - } - - private static PsiElement getContainingStatement(final PsiElement root) { - final PsiStatement statement = PsiTreeUtil.getParentOfType(root, PsiStatement.class); - final PsiField field = PsiTreeUtil.getParentOfType(root, PsiField.class); - return statement != null ? statement : field != null ? field : root; - } - - @RequiredReadAction - void migrateRootUsageExpression(final PsiReference usage, final Set processed) { - final PsiElement ref = usage.getElement(); - if (ref != null && ref.getLanguage() == JavaLanguage.INSTANCE) { - final PsiElement element = getContainingStatement(ref); - if (element != null && !processed.contains(element)) { - processed.add(element); - element.accept(new TypeMigrationStatementProcessor(ref, this)); - } + + @RequiredUIAccess + public void setRootAndMigrate(final TypeMigrationUsageInfo newRootUsageInfo, final PsiType migrationType, final PsiReference[] usages) { + final TypeMigrationUsageInfo oldRoot = getCurrentRoot(); + myCurrentRoot = newRootUsageInfo; + PsiElement root = newRootUsageInfo.getElement(); + if (root instanceof PsiMethod method) { + migrateMethodReturnExpression(migrationType, method); + } + else if (root instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiMethod) { + migrateMethodCallExpressions(migrationType, parameter, null); + } + else if (root instanceof PsiVariable || root instanceof PsiExpression) { + final PsiElement element = getContainingStatement(root); + if (root instanceof PsiExpression expression) { + migrateExpressionType(expression, migrationType, element, false, true); + myTypeEvaluator.setType(newRootUsageInfo, migrationType); + } + element.accept(new TypeMigrationStatementProcessor(element, this)); + } + else if (root instanceof PsiReferenceParameterList referenceParameterList) { + final TypeMigrationUsageInfo info = new TypeMigrationUsageInfo(root); + info.setOwnerRoot(oldRoot); + myClassTypeArgumentsChange.put(info, (PsiClassType) migrationType); + new ClassTypeArgumentMigrationProcessor(this).migrateClassTypeParameter(referenceParameterList, (PsiClassType) migrationType); + } + + final Set processed = new HashSet<>(); + for (PsiReference usage : usages) { + migrateRootUsageExpression(usage, processed); + } } - } - @RequiredUIAccess - void migrateMethodCallExpressions(final PsiType migrationType, final PsiParameter param, final PsiClass psiClass) { - boolean checkNumberOfArguments = false; - if (param.getType() instanceof PsiEllipsisType && !(migrationType instanceof PsiEllipsisType)) { - checkNumberOfArguments = true; + private static PsiElement getContainingStatement(final PsiElement root) { + final PsiStatement statement = PsiTreeUtil.getParentOfType(root, PsiStatement.class); + final PsiField field = PsiTreeUtil.getParentOfType(root, PsiField.class); + return statement != null ? statement : field != null ? field : root; } - final PsiType strippedType = migrationType instanceof PsiEllipsisType ellipsisType ? ellipsisType.getComponentType() : migrationType; - final PsiMethod method = (PsiMethod) param.getDeclarationScope(); - final PsiParameterList parameterList = method.getParameterList(); - final int parametersCount = parameterList.getParametersCount(); - final int index = parameterList.getParameterIndex(param); - final List refs = filterReferences( - psiClass, - ReferencesSearch.search(method, method.getUseScope().intersectWith(myRules.getSearchScope()), false) - ); - for (PsiReference ref1 : refs) { - final PsiElement ref = ref1.getElement(); - final PsiElement parent = Util.getEssentialParent(ref); - if (parent instanceof PsiCallExpression) { - final PsiExpressionList argumentList = ((PsiCallExpression) parent).getArgumentList(); - if (argumentList != null) { - final PsiExpression[] expressions = argumentList.getExpressions(); - if (checkNumberOfArguments && parametersCount != expressions.length) { - markFailedConversion(Couple.of(param.getType(), migrationType), (PsiCallExpression) parent); - } - if (index > -1 && index < expressions.length) { - for (int idx = index; idx < (param.isVarArgs() ? expressions.length : index + 1); idx++) { - final PsiExpression actual = expressions[idx]; - final PsiType type = getTypeEvaluator().evaluateType(actual); - if (type != null) { - migrateExpressionType(actual, strippedType, parent, TypeConversionUtil.isAssignable(strippedType, type), true); - } + + @RequiredReadAction + void migrateRootUsageExpression(final PsiReference usage, final Set processed) { + final PsiElement ref = usage.getElement(); + if (ref != null && ref.getLanguage() == JavaLanguage.INSTANCE) { + final PsiElement element = getContainingStatement(ref); + if (element != null && !processed.contains(element)) { + processed.add(element); + element.accept(new TypeMigrationStatementProcessor(ref, this)); } - } } - } else if (ref instanceof PsiDocTagValue) { - myConversions.put(ref, method); - } } - } - - private void migrateMethodReturnExpression(final PsiType migrationType, final PsiMethod method) { - final PsiCodeBlock block = method.getBody(); - if (block != null) { - block.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - @RequiredUIAccess - public void visitReturnStatement(@Nonnull PsiReturnStatement statement) { - final PsiExpression value = statement.getReturnValue(); - if (value != null) { - final PsiType type = getTypeEvaluator().evaluateType(value); - if (type != null && !type.equals(migrationType)) { - migrateExpressionType(value, migrationType, statement, TypeConversionUtil.isAssignable(migrationType, type), true); + + @RequiredUIAccess + void migrateMethodCallExpressions(final PsiType migrationType, final PsiParameter param, final PsiClass psiClass) { + boolean checkNumberOfArguments = false; + if (param.getType() instanceof PsiEllipsisType && !(migrationType instanceof PsiEllipsisType)) { + checkNumberOfArguments = true; + } + final PsiType strippedType = + migrationType instanceof PsiEllipsisType ellipsisType ? ellipsisType.getComponentType() : migrationType; + final PsiMethod method = (PsiMethod) param.getDeclarationScope(); + final PsiParameterList parameterList = method.getParameterList(); + final int parametersCount = parameterList.getParametersCount(); + final int index = parameterList.getParameterIndex(param); + final List refs = filterReferences( + psiClass, + ReferencesSearch.search(method, method.getUseScope().intersectWith(myRules.getSearchScope()), false) + ); + for (PsiReference ref1 : refs) { + final PsiElement ref = ref1.getElement(); + final PsiElement parent = Util.getEssentialParent(ref); + if (parent instanceof PsiCallExpression) { + final PsiExpressionList argumentList = ((PsiCallExpression) parent).getArgumentList(); + if (argumentList != null) { + final PsiExpression[] expressions = argumentList.getExpressions(); + if (checkNumberOfArguments && parametersCount != expressions.length) { + markFailedConversion(Couple.of(param.getType(), migrationType), (PsiCallExpression) parent); + } + if (index > -1 && index < expressions.length) { + for (int idx = index; idx < (param.isVarArgs() ? expressions.length : index + 1); idx++) { + final PsiExpression actual = expressions[idx]; + final PsiType type = getTypeEvaluator().evaluateType(actual); + if (type != null) { + migrateExpressionType( + actual, + strippedType, + parent, + TypeConversionUtil.isAssignable(strippedType, type), + true + ); + } + } + } + } + } + else if (ref instanceof PsiDocTagValue) { + myConversions.put(ref, method); } - } } + } - @Override - public void visitClass(@Nonnull PsiClass aClass) { - } + private void migrateMethodReturnExpression(final PsiType migrationType, final PsiMethod method) { + final PsiCodeBlock block = method.getBody(); + if (block != null) { + block.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + @RequiredUIAccess + public void visitReturnStatement(@Nonnull PsiReturnStatement statement) { + final PsiExpression value = statement.getReturnValue(); + if (value != null) { + final PsiType type = getTypeEvaluator().evaluateType(value); + if (type != null && !type.equals(migrationType)) { + migrateExpressionType( + value, + migrationType, + statement, + TypeConversionUtil.isAssignable(migrationType, type), + true + ); + } + } + } - @Override - public void visitLambdaExpression(@Nonnull PsiLambdaExpression expression) { + @Override + public void visitClass(@Nonnull PsiClass aClass) { + } + + @Override + public void visitLambdaExpression(@Nonnull PsiLambdaExpression expression) { + } + }); } - }); } - } - @RequiredUIAccess - private void iterate() { - final List> roots = new ArrayList<>(myMigrationRoots); + @RequiredUIAccess + private void iterate() { + final List> roots = new ArrayList<>(myMigrationRoots); - myMigrationRoots = new LinkedList<>(); + myMigrationRoots = new LinkedList<>(); - final PsiReference[][] cachedUsages = new PsiReference[roots.size()][]; - int j = 0; + final PsiReference[][] cachedUsages = new PsiReference[roots.size()][]; + int j = 0; - for (final Pair p : roots) { - cachedUsages[j++] = markRootUsages(p.getFirst().getElement(), p.getSecond()); + for (final Pair p : roots) { + cachedUsages[j++] = markRootUsages(p.getFirst().getElement(), p.getSecond()); + } + + j = 0; + + for (final Pair root : roots) { + setRootAndMigrate(root.getFirst(), root.getSecond(), cachedUsages[j++]); + } } - j = 0; + @RequiredUIAccess + private void migrate(boolean autoMigrate, final PsiElement... victims) { - for (final Pair root : roots) { - setRootAndMigrate(root.getFirst(), root.getSecond(), cachedUsages[j++]); + myMigrationRoots = new LinkedList<>(); + myTypeEvaluator = new TypeEvaluator(myMigrationRoots, this, myProject); + + SmartTypePointerManager smartTypePointerManager = SmartTypePointerManager.getInstance(myProject); + for (PsiElement victim : victims) { + // use deeply immediate types + PsiType migrationType = smartTypePointerManager.createSmartTypePointer(myMigrationRootTypeFunction.apply(victim)).getType(); + addMigrationRoot(victim, migrationType, null, false, true, true); + } + + if (autoMigrate) { + while (myMigrationRoots.size() > 0) { + iterate(); + } + } + + myDialogSemaphore.waitFor(); + checkInterrupted(); + } + + @Nonnull + private PsiReference[] findReferences(PsiElement element) { + return ReferencesSearch.search(element, myRules.getSearchScope(), false).toArray(PsiReference.EMPTY_ARRAY); } - } - @RequiredUIAccess - private void migrate(boolean autoMigrate, final PsiElement... victims) { + public TypeEvaluator getTypeEvaluator() { + return myTypeEvaluator; + } - myMigrationRoots = new LinkedList<>(); - myTypeEvaluator = new TypeEvaluator(myMigrationRoots, this, myProject); + public Map>> getRootsTree() { + return myRootsTree; + } - SmartTypePointerManager smartTypePointerManager = SmartTypePointerManager.getInstance(myProject); - for (PsiElement victim : victims) { - // use deeply immediate types - PsiType migrationType = smartTypePointerManager.createSmartTypePointer(myMigrationRootTypeFunction.apply(victim)).getType(); - addMigrationRoot(victim, migrationType, null, false, true, true); + TypeMigrationUsageInfo getCurrentRoot() { + return myCurrentRoot; } - if (autoMigrate) { - while (myMigrationRoots.size() > 0) { - iterate(); - } + public LinkedList> getMigrationRoots() { + return myMigrationRoots; } - myDialogSemaphore.waitFor(); - checkInterrupted(); - } - - @Nonnull - private PsiReference[] findReferences(PsiElement element) { - return ReferencesSearch.search(element, myRules.getSearchScope(), false).toArray(PsiReference.EMPTY_ARRAY); - } - - public TypeEvaluator getTypeEvaluator() { - return myTypeEvaluator; - } - - public Map>> getRootsTree() { - return myRootsTree; - } - - TypeMigrationUsageInfo getCurrentRoot() { - return myCurrentRoot; - } - - public LinkedList> getMigrationRoots() { - return myMigrationRoots; - } - - @RequiredReadAction - public static List filterReferences(final PsiClass psiClass, final Query memberReferences) { - final List refs = new ArrayList<>(); - for (PsiReference memberReference : memberReferences) { - if (psiClass == null) { - refs.add(memberReference); - } else { - final PsiElement referencedElement = memberReference.getElement(); - if (referencedElement instanceof PsiReferenceExpression referenceExpression) { - final PsiExpression qualifierExpression = referenceExpression.getQualifierExpression(); - if (qualifierExpression != null) { - final PsiType qualifierType = qualifierExpression.getType(); - if (qualifierType instanceof PsiClassType classType && psiClass == classType.resolve()) { - refs.add(memberReference); + @RequiredReadAction + public static List filterReferences(final PsiClass psiClass, final Query memberReferences) { + final List refs = new ArrayList<>(); + for (PsiReference memberReference : memberReferences) { + if (psiClass == null) { + refs.add(memberReference); } - } else { - if (psiClass == PsiTreeUtil.getParentOfType(referencedElement, PsiClass.class)) { - refs.add(memberReference); + else { + final PsiElement referencedElement = memberReference.getElement(); + if (referencedElement instanceof PsiReferenceExpression referenceExpression) { + final PsiExpression qualifierExpression = referenceExpression.getQualifierExpression(); + if (qualifierExpression != null) { + final PsiType qualifierType = qualifierExpression.getType(); + if (qualifierType instanceof PsiClassType classType && psiClass == classType.resolve()) { + refs.add(memberReference); + } + } + else { + if (psiClass == PsiTreeUtil.getParentOfType(referencedElement, PsiClass.class)) { + refs.add(memberReference); + } + } + } } - } } - } + return refs; } - return refs; - } - private static boolean canBeRoot(@Nullable PsiElement element, @Nonnull SearchScope migrationScope) { - return element != null && element.isValid() && element.isPhysical() && PsiSearchScopeUtil.isInScope(migrationScope, element); - } + private static boolean canBeRoot(@Nullable PsiElement element, @Nonnull SearchScope migrationScope) { + return element != null && element.isValid() && element.isPhysical() && PsiSearchScopeUtil.isInScope(migrationScope, element); + } - @TestOnly - @RequiredReadAction - public String getMigrationReport() { - final StringBuilder buffer = new StringBuilder(); + @TestOnly + @RequiredReadAction + public String getMigrationReport() { + final StringBuilder buffer = new StringBuilder(); - buffer.append("Types:\n").append(getTypeEvaluator().getReport()).append("\n"); + buffer.append("Types:\n").append(getTypeEvaluator().getReport()).append("\n"); - buffer.append("Conversions:\n"); + buffer.append("Conversions:\n"); - final String[] conversions = new String[myConversions.size()]; - int k = 0; + final String[] conversions = new String[myConversions.size()]; + int k = 0; - for (final PsiElement expr : myConversions.keySet()) { - final Object conversion = myConversions.get(expr); + for (final PsiElement expr : myConversions.keySet()) { + final Object conversion = myConversions.get(expr); - if (conversion instanceof Pair && ((Pair) conversion).first == null) { - conversions[k++] = (expr.getText() + " -> " + ((Pair) conversion).second + "\n"); - } else { - conversions[k++] = (expr.getText() + " -> " + conversion + "\n"); - } - } + if (conversion instanceof Pair && ((Pair) conversion).first == null) { + conversions[k++] = (expr.getText() + " -> " + ((Pair) conversion).second + "\n"); + } + else { + conversions[k++] = (expr.getText() + " -> " + conversion + "\n"); + } + } - Arrays.sort(conversions); + Arrays.sort(conversions); - for (String conversion : conversions) { - buffer.append(conversion); - } + for (String conversion : conversions) { + buffer.append(conversion); + } - buffer.append("\nNew expression type changes:\n"); + buffer.append("\nNew expression type changes:\n"); - final String[] newChanges = new String[myNewExpressionTypeChange.size()]; - k = 0; + final String[] newChanges = new String[myNewExpressionTypeChange.size()]; + k = 0; - for (final Map.Entry entry : myNewExpressionTypeChange.entrySet()) { - final PsiElement element = entry.getKey().getElement(); - newChanges[k++] = (element != null ? element.getText() : entry.getKey()) + " -> " + entry.getValue().getCanonicalText() + "\n"; - } + for (final Map.Entry entry : myNewExpressionTypeChange.entrySet()) { + final PsiElement element = entry.getKey().getElement(); + newChanges[k++] = (element != null ? element.getText() : entry.getKey()) + " -> " + entry.getValue().getCanonicalText() + "\n"; + } - Arrays.sort(newChanges); + Arrays.sort(newChanges); - for (String change : newChanges) { - buffer.append(change); - } + for (String change : newChanges) { + buffer.append(change); + } - buffer.append("Fails:\n"); - - final ArrayList, PsiType>> failsList = new ArrayList<>(myFailedConversions.keySet()); - Collections.sort(failsList, (o1, o2) -> - { - final PsiElement element1 = o1.getFirst().getElement(); - final PsiElement element2 = o2.getFirst().getElement(); - if (element1 == null || element2 == null) { - return 0; - } - return element1.getText().compareTo(element2.getText()); - }); - - for (final Pair, PsiType> p : failsList) { - final PsiElement element = p.getFirst().getElement(); - if (element != null) { - buffer.append(element.getText()).append("->").append(p.getSecond().getCanonicalText()).append("\n"); - } - } + buffer.append("Fails:\n"); - return buffer.toString(); - } + final ArrayList, PsiType>> failsList = new ArrayList<>(myFailedConversions.keySet()); + Collections.sort(failsList, (o1, o2) -> + { + final PsiElement element1 = o1.getFirst().getElement(); + final PsiElement element2 = o2.getFirst().getElement(); + if (element1 == null || element2 == null) { + return 0; + } + return element1.getText().compareTo(element2.getText()); + }); + + for (final Pair, PsiType> p : failsList) { + final PsiElement element = p.getFirst().getElement(); + if (element != null) { + buffer.append(element.getText()).append("->").append(p.getSecond().getCanonicalText()).append("\n"); + } + } - public static class MigrateException extends RuntimeException { - } + return buffer.toString(); + } + + public static class MigrateException extends RuntimeException { + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/ConflictsUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/ConflictsUtil.java index 4e7db3f9d8..72dccf93f1 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/ConflictsUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/ConflictsUtil.java @@ -13,18 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * created at Oct 8, 2001 - * @author Jeka - */ package com.intellij.java.impl.refactoring.util; import com.intellij.java.indexing.search.searches.ClassInheritorsSearch; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiFormatUtil; import com.intellij.java.language.psi.util.PsiUtil; -import consulo.application.util.function.Processor; +import consulo.annotation.access.RequiredReadAction; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.ui.RefactoringUIUtil; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; @@ -37,101 +32,124 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +/** + * @author Jeka + * @since 2001-10-08 + */ public class ConflictsUtil { - private ConflictsUtil() { - } + private ConflictsUtil() { + } - @Nonnull - public static PsiElement getContainer(PsiElement place) { - PsiElement parent = place; - while (true) { - if (parent instanceof PsiMember && !(parent instanceof PsiTypeParameter)) { - return parent; - } - if (parent instanceof PsiFile) { - PsiElement host = FileContextUtil.getFileContext((PsiFile)parent); - if (host == null) { - return parent; + @Nonnull + public static PsiElement getContainer(PsiElement place) { + PsiElement parent = place; + while (true) { + if (parent instanceof PsiMember && !(parent instanceof PsiTypeParameter)) { + return parent; + } + if (parent instanceof PsiFile file) { + PsiElement host = FileContextUtil.getFileContext(file); + if (host == null) { + return file; + } + parent = host; + } + parent = parent.getParent(); } - parent = host; - } - parent = parent.getParent(); } - } - public static void checkMethodConflicts(@Nullable PsiClass aClass, - PsiMethod refactoredMethod, - final PsiMethod prototype, - final MultiMap conflicts) { - if (prototype == null) return; - final String protoMethodInfo = getMethodPrototypeString(prototype); + @RequiredReadAction + public static void checkMethodConflicts( + @Nullable PsiClass aClass, + PsiMethod refactoredMethod, + PsiMethod prototype, + MultiMap conflicts + ) { + if (prototype == null) { + return; + } + String protoMethodInfo = getMethodPrototypeString(prototype); - PsiMethod method = aClass != null ? aClass.findMethodBySignature(prototype, true) : null; + PsiMethod method = aClass != null ? aClass.findMethodBySignature(prototype, true) : null; - if (method != null && method != refactoredMethod) { - if (aClass.equals(method.getContainingClass())) { - final String classDescr = aClass instanceof PsiAnonymousClass ? - RefactoringLocalize.currentClass().get() : - RefactoringUIUtil.getDescription(aClass, false); - conflicts.putValue(method, RefactoringLocalize.method0IsAlreadyDefinedInThe1(getMethodPrototypeString(prototype), classDescr).get()); - } - else { // method somewhere in base class - if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, null)) { - String className = CommonRefactoringUtil.htmlEmphasize(DescriptiveNameUtil.getDescriptiveName(method.getContainingClass())); - if (PsiUtil.getAccessLevel(prototype.getModifierList()) >= PsiUtil.getAccessLevel(method.getModifierList()) ) { - boolean isMethodAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); - boolean isMyMethodAbstract = refactoredMethod != null && refactoredMethod.hasModifierProperty(PsiModifier.ABSTRACT); - final String conflict = isMethodAbstract != isMyMethodAbstract - ? RefactoringLocalize.method0WillImplementMethodOfTheBaseClass(protoMethodInfo, className).get() - : RefactoringLocalize.method0WillOverrideAMethodOfTheBaseClass(protoMethodInfo, className).get(); - conflicts.putValue(method, conflict); - } - else { // prototype is private, will be compile-error - conflicts.putValue(method, RefactoringLocalize.method0WillHideMethodOfTheBaseClass(protoMethodInfo, className).get()); - } + if (method != null && method != refactoredMethod) { + if (aClass.equals(method.getContainingClass())) { + String classDescr = aClass instanceof PsiAnonymousClass + ? RefactoringLocalize.currentClass().get() + : RefactoringUIUtil.getDescription(aClass, false); + conflicts.putValue( + method, + RefactoringLocalize.method0IsAlreadyDefinedInThe1(getMethodPrototypeString(prototype), classDescr) + ); + } + else { // method somewhere in base class + if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, null)) { + String className = + CommonRefactoringUtil.htmlEmphasize(DescriptiveNameUtil.getDescriptiveName(method.getContainingClass())); + if (PsiUtil.getAccessLevel(prototype.getModifierList()) >= PsiUtil.getAccessLevel(method.getModifierList())) { + boolean isMethodAbstract = method.isAbstract(); + boolean isMyMethodAbstract = refactoredMethod != null && refactoredMethod.isAbstract(); + LocalizeValue conflict = isMethodAbstract != isMyMethodAbstract + ? RefactoringLocalize.method0WillImplementMethodOfTheBaseClass(protoMethodInfo, className) + : RefactoringLocalize.method0WillOverrideAMethodOfTheBaseClass(protoMethodInfo, className); + conflicts.putValue(method, conflict); + } + else { // prototype is private, will be compile-error + conflicts.putValue( + method, + RefactoringLocalize.method0WillHideMethodOfTheBaseClass(protoMethodInfo, className) + ); + } + } + } } - } - } - if (aClass != null && prototype.hasModifierProperty(PsiModifier.PRIVATE)) { - ClassInheritorsSearch.search(aClass).forEach(new Processor() { - @Override - public boolean process(PsiClass aClass) { - final PsiMethod[] methods = aClass.findMethodsBySignature(prototype, false); - for (PsiMethod method : methods) { - conflicts.putValue(method, "Method " + RefactoringUIUtil.getDescription(method, true) + " will override method of the base class " + RefactoringUIUtil.getDescription(aClass, false)); - } - return true; + if (aClass != null && prototype.isPrivate()) { + ClassInheritorsSearch.search(aClass).forEach(aClass1 -> { + PsiMethod[] methods = aClass1.findMethodsBySignature(prototype, false); + for (PsiMethod method1 : methods) { + conflicts.putValue( + method1, + LocalizeValue.localizeTODO( + "Method " + RefactoringUIUtil.getDescription(method1, true) + + " will override method of the base class " + RefactoringUIUtil.getDescription(aClass1, false) + ) + ); + } + return true; + }); } - }); } - } - private static String getMethodPrototypeString(final PsiMethod prototype) { - return PsiFormatUtil.formatMethod( - prototype, - PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_TYPE - ); - } + private static String getMethodPrototypeString(PsiMethod prototype) { + return PsiFormatUtil.formatMethod( + prototype, + PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS, + PsiFormatUtil.SHOW_TYPE + ); + } - public static void checkFieldConflicts(@Nullable PsiClass aClass, String newName, final MultiMap conflicts) { - PsiField existingField = aClass != null ? aClass.findFieldByName(newName, true) : null; - if (existingField != null) { - if (aClass.equals(existingField.getContainingClass())) { - String className = aClass instanceof PsiAnonymousClass - ? RefactoringLocalize.currentClass().get() - : RefactoringUIUtil.getDescription(aClass, false); - final LocalizeValue conflict = RefactoringLocalize.field0IsAlreadyDefinedInThe1(existingField.getName(), className); - conflicts.putValue(existingField, conflict.get()); - } - else { // method somewhere in base class - if (!existingField.hasModifierProperty(PsiModifier.PRIVATE)) { - String fieldInfo = PsiFormatUtil.formatVariable(existingField, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER, PsiSubstitutor.EMPTY); - String className = RefactoringUIUtil.getDescription(existingField.getContainingClass(), false); - final LocalizeValue descr = RefactoringLocalize.field0WillHideField1OfTheBaseClass(newName, fieldInfo, className); - conflicts.putValue(existingField, descr.get()); + public static void checkFieldConflicts(@Nullable PsiClass aClass, String newName, MultiMap conflicts) { + PsiField existingField = aClass != null ? aClass.findFieldByName(newName, true) : null; + if (existingField != null) { + if (aClass.equals(existingField.getContainingClass())) { + String className = aClass instanceof PsiAnonymousClass + ? RefactoringLocalize.currentClass().get() + : RefactoringUIUtil.getDescription(aClass, false); + LocalizeValue conflict = RefactoringLocalize.field0IsAlreadyDefinedInThe1(existingField.getName(), className); + conflicts.putValue(existingField, conflict); + } + else { // method somewhere in base class + if (!existingField.isPrivate()) { + String fieldInfo = PsiFormatUtil.formatVariable( + existingField, + PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER, + PsiSubstitutor.EMPTY + ); + String className = RefactoringUIUtil.getDescription(existingField.getContainingClass(), false); + LocalizeValue descr = RefactoringLocalize.field0WillHideField1OfTheBaseClass(newName, fieldInfo, className); + conflicts.putValue(existingField, descr); + } + } } - } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/RefactoringConflictsUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/RefactoringConflictsUtil.java index 71d0158ba7..c831589eae 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/RefactoringConflictsUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/RefactoringConflictsUtil.java @@ -18,307 +18,349 @@ import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.util.VisibilityUtil; -import consulo.language.editor.refactoring.localize.RefactoringLocalize; -import consulo.localize.LocalizeValue; -import consulo.module.Module; import consulo.ide.impl.idea.openapi.module.ModuleUtil; -import consulo.project.Project; -import consulo.module.content.ModuleRootManager; -import consulo.module.content.ProjectRootManager; -import consulo.virtualFileSystem.VirtualFile; -import consulo.language.psi.*; +import consulo.language.editor.refactoring.localize.RefactoringLocalize; +import consulo.language.editor.refactoring.ui.RefactoringUIUtil; +import consulo.language.editor.refactoring.util.CommonRefactoringUtil; import consulo.language.impl.psi.LightElement; +import consulo.language.psi.*; import consulo.language.psi.scope.GlobalSearchScope; import consulo.language.psi.scope.PsiSearchScopeUtil; import consulo.language.psi.search.ReferencesSearch; import consulo.language.psi.util.PsiTreeUtil; -import consulo.language.psi.PsiUtilCore; -import consulo.language.editor.refactoring.RefactoringBundle; -import consulo.language.editor.refactoring.util.CommonRefactoringUtil; +import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; +import consulo.module.Module; +import consulo.module.content.ModuleRootManager; +import consulo.module.content.ProjectRootManager; +import consulo.project.Project; import consulo.usage.MoveRenameUsageInfo; -import consulo.language.editor.refactoring.ui.RefactoringUIUtil; import consulo.usage.UsageInfo; -import consulo.language.util.IncorrectOperationException; import consulo.util.collection.MultiMap; - +import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.util.Collection; import java.util.HashSet; import java.util.Set; /** * @author anna - * Date: 05-Oct-2009 + * @since 2009-10-05 */ public class RefactoringConflictsUtil { - private RefactoringConflictsUtil() { } - - public static void analyzeAccessibilityConflicts(@Nonnull Set membersToMove, - @Nonnull PsiClass targetClass, - @Nonnull MultiMap conflicts, - @Nullable String newVisibility) { - analyzeAccessibilityConflicts(membersToMove, targetClass, conflicts, newVisibility, targetClass, null); - } - - public static void analyzeAccessibilityConflicts(@Nonnull Set membersToMove, - @Nullable PsiClass targetClass, - @Nonnull MultiMap conflicts, - @Nullable String newVisibility, - @Nonnull PsiElement context, - @Nullable Set abstractMethods) { - if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { //Still need to check for access object - newVisibility = PsiModifier.PUBLIC; + private RefactoringConflictsUtil() { } - for (PsiMember member : membersToMove) { - checkUsedElements(member, member, membersToMove, abstractMethods, targetClass, context, conflicts); - checkAccessibilityConflicts(member, newVisibility, targetClass, membersToMove, conflicts); + public static void analyzeAccessibilityConflicts( + @Nonnull Set membersToMove, + @Nonnull PsiClass targetClass, + @Nonnull MultiMap conflicts, + @Nullable String newVisibility + ) { + analyzeAccessibilityConflicts(membersToMove, targetClass, conflicts, newVisibility, targetClass, null); } - } - public static void checkAccessibilityConflicts(@Nonnull PsiMember member, - @PsiModifier.ModifierConstant @Nullable String newVisibility, - @Nullable PsiClass targetClass, - @Nonnull Set membersToMove, - @Nonnull MultiMap conflicts) { - PsiModifierList modifierListCopy = member.getModifierList(); - if (modifierListCopy != null) { - modifierListCopy = (PsiModifierList)modifierListCopy.copy(); - final PsiClass containingClass = member.getContainingClass(); - if (containingClass != null && containingClass.isInterface()) { - VisibilityUtil.setVisibility(modifierListCopy, PsiModifier.PUBLIC); - } - } - if (newVisibility != null && modifierListCopy != null) { - try { - VisibilityUtil.setVisibility(modifierListCopy, newVisibility); - } - catch (IncorrectOperationException ignore) { } // do nothing and hope for the best + public static void analyzeAccessibilityConflicts( + @Nonnull Set membersToMove, + @Nullable PsiClass targetClass, + @Nonnull MultiMap conflicts, + @Nullable String newVisibility, + @Nonnull PsiElement context, + @Nullable Set abstractMethods + ) { + if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { //Still need to check for access object + newVisibility = PsiModifier.PUBLIC; + } + + for (PsiMember member : membersToMove) { + checkUsedElements(member, member, membersToMove, abstractMethods, targetClass, context, conflicts); + checkAccessibilityConflicts(member, newVisibility, targetClass, membersToMove, conflicts); + } } - checkAccessibilityConflicts(member, modifierListCopy, targetClass, membersToMove, conflicts); - } + public static void checkAccessibilityConflicts( + @Nonnull PsiMember member, + @PsiModifier.ModifierConstant @Nullable String newVisibility, + @Nullable PsiClass targetClass, + @Nonnull Set membersToMove, + @Nonnull MultiMap conflicts + ) { + PsiModifierList modifierListCopy = member.getModifierList(); + if (modifierListCopy != null) { + modifierListCopy = (PsiModifierList) modifierListCopy.copy(); + final PsiClass containingClass = member.getContainingClass(); + if (containingClass != null && containingClass.isInterface()) { + VisibilityUtil.setVisibility(modifierListCopy, PsiModifier.PUBLIC); + } + } + if (newVisibility != null && modifierListCopy != null) { + try { + VisibilityUtil.setVisibility(modifierListCopy, newVisibility); + } + catch (IncorrectOperationException ignore) { + } // do nothing and hope for the best + } - public static void checkAccessibilityConflicts(@Nonnull PsiMember member, - @Nullable PsiModifierList modifierListCopy, - @Nullable PsiClass targetClass, - @Nonnull Set membersToMove, - @Nonnull MultiMap conflicts) { - for (PsiReference psiReference : ReferencesSearch.search(member)) { - checkAccessibilityConflicts(psiReference, member, modifierListCopy, targetClass, membersToMove, conflicts); + checkAccessibilityConflicts(member, modifierListCopy, targetClass, membersToMove, conflicts); } - } - public static void checkAccessibilityConflicts(@Nonnull PsiReference reference, - @Nonnull PsiMember member, - @Nullable PsiModifierList modifierListCopy, - @Nullable PsiClass targetClass, - @Nonnull Set membersToMove, - @Nonnull MultiMap conflicts) { - JavaPsiFacade manager = JavaPsiFacade.getInstance(member.getProject()); - PsiElement ref = reference.getElement(); - if (!RefactoringHierarchyUtil.willBeInTargetClass(ref, membersToMove, targetClass, false)) { - // check for target class accessibility - if (targetClass != null && !manager.getResolveHelper().isAccessible(targetClass, targetClass.getModifierList(), ref, null, null)) { - LocalizeValue message = RefactoringLocalize.zeroIs1AndWillNotBeAccessibleFrom2InTheTargetClass( - RefactoringUIUtil.getDescription(targetClass, true), - VisibilityUtil.getVisibilityStringToDisplay(targetClass), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true) - ); - conflicts.putValue(targetClass, CommonRefactoringUtil.capitalize(message.get())); - } - // check for member accessibility - else if (!manager.getResolveHelper().isAccessible(member, modifierListCopy, ref, targetClass, null)) { - LocalizeValue message = RefactoringLocalize.zeroIs1AndWillNotBeAccessibleFrom2InTheTargetClass( - RefactoringUIUtil.getDescription(member, true), - VisibilityUtil.toPresentableText(VisibilityUtil.getVisibilityModifier(modifierListCopy)), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true) - ); - conflicts.putValue(member, CommonRefactoringUtil.capitalize(message.get())); - } + public static void checkAccessibilityConflicts( + @Nonnull PsiMember member, + @Nullable PsiModifierList modifierListCopy, + @Nullable PsiClass targetClass, + @Nonnull Set membersToMove, + @Nonnull MultiMap conflicts + ) { + for (PsiReference psiReference : ReferencesSearch.search(member)) { + checkAccessibilityConflicts(psiReference, member, modifierListCopy, targetClass, membersToMove, conflicts); + } } - } - public static void checkUsedElements(PsiMember member, - PsiElement scope, - @Nonnull Set membersToMove, - @Nullable Set abstractMethods, - @Nullable PsiClass targetClass, - @Nonnull PsiElement context, - MultiMap conflicts) { - final Set moving = new HashSet(membersToMove); - if (abstractMethods != null) { - moving.addAll(abstractMethods); - } - if (scope instanceof PsiReferenceExpression) { - PsiReferenceExpression refExpr = (PsiReferenceExpression)scope; - PsiElement refElement = refExpr.resolve(); - if (refElement instanceof PsiMember) { - if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) { - PsiExpression qualifier = refExpr.getQualifierExpression(); - PsiClass accessClass = (PsiClass)(qualifier != null ? PsiUtil.getAccessObjectClass(qualifier).getElement() : null); - checkAccessibility((PsiMember)refElement, context, accessClass, member, conflicts); + public static void checkAccessibilityConflicts( + @Nonnull PsiReference reference, + @Nonnull PsiMember member, + @Nullable PsiModifierList modifierListCopy, + @Nullable PsiClass targetClass, + @Nonnull Set membersToMove, + @Nonnull MultiMap conflicts + ) { + JavaPsiFacade manager = JavaPsiFacade.getInstance(member.getProject()); + PsiElement ref = reference.getElement(); + if (!RefactoringHierarchyUtil.willBeInTargetClass(ref, membersToMove, targetClass, false)) { + // check for target class accessibility + if (targetClass != null && !manager.getResolveHelper() + .isAccessible(targetClass, targetClass.getModifierList(), ref, null, null)) { + LocalizeValue message = RefactoringLocalize.zeroIs1AndWillNotBeAccessibleFrom2InTheTargetClass( + RefactoringUIUtil.getDescription(targetClass, true), + VisibilityUtil.getVisibilityStringToDisplay(targetClass), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true) + ); + conflicts.putValue(targetClass, message.capitalize()); + } + // check for member accessibility + else if (!manager.getResolveHelper().isAccessible(member, modifierListCopy, ref, targetClass, null)) { + LocalizeValue message = RefactoringLocalize.zeroIs1AndWillNotBeAccessibleFrom2InTheTargetClass( + RefactoringUIUtil.getDescription(member, true), + VisibilityUtil.toPresentableText(VisibilityUtil.getVisibilityModifier(modifierListCopy)), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true) + ); + conflicts.putValue(member, message.capitalize()); + } } - } } - else if (scope instanceof PsiNewExpression) { - final PsiNewExpression newExpression = (PsiNewExpression)scope; - final PsiAnonymousClass anonymousClass = newExpression.getAnonymousClass(); - if (anonymousClass != null) { - if (!RefactoringHierarchyUtil.willBeInTargetClass(anonymousClass, moving, targetClass, false)) { - checkAccessibility(anonymousClass, context, anonymousClass, member, conflicts); + + public static void checkUsedElements( + PsiMember member, + PsiElement scope, + @Nonnull Set membersToMove, + @Nullable Set abstractMethods, + @Nullable PsiClass targetClass, + @Nonnull PsiElement context, + MultiMap conflicts + ) { + final Set moving = new HashSet(membersToMove); + if (abstractMethods != null) { + moving.addAll(abstractMethods); } - } - else { - final PsiMethod refElement = newExpression.resolveConstructor(); - if (refElement != null) { - if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) { - checkAccessibility(refElement, context, null, member, conflicts); - } + if (scope instanceof PsiReferenceExpression) { + PsiReferenceExpression refExpr = (PsiReferenceExpression) scope; + PsiElement refElement = refExpr.resolve(); + if (refElement instanceof PsiMember) { + if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) { + PsiExpression qualifier = refExpr.getQualifierExpression(); + PsiClass accessClass = (PsiClass) (qualifier != null ? PsiUtil.getAccessObjectClass(qualifier).getElement() : null); + checkAccessibility((PsiMember) refElement, context, accessClass, member, conflicts); + } + } } - } - } - else if (scope instanceof PsiJavaCodeReferenceElement) { - PsiJavaCodeReferenceElement refExpr = (PsiJavaCodeReferenceElement)scope; - PsiElement refElement = refExpr.resolve(); - if (refElement instanceof PsiMember) { - if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) { - checkAccessibility((PsiMember)refElement, context, null, member, conflicts); + else if (scope instanceof PsiNewExpression) { + final PsiNewExpression newExpression = (PsiNewExpression) scope; + final PsiAnonymousClass anonymousClass = newExpression.getAnonymousClass(); + if (anonymousClass != null) { + if (!RefactoringHierarchyUtil.willBeInTargetClass(anonymousClass, moving, targetClass, false)) { + checkAccessibility(anonymousClass, context, anonymousClass, member, conflicts); + } + } + else { + final PsiMethod refElement = newExpression.resolveConstructor(); + if (refElement != null) { + if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) { + checkAccessibility(refElement, context, null, member, conflicts); + } + } + } + } + else if (scope instanceof PsiJavaCodeReferenceElement) { + PsiJavaCodeReferenceElement refExpr = (PsiJavaCodeReferenceElement) scope; + PsiElement refElement = refExpr.resolve(); + if (refElement instanceof PsiMember) { + if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) { + checkAccessibility((PsiMember) refElement, context, null, member, conflicts); + } + } } - } - } - for (PsiElement child : scope.getChildren()) { - if (child instanceof PsiWhiteSpace || child instanceof PsiComment) continue; - checkUsedElements(member, child, membersToMove, abstractMethods, targetClass, context, conflicts); + for (PsiElement child : scope.getChildren()) { + if (child instanceof PsiWhiteSpace || child instanceof PsiComment) { + continue; + } + checkUsedElements(member, child, membersToMove, abstractMethods, targetClass, context, conflicts); + } } - } - public static void checkAccessibility(PsiMember refMember, - @Nonnull PsiElement newContext, - @Nullable PsiClass accessClass, - PsiMember member, - MultiMap conflicts) { - if (!PsiUtil.isAccessible(refMember, newContext, accessClass)) { - LocalizeValue message = RefactoringLocalize.zeroIs1AndWillNotBeAccessibleFrom2InTheTargetClass( - RefactoringUIUtil.getDescription(refMember, true), - VisibilityUtil.getVisibilityStringToDisplay(refMember), - RefactoringUIUtil.getDescription(member, false) - ); - conflicts.putValue(refMember, CommonRefactoringUtil.capitalize(message.get())); - } - else if (newContext instanceof PsiClass && refMember instanceof PsiField && refMember.getContainingClass() == member.getContainingClass()) { - final PsiField fieldInSubClass = ((PsiClass)newContext).findFieldByName(refMember.getName(), false); - if (fieldInSubClass != null && fieldInSubClass != refMember) { - conflicts.putValue(refMember, CommonRefactoringUtil.capitalize(RefactoringUIUtil.getDescription(fieldInSubClass, true) + - " would hide " + RefactoringUIUtil.getDescription(refMember, true) + - " which is used by moved " + RefactoringUIUtil.getDescription(member, false))); - } + public static void checkAccessibility( + PsiMember refMember, + @Nonnull PsiElement newContext, + @Nullable PsiClass accessClass, + PsiMember member, + MultiMap conflicts + ) { + if (!PsiUtil.isAccessible(refMember, newContext, accessClass)) { + LocalizeValue message = RefactoringLocalize.zeroIs1AndWillNotBeAccessibleFrom2InTheTargetClass( + RefactoringUIUtil.getDescription(refMember, true), + VisibilityUtil.getVisibilityStringToDisplay(refMember), + RefactoringUIUtil.getDescription(member, false) + ); + conflicts.putValue(refMember, message.capitalize()); + } + else if (newContext instanceof PsiClass && refMember instanceof PsiField && refMember.getContainingClass() == member.getContainingClass()) { + final PsiField fieldInSubClass = ((PsiClass) newContext).findFieldByName(refMember.getName(), false); + if (fieldInSubClass != null && fieldInSubClass != refMember) { + conflicts.putValue( + refMember, + LocalizeValue.localizeTODO(CommonRefactoringUtil.capitalize( + RefactoringUIUtil.getDescription(fieldInSubClass, true) + + " would hide " + RefactoringUIUtil.getDescription(refMember, true) + + " which is used by moved " + RefactoringUIUtil.getDescription(member, false) + )) + ); + } + } } - } - - public static void analyzeModuleConflicts(final Project project, - final Collection scopes, - final UsageInfo[] usages, - final PsiElement target, - final MultiMap conflicts) { - if (scopes == null) return; - final VirtualFile vFile = PsiUtilCore.getVirtualFile(target); - if (vFile == null) return; - analyzeModuleConflicts(project, scopes, usages, vFile, conflicts); - } + public static void analyzeModuleConflicts( + final Project project, + final Collection scopes, + final UsageInfo[] usages, + final PsiElement target, + final MultiMap conflicts + ) { + if (scopes == null) { + return; + } + final VirtualFile vFile = PsiUtilCore.getVirtualFile(target); + if (vFile == null) { + return; + } - public static void analyzeModuleConflicts(final Project project, - final Collection scopes, - final UsageInfo[] usages, - final VirtualFile vFile, - final MultiMap conflicts) { - if (scopes == null) return; - for (final PsiElement scope : scopes) { - if (scope instanceof PsiJavaPackage) return; + analyzeModuleConflicts(project, scopes, usages, vFile, conflicts); } - final Module targetModule = ModuleUtil.findModuleForFile(vFile, project); - if (targetModule == null) return; - final GlobalSearchScope resolveScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(targetModule); - final HashSet reported = new HashSet(); - for (final PsiElement scope : scopes) { - scope.accept(new JavaRecursiveElementVisitor() { - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - super.visitReferenceElement(reference); - final PsiElement resolved = reference.resolve(); - if (resolved != null && - !reported.contains(resolved) && - !CommonRefactoringUtil.isAncestor(resolved, scopes) && - !PsiSearchScopeUtil.isInScope(resolveScope, resolved) && - !(resolved instanceof LightElement)) { - final String scopeDescription = RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true); - final LocalizeValue message = RefactoringLocalize.zeroReferencedIn1WillNotBeAccessibleInModule2( - RefactoringUIUtil.getDescription(resolved, true), - scopeDescription, - CommonRefactoringUtil.htmlEmphasize(targetModule.getName()) - ); - conflicts.putValue(resolved, CommonRefactoringUtil.capitalize(message.get())); - reported.add(resolved); - } + public static void analyzeModuleConflicts( + final Project project, + final Collection scopes, + final UsageInfo[] usages, + final VirtualFile vFile, + final MultiMap conflicts + ) { + if (scopes == null) { + return; + } + for (final PsiElement scope : scopes) { + if (scope instanceof PsiJavaPackage) { + return; + } } - }); - } - - boolean isInTestSources = ModuleRootManager.getInstance(targetModule).getFileIndex().isInTestSourceContent(vFile); - NextUsage: - for (UsageInfo usage : usages) { - final PsiElement element = usage.getElement(); - if (element != null && PsiTreeUtil.getParentOfType(element, PsiImportStatement.class, false) == null) { - for (PsiElement scope : scopes) { - if (PsiTreeUtil.isAncestor(scope, element, false)) continue NextUsage; + final Module targetModule = ModuleUtil.findModuleForFile(vFile, project); + if (targetModule == null) { + return; } + final GlobalSearchScope resolveScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(targetModule); + final HashSet reported = new HashSet(); + for (final PsiElement scope : scopes) { + scope.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + super.visitReferenceElement(reference); + final PsiElement resolved = reference.resolve(); + if (resolved != null && + !reported.contains(resolved) && + !CommonRefactoringUtil.isAncestor(resolved, scopes) && + !PsiSearchScopeUtil.isInScope(resolveScope, resolved) && + !(resolved instanceof LightElement)) { + final String scopeDescription = RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true); + final LocalizeValue message = RefactoringLocalize.zeroReferencedIn1WillNotBeAccessibleInModule2( + RefactoringUIUtil.getDescription(resolved, true), + scopeDescription, + CommonRefactoringUtil.htmlEmphasize(targetModule.getName()) + ); + conflicts.putValue(resolved, message.capitalize()); + reported.add(resolved); + } + } + }); + } + + boolean isInTestSources = ModuleRootManager.getInstance(targetModule).getFileIndex().isInTestSourceContent(vFile); + NextUsage: + for (UsageInfo usage : usages) { + final PsiElement element = usage.getElement(); + if (element != null && PsiTreeUtil.getParentOfType(element, PsiImportStatement.class, false) == null) { + + for (PsiElement scope : scopes) { + if (PsiTreeUtil.isAncestor(scope, element, false)) { + continue NextUsage; + } + } - final GlobalSearchScope resolveScope1 = element.getResolveScope(); - if (!resolveScope1.isSearchInModuleContent(targetModule, isInTestSources)) { - final PsiFile usageFile = element.getContainingFile(); - PsiElement container; - if (usageFile instanceof PsiJavaFile) { - container = ConflictsUtil.getContainer(element); - } - else { - container = usageFile; - } - final String scopeDescription = RefactoringUIUtil.getDescription(container, true); - final VirtualFile usageVFile = usageFile.getVirtualFile(); - if (usageVFile != null) { - Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(usageVFile); - if (module != null) { - final String message; - final PsiElement referencedElement; - if (usage instanceof MoveRenameUsageInfo) { - referencedElement = ((MoveRenameUsageInfo)usage).getReferencedElement(); - } - else { - referencedElement = usage.getElement(); - } - assert referencedElement != null : usage; - String description = RefactoringUIUtil.getDescription(referencedElement, true); - String emphasizedName = CommonRefactoringUtil.htmlEmphasize(module.getName()); - if (module == targetModule && isInTestSources) { - message = RefactoringLocalize.zeroReferencedIn1WillNotBeAccessibleFromProductionOfModule2(description, scopeDescription, emphasizedName - ).get(); - } - else { - message = RefactoringLocalize.zeroReferencedIn1WillNotBeAccessibleFromModule2( - description, - scopeDescription, - emphasizedName - ).get(); - } - conflicts.putValue(referencedElement, CommonRefactoringUtil.capitalize(message)); + final GlobalSearchScope resolveScope1 = element.getResolveScope(); + if (!resolveScope1.isSearchInModuleContent(targetModule, isInTestSources)) { + final PsiFile usageFile = element.getContainingFile(); + PsiElement container; + if (usageFile instanceof PsiJavaFile) { + container = ConflictsUtil.getContainer(element); + } + else { + container = usageFile; + } + final String scopeDescription = RefactoringUIUtil.getDescription(container, true); + final VirtualFile usageVFile = usageFile.getVirtualFile(); + if (usageVFile != null) { + Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(usageVFile); + if (module != null) { + LocalizeValue message; + final PsiElement referencedElement; + if (usage instanceof MoveRenameUsageInfo) { + referencedElement = ((MoveRenameUsageInfo) usage).getReferencedElement(); + } + else { + referencedElement = usage.getElement(); + } + assert referencedElement != null : usage; + String description = RefactoringUIUtil.getDescription(referencedElement, true); + String emphasizedName = CommonRefactoringUtil.htmlEmphasize(module.getName()); + if (module == targetModule && isInTestSources) { + message = RefactoringLocalize.zeroReferencedIn1WillNotBeAccessibleFromProductionOfModule2( + description, + scopeDescription, + emphasizedName + ); + } + else { + message = RefactoringLocalize.zeroReferencedIn1WillNotBeAccessibleFromModule2( + description, + scopeDescription, + emphasizedName + ); + } + conflicts.putValue(referencedElement, message.capitalize()); + } + } + } } - } } - } } - } }