diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectHandler.java index 7c68a4de5..45e1f8e3a 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectHandler.java @@ -24,14 +24,12 @@ import com.intellij.java.impl.refactoring.extractMethod.ExtractMethodHandler; import com.intellij.java.impl.refactoring.extractMethod.PrepareFailedException; import com.intellij.java.impl.refactoring.util.duplicates.DuplicatesImpl; -import consulo.application.ApplicationManager; import consulo.codeEditor.Editor; import consulo.codeEditor.ScrollType; import consulo.dataContext.DataContext; import consulo.document.RangeMarker; import consulo.document.util.TextRange; import consulo.language.codeStyle.PostprocessReformattingAspect; -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; @@ -42,98 +40,116 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.undoRedo.CommandProcessor; - import jakarta.annotation.Nonnull; + import java.util.function.Consumer; public class ExtractMethodObjectHandler implements RefactoringActionHandler { - private static final Logger LOG = Logger.getInstance(ExtractMethodObjectHandler.class); - - public void invoke(@Nonnull final Project project, final Editor editor, final PsiFile file, final DataContext dataContext) { - ExtractMethodHandler.selectAndPass(project, editor, file, new Consumer() { - public void accept(final PsiElement[] selectedValue) { - invokeOnElements(project, editor, file, selectedValue); - } - }); - } + private static final Logger LOG = Logger.getInstance(ExtractMethodObjectHandler.class); - private void invokeOnElements(@Nonnull final Project project, @Nonnull final Editor editor, @Nonnull PsiFile file, @Nonnull PsiElement[] elements) { - if (elements.length == 0) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.selectedBlockShouldRepresentASetOfStatementsOrAnExpression() - ); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), ExtractMethodObjectProcessor.REFACTORING_NAME, HelpID.EXTRACT_METHOD_OBJECT); - return; - } - - final ExtractMethodObjectProcessor processor = new ExtractMethodObjectProcessor(project, editor, elements, ""); - final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor(); - try { - if (!extractProcessor.prepare()) return; - } catch (PrepareFailedException e) { - CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), ExtractMethodObjectProcessor.REFACTORING_NAME, HelpID.EXTRACT_METHOD_OBJECT); - ExtractMethodHandler.highlightPrepareError(e, file, editor, project); - return; + public void invoke(@Nonnull final Project project, final Editor editor, final PsiFile file, final DataContext dataContext) { + ExtractMethodHandler.selectAndPass(project, editor, file, new Consumer() { + public void accept(final PsiElement[] selectedValue) { + invokeOnElements(project, editor, file, selectedValue); + } + }); } - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, extractProcessor.getTargetClass().getContainingFile())) - return; - if (extractProcessor.showDialog()) { - run(project, editor, processor, extractProcessor); - } - } + @RequiredUIAccess + private void invokeOnElements( + @Nonnull final Project project, + @Nonnull final Editor editor, + @Nonnull PsiFile file, + @Nonnull PsiElement[] elements + ) { + if (elements.length == 0) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.selectedBlockShouldRepresentASetOfStatementsOrAnExpression() + ); + CommonRefactoringUtil.showErrorHint( + project, + editor, + message, + ExtractMethodObjectProcessor.REFACTORING_NAME, + HelpID.EXTRACT_METHOD_OBJECT + ); + return; + } - public static void run(@Nonnull final Project project, - @Nonnull final Editor editor, - @Nonnull final ExtractMethodObjectProcessor processor, - @Nonnull final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor) { - final int offset = editor.getCaretModel().getOffset(); - final RangeMarker marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset)); - CommandProcessor.getInstance().executeCommand(project, new Runnable() { - public void run() { - PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable() { - public void run() { - try { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - extractProcessor.doRefactoring(); - } - }); - processor.run(); - processor.runChangeSignature(); - } catch (IncorrectOperationException e) { - LOG.error(e); + final ExtractMethodObjectProcessor processor = new ExtractMethodObjectProcessor(project, editor, elements, ""); + final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor(); + try { + if (!extractProcessor.prepare()) { + return; } - } - }); + } + catch (PrepareFailedException e) { + CommonRefactoringUtil.showErrorHint( + project, + editor, + LocalizeValue.ofNullable(e.getMessage()), + ExtractMethodObjectProcessor.REFACTORING_NAME, + HelpID.EXTRACT_METHOD_OBJECT + ); + ExtractMethodHandler.highlightPrepareError(e, file, editor, project); + return; + } - PsiDocumentManager.getInstance(project).commitAllDocuments(); - if (processor.isCreateInnerClass()) { - processor.moveUsedMethodsToInner(); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - DuplicatesImpl.processDuplicates(extractProcessor, project, editor); + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, extractProcessor.getTargetClass().getContainingFile())) { + return; } - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - if (processor.isCreateInnerClass()) { - processor.changeInstanceAccess(project); - } - final PsiElement method = processor.getMethod(); - LOG.assertTrue(method != null); - method.delete(); - } - }); - } - }, ExtractMethodObjectProcessor.REFACTORING_NAME, ExtractMethodObjectProcessor.REFACTORING_NAME); - editor.getCaretModel().moveToOffset(marker.getStartOffset()); - marker.dispose(); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - } + if (extractProcessor.showDialog()) { + run(project, editor, processor, extractProcessor); + } + } - public void invoke(@Nonnull final Project project, @Nonnull final PsiElement[] elements, final DataContext dataContext) { - throw new UnsupportedOperationException(); - } + public static void run( + @Nonnull final Project project, + @Nonnull final Editor editor, + @Nonnull final ExtractMethodObjectProcessor processor, + @Nonnull final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor + ) { + final int offset = editor.getCaretModel().getOffset(); + final RangeMarker marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset)); + CommandProcessor.getInstance().newCommand() + .project(project) + .name(ExtractMethodObjectProcessor.REFACTORING_NAME) + .groupId(ExtractMethodObjectProcessor.REFACTORING_NAME) + .run(() -> { + PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(() -> { + try { + project.getApplication().runWriteAction(() -> extractProcessor.doRefactoring()); + processor.run(); + processor.runChangeSignature(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + }); + + PsiDocumentManager.getInstance(project).commitAllDocuments(); + if (processor.isCreateInnerClass()) { + processor.moveUsedMethodsToInner(); + PsiDocumentManager.getInstance(project).commitAllDocuments(); + DuplicatesImpl.processDuplicates(extractProcessor, project, editor); + } + project.getApplication().runWriteAction(() -> { + if (processor.isCreateInnerClass()) { + processor.changeInstanceAccess(project); + } + PsiElement method = processor.getMethod(); + LOG.assertTrue(method != null); + method.delete(); + }); + }); + editor.getCaretModel().moveToOffset(marker.getStartOffset()); + marker.dispose(); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + } + + public void invoke(@Nonnull final Project project, @Nonnull final PsiElement[] elements, final DataContext dataContext) { + throw new UnsupportedOperationException(); + } } \ No newline at end of file diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java index f2c679b49..d4478a60d 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java @@ -51,6 +51,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.ex.awt.DialogWrapper; @@ -63,776 +64,876 @@ import org.jetbrains.annotations.NonNls; import jakarta.annotation.Nonnull; + import javax.swing.*; import java.util.*; import java.util.function.Function; public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(ExtractMethodObjectProcessor.class); - @NonNls - public static final String REFACTORING_NAME = "Extract Method Object"; - - private final PsiElementFactory myElementFactory; - - protected final MyExtractMethodProcessor myExtractProcessor; - private boolean myCreateInnerClass = true; - private String myInnerClassName; - - private boolean myMultipleExitPoints; - private PsiField[] myOutputFields; - - private PsiMethod myInnerMethod; - private boolean myMadeStatic = false; - private final Set myUsages = new LinkedHashSet(); - private PsiClass myInnerClass; - private boolean myChangeReturnType; - private Runnable myCopyMethodToInner; - - public ExtractMethodObjectProcessor(Project project, Editor editor, PsiElement[] elements, final String innerClassName) { - super(project); - myInnerClassName = innerClassName; - myExtractProcessor = new MyExtractMethodProcessor(project, editor, elements, null, REFACTORING_NAME, innerClassName, HelpID.EXTRACT_METHOD_OBJECT); - myElementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull final UsageInfo[] usages) { - return new ExtractMethodObjectViewDescriptor(getMethod()); - } - - @Nonnull - protected UsageInfo[] findUsages() { - final ArrayList result = new ArrayList(); - final PsiClass containingClass = getMethod().getContainingClass(); - final SearchScope scope = PsiUtilCore.getVirtualFile(containingClass) == null ? new LocalSearchScope(containingClass) : GlobalSearchScope.projectScope(myProject); - PsiReference[] refs = ReferencesSearch.search(getMethod(), scope, false).toArray(PsiReference.EMPTY_ARRAY); - for (PsiReference ref : refs) { - final PsiElement element = ref.getElement(); - if (element != null && element.isValid()) { - result.add(new UsageInfo(element)); - } + private static final Logger LOG = Logger.getInstance(ExtractMethodObjectProcessor.class); + public static final LocalizeValue REFACTORING_NAME = LocalizeValue.localizeTODO("Extract Method Object"); + + private final PsiElementFactory myElementFactory; + + protected final MyExtractMethodProcessor myExtractProcessor; + private boolean myCreateInnerClass = true; + private String myInnerClassName; + + private boolean myMultipleExitPoints; + private PsiField[] myOutputFields; + + private PsiMethod myInnerMethod; + private boolean myMadeStatic = false; + private final Set myUsages = new LinkedHashSet<>(); + private PsiClass myInnerClass; + private boolean myChangeReturnType; + private Runnable myCopyMethodToInner; + + public ExtractMethodObjectProcessor(Project project, Editor editor, PsiElement[] elements, final String innerClassName) { + super(project); + myInnerClassName = innerClassName; + myExtractProcessor = new MyExtractMethodProcessor( + project, + editor, + elements, + null, + REFACTORING_NAME.get(), + innerClassName, + HelpID.EXTRACT_METHOD_OBJECT + ); + myElementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); } - if (isCreateInnerClass()) { - final Set usedMethods = new LinkedHashSet(); - getMethod().accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - super.visitMethodCallExpression(expression); - final PsiMethod method = expression.resolveMethod(); - if (method != null) { - usedMethods.add(method); - } - } - }); - - - for (PsiMethod usedMethod : usedMethods) { - if (usedMethod.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) { - PsiMethod toMove = usedMethod; - for (PsiReference reference : ReferencesSearch.search(usedMethod)) { - if (!PsiTreeUtil.isAncestor(getMethod(), reference.getElement(), false)) { - toMove = null; - break; - } - } - if (toMove != null) { - myUsages.add(new MethodToMoveUsageInfo(toMove)); - } - } - } + + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull final UsageInfo[] usages) { + return new ExtractMethodObjectViewDescriptor(getMethod()); } - UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); - return UsageViewUtil.removeDuplicatedUsages(usageInfos); - } - - public void performRefactoring(@Nonnull final UsageInfo[] usages) { - try { - if (isCreateInnerClass()) { - myInnerClass = (PsiClass) getMethod().getContainingClass().add(myElementFactory.createClass(getInnerClassName())); - final boolean isStatic = copyMethodModifiers() && notHasGeneratedFields(); - for (UsageInfo usage : usages) { - final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class); - if (methodCallExpression != null) { - replaceMethodCallExpression(inferTypeArguments(methodCallExpression), methodCallExpression); - } + + @Nonnull + protected UsageInfo[] findUsages() { + final ArrayList result = new ArrayList(); + final PsiClass containingClass = getMethod().getContainingClass(); + final SearchScope scope = + PsiUtilCore.getVirtualFile(containingClass) == null ? new LocalSearchScope(containingClass) : GlobalSearchScope.projectScope( + myProject); + PsiReference[] refs = ReferencesSearch.search(getMethod(), scope, false).toArray(PsiReference.EMPTY_ARRAY); + for (PsiReference ref : refs) { + final PsiElement element = ref.getElement(); + if (element != null && element.isValid()) { + result.add(new UsageInfo(element)); + } + } + if (isCreateInnerClass()) { + final Set usedMethods = new LinkedHashSet(); + getMethod().accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiMethod method = expression.resolveMethod(); + if (method != null) { + usedMethods.add(method); + } + } + }); + + + for (PsiMethod usedMethod : usedMethods) { + if (usedMethod.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) { + PsiMethod toMove = usedMethod; + for (PsiReference reference : ReferencesSearch.search(usedMethod)) { + if (!PsiTreeUtil.isAncestor(getMethod(), reference.getElement(), false)) { + toMove = null; + break; + } + } + if (toMove != null) { + myUsages.add(new MethodToMoveUsageInfo(toMove)); + } + } + } } + UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); + return UsageViewUtil.removeDuplicatedUsages(usageInfos); + } - if (myExtractProcessor.generatesConditionalExit()) { - myInnerClass.add(myElementFactory.createField("myResult", PsiPrimitiveType.BOOLEAN)); - myInnerClass.add(myElementFactory.createMethodFromText("boolean is(){return myResult;}", myInnerClass)); - } - - final PsiParameter[] parameters = getMethod().getParameterList().getParameters(); - if (parameters.length > 0) { - createInnerClassConstructor(parameters); - } else if (isStatic) { - final PsiMethod copy = (PsiMethod) getMethod().copy(); - copy.setName("invoke"); - myInnerClass.add(copy); - if (myMultipleExitPoints) { - addOutputVariableFieldsWithGetters(); - } - return; - } - if (myMultipleExitPoints) { - addOutputVariableFieldsWithGetters(); - } - myCopyMethodToInner = new Runnable() { - public void run() { - copyMethodWithoutParameters(); - copyMethodTypeParameters(); - } - }; - } else { - for (UsageInfo usage : usages) { - final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class); - if (methodCallExpression != null) { - methodCallExpression.replace(processMethodDeclaration(methodCallExpression.getArgumentList())); - } - } - } - } catch (IncorrectOperationException e) { - LOG.error(e); + public void performRefactoring(@Nonnull final UsageInfo[] usages) { + try { + if (isCreateInnerClass()) { + myInnerClass = (PsiClass) getMethod().getContainingClass().add(myElementFactory.createClass(getInnerClassName())); + final boolean isStatic = copyMethodModifiers() && notHasGeneratedFields(); + for (UsageInfo usage : usages) { + final PsiMethodCallExpression methodCallExpression = + PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class); + if (methodCallExpression != null) { + replaceMethodCallExpression(inferTypeArguments(methodCallExpression), methodCallExpression); + } + } + + if (myExtractProcessor.generatesConditionalExit()) { + myInnerClass.add(myElementFactory.createField("myResult", PsiPrimitiveType.BOOLEAN)); + myInnerClass.add(myElementFactory.createMethodFromText("boolean is(){return myResult;}", myInnerClass)); + } + + final PsiParameter[] parameters = getMethod().getParameterList().getParameters(); + if (parameters.length > 0) { + createInnerClassConstructor(parameters); + } + else if (isStatic) { + final PsiMethod copy = (PsiMethod) getMethod().copy(); + copy.setName("invoke"); + myInnerClass.add(copy); + if (myMultipleExitPoints) { + addOutputVariableFieldsWithGetters(); + } + return; + } + if (myMultipleExitPoints) { + addOutputVariableFieldsWithGetters(); + } + myCopyMethodToInner = new Runnable() { + public void run() { + copyMethodWithoutParameters(); + copyMethodTypeParameters(); + } + }; + } + else { + for (UsageInfo usage : usages) { + final PsiMethodCallExpression methodCallExpression = + PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class); + if (methodCallExpression != null) { + methodCallExpression.replace(processMethodDeclaration(methodCallExpression.getArgumentList())); + } + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - } - void moveUsedMethodsToInner() { - if (!myUsages.isEmpty()) { - if (ApplicationManager.getApplication().isUnitTestMode()) { - for (MethodToMoveUsageInfo usage : myUsages) { - final PsiMember member = (PsiMember) usage.getElement(); - LOG.assertTrue(member != null); - myInnerClass.add(member.copy()); - member.delete(); + void moveUsedMethodsToInner() { + if (!myUsages.isEmpty()) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + for (MethodToMoveUsageInfo usage : myUsages) { + final PsiMember member = (PsiMember) usage.getElement(); + LOG.assertTrue(member != null); + myInnerClass.add(member.copy()); + member.delete(); + } + return; + } + final List memberInfos = new ArrayList(); + for (MethodToMoveUsageInfo usage : myUsages) { + memberInfos.add(new MemberInfo((PsiMethod) usage.getElement())); + } + + final MemberSelectionPanel panel = new MemberSelectionPanel("&Methods to move to the extracted class", memberInfos, null); + DialogWrapper dlg = new DialogWrapper(myProject, false) { + { + init(); + setTitle("Move Methods Used in Extracted Block Only"); + } + + + @Override + protected JComponent createCenterPanel() { + return panel; + } + }; + if (dlg.showAndGet()) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + for (MemberInfoBase memberInfo : panel.getTable().getSelectedMemberInfos()) { + if (memberInfo.isChecked()) { + myInnerClass.add(memberInfo.getMember().copy()); + memberInfo.getMember().delete(); + } + } + } + }); + } } - return; - } - final List memberInfos = new ArrayList(); - for (MethodToMoveUsageInfo usage : myUsages) { - memberInfos.add(new MemberInfo((PsiMethod) usage.getElement())); - } + } - final MemberSelectionPanel panel = new MemberSelectionPanel("&Methods to move to the extracted class", memberInfos, null); - DialogWrapper dlg = new DialogWrapper(myProject, false) { - { - init(); - setTitle("Move Methods Used in Extracted Block Only"); + private void addOutputVariableFieldsWithGetters() throws IncorrectOperationException { + final Map var2FieldNames = new HashMap(); + final PsiVariable[] outputVariables = myExtractProcessor.getOutputVariables(); + for (int i = 0; i < outputVariables.length; i++) { + final PsiVariable var = outputVariables[i]; + final PsiField outputField = myOutputFields[i]; + final String name = getPureName(var); + LOG.assertTrue(name != null); + final PsiField field; + if (outputField != null) { + var2FieldNames.put(var.getName(), outputField.getName()); + myInnerClass.add(outputField); + field = outputField; + } + else { + field = PropertyUtil.findPropertyField(myInnerClass, name, false); + } + LOG.assertTrue( + field != null, + "i:" + i + "; output variables: " + Arrays.toString(outputVariables) + "; parameters: " + Arrays.toString(getMethod().getParameterList() + .getParameters()) + + "; output field: " + outputField + ); + myInnerClass.add(GenerateMembersUtil.generateGetterPrototype(field)); } + final PsiCodeBlock body = getMethod().getBody(); + LOG.assertTrue(body != null); + final LinkedHashSet vars = new LinkedHashSet(); + final Map replacementMap = new LinkedHashMap(); + final List returnStatements = new ArrayList(); + body.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReturnStatement(PsiReturnStatement statement) { + returnStatements.add(statement); + } - @Override - protected JComponent createCenterPanel() { - return panel; - } - }; - if (dlg.showAndGet()) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - for (MemberInfoBase memberInfo : panel.getTable().getSelectedMemberInfos()) { - if (memberInfo.isChecked()) { - myInnerClass.add(memberInfo.getMember().copy()); - memberInfo.getMember().delete(); - } - } - } + @Override + public void visitClass(PsiClass aClass) { + } + + @Override + public void visitLambdaExpression(PsiLambdaExpression expression) { + } }); - } - } - } - - private void addOutputVariableFieldsWithGetters() throws IncorrectOperationException { - final Map var2FieldNames = new HashMap(); - final PsiVariable[] outputVariables = myExtractProcessor.getOutputVariables(); - for (int i = 0; i < outputVariables.length; i++) { - final PsiVariable var = outputVariables[i]; - final PsiField outputField = myOutputFields[i]; - final String name = getPureName(var); - LOG.assertTrue(name != null); - final PsiField field; - if (outputField != null) { - var2FieldNames.put(var.getName(), outputField.getName()); - myInnerClass.add(outputField); - field = outputField; - } else { - field = PropertyUtil.findPropertyField(myInnerClass, name, false); - } - LOG.assertTrue(field != null, "i:" + i + "; output variables: " + Arrays.toString(outputVariables) + "; parameters: " + Arrays.toString(getMethod().getParameterList().getParameters()) + - "; output field: " + outputField); - myInnerClass.add(GenerateMembersUtil.generateGetterPrototype(field)); - } + if (myExtractProcessor.generatesConditionalExit()) { + for (int i = 0; i < returnStatements.size() - 1; i++) { + final PsiReturnStatement condition = returnStatements.get(i); + final PsiElement container = condition.getParent(); + final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = true;", container); + if (!RefactoringUtil.isLoopOrIf(container)) { + container.addBefore(resultStmt, condition); + } + else { + RefactoringUtil.putStatementInLoopBody(resultStmt, container, condition); + } + } - final PsiCodeBlock body = getMethod().getBody(); - LOG.assertTrue(body != null); - final LinkedHashSet vars = new LinkedHashSet(); - final Map replacementMap = new LinkedHashMap(); - final List returnStatements = new ArrayList(); - body.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReturnStatement(PsiReturnStatement statement) { - returnStatements.add(statement); - } - - @Override - public void visitClass(PsiClass aClass) { - } - - @Override - public void visitLambdaExpression(PsiLambdaExpression expression) { - } - }); - if (myExtractProcessor.generatesConditionalExit()) { - for (int i = 0; i < returnStatements.size() - 1; i++) { - final PsiReturnStatement condition = returnStatements.get(i); - final PsiElement container = condition.getParent(); - final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = true;", container); - if (!RefactoringUtil.isLoopOrIf(container)) { - container.addBefore(resultStmt, condition); - } else { - RefactoringUtil.putStatementInLoopBody(resultStmt, container, condition); - } - } - - LOG.assertTrue(!returnStatements.isEmpty()); - final PsiReturnStatement returnStatement = returnStatements.get(returnStatements.size() - 1); - final PsiElement container = returnStatement.getParent(); - final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = false;", container); - if (!RefactoringUtil.isLoopOrIf(container)) { - container.addBefore(resultStmt, returnStatement); - } else { - RefactoringUtil.putStatementInLoopBody(resultStmt, container, returnStatement); - } - } - body.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReturnStatement(final PsiReturnStatement statement) { - super.visitReturnStatement(statement); - try { - replacementMap.put(statement, myElementFactory.createStatementFromText("return this;", statement)); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - @Override - public void visitClass(PsiClass aClass) { - } - - @Override - public void visitLambdaExpression(PsiLambdaExpression expression) { - } - - @Override - public void visitDeclarationStatement(final PsiDeclarationStatement statement) { - super.visitDeclarationStatement(statement); - final PsiElement[] declaredElements = statement.getDeclaredElements();//todo - for (PsiElement declaredElement : declaredElements) { - if (declaredElement instanceof PsiVariable) { - for (PsiVariable variable : outputVariables) { - PsiVariable var = (PsiVariable) declaredElement; - if (Comparing.strEqual(var.getName(), variable.getName())) { - final PsiExpression initializer = var.getInitializer(); - if (initializer == null) { - replacementMap.put(statement, null); - } else { - replacementMap.put(var, var); - } - } - } - } - } - } - - @Override - public void visitReferenceExpression(final PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement resolved = expression.resolve(); - if (resolved instanceof PsiLocalVariable) { - final String var = ((PsiLocalVariable) resolved).getName(); - for (PsiVariable variable : outputVariables) { - if (Comparing.strEqual(variable.getName(), var)) { - vars.add((PsiLocalVariable) resolved); - break; - } - } - } - } - }); - - for (PsiLocalVariable var : vars) { - final String fieldName = var2FieldNames.get(var.getName()); - for (PsiReference reference : ReferencesSearch.search(var)) { - reference.handleElementRename(fieldName); - } - } + LOG.assertTrue(!returnStatements.isEmpty()); + final PsiReturnStatement returnStatement = returnStatements.get(returnStatements.size() - 1); + final PsiElement container = returnStatement.getParent(); + final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = false;", container); + if (!RefactoringUtil.isLoopOrIf(container)) { + container.addBefore(resultStmt, returnStatement); + } + else { + RefactoringUtil.putStatementInLoopBody(resultStmt, container, returnStatement); + } + } + body.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReturnStatement(final PsiReturnStatement statement) { + super.visitReturnStatement(statement); + try { + replacementMap.put(statement, myElementFactory.createStatementFromText("return this;", statement)); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } - for (PsiElement statement : replacementMap.keySet()) { - final PsiElement replacement = replacementMap.get(statement); - if (replacement != null) { - if (statement instanceof PsiLocalVariable) { - final PsiLocalVariable variable = (PsiLocalVariable) statement; - variable.normalizeDeclaration(); - final PsiExpression initializer = variable.getInitializer(); - LOG.assertTrue(initializer != null); - final PsiStatement assignmentStatement = myElementFactory.createStatementFromText(var2FieldNames.get(variable.getName()) + " = " + initializer.getText() + ";", statement); - final PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(statement, PsiDeclarationStatement.class); - LOG.assertTrue(declaration != null); - declaration.replace(assignmentStatement); - } else { - if (statement instanceof PsiReturnStatement) { - final PsiExpression returnValue = ((PsiReturnStatement) statement).getReturnValue(); - if (!(returnValue instanceof PsiReferenceExpression || returnValue == null || returnValue instanceof PsiLiteralExpression)) { - statement.getParent().addBefore(myElementFactory.createStatementFromText(returnValue.getText() + ";", returnValue), statement); - } - } - statement.replace(replacement); - } - } else { - statement.delete(); - } - } + @Override + public void visitClass(PsiClass aClass) { + } - myChangeReturnType = true; - } + @Override + public void visitLambdaExpression(PsiLambdaExpression expression) { + } - void runChangeSignature() { - if (myCopyMethodToInner != null) { - myCopyMethodToInner.run(); - } - if (myChangeReturnType) { - final PsiTypeElement typeElement = ((PsiLocalVariable) ((PsiDeclarationStatement) JavaPsiFacade.getElementFactory(myProject).createStatementFromText(myInnerClassName + " l =null;", - myInnerClass)).getDeclaredElements()[0]).getTypeElement(); - final PsiTypeElement innerMethodReturnTypeElement = myInnerMethod.getReturnTypeElement(); - LOG.assertTrue(innerMethodReturnTypeElement != null); - innerMethodReturnTypeElement.replace(typeElement); - } - } - - private String getPureName(PsiVariable var) { - final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); - return styleManager.variableNameToPropertyName(var.getName(), styleManager.getVariableKind(var)); - } - - public PsiExpression processMethodDeclaration(PsiExpressionList expressionList) throws IncorrectOperationException { - if (isCreateInnerClass()) { - final String typeArguments = getMethod().hasTypeParameters() ? "<" + StringUtil.join(Arrays.asList(getMethod().getTypeParameters()), new Function() { - public String apply(final PsiTypeParameter typeParameter) { - final String typeParameterName = typeParameter.getName(); - LOG.assertTrue(typeParameterName != null); - return typeParameterName; - } - }, ", ") + ">" : ""; - final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) myElementFactory.createExpressionFromText("invoke" + expressionList.getText(), null); - return replaceMethodCallExpression(typeArguments, methodCallExpression); - } else { - final String paramsDeclaration = getMethod().getParameterList().getText(); - final PsiType returnType = getMethod().getReturnType(); - LOG.assertTrue(returnType != null); - - final PsiCodeBlock methodBody = getMethod().getBody(); - LOG.assertTrue(methodBody != null); - return myElementFactory.createExpressionFromText("new Object(){ \n" + - "private " + - returnType.getPresentableText() + - " " + myInnerClassName + - paramsDeclaration + - methodBody.getText() + - "}." + myInnerClassName + - expressionList.getText(), null); - } - } - - - private PsiMethodCallExpression replaceMethodCallExpression(final String inferredTypeArguments, final PsiMethodCallExpression methodCallExpression) throws IncorrectOperationException { - @NonNls final String staticqualifier = getMethod().hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields() ? getInnerClassName() : null; - @NonNls String newReplacement; - final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); - final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); - if (staticqualifier != null) { - newReplacement = argumentList.getExpressions().length > 0 ? "new " + staticqualifier + inferredTypeArguments + argumentList.getText() + "." : staticqualifier + "."; - } else { - final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); - final String qualifier = qualifierExpression != null ? qualifierExpression.getText() + "." : ""; - newReplacement = qualifier + "new " + getInnerClassName() + inferredTypeArguments + argumentList.getText() + "."; - } - return (PsiMethodCallExpression) methodCallExpression.replace(myElementFactory.createExpressionFromText(newReplacement + "invoke()", null)); - } + @Override + public void visitDeclarationStatement(final PsiDeclarationStatement statement) { + super.visitDeclarationStatement(statement); + final PsiElement[] declaredElements = statement.getDeclaredElements();//todo + for (PsiElement declaredElement : declaredElements) { + if (declaredElement instanceof PsiVariable) { + for (PsiVariable variable : outputVariables) { + PsiVariable var = (PsiVariable) declaredElement; + if (Comparing.strEqual(var.getName(), variable.getName())) { + final PsiExpression initializer = var.getInitializer(); + if (initializer == null) { + replacementMap.put(statement, null); + } + else { + replacementMap.put(var, var); + } + } + } + } + } + } - @Nonnull - private String inferTypeArguments(final PsiMethodCallExpression methodCallExpression) { - final PsiReferenceParameterList list = methodCallExpression.getMethodExpression().getParameterList(); + @Override + public void visitReferenceExpression(final PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolved = expression.resolve(); + if (resolved instanceof PsiLocalVariable) { + final String var = ((PsiLocalVariable) resolved).getName(); + for (PsiVariable variable : outputVariables) { + if (Comparing.strEqual(variable.getName(), var)) { + vars.add((PsiLocalVariable) resolved); + break; + } + } + } + } + }); + + for (PsiLocalVariable var : vars) { + final String fieldName = var2FieldNames.get(var.getName()); + for (PsiReference reference : ReferencesSearch.search(var)) { + reference.handleElementRename(fieldName); + } + } + + for (PsiElement statement : replacementMap.keySet()) { + final PsiElement replacement = replacementMap.get(statement); + if (replacement != null) { + if (statement instanceof PsiLocalVariable) { + final PsiLocalVariable variable = (PsiLocalVariable) statement; + variable.normalizeDeclaration(); + final PsiExpression initializer = variable.getInitializer(); + LOG.assertTrue(initializer != null); + final PsiStatement assignmentStatement = myElementFactory.createStatementFromText( + var2FieldNames.get(variable.getName()) + " = " + initializer.getText() + ";", + statement + ); + final PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(statement, PsiDeclarationStatement.class); + LOG.assertTrue(declaration != null); + declaration.replace(assignmentStatement); + } + else { + if (statement instanceof PsiReturnStatement) { + final PsiExpression returnValue = ((PsiReturnStatement) statement).getReturnValue(); + if (!(returnValue instanceof PsiReferenceExpression || returnValue == null || returnValue instanceof PsiLiteralExpression)) { + statement.getParent() + .addBefore(myElementFactory.createStatementFromText(returnValue.getText() + ";", returnValue), statement); + } + } + statement.replace(replacement); + } + } + else { + statement.delete(); + } + } - if (list != null && list.getTypeArguments().length > 0) { - return list.getText(); + myChangeReturnType = true; } - final PsiTypeParameter[] methodTypeParameters = getMethod().getTypeParameters(); - if (methodTypeParameters.length > 0) { - List typeSignature = new ArrayList(); - final PsiSubstitutor substitutor = methodCallExpression.resolveMethodGenerics().getSubstitutor(); - for (final PsiTypeParameter typeParameter : methodTypeParameters) { - final PsiType type = substitutor.substitute(typeParameter); - if (type == null || PsiType.NULL.equals(type)) { - return ""; - } - typeSignature.add(type.getPresentableText()); - } - return "<" + StringUtil.join(typeSignature, ", ") + ">"; + void runChangeSignature() { + if (myCopyMethodToInner != null) { + myCopyMethodToInner.run(); + } + if (myChangeReturnType) { + final PsiTypeElement typeElement = + ((PsiLocalVariable) ((PsiDeclarationStatement) JavaPsiFacade.getElementFactory(myProject).createStatementFromText( + myInnerClassName + " l =null;", + myInnerClass + )).getDeclaredElements()[0]).getTypeElement(); + final PsiTypeElement innerMethodReturnTypeElement = myInnerMethod.getReturnTypeElement(); + LOG.assertTrue(innerMethodReturnTypeElement != null); + innerMethodReturnTypeElement.replace(typeElement); + } } - return ""; - } - protected String getCommandName() { - return REFACTORING_NAME; - } + private String getPureName(PsiVariable var) { + final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); + return styleManager.variableNameToPropertyName(var.getName(), styleManager.getVariableKind(var)); + } + public PsiExpression processMethodDeclaration(PsiExpressionList expressionList) throws IncorrectOperationException { + if (isCreateInnerClass()) { + final String typeArguments = + getMethod().hasTypeParameters() ? "<" + StringUtil.join( + Arrays.asList(getMethod().getTypeParameters()), + new Function() { + public String apply(final PsiTypeParameter typeParameter) { + final String typeParameterName = typeParameter.getName(); + LOG.assertTrue(typeParameterName != null); + return typeParameterName; + } + }, + ", " + ) + ">" : ""; + final PsiMethodCallExpression methodCallExpression = + (PsiMethodCallExpression) myElementFactory.createExpressionFromText("invoke" + expressionList.getText(), null); + return replaceMethodCallExpression(typeArguments, methodCallExpression); + } + else { + final String paramsDeclaration = getMethod().getParameterList().getText(); + final PsiType returnType = getMethod().getReturnType(); + LOG.assertTrue(returnType != null); + + final PsiCodeBlock methodBody = getMethod().getBody(); + LOG.assertTrue(methodBody != null); + return myElementFactory.createExpressionFromText("new Object(){ \n" + + "private " + + returnType.getPresentableText() + + " " + myInnerClassName + + paramsDeclaration + + methodBody.getText() + + "}." + myInnerClassName + + expressionList.getText(), null); + } + } - private boolean copyMethodModifiers() throws IncorrectOperationException { - final PsiModifierList methodModifierList = getMethod().getModifierList(); - final PsiModifierList innerClassModifierList = myInnerClass.getModifierList(); - LOG.assertTrue(innerClassModifierList != null); - innerClassModifierList.setModifierProperty(VisibilityUtil.getVisibilityModifier(methodModifierList), true); - final boolean isStatic = methodModifierList.hasModifierProperty(PsiModifier.STATIC); - innerClassModifierList.setModifierProperty(PsiModifier.STATIC, isStatic); - return isStatic; - } + private PsiMethodCallExpression replaceMethodCallExpression( + final String inferredTypeArguments, + final PsiMethodCallExpression methodCallExpression + ) throws IncorrectOperationException { + @NonNls final String staticqualifier = + getMethod().hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields() ? getInnerClassName() : null; + @NonNls String newReplacement; + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); + if (staticqualifier != null) { + newReplacement = + argumentList.getExpressions().length > 0 ? "new " + staticqualifier + inferredTypeArguments + argumentList.getText() + "." : staticqualifier + "."; + } + else { + final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + final String qualifier = qualifierExpression != null ? qualifierExpression.getText() + "." : ""; + newReplacement = qualifier + "new " + getInnerClassName() + inferredTypeArguments + argumentList.getText() + "."; + } + return (PsiMethodCallExpression) methodCallExpression.replace(myElementFactory.createExpressionFromText( + newReplacement + "invoke()", + null + )); + } - private void copyMethodTypeParameters() throws IncorrectOperationException { - final PsiTypeParameterList typeParameterList = myInnerClass.getTypeParameterList(); - LOG.assertTrue(typeParameterList != null); + @Nonnull + private String inferTypeArguments(final PsiMethodCallExpression methodCallExpression) { + final PsiReferenceParameterList list = methodCallExpression.getMethodExpression().getParameterList(); - for (PsiTypeParameter parameter : getMethod().getTypeParameters()) { - typeParameterList.add(parameter); - } - } - - private void copyMethodWithoutParameters() throws IncorrectOperationException { - final PsiMethod newMethod = myElementFactory.createMethod("invoke", getMethod().getReturnType()); - newMethod.getThrowsList().replace(getMethod().getThrowsList()); - - final PsiCodeBlock replacedMethodBody = newMethod.getBody(); - LOG.assertTrue(replacedMethodBody != null); - final PsiCodeBlock methodBody = getMethod().getBody(); - LOG.assertTrue(methodBody != null); - replacedMethodBody.replace(methodBody); - PsiUtil.setModifierProperty(newMethod, PsiModifier.STATIC, myInnerClass.hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields()); - myInnerMethod = (PsiMethod) myInnerClass.add(newMethod); - } - - private boolean notHasGeneratedFields() { - return !myMultipleExitPoints && getMethod().getParameterList().getParametersCount() == 0; - } - - private void createInnerClassConstructor(final PsiParameter[] parameters) throws IncorrectOperationException { - final PsiMethod constructor = myElementFactory.createConstructor(); - final PsiParameterList parameterList = constructor.getParameterList(); - for (PsiParameter parameter : parameters) { - final PsiModifierList parameterModifierList = parameter.getModifierList(); - LOG.assertTrue(parameterModifierList != null); - final String parameterName = parameter.getName(); - LOG.assertTrue(parameterName != null); - PsiParameter parm = myElementFactory.createParameter(parameterName, parameter.getType()); - if (CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS) { - final PsiModifierList modifierList = parm.getModifierList(); - LOG.assertTrue(modifierList != null); - modifierList.setModifierProperty(PsiModifier.FINAL, true); - } - parameterList.add(parm); - - final PsiField field = createField(parm, constructor, parameterModifierList.hasModifierProperty(PsiModifier.FINAL)); - for (PsiReference reference : ReferencesSearch.search(parameter)) { - reference.handleElementRename(field.getName()); - } - } - myInnerClass.add(constructor); - } - - private PsiField createField(PsiParameter parameter, PsiMethod constructor, boolean isFinal) { - final String parameterName = parameter.getName(); - PsiType type = parameter.getType(); - if (type instanceof PsiEllipsisType) { - type = ((PsiEllipsisType) type).toArrayType(); + if (list != null && list.getTypeArguments().length > 0) { + return list.getText(); + } + final PsiTypeParameter[] methodTypeParameters = getMethod().getTypeParameters(); + if (methodTypeParameters.length > 0) { + List typeSignature = new ArrayList(); + final PsiSubstitutor substitutor = methodCallExpression.resolveMethodGenerics().getSubstitutor(); + for (final PsiTypeParameter typeParameter : methodTypeParameters) { + final PsiType type = substitutor.substitute(typeParameter); + if (type == null || PsiType.NULL.equals(type)) { + return ""; + } + typeSignature.add(type.getPresentableText()); + } + return "<" + StringUtil.join(typeSignature, ", ") + ">"; + + } + return ""; } - try { - final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(getMethod().getProject()); - final String fieldName = styleManager.suggestVariableName(VariableKind.FIELD, styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER), null, type).names[0]; - PsiField field = myElementFactory.createField(fieldName, type); - - final PsiModifierList modifierList = field.getModifierList(); - LOG.assertTrue(modifierList != null); - final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject); - if (manager.isNullable(parameter, false)) { - modifierList.addAfter(myElementFactory.createAnnotationFromText("@" + manager.getDefaultNullable(), field), null); - } - modifierList.setModifierProperty(PsiModifier.FINAL, isFinal); - - final PsiCodeBlock methodBody = constructor.getBody(); - - LOG.assertTrue(methodBody != null); - - @NonNls final String stmtText; - if (Comparing.strEqual(parameterName, fieldName)) { - stmtText = "this." + fieldName + " = " + parameterName + ";"; - } else { - stmtText = fieldName + " = " + parameterName + ";"; - } - PsiStatement assignmentStmt = myElementFactory.createStatementFromText(stmtText, methodBody); - assignmentStmt = (PsiStatement) CodeStyleManager.getInstance(constructor.getProject()).reformat(assignmentStmt); - methodBody.add(assignmentStmt); - - field = (PsiField) myInnerClass.add(field); - return field; - } catch (IncorrectOperationException e) { - LOG.error(e); + + protected String getCommandName() { + return REFACTORING_NAME.get(); } - return null; - } - - protected void changeInstanceAccess(final Project project) throws IncorrectOperationException { - if (myMadeStatic) { - PsiReference[] refs = ReferencesSearch.search(myInnerMethod, GlobalSearchScope.projectScope(project), false).toArray(PsiReference.EMPTY_ARRAY); - for (PsiReference ref : refs) { - final PsiElement element = ref.getElement(); - final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class); - if (callExpression != null) { - replaceMethodCallExpression(inferTypeArguments(callExpression), callExpression); - } - } + + private boolean copyMethodModifiers() throws IncorrectOperationException { + final PsiModifierList methodModifierList = getMethod().getModifierList(); + + final PsiModifierList innerClassModifierList = myInnerClass.getModifierList(); + LOG.assertTrue(innerClassModifierList != null); + innerClassModifierList.setModifierProperty(VisibilityUtil.getVisibilityModifier(methodModifierList), true); + final boolean isStatic = methodModifierList.hasModifierProperty(PsiModifier.STATIC); + innerClassModifierList.setModifierProperty(PsiModifier.STATIC, isStatic); + return isStatic; } - } - public PsiMethod getMethod() { - return myExtractProcessor.getExtractedMethod(); - } + private void copyMethodTypeParameters() throws IncorrectOperationException { + final PsiTypeParameterList typeParameterList = myInnerClass.getTypeParameterList(); + LOG.assertTrue(typeParameterList != null); - public String getInnerClassName() { - return myInnerClassName; - } + for (PsiTypeParameter parameter : getMethod().getTypeParameters()) { + typeParameterList.add(parameter); + } + } - public void setCreateInnerClass(final boolean createInnerClass) { - myCreateInnerClass = createInnerClass; - } + private void copyMethodWithoutParameters() throws IncorrectOperationException { + final PsiMethod newMethod = myElementFactory.createMethod("invoke", getMethod().getReturnType()); + newMethod.getThrowsList().replace(getMethod().getThrowsList()); + + final PsiCodeBlock replacedMethodBody = newMethod.getBody(); + LOG.assertTrue(replacedMethodBody != null); + final PsiCodeBlock methodBody = getMethod().getBody(); + LOG.assertTrue(methodBody != null); + replacedMethodBody.replace(methodBody); + PsiUtil.setModifierProperty( + newMethod, + PsiModifier.STATIC, + myInnerClass.hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields() + ); + myInnerMethod = (PsiMethod) myInnerClass.add(newMethod); + } - public boolean isCreateInnerClass() { - return myCreateInnerClass; - } + private boolean notHasGeneratedFields() { + return !myMultipleExitPoints && getMethod().getParameterList().getParametersCount() == 0; + } + private void createInnerClassConstructor(final PsiParameter[] parameters) throws IncorrectOperationException { + final PsiMethod constructor = myElementFactory.createConstructor(); + final PsiParameterList parameterList = constructor.getParameterList(); + for (PsiParameter parameter : parameters) { + final PsiModifierList parameterModifierList = parameter.getModifierList(); + LOG.assertTrue(parameterModifierList != null); + final String parameterName = parameter.getName(); + LOG.assertTrue(parameterName != null); + PsiParameter parm = myElementFactory.createParameter(parameterName, parameter.getType()); + if (CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS) { + final PsiModifierList modifierList = parm.getModifierList(); + LOG.assertTrue(modifierList != null); + modifierList.setModifierProperty(PsiModifier.FINAL, true); + } + parameterList.add(parm); - public MyExtractMethodProcessor getExtractProcessor() { - return myExtractProcessor; - } + final PsiField field = createField(parm, constructor, parameterModifierList.hasModifierProperty(PsiModifier.FINAL)); + for (PsiReference reference : ReferencesSearch.search(parameter)) { + reference.handleElementRename(field.getName()); + } + } + myInnerClass.add(constructor); + } - protected AbstractExtractDialog createExtractMethodObjectDialog(final MyExtractMethodProcessor processor) { - return new ExtractMethodObjectDialog(myProject, processor.getTargetClass(), processor.getInputVariables(), processor.getReturnType(), processor.getTypeParameterList(), - processor.getThrownExceptions(), processor.isStatic(), processor.isCanBeStatic(), processor.getElements(), myMultipleExitPoints) { - @Override - protected boolean isUsedAfter(PsiVariable variable) { - return ArrayUtil.find(processor.getOutputVariables(), variable) != -1; - } - }; - } + private PsiField createField(PsiParameter parameter, PsiMethod constructor, boolean isFinal) { + final String parameterName = parameter.getName(); + PsiType type = parameter.getType(); + if (type instanceof PsiEllipsisType) { + type = ((PsiEllipsisType) type).toArrayType(); + } + try { + final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(getMethod().getProject()); + final String fieldName = styleManager.suggestVariableName( + VariableKind.FIELD, + styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER), + null, + type + ).names[0]; + PsiField field = myElementFactory.createField(fieldName, type); + + final PsiModifierList modifierList = field.getModifierList(); + LOG.assertTrue(modifierList != null); + final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject); + if (manager.isNullable(parameter, false)) { + modifierList.addAfter(myElementFactory.createAnnotationFromText("@" + manager.getDefaultNullable(), field), null); + } + modifierList.setModifierProperty(PsiModifier.FINAL, isFinal); - public PsiClass getInnerClass() { - return myInnerClass; - } + final PsiCodeBlock methodBody = constructor.getBody(); - protected boolean isFoldingApplicable() { - return true; - } + LOG.assertTrue(methodBody != null); - public class MyExtractMethodProcessor extends ExtractMethodProcessor { - public MyExtractMethodProcessor(Project project, Editor editor, PsiElement[] elements, PsiType forcedReturnType, String refactoringName, String initialMethodName, String helpId) { - super(project, editor, elements, forcedReturnType, refactoringName, initialMethodName, helpId); + @NonNls final String stmtText; + if (Comparing.strEqual(parameterName, fieldName)) { + stmtText = "this." + fieldName + " = " + parameterName + ";"; + } + else { + stmtText = fieldName + " = " + parameterName + ";"; + } + PsiStatement assignmentStmt = myElementFactory.createStatementFromText(stmtText, methodBody); + assignmentStmt = (PsiStatement) CodeStyleManager.getInstance(constructor.getProject()).reformat(assignmentStmt); + methodBody.add(assignmentStmt); + field = (PsiField) myInnerClass.add(field); + return field; + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + return null; } - @Override - protected boolean insertNotNullCheckIfPossible() { - return false; + protected void changeInstanceAccess(final Project project) throws IncorrectOperationException { + if (myMadeStatic) { + PsiReference[] refs = + ReferencesSearch.search(myInnerMethod, GlobalSearchScope.projectScope(project), false).toArray(PsiReference.EMPTY_ARRAY); + for (PsiReference ref : refs) { + final PsiElement element = ref.getElement(); + final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class); + if (callExpression != null) { + replaceMethodCallExpression(inferTypeArguments(callExpression), callExpression); + } + } + } } - @Override - protected boolean isNeedToChangeCallContext() { - return false; + public PsiMethod getMethod() { + return myExtractProcessor.getExtractedMethod(); } - @Override - protected void apply(final AbstractExtractDialog dialog) { - super.apply(dialog); - myCreateInnerClass = !(dialog instanceof ExtractMethodObjectDialog) || ((ExtractMethodObjectDialog) dialog).createInnerClass(); - myInnerClassName = myCreateInnerClass ? StringUtil.capitalize(dialog.getChosenMethodName()) : dialog.getChosenMethodName(); + public String getInnerClassName() { + return myInnerClassName; } - @Override - protected AbstractExtractDialog createExtractMethodDialog(final boolean direct) { - return createExtractMethodObjectDialog(this); + public void setCreateInnerClass(final boolean createInnerClass) { + myCreateInnerClass = createInnerClass; } - @Override - protected boolean checkOutputVariablesCount() { - myMultipleExitPoints = super.checkOutputVariablesCount(); - myOutputFields = new PsiField[myOutputVariables.length]; - for (int i = 0; i < myOutputVariables.length; i++) { - PsiVariable variable = myOutputVariables[i]; - if (!myInputVariables.contains(variable)) { //one field creation - final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); - final String fieldName = styleManager.suggestVariableName(VariableKind.FIELD, getPureName(variable), null, variable.getType()).names[0]; - try { - myOutputFields[i] = myElementFactory.createField(fieldName, variable.getType()); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - return !myCreateInnerClass && myMultipleExitPoints; + public boolean isCreateInnerClass() { + return myCreateInnerClass; } - @Override - public PsiElement processMatch(final Match match) throws IncorrectOperationException { - final boolean makeStatic = myInnerMethod != null && - RefactoringUtil.isInStaticContext(match.getMatchStart(), getExtractedMethod().getContainingClass()) && - !myInnerMethod.getContainingClass().hasModifierProperty(PsiModifier.STATIC); - final PsiElement element = super.processMatch(match); - if (makeStatic) { - myMadeStatic = true; - final PsiModifierList modifierList = myInnerMethod.getContainingClass().getModifierList(); - LOG.assertTrue(modifierList != null); - modifierList.setModifierProperty(PsiModifier.STATIC, true); - PsiUtil.setModifierProperty(myInnerMethod, PsiModifier.STATIC, true); - } - PsiMethodCallExpression methodCallExpression = null; - if (element instanceof PsiMethodCallExpression) { - methodCallExpression = (PsiMethodCallExpression) element; - } else if (element instanceof PsiExpressionStatement) { - final PsiExpression expression = ((PsiExpressionStatement) element).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - methodCallExpression = (PsiMethodCallExpression) expression; - } else if (expression instanceof PsiAssignmentExpression) { - final PsiExpression psiExpression = ((PsiAssignmentExpression) expression).getRExpression(); - if (psiExpression instanceof PsiMethodCallExpression) { - methodCallExpression = (PsiMethodCallExpression) psiExpression; - } - } - } else if (element instanceof PsiDeclarationStatement) { - final PsiElement[] declaredElements = ((PsiDeclarationStatement) element).getDeclaredElements(); - for (PsiElement declaredElement : declaredElements) { - if (declaredElement instanceof PsiLocalVariable) { - final PsiExpression initializer = ((PsiLocalVariable) declaredElement).getInitializer(); - if (initializer instanceof PsiMethodCallExpression) { - methodCallExpression = (PsiMethodCallExpression) initializer; - break; - } - } - } - } - if (methodCallExpression == null) { - return element; - } - - PsiExpression expression = processMethodDeclaration(methodCallExpression.getArgumentList()); - - return methodCallExpression.replace(expression); + public MyExtractMethodProcessor getExtractProcessor() { + return myExtractProcessor; } - public PsiVariable[] getOutputVariables() { - return myOutputVariables; + protected AbstractExtractDialog createExtractMethodObjectDialog(final MyExtractMethodProcessor processor) { + return new ExtractMethodObjectDialog( + myProject, + processor.getTargetClass(), + processor.getInputVariables(), + processor.getReturnType(), + processor.getTypeParameterList(), + processor.getThrownExceptions(), + processor.isStatic(), + processor.isCanBeStatic(), + processor.getElements(), + myMultipleExitPoints + ) { + @Override + protected boolean isUsedAfter(PsiVariable variable) { + return ArrayUtil.find(processor.getOutputVariables(), variable) != -1; + } + }; } - @Override - protected void declareNecessaryVariablesAfterCall(final PsiVariable outputVariable) throws IncorrectOperationException { - if (myMultipleExitPoints) { - final String object = JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(StringUtil.decapitalize(myInnerClassName), outputVariable, true); - final PsiStatement methodCallStatement = PsiTreeUtil.getParentOfType(getMethodCall(), PsiStatement.class); - LOG.assertTrue(methodCallStatement != null); - final PsiStatement declarationStatement = myElementFactory.createStatementFromText(myInnerClassName + " " + object + " = " + getMethodCall().getText() + ";", myInnerMethod); - if (methodCallStatement instanceof PsiIfStatement) { - methodCallStatement.getParent().addBefore(declarationStatement, methodCallStatement); - final PsiExpression conditionExpression = ((PsiIfStatement) methodCallStatement).getCondition(); - setMethodCall((PsiMethodCallExpression) conditionExpression.replace(myElementFactory.createExpressionFromText(object + ".is()", myInnerMethod))); - } else if (myElements[0] instanceof PsiExpression) { - methodCallStatement.getParent().addBefore(declarationStatement, methodCallStatement); - } else { - final PsiDeclarationStatement replace = (PsiDeclarationStatement) methodCallStatement.replace(declarationStatement); - setMethodCall((PsiMethodCallExpression) ((PsiLocalVariable) replace.getDeclaredElements()[0]).getInitializer()); - } - - final List usedVariables = myControlFlowWrapper.getUsedVariables(); - Collection reassigned = myControlFlowWrapper.getInitializedTwice(); - for (PsiVariable variable : usedVariables) { - String name = variable.getName(); - LOG.assertTrue(name != null); - PsiStatement st = null; - final String pureName = getPureName(variable); - final int varIdxInOutput = ArrayUtil.find(myOutputVariables, variable); - final String getterName = varIdxInOutput > -1 && myOutputFields[varIdxInOutput] != null ? GenerateMembersUtil.suggestGetterName(myOutputFields[varIdxInOutput]) : - GenerateMembersUtil.suggestGetterName(pureName, variable.getType(), myProject); - if (isDeclaredInside(variable)) { - st = myElementFactory.createStatementFromText(variable.getType().getCanonicalText() + " " + name + " = " + object + "." + getterName + "();", myInnerMethod); - if (reassigned.contains(new ControlFlowUtil.VariableInfo(variable, null))) { - final PsiElement[] psiElements = ((PsiDeclarationStatement) st).getDeclaredElements(); - assert psiElements.length > 0; - PsiVariable var = (PsiVariable) psiElements[0]; - PsiUtil.setModifierProperty(var, PsiModifier.FINAL, false); - } - } else { - if (varIdxInOutput != -1) { - st = myElementFactory.createStatementFromText(name + " = " + object + "." + getterName + "();", myInnerMethod); - } - } - if (st != null) { - addToMethodCallLocation(st); - } - } - if (myElements[0] instanceof PsiAssignmentExpression) { - getMethodCall().getParent().replace(((PsiAssignmentExpression) getMethodCall().getParent()).getLExpression()); - } else if (myElements[0] instanceof PsiPostfixExpression || myElements[0] instanceof PsiPrefixExpression) { - getMethodCall().getParent().replace(((PsiBinaryExpression) getMethodCall().getParent()).getLOperand()); - } - - rebindExitStatement(object); - } else { - super.declareNecessaryVariablesAfterCall(outputVariable); - } + public PsiClass getInnerClass() { + return myInnerClass; } - @Override protected boolean isFoldingApplicable() { - return ExtractMethodObjectProcessor.this.isFoldingApplicable(); + return true; } - private void rebindExitStatement(final String objectName) { - final PsiStatement exitStatementCopy = myExtractProcessor.myFirstExitStatementCopy; - if (exitStatementCopy != null) { - myExtractProcessor.getDuplicates().clear(); - final Map outVarsNames = new HashMap(); - for (PsiVariable variable : myOutputVariables) { - outVarsNames.put(variable.getName(), variable); - } - final Map replaceMap = new HashMap(); - exitStatementCopy.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - if (expression.resolve() == null) { - final PsiVariable variable = outVarsNames.get(expression.getReferenceName()); - if (variable != null) { - final String call2Getter = objectName + "." + GenerateMembersUtil.suggestGetterName(getPureName(variable), variable.getType(), myProject) + "()"; - final PsiExpression callToGetter = myElementFactory.createExpressionFromText(call2Getter, variable); - replaceMap.put(expression, callToGetter); - } - } - } - }); - for (PsiElement element : replaceMap.keySet()) { - if (element.isValid()) { - element.replace(replaceMap.get(element)); - } + public class MyExtractMethodProcessor extends ExtractMethodProcessor { + public MyExtractMethodProcessor( + Project project, + Editor editor, + PsiElement[] elements, + PsiType forcedReturnType, + String refactoringName, + String initialMethodName, + String helpId + ) { + super(project, editor, elements, forcedReturnType, refactoringName, initialMethodName, helpId); + + } + + @Override + protected boolean insertNotNullCheckIfPossible() { + return false; } - } - } - public boolean generatesConditionalExit() { - return myGenerateConditionalExit; + @Override + protected boolean isNeedToChangeCallContext() { + return false; + } + + @Override + protected void apply(final AbstractExtractDialog dialog) { + super.apply(dialog); + myCreateInnerClass = !(dialog instanceof ExtractMethodObjectDialog) || ((ExtractMethodObjectDialog) dialog).createInnerClass(); + myInnerClassName = myCreateInnerClass ? StringUtil.capitalize(dialog.getChosenMethodName()) : dialog.getChosenMethodName(); + } + + @Override + protected AbstractExtractDialog createExtractMethodDialog(final boolean direct) { + return createExtractMethodObjectDialog(this); + } + + @Override + protected boolean checkOutputVariablesCount() { + myMultipleExitPoints = super.checkOutputVariablesCount(); + myOutputFields = new PsiField[myOutputVariables.length]; + for (int i = 0; i < myOutputVariables.length; i++) { + PsiVariable variable = myOutputVariables[i]; + if (!myInputVariables.contains(variable)) { //one field creation + final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); + final String fieldName = + styleManager.suggestVariableName(VariableKind.FIELD, getPureName(variable), null, variable.getType()).names[0]; + try { + myOutputFields[i] = myElementFactory.createField(fieldName, variable.getType()); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + return !myCreateInnerClass && myMultipleExitPoints; + } + + @Override + public PsiElement processMatch(final Match match) throws IncorrectOperationException { + final boolean makeStatic = myInnerMethod != null && + RefactoringUtil.isInStaticContext(match.getMatchStart(), getExtractedMethod().getContainingClass()) && + !myInnerMethod.getContainingClass().hasModifierProperty(PsiModifier.STATIC); + final PsiElement element = super.processMatch(match); + if (makeStatic) { + myMadeStatic = true; + final PsiModifierList modifierList = myInnerMethod.getContainingClass().getModifierList(); + LOG.assertTrue(modifierList != null); + modifierList.setModifierProperty(PsiModifier.STATIC, true); + PsiUtil.setModifierProperty(myInnerMethod, PsiModifier.STATIC, true); + } + PsiMethodCallExpression methodCallExpression = null; + if (element instanceof PsiMethodCallExpression) { + methodCallExpression = (PsiMethodCallExpression) element; + } + else if (element instanceof PsiExpressionStatement) { + final PsiExpression expression = ((PsiExpressionStatement) element).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + methodCallExpression = (PsiMethodCallExpression) expression; + } + else if (expression instanceof PsiAssignmentExpression) { + final PsiExpression psiExpression = ((PsiAssignmentExpression) expression).getRExpression(); + if (psiExpression instanceof PsiMethodCallExpression) { + methodCallExpression = (PsiMethodCallExpression) psiExpression; + } + } + } + else if (element instanceof PsiDeclarationStatement) { + final PsiElement[] declaredElements = ((PsiDeclarationStatement) element).getDeclaredElements(); + for (PsiElement declaredElement : declaredElements) { + if (declaredElement instanceof PsiLocalVariable) { + final PsiExpression initializer = ((PsiLocalVariable) declaredElement).getInitializer(); + if (initializer instanceof PsiMethodCallExpression) { + methodCallExpression = (PsiMethodCallExpression) initializer; + break; + } + } + } + } + if (methodCallExpression == null) { + return element; + } + + PsiExpression expression = processMethodDeclaration(methodCallExpression.getArgumentList()); + + return methodCallExpression.replace(expression); + } + + public PsiVariable[] getOutputVariables() { + return myOutputVariables; + } + + @Override + protected void declareNecessaryVariablesAfterCall(final PsiVariable outputVariable) throws IncorrectOperationException { + if (myMultipleExitPoints) { + final String object = JavaCodeStyleManager.getInstance(myProject) + .suggestUniqueVariableName(StringUtil.decapitalize(myInnerClassName), outputVariable, true); + final PsiStatement methodCallStatement = PsiTreeUtil.getParentOfType(getMethodCall(), PsiStatement.class); + LOG.assertTrue(methodCallStatement != null); + final PsiStatement declarationStatement = myElementFactory.createStatementFromText( + myInnerClassName + " " + object + " = " + getMethodCall().getText() + ";", + myInnerMethod + ); + if (methodCallStatement instanceof PsiIfStatement) { + methodCallStatement.getParent().addBefore(declarationStatement, methodCallStatement); + final PsiExpression conditionExpression = ((PsiIfStatement) methodCallStatement).getCondition(); + setMethodCall((PsiMethodCallExpression) conditionExpression.replace(myElementFactory.createExpressionFromText( + object + ".is()", + myInnerMethod + ))); + } + else if (myElements[0] instanceof PsiExpression) { + methodCallStatement.getParent().addBefore(declarationStatement, methodCallStatement); + } + else { + final PsiDeclarationStatement replace = (PsiDeclarationStatement) methodCallStatement.replace(declarationStatement); + setMethodCall((PsiMethodCallExpression) ((PsiLocalVariable) replace.getDeclaredElements()[0]).getInitializer()); + } + + final List usedVariables = myControlFlowWrapper.getUsedVariables(); + Collection reassigned = myControlFlowWrapper.getInitializedTwice(); + for (PsiVariable variable : usedVariables) { + String name = variable.getName(); + LOG.assertTrue(name != null); + PsiStatement st = null; + final String pureName = getPureName(variable); + final int varIdxInOutput = ArrayUtil.find(myOutputVariables, variable); + final String getterName = + varIdxInOutput > -1 && myOutputFields[varIdxInOutput] != null ? GenerateMembersUtil.suggestGetterName(myOutputFields[varIdxInOutput]) : + GenerateMembersUtil.suggestGetterName(pureName, variable.getType(), myProject); + if (isDeclaredInside(variable)) { + st = myElementFactory.createStatementFromText(variable.getType() + .getCanonicalText() + " " + name + " = " + object + "." + getterName + "();", myInnerMethod); + if (reassigned.contains(new ControlFlowUtil.VariableInfo(variable, null))) { + final PsiElement[] psiElements = ((PsiDeclarationStatement) st).getDeclaredElements(); + assert psiElements.length > 0; + PsiVariable var = (PsiVariable) psiElements[0]; + PsiUtil.setModifierProperty(var, PsiModifier.FINAL, false); + } + } + else { + if (varIdxInOutput != -1) { + st = myElementFactory.createStatementFromText(name + " = " + object + "." + getterName + "();", myInnerMethod); + } + } + if (st != null) { + addToMethodCallLocation(st); + } + } + if (myElements[0] instanceof PsiAssignmentExpression) { + getMethodCall().getParent().replace(((PsiAssignmentExpression) getMethodCall().getParent()).getLExpression()); + } + else if (myElements[0] instanceof PsiPostfixExpression || myElements[0] instanceof PsiPrefixExpression) { + getMethodCall().getParent().replace(((PsiBinaryExpression) getMethodCall().getParent()).getLOperand()); + } + + rebindExitStatement(object); + } + else { + super.declareNecessaryVariablesAfterCall(outputVariable); + } + } + + @Override + protected boolean isFoldingApplicable() { + return ExtractMethodObjectProcessor.this.isFoldingApplicable(); + } + + private void rebindExitStatement(final String objectName) { + final PsiStatement exitStatementCopy = myExtractProcessor.myFirstExitStatementCopy; + if (exitStatementCopy != null) { + myExtractProcessor.getDuplicates().clear(); + final Map outVarsNames = new HashMap(); + for (PsiVariable variable : myOutputVariables) { + outVarsNames.put(variable.getName(), variable); + } + final Map replaceMap = new HashMap(); + exitStatementCopy.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (expression.resolve() == null) { + final PsiVariable variable = outVarsNames.get(expression.getReferenceName()); + if (variable != null) { + final String call2Getter = objectName + "." + GenerateMembersUtil.suggestGetterName( + getPureName(variable), + variable.getType(), + myProject + ) + "()"; + final PsiExpression callToGetter = myElementFactory.createExpressionFromText(call2Getter, variable); + replaceMap.put(expression, callToGetter); + } + } + } + }); + for (PsiElement element : replaceMap.keySet()) { + if (element.isValid()) { + element.replace(replaceMap.get(element)); + } + } + } + } + + public boolean generatesConditionalExit() { + return myGenerateConditionalExit; + } } - } } 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 4cd401edb..54c27411e 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 @@ -33,10 +33,12 @@ import consulo.language.psi.PsiManager; import consulo.language.psi.scope.GlobalSearchScope; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.module.Module; import consulo.module.content.ProjectRootManager; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awt.DialogWrapper; import consulo.util.collection.MultiMap; import consulo.util.lang.function.Condition; @@ -50,191 +52,221 @@ * @author dsl */ public class ExtractSuperClassUtil { - private static final Logger LOG = Logger.getInstance(ExtractSuperClassUtil.class); - private ExtractSuperClassUtil() {} - - public static PsiClass extractSuperClass(final Project project, - final PsiDirectory targetDirectory, - final String superclassName, - final PsiClass subclass, - final MemberInfo[] selectedMemberInfos, - final DocCommentPolicy javaDocPolicy) - throws IncorrectOperationException { - PsiClass superclass = JavaDirectoryService.getInstance().createClass(targetDirectory, superclassName); - final PsiModifierList superClassModifierList = superclass.getModifierList(); - assert superClassModifierList != null; - superClassModifierList.setModifierProperty(PsiModifier.FINAL, false); - final PsiReferenceList subClassExtends = subclass.getExtendsList(); - assert subClassExtends != null: subclass; - copyPsiReferenceList(subClassExtends, superclass.getExtendsList()); - - // create constructors if necessary - PsiMethod[] constructors = getCalledBaseConstructors(subclass); - if (constructors.length > 0) { - createConstructorsByPattern(project, superclass, constructors); + private static final Logger LOG = Logger.getInstance(ExtractSuperClassUtil.class); + + private ExtractSuperClassUtil() { } - // clear original class' "extends" list - clearPsiReferenceList(subclass.getExtendsList()); + public static PsiClass extractSuperClass( + final Project project, + final PsiDirectory targetDirectory, + final String superclassName, + final PsiClass subclass, + final MemberInfo[] selectedMemberInfos, + final DocCommentPolicy javaDocPolicy + ) + throws IncorrectOperationException { + PsiClass superclass = JavaDirectoryService.getInstance().createClass(targetDirectory, superclassName); + final PsiModifierList superClassModifierList = superclass.getModifierList(); + assert superClassModifierList != null; + superClassModifierList.setModifierProperty(PsiModifier.FINAL, false); + final PsiReferenceList subClassExtends = subclass.getExtendsList(); + assert subClassExtends != null : subclass; + copyPsiReferenceList(subClassExtends, superclass.getExtendsList()); - // make original class extend extracted superclass - PsiJavaCodeReferenceElement ref = createExtendingReference(superclass, subclass, selectedMemberInfos); - subclass.getExtendsList().add(ref); + // create constructors if necessary + PsiMethod[] constructors = getCalledBaseConstructors(subclass); + if (constructors.length > 0) { + createConstructorsByPattern(project, superclass, constructors); + } - PullUpProcessor pullUpHelper = new PullUpProcessor(subclass, superclass, selectedMemberInfos, - javaDocPolicy - ); + // clear original class' "extends" list + clearPsiReferenceList(subclass.getExtendsList()); - pullUpHelper.moveMembersToBase(); - pullUpHelper.moveFieldInitializations(); + // make original class extend extracted superclass + PsiJavaCodeReferenceElement ref = createExtendingReference(superclass, subclass, selectedMemberInfos); + subclass.getExtendsList().add(ref); - Collection toImplement = OverrideImplementUtil.getMethodSignaturesToImplement(superclass); - if (!toImplement.isEmpty()) { - superClassModifierList.setModifierProperty(PsiModifier.ABSTRACT, true); - } - return superclass; - } - - private static void createConstructorsByPattern(Project project, final PsiClass superclass, PsiMethod[] patternConstructors) throws IncorrectOperationException { - PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); - CodeStyleManager styleManager = CodeStyleManager.getInstance(project); - for (PsiMethod baseConstructor : patternConstructors) { - PsiMethod constructor = (PsiMethod)superclass.add(factory.createConstructor()); - PsiParameterList paramList = constructor.getParameterList(); - PsiParameter[] baseParams = baseConstructor.getParameterList().getParameters(); - @NonNls StringBuilder superCallText = new StringBuilder(); - superCallText.append("super("); - final PsiClass baseClass = baseConstructor.getContainingClass(); - LOG.assertTrue(baseClass != null); - final PsiSubstitutor classSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, superclass, PsiSubstitutor.EMPTY); - for (int i = 0; i < baseParams.length; i++) { - final PsiParameter baseParam = baseParams[i]; - final PsiParameter newParam = (PsiParameter)paramList.add(factory.createParameter(baseParam.getName(), classSubstitutor.substitute(baseParam.getType()))); - if (i > 0) { - superCallText.append(","); + PullUpProcessor pullUpHelper = new PullUpProcessor(subclass, superclass, selectedMemberInfos, + javaDocPolicy + ); + + pullUpHelper.moveMembersToBase(); + pullUpHelper.moveFieldInitializations(); + + Collection toImplement = OverrideImplementUtil.getMethodSignaturesToImplement(superclass); + if (!toImplement.isEmpty()) { + superClassModifierList.setModifierProperty(PsiModifier.ABSTRACT, true); } - superCallText.append(newParam.getName()); - } - superCallText.append(");"); - PsiStatement statement = factory.createStatementFromText(superCallText.toString(), null); - statement = (PsiStatement)styleManager.reformat(statement); - final PsiCodeBlock body = constructor.getBody(); - assert body != null; - body.add(statement); - constructor.getThrowsList().replace(baseConstructor.getThrowsList()); + return superclass; } - } - - private static PsiMethod[] getCalledBaseConstructors(final PsiClass subclass) { - Set baseConstructors = new HashSet(); - PsiMethod[] constructors = subclass.getConstructors(); - for (PsiMethod constructor : constructors) { - PsiCodeBlock body = constructor.getBody(); - if (body == null) continue; - PsiStatement[] statements = body.getStatements(); - if (statements.length > 0) { - PsiStatement first = statements[0]; - if (first instanceof PsiExpressionStatement) { - PsiExpression expression = ((PsiExpressionStatement)first).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - PsiReferenceExpression calledMethod = ((PsiMethodCallExpression)expression).getMethodExpression(); - @NonNls String text = calledMethod.getText(); - if ("super".equals(text)) { - PsiMethod baseConstructor = (PsiMethod)calledMethod.resolve(); - if (baseConstructor != null) { - baseConstructors.add(baseConstructor); - } + + private static void createConstructorsByPattern( + Project project, + final PsiClass superclass, + PsiMethod[] patternConstructors + ) throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); + CodeStyleManager styleManager = CodeStyleManager.getInstance(project); + for (PsiMethod baseConstructor : patternConstructors) { + PsiMethod constructor = (PsiMethod) superclass.add(factory.createConstructor()); + PsiParameterList paramList = constructor.getParameterList(); + PsiParameter[] baseParams = baseConstructor.getParameterList().getParameters(); + @NonNls StringBuilder superCallText = new StringBuilder(); + superCallText.append("super("); + final PsiClass baseClass = baseConstructor.getContainingClass(); + LOG.assertTrue(baseClass != null); + final PsiSubstitutor classSubstitutor = + TypeConversionUtil.getSuperClassSubstitutor(baseClass, superclass, PsiSubstitutor.EMPTY); + for (int i = 0; i < baseParams.length; i++) { + final PsiParameter baseParam = baseParams[i]; + final PsiParameter newParam = (PsiParameter) paramList.add(factory.createParameter( + baseParam.getName(), + classSubstitutor.substitute(baseParam.getType()) + )); + if (i > 0) { + superCallText.append(","); + } + superCallText.append(newParam.getName()); } - } + superCallText.append(");"); + PsiStatement statement = factory.createStatementFromText(superCallText.toString(), null); + statement = (PsiStatement) styleManager.reformat(statement); + final PsiCodeBlock body = constructor.getBody(); + assert body != null; + body.add(statement); + constructor.getThrowsList().replace(baseConstructor.getThrowsList()); } - } } - return baseConstructors.toArray(new PsiMethod[baseConstructors.size()]); - } - private static void clearPsiReferenceList(PsiReferenceList refList) throws IncorrectOperationException { - PsiJavaCodeReferenceElement[] refs = refList.getReferenceElements(); - for (PsiJavaCodeReferenceElement ref : refs) { - ref.delete(); + private static PsiMethod[] getCalledBaseConstructors(final PsiClass subclass) { + Set baseConstructors = new HashSet(); + PsiMethod[] constructors = subclass.getConstructors(); + for (PsiMethod constructor : constructors) { + PsiCodeBlock body = constructor.getBody(); + if (body == null) { + continue; + } + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0) { + PsiStatement first = statements[0]; + if (first instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement) first).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + PsiReferenceExpression calledMethod = ((PsiMethodCallExpression) expression).getMethodExpression(); + @NonNls String text = calledMethod.getText(); + if ("super".equals(text)) { + PsiMethod baseConstructor = (PsiMethod) calledMethod.resolve(); + if (baseConstructor != null) { + baseConstructors.add(baseConstructor); + } + } + } + } + } + } + return baseConstructors.toArray(new PsiMethod[baseConstructors.size()]); } - } - private static void copyPsiReferenceList(PsiReferenceList sourceList, PsiReferenceList destinationList) throws IncorrectOperationException { - clearPsiReferenceList(destinationList); - PsiJavaCodeReferenceElement[] refs = sourceList.getReferenceElements(); - for (PsiJavaCodeReferenceElement ref : refs) { - destinationList.add(ref); + private static void clearPsiReferenceList(PsiReferenceList refList) throws IncorrectOperationException { + PsiJavaCodeReferenceElement[] refs = refList.getReferenceElements(); + for (PsiJavaCodeReferenceElement ref : refs) { + ref.delete(); + } } - } - - public static PsiJavaCodeReferenceElement createExtendingReference(final PsiClass superClass, - final PsiClass derivedClass, - final MemberInfo[] selectedMembers) throws IncorrectOperationException { - final PsiManager manager = derivedClass.getManager(); - Set movedElements = new HashSet(); - for (final MemberInfo info : selectedMembers) { - movedElements.add(info.getMember()); + + private static void copyPsiReferenceList( + PsiReferenceList sourceList, + PsiReferenceList destinationList + ) throws IncorrectOperationException { + clearPsiReferenceList(destinationList); + PsiJavaCodeReferenceElement[] refs = sourceList.getReferenceElements(); + for (PsiJavaCodeReferenceElement ref : refs) { + destinationList.add(ref); + } } - final PsiTypeParameterList typeParameterList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(null, - new Condition() { - @Override - public boolean value( - PsiTypeParameter parameter) { - return - findTypeParameterInDerived( - derivedClass, - parameter - .getName()) != - null; - } - }, PsiUtilBase - .toPsiElementArray(movedElements)); - final PsiTypeParameterList originalTypeParameterList = superClass.getTypeParameterList(); - assert originalTypeParameterList != null; - final PsiTypeParameterList newList = typeParameterList != null ? (PsiTypeParameterList)originalTypeParameterList.replace(typeParameterList) : originalTypeParameterList; - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - Map substitutionMap = new HashMap(); - for (final PsiTypeParameter parameter : newList.getTypeParameters()) { - final PsiTypeParameter parameterInDerived = findTypeParameterInDerived(derivedClass, parameter.getName()); - if (parameterInDerived != null) { - substitutionMap.put(parameter, factory.createType(parameterInDerived)); - } + + public static PsiJavaCodeReferenceElement createExtendingReference( + final PsiClass superClass, + final PsiClass derivedClass, + final MemberInfo[] selectedMembers + ) throws IncorrectOperationException { + final PsiManager manager = derivedClass.getManager(); + Set movedElements = new HashSet(); + for (final MemberInfo info : selectedMembers) { + movedElements.add(info.getMember()); + } + final PsiTypeParameterList typeParameterList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(null, + new Condition() { + @Override + public boolean value( + PsiTypeParameter parameter + ) { + return + findTypeParameterInDerived( + derivedClass, + parameter + .getName() + ) != + null; + } + }, PsiUtilBase + .toPsiElementArray(movedElements) + ); + final PsiTypeParameterList originalTypeParameterList = superClass.getTypeParameterList(); + assert originalTypeParameterList != null; + final PsiTypeParameterList newList = + typeParameterList != null ? (PsiTypeParameterList) originalTypeParameterList.replace(typeParameterList) : originalTypeParameterList; + final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + Map substitutionMap = new HashMap(); + for (final PsiTypeParameter parameter : newList.getTypeParameters()) { + final PsiTypeParameter parameterInDerived = findTypeParameterInDerived(derivedClass, parameter.getName()); + if (parameterInDerived != null) { + substitutionMap.put(parameter, factory.createType(parameterInDerived)); + } + } + + final PsiClassType type = factory.createType(superClass, factory.createSubstitutor(substitutionMap)); + return factory.createReferenceElementByType(type); } - final PsiClassType type = factory.createType(superClass, factory.createSubstitutor(substitutionMap)); - return factory.createReferenceElementByType(type); - } + @Nullable + public static PsiTypeParameter findTypeParameterInDerived(final PsiClass aClass, final String name) { + for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) { + if (name.equals(typeParameter.getName())) { + return typeParameter; + } + } - @Nullable - public static PsiTypeParameter findTypeParameterInDerived(final PsiClass aClass, final String name) { - for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) { - if (name.equals(typeParameter.getName())) return typeParameter; + return null; } - return null; - } - - public static void checkSuperAccessible(PsiDirectory targetDirectory, MultiMap conflicts, final PsiClass subclass) { - final VirtualFile virtualFile = subclass.getContainingFile().getVirtualFile(); - if (virtualFile != null) { - final boolean inTestSourceContent = ProjectRootManager.getInstance(subclass.getProject()).getFileIndex().isInTestSourceContent(virtualFile); - final Module module = ModuleUtil.findModuleForFile(virtualFile, subclass.getProject()); - if (targetDirectory != null && - module != null && - !GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, inTestSourceContent).contains(targetDirectory.getVirtualFile())) { - conflicts.putValue(subclass, "Superclass won't be accessible in subclass"); - } + public static void checkSuperAccessible(PsiDirectory targetDirectory, MultiMap conflicts, final PsiClass subclass) { + final VirtualFile virtualFile = subclass.getContainingFile().getVirtualFile(); + if (virtualFile != null) { + final boolean inTestSourceContent = + ProjectRootManager.getInstance(subclass.getProject()).getFileIndex().isInTestSourceContent(virtualFile); + final Module module = ModuleUtil.findModuleForFile(virtualFile, subclass.getProject()); + if (targetDirectory != null && + module != null && + !GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, inTestSourceContent) + .contains(targetDirectory.getVirtualFile())) { + conflicts.putValue(subclass, "Superclass won't be accessible in subclass"); + } + } } - } - - public static boolean showConflicts(DialogWrapper dialog, MultiMap conflicts, final Project project) { - if (!conflicts.isEmpty()) { - ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts); - conflictsDialog.show(); - final boolean ok = conflictsDialog.isOK(); - if (!ok && conflictsDialog.isShowConflicts()) dialog.close(DialogWrapper.CANCEL_EXIT_CODE); - return ok; + + @RequiredUIAccess + public static boolean showConflicts(DialogWrapper dialog, MultiMap conflicts, Project project) { + if (!conflicts.isEmpty()) { + ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts); + conflictsDialog.show(); + boolean ok = conflictsDialog.isOK(); + if (!ok && conflictsDialog.isShowConflicts()) { + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } + return ok; + } + return true; } - return true; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/InlineSuperCallUsageInfo.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/InlineSuperCallUsageInfo.java index 0e389bc76..5fc2964ff 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/InlineSuperCallUsageInfo.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/InlineSuperCallUsageInfo.java @@ -30,83 +30,91 @@ import consulo.language.psi.PsiElement; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.usage.UsageInfo; import consulo.util.collection.MultiMap; import jakarta.annotation.Nonnull; public class InlineSuperCallUsageInfo extends FixableUsageInfo { - private PsiCodeBlock myConstrBody; + private PsiCodeBlock myConstrBody; - public InlineSuperCallUsageInfo(PsiMethodCallExpression methodCallExpression) { - super(methodCallExpression); - } - - public InlineSuperCallUsageInfo(PsiMethodCallExpression methodCallExpression, PsiCodeBlock constrBody) { - super(methodCallExpression); - myConstrBody = constrBody; - } + public InlineSuperCallUsageInfo(PsiMethodCallExpression methodCallExpression) { + super(methodCallExpression); + } - @Override - public void fixUsage() throws IncorrectOperationException { - PsiElement element = getElement(); - if (element != null && myConstrBody != null) { - assert !element.isPhysical(); - final PsiStatement statement = JavaPsiFacade.getElementFactory(getProject()).createStatementFromText("super();", myConstrBody); - element = ((PsiExpressionStatement)myConstrBody.addBefore(statement, myConstrBody.getFirstBodyElement())).getExpression(); + public InlineSuperCallUsageInfo(PsiMethodCallExpression methodCallExpression, PsiCodeBlock constrBody) { + super(methodCallExpression); + myConstrBody = constrBody; } - if (element instanceof PsiMethodCallExpression) { - PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)element).getMethodExpression(); - final PsiMethod superConstructor = (PsiMethod)methodExpression.resolve(); - if (superConstructor != null) { - PsiMethod methodCopy = JavaPsiFacade.getElementFactory(getProject()).createMethod("toInline", PsiType.VOID); - final PsiCodeBlock constructorBody = superConstructor.getBody(); - if (constructorBody != null) { - final PsiCodeBlock methodBody = methodCopy.getBody(); - assert methodBody != null; - methodBody.replace(constructorBody); - methodCopy.getParameterList().replace(superConstructor.getParameterList()); - methodCopy.getThrowsList().replace(superConstructor.getThrowsList()); + @Override + public void fixUsage() throws IncorrectOperationException { + PsiElement element = getElement(); + if (element != null && myConstrBody != null) { + assert !element.isPhysical(); + final PsiStatement statement = JavaPsiFacade.getElementFactory(getProject()).createStatementFromText("super();", myConstrBody); + element = ((PsiExpressionStatement) myConstrBody.addBefore(statement, myConstrBody.getFirstBodyElement())).getExpression(); + } + if (element instanceof PsiMethodCallExpression) { + PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) element).getMethodExpression(); + final PsiMethod superConstructor = (PsiMethod) methodExpression.resolve(); + if (superConstructor != null) { + PsiMethod methodCopy = JavaPsiFacade.getElementFactory(getProject()).createMethod("toInline", PsiType.VOID); + final PsiCodeBlock constructorBody = superConstructor.getBody(); + if (constructorBody != null) { + final PsiCodeBlock methodBody = methodCopy.getBody(); + assert methodBody != null; + methodBody.replace(constructorBody); - methodExpression = (PsiReferenceExpression)methodExpression.replace(JavaPsiFacade.getElementFactory(getProject()).createExpressionFromText(methodCopy.getName(), methodExpression)); - final PsiClass inliningClass = superConstructor.getContainingClass(); - assert inliningClass != null; - methodCopy = (PsiMethod)inliningClass.add(methodCopy); - final InlineMethodProcessor inlineMethodProcessor = new InlineMethodProcessor(getProject(), methodCopy, methodExpression, null, true); - inlineMethodProcessor.inlineMethodCall(methodExpression); - methodCopy.delete(); + methodCopy.getParameterList().replace(superConstructor.getParameterList()); + methodCopy.getThrowsList().replace(superConstructor.getThrowsList()); + + methodExpression = (PsiReferenceExpression) methodExpression.replace(JavaPsiFacade.getElementFactory(getProject()) + .createExpressionFromText(methodCopy.getName(), methodExpression)); + final PsiClass inliningClass = superConstructor.getContainingClass(); + assert inliningClass != null; + methodCopy = (PsiMethod) inliningClass.add(methodCopy); + final InlineMethodProcessor inlineMethodProcessor = + new InlineMethodProcessor(getProject(), methodCopy, methodExpression, null, true); + inlineMethodProcessor.inlineMethodCall(methodExpression); + methodCopy.delete(); + } + } } - } } - } - @Override - public String getConflictMessage() { - final MultiMap conflicts = new MultiMap(); - final PsiElement element = getElement(); - if (element instanceof PsiMethodCallExpression) { - PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element; - final PsiMethod superConstructor = methodCallExpression.resolveMethod(); - if (superConstructor != null) { - InlineMethodProcessor.addInaccessibleMemberConflicts(superConstructor, new UsageInfo[]{new UsageInfo(methodCallExpression.getMethodExpression())}, new ReferencedElementsCollector(){ - @Override - protected void checkAddMember(@Nonnull PsiMember member) { - if (!PsiTreeUtil.isAncestor(superConstructor.getContainingClass(), member, false)) { - super.checkAddMember(member); + @Override + public LocalizeValue getConflictMessage() { + MultiMap conflicts = new MultiMap<>(); + final PsiElement element = getElement(); + if (element instanceof PsiMethodCallExpression) { + PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) element; + final PsiMethod superConstructor = methodCallExpression.resolveMethod(); + if (superConstructor != null) { + InlineMethodProcessor.addInaccessibleMemberConflicts( + superConstructor, + new UsageInfo[]{new UsageInfo(methodCallExpression.getMethodExpression())}, + new ReferencedElementsCollector() { + @Override + protected void checkAddMember(@Nonnull PsiMember member) { + if (!PsiTreeUtil.isAncestor(superConstructor.getContainingClass(), member, false)) { + super.checkAddMember(member); + } + } + }, + conflicts + ); + if (InlineMethodProcessor.checkBadReturns(superConstructor) && !InlineUtil.allUsagesAreTailCalls(superConstructor)) { + conflicts.putValue( + superConstructor, + LocalizeValue.localizeTODO(CommonRefactoringUtil.capitalize( + RefactoringLocalize.refactoringIsNotSupportedWhenReturnStatementInterruptsTheExecutionFlow("") + + " of super constructor" + )) + ); + } } - } - }, conflicts); - if (InlineMethodProcessor.checkBadReturns(superConstructor) && !InlineUtil.allUsagesAreTailCalls(superConstructor)) { - conflicts.putValue( - superConstructor, - CommonRefactoringUtil.capitalize( - RefactoringLocalize.refactoringIsNotSupportedWhenReturnStatementInterruptsTheExecutionFlow("").get() + - " of super constructor" - ) - ); } - } + return conflicts.isEmpty() ? null : conflicts.values().iterator().next(); //todo } - return conflicts.isEmpty() ? null : conflicts.values().iterator().next(); //todo - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/ReplaceConstructorUsageInfo.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/ReplaceConstructorUsageInfo.java index 1347cf278..c8912bcd3 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/ReplaceConstructorUsageInfo.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inlineSuperClass/usageInfo/ReplaceConstructorUsageInfo.java @@ -13,131 +13,143 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * User: anna - * Date: 29-Aug-2008 - */ package com.intellij.java.impl.refactoring.inlineSuperClass.usageInfo; import com.intellij.java.impl.refactoring.util.FixableUsageInfo; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.TypeConversionUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; +import consulo.language.psi.PsiElement; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.util.lang.StringUtil; +import jakarta.annotation.Nonnull; -import java.util.function.Function; - -public class ReplaceConstructorUsageInfo extends FixableUsageInfo{ - private final PsiType myNewType; - private String myConflict; - private static final String CONSTRUCTOR_MATCHING_SUPER_NOT_FOUND = "Constructor matching super not found"; +/** + * @author anna + * @since 2008-08-29 + */ +public class ReplaceConstructorUsageInfo extends FixableUsageInfo { + private final PsiType myNewType; + @Nonnull + private LocalizeValue myConflict; + private static final LocalizeValue CONSTRUCTOR_MATCHING_SUPER_NOT_FOUND = + LocalizeValue.localizeTODO("Constructor matching super not found"); - public ReplaceConstructorUsageInfo(PsiNewExpression element, PsiType newType, final PsiClass[] targetClasses) { - super(element); - myNewType = newType; - final PsiMethod[] constructors = targetClasses[0].getConstructors(); - final PsiMethod constructor = element.resolveConstructor(); - if (constructor == null) { - if (constructors.length == 1 && constructors[0].getParameterList().getParametersCount() > 0 || constructors.length > 1) { - myConflict = CONSTRUCTOR_MATCHING_SUPER_NOT_FOUND; - } - } else { - final PsiParameter[] superParameters = constructor.getParameterList().getParameters(); - boolean foundMatchingConstructor = constructors.length == 0 && superParameters.length == 0; - constr: for (PsiMethod method : constructors) { - final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (superParameters.length == parameters.length) { - for (int i = 0; i < parameters.length; i++) { - PsiParameter parameter = parameters[i]; - if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(parameter.getType()), - TypeConversionUtil.erasure(superParameters[i].getType()))) { - continue constr; + @RequiredReadAction + public ReplaceConstructorUsageInfo(PsiNewExpression element, PsiType newType, PsiClass[] targetClasses) { + super(element); + myNewType = newType; + PsiMethod[] constructors = targetClasses[0].getConstructors(); + PsiMethod constructor = element.resolveConstructor(); + if (constructor == null) { + if (constructors.length == 1 && constructors[0].getParameterList().getParametersCount() > 0 || constructors.length > 1) { + myConflict = CONSTRUCTOR_MATCHING_SUPER_NOT_FOUND; } - } - foundMatchingConstructor = true; } - } - if (!foundMatchingConstructor) { - myConflict = CONSTRUCTOR_MATCHING_SUPER_NOT_FOUND; - } + else { + PsiParameter[] superParameters = constructor.getParameterList().getParameters(); + boolean foundMatchingConstructor = constructors.length == 0 && superParameters.length == 0; + constr: + for (PsiMethod method : constructors) { + PsiParameter[] parameters = method.getParameterList().getParameters(); + if (superParameters.length == parameters.length) { + for (int i = 0; i < parameters.length; i++) { + PsiParameter parameter = parameters[i]; + if (!TypeConversionUtil.isAssignable( + TypeConversionUtil.erasure(parameter.getType()), + TypeConversionUtil.erasure(superParameters[i].getType()) + )) { + continue constr; + } + } + foundMatchingConstructor = true; + } + } + if (!foundMatchingConstructor) { + myConflict = CONSTRUCTOR_MATCHING_SUPER_NOT_FOUND; + } - } + } - PsiType type = element.getType(); - if (type == null) { - appendConflict("Type is unknown"); - return; - } else { - type = type.getDeepComponentType(); - } + PsiType type = element.getType(); + if (type == null) { + appendConflict(LocalizeValue.localizeTODO("Type is unknown")); + return; + } + else { + type = type.getDeepComponentType(); + } - if (!TypeConversionUtil.isAssignable(type, newType)) { - final String conflict = "Type parameters do not agree in " + element.getText() + ". " + - "Expected " + newType.getPresentableText() + " but found " + type.getPresentableText(); - appendConflict(conflict); - } + if (!TypeConversionUtil.isAssignable(type, newType)) { + LocalizeValue conflict = LocalizeValue.localizeTODO( + "Type parameters do not agree in " + element.getText() + ". " + + "Expected " + newType.getPresentableText() + " but found " + type.getPresentableText() + ); + appendConflict(conflict); + } - if (targetClasses.length > 1) { - final String conflict = "Constructor " + element.getText() + " can be replaced with any of " + StringUtil.join(targetClasses, new Function() { - public String apply(final PsiClass psiClass) { - return psiClass.getQualifiedName(); + if (targetClasses.length > 1) { + LocalizeValue conflict = LocalizeValue.localizeTODO( + "Constructor " + element.getText() + " can be replaced with any of " + + StringUtil.join(targetClasses, PsiClass::getQualifiedName, ", ") + ); + appendConflict(conflict); } - }, ", "); - appendConflict(conflict); } - } - private void appendConflict(final String conflict) { - if (myConflict == null) { - myConflict = conflict; - } else { - myConflict += "\n" + conflict; + private void appendConflict(@Nonnull LocalizeValue conflict) { + if (myConflict == LocalizeValue.empty()) { + myConflict = conflict; + } + else { + myConflict = LocalizeValue.join(myConflict, LocalizeValue.of("\n"), conflict); + } } - } - public void fixUsage() throws IncorrectOperationException { - final PsiNewExpression newExpression = (PsiNewExpression)getElement(); - if (newExpression != null) { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(newExpression.getProject()).getElementFactory(); + @Override + @RequiredWriteAction + public void fixUsage() throws IncorrectOperationException { + PsiNewExpression newExpression = (PsiNewExpression) getElement(); + if (newExpression != null) { + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(newExpression.getProject()).getElementFactory(); - final StringBuffer buf = new StringBuffer(); - buf.append("new ").append(myNewType.getCanonicalText()); - final PsiArrayInitializerExpression arrayInitializer = newExpression.getArrayInitializer(); - final PsiType newExpressionType = newExpression.getType(); - assert newExpressionType != null; - if (arrayInitializer != null) { - for (int i = 0; i < newExpressionType.getArrayDimensions(); i++) { - buf.append("[]"); - } - buf.append(arrayInitializer.getText()); - } - else { - final PsiExpression[] arrayDimensions = newExpression.getArrayDimensions(); - if (arrayDimensions.length > 0) { - buf.append("["); - buf.append(StringUtil.join(arrayDimensions, new Function() { - public String apply(PsiExpression psiExpression) { - return psiExpression.getText(); + StringBuilder buf = new StringBuilder(); + buf.append("new ").append(myNewType.getCanonicalText()); + PsiArrayInitializerExpression arrayInitializer = newExpression.getArrayInitializer(); + PsiType newExpressionType = newExpression.getType(); + assert newExpressionType != null; + if (arrayInitializer != null) { + for (int i = 0; i < newExpressionType.getArrayDimensions(); i++) { + buf.append("[]"); + } + buf.append(arrayInitializer.getText()); + } + else { + PsiExpression[] arrayDimensions = newExpression.getArrayDimensions(); + if (arrayDimensions.length > 0) { + buf.append("["); + buf.append(StringUtil.join(arrayDimensions, PsiElement::getText, "][")); + buf.append("]"); + for (int i = 0; i < newExpressionType.getArrayDimensions() - arrayDimensions.length; i++) { + buf.append("[]"); + } + } + else { + PsiExpressionList list = newExpression.getArgumentList(); + if (list != null) { + buf.append(list.getText()); + } + } } - }, "][")); - buf.append("]"); - for (int i = 0; i < newExpressionType.getArrayDimensions() - arrayDimensions.length; i++) { - buf.append("[]"); - } - } else { - final PsiExpressionList list = newExpression.getArgumentList(); - if (list != null) { - buf.append(list.getText()); - } - } - } - newExpression.replace(elementFactory.createExpressionFromText(buf.toString(), newExpression)); + newExpression.replace(elementFactory.createExpressionFromText(buf.toString(), newExpression)); + } } - } - public String getConflictMessage() { - return myConflict; - } + @Override + public LocalizeValue getConflictMessage() { + return myConflict; + } } \ No newline at end of file diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/BaseExpressionToFieldHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/BaseExpressionToFieldHandler.java index 154955a55..0e4af8239 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/BaseExpressionToFieldHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/BaseExpressionToFieldHandler.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: 29.05.2002 - * Time: 13:05:34 - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.java.impl.refactoring.introduceField; import com.intellij.java.impl.codeInsight.PackageUtil; @@ -78,90 +69,101 @@ import java.util.HashMap; import java.util.List; +/** + * @author dsl + * @since 2002-05-29 + */ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase { - protected static final Logger LOG = Logger.getInstance(BaseExpressionToFieldHandler.class); + protected static final Logger LOG = Logger.getInstance(BaseExpressionToFieldHandler.class); - public enum InitializationPlace { - IN_CURRENT_METHOD, - IN_FIELD_DECLARATION, - IN_CONSTRUCTOR, - IN_SETUP_METHOD - } + public enum InitializationPlace { + IN_CURRENT_METHOD, + IN_FIELD_DECLARATION, + IN_CONSTRUCTOR, + IN_SETUP_METHOD + } - private final boolean myIsConstant; - private PsiClass myParentClass; + private final boolean myIsConstant; + private PsiClass myParentClass; - protected BaseExpressionToFieldHandler(boolean isConstant) { - myIsConstant = isConstant; - } + protected BaseExpressionToFieldHandler(boolean isConstant) { + myIsConstant = isConstant; + } - @RequiredUIAccess - protected boolean invokeImpl(final Project project, @Nonnull final PsiExpression selectedExpr, final Editor editor) { - final PsiElement element = getPhysicalElement(selectedExpr); + @RequiredUIAccess + protected boolean invokeImpl(final Project project, @Nonnull final PsiExpression selectedExpr, final Editor editor) { + final PsiElement element = getPhysicalElement(selectedExpr); - final PsiFile file = element.getContainingFile(); - LOG.assertTrue(file != null, "expr.getContainingFile() == null"); + final PsiFile file = element.getContainingFile(); + LOG.assertTrue(file != null, "expr.getContainingFile() == null"); - if (LOG.isDebugEnabled()) { - LOG.debug("expression:" + selectedExpr); - } + if (LOG.isDebugEnabled()) { + LOG.debug("expression:" + selectedExpr); + } - final PsiType tempType = getTypeByExpression(selectedExpr); - if (tempType == null || LambdaUtil.notInferredType(tempType)) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.unknownExpressionType()); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), getRefactoringName(), getHelpID()); - return false; - } + final PsiType tempType = getTypeByExpression(selectedExpr); + if (tempType == null || LambdaUtil.notInferredType(tempType)) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.unknownExpressionType()); + CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringName(), getHelpID()); + return false; + } - if (PsiType.VOID.equals(tempType)) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedExpressionHasVoidType()); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), getRefactoringName(), getHelpID()); - return false; - } + if (PsiType.VOID.equals(tempType)) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedExpressionHasVoidType()); + CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringName(), getHelpID()); + return false; + } - myParentClass = getParentClass(selectedExpr); - final List classes = new ArrayList(); - PsiClass aClass = myParentClass; - while (aClass != null) { - classes.add(aClass); - final PsiField psiField = ConvertToFieldRunnable.checkForwardRefs(selectedExpr, aClass); - if (psiField != null && psiField.getParent() == aClass) break; - aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); - } - final AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); - final boolean shouldSuggestDialog = activeIntroducer instanceof InplaceIntroduceConstantPopup && - activeIntroducer.startsOnTheSameElement(selectedExpr, null); - if (classes.size() == 1 || editor == null || ApplicationManager.getApplication().isUnitTestMode() || shouldSuggestDialog) { - return !convertExpressionToField(selectedExpr, editor, file, project, tempType); - } - else { - PsiClass selection = null; - for (PsiClass psiClass : classes) { - if (!(psiClass instanceof PsiAnonymousClass)) { - selection = psiClass; - break; + myParentClass = getParentClass(selectedExpr); + final List classes = new ArrayList(); + PsiClass aClass = myParentClass; + while (aClass != null) { + classes.add(aClass); + final PsiField psiField = ConvertToFieldRunnable.checkForwardRefs(selectedExpr, aClass); + if (psiField != null && psiField.getParent() == aClass) { + break; + } + aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); } - } - JBPopup popup = PopupNavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), new PsiClassListCellRenderer(), - "Choose class to introduce " + (myIsConstant ? "constant" : "field"), - new PsiElementProcessor() { - @Override - public boolean execute(@Nonnull PsiClass aClass) { - myParentClass = aClass; - convertExpressionToField(selectedExpr, editor, file, project, tempType); - return false; + final AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); + final boolean shouldSuggestDialog = activeIntroducer instanceof InplaceIntroduceConstantPopup && + activeIntroducer.startsOnTheSameElement(selectedExpr, null); + if (classes.size() == 1 || editor == null || ApplicationManager.getApplication().isUnitTestMode() || shouldSuggestDialog) { + return !convertExpressionToField(selectedExpr, editor, file, project, tempType); + } + else { + PsiClass selection = null; + for (PsiClass psiClass : classes) { + if (!(psiClass instanceof PsiAnonymousClass)) { + selection = psiClass; + break; } - }, selection); - EditorPopupHelper.getInstance().showPopupInBestPositionFor(editor, popup); + } + JBPopup popup = + PopupNavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), new PsiClassListCellRenderer(), + "Choose class to introduce " + (myIsConstant ? "constant" : "field"), + new PsiElementProcessor() { + @Override + public boolean execute(@Nonnull PsiClass aClass) { + myParentClass = aClass; + convertExpressionToField(selectedExpr, editor, file, project, tempType); + return false; + } + }, selection + ); + EditorPopupHelper.getInstance().showPopupInBestPositionFor(editor, popup); + } + return true; } - return true; - } - - private boolean convertExpressionToField(PsiExpression selectedExpr, - @Nullable Editor editor, - PsiFile file, - final Project project, - PsiType tempType) { + + private boolean convertExpressionToField( + PsiExpression selectedExpr, + @Nullable Editor editor, + PsiFile file, + final Project project, + PsiType tempType + ) { /*if (myParentClass == null) { if (JspPsiUtil.isInJspFile(file)) { CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.message("error.not.supported.for.jsp", getRefactoringName()), @@ -174,754 +176,856 @@ private boolean convertExpressionToField(PsiExpression selectedExpr, } } */ - if (!validClass(myParentClass, editor)) { - return true; - } + if (!validClass(myParentClass, editor)) { + return true; + } - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return true; + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { + return true; + } - final OccurrenceManager occurrenceManager = createOccurrenceManager(selectedExpr, myParentClass); - final PsiExpression[] occurrences = occurrenceManager.getOccurrences(); - final PsiElement anchorStatementIfAll = occurrenceManager.getAnchorStatementForAll(); + final OccurrenceManager occurrenceManager = createOccurrenceManager(selectedExpr, myParentClass); + final PsiExpression[] occurrences = occurrenceManager.getOccurrences(); + final PsiElement anchorStatementIfAll = occurrenceManager.getAnchorStatementForAll(); - List highlighters = null; - if (editor != null) { - highlighters = RefactoringUtil.highlightAllOccurrences(project, occurrences, editor); - } + List highlighters = null; + if (editor != null) { + highlighters = RefactoringUtil.highlightAllOccurrences(project, occurrences, editor); + } - PsiElement tempAnchorElement = RefactoringUtil.getParentExpressionAnchorElement(selectedExpr); - if (!Comparing.strEqual(IntroduceConstantHandlerImpl.REFACTORING_NAME, getRefactoringName()) && - IntroduceVariableBase.checkAnchorBeforeThisOrSuper(project, editor, tempAnchorElement, getRefactoringName(), getHelpID())) - return true; + PsiElement tempAnchorElement = RefactoringUtil.getParentExpressionAnchorElement(selectedExpr); + if (!IntroduceConstantHandlerImpl.REFACTORING_NAME.equals(getRefactoringName()) + && IntroduceVariableBase.checkAnchorBeforeThisOrSuper(project, editor, tempAnchorElement, getRefactoringName(), getHelpID())) { + return true; + } - final Settings settings = - showRefactoringDialog(project, editor, myParentClass, selectedExpr, tempType, - occurrences, tempAnchorElement, anchorStatementIfAll); + final Settings settings = + showRefactoringDialog(project, editor, myParentClass, selectedExpr, tempType, + occurrences, tempAnchorElement, anchorStatementIfAll + ); - if (settings == null) return true; + if (settings == null) { + return true; + } - if (settings.getForcedType() != null) { - tempType = settings.getForcedType(); - } - final PsiType type = tempType; + if (settings.getForcedType() != null) { + tempType = settings.getForcedType(); + } + final PsiType type = tempType; - if (editor != null) { - HighlightManager highlightManager = HighlightManager.getInstance(project); - for (RangeHighlighter highlighter : highlighters) { - highlightManager.removeSegmentHighlighter(editor, highlighter); - } - } + if (editor != null) { + HighlightManager highlightManager = HighlightManager.getInstance(project); + for (RangeHighlighter highlighter : highlighters) { + highlightManager.removeSegmentHighlighter(editor, highlighter); + } + } - final Runnable runnable = - new ConvertToFieldRunnable(settings.getSelectedExpr(), settings, type, settings.getOccurrences(), occurrenceManager, - anchorStatementIfAll, tempAnchorElement, editor, - myParentClass); + final Runnable runnable = + new ConvertToFieldRunnable(settings.getSelectedExpr(), settings, type, settings.getOccurrences(), occurrenceManager, + anchorStatementIfAll, tempAnchorElement, editor, + myParentClass + ); - new WriteCommandAction(project, getRefactoringName()){ - @Override - protected void run(Result result) throws Throwable { - runnable.run(); - } - }.execute(); - return false; - } - - public static void setModifiers(PsiField field, Settings settings) { - if (!settings.isIntroduceEnumConstant()) { - if (settings.isDeclareStatic()) { - PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true); - } - if (settings.isDeclareFinal()) { - PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true); - } - if (settings.isAnnotateAsNonNls()) { - PsiAnnotation annotation = JavaPsiFacade.getInstance(field.getProject()).getElementFactory() - .createAnnotationFromText("@" + AnnotationUtil.NON_NLS, field); - final PsiModifierList modifierList = field.getModifierList(); - LOG.assertTrue(modifierList != null); - modifierList.addAfter(annotation, null); - } - } - JavaCodeStyleManager.getInstance(field.getProject()).shortenClassReferences(field); - } - - public static PsiElement getPhysicalElement(final PsiExpression selectedExpr) { - PsiElement element = selectedExpr.getUserData(ElementToWorkOn.PARENT); - if (element == null) element = selectedExpr; - return element; - } - - protected abstract OccurrenceManager createOccurrenceManager(PsiExpression selectedExpr, PsiClass parentClass); - - protected final PsiClass getParentClass() { - return myParentClass; - } - - protected abstract boolean validClass(PsiClass parentClass, Editor editor); - - private static PsiElement getNormalizedAnchor(PsiElement anchorElement) { - PsiElement child = anchorElement; - while (child != null) { - PsiElement prev = child.getPrevSibling(); - if (RefactoringUtil.isExpressionAnchorElement(prev)) break; - if (prev instanceof PsiJavaToken && ((PsiJavaToken)prev).getTokenType() == JavaTokenType.LBRACE) break; - child = prev; + new WriteCommandAction(project, getRefactoringName().get()) { + @Override + protected void run(Result result) throws Throwable { + runnable.run(); + } + }.execute(); + return false; } - child = PsiTreeUtil.skipSiblingsForward(child, PsiWhiteSpace.class, PsiComment.class); - PsiElement anchor; - if (child != null) { - anchor = child; - } - else { - anchor = anchorElement; + public static void setModifiers(PsiField field, Settings settings) { + if (!settings.isIntroduceEnumConstant()) { + if (settings.isDeclareStatic()) { + PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true); + } + if (settings.isDeclareFinal()) { + PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true); + } + if (settings.isAnnotateAsNonNls()) { + PsiAnnotation annotation = JavaPsiFacade.getInstance(field.getProject()).getElementFactory() + .createAnnotationFromText("@" + AnnotationUtil.NON_NLS, field); + final PsiModifierList modifierList = field.getModifierList(); + LOG.assertTrue(modifierList != null); + modifierList.addAfter(annotation, null); + } + } + JavaCodeStyleManager.getInstance(field.getProject()).shortenClassReferences(field); } - return anchor; - } - - protected abstract String getHelpID(); - - protected abstract Settings showRefactoringDialog(Project project, Editor editor, PsiClass parentClass, PsiExpression expr, - PsiType type, PsiExpression[] occurrences, PsiElement anchorElement, - PsiElement anchorElementIfAll); + public static PsiElement getPhysicalElement(final PsiExpression selectedExpr) { + PsiElement element = selectedExpr.getUserData(ElementToWorkOn.PARENT); + if (element == null) { + element = selectedExpr; + } + return element; + } - private static PsiType getTypeByExpression(PsiExpression expr) { - return RefactoringUtil.getTypeByExpressionWithExpectedType(expr); - } + protected abstract OccurrenceManager createOccurrenceManager(PsiExpression selectedExpr, PsiClass parentClass); - public PsiClass getParentClass(@Nonnull PsiExpression initializerExpression) { - PsiElement element = initializerExpression.getUserData(ElementToWorkOn.PARENT); - if (element == null) element = initializerExpression.getParent(); - PsiElement parent = element; - while (parent != null) { - if (parent instanceof PsiClass && !(parent instanceof PsiAnonymousClass && myIsConstant)) { - return (PsiClass)parent; - } - parent = parent.getParent(); - } - return null; - } - - public static PsiMethod getEnclosingConstructor(PsiClass parentClass, PsiElement element) { - if (element == null) return null; - final PsiMethod[] constructors = parentClass.getConstructors(); - for (PsiMethod constructor : constructors) { - if (PsiTreeUtil.isAncestor(constructor, element, false)) { - if (PsiTreeUtil.getParentOfType(element, PsiClass.class) != parentClass) return null; - return constructor; - } - } - return null; - } - - private static void addInitializationToSetUp(final PsiExpression initializer, - final PsiField field, - final PsiExpression[] occurrences, - final boolean replaceAll, - final PsiClass parentClass) throws IncorrectOperationException { - final PsiMethod setupMethod = TestFrameworks.getInstance().findOrCreateSetUpMethod(parentClass); - - assert setupMethod != null; - - PsiElement anchor = null; - if (PsiTreeUtil.isAncestor(setupMethod, initializer, true)) { - anchor = replaceAll - ? RefactoringUtil.getAnchorElementForMultipleExpressions(occurrences, setupMethod) - : PsiTreeUtil.getParentOfType(initializer, PsiStatement.class); + protected final PsiClass getParentClass() { + return myParentClass; } - final PsiExpressionStatement expressionStatement = - (PsiExpressionStatement)JavaPsiFacade.getInstance(parentClass.getProject()).getElementFactory() - .createStatementFromText(field.getName() + "= expr;", null); - PsiAssignmentExpression expr = (PsiAssignmentExpression)expressionStatement.getExpression(); - final PsiExpression rExpression = expr.getRExpression(); - LOG.assertTrue(rExpression != null); - rExpression.replace(initializer); - - final PsiCodeBlock body = setupMethod.getBody(); - assert body != null; - body.addBefore(expressionStatement, anchor); - } - - private static void addInitializationToConstructors(PsiExpression initializerExpression, - PsiField field, - PsiMethod enclosingConstructor, final PsiClass parentClass) { - try { - PsiClass aClass = field.getContainingClass(); - PsiMethod[] constructors = aClass.getConstructors(); - - boolean added = false; - for (PsiMethod constructor : constructors) { - if (constructor == enclosingConstructor) continue; - PsiCodeBlock body = constructor.getBody(); - if (body == null) continue; - PsiStatement[] statements = body.getStatements(); - if (statements.length > 0) { - PsiStatement first = statements[0]; - if (first instanceof PsiExpressionStatement) { - PsiExpression expression = ((PsiExpressionStatement)first).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - @NonNls String text = ((PsiMethodCallExpression)expression).getMethodExpression().getText(); - if ("this".equals(text)) { - continue; - } + protected abstract boolean validClass(PsiClass parentClass, Editor editor); + + private static PsiElement getNormalizedAnchor(PsiElement anchorElement) { + PsiElement child = anchorElement; + while (child != null) { + PsiElement prev = child.getPrevSibling(); + if (RefactoringUtil.isExpressionAnchorElement(prev)) { + break; } - } + if (prev instanceof PsiJavaToken && ((PsiJavaToken) prev).getTokenType() == JavaTokenType.LBRACE) { + break; + } + child = prev; } - PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild(), parentClass); - assignment = (PsiStatement) body.add(assignment); - ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(), - RefactoringChangeUtil.createThisExpression(field.getManager(), null)); - added = true; - } - if (!added && enclosingConstructor == null) { - PsiElementFactory factory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory(); - PsiMethod constructor = (PsiMethod)aClass.add(factory.createConstructor()); - final PsiCodeBlock body = constructor.getBody(); - PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild(), parentClass); - assignment = (PsiStatement) body.add(assignment); - ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(), - RefactoringChangeUtil.createThisExpression(field.getManager(), null)); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - private static PsiField createField(String fieldName, - PsiType type, - PsiExpression initializerExpr, - boolean includeInitializer, final PsiClass parentClass) { - @NonNls StringBuilder pattern = new StringBuilder(); - pattern.append("private int "); - pattern.append(fieldName); - if (includeInitializer) { - pattern.append("=0"); - } - pattern.append(";"); - PsiManager psiManager = parentClass.getManager(); - PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); - try { - PsiField field = factory.createFieldFromText(pattern.toString(), null); - field = (PsiField)CodeStyleManager.getInstance(psiManager.getProject()).reformat(field); - field.getTypeElement().replace(factory.createTypeElement(type)); - if (includeInitializer) { - field.getInitializer().replace(initializerExpr); - } - return field; - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; - } - } - - private static PsiStatement createAssignment(PsiField field, - PsiExpression initializerExpr, - PsiElement context, - final PsiClass parentClass) { - try { - @NonNls String pattern = "x=0;"; - PsiManager psiManager = parentClass.getManager(); - PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); - PsiExpressionStatement statement = (PsiExpressionStatement)factory.createStatementFromText(pattern, null); - statement = (PsiExpressionStatement)CodeStyleManager.getInstance(psiManager.getProject()).reformat(statement); - - PsiAssignmentExpression expr = (PsiAssignmentExpression)statement.getExpression(); - final PsiExpression rExpression = expr.getRExpression(); - LOG.assertTrue(rExpression != null); - rExpression.replace(initializerExpr); - final PsiReferenceExpression fieldReference = RenameJavaVariableProcessor.createMemberReference(field, context); - expr.getLExpression().replace(fieldReference); - - return statement; - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; - } - } - - protected abstract boolean accept(ElementToWorkOn elementToWorkOn); - protected ElementToWorkOn.ElementsProcessor getElementProcessor(final Project project, final Editor editor) { - return new ElementToWorkOn.ElementsProcessor() { - @Override - public boolean accept(ElementToWorkOn el) { - return BaseExpressionToFieldHandler.this.accept(el); - } - - @Override - public void pass(final ElementToWorkOn elementToWorkOn) { - if (elementToWorkOn == null) return; - - final boolean hasRunTemplate = LookupManager.getActiveLookup(editor) == null; - if (elementToWorkOn.getExpression() == null) { - final PsiLocalVariable localVariable = elementToWorkOn.getLocalVariable(); - final boolean result = invokeImpl(project, localVariable, editor) && hasRunTemplate; - if (result) { - editor.getSelectionModel().removeSelection(); - } + child = PsiTreeUtil.skipSiblingsForward(child, PsiWhiteSpace.class, PsiComment.class); + PsiElement anchor; + if (child != null) { + anchor = child; } else { - if (invokeImpl(project, elementToWorkOn.getExpression(), editor) && hasRunTemplate) { - editor.getSelectionModel().removeSelection(); - } + anchor = anchorElement; } - } - }; - } - - protected abstract String getRefactoringName(); - - public static class Settings { - private final String myFieldName; - private final PsiType myForcedType; - - private final boolean myReplaceAll; - private final boolean myDeclareStatic; - private final boolean myDeclareFinal; - private final InitializationPlace myInitializerPlace; - private final String myVisibility; - private final boolean myDeleteLocalVariable; - private final TargetDestination myTargetClass; - private final boolean myAnnotateAsNonNls; - private final boolean myIntroduceEnumConstant; - private final PsiExpression mySelectedExpr; - private PsiExpression[] myOccurrences; - - public PsiLocalVariable getLocalVariable() { - return myLocalVariable; + return anchor; } - public boolean isDeleteLocalVariable() { - return myDeleteLocalVariable; - } + protected abstract String getHelpID(); - private final PsiLocalVariable myLocalVariable; + protected abstract Settings showRefactoringDialog( + Project project, Editor editor, PsiClass parentClass, PsiExpression expr, + PsiType type, PsiExpression[] occurrences, PsiElement anchorElement, + PsiElement anchorElementIfAll + ); - public String getFieldName() { - return myFieldName; - } - public boolean isDeclareStatic() { - return myDeclareStatic; + private static PsiType getTypeByExpression(PsiExpression expr) { + return RefactoringUtil.getTypeByExpressionWithExpectedType(expr); } - public boolean isDeclareFinal() { - return myDeclareFinal; + public PsiClass getParentClass(@Nonnull PsiExpression initializerExpression) { + PsiElement element = initializerExpression.getUserData(ElementToWorkOn.PARENT); + if (element == null) { + element = initializerExpression.getParent(); + } + PsiElement parent = element; + while (parent != null) { + if (parent instanceof PsiClass && !(parent instanceof PsiAnonymousClass && myIsConstant)) { + return (PsiClass) parent; + } + parent = parent.getParent(); + } + return null; } - public InitializationPlace getInitializerPlace() { - return myInitializerPlace; + public static PsiMethod getEnclosingConstructor(PsiClass parentClass, PsiElement element) { + if (element == null) { + return null; + } + final PsiMethod[] constructors = parentClass.getConstructors(); + for (PsiMethod constructor : constructors) { + if (PsiTreeUtil.isAncestor(constructor, element, false)) { + if (PsiTreeUtil.getParentOfType(element, PsiClass.class) != parentClass) { + return null; + } + return constructor; + } + } + return null; } - public String getFieldVisibility() { - return myVisibility; - } + private static void addInitializationToSetUp( + final PsiExpression initializer, + final PsiField field, + final PsiExpression[] occurrences, + final boolean replaceAll, + final PsiClass parentClass + ) throws IncorrectOperationException { + final PsiMethod setupMethod = TestFrameworks.getInstance().findOrCreateSetUpMethod(parentClass); + + assert setupMethod != null; + + PsiElement anchor = null; + if (PsiTreeUtil.isAncestor(setupMethod, initializer, true)) { + anchor = replaceAll + ? RefactoringUtil.getAnchorElementForMultipleExpressions(occurrences, setupMethod) + : PsiTreeUtil.getParentOfType(initializer, PsiStatement.class); + } - @Nullable - public PsiClass getDestinationClass() { - return myTargetClass != null ? myTargetClass.getTargetClass() : null; + final PsiExpressionStatement expressionStatement = + (PsiExpressionStatement) JavaPsiFacade.getInstance(parentClass.getProject()).getElementFactory() + .createStatementFromText(field.getName() + "= expr;", null); + PsiAssignmentExpression expr = (PsiAssignmentExpression) expressionStatement.getExpression(); + final PsiExpression rExpression = expr.getRExpression(); + LOG.assertTrue(rExpression != null); + rExpression.replace(initializer); + + final PsiCodeBlock body = setupMethod.getBody(); + assert body != null; + body.addBefore(expressionStatement, anchor); } - public PsiType getForcedType() { - return myForcedType; + private static void addInitializationToConstructors( + PsiExpression initializerExpression, + PsiField field, + PsiMethod enclosingConstructor, final PsiClass parentClass + ) { + try { + PsiClass aClass = field.getContainingClass(); + PsiMethod[] constructors = aClass.getConstructors(); + + boolean added = false; + for (PsiMethod constructor : constructors) { + if (constructor == enclosingConstructor) { + continue; + } + PsiCodeBlock body = constructor.getBody(); + if (body == null) { + continue; + } + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0) { + PsiStatement first = statements[0]; + if (first instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement) first).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + @NonNls String text = ((PsiMethodCallExpression) expression).getMethodExpression().getText(); + if ("this".equals(text)) { + continue; + } + } + } + } + PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild(), parentClass); + assignment = (PsiStatement) body.add(assignment); + ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(), + RefactoringChangeUtil.createThisExpression(field.getManager(), null) + ); + added = true; + } + if (!added && enclosingConstructor == null) { + PsiElementFactory factory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory(); + PsiMethod constructor = (PsiMethod) aClass.add(factory.createConstructor()); + final PsiCodeBlock body = constructor.getBody(); + PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild(), parentClass); + assignment = (PsiStatement) body.add(assignment); + ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(), + RefactoringChangeUtil.createThisExpression(field.getManager(), null) + ); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - public boolean isReplaceAll() { - return myReplaceAll; + private static PsiField createField( + String fieldName, + PsiType type, + PsiExpression initializerExpr, + boolean includeInitializer, final PsiClass parentClass + ) { + @NonNls StringBuilder pattern = new StringBuilder(); + pattern.append("private int "); + pattern.append(fieldName); + if (includeInitializer) { + pattern.append("=0"); + } + pattern.append(";"); + PsiManager psiManager = parentClass.getManager(); + PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); + try { + PsiField field = factory.createFieldFromText(pattern.toString(), null); + field = (PsiField) CodeStyleManager.getInstance(psiManager.getProject()).reformat(field); + field.getTypeElement().replace(factory.createTypeElement(type)); + if (includeInitializer) { + field.getInitializer().replace(initializerExpr); + } + return field; + } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; + } } - public boolean isAnnotateAsNonNls() { - return myAnnotateAsNonNls; + private static PsiStatement createAssignment( + PsiField field, + PsiExpression initializerExpr, + PsiElement context, + final PsiClass parentClass + ) { + try { + @NonNls String pattern = "x=0;"; + PsiManager psiManager = parentClass.getManager(); + PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); + PsiExpressionStatement statement = (PsiExpressionStatement) factory.createStatementFromText(pattern, null); + statement = (PsiExpressionStatement) CodeStyleManager.getInstance(psiManager.getProject()).reformat(statement); + + PsiAssignmentExpression expr = (PsiAssignmentExpression) statement.getExpression(); + final PsiExpression rExpression = expr.getRExpression(); + LOG.assertTrue(rExpression != null); + rExpression.replace(initializerExpr); + final PsiReferenceExpression fieldReference = RenameJavaVariableProcessor.createMemberReference(field, context); + expr.getLExpression().replace(fieldReference); + + return statement; + } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; + } } - public boolean isIntroduceEnumConstant() { - return myIntroduceEnumConstant; - } + protected abstract boolean accept(ElementToWorkOn elementToWorkOn); - public Settings(String fieldName, - PsiExpression selectedExpr, - PsiExpression[] occurrences, - boolean replaceAll, - boolean declareStatic, boolean declareFinal, - InitializationPlace initializerPlace, String visibility, PsiLocalVariable localVariableToRemove, PsiType forcedType, - boolean deleteLocalVariable, - TargetDestination targetDestination, - final boolean annotateAsNonNls, - final boolean introduceEnumConstant) { - - myFieldName = fieldName; - myOccurrences = occurrences; - mySelectedExpr = selectedExpr; - myReplaceAll = replaceAll; - myDeclareStatic = declareStatic; - myDeclareFinal = declareFinal; - myInitializerPlace = initializerPlace; - myVisibility = visibility; - myLocalVariable = localVariableToRemove; - myDeleteLocalVariable = deleteLocalVariable; - myForcedType = forcedType; - myTargetClass = targetDestination; - myAnnotateAsNonNls = annotateAsNonNls; - myIntroduceEnumConstant = introduceEnumConstant; - } + protected ElementToWorkOn.ElementsProcessor getElementProcessor(final Project project, final Editor editor) { + return new ElementToWorkOn.ElementsProcessor() { + @Override + public boolean accept(ElementToWorkOn el) { + return BaseExpressionToFieldHandler.this.accept(el); + } - public Settings(String fieldName, - PsiExpression selectedExpression, - PsiExpression[] occurrences, - boolean replaceAll, - boolean declareStatic, boolean declareFinal, - InitializationPlace initializerPlace, String visibility, PsiLocalVariable localVariableToRemove, PsiType forcedType, - boolean deleteLocalVariable, - PsiClass targetClass, - final boolean annotateAsNonNls, - final boolean introduceEnumConstant) { - - this(fieldName, selectedExpression, occurrences, replaceAll, declareStatic, declareFinal, initializerPlace, visibility, localVariableToRemove, forcedType, deleteLocalVariable, new TargetDestination(targetClass), annotateAsNonNls, introduceEnumConstant); - } + @Override + public void pass(final ElementToWorkOn elementToWorkOn) { + if (elementToWorkOn == null) { + return; + } - public PsiExpression getSelectedExpr() { - return mySelectedExpr; + final boolean hasRunTemplate = LookupManager.getActiveLookup(editor) == null; + if (elementToWorkOn.getExpression() == null) { + final PsiLocalVariable localVariable = elementToWorkOn.getLocalVariable(); + final boolean result = invokeImpl(project, localVariable, editor) && hasRunTemplate; + if (result) { + editor.getSelectionModel().removeSelection(); + } + } + else { + if (invokeImpl(project, elementToWorkOn.getExpression(), editor) && hasRunTemplate) { + editor.getSelectionModel().removeSelection(); + } + } + } + }; } - public PsiExpression[] getOccurrences() { - return myOccurrences; - } + protected abstract LocalizeValue getRefactoringName(); + + public static class Settings { + private final String myFieldName; + private final PsiType myForcedType; + + private final boolean myReplaceAll; + private final boolean myDeclareStatic; + private final boolean myDeclareFinal; + private final InitializationPlace myInitializerPlace; + private final String myVisibility; + private final boolean myDeleteLocalVariable; + private final TargetDestination myTargetClass; + private final boolean myAnnotateAsNonNls; + private final boolean myIntroduceEnumConstant; + private final PsiExpression mySelectedExpr; + private PsiExpression[] myOccurrences; + + public PsiLocalVariable getLocalVariable() { + return myLocalVariable; + } - public void setOccurrences(PsiExpression[] occurrences) { - myOccurrences = occurrences; - } - } + public boolean isDeleteLocalVariable() { + return myDeleteLocalVariable; + } - public static class TargetDestination { - private final String myQualifiedName; - private final Project myProject; + private final PsiLocalVariable myLocalVariable; - private PsiClass myParentClass; - private PsiClass myTargetClass; + public String getFieldName() { + return myFieldName; + } - public TargetDestination(String qualifiedName, PsiClass parentClass) { - myQualifiedName = qualifiedName; - myParentClass = parentClass; - myProject = parentClass.getProject(); - } + public boolean isDeclareStatic() { + return myDeclareStatic; + } - public TargetDestination(@Nonnull PsiClass targetClass) { - myTargetClass = targetClass; - myQualifiedName = targetClass.getQualifiedName(); - myProject = targetClass.getProject(); - } + public boolean isDeclareFinal() { + return myDeclareFinal; + } - @Nullable - public PsiClass getTargetClass() { - if (myTargetClass != null) return myTargetClass; - final String packageName = StringUtil.getPackageName(myQualifiedName); - final String shortName = StringUtil.getShortName(myQualifiedName); - if (Comparing.strEqual(myParentClass.getQualifiedName(), packageName)) { - myTargetClass = (PsiClass)myParentClass.add(JavaPsiFacade.getElementFactory(myProject).createClass(shortName)); - return myTargetClass; - } - PsiJavaPackage psiPackage = JavaPsiFacade.getInstance(myProject).findPackage(packageName); - final PsiDirectory psiDirectory; - if (psiPackage != null) { - final PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.allScope(myProject)); - psiDirectory = directories.length > 1 ? DirectoryChooserUtil.chooseDirectory(directories, null, myProject, new HashMap()) : directories[0]; - } else { - psiDirectory = PackageUtil.findOrCreateDirectoryForPackage(myProject, packageName, myParentClass.getContainingFile().getContainingDirectory(), false); - } - myTargetClass = psiDirectory != null ? JavaDirectoryService.getInstance().createClass(psiDirectory, shortName) : null; - return myTargetClass; - } - } - - public static class ConvertToFieldRunnable implements Runnable { - private PsiExpression mySelectedExpr; - private final Settings mySettings; - private final PsiElement myAnchorElement; - private final Project myProject; - private final String myFieldName; - private final PsiType myType; - private final PsiExpression[] myOccurrences; - private final boolean myReplaceAll; - private final OccurrenceManager myOccurrenceManager; - private final PsiElement myAnchorStatementIfAll; - private final PsiElement myAnchorElementIfOne; - private final Boolean myOutOfCodeBlockExtraction; - private final PsiElement myElement; - private boolean myDeleteSelf; - private final Editor myEditor; - private final PsiClass myParentClass; - - private PsiField myField; - - public ConvertToFieldRunnable(PsiExpression selectedExpr, - Settings settings, - PsiType type, - PsiExpression[] occurrences, - OccurrenceManager occurrenceManager, - PsiElement anchorStatementIfAll, - PsiElement anchorElementIfOne, - Editor editor, - PsiClass parentClass) { - mySelectedExpr = selectedExpr; - mySettings = settings; - myAnchorElement = settings.isReplaceAll() ? anchorStatementIfAll : anchorElementIfOne; - myProject = selectedExpr.getProject(); - myFieldName = settings.getFieldName(); - myType = type; - myOccurrences = occurrences; - myReplaceAll = settings.isReplaceAll(); - myOccurrenceManager = occurrenceManager; - myAnchorStatementIfAll = anchorStatementIfAll; - myAnchorElementIfOne = anchorElementIfOne; - myOutOfCodeBlockExtraction = selectedExpr.getUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK); - myDeleteSelf = myOutOfCodeBlockExtraction != null; - myElement = getPhysicalElement(selectedExpr); - if (myElement.getParent() instanceof PsiExpressionStatement && getNormalizedAnchor(myAnchorElement).equals(myAnchorElement) && selectedExpr.isPhysical()) { - PsiStatement statement = (PsiStatement)myElement.getParent(); - if (statement.getParent() instanceof PsiCodeBlock) { - myDeleteSelf = true; + public InitializationPlace getInitializerPlace() { + return myInitializerPlace; } - } - myEditor = editor; - myParentClass = parentClass; - } + public String getFieldVisibility() { + return myVisibility; + } + + @Nullable + public PsiClass getDestinationClass() { + return myTargetClass != null ? myTargetClass.getTargetClass() : null; + } + + public PsiType getForcedType() { + return myForcedType; + } - public void run() { - try { - InitializationPlace initializerPlace = mySettings.getInitializerPlace(); - final PsiLocalVariable localVariable = mySettings.getLocalVariable(); - final boolean deleteLocalVariable = mySettings.isDeleteLocalVariable(); - @Nullable PsiExpression initializer = null; - if (localVariable != null) { - initializer = localVariable.getInitializer(); + public boolean isReplaceAll() { + return myReplaceAll; } - else if (!(mySelectedExpr instanceof PsiReferenceExpression && ((PsiReferenceExpression)mySelectedExpr).resolve() == null)){ - initializer = mySelectedExpr; + + public boolean isAnnotateAsNonNls() { + return myAnnotateAsNonNls; } - initializer = IntroduceVariableBase.replaceExplicitWithDiamondWhenApplicable(initializer, myType); + public boolean isIntroduceEnumConstant() { + return myIntroduceEnumConstant; + } - final PsiMethod enclosingConstructor = getEnclosingConstructor(myParentClass, myAnchorElement); - PsiClass destClass = mySettings.getDestinationClass() == null ? myParentClass : mySettings.getDestinationClass(); + public Settings( + String fieldName, + PsiExpression selectedExpr, + PsiExpression[] occurrences, + boolean replaceAll, + boolean declareStatic, boolean declareFinal, + InitializationPlace initializerPlace, String visibility, PsiLocalVariable localVariableToRemove, PsiType forcedType, + boolean deleteLocalVariable, + TargetDestination targetDestination, + final boolean annotateAsNonNls, + final boolean introduceEnumConstant + ) { + + myFieldName = fieldName; + myOccurrences = occurrences; + mySelectedExpr = selectedExpr; + myReplaceAll = replaceAll; + myDeclareStatic = declareStatic; + myDeclareFinal = declareFinal; + myInitializerPlace = initializerPlace; + myVisibility = visibility; + myLocalVariable = localVariableToRemove; + myDeleteLocalVariable = deleteLocalVariable; + myForcedType = forcedType; + myTargetClass = targetDestination; + myAnnotateAsNonNls = annotateAsNonNls; + myIntroduceEnumConstant = introduceEnumConstant; + } - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, destClass.getContainingFile())) return; + public Settings( + String fieldName, + PsiExpression selectedExpression, + PsiExpression[] occurrences, + boolean replaceAll, + boolean declareStatic, boolean declareFinal, + InitializationPlace initializerPlace, String visibility, PsiLocalVariable localVariableToRemove, PsiType forcedType, + boolean deleteLocalVariable, + PsiClass targetClass, + final boolean annotateAsNonNls, + final boolean introduceEnumConstant + ) { + + this( + fieldName, + selectedExpression, + occurrences, + replaceAll, + declareStatic, + declareFinal, + initializerPlace, + visibility, + localVariableToRemove, + forcedType, + deleteLocalVariable, + new TargetDestination(targetClass), + annotateAsNonNls, + introduceEnumConstant + ); + } - if (initializer != null) { - ChangeContextUtil.encodeContextInfo(initializer, true); + public PsiExpression getSelectedExpr() { + return mySelectedExpr; } - myField = mySettings.isIntroduceEnumConstant() ? EnumConstantsUtil.createEnumConstant(destClass, myFieldName, initializer) : - createField(myFieldName, myType, initializer, initializerPlace == InitializationPlace.IN_FIELD_DECLARATION && initializer != null, - myParentClass); - setModifiers(myField, mySettings); - PsiElement finalAnchorElement = null; - if (destClass == myParentClass) { - for (finalAnchorElement = myAnchorElement; - finalAnchorElement != null && finalAnchorElement.getParent() != destClass; - finalAnchorElement = finalAnchorElement.getParent()) { - } + public PsiExpression[] getOccurrences() { + return myOccurrences; } - PsiMember anchorMember = finalAnchorElement instanceof PsiMember ? (PsiMember)finalAnchorElement : null; - if (anchorMember instanceof PsiEnumConstant && destClass == anchorMember.getContainingClass()) { - final String initialName = "Constants"; - String constantsClassName = initialName; + public void setOccurrences(PsiExpression[] occurrences) { + myOccurrences = occurrences; + } + } - PsiClass innerClass = destClass.findInnerClassByName(constantsClassName, true); - if (innerClass == null || !isConstantsClass(innerClass)) { - int i = 1; - while (destClass.findInnerClassByName(constantsClassName, true) != null) { - constantsClassName = initialName + i++; - } + public static class TargetDestination { + private final String myQualifiedName; + private final Project myProject; - PsiClass psiClass = JavaPsiFacade.getElementFactory(myProject).createClass(constantsClassName); - PsiUtil.setModifierProperty(psiClass, PsiModifier.PRIVATE, true); - PsiUtil.setModifierProperty(psiClass, PsiModifier.STATIC, true); - destClass = (PsiClass)destClass.add(psiClass); - } else { - destClass = innerClass; - } - anchorMember = null; - } - myField = appendField(initializer, initializerPlace, destClass, myParentClass, myField, anchorMember); - if (!mySettings.isIntroduceEnumConstant()) { - VisibilityUtil.fixVisibility(myOccurrences, myField, mySettings.getFieldVisibility()); - } - PsiStatement assignStatement = null; - PsiElement anchorElementHere = null; - if (initializerPlace == InitializationPlace.IN_CURRENT_METHOD && initializer != null || - initializerPlace == InitializationPlace.IN_CONSTRUCTOR && enclosingConstructor != null && initializer != null) { - if (myReplaceAll) { - if (enclosingConstructor != null) { - final PsiElement anchorInConstructor = RefactoringUtil.getAnchorElementForMultipleExpressions(mySettings.myOccurrences, - enclosingConstructor); - anchorElementHere = anchorInConstructor != null ? anchorInConstructor : myAnchorStatementIfAll; + private PsiClass myParentClass; + private PsiClass myTargetClass; + + public TargetDestination(String qualifiedName, PsiClass parentClass) { + myQualifiedName = qualifiedName; + myParentClass = parentClass; + myProject = parentClass.getProject(); + } + + public TargetDestination(@Nonnull PsiClass targetClass) { + myTargetClass = targetClass; + myQualifiedName = targetClass.getQualifiedName(); + myProject = targetClass.getProject(); + } + + @Nullable + public PsiClass getTargetClass() { + if (myTargetClass != null) { + return myTargetClass; } - else { - anchorElementHere = myAnchorStatementIfAll; + final String packageName = StringUtil.getPackageName(myQualifiedName); + final String shortName = StringUtil.getShortName(myQualifiedName); + if (Comparing.strEqual(myParentClass.getQualifiedName(), packageName)) { + myTargetClass = (PsiClass) myParentClass.add(JavaPsiFacade.getElementFactory(myProject).createClass(shortName)); + return myTargetClass; } - } - else { - anchorElementHere = myAnchorElementIfOne; - } - assignStatement = createAssignment(myField, initializer, anchorElementHere, myParentClass); - if (anchorElementHere != null && !RefactoringUtil.isLoopOrIf(anchorElementHere.getParent())) { - anchorElementHere.getParent().addBefore(assignStatement, getNormalizedAnchor(anchorElementHere)); - } - } - if (initializerPlace == InitializationPlace.IN_CONSTRUCTOR && initializer != null) { - addInitializationToConstructors(initializer, myField, enclosingConstructor, myParentClass); - } - if (initializerPlace == InitializationPlace.IN_SETUP_METHOD && initializer != null) { - addInitializationToSetUp(initializer, myField, myOccurrences, myReplaceAll, myParentClass); - } - if (mySelectedExpr.getParent() instanceof PsiParenthesizedExpression) { - mySelectedExpr = (PsiExpression)mySelectedExpr.getParent(); - } - if (myOutOfCodeBlockExtraction != null) { - final int endOffset = mySelectedExpr.getUserData(ElementToWorkOn.TEXT_RANGE).getEndOffset(); - PsiElement endElement = myElement.getContainingFile().findElementAt(endOffset); - while (true) { - final PsiElement parent = endElement.getParent(); - if (parent instanceof PsiClass) break; - endElement = parent; - } - PsiElement last = PsiTreeUtil.skipSiblingsBackward(endElement, PsiWhiteSpace.class); - if (last.getTextRange().getStartOffset() < myElement.getTextRange().getStartOffset()) { - last = myElement; - } - myElement.getParent().deleteChildRange(myElement, last); - } - else if (myDeleteSelf) { - myElement.getParent().delete(); - } - - if (myReplaceAll) { - List array = new ArrayList(); - for (PsiExpression occurrence : myOccurrences) { - if (occurrence instanceof PsiExpression) { - occurrence = RefactoringUtil.outermostParenthesizedExpression(occurrence); + PsiJavaPackage psiPackage = JavaPsiFacade.getInstance(myProject).findPackage(packageName); + final PsiDirectory psiDirectory; + if (psiPackage != null) { + final PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.allScope(myProject)); + psiDirectory = directories.length > 1 ? DirectoryChooserUtil.chooseDirectory( + directories, + null, + myProject, + new HashMap() + ) : directories[0]; } - if (myDeleteSelf && occurrence.equals(mySelectedExpr)) continue; - final PsiElement replaced = RefactoringUtil.replaceOccurenceWithFieldRef(occurrence, myField, destClass); - if (replaced != null) { - array.add(replaced); + else { + psiDirectory = PackageUtil.findOrCreateDirectoryForPackage( + myProject, + packageName, + myParentClass.getContainingFile().getContainingDirectory(), + false + ); } - } + myTargetClass = psiDirectory != null ? JavaDirectoryService.getInstance().createClass(psiDirectory, shortName) : null; + return myTargetClass; + } + } - if (myEditor != null) { - if (!ApplicationManager.getApplication().isUnitTestMode()) { - PsiElement[] exprsToHighlight = PsiUtilBase.toPsiElementArray(array); - HighlightManager highlightManager = HighlightManager.getInstance(myProject); - highlightManager.addOccurrenceHighlights(myEditor, exprsToHighlight, EditorColors.SEARCH_RESULT_ATTRIBUTES, true, null); + public static class ConvertToFieldRunnable implements Runnable { + private PsiExpression mySelectedExpr; + private final Settings mySettings; + private final PsiElement myAnchorElement; + private final Project myProject; + private final String myFieldName; + private final PsiType myType; + private final PsiExpression[] myOccurrences; + private final boolean myReplaceAll; + private final OccurrenceManager myOccurrenceManager; + private final PsiElement myAnchorStatementIfAll; + private final PsiElement myAnchorElementIfOne; + private final Boolean myOutOfCodeBlockExtraction; + private final PsiElement myElement; + private boolean myDeleteSelf; + private final Editor myEditor; + private final PsiClass myParentClass; + + private PsiField myField; + + public ConvertToFieldRunnable( + PsiExpression selectedExpr, + Settings settings, + PsiType type, + PsiExpression[] occurrences, + OccurrenceManager occurrenceManager, + PsiElement anchorStatementIfAll, + PsiElement anchorElementIfOne, + Editor editor, + PsiClass parentClass + ) { + mySelectedExpr = selectedExpr; + mySettings = settings; + myAnchorElement = settings.isReplaceAll() ? anchorStatementIfAll : anchorElementIfOne; + myProject = selectedExpr.getProject(); + myFieldName = settings.getFieldName(); + myType = type; + myOccurrences = occurrences; + myReplaceAll = settings.isReplaceAll(); + myOccurrenceManager = occurrenceManager; + myAnchorStatementIfAll = anchorStatementIfAll; + myAnchorElementIfOne = anchorElementIfOne; + myOutOfCodeBlockExtraction = selectedExpr.getUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK); + myDeleteSelf = myOutOfCodeBlockExtraction != null; + myElement = getPhysicalElement(selectedExpr); + if (myElement.getParent() instanceof PsiExpressionStatement && getNormalizedAnchor(myAnchorElement).equals(myAnchorElement) && selectedExpr.isPhysical()) { + PsiStatement statement = (PsiStatement) myElement.getParent(); + if (statement.getParent() instanceof PsiCodeBlock) { + myDeleteSelf = true; + } } - } - } - else { - if (!myDeleteSelf) { - mySelectedExpr = RefactoringUtil.outermostParenthesizedExpression(mySelectedExpr); - RefactoringUtil.replaceOccurenceWithFieldRef(mySelectedExpr, myField, destClass); - } - } - if (anchorElementHere != null && RefactoringUtil.isLoopOrIf(anchorElementHere.getParent())) { - RefactoringUtil.putStatementInLoopBody(assignStatement, anchorElementHere.getParent(), anchorElementHere); + myEditor = editor; + myParentClass = parentClass; } + public void run() { + try { + InitializationPlace initializerPlace = mySettings.getInitializerPlace(); + final PsiLocalVariable localVariable = mySettings.getLocalVariable(); + final boolean deleteLocalVariable = mySettings.isDeleteLocalVariable(); + @Nullable PsiExpression initializer = null; + if (localVariable != null) { + initializer = localVariable.getInitializer(); + } + else if (!(mySelectedExpr instanceof PsiReferenceExpression && ((PsiReferenceExpression) mySelectedExpr).resolve() == null)) { + initializer = mySelectedExpr; + } + + initializer = IntroduceVariableBase.replaceExplicitWithDiamondWhenApplicable(initializer, myType); - if (localVariable != null) { - if (deleteLocalVariable) { - localVariable.normalizeDeclaration(); - localVariable.getParent().delete(); - } - } + final PsiMethod enclosingConstructor = getEnclosingConstructor(myParentClass, myAnchorElement); + PsiClass destClass = mySettings.getDestinationClass() == null ? myParentClass : mySettings.getDestinationClass(); - if (initializer != null) { - ChangeContextUtil.clearContextInfo(initializer); + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, destClass.getContainingFile())) { + return; + } + + if (initializer != null) { + ChangeContextUtil.encodeContextInfo(initializer, true); + } + myField = mySettings.isIntroduceEnumConstant() ? EnumConstantsUtil.createEnumConstant(destClass, myFieldName, initializer) : + createField( + myFieldName, + myType, + initializer, + initializerPlace == InitializationPlace.IN_FIELD_DECLARATION && initializer != null, + myParentClass + ); + + setModifiers(myField, mySettings); + PsiElement finalAnchorElement = null; + if (destClass == myParentClass) { + for (finalAnchorElement = myAnchorElement; + finalAnchorElement != null && finalAnchorElement.getParent() != destClass; + finalAnchorElement = finalAnchorElement.getParent()) { + } + } + PsiMember anchorMember = finalAnchorElement instanceof PsiMember ? (PsiMember) finalAnchorElement : null; + + if (anchorMember instanceof PsiEnumConstant && destClass == anchorMember.getContainingClass()) { + final String initialName = "Constants"; + String constantsClassName = initialName; + + PsiClass innerClass = destClass.findInnerClassByName(constantsClassName, true); + if (innerClass == null || !isConstantsClass(innerClass)) { + int i = 1; + while (destClass.findInnerClassByName(constantsClassName, true) != null) { + constantsClassName = initialName + i++; + } + + PsiClass psiClass = JavaPsiFacade.getElementFactory(myProject).createClass(constantsClassName); + PsiUtil.setModifierProperty(psiClass, PsiModifier.PRIVATE, true); + PsiUtil.setModifierProperty(psiClass, PsiModifier.STATIC, true); + destClass = (PsiClass) destClass.add(psiClass); + } + else { + destClass = innerClass; + } + anchorMember = null; + } + myField = appendField(initializer, initializerPlace, destClass, myParentClass, myField, anchorMember); + if (!mySettings.isIntroduceEnumConstant()) { + VisibilityUtil.fixVisibility(myOccurrences, myField, mySettings.getFieldVisibility()); + } + PsiStatement assignStatement = null; + PsiElement anchorElementHere = null; + if (initializerPlace == InitializationPlace.IN_CURRENT_METHOD && initializer != null || + initializerPlace == InitializationPlace.IN_CONSTRUCTOR && enclosingConstructor != null && initializer != null) { + if (myReplaceAll) { + if (enclosingConstructor != null) { + final PsiElement anchorInConstructor = RefactoringUtil.getAnchorElementForMultipleExpressions( + mySettings.myOccurrences, + enclosingConstructor + ); + anchorElementHere = anchorInConstructor != null ? anchorInConstructor : myAnchorStatementIfAll; + } + else { + anchorElementHere = myAnchorStatementIfAll; + } + } + else { + anchorElementHere = myAnchorElementIfOne; + } + assignStatement = createAssignment(myField, initializer, anchorElementHere, myParentClass); + if (anchorElementHere != null && !RefactoringUtil.isLoopOrIf(anchorElementHere.getParent())) { + anchorElementHere.getParent().addBefore(assignStatement, getNormalizedAnchor(anchorElementHere)); + } + } + if (initializerPlace == InitializationPlace.IN_CONSTRUCTOR && initializer != null) { + addInitializationToConstructors(initializer, myField, enclosingConstructor, myParentClass); + } + if (initializerPlace == InitializationPlace.IN_SETUP_METHOD && initializer != null) { + addInitializationToSetUp(initializer, myField, myOccurrences, myReplaceAll, myParentClass); + } + if (mySelectedExpr.getParent() instanceof PsiParenthesizedExpression) { + mySelectedExpr = (PsiExpression) mySelectedExpr.getParent(); + } + if (myOutOfCodeBlockExtraction != null) { + final int endOffset = mySelectedExpr.getUserData(ElementToWorkOn.TEXT_RANGE).getEndOffset(); + PsiElement endElement = myElement.getContainingFile().findElementAt(endOffset); + while (true) { + final PsiElement parent = endElement.getParent(); + if (parent instanceof PsiClass) { + break; + } + endElement = parent; + } + PsiElement last = PsiTreeUtil.skipSiblingsBackward(endElement, PsiWhiteSpace.class); + if (last.getTextRange().getStartOffset() < myElement.getTextRange().getStartOffset()) { + last = myElement; + } + myElement.getParent().deleteChildRange(myElement, last); + } + else if (myDeleteSelf) { + myElement.getParent().delete(); + } + + if (myReplaceAll) { + List array = new ArrayList(); + for (PsiExpression occurrence : myOccurrences) { + if (occurrence instanceof PsiExpression) { + occurrence = RefactoringUtil.outermostParenthesizedExpression(occurrence); + } + if (myDeleteSelf && occurrence.equals(mySelectedExpr)) { + continue; + } + final PsiElement replaced = RefactoringUtil.replaceOccurenceWithFieldRef(occurrence, myField, destClass); + if (replaced != null) { + array.add(replaced); + } + } + + if (myEditor != null) { + if (!ApplicationManager.getApplication().isUnitTestMode()) { + PsiElement[] exprsToHighlight = PsiUtilBase.toPsiElementArray(array); + HighlightManager highlightManager = HighlightManager.getInstance(myProject); + highlightManager.addOccurrenceHighlights( + myEditor, + exprsToHighlight, + EditorColors.SEARCH_RESULT_ATTRIBUTES, + true, + null + ); + } + } + } + else { + if (!myDeleteSelf) { + mySelectedExpr = RefactoringUtil.outermostParenthesizedExpression(mySelectedExpr); + RefactoringUtil.replaceOccurenceWithFieldRef(mySelectedExpr, myField, destClass); + } + } + + if (anchorElementHere != null && RefactoringUtil.isLoopOrIf(anchorElementHere.getParent())) { + RefactoringUtil.putStatementInLoopBody(assignStatement, anchorElementHere.getParent(), anchorElementHere); + } + + + if (localVariable != null) { + if (deleteLocalVariable) { + localVariable.normalizeDeclaration(); + localVariable.getParent().delete(); + } + } + + if (initializer != null) { + ChangeContextUtil.clearContextInfo(initializer); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - static boolean isConstantsClass(PsiClass innerClass) { - if (innerClass.getMethods().length != 0) return false; - for (PsiField field : innerClass.getFields()) { - if (!field.hasModifierProperty(PsiModifier.STATIC) || !field.hasModifierProperty(PsiModifier.FINAL)) return false; - } - return true; - } + static boolean isConstantsClass(PsiClass innerClass) { + if (innerClass.getMethods().length != 0) { + return false; + } + for (PsiField field : innerClass.getFields()) { + if (!field.hasModifierProperty(PsiModifier.STATIC) || !field.hasModifierProperty(PsiModifier.FINAL)) { + return false; + } + } + return true; + } - static PsiField appendField(final PsiExpression initializer, - InitializationPlace initializerPlace, final PsiClass destClass, - final PsiClass parentClass, - final PsiField psiField, - final PsiMember anchorMember) { - return appendField(destClass, psiField, anchorMember, initializerPlace == InitializationPlace.IN_FIELD_DECLARATION - ? checkForwardRefs(initializer, parentClass) : null); - } + static PsiField appendField( + final PsiExpression initializer, + InitializationPlace initializerPlace, final PsiClass destClass, + final PsiClass parentClass, + final PsiField psiField, + final PsiMember anchorMember + ) { + return appendField(destClass, psiField, anchorMember, initializerPlace == InitializationPlace.IN_FIELD_DECLARATION + ? checkForwardRefs(initializer, parentClass) : null); + } - public static PsiField appendField(final PsiClass destClass, - final PsiField psiField, - final PsiElement anchorMember, - final PsiField forwardReference) { - final PsiClass parentClass = PsiTreeUtil.getParentOfType(anchorMember, PsiClass.class); - - if (anchorMember instanceof PsiField && - anchorMember.getParent() == parentClass && - destClass == parentClass && - ((PsiField)anchorMember).hasModifierProperty(PsiModifier.STATIC) == psiField.hasModifierProperty(PsiModifier.STATIC)) { - return (PsiField)destClass.addBefore(psiField, anchorMember); - } - else if (anchorMember instanceof PsiClassInitializer && - anchorMember.getParent() == parentClass && - destClass == parentClass) { - PsiField field = (PsiField)destClass.addBefore(psiField, anchorMember); - destClass.addBefore(CodeEditUtil.createLineFeed(field.getManager()), anchorMember); - return field; - } - else { - if (forwardReference != null ) { - return forwardReference.getParent() == destClass ? - (PsiField)destClass.addAfter(psiField, forwardReference) : - (PsiField)forwardReference.getParent().addAfter(psiField, forwardReference); - } else { - return (PsiField)destClass.add(psiField); + public static PsiField appendField( + final PsiClass destClass, + final PsiField psiField, + final PsiElement anchorMember, + final PsiField forwardReference + ) { + final PsiClass parentClass = PsiTreeUtil.getParentOfType(anchorMember, PsiClass.class); + + if (anchorMember instanceof PsiField && + anchorMember.getParent() == parentClass && + destClass == parentClass && + ((PsiField) anchorMember).hasModifierProperty(PsiModifier.STATIC) == psiField.hasModifierProperty(PsiModifier.STATIC)) { + return (PsiField) destClass.addBefore(psiField, anchorMember); + } + else if (anchorMember instanceof PsiClassInitializer && + anchorMember.getParent() == parentClass && + destClass == parentClass) { + PsiField field = (PsiField) destClass.addBefore(psiField, anchorMember); + destClass.addBefore(CodeEditUtil.createLineFeed(field.getManager()), anchorMember); + return field; + } + else { + if (forwardReference != null) { + return forwardReference.getParent() == destClass ? + (PsiField) destClass.addAfter(psiField, forwardReference) : + (PsiField) forwardReference.getParent().addAfter(psiField, forwardReference); + } + else { + return (PsiField) destClass.add(psiField); + } + } } - } - } - @Nullable - private static PsiField checkForwardRefs(@Nullable final PsiExpression initializer, final PsiClass parentClass) { - if (initializer == null) return null; - final PsiField[] refConstantFields = new PsiField[1]; - initializer.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement resolve = expression.resolve(); - if (resolve instanceof PsiField && - PsiTreeUtil.isAncestor(parentClass, resolve, false) && ((PsiField)resolve).hasInitializer() && - !PsiTreeUtil.isAncestor(initializer, resolve, false)) { - if (refConstantFields[0] == null || refConstantFields[0].getTextOffset() < resolve.getTextOffset()) { - refConstantFields[0] = (PsiField)resolve; + @Nullable + private static PsiField checkForwardRefs(@Nullable final PsiExpression initializer, final PsiClass parentClass) { + if (initializer == null) { + return null; } - } + final PsiField[] refConstantFields = new PsiField[1]; + initializer.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiField && + PsiTreeUtil.isAncestor(parentClass, resolve, false) && ((PsiField) resolve).hasInitializer() && + !PsiTreeUtil.isAncestor(initializer, resolve, false)) { + if (refConstantFields[0] == null || refConstantFields[0].getTextOffset() < resolve.getTextOffset()) { + refConstantFields[0] = (PsiField) resolve; + } + } + } + }); + return refConstantFields[0]; } - }); - return refConstantFields[0]; - } - public PsiField getField() { - return myField; + public PsiField getField() { + return myField; + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/InplaceIntroduceFieldPopup.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/InplaceIntroduceFieldPopup.java index 6a547f8e6..ef67952be 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/InplaceIntroduceFieldPopup.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/InplaceIntroduceFieldPopup.java @@ -34,204 +34,251 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; /** - * User: anna - * Date: 3/15/11 + * @author anna + * @since 2011-03-15 */ public class InplaceIntroduceFieldPopup extends AbstractInplaceIntroduceFieldPopup { - private final boolean myStatic; - - private final IntroduceFieldPopupPanel myIntroduceFieldPanel; - - static BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace; - - public InplaceIntroduceFieldPopup(PsiLocalVariable localVariable, - PsiClass parentClass, - boolean aStatic, - boolean currentMethodConstructor, PsiExpression[] occurrences, - PsiExpression initializerExpression, - TypeSelectorManagerImpl typeSelectorManager, - Editor editor, - final boolean allowInitInMethod, - boolean allowInitInMethodIfAll, final PsiElement anchorElement, - final PsiElement anchorElementIfAll, - final OccurrenceManager occurrenceManager, Project project) { - super(project, editor, initializerExpression, localVariable, occurrences, typeSelectorManager, - IntroduceFieldHandler.REFACTORING_NAME, parentClass, anchorElement, occurrenceManager, anchorElementIfAll); - myStatic = aStatic; - myIntroduceFieldPanel = - new IntroduceFieldPopupPanel(parentClass, initializerExpression, localVariable, currentMethodConstructor, localVariable != null, aStatic, - myOccurrences, allowInitInMethod, allowInitInMethodIfAll, typeSelectorManager); - - final GridBagConstraints constraints = - new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 0, 0), 0, 0); - myWholePanel.add(getPreviewComponent(), constraints); - - final JComponent centerPanel = myIntroduceFieldPanel.createCenterPanel(); - - myWholePanel.add(centerPanel, constraints); - - myIntroduceFieldPanel.initializeControls(initializerExpression, ourLastInitializerPlace); - } - - protected PsiField createFieldToStartTemplateOn(final String[] names, - final PsiType defaultType) { - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - return ApplicationManager.getApplication().runWriteAction(new Computable() { - @Override - public PsiField compute() { - PsiField field = elementFactory.createField(getInputName() != null ? getInputName() : names[0], defaultType); - field = (PsiField) myParentClass.add(field); - if (myExprText != null) { - updateInitializer(elementFactory, field); + private final boolean myStatic; + + private final IntroduceFieldPopupPanel myIntroduceFieldPanel; + + static BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace; + + public InplaceIntroduceFieldPopup( + PsiLocalVariable localVariable, + PsiClass parentClass, + boolean aStatic, + boolean currentMethodConstructor, PsiExpression[] occurrences, + PsiExpression initializerExpression, + TypeSelectorManagerImpl typeSelectorManager, + Editor editor, + final boolean allowInitInMethod, + boolean allowInitInMethodIfAll, + final PsiElement anchorElement, + final PsiElement anchorElementIfAll, + final OccurrenceManager occurrenceManager, Project project + ) { + super( + project, + editor, + initializerExpression, + localVariable, + occurrences, + typeSelectorManager, + IntroduceFieldHandler.REFACTORING_NAME.get(), + parentClass, + anchorElement, + occurrenceManager, + anchorElementIfAll + ); + myStatic = aStatic; + myIntroduceFieldPanel = new IntroduceFieldPopupPanel( + parentClass, + initializerExpression, + localVariable, + currentMethodConstructor, + localVariable != null, + aStatic, + myOccurrences, + allowInitInMethod, + allowInitInMethodIfAll, + typeSelectorManager + ); + + GridBagConstraints constraints = new GridBagConstraints( + 0, GridBagConstraints.RELATIVE, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, + new Insets(0, 0, 0, 0), 0, 0 + ); + myWholePanel.add(getPreviewComponent(), constraints); + + JComponent centerPanel = myIntroduceFieldPanel.createCenterPanel(); + + myWholePanel.add(centerPanel, constraints); + + myIntroduceFieldPanel.initializeControls(initializerExpression, ourLastInitializerPlace); + } + + protected PsiField createFieldToStartTemplateOn( + final String[] names, + final PsiType defaultType + ) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + return ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + public PsiField compute() { + PsiField field = elementFactory.createField(getInputName() != null ? getInputName() : names[0], defaultType); + field = (PsiField) myParentClass.add(field); + if (myExprText != null) { + updateInitializer(elementFactory, field); + } + PsiUtil.setModifierProperty(field, PsiModifier.FINAL, myIntroduceFieldPanel.isDeclareFinal()); + String visibility = myIntroduceFieldPanel.getFieldVisibility(); + if (visibility != null) { + PsiUtil.setModifierProperty(field, visibility, true); + } + myFieldRangeStart = myEditor.getDocument().createRangeMarker(field.getTextRange()); + return field; + } + }); + } + + @Override + protected String[] suggestNames(PsiType defaultType, String propName) { + return suggestFieldName( + defaultType, + (PsiLocalVariable) getLocalVariable(), + myExpr != null && myExpr.isValid() ? myExpr : null, + myStatic, + myParentClass + ).names; + } + + public static SuggestedNameInfo suggestFieldName( + @Nullable PsiType defaultType, + @Nullable final PsiLocalVariable localVariable, + final PsiExpression initializer, + final boolean forStatic, + @Nonnull final PsiClass parentClass + ) { + return IntroduceFieldDialog. + createGenerator(forStatic, localVariable, initializer, localVariable != null, null, parentClass, parentClass.getProject()). + getSuggestedNameInfo(defaultType); + } + + @Override + protected VariableKind getVariableKind() { + return VariableKind.FIELD; + } + + public void setReplaceAllOccurrences(boolean replaceAllOccurrences) { + myIntroduceFieldPanel.setReplaceAllOccurrences(replaceAllOccurrences); + } + + @Override + protected void updateTitle(@Nullable PsiVariable variable, String value) { + if (variable == null || !variable.hasInitializer()) { + super.updateTitle(variable, value); } - PsiUtil.setModifierProperty(field, PsiModifier.FINAL, myIntroduceFieldPanel.isDeclareFinal()); - final String visibility = myIntroduceFieldPanel.getFieldVisibility(); - if (visibility != null) { - PsiUtil.setModifierProperty(field, visibility, true); + else { + + final PsiExpression initializer = variable.getInitializer(); + assert initializer != null; + String text = variable.getText().replace(variable.getName(), value); + text = text.replace(initializer.getText(), PsiExpressionTrimRenderer.render(initializer)); + setPreviewText(text); + revalidate(); } - myFieldRangeStart = myEditor.getDocument().createRangeMarker(field.getTextRange()); - return field; - } - }); - } - - @Override - protected String[] suggestNames(PsiType defaultType, String propName) { - return suggestFieldName(defaultType, (PsiLocalVariable) getLocalVariable(), myExpr != null && myExpr.isValid() ? myExpr : null, myStatic, myParentClass).names; - } - - public static SuggestedNameInfo suggestFieldName(@Nullable PsiType defaultType, - @Nullable final PsiLocalVariable localVariable, - final PsiExpression initializer, - final boolean forStatic, - @Nonnull final PsiClass parentClass) { - return IntroduceFieldDialog. - createGenerator(forStatic, localVariable, initializer, localVariable != null, null, parentClass, parentClass.getProject()). - getSuggestedNameInfo(defaultType); - } - - @Override - protected VariableKind getVariableKind() { - return VariableKind.FIELD; - } - - public void setReplaceAllOccurrences(boolean replaceAllOccurrences) { - myIntroduceFieldPanel.setReplaceAllOccurrences(replaceAllOccurrences); - } - - @Override - protected void updateTitle(@Nullable PsiVariable variable, String value) { - if (variable == null || !variable.hasInitializer()) { - super.updateTitle(variable, value); - } else { - - final PsiExpression initializer = variable.getInitializer(); - assert initializer != null; - String text = variable.getText().replace(variable.getName(), value); - text = text.replace(initializer.getText(), PsiExpressionTrimRenderer.render(initializer)); - setPreviewText(text); - revalidate(); - } - } - - @Override - protected void updateTitle(@Nullable PsiVariable variable) { - if (variable != null) { - updateTitle(variable, variable.getName()); - } - } - - public void setVisibility(String visibility) { - myIntroduceFieldPanel.setVisibility(visibility); - } - - - @Override - public boolean isReplaceAllOccurrences() { - return myIntroduceFieldPanel.isReplaceAllOccurrences(); - } - - @Override - protected void saveSettings(@Nonnull PsiVariable psiVariable) { - super.saveSettings(psiVariable); - JavaRefactoringSettings.getInstance().INTRODUCE_FIELD_VISIBILITY = myIntroduceFieldPanel.getFieldVisibility(); - myIntroduceFieldPanel.saveFinalState(); - } - - @Override - protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) { - return super.startsOnTheSameElement(handler, element) && handler instanceof IntroduceFieldHandler; - } - - @Override - protected JComponent getComponent() { - myIntroduceFieldPanel.addOccurrenceListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - restartInplaceIntroduceTemplate(); - } - }); - - return myWholePanel; - } - - private void updateInitializer(PsiElementFactory elementFactory, PsiField variable) { - if (variable != null) { - if (myIntroduceFieldPanel.getInitializerPlace() == BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION) { - variable.setInitializer(elementFactory.createExpressionFromText(myExprText, variable)); - } else { - variable.setInitializer(null); - } - } - } - - @Override - protected String getActionName() { - return "IntroduceField"; - } - - public BaseExpressionToFieldHandler.InitializationPlace getInitializerPlace() { - return myIntroduceFieldPanel.getInitializerPlace(); - } - - protected void performIntroduce() { - ourLastInitializerPlace = myIntroduceFieldPanel.getInitializerPlace(); - final BaseExpressionToFieldHandler.Settings settings = - new BaseExpressionToFieldHandler.Settings(getInputName(), - getExpr(), - getOccurrences(), - myIntroduceFieldPanel.isReplaceAllOccurrences(), myStatic, - myIntroduceFieldPanel.isDeclareFinal(), - myIntroduceFieldPanel.getInitializerPlace(), - myIntroduceFieldPanel.getFieldVisibility(), (PsiLocalVariable) getLocalVariable(), - getType(), - myIntroduceFieldPanel.isDeleteVariable(), - myParentClass, false, false); - new WriteCommandAction(myProject, getCommandName(), getCommandName()) { - @Override - protected void run(Result result) throws Throwable { - if (getLocalVariable() != null) { - final LocalToFieldHandler.IntroduceFieldRunnable fieldRunnable = - new LocalToFieldHandler.IntroduceFieldRunnable(false, (PsiLocalVariable) getLocalVariable(), myParentClass, settings, myStatic, myOccurrences); - fieldRunnable.run(); - } else { - final BaseExpressionToFieldHandler.ConvertToFieldRunnable convertToFieldRunnable = - new BaseExpressionToFieldHandler.ConvertToFieldRunnable(myExpr, settings, settings.getForcedType(), - myOccurrences, myOccurrenceManager, - getAnchorElementIfAll(), - getAnchorElement(), myEditor, - myParentClass); - convertToFieldRunnable.run(); + } + + @Override + protected void updateTitle(@Nullable PsiVariable variable) { + if (variable != null) { + updateTitle(variable, variable.getName()); } - } - }.execute(); - } + } + + public void setVisibility(String visibility) { + myIntroduceFieldPanel.setVisibility(visibility); + } + + + @Override + public boolean isReplaceAllOccurrences() { + return myIntroduceFieldPanel.isReplaceAllOccurrences(); + } + + @Override + protected void saveSettings(@Nonnull PsiVariable psiVariable) { + super.saveSettings(psiVariable); + JavaRefactoringSettings.getInstance().INTRODUCE_FIELD_VISIBILITY = myIntroduceFieldPanel.getFieldVisibility(); + myIntroduceFieldPanel.saveFinalState(); + } + + @Override + protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) { + return super.startsOnTheSameElement(handler, element) && handler instanceof IntroduceFieldHandler; + } + + @Override + protected JComponent getComponent() { + myIntroduceFieldPanel.addOccurrenceListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + restartInplaceIntroduceTemplate(); + } + }); + + return myWholePanel; + } + + private void updateInitializer(PsiElementFactory elementFactory, PsiField variable) { + if (variable != null) { + if (myIntroduceFieldPanel.getInitializerPlace() == BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION) { + variable.setInitializer(elementFactory.createExpressionFromText(myExprText, variable)); + } + else { + variable.setInitializer(null); + } + } + } + + @Override + protected String getActionName() { + return "IntroduceField"; + } + + public BaseExpressionToFieldHandler.InitializationPlace getInitializerPlace() { + return myIntroduceFieldPanel.getInitializerPlace(); + } + + protected void performIntroduce() { + ourLastInitializerPlace = myIntroduceFieldPanel.getInitializerPlace(); + final BaseExpressionToFieldHandler.Settings settings = + new BaseExpressionToFieldHandler.Settings(getInputName(), + getExpr(), + getOccurrences(), + myIntroduceFieldPanel.isReplaceAllOccurrences(), myStatic, + myIntroduceFieldPanel.isDeclareFinal(), + myIntroduceFieldPanel.getInitializerPlace(), + myIntroduceFieldPanel.getFieldVisibility(), (PsiLocalVariable) getLocalVariable(), + getType(), + myIntroduceFieldPanel.isDeleteVariable(), + myParentClass, false, false + ); + new WriteCommandAction(myProject, getCommandName(), getCommandName()) { + @Override + protected void run(Result result) throws Throwable { + if (getLocalVariable() != null) { + final LocalToFieldHandler.IntroduceFieldRunnable fieldRunnable = + new LocalToFieldHandler.IntroduceFieldRunnable( + false, + (PsiLocalVariable) getLocalVariable(), + myParentClass, + settings, + myStatic, + myOccurrences + ); + fieldRunnable.run(); + } + else { + final BaseExpressionToFieldHandler.ConvertToFieldRunnable convertToFieldRunnable = + new BaseExpressionToFieldHandler.ConvertToFieldRunnable(myExpr, settings, settings.getForcedType(), + myOccurrences, myOccurrenceManager, + getAnchorElementIfAll(), + getAnchorElement(), myEditor, + myParentClass + ); + convertToFieldRunnable.run(); + } + } + }.execute(); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceConstantHandlerImpl.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceConstantHandlerImpl.java index 9f9d352ba..635ad3b0f 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceConstantHandlerImpl.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceConstantHandlerImpl.java @@ -28,12 +28,9 @@ import consulo.codeEditor.Editor; import consulo.codeEditor.EditorColors; import consulo.codeEditor.markup.RangeHighlighter; -import consulo.colorScheme.EditorColorsManager; -import consulo.colorScheme.TextAttributes; import consulo.dataContext.DataContext; import consulo.document.util.TextRange; import consulo.language.editor.highlight.HighlightManager; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.introduce.inplace.AbstractInplaceIntroducer; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; @@ -43,7 +40,7 @@ import consulo.language.psi.util.PsiTreeUtil; import consulo.localize.LocalizeValue; import consulo.project.Project; -import consulo.project.ui.wm.WindowManager; +import consulo.ui.annotation.RequiredUIAccess; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -51,267 +48,314 @@ import java.util.List; public class IntroduceConstantHandlerImpl extends BaseExpressionToFieldHandler implements IntroduceConstantHandler { - public static final String REFACTORING_NAME = RefactoringBundle.message("introduce.constant.title"); - protected InplaceIntroduceConstantPopup myInplaceIntroduceConstantPopup; + public static final LocalizeValue REFACTORING_NAME = RefactoringLocalize.introduceConstantTitle(); + protected InplaceIntroduceConstantPopup myInplaceIntroduceConstantPopup; - public IntroduceConstantHandlerImpl() { - super(true); - } - - protected String getHelpID() { - return HelpID.INTRODUCE_CONSTANT; - } - - public void invoke(Project project, PsiExpression[] expressions) { - for (PsiExpression expression : expressions) { - final PsiFile file = expression.getContainingFile(); - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return; - } - PsiDocumentManager.getInstance(project).commitAllDocuments(); - super.invoke(project, expressions, null); - } - - public void invoke(@Nonnull final Project project, final Editor editor, PsiFile file, DataContext dataContext) { - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return; - - PsiDocumentManager.getInstance(project).commitAllDocuments(); - ElementToWorkOn.processElementToWorkOn(editor, file, REFACTORING_NAME, getHelpID(), project, getElementProcessor(project, editor)); - } - - protected boolean invokeImpl(final Project project, final PsiLocalVariable localVariable, final Editor editor) { - final PsiElement parent = localVariable.getParent(); - if (!(parent instanceof PsiDeclarationStatement)) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.errorWrongCaretPositionLocalOrExpressionName()); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, getHelpID()); - return false; - } - final LocalToFieldHandler localToFieldHandler = new LocalToFieldHandler(project, true){ - @Override - protected Settings showRefactoringDialog(PsiClass aClass, - PsiLocalVariable local, - PsiExpression[] occurences, - boolean isStatic) { - return IntroduceConstantHandlerImpl.this.showRefactoringDialog(project, editor, aClass, local.getInitializer(), local.getType(), occurences, local, null); - } - }; - return localToFieldHandler.convertLocalToField(localVariable, editor); - } - - - protected Settings showRefactoringDialog(Project project, - final Editor editor, - PsiClass parentClass, - PsiExpression expr, - PsiType type, - PsiExpression[] occurrences, - PsiElement anchorElement, - PsiElement anchorElementIfAll) { - final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expr != null ? expr : anchorElement, PsiMethod.class); - - PsiLocalVariable localVariable = null; - if (expr instanceof PsiReferenceExpression) { - PsiElement ref = ((PsiReferenceExpression)expr).resolve(); - if (ref instanceof PsiLocalVariable) { - localVariable = (PsiLocalVariable)ref; - } - } else if (anchorElement instanceof PsiLocalVariable) { - localVariable = (PsiLocalVariable)anchorElement; + public IntroduceConstantHandlerImpl() { + super(true); } - String enteredName = null; - boolean replaceAllOccurrences = true; - - final AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); - if (activeIntroducer != null) { - activeIntroducer.stopIntroduce(editor); - expr = (PsiExpression)activeIntroducer.getExpr(); - localVariable = (PsiLocalVariable)activeIntroducer.getLocalVariable(); - occurrences = (PsiExpression[])activeIntroducer.getOccurrences(); - enteredName = activeIntroducer.getInputName(); - replaceAllOccurrences = activeIntroducer.isReplaceAllOccurrences(); - type = ((InplaceIntroduceConstantPopup)activeIntroducer).getType(); - } - - for (PsiExpression occurrence : occurrences) { - if (RefactoringUtil.isAssignmentLHS(occurrence)) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(LocalizeValue.localizeTODO("Selected expression is used for write")); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, getHelpID()); - highlightError(project, editor, occurrence); - return null; - } + protected String getHelpID() { + return HelpID.INTRODUCE_CONSTANT; } - - if (localVariable == null) { - final PsiElement errorElement = isStaticFinalInitializer(expr); - if (errorElement != null) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedExpressionCannotBeAConstantInitializer()); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, getHelpID()); - highlightError(project, editor, errorElement); - return null; - } + + public void invoke(Project project, PsiExpression[] expressions) { + for (PsiExpression expression : expressions) { + final PsiFile file = expression.getContainingFile(); + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { + return; + } + } + PsiDocumentManager.getInstance(project).commitAllDocuments(); + super.invoke(project, expressions, null); } - else { - final PsiExpression initializer = localVariable.getInitializer(); - if (initializer == null) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.variableDoesNotHaveAnInitializer(localVariable.getName()) + + public void invoke(@Nonnull final Project project, final Editor editor, PsiFile file, DataContext dataContext) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { + return; + } + + PsiDocumentManager.getInstance(project).commitAllDocuments(); + ElementToWorkOn.processElementToWorkOn( + editor, + file, + REFACTORING_NAME.get(), + getHelpID(), + project, + getElementProcessor(project, editor) ); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, getHelpID()); - return null; - } - final PsiElement errorElement = isStaticFinalInitializer(initializer); - if (errorElement != null) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.initializerForVariableCannotBeAConstantInitializer(localVariable.getName())); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, getHelpID()); - highlightError(project, editor, errorElement); - return null; - } } - final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurrences); - if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled() && - (expr == null || expr.isPhysical()) && activeIntroducer == null) { - myInplaceIntroduceConstantPopup = - new InplaceIntroduceConstantPopup(project, editor, parentClass, expr, localVariable, occurrences, - typeSelectorManager, - anchorElement, anchorElementIfAll, - expr != null ? createOccurrenceManager(expr, parentClass) : null); - if (myInplaceIntroduceConstantPopup.startInplaceIntroduceTemplate()) { - return null; - } + protected boolean invokeImpl(final Project project, final PsiLocalVariable localVariable, final Editor editor) { + final PsiElement parent = localVariable.getParent(); + if (!(parent instanceof PsiDeclarationStatement)) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.errorWrongCaretPositionLocalOrExpressionName()); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID()); + return false; + } + final LocalToFieldHandler localToFieldHandler = new LocalToFieldHandler(project, true) { + @Override + protected Settings showRefactoringDialog( + PsiClass aClass, + PsiLocalVariable local, + PsiExpression[] occurences, + boolean isStatic + ) { + return IntroduceConstantHandlerImpl.this.showRefactoringDialog( + project, + editor, + aClass, + local.getInitializer(), + local.getType(), + occurences, + local, + null + ); + } + }; + return localToFieldHandler.convertLocalToField(localVariable, editor); } - - final IntroduceConstantDialog dialog = - new IntroduceConstantDialog(project, parentClass, expr, localVariable, localVariable != null, occurrences, getParentClass(), - typeSelectorManager, enteredName); - dialog.setReplaceAllOccurrences(replaceAllOccurrences); - dialog.show(); - if (!dialog.isOK()) { - return null; - } - return new Settings(dialog.getEnteredName(), expr, occurrences, dialog.isReplaceAllOccurrences(), true, true, - InitializationPlace.IN_FIELD_DECLARATION, dialog.getFieldVisibility(), localVariable, - dialog.getSelectedType(), dialog.isDeleteVariable(), dialog.getDestinationClass(), - dialog.isAnnotateAsNonNls(), - dialog.introduceEnumConstant()); - } - - private static void highlightError(Project project, Editor editor, PsiElement errorElement) { - if (editor != null) { - final TextRange textRange = errorElement.getTextRange(); - HighlightManager.getInstance(project).addRangeHighlight(editor, textRange.getStartOffset(), textRange.getEndOffset(), EditorColors.SEARCH_RESULT_ATTRIBUTES, true, new ArrayList()); + @RequiredUIAccess + protected Settings showRefactoringDialog( + Project project, + final Editor editor, + PsiClass parentClass, + PsiExpression expr, + PsiType type, + PsiExpression[] occurrences, + PsiElement anchorElement, + PsiElement anchorElementIfAll + ) { + final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expr != null ? expr : anchorElement, PsiMethod.class); + + PsiLocalVariable localVariable = null; + if (expr instanceof PsiReferenceExpression) { + PsiElement ref = ((PsiReferenceExpression) expr).resolve(); + if (ref instanceof PsiLocalVariable) { + localVariable = (PsiLocalVariable) ref; + } + } + else if (anchorElement instanceof PsiLocalVariable) { + localVariable = (PsiLocalVariable) anchorElement; + } + + String enteredName = null; + boolean replaceAllOccurrences = true; + + final AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); + if (activeIntroducer != null) { + activeIntroducer.stopIntroduce(editor); + expr = (PsiExpression) activeIntroducer.getExpr(); + localVariable = (PsiLocalVariable) activeIntroducer.getLocalVariable(); + occurrences = (PsiExpression[]) activeIntroducer.getOccurrences(); + enteredName = activeIntroducer.getInputName(); + replaceAllOccurrences = activeIntroducer.isReplaceAllOccurrences(); + type = ((InplaceIntroduceConstantPopup) activeIntroducer).getType(); + } + + for (PsiExpression occurrence : occurrences) { + if (RefactoringUtil.isAssignmentLHS(occurrence)) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(LocalizeValue.localizeTODO( + "Selected expression is used for write" + )); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID()); + highlightError(project, editor, occurrence); + return null; + } + } + + if (localVariable == null) { + final PsiElement errorElement = isStaticFinalInitializer(expr); + if (errorElement != null) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.selectedExpressionCannotBeAConstantInitializer()); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID()); + highlightError(project, editor, errorElement); + return null; + } + } + else { + final PsiExpression initializer = localVariable.getInitializer(); + if (initializer == null) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.variableDoesNotHaveAnInitializer(localVariable.getName()) + ); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID()); + return null; + } + final PsiElement errorElement = isStaticFinalInitializer(initializer); + if (errorElement != null) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.initializerForVariableCannotBeAConstantInitializer(localVariable.getName())); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID()); + highlightError(project, editor, errorElement); + return null; + } + } + + final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurrences); + if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled() && + (expr == null || expr.isPhysical()) && activeIntroducer == null) { + myInplaceIntroduceConstantPopup = + new InplaceIntroduceConstantPopup(project, editor, parentClass, expr, localVariable, occurrences, + typeSelectorManager, + anchorElement, anchorElementIfAll, + expr != null ? createOccurrenceManager(expr, parentClass) : null + ); + if (myInplaceIntroduceConstantPopup.startInplaceIntroduceTemplate()) { + return null; + } + } + + + final IntroduceConstantDialog dialog = + new IntroduceConstantDialog(project, parentClass, expr, localVariable, localVariable != null, occurrences, getParentClass(), + typeSelectorManager, enteredName + ); + dialog.setReplaceAllOccurrences(replaceAllOccurrences); + dialog.show(); + if (!dialog.isOK()) { + return null; + } + return new Settings(dialog.getEnteredName(), expr, occurrences, dialog.isReplaceAllOccurrences(), true, true, + InitializationPlace.IN_FIELD_DECLARATION, dialog.getFieldVisibility(), localVariable, + dialog.getSelectedType(), dialog.isDeleteVariable(), dialog.getDestinationClass(), + dialog.isAnnotateAsNonNls(), + dialog.introduceEnumConstant() + ); } - } - - protected String getRefactoringName() { - return REFACTORING_NAME; - } - - @Override - public AbstractInplaceIntroducer getInplaceIntroducer() { - return myInplaceIntroduceConstantPopup; - } - - @Nullable - private PsiElement isStaticFinalInitializer(PsiExpression expr) { - PsiClass parentClass = expr != null ? getParentClass(expr) : null; - if (parentClass == null) return null; - IsStaticFinalInitializerExpression visitor = new IsStaticFinalInitializerExpression(parentClass, expr); - expr.accept(visitor); - return visitor.getElementReference(); - } - - protected OccurrenceManager createOccurrenceManager(final PsiExpression selectedExpr, final PsiClass parentClass) { - return new ExpressionOccurrenceManager(selectedExpr, parentClass, null); - } - - private static class IsStaticFinalInitializerExpression extends ClassMemberReferencesVisitor { - private PsiElement myElementReference = null; - private final PsiExpression myInitializer; - - public IsStaticFinalInitializerExpression(PsiClass aClass, PsiExpression initializer) { - super(aClass); - myInitializer = initializer; + + private static void highlightError(Project project, Editor editor, PsiElement errorElement) { + if (editor != null) { + final TextRange textRange = errorElement.getTextRange(); + HighlightManager.getInstance(project) + .addRangeHighlight( + editor, + textRange.getStartOffset(), + textRange.getEndOffset(), + EditorColors.SEARCH_RESULT_ATTRIBUTES, + true, + new ArrayList() + ); + } } - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - final PsiElement psiElement = expression.resolve(); - if ((psiElement instanceof PsiLocalVariable || psiElement instanceof PsiParameter) && - !PsiTreeUtil.isAncestor(myInitializer, psiElement, false)) { - myElementReference = expression; - } - else { - super.visitReferenceExpression(expression); - } + protected LocalizeValue getRefactoringName() { + return REFACTORING_NAME; } @Override - public void visitCallExpression(PsiCallExpression callExpression) { - super.visitCallExpression(callExpression); - final List checkedExceptions = ExceptionUtil.getThrownCheckedExceptions(new PsiElement[]{callExpression}); - if (!checkedExceptions.isEmpty()) { - myElementReference = callExpression; - } + public AbstractInplaceIntroducer getInplaceIntroducer() { + return myInplaceIntroduceConstantPopup; } - protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { - if (!classMember.hasModifierProperty(PsiModifier.STATIC)) { - myElementReference = classMemberReference; - } + @Nullable + private PsiElement isStaticFinalInitializer(PsiExpression expr) { + PsiClass parentClass = expr != null ? getParentClass(expr) : null; + if (parentClass == null) { + return null; + } + IsStaticFinalInitializerExpression visitor = new IsStaticFinalInitializerExpression(parentClass, expr); + expr.accept(visitor); + return visitor.getElementReference(); } - @Override - public void visitElement(PsiElement element) { - if (myElementReference != null) return; - super.visitElement(element); + protected OccurrenceManager createOccurrenceManager(final PsiExpression selectedExpr, final PsiClass parentClass) { + return new ExpressionOccurrenceManager(selectedExpr, parentClass, null); } - @Nullable - public PsiElement getElementReference() { - return myElementReference; + private static class IsStaticFinalInitializerExpression extends ClassMemberReferencesVisitor { + private PsiElement myElementReference = null; + private final PsiExpression myInitializer; + + public IsStaticFinalInitializerExpression(PsiClass aClass, PsiExpression initializer) { + super(aClass); + myInitializer = initializer; + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiElement psiElement = expression.resolve(); + if ((psiElement instanceof PsiLocalVariable || psiElement instanceof PsiParameter) && + !PsiTreeUtil.isAncestor(myInitializer, psiElement, false)) { + myElementReference = expression; + } + else { + super.visitReferenceExpression(expression); + } + } + + @Override + public void visitCallExpression(PsiCallExpression callExpression) { + super.visitCallExpression(callExpression); + final List checkedExceptions = ExceptionUtil.getThrownCheckedExceptions(new PsiElement[]{callExpression}); + if (!checkedExceptions.isEmpty()) { + myElementReference = callExpression; + } + } + + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if (!classMember.hasModifierProperty(PsiModifier.STATIC)) { + myElementReference = classMemberReference; + } + } + + @Override + public void visitElement(PsiElement element) { + if (myElementReference != null) { + return; + } + super.visitElement(element); + } + + @Nullable + public PsiElement getElementReference() { + return myElementReference; + } } - } - - public PsiClass getParentClass(@Nonnull PsiExpression initializerExpression) { - final PsiType type = initializerExpression.getType(); - if (type != null && PsiUtil.isConstantExpression(initializerExpression)) { - if (type instanceof PsiPrimitiveType || - PsiType.getJavaLangString(initializerExpression.getManager(), initializerExpression.getResolveScope()).equals(type)) { - return super.getParentClass(initializerExpression); - } + public PsiClass getParentClass(@Nonnull PsiExpression initializerExpression) { + final PsiType type = initializerExpression.getType(); + + if (type != null && PsiUtil.isConstantExpression(initializerExpression)) { + if (type instanceof PsiPrimitiveType || + PsiType.getJavaLangString(initializerExpression.getManager(), initializerExpression.getResolveScope()).equals(type)) { + return super.getParentClass(initializerExpression); + } + } + + PsiElement parent = initializerExpression.getUserData(ElementToWorkOn.PARENT); + if (parent == null) { + parent = initializerExpression; + } + PsiClass aClass = PsiTreeUtil.getParentOfType(parent, PsiClass.class); + while (aClass != null) { + if (aClass.hasModifierProperty(PsiModifier.STATIC)) { + return aClass; + } + if (aClass.getParent() instanceof PsiJavaFile) { + return aClass; + } + aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class); + } + return null; } - PsiElement parent = initializerExpression.getUserData(ElementToWorkOn.PARENT); - if (parent == null) parent = initializerExpression; - PsiClass aClass = PsiTreeUtil.getParentOfType(parent, PsiClass.class); - while (aClass != null) { - if (aClass.hasModifierProperty(PsiModifier.STATIC)) return aClass; - if (aClass.getParent() instanceof PsiJavaFile) return aClass; - aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class); + @Override + protected boolean accept(ElementToWorkOn elementToWorkOn) { + final PsiExpression expr = elementToWorkOn.getExpression(); + if (expr != null) { + return isStaticFinalInitializer(expr) == null; + } + final PsiLocalVariable localVariable = elementToWorkOn.getLocalVariable(); + final PsiExpression initializer = localVariable.getInitializer(); + return initializer != null && isStaticFinalInitializer(initializer) == null; } - return null; - } - - @Override - protected boolean accept(ElementToWorkOn elementToWorkOn) { - final PsiExpression expr = elementToWorkOn.getExpression(); - if (expr != null) { - return isStaticFinalInitializer(expr) == null; + + protected boolean validClass(PsiClass parentClass, Editor editor) { + return true; } - final PsiLocalVariable localVariable = elementToWorkOn.getLocalVariable(); - final PsiExpression initializer = localVariable.getInitializer(); - return initializer != null && isStaticFinalInitializer(initializer) == null; - } - - protected boolean validClass(PsiClass parentClass, Editor editor) { - return true; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceFieldHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceFieldHandler.java index 96ab25ac1..b99d92366 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceFieldHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceField/IntroduceFieldHandler.java @@ -23,7 +23,6 @@ import com.intellij.java.language.psi.util.PsiUtil; import consulo.codeEditor.Editor; import consulo.dataContext.DataContext; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.introduce.inplace.AbstractInplaceIntroducer; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; @@ -33,220 +32,255 @@ import consulo.language.psi.util.PsiTreeUtil; import consulo.localize.LocalizeValue; import consulo.project.Project; -import consulo.project.ui.wm.WindowManager; +import consulo.ui.annotation.RequiredUIAccess; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import java.util.List; public class IntroduceFieldHandler extends BaseExpressionToFieldHandler implements JavaIntroduceFieldHandlerBase { + public static final LocalizeValue REFACTORING_NAME = RefactoringLocalize.introduceFieldTitle(); + private static final MyOccurrenceFilter MY_OCCURRENCE_FILTER = new MyOccurrenceFilter(); + private InplaceIntroduceFieldPopup myInplaceIntroduceFieldPopup; - public static final String REFACTORING_NAME = RefactoringBundle.message("introduce.field.title"); - private static final MyOccurrenceFilter MY_OCCURRENCE_FILTER = new MyOccurrenceFilter(); - private InplaceIntroduceFieldPopup myInplaceIntroduceFieldPopup; - - public IntroduceFieldHandler() { - super(false); - } - - protected String getRefactoringName() { - return REFACTORING_NAME; - } - - protected boolean validClass(PsiClass parentClass, Editor editor) { - if (parentClass.isInterface()) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.cannotIntroduceFieldInInterface()); - CommonRefactoringUtil.showErrorHint(parentClass.getProject(), editor, message.get(), REFACTORING_NAME, getHelpID()); - return false; + public IntroduceFieldHandler() { + super(false); } - else { - return true; + + @Nonnull + @Override + protected LocalizeValue getRefactoringName() { + return REFACTORING_NAME; } - } - - protected String getHelpID() { - return HelpID.INTRODUCE_FIELD; - } - - public void invoke(@Nonnull final Project project, final Editor editor, PsiFile file, DataContext dataContext) { - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return; - PsiDocumentManager.getInstance(project).commitAllDocuments(); - - ElementToWorkOn.processElementToWorkOn(editor, - file, - REFACTORING_NAME, - HelpID.INTRODUCE_FIELD, - project, - getElementProcessor(project, editor)); - } - - protected Settings showRefactoringDialog(Project project, Editor editor, PsiClass parentClass, PsiExpression expr, - PsiType type, - PsiExpression[] occurrences, PsiElement anchorElement, PsiElement anchorElementIfAll) { - final AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); - - PsiLocalVariable localVariable = null; - if (anchorElement instanceof PsiLocalVariable) { - localVariable = (PsiLocalVariable)anchorElement; + + @Override + @RequiredUIAccess + protected boolean validClass(PsiClass parentClass, Editor editor) { + if (parentClass.isInterface()) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.cannotIntroduceFieldInInterface()); + CommonRefactoringUtil.showErrorHint(parentClass.getProject(), editor, message, REFACTORING_NAME, getHelpID()); + return false; + } + else { + return true; + } } - else if (expr instanceof PsiReferenceExpression) { - PsiElement ref = ((PsiReferenceExpression)expr).resolve(); - if (ref instanceof PsiLocalVariable) { - localVariable = (PsiLocalVariable)ref; - } + + @Override + protected String getHelpID() { + return HelpID.INTRODUCE_FIELD; } - String enteredName = null; - boolean replaceAll = false; - if (activeIntroducer != null) { - activeIntroducer.stopIntroduce(editor); - expr = (PsiExpression)activeIntroducer.getExpr(); - localVariable = (PsiLocalVariable)activeIntroducer.getLocalVariable(); - occurrences = (PsiExpression[])activeIntroducer.getOccurrences(); - enteredName = activeIntroducer.getInputName(); - replaceAll = activeIntroducer.isReplaceAllOccurrences(); - type = ((AbstractJavaInplaceIntroducer)activeIntroducer).getType(); - IntroduceFieldDialog.ourLastInitializerPlace = ((InplaceIntroduceFieldPopup)activeIntroducer).getInitializerPlace(); + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, Editor editor, PsiFile file, DataContext dataContext) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { + return; + } + PsiDocumentManager.getInstance(project).commitAllDocuments(); + + ElementToWorkOn.processElementToWorkOn( + editor, + file, + REFACTORING_NAME.get(), + HelpID.INTRODUCE_FIELD, + project, + getElementProcessor(project, editor) + ); } - final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expr != null ? expr : anchorElement, PsiMethod.class); - final PsiModifierListOwner staticParentElement = PsiUtil.getEnclosingStaticElement(getElement(expr, anchorElement), parentClass); - boolean declareStatic = staticParentElement != null; - - boolean isInSuperOrThis = false; - if (!declareStatic) { - for (int i = 0; !declareStatic && i < occurrences.length; i++) { - PsiExpression occurrence = occurrences[i]; - isInSuperOrThis = isInSuperOrThis(occurrence); - declareStatic = isInSuperOrThis; - } + @Override + @RequiredUIAccess + protected Settings showRefactoringDialog( + Project project, + Editor editor, + PsiClass parentClass, + PsiExpression expr, + PsiType type, + PsiExpression[] occurrences, + PsiElement anchorElement, + PsiElement anchorElementIfAll + ) { + AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); + + PsiLocalVariable localVariable = null; + if (anchorElement instanceof PsiLocalVariable localVar) { + localVariable = localVar; + } + else if (expr instanceof PsiReferenceExpression refExpr) { + if (refExpr.resolve() instanceof PsiLocalVariable localVar) { + localVariable = localVar; + } + } + + String enteredName = null; + boolean replaceAll = false; + if (activeIntroducer != null) { + activeIntroducer.stopIntroduce(editor); + expr = (PsiExpression) activeIntroducer.getExpr(); + localVariable = (PsiLocalVariable) activeIntroducer.getLocalVariable(); + occurrences = (PsiExpression[]) activeIntroducer.getOccurrences(); + enteredName = activeIntroducer.getInputName(); + replaceAll = activeIntroducer.isReplaceAllOccurrences(); + type = ((AbstractJavaInplaceIntroducer) activeIntroducer).getType(); + IntroduceFieldDialog.ourLastInitializerPlace = ((InplaceIntroduceFieldPopup) activeIntroducer).getInitializerPlace(); + } + + PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expr != null ? expr : anchorElement, PsiMethod.class); + PsiModifierListOwner staticParentElement = PsiUtil.getEnclosingStaticElement(getElement(expr, anchorElement), parentClass); + boolean declareStatic = staticParentElement != null; + + boolean isInSuperOrThis = false; + if (!declareStatic) { + for (int i = 0; !declareStatic && i < occurrences.length; i++) { + PsiExpression occurrence = occurrences[i]; + isInSuperOrThis = isInSuperOrThis(occurrence); + declareStatic = isInSuperOrThis; + } + } + boolean currentMethodConstructor = containingMethod != null && containingMethod.isConstructor(); + boolean allowInitInMethod = (!currentMethodConstructor || !isInSuperOrThis) + && (anchorElement instanceof PsiLocalVariable || anchorElement instanceof PsiStatement); + boolean allowInitInMethodIfAll = + (!currentMethodConstructor || !isInSuperOrThis) && anchorElementIfAll instanceof PsiStatement; + + if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled() && + (expr == null || expr.isPhysical()) && activeIntroducer == null) { + myInplaceIntroduceFieldPopup = + new InplaceIntroduceFieldPopup(localVariable, parentClass, declareStatic, currentMethodConstructor, occurrences, expr, + new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurrences), editor, + allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, + expr != null ? createOccurrenceManager(expr, parentClass) : null, project + ); + if (myInplaceIntroduceFieldPopup.startInplaceIntroduceTemplate()) { + return null; + } + } + + IntroduceFieldDialog dialog = new IntroduceFieldDialog( + project, parentClass, expr, localVariable, + currentMethodConstructor, + localVariable != null, declareStatic, occurrences, + allowInitInMethod, allowInitInMethodIfAll, + new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurrences), + enteredName + ); + dialog.setReplaceAllOccurrences(replaceAll); + dialog.show(); + + if (!dialog.isOK()) { + return null; + } + + if (!dialog.isDeleteVariable()) { + localVariable = null; + } + + + return new Settings(dialog.getEnteredName(), expr, occurrences, dialog.isReplaceAllOccurrences(), + declareStatic, dialog.isDeclareFinal(), + dialog.getInitializerPlace(), dialog.getFieldVisibility(), + localVariable, + dialog.getFieldType(), localVariable != null, (TargetDestination) null, false, false + ); } - int occurrencesNumber = occurrences.length; - final boolean currentMethodConstructor = containingMethod != null && containingMethod.isConstructor(); - final boolean allowInitInMethod = - (!currentMethodConstructor || !isInSuperOrThis) && (anchorElement instanceof PsiLocalVariable || anchorElement instanceof PsiStatement); - final boolean allowInitInMethodIfAll = (!currentMethodConstructor || !isInSuperOrThis) && anchorElementIfAll instanceof PsiStatement; - - if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled() && - (expr == null || expr.isPhysical()) && activeIntroducer == null) { - myInplaceIntroduceFieldPopup = - new InplaceIntroduceFieldPopup(localVariable, parentClass, declareStatic, currentMethodConstructor, occurrences, expr, - new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurrences), editor, - allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, - expr != null ? createOccurrenceManager(expr, parentClass) : null, project); - if (myInplaceIntroduceFieldPopup.startInplaceIntroduceTemplate()) { - return null; - } + + @Override + protected boolean accept(ElementToWorkOn elementToWorkOn) { + return true; } - IntroduceFieldDialog dialog = new IntroduceFieldDialog( - project, parentClass, expr, localVariable, - currentMethodConstructor, - localVariable != null, declareStatic, occurrences, - allowInitInMethod, allowInitInMethodIfAll, - new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurrences), - enteredName - ); - dialog.setReplaceAllOccurrences(replaceAll); - dialog.show(); - - if (!dialog.isOK()) { - return null; + private static PsiElement getElement(PsiExpression expr, PsiElement anchorElement) { + PsiElement element = null; + if (expr != null) { + element = expr.getUserData(ElementToWorkOn.PARENT); + if (element == null) { + element = expr; + } + } + if (element == null) { + element = anchorElement; + } + return element; } - if (!dialog.isDeleteVariable()) { - localVariable = null; + @Override + public AbstractInplaceIntroducer getInplaceIntroducer() { + return myInplaceIntroduceFieldPopup; } + private static boolean isInSuperOrThis(PsiExpression occurrence) { + return !NotInSuperCallOccurrenceFilter.INSTANCE.isOK(occurrence) || !NotInThisCallFilter.INSTANCE.isOK(occurrence); + } - return new Settings(dialog.getEnteredName(), expr, occurrences, dialog.isReplaceAllOccurrences(), - declareStatic, dialog.isDeclareFinal(), - dialog.getInitializerPlace(), dialog.getFieldVisibility(), - localVariable, - dialog.getFieldType(), localVariable != null, (TargetDestination)null, false, false); - } + @Override + protected OccurrenceManager createOccurrenceManager(PsiExpression selectedExpr, PsiClass parentClass) { + OccurrenceFilter occurrenceFilter = isInSuperOrThis(selectedExpr) ? null : MY_OCCURRENCE_FILTER; + return new ExpressionOccurrenceManager(selectedExpr, parentClass, occurrenceFilter, true); + } - @Override - protected boolean accept(ElementToWorkOn elementToWorkOn) { - return true; - } + @Override + @RequiredUIAccess + protected boolean invokeImpl(final Project project, PsiLocalVariable localVariable, final Editor editor) { + PsiElement parent = localVariable.getParent(); + if (!(parent instanceof PsiDeclarationStatement)) { + LocalizeValue message = + RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.errorWrongCaretPositionLocalOrExpressionName()); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID()); + return false; + } + LocalToFieldHandler localToFieldHandler = new LocalToFieldHandler(project, false) { + @Override + protected Settings showRefactoringDialog( + PsiClass aClass, + PsiLocalVariable local, + PsiExpression[] occurrences, + boolean isStatic + ) { + PsiStatement statement = PsiTreeUtil.getParentOfType(local, PsiStatement.class); + return IntroduceFieldHandler.this.showRefactoringDialog( + project, + editor, + aClass, + local.getInitializer(), + local.getType(), + occurrences, + local, + statement + ); + } - private static PsiElement getElement(PsiExpression expr, PsiElement anchorElement) { - PsiElement element = null; - if (expr != null) { - element = expr.getUserData(ElementToWorkOn.PARENT); - if (element == null) element = expr; - } - if (element == null) element = anchorElement; - return element; - } - - @Override - public AbstractInplaceIntroducer getInplaceIntroducer() { - return myInplaceIntroduceFieldPopup; - } - - private static boolean isInSuperOrThis(PsiExpression occurrence) { - return !NotInSuperCallOccurrenceFilter.INSTANCE.isOK(occurrence) || !NotInThisCallFilter.INSTANCE.isOK(occurrence); - } - - protected OccurrenceManager createOccurrenceManager(final PsiExpression selectedExpr, final PsiClass parentClass) { - final OccurrenceFilter occurrenceFilter = isInSuperOrThis(selectedExpr) ? null : MY_OCCURRENCE_FILTER; - return new ExpressionOccurrenceManager(selectedExpr, parentClass, occurrenceFilter, true); - } - - protected boolean invokeImpl(final Project project, PsiLocalVariable localVariable, final Editor editor) { - final PsiElement parent = localVariable.getParent(); - if (!(parent instanceof PsiDeclarationStatement)) { - LocalizeValue message = - RefactoringLocalize.cannotPerformRefactoringWithReason(RefactoringLocalize.errorWrongCaretPositionLocalOrExpressionName()); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, getHelpID()); - return false; - } - LocalToFieldHandler localToFieldHandler = new LocalToFieldHandler(project, false) { - @Override - protected Settings showRefactoringDialog(PsiClass aClass, - PsiLocalVariable local, - PsiExpression[] occurences, - boolean isStatic) { - final PsiStatement statement = PsiTreeUtil.getParentOfType(local, PsiStatement.class); - return IntroduceFieldHandler.this.showRefactoringDialog(project, - editor, - aClass, - local.getInitializer(), - local.getType(), - occurences, - local, - statement); - } - - @Override - protected int getChosenClassIndex(List classes) { - return IntroduceFieldHandler.this.getChosenClassIndex(classes); - } - }; - return localToFieldHandler.convertLocalToField(localVariable, editor); - } - - public void invoke(@Nonnull Project project, PsiElement element, @Nullable Editor editor) { - if (element instanceof PsiExpression) { - invokeImpl(project, (PsiExpression)element, editor); + @Override + protected int getChosenClassIndex(List classes) { + return IntroduceFieldHandler.this.getChosenClassIndex(classes); + } + }; + return localToFieldHandler.convertLocalToField(localVariable, editor); } - else if (element instanceof PsiLocalVariable) { - invokeImpl(project, (PsiLocalVariable)element, editor); - } - else { - LOG.error("elements[0] should be PsiExpression or PsiLocalVariable; was " + element); + + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, PsiElement element, @Nullable Editor editor) { + if (element instanceof PsiExpression) { + invokeImpl(project, (PsiExpression) element, editor); + } + else if (element instanceof PsiLocalVariable) { + invokeImpl(project, (PsiLocalVariable) element, editor); + } + else { + LOG.error("elements[0] should be PsiExpression or PsiLocalVariable; was " + element); + } } - } - protected int getChosenClassIndex(List classes) { - return classes.size() - 1; - } + protected int getChosenClassIndex(List classes) { + return classes.size() - 1; + } - private static class MyOccurrenceFilter implements OccurrenceFilter { - public boolean isOK(PsiExpression occurrence) { - return !isInSuperOrThis(occurrence); + private static class MyOccurrenceFilter implements OccurrenceFilter { + @Override + public boolean isOK(PsiExpression occurrence) { + return !isInSuperOrThis(occurrence); + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/JavaIntroduceParameterMethodUsagesProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/JavaIntroduceParameterMethodUsagesProcessor.java index 72544fdb5..d35c6c9a6 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/JavaIntroduceParameterMethodUsagesProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/JavaIntroduceParameterMethodUsagesProcessor.java @@ -33,6 +33,7 @@ import consulo.language.psi.PsiElement; 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.UsageInfo; @@ -48,262 +49,294 @@ */ @ExtensionImpl public class JavaIntroduceParameterMethodUsagesProcessor implements IntroduceParameterMethodUsagesProcessor { - private static final Logger LOG = - Logger.getInstance(JavaIntroduceParameterMethodUsagesProcessor.class); - private static final JavaLanguage myLanguage = Language.findInstance(JavaLanguage.class); + private static final Logger LOG = + Logger.getInstance(JavaIntroduceParameterMethodUsagesProcessor.class); + private static final JavaLanguage myLanguage = Language.findInstance(JavaLanguage.class); - private static boolean isJavaUsage(UsageInfo usage) { - PsiElement e = usage.getElement(); - return e != null && e.getLanguage().is(myLanguage); - } - - public boolean isMethodUsage(UsageInfo usage) { - return RefactoringUtil.isMethodUsage(usage.getElement()) && isJavaUsage(usage); - } - - public boolean processChangeMethodUsage(IntroduceParameterData data, - UsageInfo usage, - UsageInfo[] usages) throws IncorrectOperationException { - if (!isMethodUsage(usage)) { - return true; - } - final PsiElement ref = usage.getElement(); - PsiCall callExpression = RefactoringUtil.getCallExpressionByMethodReference(ref); - PsiExpressionList argList = RefactoringUtil.getArgumentListByMethodReference(ref); - if (argList == null) { - return true; + private static boolean isJavaUsage(UsageInfo usage) { + PsiElement e = usage.getElement(); + return e != null && e.getLanguage().is(myLanguage); } - PsiExpression[] oldArgs = argList.getExpressions(); - final PsiExpression anchor; - final PsiMethod methodToSearchFor = data.getMethodToSearchFor(); - if (!methodToSearchFor.isVarArgs()) { - anchor = getLast(oldArgs); - } - else { - final PsiParameter[] parameters = methodToSearchFor.getParameterList().getParameters(); - if (parameters.length > oldArgs.length) { - anchor = getLast(oldArgs); - } - else { - LOG.assertTrue(parameters.length > 0); - final int lastNonVararg = parameters.length - 2; - anchor = lastNonVararg >= 0 ? oldArgs[lastNonVararg] : null; - } + public boolean isMethodUsage(UsageInfo usage) { + return RefactoringUtil.isMethodUsage(usage.getElement()) && isJavaUsage(usage); } - //if we insert parameter in method usage which is contained in method in which we insert this parameter too, we must insert parameter name instead of its initializer - PsiMethod method = PsiTreeUtil.getParentOfType(argList, PsiMethod.class); - if (method != null && IntroduceParameterUtil.isMethodInUsages(data, method, usages)) { - argList - .addAfter(JavaPsiFacade.getElementFactory(data.getProject()).createExpressionFromText(data.getParameterName(), argList), anchor); - } - else { - PsiElement initializer = - ExpressionConverter.getExpression(data.getParameterInitializer().getExpression(), JavaLanguage.INSTANCE, data.getProject()); - assert initializer instanceof PsiExpression; - if (initializer instanceof PsiNewExpression) { - if (!PsiDiamondTypeUtil.canChangeContextForDiamond((PsiNewExpression)initializer, ((PsiNewExpression)initializer).getType())) { - initializer = PsiDiamondTypeUtil.expandTopLevelDiamondsInside((PsiNewExpression)initializer); + public boolean processChangeMethodUsage( + IntroduceParameterData data, + UsageInfo usage, + UsageInfo[] usages + ) throws IncorrectOperationException { + if (!isMethodUsage(usage)) { + return true; } - } - substituteTypeParametersInInitializer(initializer, callExpression, argList, methodToSearchFor); - ChangeContextUtil.encodeContextInfo(initializer, true); - PsiExpression newArg = (PsiExpression)argList.addAfter(initializer, anchor); - ChangeContextUtil.decodeContextInfo(newArg, null, null); - ChangeContextUtil.clearContextInfo(initializer); - - // here comes some postprocessing... - new OldReferenceResolver(callExpression, newArg, data.getMethodToReplaceIn(), data.getReplaceFieldsWithGetters(), initializer) - .resolve(); - } - - - final PsiExpressionList argumentList = callExpression.getArgumentList(); - LOG.assertTrue(argumentList != null, callExpression.getText()); - removeParametersFromCall(argumentList, data.getParametersToRemove()); - return false; - } + final PsiElement ref = usage.getElement(); + PsiCall callExpression = RefactoringUtil.getCallExpressionByMethodReference(ref); + PsiExpressionList argList = RefactoringUtil.getArgumentListByMethodReference(ref); + if (argList == null) { + return true; + } + PsiExpression[] oldArgs = argList.getExpressions(); - private static void substituteTypeParametersInInitializer(PsiElement initializer, - PsiCall callExpression, - PsiExpressionList argList, - PsiMethod method) { - final Project project = method.getProject(); - final PsiSubstitutor psiSubstitutor = JavaPsiFacade.getInstance(project).getResolveHelper() - .inferTypeArguments(method.getTypeParameters(), - method.getParameterList().getParameters(), - argList.getExpressions(), - PsiSubstitutor.EMPTY, - callExpression, - DefaultParameterTypeInferencePolicy.INSTANCE); - RefactoringUtil.replaceMovedMemberTypeParameters(initializer, PsiUtil.typeParametersIterable(method), psiSubstitutor, - JavaPsiFacade.getElementFactory(project)); - } + final PsiExpression anchor; + final PsiMethod methodToSearchFor = data.getMethodToSearchFor(); + if (!methodToSearchFor.isVarArgs()) { + anchor = getLast(oldArgs); + } + else { + final PsiParameter[] parameters = methodToSearchFor.getParameterList().getParameters(); + if (parameters.length > oldArgs.length) { + anchor = getLast(oldArgs); + } + else { + LOG.assertTrue(parameters.length > 0); + final int lastNonVararg = parameters.length - 2; + anchor = lastNonVararg >= 0 ? oldArgs[lastNonVararg] : null; + } + } - private static void removeParametersFromCall(@Nonnull final PsiExpressionList argList, IntList parametersToRemove) { - final PsiExpression[] exprs = argList.getExpressions(); + //if we insert parameter in method usage which is contained in method in which we insert this parameter too, we must insert parameter name instead of its initializer + PsiMethod method = PsiTreeUtil.getParentOfType(argList, PsiMethod.class); + if (method != null && IntroduceParameterUtil.isMethodInUsages(data, method, usages)) { + argList + .addAfter( + JavaPsiFacade.getElementFactory(data.getProject()).createExpressionFromText(data.getParameterName(), argList), + anchor + ); + } + else { + PsiElement initializer = + ExpressionConverter.getExpression(data.getParameterInitializer().getExpression(), JavaLanguage.INSTANCE, data.getProject()); + assert initializer instanceof PsiExpression; + if (initializer instanceof PsiNewExpression) { + if (!PsiDiamondTypeUtil.canChangeContextForDiamond( + (PsiNewExpression) initializer, + ((PsiNewExpression) initializer).getType() + )) { + initializer = PsiDiamondTypeUtil.expandTopLevelDiamondsInside((PsiNewExpression) initializer); + } + } + substituteTypeParametersInInitializer(initializer, callExpression, argList, methodToSearchFor); + ChangeContextUtil.encodeContextInfo(initializer, true); + PsiExpression newArg = (PsiExpression) argList.addAfter(initializer, anchor); + ChangeContextUtil.decodeContextInfo(newArg, null, null); + ChangeContextUtil.clearContextInfo(initializer); - IntList reverse = IntLists.newArrayList(parametersToRemove.toArray()); - IntLists.reverse(reverse); - reverse.forEach(paramNum -> { - try { - if (paramNum < exprs.length) { - exprs[paramNum].delete(); + // here comes some postprocessing... + new OldReferenceResolver(callExpression, newArg, data.getMethodToReplaceIn(), data.getReplaceFieldsWithGetters(), initializer) + .resolve(); } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - }); - } - @Nullable - private static PsiExpression getLast(PsiExpression[] oldArgs) { - PsiExpression anchor; - if (oldArgs.length > 0) { - anchor = oldArgs[oldArgs.length - 1]; + + final PsiExpressionList argumentList = callExpression.getArgumentList(); + LOG.assertTrue(argumentList != null, callExpression.getText()); + removeParametersFromCall(argumentList, data.getParametersToRemove()); + return false; } - else { - anchor = null; + + private static void substituteTypeParametersInInitializer( + PsiElement initializer, + PsiCall callExpression, + PsiExpressionList argList, + PsiMethod method + ) { + final Project project = method.getProject(); + final PsiSubstitutor psiSubstitutor = JavaPsiFacade.getInstance(project).getResolveHelper() + .inferTypeArguments( + method.getTypeParameters(), + method.getParameterList().getParameters(), + argList.getExpressions(), + PsiSubstitutor.EMPTY, + callExpression, + DefaultParameterTypeInferencePolicy.INSTANCE + ); + RefactoringUtil.replaceMovedMemberTypeParameters(initializer, PsiUtil.typeParametersIterable(method), psiSubstitutor, + JavaPsiFacade.getElementFactory(project) + ); } - return anchor; - } + private static void removeParametersFromCall(@Nonnull final PsiExpressionList argList, IntList parametersToRemove) { + final PsiExpression[] exprs = argList.getExpressions(); - public void findConflicts(IntroduceParameterData data, UsageInfo[] usages, final MultiMap conflicts) { - final PsiMethod method = data.getMethodToReplaceIn(); - final int parametersCount = method.getParameterList().getParametersCount(); - for (UsageInfo usage : usages) { - if (!isMethodUsage(usage)) { - continue; - } - final PsiElement element = usage.getElement(); - final PsiCall call = RefactoringUtil.getCallExpressionByMethodReference(element); - final PsiExpressionList argList = call.getArgumentList(); - if (argList != null) { - final int actualParamLength = argList.getExpressions().length; - if ((method.isVarArgs() && actualParamLength + 1 < parametersCount) || - (!method.isVarArgs() && actualParamLength < parametersCount)) { - conflicts.putValue(call, - "Incomplete call(" + call.getText() + "): " + parametersCount + " parameters expected but only " + actualParamLength + " found"); - } - data.getParametersToRemove().forEach(paramNum -> { - if (paramNum >= actualParamLength) { - conflicts.putValue(call, - "Incomplete call(" + call.getText() + "): expected to delete the " + paramNum + " parameter but only " + actualParamLength + " parameters found"); - } + IntList reverse = IntLists.newArrayList(parametersToRemove.toArray()); + IntLists.reverse(reverse); + reverse.forEach(paramNum -> { + try { + if (paramNum < exprs.length) { + exprs[paramNum].delete(); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } }); - } } - } - public boolean processChangeMethodSignature(IntroduceParameterData data, - UsageInfo usage, - UsageInfo[] usages) throws IncorrectOperationException { - if (!(usage.getElement() instanceof PsiMethod) || !isJavaUsage(usage)) { - return true; + @Nullable + private static PsiExpression getLast(PsiExpression[] oldArgs) { + PsiExpression anchor; + if (oldArgs.length > 0) { + anchor = oldArgs[oldArgs.length - 1]; + } + else { + anchor = null; + } + return anchor; } - PsiMethod method = (PsiMethod)usage.getElement(); - final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(data.getParameterName(), method.getBody()); - final MethodJavaDocHelper javaDocHelper = new MethodJavaDocHelper(method); - PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory(); + @Override + public void findConflicts(IntroduceParameterData data, UsageInfo[] usages, MultiMap conflicts) { + final PsiMethod method = data.getMethodToReplaceIn(); + final int parametersCount = method.getParameterList().getParametersCount(); + for (UsageInfo usage : usages) { + if (!isMethodUsage(usage)) { + continue; + } + final PsiElement element = usage.getElement(); + final PsiCall call = RefactoringUtil.getCallExpressionByMethodReference(element); + final PsiExpressionList argList = call.getArgumentList(); + if (argList != null) { + final int actualParamLength = argList.getExpressions().length; + if ((method.isVarArgs() && actualParamLength + 1 < parametersCount) || + (!method.isVarArgs() && actualParamLength < parametersCount)) { + conflicts.putValue( + call, + LocalizeValue.localizeTODO( + "Incomplete call(" + call.getText() + "): " + parametersCount + " parameters expected " + + "but only " + actualParamLength + " found" + ) + ); + } + data.getParametersToRemove().forEach(paramNum -> { + if (paramNum >= actualParamLength) { + conflicts.putValue( + call, + LocalizeValue.localizeTODO( + "Incomplete call(" + call.getText() + "): expected to delete the " + paramNum + " parameter " + + "but only " + actualParamLength + " parameters found" + ) + ); + } + }); + } + } + } - PsiParameter parameter = factory.createParameter(data.getParameterName(), data.getForcedType()); - PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, data.isDeclareFinal()); + @Override + public boolean processChangeMethodSignature( + IntroduceParameterData data, + UsageInfo usage, + UsageInfo[] usages + ) throws IncorrectOperationException { + if (!(usage.getElement() instanceof PsiMethod) || !isJavaUsage(usage)) { + return true; + } + PsiMethod method = (PsiMethod) usage.getElement(); - final PsiParameterList parameterList = method.getParameterList(); - final PsiParameter[] parameters = parameterList.getParameters(); + final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(data.getParameterName(), method.getBody()); + final MethodJavaDocHelper javaDocHelper = new MethodJavaDocHelper(method); + PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory(); - IntList reverse = IntLists.newArrayList(data.getParametersToRemove().toArray()); - IntLists.reverse(reverse); + PsiParameter parameter = factory.createParameter(data.getParameterName(), data.getForcedType()); + PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, data.isDeclareFinal()); - reverse.forEach(paramNum -> { - try { - PsiParameter param = parameters[paramNum]; - PsiDocTag tag = javaDocHelper.getTagForParameter(param); - if (tag != null) { - tag.delete(); - } - param.delete(); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - }); + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); - final PsiParameter anchorParameter = getAnchorParameter(method); - parameter = (PsiParameter)parameterList.addAfter(parameter, anchorParameter); - JavaCodeStyleManager.getInstance(data.getProject()).shortenClassReferences(parameter); - final PsiDocTag tagForAnchorParameter = javaDocHelper.getTagForParameter(anchorParameter); - javaDocHelper.addParameterAfter(data.getParameterName(), tagForAnchorParameter); + IntList reverse = IntLists.newArrayList(data.getParametersToRemove().toArray()); + IntLists.reverse(reverse); - fieldConflictsResolver.fix(); + reverse.forEach(paramNum -> { + try { + PsiParameter param = parameters[paramNum]; + PsiDocTag tag = javaDocHelper.getTagForParameter(param); + if (tag != null) { + tag.delete(); + } + param.delete(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + }); - return false; - } + final PsiParameter anchorParameter = getAnchorParameter(method); + parameter = (PsiParameter) parameterList.addAfter(parameter, anchorParameter); + JavaCodeStyleManager.getInstance(data.getProject()).shortenClassReferences(parameter); + final PsiDocTag tagForAnchorParameter = javaDocHelper.getTagForParameter(anchorParameter); + javaDocHelper.addParameterAfter(data.getParameterName(), tagForAnchorParameter); - @Nullable - public static PsiParameter getAnchorParameter(PsiMethod methodToReplaceIn) { - PsiParameterList parameterList = methodToReplaceIn.getParameterList(); - final PsiParameter anchorParameter; - final PsiParameter[] parameters = parameterList.getParameters(); - final int length = parameters.length; - if (!methodToReplaceIn.isVarArgs()) { - anchorParameter = length > 0 ? parameters[length - 1] : null; - } - else { - LOG.assertTrue(length > 0); - LOG.assertTrue(parameters[length - 1].isVarArgs()); - anchorParameter = length > 1 ? parameters[length - 2] : null; - } - return anchorParameter; - } + fieldConflictsResolver.fix(); - public boolean processAddDefaultConstructor(IntroduceParameterData data, UsageInfo usage, UsageInfo[] usages) { - if (!(usage.getElement() instanceof PsiClass) || !isJavaUsage(usage)) { - return true; + return false; } - PsiClass aClass = (PsiClass)usage.getElement(); - if (!(aClass instanceof PsiAnonymousClass)) { - final PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory(); - PsiMethod constructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass); - constructor = (PsiMethod)CodeStyleManager.getInstance(data.getProject()).reformat(constructor); - constructor = (PsiMethod)aClass.add(constructor); - PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true); - processAddSuperCall(data, new UsageInfo(constructor), usages); - } - else { - return true; - } - return false; - } - public boolean processAddSuperCall(IntroduceParameterData data, UsageInfo usage, UsageInfo[] usages) throws IncorrectOperationException { - if (!(usage.getElement() instanceof PsiMethod) || !isJavaUsage(usage)) { - return true; + @Nullable + public static PsiParameter getAnchorParameter(PsiMethod methodToReplaceIn) { + PsiParameterList parameterList = methodToReplaceIn.getParameterList(); + final PsiParameter anchorParameter; + final PsiParameter[] parameters = parameterList.getParameters(); + final int length = parameters.length; + if (!methodToReplaceIn.isVarArgs()) { + anchorParameter = length > 0 ? parameters[length - 1] : null; + } + else { + LOG.assertTrue(length > 0); + LOG.assertTrue(parameters[length - 1].isVarArgs()); + anchorParameter = length > 1 ? parameters[length - 2] : null; + } + return anchorParameter; } - PsiMethod constructor = (PsiMethod)usage.getElement(); - if (!constructor.isConstructor()) { - return true; + public boolean processAddDefaultConstructor(IntroduceParameterData data, UsageInfo usage, UsageInfo[] usages) { + if (!(usage.getElement() instanceof PsiClass) || !isJavaUsage(usage)) { + return true; + } + PsiClass aClass = (PsiClass) usage.getElement(); + if (!(aClass instanceof PsiAnonymousClass)) { + final PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory(); + PsiMethod constructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass); + constructor = (PsiMethod) CodeStyleManager.getInstance(data.getProject()).reformat(constructor); + constructor = (PsiMethod) aClass.add(constructor); + PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true); + processAddSuperCall(data, new UsageInfo(constructor), usages); + } + else { + return true; + } + return false; } - final PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory(); - PsiExpressionStatement superCall = (PsiExpressionStatement)factory.createStatementFromText("super();", constructor); - superCall = (PsiExpressionStatement)CodeStyleManager.getInstance(data.getProject()).reformat(superCall); - PsiCodeBlock body = constructor.getBody(); - final PsiStatement[] statements = body.getStatements(); - if (statements.length > 0) { - superCall = (PsiExpressionStatement)body.addBefore(superCall, statements[0]); - } - else { - superCall = (PsiExpressionStatement)body.add(superCall); + public boolean processAddSuperCall( + IntroduceParameterData data, + UsageInfo usage, + UsageInfo[] usages + ) throws IncorrectOperationException { + if (!(usage.getElement() instanceof PsiMethod) || !isJavaUsage(usage)) { + return true; + } + PsiMethod constructor = (PsiMethod) usage.getElement(); + + if (!constructor.isConstructor()) { + return true; + } + + final PsiElementFactory factory = JavaPsiFacade.getInstance(data.getProject()).getElementFactory(); + PsiExpressionStatement superCall = (PsiExpressionStatement) factory.createStatementFromText("super();", constructor); + superCall = (PsiExpressionStatement) CodeStyleManager.getInstance(data.getProject()).reformat(superCall); + PsiCodeBlock body = constructor.getBody(); + final PsiStatement[] statements = body.getStatements(); + if (statements.length > 0) { + superCall = (PsiExpressionStatement) body.addBefore(superCall, statements[0]); + } + else { + superCall = (PsiExpressionStatement) body.add(superCall); + } + processChangeMethodUsage( + data, + new ExternalUsageInfo(((PsiMethodCallExpression) superCall.getExpression()).getMethodExpression()), + usages + ); + return false; } - processChangeMethodUsage(data, - new ExternalUsageInfo(((PsiMethodCallExpression)superCall.getExpression()).getMethodExpression()), - usages); - return false; - } }