diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java index fbdc09c4b..f894c21c6 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/makeStatic/MakeMethodOrClassStaticProcessor.java @@ -296,8 +296,8 @@ protected static boolean makeFieldParameterFinal(PsiField field, UsageInfo[] usa @Nonnull @Override @RequiredReadAction - protected String getCommandName() { - return RefactoringLocalize.makeStaticCommand(DescriptiveNameUtil.getDescriptiveName(myMember)).get(); + protected LocalizeValue getCommandName() { + return RefactoringLocalize.makeStaticCommand(DescriptiveNameUtil.getDescriptiveName(myMember)); } public T getMember() { diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHelper.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHelper.java index 223e18548..866b60c1b 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHelper.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/JavaPullUpHelper.java @@ -30,6 +30,8 @@ import com.intellij.java.language.psi.util.MethodSignatureUtil; import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.util.VisibilityUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.Language; import consulo.language.codeStyle.CodeStyleSettingsManager; import consulo.language.editor.PsiEquivalenceUtil; @@ -46,838 +48,879 @@ import consulo.project.Project; import consulo.util.dataholder.Key; import consulo.util.lang.function.Condition; +import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import java.util.*; /** - * Created by Max Medvedev on 10/3/13 + * @author Max Medvedev + * @since 2013-10-03 */ public class JavaPullUpHelper implements PullUpHelper { - private static final Logger LOG = Logger.getInstance(JavaPullUpHelper.class); - - private static final Key PRESERVE_QUALIFIER = Key.create("PRESERVE_QUALIFIER"); - - private final PsiClass mySourceClass; - private final PsiClass myTargetSuperClass; - private final boolean myIsTargetInterface; - private final DocCommentPolicy myJavaDocPolicy; - private Set myMembersAfterMove = null; - private final Set myMembersToMove; - private final Project myProject; - - private final QualifiedThisSuperAdjuster myThisSuperAdjuster; - private final ExplicitSuperDeleter myExplicitSuperDeleter; - - public JavaPullUpHelper(PullUpData data) { - myProject = data.getProject(); - myMembersToMove = data.getMembersToMove(); - myMembersAfterMove = data.getMovedMembers(); - myTargetSuperClass = data.getTargetClass(); - mySourceClass = data.getSourceClass(); - myJavaDocPolicy = data.getDocCommentPolicy(); - myIsTargetInterface = myTargetSuperClass.isInterface(); - - myThisSuperAdjuster = new QualifiedThisSuperAdjuster(); - myExplicitSuperDeleter = new ExplicitSuperDeleter(); - } - - @Override - public void encodeContextInfo(MemberInfo info) { - ChangeContextUtil.encodeContextInfo(info.getMember(), true); - } - - @Override - public void move(MemberInfo info, PsiSubstitutor substitutor) { - if (info.getMember() instanceof PsiMethod) { - doMoveMethod(substitutor, info); - } else if (info.getMember() instanceof PsiField) { - doMoveField(substitutor, info); - } else if (info.getMember() instanceof PsiClass) { - doMoveClass(substitutor, info); - } - } - - @Override - public void postProcessMember(PsiMember member) { - member.accept(myExplicitSuperDeleter); - member.accept(myThisSuperAdjuster); - - ChangeContextUtil.decodeContextInfo(member, null, null); - - member.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - PsiExpression qualifierExpression = expression.getQualifierExpression(); - if (qualifierExpression != null) { - Boolean preserveQualifier = qualifierExpression.getCopyableUserData(PRESERVE_QUALIFIER); - if (preserveQualifier != null && !preserveQualifier) { - qualifierExpression.delete(); - return; - } - } - super.visitReferenceExpression(expression); - } - }); - - } - - @Override - public void setCorrectVisibility(MemberInfo info) { - PsiModifierListOwner modifierListOwner = info.getMember(); - if (myIsTargetInterface) { - PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PUBLIC, true); - } else if (modifierListOwner.hasModifierProperty(PsiModifier.PRIVATE)) { - if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, myTargetSuperClass, mySourceClass)) { - PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true); - } - if (modifierListOwner instanceof PsiClass) { - modifierListOwner.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitMethod(PsiMethod method) { - check(method); - } - - @Override - public void visitField(PsiField field) { - check(field); - } - - @Override - public void visitClass(PsiClass aClass) { - check(aClass); - super.visitClass(aClass); - } - - private void check(PsiMember member) { - if (member.hasModifierProperty(PsiModifier.PRIVATE)) { - if (willBeUsedInSubclass(member, myTargetSuperClass, mySourceClass)) { - PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true); - } - } - } - }); - } - } - } - - private void doMoveClass(PsiSubstitutor substitutor, MemberInfo info) { - PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - PsiClass aClass = (PsiClass) info.getMember(); - if (Boolean.FALSE.equals(info.getOverrides())) { - PsiReferenceList sourceReferenceList = info.getSourceReferenceList(); - LOG.assertTrue(sourceReferenceList != null); - PsiJavaCodeReferenceElement ref = mySourceClass.equals(sourceReferenceList.getParent()) ? RefactoringUtil - .removeFromReferenceList(sourceReferenceList, aClass) : RefactoringUtil.findReferenceToClass - (sourceReferenceList, aClass); - if (ref != null && !myTargetSuperClass.isInheritor(aClass, false)) { - RefactoringUtil.replaceMovedMemberTypeParameters(ref, PsiUtil.typeParametersIterable(mySourceClass), - substitutor, elementFactory); - PsiReferenceList referenceList = myIsTargetInterface ? myTargetSuperClass.getExtendsList() : - myTargetSuperClass.getImplementsList(); - assert referenceList != null; - referenceList.add(ref); - } - } else { - RefactoringUtil.replaceMovedMemberTypeParameters(aClass, PsiUtil.typeParametersIterable(mySourceClass), - substitutor, elementFactory); - fixReferencesToStatic(aClass); - PsiMember movedElement = (PsiMember) myTargetSuperClass.add(convertClassToLanguage(aClass, - myTargetSuperClass.getLanguage())); - myMembersAfterMove.add(movedElement); - aClass.delete(); - } - } - - private void doMoveField(PsiSubstitutor substitutor, MemberInfo info) { - PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - PsiField field = (PsiField) info.getMember(); - field.normalizeDeclaration(); - RefactoringUtil.replaceMovedMemberTypeParameters(field, PsiUtil.typeParametersIterable(mySourceClass), - substitutor, elementFactory); - fixReferencesToStatic(field); - if (myIsTargetInterface) { - PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true); - } - PsiMember movedElement = (PsiMember) myTargetSuperClass.add(convertFieldToLanguage(field, - myTargetSuperClass.getLanguage())); - myMembersAfterMove.add(movedElement); - field.delete(); - } - - private void doMoveMethod(PsiSubstitutor substitutor, MemberInfo info) { - PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - PsiMethod method = (PsiMethod) info.getMember(); - PsiMethod sibling = method; - PsiMethod anchor = null; - while (sibling != null) { - sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class); - if (sibling != null) { - anchor = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(method.getContainingClass(), - myTargetSuperClass, sibling.getSignature(PsiSubstitutor.EMPTY), false); - if (anchor != null) { - break; - } - } + private static final Logger LOG = Logger.getInstance(JavaPullUpHelper.class); + + private static final Key PRESERVE_QUALIFIER = Key.create("PRESERVE_QUALIFIER"); + + private final PsiClass mySourceClass; + private final PsiClass myTargetSuperClass; + private final boolean myIsTargetInterface; + private final DocCommentPolicy myJavaDocPolicy; + private Set myMembersAfterMove = null; + private final Set myMembersToMove; + private final Project myProject; + + private final QualifiedThisSuperAdjuster myThisSuperAdjuster; + private final ExplicitSuperDeleter myExplicitSuperDeleter; + + public JavaPullUpHelper(PullUpData data) { + myProject = data.getProject(); + myMembersToMove = data.getMembersToMove(); + myMembersAfterMove = data.getMovedMembers(); + myTargetSuperClass = data.getTargetClass(); + mySourceClass = data.getSourceClass(); + myJavaDocPolicy = data.getDocCommentPolicy(); + myIsTargetInterface = myTargetSuperClass.isInterface(); + + myThisSuperAdjuster = new QualifiedThisSuperAdjuster(); + myExplicitSuperDeleter = new ExplicitSuperDeleter(); } - PsiMethod methodCopy = (PsiMethod) method.copy(); - RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), - substitutor, elementFactory); - - Language language = myTargetSuperClass.getLanguage(); - PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false); - if (superClassMethod != null && superClassMethod.findDeepestSuperMethods().length == 0 || method - .findSuperMethods(myTargetSuperClass).length == 0) { - deleteOverrideAnnotationIfFound(methodCopy); + + @Override + public void encodeContextInfo(MemberInfo info) { + ChangeContextUtil.encodeContextInfo(info.getMember(), true); } - boolean isOriginalMethodAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT) || method - .hasModifierProperty(PsiModifier.DEFAULT); - if (myIsTargetInterface || info.isToAbstract()) { - ChangeContextUtil.clearContextInfo(method); - - if (!info.isToAbstract() && !method.hasModifierProperty(PsiModifier.ABSTRACT) && PsiUtil - .isLanguageLevel8OrHigher(myTargetSuperClass)) { - //pull as default - RefactoringUtil.makeMethodDefault(methodCopy); - isOriginalMethodAbstract = true; - } else { - RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy); - } - - myJavaDocPolicy.processCopiedJavaDoc(methodCopy.getDocComment(), method.getDocComment(), - isOriginalMethodAbstract); - - PsiMember movedElement; - if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - movedElement = (PsiMember) superClassMethod.replace(convertMethodToLanguage(methodCopy, language)); - } else { - movedElement = anchor != null ? (PsiMember) myTargetSuperClass.addBefore(methodCopy, - anchor) : (PsiMember) myTargetSuperClass.add(methodCopy); - } - JavaCodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject()).getCustomSettings(JavaCodeStyleSettings.class); - if (styleSettings.INSERT_OVERRIDE_ANNOTATION) { - if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myIsTargetInterface || PsiUtil - .isLanguageLevel6OrHigher(mySourceClass)) { - new AddAnnotationFix(Override.class.getName(), method).invoke(method.getProject(), null, - mySourceClass.getContainingFile()); - } - } - if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myIsTargetInterface) { - if (isOriginalMethodAbstract) { - for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) { - deleteOverrideAnnotationIfFound(oMethod); - } - } - deleteOverrideAnnotationIfFound(method); - } - myMembersAfterMove.add(movedElement); - if (isOriginalMethodAbstract) { - method.delete(); - } - } else { - if (isOriginalMethodAbstract) { - PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true); - } - RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass) - , substitutor, elementFactory); - fixReferencesToStatic(methodCopy); - - if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - superClassMethod.replace(convertMethodToLanguage(methodCopy, language)); - } else { - PsiMember movedElement = anchor != null ? (PsiMember) myTargetSuperClass.addBefore - (convertMethodToLanguage(methodCopy, language), anchor) : (PsiMember) myTargetSuperClass.add - (convertMethodToLanguage(methodCopy, language)); - myMembersAfterMove.add(movedElement); - } - method.delete(); + + @Override + @RequiredWriteAction + public void move(MemberInfo info, PsiSubstitutor substitutor) { + if (info.getMember() instanceof PsiMethod) { + doMoveMethod(substitutor, info); + } + else if (info.getMember() instanceof PsiField) { + doMoveField(substitutor, info); + } + else if (info.getMember() instanceof PsiClass) { + doMoveClass(substitutor, info); + } } - } - private static PsiMethod convertMethodToLanguage(PsiMethod method, Language language) { - if (method.getLanguage().equals(language)) { - return method; + @Override + public void postProcessMember(PsiMember member) { + member.accept(myExplicitSuperDeleter); + member.accept(myThisSuperAdjuster); + + ChangeContextUtil.decodeContextInfo(member, null, null); + + member.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + @RequiredWriteAction + public void visitReferenceExpression(PsiReferenceExpression expression) { + PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (qualifierExpression != null) { + Boolean preserveQualifier = qualifierExpression.getCopyableUserData(PRESERVE_QUALIFIER); + if (preserveQualifier != null && !preserveQualifier) { + qualifierExpression.delete(); + return; + } + } + super.visitReferenceExpression(expression); + } + }); + } - return JVMElementFactories.getFactory(language, method.getProject()).createMethodFromText(method.getText(), - null); - } - private static PsiField convertFieldToLanguage(PsiField field, Language language) { - if (field.getLanguage().equals(language)) { - return field; + @Override + @RequiredReadAction + public void setCorrectVisibility(MemberInfo info) { + PsiModifierListOwner modifierListOwner = info.getMember(); + if (myIsTargetInterface) { + PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PUBLIC, true); + } + else if (modifierListOwner.hasModifierProperty(PsiModifier.PRIVATE)) { + if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, myTargetSuperClass, mySourceClass)) { + PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true); + } + if (modifierListOwner instanceof PsiClass) { + modifierListOwner.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + @RequiredReadAction + public void visitMethod(@Nonnull PsiMethod method) { + check(method); + } + + @Override + @RequiredReadAction + public void visitField(@Nonnull PsiField field) { + check(field); + } + + @Override + @RequiredReadAction + public void visitClass(@Nonnull PsiClass aClass) { + check(aClass); + super.visitClass(aClass); + } + + @RequiredReadAction + private void check(PsiMember member) { + if (member.isPrivate() && willBeUsedInSubclass(member, myTargetSuperClass, mySourceClass)) { + PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true); + } + } + }); + } + } } - return JVMElementFactories.getFactory(language, field.getProject()).createField(field.getName(), - field.getType()); - } - - private static PsiClass convertClassToLanguage(PsiClass clazz, Language language) { - //if (clazz.getLanguage().equals(language)) { - // return clazz; - //} - //PsiClass newClass = JVMElementFactories.getFactory(language, clazz.getProject()).createClass(clazz.getName - // ()); - return clazz; - } - - private static void deleteOverrideAnnotationIfFound(PsiMethod oMethod) { - PsiAnnotation annotation = AnnotationUtil.findAnnotation(oMethod, Override.class.getName()); - if (annotation != null) { - annotation.delete(); + + @RequiredWriteAction + private void doMoveClass(PsiSubstitutor substitutor, MemberInfo info) { + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + PsiClass aClass = (PsiClass) info.getMember(); + if (Boolean.FALSE.equals(info.getOverrides())) { + PsiReferenceList sourceReferenceList = info.getSourceReferenceList(); + LOG.assertTrue(sourceReferenceList != null); + PsiJavaCodeReferenceElement ref = mySourceClass.equals(sourceReferenceList.getParent()) + ? RefactoringUtil.removeFromReferenceList(sourceReferenceList, aClass) + : RefactoringUtil.findReferenceToClass(sourceReferenceList, aClass); + if (ref != null && !myTargetSuperClass.isInheritor(aClass, false)) { + RefactoringUtil.replaceMovedMemberTypeParameters(ref, PsiUtil.typeParametersIterable(mySourceClass), + substitutor, elementFactory + ); + PsiReferenceList referenceList = myIsTargetInterface ? myTargetSuperClass.getExtendsList() : + myTargetSuperClass.getImplementsList(); + assert referenceList != null; + referenceList.add(ref); + } + } + else { + RefactoringUtil.replaceMovedMemberTypeParameters(aClass, PsiUtil.typeParametersIterable(mySourceClass), + substitutor, elementFactory + ); + fixReferencesToStatic(aClass); + PsiMember movedElement = (PsiMember) myTargetSuperClass.add(convertClassToLanguage( + aClass, + myTargetSuperClass.getLanguage() + )); + myMembersAfterMove.add(movedElement); + aClass.delete(); + } } - } - @Override - public void moveFieldInitializations(LinkedHashSet movedFields) { - PsiMethod[] constructors = myTargetSuperClass.getConstructors(); + @RequiredWriteAction + private void doMoveField(PsiSubstitutor substitutor, MemberInfo info) { + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + PsiField field = (PsiField) info.getMember(); + field.normalizeDeclaration(); + RefactoringUtil.replaceMovedMemberTypeParameters(field, PsiUtil.typeParametersIterable(mySourceClass), + substitutor, elementFactory + ); + fixReferencesToStatic(field); + if (myIsTargetInterface) { + PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true); + } + PsiMember movedElement = (PsiMember) myTargetSuperClass.add(convertFieldToLanguage( + field, + myTargetSuperClass.getLanguage() + )); + myMembersAfterMove.add(movedElement); + field.delete(); + } + + @RequiredWriteAction + private void doMoveMethod(PsiSubstitutor substitutor, MemberInfo info) { + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + PsiMethod method = (PsiMethod) info.getMember(); + PsiMethod sibling = method; + PsiMethod anchor = null; + while (sibling != null) { + sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class); + if (sibling != null) { + anchor = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived( + method.getContainingClass(), + myTargetSuperClass, + sibling.getSignature(PsiSubstitutor.EMPTY), + false + ); + if (anchor != null) { + break; + } + } + } + PsiMethod methodCopy = (PsiMethod) method.copy(); + RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), + substitutor, elementFactory + ); + + Language language = myTargetSuperClass.getLanguage(); + PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false); + if (superClassMethod != null && superClassMethod.findDeepestSuperMethods().length == 0 || method + .findSuperMethods(myTargetSuperClass).length == 0) { + deleteOverrideAnnotationIfFound(methodCopy); + } + boolean isOriginalMethodAbstract = method.isAbstract() + || method.hasModifierProperty(PsiModifier.DEFAULT); + if (myIsTargetInterface || info.isToAbstract()) { + ChangeContextUtil.clearContextInfo(method); + + if (!info.isToAbstract() && !method.isAbstract() && PsiUtil.isLanguageLevel8OrHigher(myTargetSuperClass)) { + //pull as default + RefactoringUtil.makeMethodDefault(methodCopy); + isOriginalMethodAbstract = true; + } + else { + RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy); + } - if (constructors.length == 0) { - constructors = new PsiMethod[]{null}; - } + myJavaDocPolicy.processCopiedJavaDoc(methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract); - HashMap> constructorsToSubConstructors = buildConstructorsToSubConstructorsMap - (constructors); - for (PsiMethod constructor : constructors) { - HashSet subConstructors = constructorsToSubConstructors.get(constructor); - tryToMoveInitializers(constructor, subConstructors, movedFields); + PsiMember movedElement; + if (superClassMethod != null && superClassMethod.isAbstract()) { + movedElement = (PsiMember) superClassMethod.replace(convertMethodToLanguage(methodCopy, language)); + } + else { + movedElement = anchor != null + ? (PsiMember) myTargetSuperClass.addBefore(methodCopy, anchor) + : (PsiMember) myTargetSuperClass.add(methodCopy); + } + JavaCodeStyleSettings styleSettings = + CodeStyleSettingsManager.getSettings(method.getProject()).getCustomSettings(JavaCodeStyleSettings.class); + if (styleSettings.INSERT_OVERRIDE_ANNOTATION) { + if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myIsTargetInterface + || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) { + new AddAnnotationFix(Override.class.getName(), method).invoke(method.getProject(), null, + mySourceClass.getContainingFile() + ); + } + } + if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myIsTargetInterface) { + if (isOriginalMethodAbstract) { + for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) { + deleteOverrideAnnotationIfFound(oMethod); + } + } + deleteOverrideAnnotationIfFound(method); + } + myMembersAfterMove.add(movedElement); + if (isOriginalMethodAbstract) { + method.delete(); + } + } + else { + if (isOriginalMethodAbstract) { + PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true); + } + RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass) + , substitutor, elementFactory); + fixReferencesToStatic(methodCopy); + + if (superClassMethod != null && superClassMethod.isAbstract()) { + superClassMethod.replace(convertMethodToLanguage(methodCopy, language)); + } + else { + PsiMember movedElement = anchor != null ? (PsiMember) myTargetSuperClass.addBefore + (convertMethodToLanguage(methodCopy, language), anchor) : (PsiMember) myTargetSuperClass.add + (convertMethodToLanguage(methodCopy, language)); + myMembersAfterMove.add(movedElement); + } + method.delete(); + } } - } - - @Override - public void updateUsage(PsiElement element) { - if (element instanceof PsiReferenceExpression) { - PsiExpression qualifierExpression = ((PsiReferenceExpression) element).getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression) qualifierExpression) - .resolve() == mySourceClass) { - ((PsiReferenceExpression) qualifierExpression).bindToElement(myTargetSuperClass); - } + + @RequiredReadAction + private static PsiMethod convertMethodToLanguage(PsiMethod method, Language language) { + if (method.getLanguage().equals(language)) { + return method; + } + return JVMElementFactories.getFactory(language, method.getProject()).createMethodFromText(method.getText(), null); } - } - - private static class Initializer { - public final PsiStatement initializer; - public final Set movedFieldsUsed; - public final Set usedParameters; - public final List statementsToRemove; - - private Initializer(PsiStatement initializer, - Set movedFieldsUsed, - Set usedParameters, - List statementsToRemove) { - this.initializer = initializer; - this.movedFieldsUsed = movedFieldsUsed; - this.statementsToRemove = statementsToRemove; - this.usedParameters = usedParameters; + + @RequiredReadAction + private static PsiField convertFieldToLanguage(PsiField field, Language language) { + if (field.getLanguage().equals(language)) { + return field; + } + return JVMElementFactories.getFactory(language, field.getProject()).createField(field.getName(), field.getType()); } - } - - private void tryToMoveInitializers(PsiMethod constructor, - HashSet subConstructors, - LinkedHashSet movedFields) throws IncorrectOperationException { - final LinkedHashMap fieldsToInitializers = new LinkedHashMap(); - boolean anyFound = false; - - for (PsiField field : movedFields) { - PsiStatement commonInitializer = null; - ArrayList fieldInitializersToRemove = new ArrayList(); - for (PsiMethod subConstructor : subConstructors) { - commonInitializer = hasCommonInitializer(commonInitializer, subConstructor, field, - fieldInitializersToRemove); - if (commonInitializer == null) { - break; - } - } - if (commonInitializer != null) { - ParametersAndMovedFieldsUsedCollector visitor = new ParametersAndMovedFieldsUsedCollector - (movedFields); - commonInitializer.accept(visitor); - fieldsToInitializers.put(field, new Initializer(commonInitializer, visitor.getUsedFields(), - visitor.getUsedParameters(), fieldInitializersToRemove)); - anyFound = true; - } + + private static PsiClass convertClassToLanguage(PsiClass clazz, Language language) { + //if (clazz.getLanguage().equals(language)) { + // return clazz; + //} + //PsiClass newClass = JVMElementFactories.getFactory(language, clazz.getProject()).createClass(clazz.getName()); + return clazz; } - if (!anyFound) { - return; + @RequiredWriteAction + private static void deleteOverrideAnnotationIfFound(PsiMethod oMethod) { + PsiAnnotation annotation = AnnotationUtil.findAnnotation(oMethod, Override.class.getName()); + if (annotation != null) { + annotation.delete(); + } } + @Override + @RequiredWriteAction + public void moveFieldInitializations(Set movedFields) { + PsiMethod[] constructors = myTargetSuperClass.getConstructors(); + + if (constructors.length == 0) { + constructors = new PsiMethod[]{null}; + } - { - final Set initializedFields = fieldsToInitializers.keySet(); - Set unmovable = RefactoringUtil.transitiveClosure(new RefactoringUtil.Graph() { - public Set getVertices() { - return initializedFields; - } - - public Set getTargets(PsiField source) { - return fieldsToInitializers.get(source).movedFieldsUsed; - } - }, new Condition() { - public boolean value(PsiField object) { - return !initializedFields.contains(object); - } - } - ); - - for (PsiField psiField : unmovable) { - fieldsToInitializers.remove(psiField); - } + Map> constructorsToSubConstructors = buildConstructorsToSubConstructorsMap(constructors); + for (PsiMethod constructor : constructors) { + Set subConstructors = constructorsToSubConstructors.get(constructor); + tryToMoveInitializers(constructor, subConstructors, movedFields); + } } - PsiElementFactory factory = JavaPsiFacade.getElementFactory(myProject); + @Override + @RequiredWriteAction + public void updateUsage(PsiElement element) { + if (element instanceof PsiReferenceExpression refExpr + && refExpr.getQualifierExpression() instanceof PsiReferenceExpression qRefExpr + && qRefExpr.resolve() == mySourceClass) { + qRefExpr.bindToElement(myTargetSuperClass); + } + } - if (constructor == null) { - constructor = (PsiMethod) myTargetSuperClass.add(factory.createConstructor()); - String visibilityModifier = VisibilityUtil.getVisibilityModifier(myTargetSuperClass.getModifierList - ()); - PsiUtil.setModifierProperty(constructor, visibilityModifier, true); + private static class Initializer { + public final PsiStatement initializer; + public final Set movedFieldsUsed; + public final Set usedParameters; + public final List statementsToRemove; + + private Initializer( + PsiStatement initializer, + Set movedFieldsUsed, + Set usedParameters, + List statementsToRemove + ) { + this.initializer = initializer; + this.movedFieldsUsed = movedFieldsUsed; + this.statementsToRemove = statementsToRemove; + this.usedParameters = usedParameters; + } } + @RequiredWriteAction + private void tryToMoveInitializers( + PsiMethod constructor, + Set subConstructors, + Set movedFields + ) throws IncorrectOperationException { + final Map fieldsToInitializers = new LinkedHashMap<>(); + boolean anyFound = false; + + for (PsiField field : movedFields) { + PsiStatement commonInitializer = null; + List fieldInitializersToRemove = new ArrayList<>(); + for (PsiMethod subConstructor : subConstructors) { + commonInitializer = hasCommonInitializer(commonInitializer, subConstructor, field, fieldInitializersToRemove); + if (commonInitializer == null) { + break; + } + } + if (commonInitializer != null) { + ParametersAndMovedFieldsUsedCollector visitor = new ParametersAndMovedFieldsUsedCollector(movedFields); + commonInitializer.accept(visitor); + fieldsToInitializers.put(field, new Initializer(commonInitializer, visitor.getUsedFields(), + visitor.getUsedParameters(), fieldInitializersToRemove + )); + anyFound = true; + } + } + + if (!anyFound) { + return; + } - ArrayList initializedFields = new ArrayList(fieldsToInitializers.keySet()); - Collections.sort(initializedFields, new Comparator() { - public int compare(PsiField field1, PsiField field2) { - Initializer i1 = fieldsToInitializers.get(field1); - Initializer i2 = fieldsToInitializers.get(field2); - if (i1.movedFieldsUsed.contains(field2)) { - return 1; + { + final Set initializedFields = fieldsToInitializers.keySet(); + Set unmovable = RefactoringUtil.transitiveClosure( + new RefactoringUtil.Graph<>() { + @Override + public Set getVertices() { + return initializedFields; + } + + @Override + public Set getTargets(PsiField source) { + return fieldsToInitializers.get(source).movedFieldsUsed; + } + }, + (Condition) object -> !initializedFields.contains(object) + ); + + for (PsiField psiField : unmovable) { + fieldsToInitializers.remove(psiField); + } } - if (i2.movedFieldsUsed.contains(field1)) { - return -1; + + PsiElementFactory factory = JavaPsiFacade.getElementFactory(myProject); + + if (constructor == null) { + constructor = (PsiMethod) myTargetSuperClass.add(factory.createConstructor()); + String visibilityModifier = VisibilityUtil.getVisibilityModifier(myTargetSuperClass.getModifierList + ()); + PsiUtil.setModifierProperty(constructor, visibilityModifier, true); } - return 0; - } - }); - for (PsiField initializedField : initializedFields) { - Initializer initializer = fieldsToInitializers.get(initializedField); - //correct constructor parameters and subConstructors super calls - PsiParameterList parameterList = constructor.getParameterList(); - for (PsiParameter parameter : initializer.usedParameters) { - parameterList.add(parameter); - } + List initializedFields = new ArrayList<>(fieldsToInitializers.keySet()); - for (PsiMethod subConstructor : subConstructors) { - modifySuperCall(subConstructor, initializer.usedParameters); - } + Collections.sort( + initializedFields, + (field1, field2) -> { + Initializer i1 = fieldsToInitializers.get(field1); + Initializer i2 = fieldsToInitializers.get(field2); + if (i1.movedFieldsUsed.contains(field2)) { + return 1; + } + if (i2.movedFieldsUsed.contains(field1)) { + return -1; + } + return 0; + } + ); - PsiStatement assignmentStatement = (PsiStatement) constructor.getBody().add(initializer.initializer); + for (PsiField initializedField : initializedFields) { + Initializer initializer = fieldsToInitializers.get(initializedField); - PsiManager manager = PsiManager.getInstance(myProject); - ChangeContextUtil.decodeContextInfo(assignmentStatement, myTargetSuperClass, - RefactoringChangeUtil.createThisExpression(manager, null)); - for (PsiElement psiElement : initializer.statementsToRemove) { - psiElement.delete(); - } - } - } - - private static void modifySuperCall(PsiMethod subConstructor, - Set parametersToPassToSuper) { - PsiCodeBlock body = subConstructor.getBody(); - if (body != null) { - PsiMethodCallExpression superCall = null; - PsiStatement[] statements = body.getStatements(); - if (statements.length > 0) { - if (statements[0] instanceof PsiExpressionStatement) { - PsiExpression expression = ((PsiExpressionStatement) statements[0]).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - PsiMethodCallExpression methodCall = (PsiMethodCallExpression) expression; - if ("super".equals(methodCall.getMethodExpression().getText())) { - superCall = methodCall; - } - } - } - } - - PsiElementFactory factory = JavaPsiFacade.getInstance(subConstructor.getProject()) - .getElementFactory(); - try { - if (superCall == null) { - PsiExpressionStatement statement = (PsiExpressionStatement) factory.createStatementFromText("super" + - "();", null); - statement = (PsiExpressionStatement) body.addAfter(statement, null); - superCall = (PsiMethodCallExpression) statement.getExpression(); - } - - PsiExpressionList argList = superCall.getArgumentList(); - for (PsiParameter parameter : parametersToPassToSuper) { - argList.add(factory.createExpressionFromText(parameter.getName(), null)); - } - } catch (IncorrectOperationException e) { - LOG.error(e); - } + //correct constructor parameters and subConstructors super calls + PsiParameterList parameterList = constructor.getParameterList(); + for (PsiParameter parameter : initializer.usedParameters) { + parameterList.add(parameter); + } + + for (PsiMethod subConstructor : subConstructors) { + modifySuperCall(subConstructor, initializer.usedParameters); + } + + PsiStatement assignmentStatement = (PsiStatement) constructor.getBody().add(initializer.initializer); + + PsiManager manager = PsiManager.getInstance(myProject); + ChangeContextUtil.decodeContextInfo( + assignmentStatement, + myTargetSuperClass, + RefactoringChangeUtil.createThisExpression(manager, null) + ); + for (PsiElement psiElement : initializer.statementsToRemove) { + psiElement.delete(); + } + } } - } - - @Nullable - private PsiStatement hasCommonInitializer(PsiStatement commonInitializer, - PsiMethod subConstructor, - PsiField field, - ArrayList statementsToRemove) { - PsiCodeBlock body = subConstructor.getBody(); - if (body == null) { - return null; + + @RequiredWriteAction + private static void modifySuperCall(PsiMethod subConstructor, Set parametersToPassToSuper) { + PsiCodeBlock body = subConstructor.getBody(); + if (body != null) { + PsiMethodCallExpression superCall = null; + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0 + && statements[0] instanceof PsiExpressionStatement fistStmt + && fistStmt.getExpression() instanceof PsiMethodCallExpression methodCall + && "super".equals(methodCall.getMethodExpression().getText())) { + superCall = methodCall; + } + + PsiElementFactory factory = JavaPsiFacade.getInstance(subConstructor.getProject()).getElementFactory(); + try { + if (superCall == null) { + PsiExpressionStatement statement = (PsiExpressionStatement) factory.createStatementFromText("super();", null); + statement = (PsiExpressionStatement) body.addAfter(statement, null); + superCall = (PsiMethodCallExpression) statement.getExpression(); + } + + PsiExpressionList argList = superCall.getArgumentList(); + for (PsiParameter parameter : parametersToPassToSuper) { + argList.add(factory.createExpressionFromText(parameter.getName(), null)); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } } - PsiStatement[] statements = body.getStatements(); - - // Algorithm: there should be only one write usage of field in a subConstructor, - // and in that usage field must be a target of top-level assignment, and RHS of assignment - // should be the same as commonInitializer if latter is non-null. - // - // There should be no usages before that initializer, and there should be - // no write usages afterwards. - PsiStatement commonInitializerCandidate = null; - for (PsiStatement statement : statements) { - HashSet collectedStatements = new HashSet(); - collectPsiStatements(statement, collectedStatements); - boolean doLookup = true; - for (PsiStatement collectedStatement : collectedStatements) { - if (collectedStatement instanceof PsiExpressionStatement) { - PsiExpression expression = ((PsiExpressionStatement) collectedStatement).getExpression(); - if (expression instanceof PsiAssignmentExpression) { - PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) expression; - PsiExpression lExpression = assignmentExpression.getLExpression(); - if (lExpression instanceof PsiReferenceExpression) { - PsiReferenceExpression lRef = (PsiReferenceExpression) lExpression; - if (lRef.getQualifierExpression() == null || lRef.getQualifierExpression() instanceof - PsiThisExpression) { - PsiElement resolved = lRef.resolve(); - if (resolved == field) { - doLookup = false; - if (commonInitializerCandidate == null) { - PsiExpression initializer = assignmentExpression.getRExpression(); - if (initializer == null) { - return null; + + @Nullable + @RequiredReadAction + private PsiStatement hasCommonInitializer( + PsiStatement commonInitializer, + PsiMethod subConstructor, + PsiField field, + List statementsToRemove + ) { + PsiCodeBlock body = subConstructor.getBody(); + if (body == null) { + return null; + } + PsiStatement[] statements = body.getStatements(); + + // Algorithm: there should be only one write usage of field in a subConstructor, + // and in that usage field must be a target of top-level assignment, and RHS of assignment + // should be the same as commonInitializer if latter is non-null. + // + // There should be no usages before that initializer, and there should be + // no write usages afterwards. + PsiStatement commonInitializerCandidate = null; + for (PsiStatement statement : statements) { + Set collectedStatements = new HashSet<>(); + collectPsiStatements(statement, collectedStatements); + boolean doLookup = true; + for (PsiStatement collectedStatement : collectedStatements) { + if (collectedStatement instanceof PsiExpressionStatement exprStmt + && exprStmt.getExpression() instanceof PsiAssignmentExpression assignment + && assignment.getLExpression() instanceof PsiReferenceExpression lRef) { + if (lRef.getQualifierExpression() == null || lRef.getQualifierExpression() instanceof PsiThisExpression) { + if (lRef.resolve() == field) { + doLookup = false; + if (commonInitializerCandidate == null) { + PsiExpression initializer = assignment.getRExpression(); + if (initializer == null) { + return null; + } + if (commonInitializer == null) { + IsMovableInitializerVisitor visitor = new IsMovableInitializerVisitor(); + statement.accept(visitor); + if (visitor.isMovable()) { + ChangeContextUtil.encodeContextInfo(statement, true); + PsiStatement statementCopy = (PsiStatement) statement.copy(); + ChangeContextUtil.clearContextInfo(statement); + statementsToRemove.add(statement); + commonInitializerCandidate = statementCopy; + } + else { + return null; + } + } + else if (PsiEquivalenceUtil.areElementsEquivalent(commonInitializer, statement)) { + statementsToRemove.add(statement); + commonInitializerCandidate = commonInitializer; + } + else { + return null; + } + } + else if (!PsiEquivalenceUtil.areElementsEquivalent(commonInitializerCandidate, statement)) { + return null; + } + } } - if (commonInitializer == null) { - IsMovableInitializerVisitor visitor = new - IsMovableInitializerVisitor(); - statement.accept(visitor); - if (visitor.isMovable()) { - ChangeContextUtil.encodeContextInfo(statement, true); - PsiStatement statementCopy = (PsiStatement) statement.copy(); - ChangeContextUtil.clearContextInfo(statement); - statementsToRemove.add(statement); - commonInitializerCandidate = statementCopy; - } else { - return null; - } - } else { - if (PsiEquivalenceUtil.areElementsEquivalent(commonInitializer, statement)) { - statementsToRemove.add(statement); - commonInitializerCandidate = commonInitializer; - } else { + } + } + if (doLookup) { + PsiReference[] references = + ReferencesSearch.search(field, new LocalSearchScope(statement), false).toArray(new PsiReference[0]); + if (commonInitializerCandidate == null && references.length > 0) { + return null; + } + + for (PsiReference reference : references) { + if (RefactoringUtil.isAssignmentLHS(reference.getElement())) { return null; - } } - } else if (!PsiEquivalenceUtil.areElementsEquivalent(commonInitializerCandidate, - statement)) { - return null; - } } - } } - } } - } - if (doLookup) { - PsiReference[] references = ReferencesSearch.search(field, new LocalSearchScope(statement), - false).toArray(new PsiReference[0]); - if (commonInitializerCandidate == null && references.length > 0) { - return null; + return commonInitializerCandidate; + } + + @RequiredReadAction + private static void collectPsiStatements(PsiElement root, Set collected) { + if (root instanceof PsiStatement statement) { + collected.add(statement); } - for (PsiReference reference : references) { - if (RefactoringUtil.isAssignmentLHS(reference.getElement())) { - return null; - } + for (PsiElement element : root.getChildren()) { + collectPsiStatements(element, collected); } - } } - return commonInitializerCandidate; - } - private static void collectPsiStatements(PsiElement root, Set collected) { - if (root instanceof PsiStatement) { - collected.add((PsiStatement) root); - } + private static class ParametersAndMovedFieldsUsedCollector extends JavaRecursiveElementWalkingVisitor { + private final Set myMovedFields; + private final Set myUsedFields; - for (PsiElement element : root.getChildren()) { - collectPsiStatements(element, collected); - } - } + private final Set myUsedParameters = new LinkedHashSet<>(); - private static class ParametersAndMovedFieldsUsedCollector extends JavaRecursiveElementWalkingVisitor { - private final Set myMovedFields; - private final Set myUsedFields; + private ParametersAndMovedFieldsUsedCollector(Set movedFields) { + myMovedFields = movedFields; + myUsedFields = new HashSet<>(); + } - private final Set myUsedParameters = new LinkedHashSet(); + public Set getUsedParameters() { + return myUsedParameters; + } - private ParametersAndMovedFieldsUsedCollector(HashSet movedFields) { - myMovedFields = movedFields; - myUsedFields = new HashSet(); - } + public Set getUsedFields() { + return myUsedFields; + } - public Set getUsedParameters() { - return myUsedParameters; + @Override + @RequiredReadAction + public void visitReferenceExpression(PsiReferenceExpression expression) { + PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (qualifierExpression != null && !(qualifierExpression instanceof PsiThisExpression)) { + return; + } + PsiElement resolved = expression.resolve(); + if (resolved instanceof PsiParameter parameter) { + myUsedParameters.add(parameter); + } + else if (myMovedFields.contains(resolved)) { + myUsedFields.add((PsiField) resolved); + } + } } - public Set getUsedFields() { - return myUsedFields; - } + private class IsMovableInitializerVisitor extends JavaRecursiveElementWalkingVisitor { + private boolean myIsMovable = true; - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - PsiExpression qualifierExpression = expression.getQualifierExpression(); - if (qualifierExpression != null && !(qualifierExpression instanceof PsiThisExpression)) { - return; - } - PsiElement resolved = expression.resolve(); - if (resolved instanceof PsiParameter) { - myUsedParameters.add((PsiParameter) resolved); - } else if (myMovedFields.contains(resolved)) { - myUsedFields.add((PsiField) resolved); - } - } - } + public boolean isMovable() { + return myIsMovable; + } - private class IsMovableInitializerVisitor extends JavaRecursiveElementWalkingVisitor { - private boolean myIsMovable = true; + @Override + @RequiredReadAction + public void visitReferenceExpression(PsiReferenceExpression expression) { + visitReferenceElement(expression); + } - public boolean isMovable() { - return myIsMovable; - } + @Override + @RequiredReadAction + public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement referenceElement) { + if (!myIsMovable) { + return; + } + PsiExpression qualifier; + if (referenceElement instanceof PsiReferenceExpression refExpr) { + qualifier = refExpr.getQualifierExpression(); + } + else { + qualifier = null; + } + if (qualifier == null || qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) { + PsiElement resolved = referenceElement.resolve(); + if (!(resolved instanceof PsiParameter)) { + if (resolved instanceof PsiClass psiClass && (psiClass.isStatic() || psiClass.getContainingClass() == null)) { + return; + } + PsiClass containingClass = null; + if (resolved instanceof PsiMember member && !member.isStatic()) { + containingClass = member.getContainingClass(); + } + myIsMovable = containingClass != null && InheritanceUtil.isInheritorOrSelf(myTargetSuperClass, containingClass, true); + } + } + else { + qualifier.accept(this); + } + } - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - visitReferenceElement(expression); + @Override + public void visitElement(PsiElement element) { + if (myIsMovable) { + super.visitElement(element); + } + } } - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement referenceElement) { - if (!myIsMovable) { - return; - } - PsiExpression qualifier; - if (referenceElement instanceof PsiReferenceExpression) { - qualifier = ((PsiReferenceExpression) referenceElement).getQualifierExpression(); - } else { - qualifier = null; - } - if (qualifier == null || qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) { - PsiElement resolved = referenceElement.resolve(); - if (!(resolved instanceof PsiParameter)) { - if (resolved instanceof PsiClass && (((PsiClass) resolved).hasModifierProperty(PsiModifier.STATIC) - || ((PsiClass) resolved).getContainingClass() == null)) { - return; - } - PsiClass containingClass = null; - if (resolved instanceof PsiMember && !((PsiMember) resolved).hasModifierProperty(PsiModifier - .STATIC)) { - containingClass = ((PsiMember) resolved).getContainingClass(); - } - myIsMovable = containingClass != null && InheritanceUtil.isInheritorOrSelf(myTargetSuperClass, - containingClass, true); - } - } else { - qualifier.accept(this); - } - } + @RequiredReadAction + private Map> buildConstructorsToSubConstructorsMap(PsiMethod[] constructors) { + Map> constructorsToSubConstructors = new HashMap<>(); + for (PsiMethod constructor : constructors) { + Set referencingSubConstructors = new HashSet<>(); + constructorsToSubConstructors.put(constructor, referencingSubConstructors); + if (constructor != null) { + // find references + for (PsiReference reference : ReferencesSearch.search(constructor, new LocalSearchScope(mySourceClass), false)) { + PsiElement element = reference.getElement(); + if (element != null && "super".equals(element.getText())) { + PsiMethod parentMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class); + if (parentMethod != null && parentMethod.isConstructor()) { + referencingSubConstructors.add(parentMethod); + } + } + } + } - @Override - public void visitElement(PsiElement element) { - if (myIsMovable) { - super.visitElement(element); - } - } - } - - private HashMap> buildConstructorsToSubConstructorsMap(PsiMethod[] - constructors) { - HashMap> constructorsToSubConstructors = new HashMap>(); - for (PsiMethod constructor : constructors) { - final HashSet referencingSubConstructors = new HashSet(); - constructorsToSubConstructors.put(constructor, referencingSubConstructors); - if (constructor != null) { - // find references - for (PsiReference reference : ReferencesSearch.search(constructor, new LocalSearchScope(mySourceClass), - false)) { - PsiElement element = reference.getElement(); - if (element != null && "super".equals(element.getText())) { - PsiMethod parentMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class); - if (parentMethod != null && parentMethod.isConstructor()) { - referencingSubConstructors.add(parentMethod); - } - } - } - } - - // check default constructor - if (constructor == null || constructor.getParameterList().getParametersCount() == 0) { - RefactoringUtil.visitImplicitSuperConstructorUsages(mySourceClass, - new RefactoringUtil.ImplicitConstructorUsageVisitor() { - public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) { - referencingSubConstructors.add(constructor); - } - - public void visitClassWithoutConstructors(PsiClass aClass) { - } - }, myTargetSuperClass); - - } - } - return constructorsToSubConstructors; - } - - private void fixReferencesToStatic(PsiElement classMember) throws IncorrectOperationException { - StaticReferencesCollector collector = new StaticReferencesCollector(); - classMember.accept(collector); - ArrayList refs = collector.getReferences(); - ArrayList members = collector.getReferees(); - ArrayList classes = collector.getRefereeClasses(); - PsiElementFactory factory = JavaPsiFacade.getInstance(classMember.getProject()).getElementFactory(); - - for (int i = 0; i < refs.size(); i++) { - PsiJavaCodeReferenceElement ref = refs.get(i); - PsiElement namedElement = members.get(i); - PsiClass aClass = classes.get(i); - - if (namedElement instanceof PsiNamedElement) { - PsiReferenceExpression newRef = (PsiReferenceExpression) factory.createExpressionFromText("a." + ( - (PsiNamedElement) namedElement).getName(), null); - PsiExpression qualifierExpression = newRef.getQualifierExpression(); - assert qualifierExpression != null; - qualifierExpression = (PsiExpression) qualifierExpression.replace(factory.createReferenceExpression - (aClass)); - qualifierExpression.putCopyableUserData(PRESERVE_QUALIFIER, ref.isQualified()); - ref.replace(newRef); - } - } - } - - private class StaticReferencesCollector extends ClassMemberReferencesVisitor { - private final ArrayList myReferences; - private final ArrayList myReferees; - private final ArrayList myRefereeClasses; - - private StaticReferencesCollector() { - super(mySourceClass); - myReferees = new ArrayList(); - myRefereeClasses = new ArrayList(); - myReferences = new ArrayList(); - } + // check default constructor + if (constructor == null || constructor.getParameterList().getParametersCount() == 0) { + RefactoringUtil.visitImplicitSuperConstructorUsages( + mySourceClass, + new RefactoringUtil.ImplicitConstructorUsageVisitor() { + @Override + public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) { + referencingSubConstructors.add(constructor); + } + + @Override + public void visitClassWithoutConstructors(PsiClass aClass) { + } + }, + myTargetSuperClass + ); - public ArrayList getReferees() { - return myReferees; + } + } + return constructorsToSubConstructors; + } + + @RequiredWriteAction + private void fixReferencesToStatic(PsiElement classMember) throws IncorrectOperationException { + StaticReferencesCollector collector = new StaticReferencesCollector(); + classMember.accept(collector); + List refs = collector.getReferences(); + List members = collector.getReferees(); + List classes = collector.getRefereeClasses(); + PsiElementFactory factory = JavaPsiFacade.getInstance(classMember.getProject()).getElementFactory(); + + for (int i = 0; i < refs.size(); i++) { + PsiJavaCodeReferenceElement ref = refs.get(i); + PsiClass aClass = classes.get(i); + + if (members.get(i) instanceof PsiNamedElement namedElement) { + PsiReferenceExpression newRef = + (PsiReferenceExpression) factory.createExpressionFromText("a." + namedElement.getName(), null); + PsiExpression qualifierExpression = newRef.getQualifierExpression(); + assert qualifierExpression != null; + qualifierExpression = (PsiExpression) qualifierExpression.replace(factory.createReferenceExpression(aClass)); + qualifierExpression.putCopyableUserData(PRESERVE_QUALIFIER, ref.isQualified()); + ref.replace(newRef); + } + } } - public ArrayList getRefereeClasses() { - return myRefereeClasses; - } + private class StaticReferencesCollector extends ClassMemberReferencesVisitor { + private final List myReferences; + private final List myReferees; + private final List myRefereeClasses; - public ArrayList getReferences() { - return myReferences; - } + private StaticReferencesCollector() { + super(mySourceClass); + myReferees = new ArrayList<>(); + myRefereeClasses = new ArrayList<>(); + myReferences = new ArrayList<>(); + } - protected void visitClassMemberReferenceElement(PsiMember classMember, - PsiJavaCodeReferenceElement classMemberReference) { - if (classMember.hasModifierProperty(PsiModifier.STATIC)) { - if (!myMembersToMove.contains(classMember) && RefactoringHierarchyUtil.isMemberBetween - (myTargetSuperClass, mySourceClass, classMember)) { - myReferences.add(classMemberReference); - myReferees.add(classMember); - myRefereeClasses.add(classMember.getContainingClass()); - } else if (myMembersToMove.contains(classMember) || myMembersAfterMove.contains(classMember)) { - myReferences.add(classMemberReference); - myReferees.add(classMember); - myRefereeClasses.add(myTargetSuperClass); - } - } - } - } + public List getReferees() { + return myReferees; + } - private class QualifiedThisSuperAdjuster extends JavaRecursiveElementVisitor { - @Override - public void visitThisExpression(PsiThisExpression expression) { - super.visitThisExpression(expression); - PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); - if (qualifier != null && qualifier.isReferenceTo(mySourceClass)) { - try { - qualifier.bindToElement(myTargetSuperClass); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } + public List getRefereeClasses() { + return myRefereeClasses; + } - @Override - public void visitSuperExpression(PsiSuperExpression expression) { - super.visitSuperExpression(expression); - PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); - if (qualifier != null && qualifier.isReferenceTo(mySourceClass)) { - try { - expression.replace(JavaPsiFacade.getElementFactory(myProject).createExpressionFromText - (myTargetSuperClass.getName() + ".this", null)); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } + public List getReferences() { + return myReferences; + } + + @Override + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if (classMember.isStatic()) { + if (!myMembersToMove.contains(classMember) && RefactoringHierarchyUtil.isMemberBetween + (myTargetSuperClass, mySourceClass, classMember)) { + myReferences.add(classMemberReference); + myReferees.add(classMember); + myRefereeClasses.add(classMember.getContainingClass()); + } + else if (myMembersToMove.contains(classMember) || myMembersAfterMove.contains(classMember)) { + myReferences.add(classMemberReference); + myReferees.add(classMember); + myRefereeClasses.add(myTargetSuperClass); + } + } + } } - } - private class ExplicitSuperDeleter extends JavaRecursiveElementWalkingVisitor { - private final PsiExpression myThisExpression = JavaPsiFacade.getElementFactory(myProject) - .createExpressionFromText("this", null); + private class QualifiedThisSuperAdjuster extends JavaRecursiveElementVisitor { + @Override + @RequiredWriteAction + public void visitThisExpression(@Nonnull PsiThisExpression expression) { + super.visitThisExpression(expression); + PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); + if (qualifier != null && qualifier.isReferenceTo(mySourceClass)) { + try { + qualifier.bindToElement(myTargetSuperClass); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - if (expression.getQualifierExpression() instanceof PsiSuperExpression) { - PsiElement resolved = expression.resolve(); - if (resolved == null || resolved instanceof PsiMethod && shouldFixSuper((PsiMethod) resolved)) { - expression.getQualifierExpression().delete(); + @Override + @RequiredWriteAction + public void visitSuperExpression(@Nonnull PsiSuperExpression expression) { + super.visitSuperExpression(expression); + PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); + if (qualifier != null && qualifier.isReferenceTo(mySourceClass)) { + try { + expression.replace( + JavaPsiFacade.getElementFactory(myProject).createExpressionFromText(myTargetSuperClass.getName() + ".this", null) + ); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } } - } } - @Override - public void visitSuperExpression(PsiSuperExpression expression) { - expression.replace(myThisExpression); - } + private class ExplicitSuperDeleter extends JavaRecursiveElementWalkingVisitor { + private final PsiExpression myThisExpression = JavaPsiFacade.getElementFactory(myProject) + .createExpressionFromText("this", null); - @Override - public void visitClass(PsiClass aClass) { - // do nothing - } + @Override + @RequiredWriteAction + public void visitReferenceExpression(@Nonnull PsiReferenceExpression expression) { + if (expression.getQualifierExpression() instanceof PsiSuperExpression superExpr) { + PsiElement resolved = expression.resolve(); + if (resolved == null || resolved instanceof PsiMethod method && shouldFixSuper(method)) { + superExpr.delete(); + } + } + } + + @Override + @RequiredWriteAction + public void visitSuperExpression(PsiSuperExpression expression) { + expression.replace(myThisExpression); + } - private boolean shouldFixSuper(PsiMethod method) { - for (PsiMember element : myMembersAfterMove) { - if (element instanceof PsiMethod) { - PsiMethod member = (PsiMethod) element; - // if there is such member among moved members, super qualifier - // should not be removed - PsiManager manager = method.getManager(); - if (manager.areElementsEquivalent(member.getContainingClass(), method.getContainingClass()) && - MethodSignatureUtil.areSignaturesEqual(member, method)) { - return false; - } - } - } - - PsiMethod methodFromSuper = myTargetSuperClass.findMethodBySignature(method, false); - return methodFromSuper == null; + @Override + public void visitClass(@Nonnull PsiClass aClass) { + // do nothing + } + + private boolean shouldFixSuper(PsiMethod method) { + for (PsiMember element : myMembersAfterMove) { + if (element instanceof PsiMethod member) { + // if there is such member among moved members, super qualifier + // should not be removed + PsiManager manager = method.getManager(); + if (manager.areElementsEquivalent(member.getContainingClass(), method.getContainingClass()) + && MethodSignatureUtil.areSignaturesEqual(member, method)) { + return false; + } + } + } + + PsiMethod methodFromSuper = myTargetSuperClass.findMethodBySignature(method, false); + return methodFromSuper == null; + } } - } - - private boolean willBeUsedInSubclass(PsiElement member, PsiClass superclass, PsiClass subclass) { - for (PsiReference ref : ReferencesSearch.search(member, new LocalSearchScope(subclass), false)) { - PsiElement element = ref.getElement(); - if (!RefactoringHierarchyUtil.willBeInTargetClass(element, myMembersToMove, superclass, false)) { - return true; - } + + @RequiredReadAction + private boolean willBeUsedInSubclass(PsiElement member, PsiClass superclass, PsiClass subclass) { + for (PsiReference ref : ReferencesSearch.search(member, new LocalSearchScope(subclass), false)) { + PsiElement element = ref.getElement(); + if (!RefactoringHierarchyUtil.willBeInTargetClass(element, myMembersToMove, superclass, false)) { + return true; + } + } + return false; } - return false; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpHelper.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpHelper.java index b2ad52f44..2617a8197 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpHelper.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpHelper.java @@ -18,24 +18,27 @@ import com.intellij.java.language.psi.PsiField; import com.intellij.java.language.psi.PsiMember; import com.intellij.java.language.psi.PsiSubstitutor; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.editor.refactoring.classMember.MemberInfoBase; import consulo.language.psi.PsiElement; -import java.util.LinkedHashSet; +import java.util.Set; /** - * Created by Max Medvedev on 10/4/13 + * @author Max Medvedev + * @since 2013-10-04 */ public interface PullUpHelper> { - void encodeContextInfo(T info); + void encodeContextInfo(T info); - void move(T info, PsiSubstitutor substitutor); + @RequiredWriteAction + void move(T info, PsiSubstitutor substitutor); - void postProcessMember(PsiMember member); + void postProcessMember(PsiMember member); - void setCorrectVisibility(T info); + void setCorrectVisibility(T info); - void moveFieldInitializations(LinkedHashSet movedFields); + void moveFieldInitializations(Set movedFields); - void updateUsage(PsiElement element); + void updateUsage(PsiElement element); } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpProcessor.java index 50c4c8545..cc1e8cc4b 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPullUp/PullUpProcessor.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: 14.06.2002 - * Time: 22:35:19 - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.java.impl.refactoring.memberPullUp; import com.intellij.java.impl.refactoring.listeners.JavaRefactoringListenerManager; @@ -32,8 +23,9 @@ import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.psi.util.TypeConversionUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.application.Application; -import consulo.application.ApplicationManager; import consulo.application.progress.ProgressManager; import consulo.application.util.query.Query; import consulo.language.Language; @@ -49,6 +41,7 @@ import consulo.language.psi.PsiReference; import consulo.language.psi.search.ReferencesSearch; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; import consulo.usage.UsageInfo; @@ -58,298 +51,305 @@ import java.util.*; +/** + * @author dsl + * @since 2002-06-14 + */ public class PullUpProcessor extends BaseRefactoringProcessor implements PullUpData { - private static final Logger LOG = Logger.getInstance(PullUpProcessor.class); - - private final PsiClass mySourceClass; - private final PsiClass myTargetSuperClass; - private final MemberInfo[] myMembersToMove; - private final DocCommentPolicy myJavaDocPolicy; - private Set myMembersAfterMove = null; - private Set myMovedMembers = null; - private final Map> myProcessors = new HashMap<>(); - - public PullUpProcessor(PsiClass sourceClass, - PsiClass targetSuperClass, - MemberInfo[] membersToMove, - DocCommentPolicy javaDocPolicy) { - super(sourceClass.getProject()); - mySourceClass = sourceClass; - myTargetSuperClass = targetSuperClass; - myMembersToMove = membersToMove; - myJavaDocPolicy = javaDocPolicy; - } + private static final Logger LOG = Logger.getInstance(PullUpProcessor.class); + + private final PsiClass mySourceClass; + private final PsiClass myTargetSuperClass; + private final MemberInfo[] myMembersToMove; + private final DocCommentPolicy myJavaDocPolicy; + private Set myMembersAfterMove = null; + private Set myMovedMembers = null; + private final Map> myProcessors = new HashMap<>(); + + public PullUpProcessor( + PsiClass sourceClass, + PsiClass targetSuperClass, + MemberInfo[] membersToMove, + DocCommentPolicy javaDocPolicy + ) { + super(sourceClass.getProject()); + mySourceClass = sourceClass; + myTargetSuperClass = targetSuperClass; + myMembersToMove = membersToMove; + myJavaDocPolicy = javaDocPolicy; + } - @Override - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { - return new PullUpUsageViewDescriptor(); - } + @Override + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new PullUpUsageViewDescriptor(); + } - @Override - @Nonnull - protected UsageInfo[] findUsages() { - List result = new ArrayList(); - for (MemberInfo memberInfo : myMembersToMove) { - PsiMember member = memberInfo.getMember(); - if (member.hasModifierProperty(PsiModifier.STATIC)) { - for (PsiReference reference : ReferencesSearch.search(member)) { - result.add(new UsageInfo(reference)); + @Nonnull + @Override + @RequiredReadAction + protected UsageInfo[] findUsages() { + List result = new ArrayList<>(); + for (MemberInfo memberInfo : myMembersToMove) { + PsiMember member = memberInfo.getMember(); + if (member.isStatic()) { + for (PsiReference reference : ReferencesSearch.search(member)) { + result.add(new UsageInfo(reference)); + } + } } - } + return result.isEmpty() ? UsageInfo.EMPTY_ARRAY : result.toArray(new UsageInfo[result.size()]); } - return result.isEmpty() ? UsageInfo.EMPTY_ARRAY : result.toArray(new UsageInfo[result.size()]); - } - - /*@Nullable - @Override - protected String getRefactoringId() - { - return "refactoring.pull.up"; - } - - @Nullable - @Override - protected RefactoringEventData getBeforeData() - { - RefactoringEventData data = new RefactoringEventData(); - data.addElement(mySourceClass); - data.addMembers(myMembersToMove, new Function() - { - @Override - public PsiElement fun(MemberInfo info) - { - return info.getMember(); - } - }); - return data; - } - - @Nullable - @Override - protected RefactoringEventData getAfterData(@NotNull UsageInfo[] usages) - { - final RefactoringEventData data = new RefactoringEventData(); - data.addElement(myTargetSuperClass); - return data; - } */ + /*@Nullable @Override - protected void performRefactoring(@Nonnull UsageInfo[] usages) { - moveMembersToBase(); - moveFieldInitializations(); - for (UsageInfo usage : usages) { - PsiElement element = usage.getElement(); - if (element == null) { - continue; - } - - PullUpHelper processor = getProcessor(element); - processor.updateUsage(element); + protected String getRefactoringId() + { + return "refactoring.pull.up"; } - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - processMethodsDuplicates(); - } - }, Application.get().getNoneModalityState(), myProject.getDisposed()); - } - - private void processMethodsDuplicates() { - ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - if (!myTargetSuperClass.isValid()) { - return; - } - Query search = ClassInheritorsSearch.search(myTargetSuperClass); - Set hierarchyFiles = new HashSet(); - for (PsiClass aClass : search) { - PsiFile containingFile = aClass.getContainingFile(); - if (containingFile != null) { - VirtualFile virtualFile = containingFile.getVirtualFile(); - if (virtualFile != null) { - hierarchyFiles.add(virtualFile); - } - } + + @Nullable + @Override + protected RefactoringEventData getBeforeData() + { + RefactoringEventData data = new RefactoringEventData(); + data.addElement(mySourceClass); + data.addMembers(myMembersToMove, new Function() + { + @Override + public PsiElement fun(MemberInfo info) + { + return info.getMember(); } - Set methodsToSearchDuplicates = new HashSet(); - for (PsiMember psiMember : myMembersAfterMove) { - if (psiMember instanceof PsiMethod && psiMember.isValid() && ((PsiMethod) psiMember) - .getBody() != null) { - methodsToSearchDuplicates.add(psiMember); - } + }); + return data; + } + + @Nullable + @Override + protected RefactoringEventData getAfterData(@NotNull UsageInfo[] usages) + { + final RefactoringEventData data = new RefactoringEventData(); + data.addElement(myTargetSuperClass); + return data; + }*/ + + @Override + @RequiredWriteAction + protected void performRefactoring(@Nonnull UsageInfo[] usages) { + moveMembersToBase(); + moveFieldInitializations(); + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element == null) { + continue; } - MethodDuplicatesHandler.invokeOnScope(myProject, methodsToSearchDuplicates, - new AnalysisScope(myProject, hierarchyFiles), true); - } - }); - } - }, MethodDuplicatesHandler.REFACTORING_NAME, true, myProject); - } + PullUpHelper processor = getProcessor(element); + processor.updateUsage(element); + } + Application application = myProject.getApplication(); + application.invokeLater(this::processMethodsDuplicates, application.getNoneModalityState(), myProject.getDisposed()); + } - @Override - protected String getCommandName() { - return RefactoringLocalize.pullupCommand(DescriptiveNameUtil.getDescriptiveName(mySourceClass)).get(); - } + private void processMethodsDuplicates() { + ProgressManager.getInstance().runProcessWithProgressSynchronously( + () -> myProject.getApplication().runReadAction(() -> { + if (!myTargetSuperClass.isValid()) { + return; + } + Query search = ClassInheritorsSearch.search(myTargetSuperClass); + Set hierarchyFiles = new HashSet<>(); + for (PsiClass aClass : search) { + PsiFile containingFile = aClass.getContainingFile(); + if (containingFile != null) { + VirtualFile virtualFile = containingFile.getVirtualFile(); + if (virtualFile != null) { + hierarchyFiles.add(virtualFile); + } + } + } + Set methodsToSearchDuplicates = new HashSet<>(); + for (PsiMember psiMember : myMembersAfterMove) { + if (psiMember instanceof PsiMethod method && method.isValid() && method.getBody() != null) { + methodsToSearchDuplicates.add(psiMember); + } + } - public void moveMembersToBase() throws IncorrectOperationException { - myMovedMembers = new HashSet<>(); - myMembersAfterMove = new HashSet<>(); + MethodDuplicatesHandler.invokeOnScope( + myProject, + methodsToSearchDuplicates, + new AnalysisScope(myProject, hierarchyFiles), + true + ); + }), + MethodDuplicatesHandler.REFACTORING_NAME, + true, + myProject + ); + } - // build aux sets - for (MemberInfo info : myMembersToMove) { - myMovedMembers.add(info.getMember()); + @Nonnull + @Override + protected LocalizeValue getCommandName() { + return RefactoringLocalize.pullupCommand(DescriptiveNameUtil.getDescriptiveName(mySourceClass)); } - PsiSubstitutor substitutor = upDownSuperClassSubstitutor(); + @RequiredWriteAction + public void moveMembersToBase() throws IncorrectOperationException { + myMovedMembers = new HashSet<>(); + myMembersAfterMove = new HashSet<>(); + + // build aux sets + for (MemberInfo info : myMembersToMove) { + myMovedMembers.add(info.getMember()); + } - for (MemberInfo info : myMembersToMove) { - PullUpHelper processor = getProcessor(info); + PsiSubstitutor substitutor = upDownSuperClassSubstitutor(); - if (!(info.getMember() instanceof PsiClass) || info.getOverrides() == null) { - processor.setCorrectVisibility(info); - processor.encodeContextInfo(info); - } + for (MemberInfo info : myMembersToMove) { + PullUpHelper processor = getProcessor(info); - processor.move(info, substitutor); - } + if (!(info.getMember() instanceof PsiClass) || info.getOverrides() == null) { + processor.setCorrectVisibility(info); + processor.encodeContextInfo(info); + } - for (PsiMember member : myMembersAfterMove) { - getProcessor(member).postProcessMember(member); + processor.move(info, substitutor); + } - JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance - (myProject); - ((JavaRefactoringListenerManagerImpl) listenerManager).fireMemberMoved(mySourceClass, member); - } - } - - private PullUpHelper getProcessor(@Nonnull PsiElement element) { - Language language = element.getLanguage(); - return getProcessor(language); - } - - private PullUpHelper getProcessor(Language language) { - PullUpHelper helper = myProcessors.get(language); - if (helper == null) { - helper = PullUpHelperFactory.forLanguage(language).createPullUpHelper(this); - myProcessors.put(language, helper); - } - return helper; - } + for (PsiMember member : myMembersAfterMove) { + getProcessor(member).postProcessMember(member); - private PullUpHelper getProcessor(@Nonnull MemberInfo info) { - PsiReferenceList refList = info.getSourceReferenceList(); - if (refList != null) { - return getProcessor(refList.getLanguage()); + JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance(myProject); + ((JavaRefactoringListenerManagerImpl) listenerManager).fireMemberMoved(mySourceClass, member); + } } - return getProcessor(info.getMember()); - } - private PsiSubstitutor upDownSuperClassSubstitutor() { - PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; - for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(mySourceClass)) { - substitutor = substitutor.put(parameter, null); + @RequiredReadAction + private PullUpHelper getProcessor(@Nonnull PsiElement element) { + Language language = element.getLanguage(); + return getProcessor(language); } - Map substitutionMap = TypeConversionUtil.getSuperClassSubstitutor - (myTargetSuperClass, mySourceClass, PsiSubstitutor.EMPTY).getSubstitutionMap(); - for (PsiTypeParameter parameter : substitutionMap.keySet()) { - PsiType type = substitutionMap.get(parameter); - PsiClass resolvedClass = PsiUtil.resolveClassInType(type); - if (resolvedClass instanceof PsiTypeParameter) { - substitutor = substitutor.put((PsiTypeParameter) resolvedClass, JavaPsiFacade.getElementFactory - (myProject).createType(parameter)); - } - } - return substitutor; - } - - public void moveFieldInitializations() throws IncorrectOperationException { - LOG.assertTrue(myMembersAfterMove != null); - LinkedHashSet movedFields = new LinkedHashSet(); - for (PsiMember member : myMembersAfterMove) { - if (member instanceof PsiField) { - movedFields.add((PsiField) member); - } + private PullUpHelper getProcessor(Language language) { + PullUpHelper helper = myProcessors.get(language); + if (helper == null) { + helper = PullUpHelperFactory.forLanguage(language).createPullUpHelper(this); + myProcessors.put(language, helper); + } + return helper; } - if (movedFields.isEmpty()) { - return; + @RequiredReadAction + private PullUpHelper getProcessor(@Nonnull MemberInfo info) { + PsiReferenceList refList = info.getSourceReferenceList(); + if (refList != null) { + return getProcessor(refList.getLanguage()); + } + return getProcessor(info.getMember()); } - getProcessor(myTargetSuperClass).moveFieldInitializations(movedFields); - } - - public static boolean checkedInterfacesContain(Collection> - memberInfos, - PsiMethod psiMethod) { - for (MemberInfoBase memberInfo : memberInfos) { - if (memberInfo.isChecked() && - memberInfo.getMember() instanceof PsiClass && - Boolean.FALSE.equals(memberInfo.getOverrides())) { - if (((PsiClass) memberInfo.getMember()).findMethodBySignature(psiMethod, true) != null) { - return true; + private PsiSubstitutor upDownSuperClassSubstitutor() { + PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; + for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(mySourceClass)) { + substitutor = substitutor.put(parameter, null); + } + Map substitutionMap = TypeConversionUtil.getSuperClassSubstitutor + (myTargetSuperClass, mySourceClass, PsiSubstitutor.EMPTY).getSubstitutionMap(); + for (PsiTypeParameter parameter : substitutionMap.keySet()) { + PsiType type = substitutionMap.get(parameter); + if (PsiUtil.resolveClassInType(type) instanceof PsiTypeParameter typeParam) { + substitutor = substitutor.put(typeParam, JavaPsiFacade.getElementFactory(myProject).createType(parameter)); + } } - } + return substitutor; } - return false; - } - @Override - public PsiClass getSourceClass() { - return mySourceClass; - } + @RequiredReadAction + public void moveFieldInitializations() throws IncorrectOperationException { + LOG.assertTrue(myMembersAfterMove != null); - @Override - public PsiClass getTargetClass() { - return myTargetSuperClass; - } + Set movedFields = new LinkedHashSet<>(); + for (PsiMember member : myMembersAfterMove) { + if (member instanceof PsiField field) { + movedFields.add(field); + } + } - @Override - public DocCommentPolicy getDocCommentPolicy() { - return myJavaDocPolicy; - } + if (movedFields.isEmpty()) { + return; + } - @Override - public Set getMembersToMove() { - return myMovedMembers; - } + getProcessor(myTargetSuperClass).moveFieldInitializations(movedFields); + } - @Override - public Set getMovedMembers() { - return myMembersAfterMove; - } + public static boolean checkedInterfacesContain( + Collection> + memberInfos, + PsiMethod psiMethod + ) { + for (MemberInfoBase memberInfo : memberInfos) { + if (memberInfo.isChecked() + && memberInfo.getMember() instanceof PsiClass psiClass + && Boolean.FALSE.equals(memberInfo.getOverrides()) + && psiClass.findMethodBySignature(psiMethod, true) != null) { + return true; + } + } + return false; + } - @Override - public Project getProject() { - return myProject; - } + @Override + public PsiClass getSourceClass() { + return mySourceClass; + } - private class PullUpUsageViewDescriptor implements UsageViewDescriptor { @Override - public String getProcessedElementsHeader() { - return "Pull up members from"; + public PsiClass getTargetClass() { + return myTargetSuperClass; } @Override - @Nonnull - public PsiElement[] getElements() { - return new PsiElement[]{mySourceClass}; + public DocCommentPolicy getDocCommentPolicy() { + return myJavaDocPolicy; + } + + @Override + public Set getMembersToMove() { + return myMovedMembers; } @Override - public String getCodeReferencesText(int usagesCount, int filesCount) { - return "Class to pull up members to \"" + RefactoringUIUtil.getDescription(myTargetSuperClass, true) + "\""; + public Set getMovedMembers() { + return myMembersAfterMove; } @Override - public String getCommentReferencesText(int usagesCount, int filesCount) { - return null; + public Project getProject() { + return myProject; + } + + private class PullUpUsageViewDescriptor implements UsageViewDescriptor { + @Override + public String getProcessedElementsHeader() { + return "Pull up members from"; + } + + @Override + @Nonnull + public PsiElement[] getElements() { + return new PsiElement[]{mySourceClass}; + } + + @Override + public String getCodeReferencesText(int usagesCount, int filesCount) { + return "Class to pull up members to \"" + RefactoringUIUtil.getDescription(myTargetSuperClass, true) + "\""; + } + + @Override + public String getCommentReferencesText(int usagesCount, int filesCount) { + return null; + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/JavaPushDownHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/JavaPushDownHandler.java index be122dca6..831882de8 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/JavaPushDownHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/JavaPushDownHandler.java @@ -15,22 +15,24 @@ */ package com.intellij.java.impl.refactoring.memberPushDown; +import com.intellij.java.impl.refactoring.HelpID; +import com.intellij.java.impl.refactoring.util.classMembers.MemberInfo; +import com.intellij.java.impl.refactoring.util.classMembers.MemberInfoStorage; import com.intellij.java.language.psi.*; -import consulo.dataContext.DataContext; import consulo.codeEditor.Editor; import consulo.codeEditor.ScrollType; -import consulo.language.editor.refactoring.localize.RefactoringLocalize; -import consulo.localize.LocalizeValue; -import consulo.project.Project; -import consulo.language.psi.*; -import com.intellij.java.impl.refactoring.HelpID; +import consulo.dataContext.DataContext; +import consulo.language.editor.refactoring.ElementsHandler; import consulo.language.editor.refactoring.action.RefactoringActionHandler; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.classMember.MemberInfoBase; -import consulo.language.editor.refactoring.ElementsHandler; +import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.util.CommonRefactoringUtil; -import com.intellij.java.impl.refactoring.util.classMembers.MemberInfo; -import com.intellij.java.impl.refactoring.util.classMembers.MemberInfoStorage; +import consulo.language.psi.PsiElement; +import consulo.language.psi.PsiFile; +import consulo.language.psi.PsiManager; +import consulo.localize.LocalizeValue; +import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import jakarta.annotation.Nonnull; import java.util.List; @@ -39,89 +41,99 @@ * @author dsl */ public class JavaPushDownHandler implements RefactoringActionHandler, ElementsHandler { - public static final String REFACTORING_NAME = RefactoringBundle.message("push.members.down.title"); + public static final LocalizeValue REFACTORING_NAME = RefactoringLocalize.pushMembersDownTitle(); - public void invoke(@Nonnull Project project, Editor editor, PsiFile file, DataContext dataContext) { - int offset = editor.getCaretModel().getOffset(); - editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - PsiElement element = file.findElementAt(offset); + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, Editor editor, PsiFile file, DataContext dataContext) { + int offset = editor.getCaretModel().getOffset(); + editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + PsiElement element = file.findElementAt(offset); - while (true) { - if (element == null || element instanceof PsiFile) { - LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( - RefactoringLocalize.theCaretShouldBePositionedInsideAClassToPushMembersFrom() - ); - CommonRefactoringUtil.showErrorHint(project, editor, message.get(), REFACTORING_NAME, HelpID.MEMBERS_PUSH_DOWN); - return; - } + while (true) { + if (element == null || element instanceof PsiFile) { + LocalizeValue message = RefactoringLocalize.cannotPerformRefactoringWithReason( + RefactoringLocalize.theCaretShouldBePositionedInsideAClassToPushMembersFrom() + ); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.MEMBERS_PUSH_DOWN); + return; + } - if (element instanceof PsiClass || element instanceof PsiField || element instanceof PsiMethod) { - /*if (element instanceof JspClass) { - RefactoringMessageUtil.showNotSupportedForJspClassesError(project, editor, REFACTORING_NAME, HelpID.MEMBERS_PUSH_DOWN); - return; - } */ - invoke(project, new PsiElement[]{element}, dataContext); - return; - } - element = element.getParent(); + if (element instanceof PsiClass || element instanceof PsiField || element instanceof PsiMethod) { + /*if (element instanceof JspClass) { + RefactoringMessageUtil.showNotSupportedForJspClassesError(project, editor, REFACTORING_NAME, HelpID.MEMBERS_PUSH_DOWN); + return; + }*/ + invoke(project, new PsiElement[]{element}, dataContext); + return; + } + element = element.getParent(); + } } - } - public void invoke(@Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { - if (elements.length != 1) return; + @Override + @RequiredUIAccess + public void invoke(@Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { + if (elements.length != 1) { + return; + } - PsiElement element = elements[0]; - PsiClass aClass; - PsiElement aMember = null; + PsiElement element = elements[0]; + PsiClass aClass; + PsiElement aMember = null; - if (element instanceof PsiClass) { - aClass = (PsiClass) element; - } else if (element instanceof PsiMethod) { - aClass = ((PsiMethod) element).getContainingClass(); - aMember = element; - } else if (element instanceof PsiField) { - aClass = ((PsiField) element).getContainingClass(); - aMember = element; - } else - return; + if (element instanceof PsiClass psiClass) { + aClass = psiClass; + } + else if (element instanceof PsiMethod method) { + aClass = method.getContainingClass(); + aMember = method; + } + else if (element instanceof PsiField field) { + aClass = field.getContainingClass(); + aMember = field; + } + else { + return; + } - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, aClass)) return; - MemberInfoStorage memberInfoStorage = new MemberInfoStorage(aClass, new MemberInfo.Filter() { - public boolean includeMember(PsiMember element) { - return !(element instanceof PsiEnumConstant); - } - }); - List members = memberInfoStorage.getClassMemberInfos(aClass); - PsiManager manager = aClass.getManager(); + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, aClass)) { + return; + } + MemberInfoStorage memberInfoStorage = new MemberInfoStorage(aClass, element1 -> !(element1 instanceof PsiEnumConstant)); + List members = memberInfoStorage.getClassMemberInfos(aClass); + PsiManager manager = aClass.getManager(); - for (MemberInfoBase member : members) { - if (manager.areElementsEquivalent(member.getMember(), aMember)) { - member.setChecked(true); - break; - } - } - PushDownDialog dialog = new PushDownDialog( + for (MemberInfoBase member : members) { + if (manager.areElementsEquivalent(member.getMember(), aMember)) { + member.setChecked(true); + break; + } + } + PushDownDialog dialog = new PushDownDialog( project, members.toArray(new MemberInfo[members.size()]), - aClass); - dialog.show(); - } - - public boolean isEnabledOnElements(PsiElement[] elements) { - /* - if (elements.length == 1) { - return elements[0] instanceof PsiClass || elements[0] instanceof PsiField || elements[0] instanceof PsiMethod; + aClass + ); + dialog.show(); } - else if (elements.length > 1){ - for (int idx = 0; idx < elements.length; idx++) { - PsiElement element = elements[idx]; - if (!(element instanceof PsiField || element instanceof PsiMethod)) return false; - } - return true; + + @Override + public boolean isEnabledOnElements(PsiElement[] elements) { + /* + if (elements.length == 1) { + return elements[0] instanceof PsiClass || elements[0] instanceof PsiField || elements[0] instanceof PsiMethod; + } + else if (elements.length > 1){ + for (int idx = 0; idx < elements.length; idx++) { + PsiElement element = elements[idx]; + if (!(element instanceof PsiField || element instanceof PsiMethod)) return false; + } + return true; + } + return false; + */ + // todo: multiple selection etc + return elements.length == 1 && elements[0] instanceof PsiClass; } - return false; - */ - // todo: multiple selection etc - return elements.length == 1 && elements[0] instanceof PsiClass; - } } \ No newline at end of file diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownProcessor.java index aded383a5..565f3f841 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/memberPushDown/PushDownProcessor.java @@ -78,7 +78,7 @@ public PushDownProcessor( @Nonnull @Override - protected String getCommandName() { + protected LocalizeValue getCommandName() { return JavaPushDownHandler.REFACTORING_NAME; } @@ -115,7 +115,7 @@ protected boolean preprocessUsages(@Nonnull SimpleReference refUsag ? "Enum " + myClass.getQualifiedName() + " doesn't have constants to inline to. " : "Final class " + myClass.getQualifiedName() + "does not have inheritors. " ) + "Pushing members down will result in them being deleted. Would you like to proceed?", - JavaPushDownHandler.REFACTORING_NAME, + JavaPushDownHandler.REFACTORING_NAME.get(), UIUtil.getWarningIcon() ) != DialogWrapper.OK_EXIT_CODE) { return false; @@ -126,7 +126,7 @@ protected boolean preprocessUsages(@Nonnull SimpleReference refUsag ? RefactoringLocalize.interface0DoesNotHaveInheritors(myClass.getQualifiedName()) : RefactoringLocalize.class0DoesNotHaveInheritors(myClass.getQualifiedName()); String message = noInheritors + "\n" + RefactoringLocalize.pushDownWillDeleteMembers(); - int answer = Messages.showYesNoCancelDialog(message, JavaPushDownHandler.REFACTORING_NAME, UIUtil.getWarningIcon()); + int answer = Messages.showYesNoCancelDialog(message, JavaPushDownHandler.REFACTORING_NAME.get(), UIUtil.getWarningIcon()); if (answer == DialogWrapper.OK_EXIT_CODE) { myCreateClassDlg = CreateSubclassAction.chooseSubclassToCreate(myClass); if (myCreateClassDlg != null) { @@ -145,16 +145,15 @@ else if (answer != 1) { @RequiredReadAction Runnable runnable = () -> { for (UsageInfo usage : usagesIn) { - PsiElement element = usage.getElement(); - if (element instanceof PsiClass psiClass) { - pushDownConflicts.checkTargetClassConflicts(psiClass, usagesIn.length > 1, element); + if (usage.getElement() instanceof PsiClass psiClass) { + pushDownConflicts.checkTargetClassConflicts(psiClass, usagesIn.length > 1, psiClass); } } }; boolean processFinished = ProgressManager.getInstance().runProcessWithProgressSynchronously( runnable, - RefactoringLocalize.detectingPossibleConflicts().get(), + RefactoringLocalize.detectingPossibleConflicts(), true, myProject ); @@ -172,7 +171,7 @@ protected void refreshElements(PsiElement[] elements) { } @Override - @RequiredUIAccess + @RequiredWriteAction protected void performRefactoring(@Nonnull UsageInfo[] usages) { try { encodeRefs(); @@ -250,10 +249,8 @@ private void encodeRef(PsiJavaCodeReferenceElement expression, Set mo if (qualifier == null) { toPut.putCopyableUserData(REMOVE_QUALIFIER_KEY, Boolean.TRUE); } - else { - if (qualifier instanceof PsiJavaCodeReferenceElement referenceElement && referenceElement.isReferenceTo(myClass)) { - toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, myClass); - } + else if (qualifier instanceof PsiJavaCodeReferenceElement refElem && refElem.isReferenceTo(myClass)) { + toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, myClass); } } else if (movedMember instanceof PsiClass movedClass @@ -262,12 +259,10 @@ else if (movedMember instanceof PsiClass movedClass toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, movedClass); } } - else { - if (qualifier instanceof PsiThisExpression thisExpression) { - PsiJavaCodeReferenceElement qElement = thisExpression.getQualifier(); - if (qElement != null && qElement.isReferenceTo(myClass)) { - toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, myClass); - } + else if (qualifier instanceof PsiThisExpression thisExpression) { + PsiJavaCodeReferenceElement qElement = thisExpression.getQualifier(); + if (qElement != null && qElement.isReferenceTo(myClass)) { + toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, myClass); } } } @@ -312,7 +307,7 @@ public void visitTypeElement(@Nonnull PsiTypeElement type) { }); } - @RequiredReadAction + @RequiredWriteAction private void decodeRef(PsiJavaCodeReferenceElement ref, PsiElementFactory factory, PsiClass targetClass, PsiElement toGet) { try { if (toGet.getCopyableUserData(REMOVE_QUALIFIER_KEY) != null) { @@ -360,8 +355,8 @@ private void removeFromTargetClass() throws IncorrectOperationException { for (MemberInfo memberInfo : myMemberInfos) { PsiElement member = memberInfo.getMember(); - if (member instanceof PsiField) { - member.delete(); + if (member instanceof PsiField field) { + field.delete(); } else if (member instanceof PsiMethod method) { if (memberInfo.isToAbstract()) { @@ -372,7 +367,7 @@ else if (member instanceof PsiMethod method) { myJavaDocPolicy.processOldJavaDoc(method.getDocComment()); } else { - member.delete(); + method.delete(); } } else if (member instanceof PsiClass psiClass) { @@ -380,45 +375,41 @@ else if (member instanceof PsiClass psiClass) { RefactoringUtil.removeFromReferenceList(myClass.getImplementsList(), psiClass); } else { - member.delete(); + psiClass.delete(); } } } } - @RequiredUIAccess + @RequiredWriteAction protected void pushDownToClass(PsiClass targetClass) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(myClass, targetClass, PsiSubstitutor.EMPTY); for (MemberInfo memberInfo : myMemberInfos) { PsiMember member = memberInfo.getMember(); List refsToRebind = new ArrayList<>(); - PsiModifierList list = member.getModifierList(); - LOG.assertTrue(list != null); - if (list.hasModifierProperty(PsiModifier.STATIC)) { + if (member.isStatic()) { for (PsiReference reference : ReferencesSearch.search(member)) { - PsiElement element = reference.getElement(); - if (element instanceof PsiReferenceExpression referenceExpression) { - PsiExpression qualifierExpression = referenceExpression.getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression refExpr && !(refExpr.resolve() instanceof PsiClass)) { - continue; - } + if (reference.getElement() instanceof PsiReferenceExpression refExpr + && refExpr.getQualifierExpression() instanceof PsiReferenceExpression qRefExpr + && !(qRefExpr.resolve() instanceof PsiClass)) { + continue; } refsToRebind.add(reference); } } - member = (PsiMember)member.copy(); + member = (PsiMember) member.copy(); RefactoringUtil.replaceMovedMemberTypeParameters(member, PsiUtil.typeParametersIterable(myClass), substitutor, factory); PsiMember newMember = null; if (member instanceof PsiField field) { field.normalizeDeclaration(); - newMember = (PsiMember)targetClass.add(member); + newMember = (PsiMember) targetClass.add(field); } else if (member instanceof PsiMethod method) { PsiMethod methodBySignature = MethodSignatureUtil.findMethodBySuperSignature(targetClass, method.getSignature(substitutor), false); if (methodBySignature == null) { - newMember = (PsiMethod)targetClass.add(method); + newMember = (PsiMethod) targetClass.add(method); if (myClass.isInterface()) { if (!targetClass.isInterface()) { PsiUtil.setModifierProperty(newMember, PsiModifier.PUBLIC, true); @@ -434,7 +425,7 @@ else if (memberInfo.isToAbstract()) { if (newMember.isPrivate()) { PsiUtil.setModifierProperty(newMember, PsiModifier.PROTECTED, true); } - myJavaDocPolicy.processNewJavaDoc(((PsiMethod)newMember).getDocComment()); + myJavaDocPolicy.processNewJavaDoc(((PsiMethod) newMember).getDocComment()); } } else { //abstract method: remove @Override @@ -459,13 +450,13 @@ else if (memberInfo.isToAbstract()) { } else if (member instanceof PsiClass) { if (Boolean.FALSE.equals(memberInfo.getOverrides())) { - PsiClass aClass = (PsiClass)memberInfo.getMember(); + PsiClass aClass = (PsiClass) memberInfo.getMember(); PsiClassType classType = null; if (!targetClass.isInheritor(aClass, false)) { PsiClassType[] types = memberInfo.getSourceReferenceList().getReferencedTypes(); for (PsiClassType type : types) { if (type.resolve() == aClass) { - classType = (PsiClassType)substitutor.substitute(type); + classType = (PsiClassType) substitutor.substitute(type); } } PsiJavaCodeReferenceElement classRef = classType != null @@ -480,7 +471,7 @@ else if (member instanceof PsiClass) { } } else { - newMember = (PsiMember)targetClass.add(member); + newMember = (PsiMember) targetClass.add(member); } } @@ -492,7 +483,7 @@ else if (member instanceof PsiClass) { JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(psiReference.bindToElement(newMember)); } JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance(newMember.getProject()); - ((JavaRefactoringListenerManagerImpl)listenerManager).fireMemberMoved(myClass, newMember); + ((JavaRefactoringListenerManagerImpl) listenerManager).fireMemberMoved(myClass, newMember); } } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java index 4d5f8891e..348b30c26 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationProcessor.java @@ -19,7 +19,6 @@ import com.intellij.java.language.psi.PsiMigration; import com.intellij.java.language.psi.codeStyle.JavaCodeStyleManager; import consulo.annotation.access.RequiredReadAction; -import consulo.application.Application; import consulo.application.WriteAction; import consulo.content.scope.SearchScope; import consulo.language.editor.refactoring.BaseRefactoringProcessor; @@ -29,6 +28,7 @@ import consulo.language.psi.scope.GlobalSearchScope; import consulo.localHistory.LocalHistory; import consulo.localHistory.LocalHistoryAction; +import consulo.localize.LocalizeValue; import consulo.project.Project; import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awt.Messages; @@ -40,6 +40,7 @@ import jakarta.annotation.Nonnull; import java.util.ArrayList; +import java.util.List; /** * @author ven @@ -48,7 +49,7 @@ public class MigrationProcessor extends BaseRefactoringProcessor { private final MigrationMap myMigrationMap; private PsiMigration myPsiMigration; private final SearchScope mySearchScope; - private ArrayList> myRefsToShorten; + private List> myRefsToShorten; public MigrationProcessor(Project project, MigrationMap migrationMap) { this(project, migrationMap, GlobalSearchScope.projectScope(project)); @@ -94,7 +95,7 @@ protected void refreshElements(@Nonnull PsiElement[] elements) { @Override @RequiredReadAction protected UsageInfo[] findUsages() { - ArrayList usagesVector = new ArrayList<>(); + List usagesVector = new ArrayList<>(); try { if (myMigrationMap == null) { return UsageInfo.EMPTY_ARRAY; @@ -119,7 +120,7 @@ protected UsageInfo[] findUsages() { // when somebody with read action resolves reference and gets ResolveResult. // Then here, in another read actions, all caches are invalidated but those resolve result // is used without additional checks inside that read action - but it's already invalid - Application.get().invokeLater(() -> WriteAction.run(this::finishFindMigration), myProject.getDisposed()); + myProject.getApplication().invokeLater(() -> WriteAction.run(this::finishFindMigration), myProject.getDisposed()); } return usagesVector.toArray(UsageInfo.EMPTY_ARRAY); } @@ -194,8 +195,8 @@ protected void performPsiSpoilingRefactoring() { @Override @Nonnull - protected String getCommandName() { - return RefactoringLocalize.migrationTitle().get(); + protected LocalizeValue getCommandName() { + return RefactoringLocalize.migrationTitle(); } static class MigrationUsageInfo extends UsageInfo { diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationUtil.java index c97cc2f1a..bc3f9cd0a 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationUtil.java @@ -20,6 +20,8 @@ import com.intellij.java.language.psi.PsiClass; import com.intellij.java.language.psi.PsiJavaCodeReferenceElement; import com.intellij.java.language.psi.PsiMigration; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.application.WriteAction; import consulo.content.scope.SearchScope; import consulo.document.util.TextRange; @@ -33,91 +35,96 @@ import consulo.util.lang.Comparing; import java.util.ArrayList; +import java.util.List; public class MigrationUtil { - private static final Logger LOG = Logger.getInstance(MigrationUtil.class); + private static final Logger LOG = Logger.getInstance(MigrationUtil.class); - private MigrationUtil() { - } + private MigrationUtil() { + } - public static UsageInfo[] findPackageUsages(Project project, PsiMigration migration, String qName, SearchScope searchScope) { - PsiPackage aPackage = findOrCreatePackage(project, migration, qName); + @RequiredReadAction + public static UsageInfo[] findPackageUsages(Project project, PsiMigration migration, String qName, SearchScope searchScope) { + PsiPackage aPackage = findOrCreatePackage(project, migration, qName); - return findRefs(aPackage, searchScope); - } + return findRefs(aPackage, searchScope); + } - private static PsiElement bindNonJavaReference(PsiElement bindTo, PsiElement element, UsageInfo usage) { - TextRange range = usage.getRangeInElement(); - for (PsiReference reference : element.getReferences()) { - if (reference instanceof JavaClassReference) { - JavaClassReference classReference = (JavaClassReference) reference; - if (classReference.getRangeInElement().equals(range)) { - return classReference.bindToElement(bindTo); + @RequiredReadAction + private static PsiElement bindNonJavaReference(PsiElement bindTo, PsiElement element, UsageInfo usage) { + TextRange range = usage.getRangeInElement(); + for (PsiReference reference : element.getReferences()) { + if (reference instanceof JavaClassReference classReference && classReference.getRangeInElement().equals(range)) { + return classReference.bindToElement(bindTo); + } } - } + return bindTo; } - return bindTo; - } - - public static UsageInfo[] findClassUsages(Project project, PsiMigration migration, String qName, SearchScope searchScope) { - PsiClass aClass = findOrCreateClass(project, migration, qName); - return findRefs(aClass, searchScope); - } + @RequiredReadAction + public static UsageInfo[] findClassUsages(Project project, PsiMigration migration, String qName, SearchScope searchScope) { + PsiClass aClass = findOrCreateClass(project, migration, qName); - private static UsageInfo[] findRefs(PsiElement aClass, SearchScope searchScope) { - ArrayList results = new ArrayList<>(); - for (PsiReference usage : ReferencesSearch.search(aClass, searchScope, false)) { - results.add(new UsageInfo(usage)); + return findRefs(aClass, searchScope); } - return results.toArray(UsageInfo.EMPTY_ARRAY); - } + @RequiredReadAction + private static UsageInfo[] findRefs(PsiElement aClass, SearchScope searchScope) { + List results = new ArrayList<>(); + for (PsiReference usage : ReferencesSearch.search(aClass, searchScope, false)) { + results.add(new UsageInfo(usage)); + } - static void doMigration(PsiElement elementToBind, String newQName, UsageInfo[] usages, ArrayList> refsToShorten) { - try { - SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(elementToBind.getProject()); - // rename all references - for (UsageInfo usage : usages) { - if (usage instanceof MigrationProcessor.MigrationUsageInfo) { - MigrationProcessor.MigrationUsageInfo usageInfo = (MigrationProcessor.MigrationUsageInfo) usage; - if (Comparing.equal(newQName, usageInfo.mapEntry.getNewName())) { - PsiElement element = usage.getElement(); - if (element == null || !element.isValid()) { - continue; - } - PsiElement psiElement; - if (element instanceof PsiJavaCodeReferenceElement) { - psiElement = ((PsiJavaCodeReferenceElement) element).bindToElement(elementToBind); - } else { - psiElement = bindNonJavaReference(elementToBind, element, usage); - } - if (psiElement != null) { - refsToShorten.add(smartPointerManager.createSmartPsiElementPointer(psiElement)); + return results.toArray(UsageInfo.EMPTY_ARRAY); + } + + @RequiredWriteAction + static void doMigration( + PsiElement elementToBind, + String newQName, + UsageInfo[] usages, + List> refsToShorten + ) { + try { + SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(elementToBind.getProject()); + // rename all references + for (UsageInfo usage : usages) { + if (usage instanceof MigrationProcessor.MigrationUsageInfo usageInfo + && Comparing.equal(newQName, usageInfo.mapEntry.getNewName())) { + PsiElement element = usageInfo.getElement(); + if (element == null || !element.isValid()) { + continue; + } + PsiElement psiElement = element instanceof PsiJavaCodeReferenceElement codeRef + ? codeRef.bindToElement(elementToBind) + : bindNonJavaReference(elementToBind, element, usageInfo); + if (psiElement != null) { + refsToShorten.add(smartPointerManager.createSmartPsiElementPointer(psiElement)); + } + } } - } } - } - } catch (IncorrectOperationException e) { - // should not happen! - LOG.error(e); + catch (IncorrectOperationException e) { + // should not happen! + LOG.error(e); + } } - } - static PsiPackage findOrCreatePackage(Project project, PsiMigration migration, String qName) { - PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(qName); - if (aPackage != null) { - return aPackage; - } else { - return WriteAction.compute(() -> migration.createPackage(qName)); + static PsiPackage findOrCreatePackage(Project project, PsiMigration migration, String qName) { + PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(qName); + if (aPackage != null) { + return aPackage; + } + else { + return WriteAction.compute(() -> migration.createPackage(qName)); + } } - } - static PsiClass findOrCreateClass(Project project, PsiMigration migration, String qName) { - PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(qName, GlobalSearchScope.allScope(project)); - if (aClass == null) { - aClass = WriteAction.compute(() -> migration.createClass(qName)); + static PsiClass findOrCreateClass(Project project, PsiMigration migration, String qName) { + PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(qName, GlobalSearchScope.allScope(project)); + if (aClass == null) { + aClass = WriteAction.compute(() -> migration.createClass(qName)); + } + return aClass; } - return aClass; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java index 1da6782b4..247833d58 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java @@ -23,7 +23,6 @@ import com.intellij.java.language.util.VisibilityUtil; import consulo.annotation.access.RequiredReadAction; import consulo.annotation.access.RequiredWriteAction; -import consulo.application.Application; import consulo.component.extension.ExtensionPoint; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.localize.RefactoringLocalize; @@ -129,7 +128,7 @@ protected boolean preprocessUsages(@Nonnull SimpleReference refUsag @Override protected void refreshElements(@Nonnull PsiElement[] elements) { - Application.get().runReadAction(() -> { + myProject.getApplication().runReadAction(() -> { PsiClass[] classesToMove = new PsiClass[elements.length]; for (int i = 0; i < classesToMove.length; i++) { classesToMove[i] = (PsiClass)elements[i]; @@ -235,12 +234,12 @@ protected void performPsiSpoilingRefactoring() { @Nonnull @Override - protected String getCommandName() { + protected LocalizeValue getCommandName() { return RefactoringLocalize.moveClassToInnerCommandName( (myClassesToMove.length > 1 ? "classes " : "class ") + StringUtil.join(myClassesToMove, PsiNamedElement::getName, ", "), myTargetClass.getQualifiedName() - ).get(); + ); } @Nonnull diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java index fbedeeb38..50e89ee0e 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java @@ -278,7 +278,7 @@ private void detectPackageLocalsMoved(UsageInfo[] usages, MultiMap usages) { protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { MultiMap conflicts = new MultiMap<>(); for (MemberInfo memberInfo : myDelegateMethodInfos) { - if (memberInfo.isChecked() && memberInfo.isToAbstract() - && memberInfo.getMember() instanceof PsiMethod method && method.findDeepestSuperMethods().length > 0) { + if (memberInfo.isChecked() + && memberInfo.isToAbstract() + && memberInfo.getMember() instanceof PsiMethod method + && method.findDeepestSuperMethods().length > 0) { conflicts.putValue( method, JavaRefactoringLocalize.removeMiddlemanDeletedHierarchyConflict( @@ -103,7 +105,7 @@ protected boolean preprocessUsages(@Nonnull SimpleReference refUsag return showConflicts(conflicts, refUsages.get()); } - @RequiredWriteAction + @RequiredReadAction private void processUsagesForMethod( boolean deleteMethodHierarchy, PsiMethod method, @@ -152,7 +154,7 @@ protected void performRefactoring(@Nonnull UsageInfo[] usageInfos) { @Nonnull @Override @RequiredReadAction - protected String getCommandName() { - return JavaRefactoringLocalize.exposedDelegationCommandName(containingClass.getName(), '.', field.getName()).get(); + protected LocalizeValue getCommandName() { + return JavaRefactoringLocalize.exposedDelegationCommandName(containingClass.getName(), '.', field.getName()); } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/duplicates/DuplicatesImpl.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/duplicates/DuplicatesImpl.java index 7a4babd04..7a6661425 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/util/duplicates/DuplicatesImpl.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/util/duplicates/DuplicatesImpl.java @@ -35,10 +35,11 @@ import consulo.navigation.OpenFileDescriptorFactory; import consulo.platform.base.localize.CommonLocalize; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awt.Messages; import consulo.ui.ex.awt.ReplacePromptDialog; import consulo.ui.ex.awt.UIUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -50,191 +51,223 @@ * @author dsl */ public class DuplicatesImpl { - private static final Logger LOG = Logger.getInstance(DuplicatesImpl.class); + private static final Logger LOG = Logger.getInstance(DuplicatesImpl.class); - private DuplicatesImpl() { - } - - public static void invoke(@Nonnull Project project, @Nonnull Editor editor, @Nonnull MatchProvider provider) { - invoke(project, editor, provider, true); - } - - public static void invoke(@Nonnull Project project, @Nonnull Editor editor, @Nonnull MatchProvider provider, boolean skipPromptWhenOne) { - List duplicates = provider.getDuplicates(); - int idx = 0; - Ref showAll = new Ref<>(); - String confirmDuplicatePrompt = getConfirmationPrompt(provider, duplicates); - for (Match match : duplicates) { - if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid()) { - continue; - } - if (replaceMatch(project, provider, match, editor, ++idx, duplicates.size(), showAll, confirmDuplicatePrompt, skipPromptWhenOne)) { - return; - } + private DuplicatesImpl() { } - } - public static void invoke(Project project, MatchProvider provider) { - List duplicates = provider.getDuplicates(); - int idx = 0; - Ref showAll = new Ref<>(); - String confirmDuplicatePrompt = getConfirmationPrompt(provider, duplicates); - for (Match match : duplicates) { - PsiFile file = match.getFile(); - VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile == null || !virtualFile.isValid()) { - return; - } - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { - return; - } - Editor editor = FileEditorManager.getInstance(project) - .openTextEditor(OpenFileDescriptorFactory.getInstance(project).builder(virtualFile).build(), false); - LOG.assertTrue(editor != null); - if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid()) { - continue; - } - if (replaceMatch(project, provider, match, editor, ++idx, duplicates.size(), showAll, confirmDuplicatePrompt, false)) { - return; - } + @RequiredUIAccess + public static void invoke(@Nonnull Project project, @Nonnull Editor editor, @Nonnull MatchProvider provider) { + invoke(project, editor, provider, true); } - } - @Nullable - private static String getConfirmationPrompt(MatchProvider provider, List duplicates) { - String confirmDuplicatePrompt = null; - for (Match duplicate : duplicates) { - confirmDuplicatePrompt = provider.getConfirmDuplicatePrompt(duplicate); - if (confirmDuplicatePrompt != null) { - break; - } + @RequiredUIAccess + public static void invoke( + @Nonnull Project project, + @Nonnull Editor editor, + @Nonnull MatchProvider provider, + boolean skipPromptWhenOne + ) { + List duplicates = provider.getDuplicates(); + int idx = 0; + SimpleReference showAll = SimpleReference.create(); + String confirmDuplicatePrompt = getConfirmationPrompt(provider, duplicates); + for (Match match : duplicates) { + if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid()) { + continue; + } + if (replaceMatch( + project, + provider, + match, + editor, + ++idx, + duplicates.size(), + showAll, + confirmDuplicatePrompt, + skipPromptWhenOne + )) { + return; + } + } } - return confirmDuplicatePrompt; - } - private static boolean replaceMatch( - final Project project, - final MatchProvider provider, - final Match match, - @Nonnull Editor editor, - final int idx, - final int size, - Ref showAll, - String confirmDuplicatePrompt, - boolean skipPromptWhenOne - ) { - ArrayList highlighters = previewMatch(project, match, editor); - try { - if (!project.getApplication().isUnitTestMode()) { - if ((!skipPromptWhenOne || size > 1) && (showAll.get() == null || !showAll.get())) { - final String prompt = provider.getConfirmDuplicatePrompt(match); - ReplacePromptDialog promptDialog = new ReplacePromptDialog(false, provider.getReplaceDuplicatesTitle(idx, size), project) { - @Override - protected String getMessage() { - String message = super.getMessage(); - return prompt != null ? message + " " + prompt : message; + @RequiredUIAccess + public static void invoke(Project project, MatchProvider provider) { + List duplicates = provider.getDuplicates(); + int idx = 0; + SimpleReference showAll = SimpleReference.create(); + String confirmDuplicatePrompt = getConfirmationPrompt(provider, duplicates); + for (Match match : duplicates) { + PsiFile file = match.getFile(); + VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile == null || !virtualFile.isValid()) { + return; } - }; - promptDialog.show(); - boolean allChosen = promptDialog.getExitCode() == FindManager.PromptResult.ALL; - showAll.set(allChosen); - if (allChosen && confirmDuplicatePrompt != null && prompt == null) { - if (Messages.showOkCancelDialog( - project, - "In order to replace all occurrences method signature will be changed. Proceed?", - CommonLocalize.titleWarning().get(), - UIUtil.getWarningIcon() - ) != Messages.OK) { - return true; + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) { + return; + } + Editor editor = FileEditorManager.getInstance(project) + .openTextEditor(OpenFileDescriptorFactory.getInstance(project).builder(virtualFile).build(), false); + LOG.assertTrue(editor != null); + if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid()) { + continue; + } + if (replaceMatch(project, provider, match, editor, ++idx, duplicates.size(), showAll, confirmDuplicatePrompt, false)) { + return; + } + } + } + + @Nullable + private static String getConfirmationPrompt(MatchProvider provider, List duplicates) { + String confirmDuplicatePrompt = null; + for (Match duplicate : duplicates) { + confirmDuplicatePrompt = provider.getConfirmDuplicatePrompt(duplicate); + if (confirmDuplicatePrompt != null) { + break; } - } - if (promptDialog.getExitCode() == FindManager.PromptResult.SKIP) { - return false; - } - if (promptDialog.getExitCode() == FindManager.PromptResult.CANCEL) { - return true; - } } - } - } finally { - HighlightManager.getInstance(project).removeSegmentHighlighter(editor, highlighters.get(0)); + return confirmDuplicatePrompt; } - new WriteCommandAction(project, MethodDuplicatesHandler.REFACTORING_NAME, MethodDuplicatesHandler.REFACTORING_NAME) { - @Override - protected void run(@Nonnull Result result) throws Throwable { + @RequiredUIAccess + private static boolean replaceMatch( + final Project project, + final MatchProvider provider, + final Match match, + @Nonnull Editor editor, + final int idx, + final int size, + SimpleReference showAll, + String confirmDuplicatePrompt, + boolean skipPromptWhenOne + ) { + List highlighters = previewMatch(project, match, editor); try { - provider.processMatch(match); - } catch (IncorrectOperationException e) { - LOG.error(e); + if (!project.getApplication().isUnitTestMode()) { + if ((!skipPromptWhenOne || size > 1) && (showAll.get() == null || !showAll.get())) { + final String prompt = provider.getConfirmDuplicatePrompt(match); + ReplacePromptDialog promptDialog = + new ReplacePromptDialog(false, provider.getReplaceDuplicatesTitle(idx, size), project) { + @Override + protected String getMessage() { + String message = super.getMessage(); + return prompt != null ? message + " " + prompt : message; + } + }; + promptDialog.show(); + boolean allChosen = promptDialog.getExitCode() == FindManager.PromptResult.ALL; + showAll.set(allChosen); + if (allChosen && confirmDuplicatePrompt != null && prompt == null) { + if (Messages.showOkCancelDialog( + project, + "In order to replace all occurrences method signature will be changed. Proceed?", + CommonLocalize.titleWarning().get(), + UIUtil.getWarningIcon() + ) != Messages.OK) { + return true; + } + } + if (promptDialog.getExitCode() == FindManager.PromptResult.SKIP) { + return false; + } + if (promptDialog.getExitCode() == FindManager.PromptResult.CANCEL) { + return true; + } + } + } + } + finally { + HighlightManager.getInstance(project).removeSegmentHighlighter(editor, highlighters.get(0)); } - } - }.execute(); - return false; - } + new WriteCommandAction(project, MethodDuplicatesHandler.REFACTORING_NAME.get(), MethodDuplicatesHandler.REFACTORING_NAME.get()) { + @Override + protected void run(@Nonnull Result result) throws Throwable { + try { + provider.processMatch(match); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + }.execute(); - public static ArrayList previewMatch(Project project, Match match, Editor editor) { - ArrayList highlighters = new ArrayList<>(); - highlightMatch(project, editor, match, highlighters); - TextRange textRange = match.getTextRange(); - LogicalPosition logicalPosition = editor.offsetToLogicalPosition(textRange.getStartOffset()); - expandAllRegionsCoveringRange(project, editor, textRange); - editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.MAKE_VISIBLE); - return highlighters; - } + return false; + } - private static void expandAllRegionsCoveringRange(Project project, Editor editor, TextRange textRange) { - FoldRegion[] foldRegions = CodeFoldingManager.getInstance(project).getFoldRegionsAtOffset(editor, textRange.getStartOffset()); - boolean anyCollapsed = false; - for (FoldRegion foldRegion : foldRegions) { - if (!foldRegion.isExpanded()) { - anyCollapsed = true; - break; - } + public static List previewMatch(Project project, Match match, Editor editor) { + List highlighters = new ArrayList<>(); + highlightMatch(project, editor, match, highlighters); + TextRange textRange = match.getTextRange(); + LogicalPosition logicalPosition = editor.offsetToLogicalPosition(textRange.getStartOffset()); + expandAllRegionsCoveringRange(project, editor, textRange); + editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.MAKE_VISIBLE); + return highlighters; } - if (anyCollapsed) { - editor.getFoldingModel().runBatchFoldingOperation(() -> { + + private static void expandAllRegionsCoveringRange(Project project, Editor editor, TextRange textRange) { + FoldRegion[] foldRegions = CodeFoldingManager.getInstance(project).getFoldRegionsAtOffset(editor, textRange.getStartOffset()); + boolean anyCollapsed = false; for (FoldRegion foldRegion : foldRegions) { - if (!foldRegion.isExpanded()) { - foldRegion.setExpanded(true); - } + if (!foldRegion.isExpanded()) { + anyCollapsed = true; + break; + } + } + if (anyCollapsed) { + editor.getFoldingModel().runBatchFoldingOperation(() -> { + for (FoldRegion foldRegion : foldRegions) { + if (!foldRegion.isExpanded()) { + foldRegion.setExpanded(true); + } + } + }); } - }); } - } - public static void highlightMatch(Project project, Editor editor, Match match, ArrayList highlighters) { - HighlightManager.getInstance(project).addRangeHighlight(editor, match.getTextRange().getStartOffset(), match.getTextRange().getEndOffset(), EditorColors.SEARCH_RESULT_ATTRIBUTES, true, highlighters); - } + public static void highlightMatch(Project project, Editor editor, Match match, List highlighters) { + HighlightManager.getInstance(project).addRangeHighlight( + editor, + match.getTextRange().getStartOffset(), + match.getTextRange().getEndOffset(), + EditorColors.SEARCH_RESULT_ATTRIBUTES, + true, + highlighters + ); + } - public static void processDuplicates(@Nonnull MatchProvider provider, @Nonnull Project project, @Nonnull Editor editor) { - Boolean hasDuplicates = provider.hasDuplicates(); - if (hasDuplicates == null || hasDuplicates.booleanValue()) { - List duplicates = provider.getDuplicates(); - ArrayList highlighters = null; - if (duplicates.size() == 1) { - highlighters = previewMatch(project, duplicates.get(0), editor); - } - int answer = project.getApplication().isUnitTestMode() || hasDuplicates == null ? Messages.YES - : Messages.showYesNoDialog( - project, - RefactoringLocalize.zeroHasDetected1CodeFragmentsInThisFileThatCanBeReplacedWithACallToExtractedMethod( - Application.get().getName(), - duplicates.size() - ).get(), - "Process Duplicates", - UIUtil.getQuestionIcon() - ); - if (answer == Messages.YES) { - PsiDocumentManager.getInstance(project).commitAllDocuments(); - invoke(project, editor, provider, hasDuplicates != null); - } else if (highlighters != null) { - HighlightManager highlightManager = HighlightManager.getInstance(project); - for (RangeHighlighter highlighter : highlighters) { - highlightManager.removeSegmentHighlighter(editor, highlighter); + @RequiredUIAccess + public static void processDuplicates(@Nonnull MatchProvider provider, @Nonnull Project project, @Nonnull Editor editor) { + Boolean hasDuplicates = provider.hasDuplicates(); + if (hasDuplicates == null || hasDuplicates) { + List duplicates = provider.getDuplicates(); + List highlighters = null; + if (duplicates.size() == 1) { + highlighters = previewMatch(project, duplicates.get(0), editor); + } + int answer = project.getApplication().isUnitTestMode() || hasDuplicates == null + ? Messages.YES + : Messages.showYesNoDialog( + project, + RefactoringLocalize.zeroHasDetected1CodeFragmentsInThisFileThatCanBeReplacedWithACallToExtractedMethod( + Application.get().getName(), + duplicates.size() + ).get(), + "Process Duplicates", + UIUtil.getQuestionIcon() + ); + if (answer == Messages.YES) { + PsiDocumentManager.getInstance(project).commitAllDocuments(); + invoke(project, editor, provider, hasDuplicates != null); + } + else if (highlighters != null) { + HighlightManager highlightManager = HighlightManager.getInstance(project); + for (RangeHighlighter highlighter : highlighters) { + highlightManager.removeSegmentHighlighter(editor, highlighter); + } + } } - } } - } } \ No newline at end of file