diff --git a/java-language-api/src/main/java/com/intellij/java/language/util/VisibilityUtil.java b/java-language-api/src/main/java/com/intellij/java/language/util/VisibilityUtil.java index 109c5ac5cc..7b485887f1 100644 --- a/java-language-api/src/main/java/com/intellij/java/language/util/VisibilityUtil.java +++ b/java-language-api/src/main/java/com/intellij/java/language/util/VisibilityUtil.java @@ -38,137 +38,141 @@ import jakarta.annotation.Nonnull; - public class VisibilityUtil { - @NonNls - public static final String ESCALATE_VISIBILITY = "EscalateVisible"; - private static final String[] visibilityModifiers = { - PsiModifier.PRIVATE, - PsiModifier.PACKAGE_LOCAL, - PsiModifier.PROTECTED, - PsiModifier.PUBLIC - }; - - private VisibilityUtil() { - } - - public static int compare(@PsiModifier.ModifierConstant String v1, @PsiModifier.ModifierConstant String v2) { - return ArrayUtil.find(visibilityModifiers, v2) - ArrayUtil.find(visibilityModifiers, v1); - } - - @PsiModifier.ModifierConstant - public static String getHighestVisibility(@PsiModifier.ModifierConstant String v1, @PsiModifier.ModifierConstant String v2) { - return compare(v1, v2) < 0 ? v1 : v2; - } - - public static void escalateVisibility(PsiMember modifierListOwner, PsiElement place) throws IncorrectOperationException { - final String visibilityModifier = getVisibilityModifier(modifierListOwner.getModifierList()); - int index; - for (index = 0; index < visibilityModifiers.length; index++) { - String modifier = visibilityModifiers[index]; - if (modifier.equals(visibilityModifier)) { - break; - } - } - for (; index < visibilityModifiers.length && !PsiUtil.isAccessible(modifierListOwner, place, null); index++) { - @PsiModifier.ModifierConstant String modifier = visibilityModifiers[index]; - PsiUtil.setModifierProperty(modifierListOwner, modifier, true); - } - } + @NonNls + public static final String ESCALATE_VISIBILITY = "EscalateVisible"; + private static final String[] visibilityModifiers = { + PsiModifier.PRIVATE, + PsiModifier.PACKAGE_LOCAL, + PsiModifier.PROTECTED, + PsiModifier.PUBLIC + }; - public static void escalateVisibility(PsiModifierList modifierList, PsiElement place) throws IncorrectOperationException { - final PsiElement parent = modifierList.getParent(); - if (parent instanceof PsiMember) { - escalateVisibility((PsiMember) parent, place); + private VisibilityUtil() { } - } - @PsiModifier.ModifierConstant - public static String getPossibleVisibility(final PsiMember psiMethod, final PsiElement place) { - Project project = psiMethod.getProject(); - if (PsiUtil.isAccessible(project, psiMethod, place, null)) { - return getVisibilityModifier(psiMethod.getModifierList()); - } - if (JavaPsiFacade.getInstance(project).arePackagesTheSame(psiMethod, place)) { - return PsiModifier.PACKAGE_LOCAL; + public static int compare(@PsiModifier.ModifierConstant String v1, @PsiModifier.ModifierConstant String v2) { + return ArrayUtil.find(visibilityModifiers, v2) - ArrayUtil.find(visibilityModifiers, v1); } - if (InheritanceUtil.isInheritorOrSelf(PsiTreeUtil.getParentOfType(place, PsiClass.class), psiMethod.getContainingClass(), true)) { - return PsiModifier.PROTECTED; - } - return PsiModifier.PUBLIC; - } - @PsiModifier.ModifierConstant - public static String getVisibilityModifier(PsiModifierList list) { - if (list == null) { - return PsiModifier.PACKAGE_LOCAL; - } - for (@PsiModifier.ModifierConstant String modifier : visibilityModifiers) { - if (list.hasModifierProperty(modifier)) { - return modifier; - } + @PsiModifier.ModifierConstant + public static String getHighestVisibility(@PsiModifier.ModifierConstant String v1, @PsiModifier.ModifierConstant String v2) { + return compare(v1, v2) < 0 ? v1 : v2; } - return PsiModifier.PACKAGE_LOCAL; - } - - @Nonnull - @NonNls - public static String getVisibilityString(@PsiModifier.ModifierConstant String visibilityModifier) { - if (PsiModifier.PACKAGE_LOCAL.equals(visibilityModifier)) { - return ""; + + public static void escalateVisibility(PsiMember modifierListOwner, PsiElement place) throws IncorrectOperationException { + final String visibilityModifier = getVisibilityModifier(modifierListOwner.getModifierList()); + int index; + for (index = 0; index < visibilityModifiers.length; index++) { + String modifier = visibilityModifiers[index]; + if (modifier.equals(visibilityModifier)) { + break; + } + } + for (; index < visibilityModifiers.length && !PsiUtil.isAccessible(modifierListOwner, place, null); index++) { + @PsiModifier.ModifierConstant String modifier = visibilityModifiers[index]; + PsiUtil.setModifierProperty(modifierListOwner, modifier, true); + } } - return visibilityModifier; - } - - @Nls - @Nonnull - public static String getVisibilityStringToDisplay(@Nonnull PsiMember member) { - if (member.hasModifierProperty(PsiModifier.PUBLIC)) { - return toPresentableText(PsiModifier.PUBLIC); + + public static void escalateVisibility(PsiModifierList modifierList, PsiElement place) throws IncorrectOperationException { + final PsiElement parent = modifierList.getParent(); + if (parent instanceof PsiMember) { + escalateVisibility((PsiMember)parent, place); + } } - if (member.hasModifierProperty(PsiModifier.PROTECTED)) { - return toPresentableText(PsiModifier.PROTECTED); + + @PsiModifier.ModifierConstant + public static String getPossibleVisibility(final PsiMember psiMethod, final PsiElement place) { + Project project = psiMethod.getProject(); + if (PsiUtil.isAccessible(project, psiMethod, place, null)) { + return getVisibilityModifier(psiMethod.getModifierList()); + } + if (JavaPsiFacade.getInstance(project).arePackagesTheSame(psiMethod, place)) { + return PsiModifier.PACKAGE_LOCAL; + } + if (InheritanceUtil.isInheritorOrSelf(PsiTreeUtil.getParentOfType(place, PsiClass.class), psiMethod.getContainingClass(), true)) { + return PsiModifier.PROTECTED; + } + return PsiModifier.PUBLIC; } - if (member.hasModifierProperty(PsiModifier.PRIVATE)) { - return toPresentableText(PsiModifier.PRIVATE); + + @PsiModifier.ModifierConstant + public static String getVisibilityModifier(PsiModifierList list) { + if (list == null) { + return PsiModifier.PACKAGE_LOCAL; + } + for (@PsiModifier.ModifierConstant String modifier : visibilityModifiers) { + if (list.hasModifierProperty(modifier)) { + return modifier; + } + } + return PsiModifier.PACKAGE_LOCAL; } - return toPresentableText(PsiModifier.PACKAGE_LOCAL); - } - @Nonnull - public static String toPresentableText(@PsiModifier.ModifierConstant @Nonnull String modifier) { - return PsiBundle.visibilityPresentation(modifier); - } + @Nonnull + @NonNls + public static String getVisibilityString(@PsiModifier.ModifierConstant String visibilityModifier) { + if (PsiModifier.PACKAGE_LOCAL.equals(visibilityModifier)) { + return ""; + } + return visibilityModifier; + } - public static void fixVisibility(PsiElement[] elements, PsiMember member, @PsiModifier.ModifierConstant String newVisibility) { - if (newVisibility == null) { - return; + @Nls + @Nonnull + public static String getVisibilityStringToDisplay(@Nonnull PsiMember member) { + if (member.hasModifierProperty(PsiModifier.PUBLIC)) { + return toPresentableText(PsiModifier.PUBLIC); + } + if (member.hasModifierProperty(PsiModifier.PROTECTED)) { + return toPresentableText(PsiModifier.PROTECTED); + } + if (member.hasModifierProperty(PsiModifier.PRIVATE)) { + return toPresentableText(PsiModifier.PRIVATE); + } + return toPresentableText(PsiModifier.PACKAGE_LOCAL); } - if (ESCALATE_VISIBILITY.equals(newVisibility)) { - for (PsiElement element : elements) { - if (element != null) { - escalateVisibility(member, element); - } - } - } else { - setVisibility(member.getModifierList(), newVisibility); + + @Nonnull + public static String toPresentableText(@PsiModifier.ModifierConstant @Nonnull String modifier) { + return PsiBundle.visibilityPresentation(modifier); } - } - public static void setVisibility(PsiModifierList modifierList, @PsiModifier.ModifierConstant String newVisibility) throws IncorrectOperationException { - modifierList.setModifierProperty(newVisibility, true); - } + public static void fixVisibility(PsiElement[] elements, PsiMember member, @PsiModifier.ModifierConstant String newVisibility) { + if (newVisibility == null) { + return; + } + if (ESCALATE_VISIBILITY.equals(newVisibility)) { + for (PsiElement element : elements) { + if (element != null) { + escalateVisibility(member, element); + } + } + } + else { + setVisibility(member.getModifierList(), newVisibility); + } + } - public static void fixVisibility(PsiExpression[] expressions, PsiMember member, String newVisibility) { - if (newVisibility == null) { - return; + public static void setVisibility( + PsiModifierList modifierList, + @PsiModifier.ModifierConstant String newVisibility + ) throws IncorrectOperationException { + modifierList.setModifierProperty(newVisibility, true); } - if (ESCALATE_VISIBILITY.equals(newVisibility)) { - for (PsiExpression element : expressions) { - escalateVisibility(member, element); - } - } else { - setVisibility(member.getModifierList(), newVisibility); + + public static void fixVisibility(PsiExpression[] expressions, PsiMember member, String newVisibility) { + if (newVisibility == null) { + return; + } + if (ESCALATE_VISIBILITY.equals(newVisibility)) { + for (PsiExpression element : expressions) { + escalateVisibility(member, element); + } + } + else { + setVisibility(member.getModifierList(), newVisibility); + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java index 2c778c0f46..5e174c3ab0 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java @@ -42,11 +42,12 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; import consulo.util.dataholder.Key; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -56,323 +57,366 @@ * @author dsl */ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = - Logger.getInstance(ConvertToInstanceMethodProcessor.class); - private PsiMethod myMethod; - private PsiParameter myTargetParameter; - private PsiClass myTargetClass; - private Map myTypeParameterReplacements; - private static final Key BIND_TO_TYPE_PARAMETER = Key.create("REPLACEMENT"); - private final String myOldVisibility; - private final String myNewVisibility; - - - public ConvertToInstanceMethodProcessor(final Project project, - final PsiMethod method, - final PsiParameter targetParameter, - final String newVisibility) { - super(project); - myMethod = method; - myTargetParameter = targetParameter; - LOG.assertTrue(method.hasModifierProperty(PsiModifier.STATIC)); - LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod); - LOG.assertTrue(myTargetParameter.getType() instanceof PsiClassType); - final PsiType type = myTargetParameter.getType(); - LOG.assertTrue(type instanceof PsiClassType); - myTargetClass = ((PsiClassType) type).resolve(); - myOldVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList()); - myNewVisibility = newVisibility; - } - - public PsiClass getTargetClass() { - return myTargetClass; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new MoveInstanceMethodViewDescriptor(myMethod, myTargetParameter, myTargetClass); - } - - protected void refreshElements(PsiElement[] elements) { - LOG.assertTrue(elements.length == 3); - myMethod = (PsiMethod) elements[0]; - myTargetParameter = (PsiParameter) elements[1]; - myTargetClass = (PsiClass) elements[2]; - } - - @Nonnull - protected UsageInfo[] findUsages() { - LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod); - final Project project = myMethod.getProject(); - - final PsiReference[] methodReferences = - ReferencesSearch.search(myMethod, GlobalSearchScope.projectScope(project), false).toArray(new PsiReference[0]); - List result = new ArrayList(); - for (final PsiReference ref : methodReferences) { - final PsiElement element = ref.getElement(); - if (element instanceof PsiReferenceExpression) { - if (element.getParent() instanceof PsiMethodCallExpression) { - result.add(new MethodCallUsageInfo((PsiMethodCallExpression) element.getParent())); - } - } else if (element instanceof PsiDocTagValue) { - result.add(new JavaDocUsageInfo(ref)); //TODO:!!! - } + private static final Logger LOG = Logger.getInstance(ConvertToInstanceMethodProcessor.class); + private PsiMethod myMethod; + private PsiParameter myTargetParameter; + private PsiClass myTargetClass; + private Map myTypeParameterReplacements; + private static final Key BIND_TO_TYPE_PARAMETER = Key.create("REPLACEMENT"); + private final String myOldVisibility; + private final String myNewVisibility; + + public ConvertToInstanceMethodProcessor( + final Project project, + final PsiMethod method, + final PsiParameter targetParameter, + final String newVisibility + ) { + super(project); + myMethod = method; + myTargetParameter = targetParameter; + LOG.assertTrue(method.hasModifierProperty(PsiModifier.STATIC)); + LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod); + LOG.assertTrue(myTargetParameter.getType() instanceof PsiClassType); + final PsiType type = myTargetParameter.getType(); + LOG.assertTrue(type instanceof PsiClassType); + myTargetClass = ((PsiClassType)type).resolve(); + myOldVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList()); + myNewVisibility = newVisibility; } - for (final PsiReference ref : ReferencesSearch.search(myTargetParameter, new LocalSearchScope(myMethod), false)) { - final PsiElement element = ref.getElement(); - if (element instanceof PsiReferenceExpression || element instanceof PsiDocParamRef) { - result.add(new ParameterUsageInfo(ref)); - } + public PsiClass getTargetClass() { + return myTargetClass; } - if (myTargetClass.isInterface()) { - PsiClass[] implementingClasses = RefactoringHierarchyUtil.findImplementingClasses(myTargetClass); - for (final PsiClass implementingClass : implementingClasses) { - result.add(new ImplementingClassUsageInfo(implementingClass)); - } + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new MoveInstanceMethodViewDescriptor(myMethod, myTargetParameter, myTargetClass); } + protected void refreshElements(PsiElement[] elements) { + LOG.assertTrue(elements.length == 3); + myMethod = (PsiMethod)elements[0]; + myTargetParameter = (PsiParameter)elements[1]; + myTargetClass = (PsiClass)elements[2]; + } - return result.toArray(new UsageInfo[result.size()]); - } + @Nonnull + protected UsageInfo[] findUsages() { + LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod); + final Project project = myMethod.getProject(); + + final PsiReference[] methodReferences = + ReferencesSearch.search(myMethod, GlobalSearchScope.projectScope(project), false).toArray(new PsiReference[0]); + List result = new ArrayList(); + for (final PsiReference ref : methodReferences) { + final PsiElement element = ref.getElement(); + if (element instanceof PsiReferenceExpression) { + if (element.getParent() instanceof PsiMethodCallExpression) { + result.add(new MethodCallUsageInfo((PsiMethodCallExpression)element.getParent())); + } + } + else if (element instanceof PsiDocTagValue) { + result.add(new JavaDocUsageInfo(ref)); //TODO:!!! + } + } + for (final PsiReference ref : ReferencesSearch.search(myTargetParameter, new LocalSearchScope(myMethod), false)) { + final PsiElement element = ref.getElement(); + if (element instanceof PsiReferenceExpression || element instanceof PsiDocParamRef) { + result.add(new ParameterUsageInfo(ref)); + } + } - protected boolean preprocessUsages(Ref refUsages) { - UsageInfo[] usagesIn = refUsages.get(); - MultiMap conflicts = new MultiMap(); - final Set methods = Collections.singleton((PsiMember) myMethod); - if (!myTargetClass.isInterface()) { - RefactoringConflictsUtil.analyzeAccessibilityConflicts(methods, myTargetClass, conflicts, myNewVisibility); - } else { - for (final UsageInfo usage : usagesIn) { - if (usage instanceof ImplementingClassUsageInfo) { - RefactoringConflictsUtil - .analyzeAccessibilityConflicts(methods, ((ImplementingClassUsageInfo) usage).getPsiClass(), conflicts, PsiModifier.PUBLIC); + if (myTargetClass.isInterface()) { + PsiClass[] implementingClasses = RefactoringHierarchyUtil.findImplementingClasses(myTargetClass); + for (final PsiClass implementingClass : implementingClasses) { + result.add(new ImplementingClassUsageInfo(implementingClass)); + } } - } + + return result.toArray(new UsageInfo[result.size()]); } - for (final UsageInfo usageInfo : usagesIn) { - if (usageInfo instanceof MethodCallUsageInfo) { - final PsiMethodCallExpression methodCall = ((MethodCallUsageInfo) usageInfo).getMethodCall(); - final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions(); - final int index = myMethod.getParameterList().getParameterIndex(myTargetParameter); - if (index < expressions.length) { - PsiExpression instanceValue = expressions[index]; - instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); - if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression) instanceValue).getValue() == null) { - LocalizeValue message = RefactoringLocalize.zeroContainsCallWithNullArgumentForParameter1( - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true), - CommonRefactoringUtil.htmlEmphasize(myTargetParameter.getName())); - conflicts.putValue(methodCall, message.get()); - } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + UsageInfo[] usagesIn = refUsages.get(); + MultiMap conflicts = new MultiMap(); + final Set methods = Collections.singleton((PsiMember)myMethod); + if (!myTargetClass.isInterface()) { + RefactoringConflictsUtil.analyzeAccessibilityConflicts(methods, myTargetClass, conflicts, myNewVisibility); + } + else { + for (final UsageInfo usage : usagesIn) { + if (usage instanceof ImplementingClassUsageInfo) { + RefactoringConflictsUtil.analyzeAccessibilityConflicts( + methods, + ((ImplementingClassUsageInfo)usage).getPsiClass(), + conflicts, + PsiModifier.PUBLIC + ); + } + } } - } - } - return showConflicts(conflicts, usagesIn); - } + for (final UsageInfo usageInfo : usagesIn) { + if (usageInfo instanceof MethodCallUsageInfo) { + final PsiMethodCallExpression methodCall = ((MethodCallUsageInfo)usageInfo).getMethodCall(); + final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions(); + final int index = myMethod.getParameterList().getParameterIndex(myTargetParameter); + if (index < expressions.length) { + PsiExpression instanceValue = expressions[index]; + instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); + if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression)instanceValue).getValue() == null) { + LocalizeValue message = RefactoringLocalize.zeroContainsCallWithNullArgumentForParameter1( + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true), + CommonRefactoringUtil.htmlEmphasize(myTargetParameter.getName()) + ); + conflicts.putValue(methodCall, message.get()); + } + } + } + } - protected void performRefactoring(UsageInfo[] usages) { - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myTargetClass)) return; - LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); - try { - doRefactoring(usages); - } catch (IncorrectOperationException e) { - LOG.error(e); - } finally { - a.finish(); + return showConflicts(conflicts, usagesIn); } - } - private void doRefactoring(UsageInfo[] usages) throws IncorrectOperationException { - myTypeParameterReplacements = buildTypeParameterReplacements(); - List inheritors = new ArrayList(); + protected void performRefactoring(UsageInfo[] usages) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myTargetClass)) { + return; + } + LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); + try { + doRefactoring(usages); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + finally { + a.finish(); + } + } - CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); + private void doRefactoring(UsageInfo[] usages) throws IncorrectOperationException { + myTypeParameterReplacements = buildTypeParameterReplacements(); + List inheritors = new ArrayList(); - // Process usages - for (final UsageInfo usage : usages) { - if (usage instanceof MethodCallUsageInfo) { - processMethodCall((MethodCallUsageInfo) usage); - } else if (usage instanceof ParameterUsageInfo) { - processParameterUsage((ParameterUsageInfo) usage); - } else if (usage instanceof ImplementingClassUsageInfo) { - inheritors.add(((ImplementingClassUsageInfo) usage).getPsiClass()); - } - } + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); - prepareTypeParameterReplacement(); - myTargetParameter.delete(); - ChangeContextUtil.encodeContextInfo(myMethod, true); - if (!myTargetClass.isInterface()) { - PsiMethod method = addMethodToClass(myTargetClass); - fixVisibility(method, usages); - } else { - final PsiMethod interfaceMethod = addMethodToClass(myTargetClass); - final PsiModifierList modifierList = interfaceMethod.getModifierList(); - modifierList.setModifierProperty(PsiModifier.PRIVATE, false); - modifierList.setModifierProperty(PsiModifier.PUBLIC, false); - modifierList.setModifierProperty(PsiModifier.PROTECTED, false); - RefactoringUtil.makeMethodAbstract(myTargetClass, interfaceMethod); + // Process usages + for (final UsageInfo usage : usages) { + if (usage instanceof MethodCallUsageInfo) { + processMethodCall((MethodCallUsageInfo)usage); + } + else if (usage instanceof ParameterUsageInfo) { + processParameterUsage((ParameterUsageInfo)usage); + } + else if (usage instanceof ImplementingClassUsageInfo) { + inheritors.add(((ImplementingClassUsageInfo)usage).getPsiClass()); + } + } - for (final PsiClass psiClass : inheritors) { - final PsiMethod newMethod = addMethodToClass(psiClass); - PsiUtil.setModifierProperty(newMethod, myNewVisibility != null && !myNewVisibility.equals(VisibilityUtil.ESCALATE_VISIBILITY) ? myNewVisibility - : PsiModifier.PUBLIC, true); - } + prepareTypeParameterReplacement(); + myTargetParameter.delete(); + ChangeContextUtil.encodeContextInfo(myMethod, true); + if (!myTargetClass.isInterface()) { + PsiMethod method = addMethodToClass(myTargetClass); + fixVisibility(method, usages); + } + else { + final PsiMethod interfaceMethod = addMethodToClass(myTargetClass); + final PsiModifierList modifierList = interfaceMethod.getModifierList(); + modifierList.setModifierProperty(PsiModifier.PRIVATE, false); + modifierList.setModifierProperty(PsiModifier.PUBLIC, false); + modifierList.setModifierProperty(PsiModifier.PROTECTED, false); + RefactoringUtil.makeMethodAbstract(myTargetClass, interfaceMethod); + + for (final PsiClass psiClass : inheritors) { + final PsiMethod newMethod = addMethodToClass(psiClass); + PsiUtil.setModifierProperty( + newMethod, + myNewVisibility != null && !myNewVisibility.equals(VisibilityUtil.ESCALATE_VISIBILITY) ? myNewVisibility + : PsiModifier.PUBLIC, + true + ); + } + } + myMethod.delete(); } - myMethod.delete(); - } - private void fixVisibility(final PsiMethod method, final UsageInfo[] usages) throws IncorrectOperationException { - final PsiModifierList modifierList = method.getModifierList(); - if (VisibilityUtil.ESCALATE_VISIBILITY.equals(myNewVisibility)) { - for (UsageInfo usage : usages) { - if (usage instanceof MethodCallUsageInfo) { - final PsiElement place = usage.getElement(); - if (place != null) { - VisibilityUtil.escalateVisibility(method, place); - } + private void fixVisibility(final PsiMethod method, final UsageInfo[] usages) throws IncorrectOperationException { + final PsiModifierList modifierList = method.getModifierList(); + if (VisibilityUtil.ESCALATE_VISIBILITY.equals(myNewVisibility)) { + for (UsageInfo usage : usages) { + if (usage instanceof MethodCallUsageInfo) { + final PsiElement place = usage.getElement(); + if (place != null) { + VisibilityUtil.escalateVisibility(method, place); + } + } + } + } + else if (myNewVisibility != null && !myNewVisibility.equals(myOldVisibility)) { + modifierList.setModifierProperty(myNewVisibility, true); } - } - } else if (myNewVisibility != null && !myNewVisibility.equals(myOldVisibility)) { - modifierList.setModifierProperty(myNewVisibility, true); } - } - private void prepareTypeParameterReplacement() throws IncorrectOperationException { - if (myTypeParameterReplacements == null) return; - final Collection typeParameters = myTypeParameterReplacements.keySet(); - for (final PsiTypeParameter parameter : typeParameters) { - for (final PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(myMethod), false)) { - if (reference.getElement() instanceof PsiJavaCodeReferenceElement) { - reference.getElement().putCopyableUserData(BIND_TO_TYPE_PARAMETER, myTypeParameterReplacements.get(parameter)); + private void prepareTypeParameterReplacement() throws IncorrectOperationException { + if (myTypeParameterReplacements == null) { + return; + } + final Collection typeParameters = myTypeParameterReplacements.keySet(); + for (final PsiTypeParameter parameter : typeParameters) { + for (final PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(myMethod), false)) { + if (reference.getElement() instanceof PsiJavaCodeReferenceElement) { + reference.getElement().putCopyableUserData(BIND_TO_TYPE_PARAMETER, myTypeParameterReplacements.get(parameter)); + } + } + } + final Set methodTypeParameters = myTypeParameterReplacements.keySet(); + for (final PsiTypeParameter methodTypeParameter : methodTypeParameters) { + methodTypeParameter.delete(); } - } - } - final Set methodTypeParameters = myTypeParameterReplacements.keySet(); - for (final PsiTypeParameter methodTypeParameter : methodTypeParameters) { - methodTypeParameter.delete(); } - } - private PsiMethod addMethodToClass(final PsiClass targetClass) throws IncorrectOperationException { - final PsiMethod newMethod = (PsiMethod) targetClass.add(myMethod); - final PsiModifierList modifierList = newMethod.getModifierList(); - modifierList.setModifierProperty(PsiModifier.STATIC, false); - ChangeContextUtil.decodeContextInfo(newMethod, null, null); - if (myTypeParameterReplacements == null) return newMethod; - final Map additionalReplacements; - if (targetClass != myTargetClass) { - final PsiSubstitutor superClassSubstitutor = - TypeConversionUtil.getSuperClassSubstitutor(myTargetClass, targetClass, PsiSubstitutor.EMPTY); - final Map map = calculateReplacementMap(superClassSubstitutor, myTargetClass, targetClass); - if (map == null) return newMethod; - additionalReplacements = new HashMap(); - for (final Map.Entry entry : map.entrySet()) { - additionalReplacements.put(entry.getValue(), entry.getKey()); - } - } else { - additionalReplacements = null; - } - newMethod.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - PsiTypeParameter typeParameterToBind = reference.getCopyableUserData(BIND_TO_TYPE_PARAMETER); - if (typeParameterToBind != null) { - reference.putCopyableUserData(BIND_TO_TYPE_PARAMETER, null); - try { - if (additionalReplacements != null) { - typeParameterToBind = additionalReplacements.get(typeParameterToBind); + private PsiMethod addMethodToClass(final PsiClass targetClass) throws IncorrectOperationException { + final PsiMethod newMethod = (PsiMethod)targetClass.add(myMethod); + final PsiModifierList modifierList = newMethod.getModifierList(); + modifierList.setModifierProperty(PsiModifier.STATIC, false); + ChangeContextUtil.decodeContextInfo(newMethod, null, null); + if (myTypeParameterReplacements == null) { + return newMethod; + } + final Map additionalReplacements; + if (targetClass != myTargetClass) { + final PsiSubstitutor superClassSubstitutor = + TypeConversionUtil.getSuperClassSubstitutor(myTargetClass, targetClass, PsiSubstitutor.EMPTY); + final Map map = calculateReplacementMap(superClassSubstitutor, myTargetClass, targetClass); + if (map == null) { + return newMethod; + } + additionalReplacements = new HashMap(); + for (final Map.Entry entry : map.entrySet()) { + additionalReplacements.put(entry.getValue(), entry.getKey()); } - reference.bindToElement(typeParameterToBind); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } else { - visitElement(reference); } - } - }); - return newMethod; - } - - private void processParameterUsage(ParameterUsageInfo usage) throws IncorrectOperationException { - final PsiReference reference = usage.getReferenceExpression(); - if (reference instanceof PsiReferenceExpression) { - final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) reference; - if (referenceExpression.getParent() instanceof PsiReferenceExpression) { - // todo: check for correctness - referenceExpression.delete(); - } else { - final PsiExpression expression = - JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory().createExpressionFromText("this", null); - referenceExpression.replace(expression); - } - } else { - final PsiElement element = reference.getElement(); - if (element instanceof PsiDocParamRef) { - element.getParent().delete(); - } + else { + additionalReplacements = null; + } + newMethod.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + PsiTypeParameter typeParameterToBind = reference.getCopyableUserData(BIND_TO_TYPE_PARAMETER); + if (typeParameterToBind != null) { + reference.putCopyableUserData(BIND_TO_TYPE_PARAMETER, null); + try { + if (additionalReplacements != null) { + typeParameterToBind = additionalReplacements.get(typeParameterToBind); + } + reference.bindToElement(typeParameterToBind); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + else { + visitElement(reference); + } + } + }); + return newMethod; } - } - private void processMethodCall(MethodCallUsageInfo usageInfo) throws IncorrectOperationException { - PsiMethodCallExpression methodCall = usageInfo.getMethodCall(); - PsiParameterList parameterList = myMethod.getParameterList(); - PsiElementFactory factory = JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory(); - int parameterIndex = parameterList.getParameterIndex(myTargetParameter); - PsiExpression[] arguments = methodCall.getArgumentList().getExpressions(); - if (arguments.length <= parameterIndex) return; - final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); - final PsiExpression qualifier; - if (methodExpression.getQualifierExpression() != null) { - qualifier = methodExpression.getQualifierExpression(); - } else { - final PsiReferenceExpression newRefExpr = (PsiReferenceExpression) factory.createExpressionFromText("x." + myMethod.getName(), null); - qualifier = ((PsiReferenceExpression) methodExpression.replace(newRefExpr)).getQualifierExpression(); + private void processParameterUsage(ParameterUsageInfo usage) throws IncorrectOperationException { + final PsiReference reference = usage.getReferenceExpression(); + if (reference instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)reference; + if (referenceExpression.getParent() instanceof PsiReferenceExpression) { + // todo: check for correctness + referenceExpression.delete(); + } + else { + final PsiExpression expression = + JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory().createExpressionFromText("this", null); + referenceExpression.replace(expression); + } + } + else { + final PsiElement element = reference.getElement(); + if (element instanceof PsiDocParamRef) { + element.getParent().delete(); + } + } } - qualifier.replace(arguments[parameterIndex]); - arguments[parameterIndex].delete(); - } - protected String getCommandName() { - return ConvertToInstanceMethodHandler.REFACTORING_NAME; - } + private void processMethodCall(MethodCallUsageInfo usageInfo) throws IncorrectOperationException { + PsiMethodCallExpression methodCall = usageInfo.getMethodCall(); + PsiParameterList parameterList = myMethod.getParameterList(); + PsiElementFactory factory = JavaPsiFacade.getInstance(myMethod.getProject()).getElementFactory(); + int parameterIndex = parameterList.getParameterIndex(myTargetParameter); + PsiExpression[] arguments = methodCall.getArgumentList().getExpressions(); + if (arguments.length <= parameterIndex) { + return; + } + final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); + final PsiExpression qualifier; + if (methodExpression.getQualifierExpression() != null) { + qualifier = methodExpression.getQualifierExpression(); + } + else { + final PsiReferenceExpression newRefExpr = + (PsiReferenceExpression)factory.createExpressionFromText("x." + myMethod.getName(), null); + qualifier = ((PsiReferenceExpression)methodExpression.replace(newRefExpr)).getQualifierExpression(); + } + qualifier.replace(arguments[parameterIndex]); + arguments[parameterIndex].delete(); + } - @Nullable - public Map buildTypeParameterReplacements() { - final PsiClassType type = (PsiClassType) myTargetParameter.getType(); - final PsiSubstitutor substitutor = type.resolveGenerics().getSubstitutor(); - return calculateReplacementMap(substitutor, myTargetClass, myMethod); - } + protected String getCommandName() { + return ConvertToInstanceMethodHandler.REFACTORING_NAME; + } - @Nullable - private static Map calculateReplacementMap(final PsiSubstitutor substitutor, - final PsiClass targetClass, - final PsiElement containingElement) { - final HashMap result = new HashMap(); - for (PsiTypeParameter classTypeParameter : PsiUtil.typeParametersIterable(targetClass)) { - final PsiType substitution = substitutor.substitute(classTypeParameter); - if (!(substitution instanceof PsiClassType)) return null; - final PsiClass aClass = ((PsiClassType) substitution).resolve(); - if (!(aClass instanceof PsiTypeParameter)) return null; - final PsiTypeParameter methodTypeParameter = (PsiTypeParameter) aClass; - if (methodTypeParameter.getOwner() != containingElement) return null; - if (result.keySet().contains(methodTypeParameter)) return null; - result.put(methodTypeParameter, classTypeParameter); + @Nullable + public Map buildTypeParameterReplacements() { + final PsiClassType type = (PsiClassType)myTargetParameter.getType(); + final PsiSubstitutor substitutor = type.resolveGenerics().getSubstitutor(); + return calculateReplacementMap(substitutor, myTargetClass, myMethod); } - return result; - } - public PsiMethod getMethod() { - return myMethod; - } + @Nullable + private static Map calculateReplacementMap( + final PsiSubstitutor substitutor, + final PsiClass targetClass, + final PsiElement containingElement + ) { + final HashMap result = new HashMap(); + for (PsiTypeParameter classTypeParameter : PsiUtil.typeParametersIterable(targetClass)) { + final PsiType substitution = substitutor.substitute(classTypeParameter); + if (!(substitution instanceof PsiClassType)) { + return null; + } + final PsiClass aClass = ((PsiClassType)substitution).resolve(); + if (!(aClass instanceof PsiTypeParameter)) { + return null; + } + final PsiTypeParameter methodTypeParameter = (PsiTypeParameter)aClass; + if (methodTypeParameter.getOwner() != containingElement) { + return null; + } + if (result.keySet().contains(methodTypeParameter)) { + return null; + } + result.put(methodTypeParameter, classTypeParameter); + } + return result; + } - public PsiParameter getTargetParameter() { - return myTargetParameter; - } + public PsiMethod getMethod() { + return myMethod; + } + public PsiParameter getTargetParameter() { + return myTargetParameter; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java index fd0bcaea63..997827f107 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java @@ -1,4 +1,3 @@ - /* * Copyright 2000-2013 JetBrains s.r.o. * @@ -44,291 +43,310 @@ import consulo.usage.UsageViewUtil; import consulo.util.collection.ContainerUtil; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.*; public class EncapsulateFieldsProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(EncapsulateFieldsProcessor.class); - - private PsiClass myClass; - @Nonnull - private final EncapsulateFieldsDescriptor myDescriptor; - private final FieldDescriptor[] myFieldDescriptors; - - private HashMap myNameToGetter; - private HashMap myNameToSetter; - - public EncapsulateFieldsProcessor(Project project, @Nonnull EncapsulateFieldsDescriptor descriptor) { - super(project); - myDescriptor = descriptor; - myFieldDescriptors = descriptor.getSelectedFields(); - myClass = descriptor.getTargetClass(); - } - - public static void setNewFieldVisibility(PsiField field, EncapsulateFieldsDescriptor descriptor) { - try { - if (descriptor.getFieldsVisibility() != null) { - field.normalizeDeclaration(); - PsiUtil.setModifierProperty(field, descriptor.getFieldsVisibility(), true); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); + private static final Logger LOG = Logger.getInstance(EncapsulateFieldsProcessor.class); + + private PsiClass myClass; + @Nonnull + private final EncapsulateFieldsDescriptor myDescriptor; + private final FieldDescriptor[] myFieldDescriptors; + + private HashMap myNameToGetter; + private HashMap myNameToSetter; + + public EncapsulateFieldsProcessor(Project project, @Nonnull EncapsulateFieldsDescriptor descriptor) { + super(project); + myDescriptor = descriptor; + myFieldDescriptors = descriptor.getSelectedFields(); + myClass = descriptor.getTargetClass(); } - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - FieldDescriptor[] fields = new FieldDescriptor[myFieldDescriptors.length]; - System.arraycopy(myFieldDescriptors, 0, fields, 0, myFieldDescriptors.length); - return new EncapsulateFieldsViewDescriptor(fields); - } - - protected String getCommandName() { - return RefactoringLocalize.encapsulateFieldsCommandName(DescriptiveNameUtil.getDescriptiveName(myClass)).get(); - } - - protected boolean preprocessUsages(Ref refUsages) { - final MultiMap conflicts = new MultiMap(); - - checkExistingMethods(conflicts, true); - checkExistingMethods(conflicts, false); - final Collection classes = ClassInheritorsSearch.search(myClass).findAll(); - for (FieldDescriptor fieldDescriptor : myFieldDescriptors) { - final Set setters = new HashSet(); - final Set getters = new HashSet(); - - for (PsiClass aClass : classes) { - final PsiMethod getterOverrider = - myDescriptor.isToEncapsulateGet() ? aClass.findMethodBySignature(fieldDescriptor.getGetterPrototype(), false) : null; - if (getterOverrider != null) { - getters.add(getterOverrider); - } - final PsiMethod setterOverrider = - myDescriptor.isToEncapsulateSet() ? aClass.findMethodBySignature(fieldDescriptor.getSetterPrototype(), false) : null; - if (setterOverrider != null) { - setters.add(setterOverrider); - } - } - if (!getters.isEmpty() || !setters.isEmpty()) { - final PsiField field = fieldDescriptor.getField(); - for (PsiReference reference : ReferencesSearch.search(field)) { - final PsiElement place = reference.getElement(); - LOG.assertTrue(place instanceof PsiReferenceExpression); - final PsiExpression qualifierExpression = ((PsiReferenceExpression)place).getQualifierExpression(); - final PsiClass ancestor; - if (qualifierExpression == null) { - ancestor = PsiTreeUtil.getParentOfType(place, PsiClass.class, false); - } - else { - ancestor = PsiUtil.resolveClassInType(qualifierExpression.getType()); - } - - final boolean isGetter = !PsiUtil.isAccessedForWriting((PsiExpression)place); - for (PsiMethod overridden : isGetter ? getters : setters) { - if (InheritanceUtil.isInheritorOrSelf(myClass, ancestor, true)) { - conflicts.putValue(overridden, "There is already a " + - RefactoringUIUtil.getDescription(overridden, true) + - " which would hide generated " + - (isGetter ? "getter" : "setter") + " for " + place.getText()); - break; + + public static void setNewFieldVisibility(PsiField field, EncapsulateFieldsDescriptor descriptor) { + try { + if (descriptor.getFieldsVisibility() != null) { + field.normalizeDeclaration(); + PsiUtil.setModifierProperty(field, descriptor.getFieldsVisibility(), true); } - } } - } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - return showConflicts(conflicts, refUsages.get()); - } - private void checkExistingMethods(MultiMap conflicts, boolean isGetter) { - if (isGetter) { - if (!myDescriptor.isToEncapsulateGet()) return; + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + FieldDescriptor[] fields = new FieldDescriptor[myFieldDescriptors.length]; + System.arraycopy(myFieldDescriptors, 0, fields, 0, myFieldDescriptors.length); + return new EncapsulateFieldsViewDescriptor(fields); } - else { - if (!myDescriptor.isToEncapsulateSet()) return; + + protected String getCommandName() { + return RefactoringLocalize.encapsulateFieldsCommandName(DescriptiveNameUtil.getDescriptiveName(myClass)).get(); } - for (FieldDescriptor descriptor : myFieldDescriptors) { - PsiMethod prototype = isGetter - ? descriptor.getGetterPrototype() - : descriptor.getSetterPrototype(); - - final PsiType prototypeReturnType = prototype.getReturnType(); - PsiMethod existing = myClass.findMethodBySignature(prototype, true); - if (existing != null) { - final PsiType returnType = existing.getReturnType(); - if (!RefactoringUtil.equivalentTypes(prototypeReturnType, returnType, myClass.getManager())) { - final String descr = PsiFormatUtil.formatMethod(existing, - PsiSubstitutor.EMPTY, - PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS | PsiFormatUtilBase.SHOW_TYPE, - PsiFormatUtilBase.SHOW_TYPE - ); - LocalizeValue message = isGetter - ? RefactoringLocalize.encapsulateFieldsGetterExists( - CommonRefactoringUtil.htmlEmphasize(descr), - CommonRefactoringUtil.htmlEmphasize(prototype.getName()) - ) - : RefactoringLocalize.encapsulateFieldsSetterExists( - CommonRefactoringUtil.htmlEmphasize(descr), - CommonRefactoringUtil.htmlEmphasize(prototype.getName()) - ); - conflicts.putValue(existing, message.get()); + @Override + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + final MultiMap conflicts = new MultiMap(); + + checkExistingMethods(conflicts, true); + checkExistingMethods(conflicts, false); + final Collection classes = ClassInheritorsSearch.search(myClass).findAll(); + for (FieldDescriptor fieldDescriptor : myFieldDescriptors) { + final Set setters = new HashSet(); + final Set getters = new HashSet(); + + for (PsiClass aClass : classes) { + final PsiMethod getterOverrider = + myDescriptor.isToEncapsulateGet() ? aClass.findMethodBySignature(fieldDescriptor.getGetterPrototype(), false) : null; + if (getterOverrider != null) { + getters.add(getterOverrider); + } + final PsiMethod setterOverrider = + myDescriptor.isToEncapsulateSet() ? aClass.findMethodBySignature(fieldDescriptor.getSetterPrototype(), false) : null; + if (setterOverrider != null) { + setters.add(setterOverrider); + } + } + if (!getters.isEmpty() || !setters.isEmpty()) { + final PsiField field = fieldDescriptor.getField(); + for (PsiReference reference : ReferencesSearch.search(field)) { + final PsiElement place = reference.getElement(); + LOG.assertTrue(place instanceof PsiReferenceExpression); + final PsiExpression qualifierExpression = ((PsiReferenceExpression)place).getQualifierExpression(); + final PsiClass ancestor; + if (qualifierExpression == null) { + ancestor = PsiTreeUtil.getParentOfType(place, PsiClass.class, false); + } + else { + ancestor = PsiUtil.resolveClassInType(qualifierExpression.getType()); + } + + final boolean isGetter = !PsiUtil.isAccessedForWriting((PsiExpression)place); + for (PsiMethod overridden : isGetter ? getters : setters) { + if (InheritanceUtil.isInheritorOrSelf(myClass, ancestor, true)) { + conflicts.putValue(overridden, "There is already a " + + RefactoringUIUtil.getDescription(overridden, true) + + " which would hide generated " + + (isGetter ? "getter" : "setter") + " for " + place.getText()); + break; + } + } + } + } } - } else { - PsiClass containingClass = myClass.getContainingClass(); - while (containingClass != null && existing == null) { - existing = containingClass.findMethodBySignature(prototype, true); - if (existing != null) { - for (PsiReference reference : ReferencesSearch.search(existing)) { - final PsiElement place = reference.getElement(); - LOG.assertTrue(place instanceof PsiReferenceExpression); - final PsiExpression qualifierExpression = ((PsiReferenceExpression)place).getQualifierExpression(); - final PsiClass inheritor; - if (qualifierExpression == null) { - inheritor = PsiTreeUtil.getParentOfType(place, PsiClass.class, false); - } else { - inheritor = PsiUtil.resolveClassInType(qualifierExpression.getType()); - } - - if (InheritanceUtil.isInheritorOrSelf(inheritor, myClass, true)) { - conflicts.putValue(existing, "There is already a " + RefactoringUIUtil.getDescription(existing, true) + " which would be hidden by generated " + (isGetter ? "getter" : "setter")); - break; - } + return showConflicts(conflicts, refUsages.get()); + } + + private void checkExistingMethods(MultiMap conflicts, boolean isGetter) { + if (isGetter) { + if (!myDescriptor.isToEncapsulateGet()) { + return; + } + } + else if (!myDescriptor.isToEncapsulateSet()) { + return; + } + + for (FieldDescriptor descriptor : myFieldDescriptors) { + PsiMethod prototype = isGetter + ? descriptor.getGetterPrototype() + : descriptor.getSetterPrototype(); + + final PsiType prototypeReturnType = prototype.getReturnType(); + PsiMethod existing = myClass.findMethodBySignature(prototype, true); + if (existing != null) { + final PsiType returnType = existing.getReturnType(); + if (!RefactoringUtil.equivalentTypes(prototypeReturnType, returnType, myClass.getManager())) { + final String descr = PsiFormatUtil.formatMethod( + existing, + PsiSubstitutor.EMPTY, + PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS | PsiFormatUtilBase.SHOW_TYPE, + PsiFormatUtilBase.SHOW_TYPE + ); + LocalizeValue message = isGetter + ? RefactoringLocalize.encapsulateFieldsGetterExists( + CommonRefactoringUtil.htmlEmphasize(descr), + CommonRefactoringUtil.htmlEmphasize(prototype.getName()) + ) + : RefactoringLocalize.encapsulateFieldsSetterExists( + CommonRefactoringUtil.htmlEmphasize(descr), + CommonRefactoringUtil.htmlEmphasize(prototype.getName()) + ); + conflicts.putValue(existing, message.get()); + } + } + else { + PsiClass containingClass = myClass.getContainingClass(); + while (containingClass != null && existing == null) { + existing = containingClass.findMethodBySignature(prototype, true); + if (existing != null) { + for (PsiReference reference : ReferencesSearch.search(existing)) { + final PsiElement place = reference.getElement(); + LOG.assertTrue(place instanceof PsiReferenceExpression); + final PsiExpression qualifierExpression = ((PsiReferenceExpression)place).getQualifierExpression(); + final PsiClass inheritor; + if (qualifierExpression == null) { + inheritor = PsiTreeUtil.getParentOfType(place, PsiClass.class, false); + } + else { + inheritor = PsiUtil.resolveClassInType(qualifierExpression.getType()); + } + + if (InheritanceUtil.isInheritorOrSelf(inheritor, myClass, true)) { + conflicts.putValue( + existing, + "There is already a " + RefactoringUIUtil.getDescription( + existing, + true + ) + " which would be hidden by generated " + (isGetter ? "getter" : "setter") + ); + break; + } + } + } + containingClass = containingClass.getContainingClass(); + } } - } - containingClass = containingClass.getContainingClass(); } - } } - } - - @Nonnull - protected UsageInfo[] findUsages() { - ArrayList array = ContainerUtil.newArrayList(); - for (FieldDescriptor fieldDescriptor : myFieldDescriptors) { - for (final PsiReference reference : ReferencesSearch.search(fieldDescriptor.getField())) { - final PsiElement element = reference.getElement(); - if (element == null) continue; - - final EncapsulateFieldHelper helper = EncapsulateFieldHelper.getHelper(element.getLanguage()); - EncapsulateFieldUsageInfo usageInfo = helper.createUsage(myDescriptor, fieldDescriptor, reference); - if (usageInfo != null) { - array.add(usageInfo); + + @Nonnull + protected UsageInfo[] findUsages() { + ArrayList array = ContainerUtil.newArrayList(); + for (FieldDescriptor fieldDescriptor : myFieldDescriptors) { + for (final PsiReference reference : ReferencesSearch.search(fieldDescriptor.getField())) { + final PsiElement element = reference.getElement(); + if (element == null) { + continue; + } + + final EncapsulateFieldHelper helper = EncapsulateFieldHelper.getHelper(element.getLanguage()); + EncapsulateFieldUsageInfo usageInfo = helper.createUsage(myDescriptor, fieldDescriptor, reference); + if (usageInfo != null) { + array.add(usageInfo); + } + } } - } + EncapsulateFieldUsageInfo[] usageInfos = array.toArray(new EncapsulateFieldUsageInfo[array.size()]); + return UsageViewUtil.removeDuplicatedUsages(usageInfos); } - EncapsulateFieldUsageInfo[] usageInfos = array.toArray(new EncapsulateFieldUsageInfo[array.size()]); - return UsageViewUtil.removeDuplicatedUsages(usageInfos); - } - protected void refreshElements(PsiElement[] elements) { - LOG.assertTrue(elements.length == myFieldDescriptors.length); + protected void refreshElements(PsiElement[] elements) { + LOG.assertTrue(elements.length == myFieldDescriptors.length); - for (int idx = 0; idx < elements.length; idx++) { - PsiElement element = elements[idx]; + for (int idx = 0; idx < elements.length; idx++) { + PsiElement element = elements[idx]; - LOG.assertTrue(element instanceof PsiField); + LOG.assertTrue(element instanceof PsiField); - myFieldDescriptors[idx].refreshField((PsiField)element); - } + myFieldDescriptors[idx].refreshField((PsiField)element); + } - myClass = myFieldDescriptors[0].getField().getContainingClass(); - } + myClass = myFieldDescriptors[0].getField().getContainingClass(); + } - protected void performRefactoring(UsageInfo[] usages) { - updateFieldVisibility(); - generateAccessors(); - processUsagesPerFile(usages); - } + protected void performRefactoring(UsageInfo[] usages) { + updateFieldVisibility(); + generateAccessors(); + processUsagesPerFile(usages); + } - private void updateFieldVisibility() { - if (myDescriptor.getFieldsVisibility() == null) return; + private void updateFieldVisibility() { + if (myDescriptor.getFieldsVisibility() == null) { + return; + } - for (FieldDescriptor descriptor : myFieldDescriptors) { - setNewFieldVisibility(descriptor.getField(), myDescriptor); - } - } - - private void generateAccessors() { - // generate accessors - myNameToGetter = new HashMap(); - myNameToSetter = new HashMap(); - - for (FieldDescriptor fieldDescriptor : myFieldDescriptors) { - final DocCommentPolicy commentPolicy = new DocCommentPolicy(myDescriptor.getJavadocPolicy()); - - PsiField field = fieldDescriptor.getField(); - final PsiDocComment docComment = field.getDocComment(); - if (myDescriptor.isToEncapsulateGet()) { - final PsiMethod prototype = fieldDescriptor.getGetterPrototype(); - assert prototype != null; - final PsiMethod getter = addOrChangeAccessor(prototype, myNameToGetter); - if (docComment != null) { - final PsiDocComment getterJavadoc = (PsiDocComment)getter.addBefore(docComment, getter.getFirstChild()); - commentPolicy.processNewJavaDoc(getterJavadoc); + for (FieldDescriptor descriptor : myFieldDescriptors) { + setNewFieldVisibility(descriptor.getField(), myDescriptor); } - } - if (myDescriptor.isToEncapsulateSet() && !field.hasModifierProperty(PsiModifier.FINAL)) { - PsiMethod prototype = fieldDescriptor.getSetterPrototype(); - assert prototype != null; - addOrChangeAccessor(prototype, myNameToSetter); - } - - if (docComment != null) { - commentPolicy.processOldJavaDoc(docComment); - } - } - } - - private void processUsagesPerFile(UsageInfo[] usages) { - Map> usagesInFiles = new HashMap>(); - for (UsageInfo usage : usages) { - PsiElement element = usage.getElement(); - if (element == null) continue; - final PsiFile file = element.getContainingFile(); - List usagesInFile = usagesInFiles.get(file); - if (usagesInFile == null) { - usagesInFile = new ArrayList(); - usagesInFiles.put(file, usagesInFile); - } - usagesInFile.add(((EncapsulateFieldUsageInfo)usage)); } - for (List usageInfos : usagesInFiles.values()) { - //this is to avoid elements to become invalid as a result of processUsage - final EncapsulateFieldUsageInfo[] infos = usageInfos.toArray(new EncapsulateFieldUsageInfo[usageInfos.size()]); - CommonRefactoringUtil.sortDepthFirstRightLeftOrder(infos); - - for (EncapsulateFieldUsageInfo info : infos) { - EncapsulateFieldHelper helper = EncapsulateFieldHelper.getHelper(info.getElement().getLanguage()); - helper.processUsage(info, - myDescriptor, - myNameToSetter.get(info.getFieldDescriptor().getSetterName()), - myNameToGetter.get(info.getFieldDescriptor().getGetterName()) - ); - } + private void generateAccessors() { + // generate accessors + myNameToGetter = new HashMap(); + myNameToSetter = new HashMap(); + + for (FieldDescriptor fieldDescriptor : myFieldDescriptors) { + final DocCommentPolicy commentPolicy = new DocCommentPolicy(myDescriptor.getJavadocPolicy()); + + PsiField field = fieldDescriptor.getField(); + final PsiDocComment docComment = field.getDocComment(); + if (myDescriptor.isToEncapsulateGet()) { + final PsiMethod prototype = fieldDescriptor.getGetterPrototype(); + assert prototype != null; + final PsiMethod getter = addOrChangeAccessor(prototype, myNameToGetter); + if (docComment != null) { + final PsiDocComment getterJavadoc = (PsiDocComment)getter.addBefore(docComment, getter.getFirstChild()); + commentPolicy.processNewJavaDoc(getterJavadoc); + } + } + if (myDescriptor.isToEncapsulateSet() && !field.hasModifierProperty(PsiModifier.FINAL)) { + PsiMethod prototype = fieldDescriptor.getSetterPrototype(); + assert prototype != null; + addOrChangeAccessor(prototype, myNameToSetter); + } + + if (docComment != null) { + commentPolicy.processOldJavaDoc(docComment); + } + } } - } - - private PsiMethod addOrChangeAccessor(PsiMethod prototype, HashMap nameToAncestor) { - PsiMethod existing = myClass.findMethodBySignature(prototype, false); - PsiMethod result = existing; - try{ - if (existing == null){ - PsiUtil.setModifierProperty(prototype, myDescriptor.getAccessorsVisibility(), true); - result = (PsiMethod) myClass.add(prototype); - } - else{ - //TODO : change visibility - } - nameToAncestor.put(prototype.getName(), result); - return result; + + private void processUsagesPerFile(UsageInfo[] usages) { + Map> usagesInFiles = new HashMap>(); + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element == null) { + continue; + } + final PsiFile file = element.getContainingFile(); + List usagesInFile = usagesInFiles.get(file); + if (usagesInFile == null) { + usagesInFile = new ArrayList(); + usagesInFiles.put(file, usagesInFile); + } + usagesInFile.add(((EncapsulateFieldUsageInfo)usage)); + } + + for (List usageInfos : usagesInFiles.values()) { + //this is to avoid elements to become invalid as a result of processUsage + final EncapsulateFieldUsageInfo[] infos = usageInfos.toArray(new EncapsulateFieldUsageInfo[usageInfos.size()]); + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(infos); + + for (EncapsulateFieldUsageInfo info : infos) { + EncapsulateFieldHelper helper = EncapsulateFieldHelper.getHelper(info.getElement().getLanguage()); + helper.processUsage( + info, + myDescriptor, + myNameToSetter.get(info.getFieldDescriptor().getSetterName()), + myNameToGetter.get(info.getFieldDescriptor().getGetterName()) + ); + } + } } - catch(IncorrectOperationException e){ - LOG.error(e); + + private PsiMethod addOrChangeAccessor(PsiMethod prototype, HashMap nameToAncestor) { + PsiMethod existing = myClass.findMethodBySignature(prototype, false); + PsiMethod result = existing; + try { + if (existing == null) { + PsiUtil.setModifierProperty(prototype, myDescriptor.getAccessorsVisibility(), true); + result = (PsiMethod)myClass.add(prototype); + } + else { + //TODO : change visibility + } + nameToAncestor.put(prototype.getName(), result); + return result; + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + return null; } - return null; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java index 8a847a56ce..43e9e8d45d 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/extractclass/ExtractClassProcessor.java @@ -173,7 +173,7 @@ public PsiClass getCreatedClass() { @Override @RequiredUIAccess - protected boolean preprocessUsages(@Nonnull final SimpleReference refUsages) { + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { final MultiMap conflicts = new MultiMap<>(); myExtractEnumProcessor.findEnumConstantConflicts(refUsages); if (!DestinationFolderComboBox.isAccessible( @@ -673,12 +673,12 @@ else if (RefactoringUtil.isAssignmentLHS(exp)) { isStatic ? new ReplaceStaticVariableAssignment(exp, qualifiedName) : new ReplaceInstanceVariableAssignment( - PsiTreeUtil.getParentOfType(exp, PsiAssignmentExpression.class), - delegateFieldName, - setter, - getter, - field.getName() - ) + PsiTreeUtil.getParentOfType(exp, PsiAssignmentExpression.class), + delegateFieldName, + setter, + getter, + field.getName() + ) ); } else { diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java index 8477649a13..4790363717 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java @@ -49,9 +49,10 @@ import consulo.logging.Logger; import consulo.project.Project; import consulo.project.ui.wm.WindowManager; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.*; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.jetbrains.annotations.NonNls; @@ -62,1175 +63,1217 @@ * @author dsl */ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(InheritanceToDelegationProcessor.class); - private final PsiClass myClass; - private final String myInnerClassName; - private final boolean myIsDelegateOtherMembers; - private final Set myDelegatedInterfaces; - private final Set myDelegatedMethods; - private final HashMap myDelegatedMethodsVisibility; - private final Set myOverriddenMethods; - - private final PsiClass myBaseClass; - private final Set myBaseClassMembers; - private final String myFieldName; - private final String myGetterName; - private final boolean myGenerateGetter; - private final Set myBaseClassBases; - private Set myClassImplementedInterfaces; - private final PsiElementFactory myFactory; - private final PsiClassType myBaseClassType; - private final PsiManager myManager; - private final boolean myIsInnerClassNeeded; - private Set myClassInheritors; - private HashSet myAbstractDelegatedMethods; - private final Map mySuperClassesToSubstitutors = new HashMap(); - - public InheritanceToDelegationProcessor( - Project project, - PsiClass aClass, - PsiClass targetBaseClass, - String fieldName, - String innerClassName, - PsiClass[] delegatedInterfaces, - PsiMethod[] delegatedMethods, - boolean delegateOtherMembers, - boolean generateGetter - ) { - super(project); - - myClass = aClass; - myInnerClassName = innerClassName; - myIsDelegateOtherMembers = delegateOtherMembers; - myManager = myClass.getManager(); - myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); - - myBaseClass = targetBaseClass; - LOG.assertTrue( - myBaseClass != null // && !myBaseClass.isInterface() - && (myBaseClass.getQualifiedName() == null || !myBaseClass.getQualifiedName().equals(CommonClassNames.JAVA_LANG_OBJECT)) - ); - myBaseClassMembers = getAllBaseClassMembers(); - myBaseClassBases = getAllBases(); - myBaseClassType = myFactory.createType(myBaseClass, getSuperSubstitutor(myBaseClass)); - - myIsInnerClassNeeded = InheritanceToDelegationUtil.isInnerClassNeeded(myClass, myBaseClass); - - - myFieldName = fieldName; - final String propertyName = JavaCodeStyleManager.getInstance(myProject).variableNameToPropertyName(myFieldName, VariableKind.FIELD); - myGetterName = PropertyUtil.suggestGetterName(propertyName, myBaseClassType); - myGenerateGetter = generateGetter; - - myDelegatedInterfaces = new LinkedHashSet(); - addAll(myDelegatedInterfaces, delegatedInterfaces); - myDelegatedMethods = new LinkedHashSet(); - addAll(myDelegatedMethods, delegatedMethods); - myDelegatedMethodsVisibility = new HashMap(); - for (PsiMethod method : myDelegatedMethods) { - MethodSignature signature = method.getSignature(getSuperSubstitutor(method.getContainingClass())); - PsiMethod overridingMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, false); - if (overridingMethod != null) { - myDelegatedMethodsVisibility.put(method, VisibilityUtil.getVisibilityModifier(overridingMethod.getModifierList())); - } - } - - myOverriddenMethods = getOverriddenMethods(); - } + private static final Logger LOG = Logger.getInstance(InheritanceToDelegationProcessor.class); + private final PsiClass myClass; + private final String myInnerClassName; + private final boolean myIsDelegateOtherMembers; + private final Set myDelegatedInterfaces; + private final Set myDelegatedMethods; + private final HashMap myDelegatedMethodsVisibility; + private final Set myOverriddenMethods; + + private final PsiClass myBaseClass; + private final Set myBaseClassMembers; + private final String myFieldName; + private final String myGetterName; + private final boolean myGenerateGetter; + private final Set myBaseClassBases; + private Set myClassImplementedInterfaces; + private final PsiElementFactory myFactory; + private final PsiClassType myBaseClassType; + private final PsiManager myManager; + private final boolean myIsInnerClassNeeded; + private Set myClassInheritors; + private HashSet myAbstractDelegatedMethods; + private final Map mySuperClassesToSubstitutors = new HashMap(); + + public InheritanceToDelegationProcessor( + Project project, + PsiClass aClass, + PsiClass targetBaseClass, + String fieldName, + String innerClassName, + PsiClass[] delegatedInterfaces, + PsiMethod[] delegatedMethods, + boolean delegateOtherMembers, + boolean generateGetter + ) { + super(project); + + myClass = aClass; + myInnerClassName = innerClassName; + myIsDelegateOtherMembers = delegateOtherMembers; + myManager = myClass.getManager(); + myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); + + myBaseClass = targetBaseClass; + LOG.assertTrue( + myBaseClass != null // && !myBaseClass.isInterface() + && (myBaseClass.getQualifiedName() == null || !myBaseClass.getQualifiedName().equals(CommonClassNames.JAVA_LANG_OBJECT)) + ); + myBaseClassMembers = getAllBaseClassMembers(); + myBaseClassBases = getAllBases(); + myBaseClassType = myFactory.createType(myBaseClass, getSuperSubstitutor(myBaseClass)); + + myIsInnerClassNeeded = InheritanceToDelegationUtil.isInnerClassNeeded(myClass, myBaseClass); + + + myFieldName = fieldName; + final String propertyName = JavaCodeStyleManager.getInstance(myProject).variableNameToPropertyName(myFieldName, VariableKind.FIELD); + myGetterName = PropertyUtil.suggestGetterName(propertyName, myBaseClassType); + myGenerateGetter = generateGetter; + + myDelegatedInterfaces = new LinkedHashSet(); + addAll(myDelegatedInterfaces, delegatedInterfaces); + myDelegatedMethods = new LinkedHashSet(); + addAll(myDelegatedMethods, delegatedMethods); + myDelegatedMethodsVisibility = new HashMap(); + for (PsiMethod method : myDelegatedMethods) { + MethodSignature signature = method.getSignature(getSuperSubstitutor(method.getContainingClass())); + PsiMethod overridingMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, false); + if (overridingMethod != null) { + myDelegatedMethodsVisibility.put(method, VisibilityUtil.getVisibilityModifier(overridingMethod.getModifierList())); + } + } - private PsiSubstitutor getSuperSubstitutor(final PsiClass superClass) { - PsiSubstitutor result = mySuperClassesToSubstitutors.get(superClass); - if (result == null) { - result = TypeConversionUtil.getSuperClassSubstitutor(superClass, myClass, PsiSubstitutor.EMPTY); - mySuperClassesToSubstitutors.put(superClass, result); + myOverriddenMethods = getOverriddenMethods(); } - return result; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new InheritanceToDelegationViewDescriptor(myClass); - } - - @Nonnull - protected UsageInfo[] findUsages() { - ArrayList usages = new ArrayList(); - final PsiClass[] inheritors = ClassInheritorsSearch.search(myClass, true).toArray(PsiClass.EMPTY_ARRAY); - myClassInheritors = new HashSet(); - myClassInheritors.add(myClass); - addAll(myClassInheritors, inheritors); - - { - ClassReferenceScanner scanner = new ClassReferenceSearchingScanner(myClass); - final MyClassInstanceReferenceVisitor instanceReferenceVisitor = new MyClassInstanceReferenceVisitor(myClass, usages); - scanner.processReferences(new ClassInstanceScanner(myClass, instanceReferenceVisitor)); - - MyClassMemberReferencesVisitor visitor = new MyClassMemberReferencesVisitor(usages, instanceReferenceVisitor); - myClass.accept(visitor); - - myClassImplementedInterfaces = instanceReferenceVisitor.getImplementedInterfaces(); + + private PsiSubstitutor getSuperSubstitutor(final PsiClass superClass) { + PsiSubstitutor result = mySuperClassesToSubstitutors.get(superClass); + if (result == null) { + result = TypeConversionUtil.getSuperClassSubstitutor(superClass, myClass, PsiSubstitutor.EMPTY); + mySuperClassesToSubstitutors.put(superClass, result); + } + return result; } - for (PsiClass inheritor : inheritors) { - processClass(inheritor, usages); + + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new InheritanceToDelegationViewDescriptor(myClass); } - return usages.toArray(new UsageInfo[usages.size()]); - } + @Nonnull + protected UsageInfo[] findUsages() { + ArrayList usages = new ArrayList(); + final PsiClass[] inheritors = ClassInheritorsSearch.search(myClass, true).toArray(PsiClass.EMPTY_ARRAY); + myClassInheritors = new HashSet(); + myClassInheritors.add(myClass); + addAll(myClassInheritors, inheritors); + + { + ClassReferenceScanner scanner = new ClassReferenceSearchingScanner(myClass); + final MyClassInstanceReferenceVisitor instanceReferenceVisitor = new MyClassInstanceReferenceVisitor(myClass, usages); + scanner.processReferences(new ClassInstanceScanner(myClass, instanceReferenceVisitor)); + + MyClassMemberReferencesVisitor visitor = new MyClassMemberReferencesVisitor(usages, instanceReferenceVisitor); + myClass.accept(visitor); + + myClassImplementedInterfaces = instanceReferenceVisitor.getImplementedInterfaces(); + } + for (PsiClass inheritor : inheritors) { + processClass(inheritor, usages); + } - private FieldAccessibility getFieldAccessibility(PsiElement element) { - for (PsiClass aClass : myClassInheritors) { - if (PsiTreeUtil.isAncestor(aClass, element, false)) { - return new FieldAccessibility(true, aClass); - } + return usages.toArray(new UsageInfo[usages.size()]); } - return FieldAccessibility.INVISIBLE; - } - - protected boolean preprocessUsages(Ref refUsages) { - final UsageInfo[] usagesIn = refUsages.get(); - ArrayList oldUsages = new ArrayList(); - addAll(oldUsages, usagesIn); - final ObjectUpcastedUsageInfo[] objectUpcastedUsageInfos = objectUpcastedUsages(usagesIn); - if (myPrepareSuccessfulSwingThreadCallback != null) { - MultiMap conflicts = new MultiMap(); - if (objectUpcastedUsageInfos.length > 0) { - final LocalizeValue message = RefactoringLocalize.instancesOf0UpcastedTo1WereFound( - RefactoringUIUtil.getDescription(myClass, true), - CommonRefactoringUtil.htmlEmphasize(CommonClassNames.JAVA_LANG_OBJECT) - ); - conflicts.putValue(myClass, message.get()); - } - - analyzeConflicts(usagesIn, conflicts); - if (!conflicts.isEmpty()) { - ConflictsDialog conflictsDialog = prepareConflictsDialog(conflicts, usagesIn); - conflictsDialog.show(); - if (!conflictsDialog.isOK()) { - if (conflictsDialog.isShowConflicts()) { - prepareSuccessful(); - } - return false; - } - } - - if (objectUpcastedUsageInfos.length > 0) { - showObjectUpcastedUsageView(objectUpcastedUsageInfos); - setPreviewUsages(true); - } + private FieldAccessibility getFieldAccessibility(PsiElement element) { + for (PsiClass aClass : myClassInheritors) { + if (PsiTreeUtil.isAncestor(aClass, element, false)) { + return new FieldAccessibility(true, aClass); + } + } + return FieldAccessibility.INVISIBLE; } - ArrayList filteredUsages = filterUsages(oldUsages); - refUsages.set(filteredUsages.toArray(new UsageInfo[filteredUsages.size()])); - prepareSuccessful(); - return true; - } - - private void analyzeConflicts(UsageInfo[] usage, MultiMap conflicts) { - HashMap> reportedNonDelegatedUsages = new HashMap>(); - HashMap> reportedUpcasts = new HashMap>(); - // HashSet reportedObjectUpcasts = new HashSet(); - - // final String nameJavaLangObject = ConflictsUtil.htmlEmphasize(CommonClassNames.JAVA_LANG_OBJECT); - final String classDescription = RefactoringUIUtil.getDescription(myClass, false); - - for (UsageInfo aUsage : usage) { - final PsiElement element = aUsage.getElement(); - if (aUsage instanceof InheritanceToDelegationUsageInfo) { - InheritanceToDelegationUsageInfo usageInfo = (InheritanceToDelegationUsageInfo)aUsage; - /*if (usageInfo instanceof ObjectUpcastedUsageInfo) { - PsiElement container = ConflictsUtil.getContainer(usageInfo.element); - if (!reportedObjectUpcasts.contains(container)) { - String message = "An instance of " + classDescription + " is upcasted to " - + nameJavaLangObject + " in " + ConflictsUtil.getDescription(container, true) + "."; - conflicts.add(message); - reportedObjectUpcasts.add(container); - } - } else*/ - if (!myIsDelegateOtherMembers && !usageInfo.getDelegateFieldAccessible().isAccessible()) { - if (usageInfo instanceof NonDelegatedMemberUsageInfo) { - final PsiElement nonDelegatedMember = ((NonDelegatedMemberUsageInfo)usageInfo).nonDelegatedMember; - HashSet reportedContainers = reportedNonDelegatedUsages.get(nonDelegatedMember); - if (reportedContainers == null) { - reportedContainers = new HashSet(); - reportedNonDelegatedUsages.put(nonDelegatedMember, reportedContainers); + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + final UsageInfo[] usagesIn = refUsages.get(); + ArrayList oldUsages = new ArrayList(); + addAll(oldUsages, usagesIn); + final ObjectUpcastedUsageInfo[] objectUpcastedUsageInfos = objectUpcastedUsages(usagesIn); + if (myPrepareSuccessfulSwingThreadCallback != null) { + MultiMap conflicts = new MultiMap(); + if (objectUpcastedUsageInfos.length > 0) { + final LocalizeValue message = RefactoringLocalize.instancesOf0UpcastedTo1WereFound( + RefactoringUIUtil.getDescription(myClass, true), + CommonRefactoringUtil.htmlEmphasize(CommonClassNames.JAVA_LANG_OBJECT) + ); + + conflicts.putValue(myClass, message.get()); + } + + analyzeConflicts(usagesIn, conflicts); + if (!conflicts.isEmpty()) { + ConflictsDialog conflictsDialog = prepareConflictsDialog(conflicts, usagesIn); + conflictsDialog.show(); + if (!conflictsDialog.isOK()) { + if (conflictsDialog.isShowConflicts()) { + prepareSuccessful(); + } + return false; + } } - final PsiElement container = ConflictsUtil.getContainer(element); - if (!reportedContainers.contains(container)) { - LocalizeValue message = RefactoringLocalize.zeroUses1OfAnInstanceOfA2( - RefactoringUIUtil.getDescription(container, true), - RefactoringUIUtil.getDescription(nonDelegatedMember, true), - classDescription - ); - conflicts.putValue(container, CommonRefactoringUtil.capitalize(message.get())); - reportedContainers.add(container); + + if (objectUpcastedUsageInfos.length > 0) { + showObjectUpcastedUsageView(objectUpcastedUsageInfos); + setPreviewUsages(true); } - } else if (usageInfo instanceof UpcastedUsageInfo) { - final PsiClass upcastedTo = ((UpcastedUsageInfo)usageInfo).upcastedTo; - HashSet reportedContainers = reportedUpcasts.get(upcastedTo); - if (reportedContainers == null) { - reportedContainers = new HashSet(); - reportedUpcasts.put(upcastedTo, reportedContainers); + } + ArrayList filteredUsages = filterUsages(oldUsages); + refUsages.set(filteredUsages.toArray(new UsageInfo[filteredUsages.size()])); + prepareSuccessful(); + return true; + } + + private void analyzeConflicts(UsageInfo[] usage, MultiMap conflicts) { + HashMap> reportedNonDelegatedUsages = new HashMap>(); + HashMap> reportedUpcasts = new HashMap>(); + //HashSet reportedObjectUpcasts = new HashSet(); + + //final String nameJavaLangObject = ConflictsUtil.htmlEmphasize(CommonClassNames.JAVA_LANG_OBJECT); + final String classDescription = RefactoringUIUtil.getDescription(myClass, false); + + for (UsageInfo aUsage : usage) { + final PsiElement element = aUsage.getElement(); + if (aUsage instanceof InheritanceToDelegationUsageInfo) { + InheritanceToDelegationUsageInfo usageInfo = (InheritanceToDelegationUsageInfo)aUsage; + /*if (usageInfo instanceof ObjectUpcastedUsageInfo) { + PsiElement container = ConflictsUtil.getContainer(usageInfo.element); + if (!reportedObjectUpcasts.contains(container)) { + String message = "An instance of " + classDescription + " is upcasted to " + + nameJavaLangObject + " in " + ConflictsUtil.getDescription(container, true) + "."; + conflicts.add(message); + reportedObjectUpcasts.add(container); + } + } else*/ + if (!myIsDelegateOtherMembers && !usageInfo.getDelegateFieldAccessible().isAccessible()) { + if (usageInfo instanceof NonDelegatedMemberUsageInfo) { + final PsiElement nonDelegatedMember = ((NonDelegatedMemberUsageInfo)usageInfo).nonDelegatedMember; + HashSet reportedContainers = reportedNonDelegatedUsages.get(nonDelegatedMember); + if (reportedContainers == null) { + reportedContainers = new HashSet(); + reportedNonDelegatedUsages.put(nonDelegatedMember, reportedContainers); + } + final PsiElement container = ConflictsUtil.getContainer(element); + if (!reportedContainers.contains(container)) { + LocalizeValue message = RefactoringLocalize.zeroUses1OfAnInstanceOfA2( + RefactoringUIUtil.getDescription(container, true), + RefactoringUIUtil.getDescription(nonDelegatedMember, true), + classDescription + ); + conflicts.putValue(container, CommonRefactoringUtil.capitalize(message.get())); + reportedContainers.add(container); + } + } + else if (usageInfo instanceof UpcastedUsageInfo) { + final PsiClass upcastedTo = ((UpcastedUsageInfo)usageInfo).upcastedTo; + HashSet reportedContainers = reportedUpcasts.get(upcastedTo); + if (reportedContainers == null) { + reportedContainers = new HashSet(); + reportedUpcasts.put(upcastedTo, reportedContainers); + } + final PsiElement container = ConflictsUtil.getContainer(element); + if (!reportedContainers.contains(container)) { + LocalizeValue message = RefactoringLocalize.zeroUpcastsAnInstanceOf1To2( + RefactoringUIUtil.getDescription(container, true), + classDescription, + RefactoringUIUtil.getDescription(upcastedTo, false) + ); + conflicts.putValue(container, CommonRefactoringUtil.capitalize(message.get())); + reportedContainers.add(container); + } + } + } } - final PsiElement container = ConflictsUtil.getContainer(element); - if (!reportedContainers.contains(container)) { - LocalizeValue message = RefactoringLocalize.zeroUpcastsAnInstanceOf1To2( - RefactoringUIUtil.getDescription(container, true), - classDescription, - RefactoringUIUtil.getDescription(upcastedTo, false) - ); - conflicts.putValue(container, CommonRefactoringUtil.capitalize(message.get())); - reportedContainers.add(container); + else if (aUsage instanceof NoLongerOverridingSubClassMethodUsageInfo info) { + LocalizeValue message = RefactoringLocalize.zeroWillNoLongerOverride1( + RefactoringUIUtil.getDescription(info.getSubClassMethod(), true), + RefactoringUIUtil.getDescription(info.getOverridenMethod(), true) + ); + conflicts.putValue(info.getSubClassMethod(), message.get()); } - } } - } else if (aUsage instanceof NoLongerOverridingSubClassMethodUsageInfo info) { - LocalizeValue message = RefactoringLocalize.zeroWillNoLongerOverride1( - RefactoringUIUtil.getDescription(info.getSubClassMethod(), true), - RefactoringUIUtil.getDescription(info.getOverridenMethod(), true) - ); - conflicts.putValue(info.getSubClassMethod(), message.get()); - } } - } - - private static ObjectUpcastedUsageInfo[] objectUpcastedUsages(UsageInfo[] usages) { - ArrayList result = new ArrayList(); - for (UsageInfo usage : usages) { - if (usage instanceof ObjectUpcastedUsageInfo) { - result.add(((ObjectUpcastedUsageInfo)usage)); - } + + private static ObjectUpcastedUsageInfo[] objectUpcastedUsages(UsageInfo[] usages) { + ArrayList result = new ArrayList(); + for (UsageInfo usage : usages) { + if (usage instanceof ObjectUpcastedUsageInfo) { + result.add(((ObjectUpcastedUsageInfo)usage)); + } + } + return result.toArray(new ObjectUpcastedUsageInfo[result.size()]); } - return result.toArray(new ObjectUpcastedUsageInfo[result.size()]); - } - private ArrayList filterUsages(ArrayList usages) { - ArrayList result = new ArrayList(); + private ArrayList filterUsages(ArrayList usages) { + ArrayList result = new ArrayList(); - for (UsageInfo usageInfo : usages) { - if (!(usageInfo instanceof InheritanceToDelegationUsageInfo)) { - continue; - } - if (usageInfo instanceof ObjectUpcastedUsageInfo) { - continue; - } + for (UsageInfo usageInfo : usages) { + if (!(usageInfo instanceof InheritanceToDelegationUsageInfo)) { + continue; + } + if (usageInfo instanceof ObjectUpcastedUsageInfo) { + continue; + } - if (!myIsDelegateOtherMembers) { - final FieldAccessibility delegateFieldAccessible = ((InheritanceToDelegationUsageInfo)usageInfo).getDelegateFieldAccessible(); - if (!delegateFieldAccessible.isAccessible()) { - continue; - } - } + if (!myIsDelegateOtherMembers) { + final FieldAccessibility delegateFieldAccessible = + ((InheritanceToDelegationUsageInfo)usageInfo).getDelegateFieldAccessible(); + if (!delegateFieldAccessible.isAccessible()) { + continue; + } + } - result.add(usageInfo); + result.add(usageInfo); + } + return result; } - return result; - } - - private void processClass(PsiClass inheritor, ArrayList usages) { - ClassReferenceScanner scanner = new ClassReferenceSearchingScanner(inheritor); - final MyClassInstanceReferenceVisitor instanceVisitor = new MyClassInstanceReferenceVisitor(inheritor, usages); - scanner.processReferences(new ClassInstanceScanner(inheritor, instanceVisitor)); - MyClassInheritorMemberReferencesVisitor classMemberVisitor = - new MyClassInheritorMemberReferencesVisitor(inheritor, usages, instanceVisitor); - inheritor.accept(classMemberVisitor); - PsiSubstitutor inheritorSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(myClass, inheritor, PsiSubstitutor.EMPTY); - - PsiMethod[] methods = inheritor.getMethods(); - for (PsiMethod method : methods) { - final PsiMethod baseMethod = findSuperMethodInBaseClass(method); - - if (baseMethod != null) { - if (!baseMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - usages.add(new NoLongerOverridingSubClassMethodUsageInfo(method, baseMethod)); - } else { - final PsiMethod[] methodsByName = myClass.findMethodsByName(method.getName(), false); - for (final PsiMethod classMethod : methodsByName) { - final MethodSignature signature = classMethod.getSignature(inheritorSubstitutor); - if (signature.equals(method.getSignature(PsiSubstitutor.EMPTY))) { - if (!classMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - usages.add(new NoLongerOverridingSubClassMethodUsageInfo(method, baseMethod)); - break; - } + + private void processClass(PsiClass inheritor, ArrayList usages) { + ClassReferenceScanner scanner = new ClassReferenceSearchingScanner(inheritor); + final MyClassInstanceReferenceVisitor instanceVisitor = new MyClassInstanceReferenceVisitor(inheritor, usages); + scanner.processReferences(new ClassInstanceScanner(inheritor, instanceVisitor)); + MyClassInheritorMemberReferencesVisitor classMemberVisitor = + new MyClassInheritorMemberReferencesVisitor(inheritor, usages, instanceVisitor); + inheritor.accept(classMemberVisitor); + PsiSubstitutor inheritorSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(myClass, inheritor, PsiSubstitutor.EMPTY); + + PsiMethod[] methods = inheritor.getMethods(); + for (PsiMethod method : methods) { + final PsiMethod baseMethod = findSuperMethodInBaseClass(method); + + if (baseMethod != null) { + if (!baseMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + usages.add(new NoLongerOverridingSubClassMethodUsageInfo(method, baseMethod)); + } + else { + final PsiMethod[] methodsByName = myClass.findMethodsByName(method.getName(), false); + for (final PsiMethod classMethod : methodsByName) { + final MethodSignature signature = classMethod.getSignature(inheritorSubstitutor); + if (signature.equals(method.getSignature(PsiSubstitutor.EMPTY))) { + if (!classMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + usages.add(new NoLongerOverridingSubClassMethodUsageInfo(method, baseMethod)); + break; + } + } + } + } } - } } - } - } - } - - protected void performRefactoring(UsageInfo[] usages) { - try { - for (UsageInfo aUsage : usages) { - InheritanceToDelegationUsageInfo usage = (InheritanceToDelegationUsageInfo)aUsage; - - - if (usage instanceof UnqualifiedNonDelegatedMemberUsageInfo) { - delegateUsageFromClass( - usage.getElement(), - ((NonDelegatedMemberUsageInfo)usage).nonDelegatedMember, - usage.getDelegateFieldAccessible() - ); - } else { - upcastToDelegation(usage.getElement(), usage.getDelegateFieldAccessible()); - } - } - - myAbstractDelegatedMethods = new HashSet(); - addInnerClass(); - addField(usages); - delegateMethods(); - addImplementingInterfaces(); - } catch (IncorrectOperationException e) { - LOG.error(e); } - } - private void addInnerClass() throws IncorrectOperationException { - if (!myIsInnerClassNeeded) { - return; - } + protected void performRefactoring(UsageInfo[] usages) { + try { + for (UsageInfo aUsage : usages) { + InheritanceToDelegationUsageInfo usage = (InheritanceToDelegationUsageInfo)aUsage; - PsiClass innerClass = myFactory.createClass(myInnerClassName); - final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(myBaseClass, myClass, PsiSubstitutor.EMPTY); - final PsiClassType superClassType = myFactory.createType(myBaseClass, superClassSubstitutor); - final PsiJavaCodeReferenceElement baseClassReferenceElement = myFactory.createReferenceElementByType(superClassType); - if (!myBaseClass.isInterface()) { - innerClass.getExtendsList().add(baseClassReferenceElement); - } else { - innerClass.getImplementsList().add(baseClassReferenceElement); - } - PsiUtil.setModifierProperty(innerClass, PsiModifier.PRIVATE, true); - innerClass = (PsiClass)myClass.add(innerClass); - List innerClassMethods = getInnerClassMethods(); - for (InnerClassMethod innerClassMethod : innerClassMethods) { - innerClassMethod.createMethod(innerClass); - } - } - - private void delegateUsageFromClass( - PsiElement element, - PsiElement nonDelegatedMember, - FieldAccessibility fieldAccessibility - ) throws IncorrectOperationException { - if (element instanceof PsiReferenceExpression) { - PsiReferenceExpression referenceExpression = (PsiReferenceExpression)element; - if (referenceExpression.getQualifierExpression() != null) { - upcastToDelegation(referenceExpression.getQualifierExpression(), fieldAccessibility); - } else { - final String name = ((PsiNamedElement)nonDelegatedMember).getName(); - final String qualifier; - if (isStatic(nonDelegatedMember)) { - qualifier = myBaseClass.getName(); - } else if (!fieldAccessibility.isAccessible() && myGenerateGetter) { - qualifier = myGetterName + "()"; - } else { - qualifier = myFieldName; - } - - PsiExpression newExpr = myFactory.createExpressionFromText(qualifier + "." + name, element); - newExpr = (PsiExpression)CodeStyleManager.getInstance(myProject).reformat(newExpr); - element.replace(newExpr); - } - } else if (element instanceof PsiJavaCodeReferenceElement) { - final String name = ((PsiNamedElement)nonDelegatedMember).getName(); - - PsiElement parent = element.getParent(); - if (!isStatic(nonDelegatedMember) && parent instanceof PsiNewExpression) { - final PsiNewExpression newExpr = (PsiNewExpression)parent; - if (newExpr.getQualifier() != null) { - upcastToDelegation(newExpr.getQualifier(), fieldAccessibility); - } else { - final String qualifier; - if (!fieldAccessibility.isAccessible() && myGenerateGetter) { - qualifier = myGetterName + "()"; - } else { - qualifier = myFieldName; - } - newExpr.replace(myFactory.createExpressionFromText(qualifier + "." + newExpr.getText(), parent)); - } - } else { - final String qualifier = myBaseClass.getName(); - PsiJavaCodeReferenceElement newRef = myFactory.createFQClassNameReferenceElement(qualifier + "." + name, element.getResolveScope()); - //newRef = (PsiJavaCodeReferenceElement) CodeStyleManager.getInstance(myProject).reformat(newRef); - element.replace(newRef); - } - } else { - LOG.assertTrue(false); - } - } + if (usage instanceof UnqualifiedNonDelegatedMemberUsageInfo) { + delegateUsageFromClass( + usage.getElement(), + ((NonDelegatedMemberUsageInfo)usage).nonDelegatedMember, + usage.getDelegateFieldAccessible() + ); + } + else { + upcastToDelegation(usage.getElement(), usage.getDelegateFieldAccessible()); + } + } - private static boolean isStatic(PsiElement member) { - if (member instanceof PsiModifierListOwner) { - final PsiModifierListOwner method = (PsiModifierListOwner)member; - return method.hasModifierProperty(PsiModifier.STATIC); - } - return false; - } - - private void upcastToDelegation(PsiElement element, FieldAccessibility fieldAccessibility) throws IncorrectOperationException { - final PsiExpression expression = (PsiExpression)element; - - final PsiExpression newExpr; - final PsiReferenceExpression ref; - @NonNls final String delegateQualifier; - if (!(expression instanceof PsiThisExpression || expression instanceof PsiSuperExpression)) { - delegateQualifier = "a."; - } else { - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myProject).getResolveHelper(); - final PsiVariable psiVariable = resolveHelper.resolveReferencedVariable(myFieldName, element); - if (psiVariable == null) { - delegateQualifier = ""; - } else { - delegateQualifier = "a."; - } - } - if (!fieldAccessibility.isAccessible() && myGenerateGetter) { - newExpr = myFactory.createExpressionFromText(delegateQualifier + myGetterName + "()", expression); - ref = (PsiReferenceExpression)((PsiMethodCallExpression)newExpr).getMethodExpression().getQualifierExpression(); - } else { - newExpr = myFactory.createExpressionFromText(delegateQualifier + myFieldName, expression); - ref = (PsiReferenceExpression)((PsiReferenceExpression)newExpr).getQualifierExpression(); - } - // LOG.debug("upcastToDelegation:" + element + ":newExpr = " + newExpr); - // LOG.debug("upcastToDelegation:" + element + ":ref = " + ref); - if (ref != null) { - ref.replace(expression); + myAbstractDelegatedMethods = new HashSet(); + addInnerClass(); + addField(usages); + delegateMethods(); + addImplementingInterfaces(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - expression.replace(newExpr); - // LOG.debug("upcastToDelegation:" + element + ":replaced = " + replaced); - } - private void delegateMethods() throws IncorrectOperationException { - for (PsiMethod method : myDelegatedMethods) { - if (!myAbstractDelegatedMethods.contains(method)) { - PsiMethod methodToAdd = delegateMethod(myFieldName, method, getSuperSubstitutor(method.getContainingClass())); + private void addInnerClass() throws IncorrectOperationException { + if (!myIsInnerClassNeeded) { + return; + } - String visibility = myDelegatedMethodsVisibility.get(method); - if (visibility != null) { - PsiUtil.setModifierProperty(methodToAdd, visibility, true); + PsiClass innerClass = myFactory.createClass(myInnerClassName); + final PsiSubstitutor superClassSubstitutor = + TypeConversionUtil.getSuperClassSubstitutor(myBaseClass, myClass, PsiSubstitutor.EMPTY); + final PsiClassType superClassType = myFactory.createType(myBaseClass, superClassSubstitutor); + final PsiJavaCodeReferenceElement baseClassReferenceElement = myFactory.createReferenceElementByType(superClassType); + if (!myBaseClass.isInterface()) { + innerClass.getExtendsList().add(baseClassReferenceElement); + } + else { + innerClass.getImplementsList().add(baseClassReferenceElement); } + PsiUtil.setModifierProperty(innerClass, PsiModifier.PRIVATE, true); + innerClass = (PsiClass)myClass.add(innerClass); - myClass.add(methodToAdd); - } + List innerClassMethods = getInnerClassMethods(); + for (InnerClassMethod innerClassMethod : innerClassMethods) { + innerClassMethod.createMethod(innerClass); + } } - } - - private PsiMethod delegateMethod( - @NonNls String delegationTarget, - PsiMethod method, - PsiSubstitutor substitutor - ) throws IncorrectOperationException { - substitutor = OverrideImplementUtil.correctSubstitutor(method, substitutor); - PsiMethod methodToAdd = GenerateMembersUtil.substituteGenericMethod(method, substitutor); - - final PsiModifierList modifierList = methodToAdd.getModifierList(); - final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject); - modifierList.setModifierProperty(PsiModifier.ABSTRACT, false); - - NullableNotNullManager.getInstance(myProject).copyNullableOrNotNullAnnotation(method, methodToAdd); - - final String delegationBody = getDelegationBody(methodToAdd, delegationTarget); - PsiCodeBlock newBody = myFactory.createCodeBlockFromText(delegationBody, method); - - PsiCodeBlock oldBody = methodToAdd.getBody(); - if (oldBody != null) { - oldBody.replace(newBody); - } else { - methodToAdd.addBefore(newBody, null); + + private void delegateUsageFromClass( + PsiElement element, + PsiElement nonDelegatedMember, + FieldAccessibility fieldAccessibility + ) throws IncorrectOperationException { + if (element instanceof PsiReferenceExpression) { + PsiReferenceExpression referenceExpression = (PsiReferenceExpression)element; + if (referenceExpression.getQualifierExpression() != null) { + upcastToDelegation(referenceExpression.getQualifierExpression(), fieldAccessibility); + } + else { + final String name = ((PsiNamedElement)nonDelegatedMember).getName(); + final String qualifier; + if (isStatic(nonDelegatedMember)) { + qualifier = myBaseClass.getName(); + } + else if (!fieldAccessibility.isAccessible() && myGenerateGetter) { + qualifier = myGetterName + "()"; + } + else { + qualifier = myFieldName; + } + + PsiExpression newExpr = myFactory.createExpressionFromText(qualifier + "." + name, element); + newExpr = (PsiExpression)CodeStyleManager.getInstance(myProject).reformat(newExpr); + element.replace(newExpr); + } + } + else if (element instanceof PsiJavaCodeReferenceElement) { + final String name = ((PsiNamedElement)nonDelegatedMember).getName(); + + PsiElement parent = element.getParent(); + if (!isStatic(nonDelegatedMember) && parent instanceof PsiNewExpression) { + final PsiNewExpression newExpr = (PsiNewExpression)parent; + if (newExpr.getQualifier() != null) { + upcastToDelegation(newExpr.getQualifier(), fieldAccessibility); + } + else { + final String qualifier; + if (!fieldAccessibility.isAccessible() && myGenerateGetter) { + qualifier = myGetterName + "()"; + } + else { + qualifier = myFieldName; + } + newExpr.replace(myFactory.createExpressionFromText(qualifier + "." + newExpr.getText(), parent)); + } + } + else { + final String qualifier = myBaseClass.getName(); + PsiJavaCodeReferenceElement newRef = + myFactory.createFQClassNameReferenceElement(qualifier + "." + name, element.getResolveScope()); + //newRef = (PsiJavaCodeReferenceElement) CodeStyleManager.getInstance(myProject).reformat(newRef); + element.replace(newRef); + } + } + else { + LOG.assertTrue(false); + } } - if (methodToAdd.getDocComment() != null) { - methodToAdd.getDocComment().delete(); + private static boolean isStatic(PsiElement member) { + if (member instanceof PsiModifierListOwner) { + final PsiModifierListOwner method = (PsiModifierListOwner)member; + return method.hasModifierProperty(PsiModifier.STATIC); + } + return false; } - methodToAdd = (PsiMethod)CodeStyleManager.getInstance(myProject).reformat(methodToAdd); - methodToAdd = (PsiMethod)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(methodToAdd); - return methodToAdd; - } - private static String getDelegationBody(PsiMethod methodToAdd, String delegationTarget) { - @NonNls final StringBuffer buffer = new StringBuffer(); - buffer.append("{\n"); + private void upcastToDelegation(PsiElement element, FieldAccessibility fieldAccessibility) throws IncorrectOperationException { + final PsiExpression expression = (PsiExpression)element; - if (!PsiType.VOID.equals(methodToAdd.getReturnType())) { - buffer.append("return "); + final PsiExpression newExpr; + final PsiReferenceExpression ref; + @NonNls final String delegateQualifier; + if (!(expression instanceof PsiThisExpression || expression instanceof PsiSuperExpression)) { + delegateQualifier = "a."; + } + else { + PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myProject).getResolveHelper(); + final PsiVariable psiVariable = resolveHelper.resolveReferencedVariable(myFieldName, element); + if (psiVariable == null) { + delegateQualifier = ""; + } + else { + delegateQualifier = "a."; + } + } + if (!fieldAccessibility.isAccessible() && myGenerateGetter) { + newExpr = myFactory.createExpressionFromText(delegateQualifier + myGetterName + "()", expression); + ref = (PsiReferenceExpression)((PsiMethodCallExpression)newExpr).getMethodExpression().getQualifierExpression(); + } + else { + newExpr = myFactory.createExpressionFromText(delegateQualifier + myFieldName, expression); + ref = (PsiReferenceExpression)((PsiReferenceExpression)newExpr).getQualifierExpression(); + } + // LOG.debug("upcastToDelegation:" + element + ":newExpr = " + newExpr); + // LOG.debug("upcastToDelegation:" + element + ":ref = " + ref); + if (ref != null) { + ref.replace(expression); + } + expression.replace(newExpr); + // LOG.debug("upcastToDelegation:" + element + ":replaced = " + replaced); } - buffer.append(delegationTarget); - buffer.append("."); - buffer.append(methodToAdd.getName()); - buffer.append("("); - PsiParameter[] params = methodToAdd.getParameterList().getParameters(); - for (int i = 0; i < params.length; i++) { - PsiParameter param = params[i]; - if (i > 0) { - buffer.append(","); - } - buffer.append(param.getName()); - } - buffer.append(");\n}"); - return buffer.toString(); - } - - private void addImplementingInterfaces() throws IncorrectOperationException { - final PsiReferenceList implementsList = myClass.getImplementsList(); - LOG.assertTrue(implementsList != null); - for (PsiClass delegatedInterface : myDelegatedInterfaces) { - if (!myClassImplementedInterfaces.contains(delegatedInterface)) { - implementsList.add(myFactory.createClassReferenceElement(delegatedInterface)); - } - } + private void delegateMethods() throws IncorrectOperationException { + for (PsiMethod method : myDelegatedMethods) { + if (!myAbstractDelegatedMethods.contains(method)) { + PsiMethod methodToAdd = delegateMethod(myFieldName, method, getSuperSubstitutor(method.getContainingClass())); + + String visibility = myDelegatedMethodsVisibility.get(method); + if (visibility != null) { + PsiUtil.setModifierProperty(methodToAdd, visibility, true); + } - if (!myBaseClass.isInterface()) { - final PsiReferenceList extendsList = myClass.getExtendsList(); - LOG.assertTrue(extendsList != null); - extendsList.getReferenceElements()[0].delete(); - } else { - final PsiJavaCodeReferenceElement[] interfaceRefs = implementsList.getReferenceElements(); - for (PsiJavaCodeReferenceElement interfaceRef : interfaceRefs) { - final PsiElement resolved = interfaceRef.resolve(); - if (myManager.areElementsEquivalent(myBaseClass, resolved)) { - interfaceRef.delete(); - break; - } - } + myClass.add(methodToAdd); + } + } } - } - private void addField(UsageInfo[] usages) throws IncorrectOperationException { - final String fieldVisibility = getFieldVisibility(usages); + private PsiMethod delegateMethod( + @NonNls String delegationTarget, + PsiMethod method, + PsiSubstitutor substitutor + ) throws IncorrectOperationException { + substitutor = OverrideImplementUtil.correctSubstitutor(method, substitutor); + PsiMethod methodToAdd = GenerateMembersUtil.substituteGenericMethod(method, substitutor); - final boolean fieldInitializerNeeded = isFieldInitializerNeeded(); + final PsiModifierList modifierList = methodToAdd.getModifierList(); + final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject); + modifierList.setModifierProperty(PsiModifier.ABSTRACT, false); - PsiField field = createField(fieldVisibility, fieldInitializerNeeded, defaultClassFieldType()); + NullableNotNullManager.getInstance(myProject).copyNullableOrNotNullAnnotation(method, methodToAdd); - if (!myIsInnerClassNeeded) { - field.getTypeElement().replace(myFactory.createTypeElement(myBaseClassType)); - if (fieldInitializerNeeded) { - final PsiJavaCodeReferenceElement classReferenceElement = myFactory.createReferenceElementByType(myBaseClassType); - PsiNewExpression newExpression = (PsiNewExpression)field.getInitializer(); - newExpression.getClassReference().replace(classReferenceElement); - } - } + final String delegationBody = getDelegationBody(methodToAdd, delegationTarget); + PsiCodeBlock newBody = myFactory.createCodeBlockFromText(delegationBody, method); - field = (PsiField)CodeStyleManager.getInstance(myProject).reformat(field); - myClass.add(field); - if (!fieldInitializerNeeded) { - fixConstructors(); - } + PsiCodeBlock oldBody = methodToAdd.getBody(); + if (oldBody != null) { + oldBody.replace(newBody); + } + else { + methodToAdd.addBefore(newBody, null); + } - if (myGenerateGetter) { - final String getterVisibility = PsiModifier.PUBLIC; - @NonNls StringBuffer getterBuffer = new StringBuffer(); - getterBuffer.append(getterVisibility); - getterBuffer.append(" Object "); - getterBuffer.append(myGetterName); - getterBuffer.append("() {\n return "); - getterBuffer.append(myFieldName); - getterBuffer.append(";\n}"); - PsiMethod getter = myFactory.createMethodFromText(getterBuffer.toString(), myClass); - getter.getReturnTypeElement().replace(myFactory.createTypeElement(myBaseClassType)); - getter = (PsiMethod)CodeStyleManager.getInstance(myProject).reformat(getter); - myClass.add(getter); + if (methodToAdd.getDocComment() != null) { + methodToAdd.getDocComment().delete(); + } + methodToAdd = (PsiMethod)CodeStyleManager.getInstance(myProject).reformat(methodToAdd); + methodToAdd = (PsiMethod)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(methodToAdd); + return methodToAdd; } - } - private String getFieldVisibility(UsageInfo[] usages) { - if (myIsDelegateOtherMembers && !myGenerateGetter) { - return PsiModifier.PUBLIC; - } + private static String getDelegationBody(PsiMethod methodToAdd, String delegationTarget) { + @NonNls final StringBuffer buffer = new StringBuffer(); + buffer.append("{\n"); - for (UsageInfo aUsage : usages) { - InheritanceToDelegationUsageInfo usage = (InheritanceToDelegationUsageInfo)aUsage; - final FieldAccessibility delegateFieldAccessible = usage.getDelegateFieldAccessible(); - if (delegateFieldAccessible.isAccessible() && delegateFieldAccessible.getContainingClass() != myClass) { - return PsiModifier.PROTECTED; - } - } - return PsiModifier.PRIVATE; - } - - private - @NonNls - String defaultClassFieldType() { - return (myIsInnerClassNeeded ? myInnerClassName : "Object"); - } - - private PsiField createField( - final String fieldVisibility, - final boolean fieldInitializerNeeded, - String defaultTypeName - ) throws IncorrectOperationException { - @NonNls StringBuffer buffer = new StringBuffer(); - buffer.append(fieldVisibility); - buffer.append(" final " + defaultTypeName + " "); - buffer.append(myFieldName); - if (fieldInitializerNeeded) { - buffer.append(" = new " + defaultTypeName + "()"); + if (!PsiType.VOID.equals(methodToAdd.getReturnType())) { + buffer.append("return "); + } + + buffer.append(delegationTarget); + buffer.append("."); + buffer.append(methodToAdd.getName()); + buffer.append("("); + PsiParameter[] params = methodToAdd.getParameterList().getParameters(); + for (int i = 0; i < params.length; i++) { + PsiParameter param = params[i]; + if (i > 0) { + buffer.append(","); + } + buffer.append(param.getName()); + } + buffer.append(");\n}"); + return buffer.toString(); } - buffer.append(";"); - return myFactory.createFieldFromText(buffer.toString(), myClass); - } - private void fixConstructors() throws IncorrectOperationException { - if (myBaseClass.isInterface()) { - return; + private void addImplementingInterfaces() throws IncorrectOperationException { + final PsiReferenceList implementsList = myClass.getImplementsList(); + LOG.assertTrue(implementsList != null); + for (PsiClass delegatedInterface : myDelegatedInterfaces) { + if (!myClassImplementedInterfaces.contains(delegatedInterface)) { + implementsList.add(myFactory.createClassReferenceElement(delegatedInterface)); + } + } + + if (!myBaseClass.isInterface()) { + final PsiReferenceList extendsList = myClass.getExtendsList(); + LOG.assertTrue(extendsList != null); + extendsList.getReferenceElements()[0].delete(); + } + else { + final PsiJavaCodeReferenceElement[] interfaceRefs = implementsList.getReferenceElements(); + for (PsiJavaCodeReferenceElement interfaceRef : interfaceRefs) { + final PsiElement resolved = interfaceRef.resolve(); + if (myManager.areElementsEquivalent(myBaseClass, resolved)) { + interfaceRef.delete(); + break; + } + } + } } - final PsiJavaCodeReferenceElement baseClassReference = myFactory.createClassReferenceElement(myBaseClass); - - PsiMethod[] constructors = myClass.getConstructors(); - for (PsiMethod constructor : constructors) { - PsiCodeBlock body = constructor.getBody(); - final PsiStatement[] statements = body.getStatements(); - @NonNls String fieldQualifier = ""; - PsiParameter[] constructorParams = constructor.getParameterList().getParameters(); - for (PsiParameter constructorParam : constructorParams) { - if (myFieldName.equals(constructorParam.getName())) { - fieldQualifier = "this."; - break; - } - } - final @NonNls String assignmentText = fieldQualifier + myFieldName + "= new " + defaultClassFieldType() + "()"; - if (statements.length < 1 || !JavaHighlightUtil.isSuperOrThisCall(statements[0], true, true) || myBaseClass.isInterface()) { - PsiExpressionStatement assignmentStatement = - (PsiExpressionStatement)myFactory.createStatementFromText( - assignmentText, body - ); + + private void addField(UsageInfo[] usages) throws IncorrectOperationException { + final String fieldVisibility = getFieldVisibility(usages); + + final boolean fieldInitializerNeeded = isFieldInitializerNeeded(); + + PsiField field = createField(fieldVisibility, fieldInitializerNeeded, defaultClassFieldType()); + if (!myIsInnerClassNeeded) { - final PsiAssignmentExpression assignmentExpr = (PsiAssignmentExpression)assignmentStatement.getExpression(); - final PsiNewExpression newExpression = (PsiNewExpression)assignmentExpr.getRExpression(); - assert newExpression != null; - final PsiJavaCodeReferenceElement classRef = newExpression.getClassReference(); - assert classRef != null; - classRef.replace(baseClassReference); - } - - assignmentStatement = (PsiExpressionStatement)CodeStyleManager.getInstance(myProject).reformat(assignmentStatement); - if (statements.length > 0) { - if (!JavaHighlightUtil.isSuperOrThisCall(statements[0], true, false)) { - body.addBefore(assignmentStatement, statements[0]); - } else { - body.addAfter(assignmentStatement, statements[0]); - } - } else { - body.add(assignmentStatement); - } - } else { - final PsiExpressionStatement callStatement = ((PsiExpressionStatement)statements[0]); - if (!JavaHighlightUtil.isSuperOrThisCall(callStatement, false, true)) { - final PsiMethodCallExpression superConstructorCall = - (PsiMethodCallExpression)callStatement.getExpression(); - PsiAssignmentExpression assignmentExpression = - (PsiAssignmentExpression)myFactory.createExpressionFromText( - assignmentText, superConstructorCall - ); - PsiNewExpression newExpression = - (PsiNewExpression)assignmentExpression.getRExpression(); - if (!myIsInnerClassNeeded) { - newExpression.getClassReference().replace(baseClassReference); - } - assignmentExpression = (PsiAssignmentExpression)CodeStyleManager.getInstance(myProject).reformat(assignmentExpression); - newExpression.getArgumentList().replace(superConstructorCall.getArgumentList()); - superConstructorCall.replace(assignmentExpression); - } - } - } - } + field.getTypeElement().replace(myFactory.createTypeElement(myBaseClassType)); + if (fieldInitializerNeeded) { + final PsiJavaCodeReferenceElement classReferenceElement = myFactory.createReferenceElementByType(myBaseClassType); + PsiNewExpression newExpression = (PsiNewExpression)field.getInitializer(); + newExpression.getClassReference().replace(classReferenceElement); + } + } - private boolean isFieldInitializerNeeded() { - if (myBaseClass.isInterface()) { - return true; - } - PsiMethod[] constructors = myClass.getConstructors(); - for (PsiMethod constructor : constructors) { - final PsiStatement[] statements = constructor.getBody().getStatements(); - if (statements.length > 0 && JavaHighlightUtil.isSuperOrThisCall(statements[0], true, false)) { - return false; - } + field = (PsiField)CodeStyleManager.getInstance(myProject).reformat(field); + myClass.add(field); + if (!fieldInitializerNeeded) { + fixConstructors(); + } + + if (myGenerateGetter) { + final String getterVisibility = PsiModifier.PUBLIC; + @NonNls StringBuffer getterBuffer = new StringBuffer(); + getterBuffer.append(getterVisibility); + getterBuffer.append(" Object "); + getterBuffer.append(myGetterName); + getterBuffer.append("() {\n return "); + getterBuffer.append(myFieldName); + getterBuffer.append(";\n}"); + PsiMethod getter = myFactory.createMethodFromText(getterBuffer.toString(), myClass); + getter.getReturnTypeElement().replace(myFactory.createTypeElement(myBaseClassType)); + getter = (PsiMethod)CodeStyleManager.getInstance(myProject).reformat(getter); + myClass.add(getter); + } } - return true; - } - - private List getInnerClassMethods() { - ArrayList result = new ArrayList(); - - // find all neccessary constructors - if (!myBaseClass.isInterface()) { - PsiMethod[] constructors = myClass.getConstructors(); - for (PsiMethod constructor : constructors) { - final PsiStatement[] statements = constructor.getBody().getStatements(); - if (statements.length > 0 && JavaHighlightUtil.isSuperOrThisCall(statements[0], true, false)) { - final PsiMethodCallExpression superConstructorCall = - (PsiMethodCallExpression)((PsiExpressionStatement)statements[0]).getExpression(); - PsiElement superConstructor = superConstructorCall.getMethodExpression().resolve(); - if (superConstructor instanceof PsiMethod && ((PsiMethod)superConstructor).isConstructor()) { - result.add(new InnerClassConstructor((PsiMethod)superConstructor)); - } - } - } + + private String getFieldVisibility(UsageInfo[] usages) { + if (myIsDelegateOtherMembers && !myGenerateGetter) { + return PsiModifier.PUBLIC; + } + + for (UsageInfo aUsage : usages) { + InheritanceToDelegationUsageInfo usage = (InheritanceToDelegationUsageInfo)aUsage; + final FieldAccessibility delegateFieldAccessible = usage.getDelegateFieldAccessible(); + if (delegateFieldAccessible.isAccessible() && delegateFieldAccessible.getContainingClass() != myClass) { + return PsiModifier.PROTECTED; + } + } + return PsiModifier.PRIVATE; + } + + private + @NonNls + String defaultClassFieldType() { + return (myIsInnerClassNeeded ? myInnerClassName : "Object"); + } + + private PsiField createField( + final String fieldVisibility, + final boolean fieldInitializerNeeded, + String defaultTypeName + ) throws IncorrectOperationException { + @NonNls StringBuffer buffer = new StringBuffer(); + buffer.append(fieldVisibility); + buffer.append(" final " + defaultTypeName + " "); + buffer.append(myFieldName); + if (fieldInitializerNeeded) { + buffer.append(" = new " + defaultTypeName + "()"); + } + buffer.append(";"); + return myFactory.createFieldFromText(buffer.toString(), myClass); } - // find overriding/implementing method - { - class InnerClassOverridingMethod extends InnerClassMethod { - public InnerClassOverridingMethod(PsiMethod method) { - super(method); - } - - public void createMethod(PsiClass innerClass) - throws IncorrectOperationException { - OverriddenMethodClassMemberReferencesVisitor visitor = new OverriddenMethodClassMemberReferencesVisitor(); - myClass.accept(visitor); - final List actions = visitor.getPsiActions(); - for (PsiAction action : actions) { - action.run(); - } - innerClass.add(myMethod); - myMethod.delete(); - // myMethod.replace(delegateMethod(myMethod)); - } - } - - for (PsiMethod method : myOverriddenMethods) { - result.add(new InnerClassOverridingMethod(method)); - } + private void fixConstructors() throws IncorrectOperationException { + if (myBaseClass.isInterface()) { + return; + } + final PsiJavaCodeReferenceElement baseClassReference = myFactory.createClassReferenceElement(myBaseClass); + + PsiMethod[] constructors = myClass.getConstructors(); + for (PsiMethod constructor : constructors) { + PsiCodeBlock body = constructor.getBody(); + final PsiStatement[] statements = body.getStatements(); + @NonNls String fieldQualifier = ""; + PsiParameter[] constructorParams = constructor.getParameterList().getParameters(); + for (PsiParameter constructorParam : constructorParams) { + if (myFieldName.equals(constructorParam.getName())) { + fieldQualifier = "this."; + break; + } + } + final @NonNls String assignmentText = fieldQualifier + myFieldName + "= new " + defaultClassFieldType() + "()"; + if (statements.length < 1 || !JavaHighlightUtil.isSuperOrThisCall(statements[0], true, true) || myBaseClass.isInterface()) { + PsiExpressionStatement assignmentStatement = + (PsiExpressionStatement)myFactory.createStatementFromText( + assignmentText, body + ); + if (!myIsInnerClassNeeded) { + final PsiAssignmentExpression assignmentExpr = (PsiAssignmentExpression)assignmentStatement.getExpression(); + final PsiNewExpression newExpression = (PsiNewExpression)assignmentExpr.getRExpression(); + assert newExpression != null; + final PsiJavaCodeReferenceElement classRef = newExpression.getClassReference(); + assert classRef != null; + classRef.replace(baseClassReference); + } + + assignmentStatement = (PsiExpressionStatement)CodeStyleManager.getInstance(myProject).reformat(assignmentStatement); + if (statements.length > 0) { + if (!JavaHighlightUtil.isSuperOrThisCall(statements[0], true, false)) { + body.addBefore(assignmentStatement, statements[0]); + } + else { + body.addAfter(assignmentStatement, statements[0]); + } + } + else { + body.add(assignmentStatement); + } + } + else { + final PsiExpressionStatement callStatement = ((PsiExpressionStatement)statements[0]); + if (!JavaHighlightUtil.isSuperOrThisCall(callStatement, false, true)) { + final PsiMethodCallExpression superConstructorCall = + (PsiMethodCallExpression)callStatement.getExpression(); + PsiAssignmentExpression assignmentExpression = + (PsiAssignmentExpression)myFactory.createExpressionFromText( + assignmentText, superConstructorCall + ); + PsiNewExpression newExpression = + (PsiNewExpression)assignmentExpression.getRExpression(); + if (!myIsInnerClassNeeded) { + newExpression.getClassReference().replace(baseClassReference); + } + assignmentExpression = (PsiAssignmentExpression)CodeStyleManager.getInstance(myProject).reformat(assignmentExpression); + newExpression.getArgumentList().replace(superConstructorCall.getArgumentList()); + superConstructorCall.replace(assignmentExpression); + } + } + } } - // fix abstract methods - { - class InnerClassAbstractMethod extends InnerClassMethod { - private final boolean myImplicitImplementation; - - public InnerClassAbstractMethod(PsiMethod method, final boolean implicitImplementation) { - super(method); - myImplicitImplementation = implicitImplementation; - } - - public void createMethod(PsiClass innerClass) - throws IncorrectOperationException { - PsiSubstitutor substitutor = getSuperSubstitutor(myMethod.getContainingClass()); - PsiMethod method = delegateMethod(myClass.getName() + ".this", myMethod, substitutor); - final PsiClass containingClass = myMethod.getContainingClass(); - if (myBaseClass.isInterface() || containingClass.isInterface()) { - PsiUtil.setModifierProperty(method, PsiModifier.PUBLIC, true); - } - innerClass.add(method); - if (!myImplicitImplementation) { - final MethodSignature signature = myMethod.getSignature(substitutor); - PsiMethod outerMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, false); - if (outerMethod == null) { - String visibility = checkOuterClassAbstractMethod(signature); - PsiMethod newOuterMethod = (PsiMethod)myClass.add(myMethod); - PsiUtil.setModifierProperty(newOuterMethod, visibility, true); - final PsiDocComment docComment = newOuterMethod.getDocComment(); - if (docComment != null) { - docComment.delete(); - } + private boolean isFieldInitializerNeeded() { + if (myBaseClass.isInterface()) { + return true; + } + PsiMethod[] constructors = myClass.getConstructors(); + for (PsiMethod constructor : constructors) { + final PsiStatement[] statements = constructor.getBody().getStatements(); + if (statements.length > 0 && JavaHighlightUtil.isSuperOrThisCall(statements[0], true, false)) { + return false; } - } - } - } - PsiMethod[] methods = myBaseClass.getAllMethods(); - - for (PsiMethod method : methods) { - if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { - final MethodSignature signature = method.getSignature(getSuperSubstitutor(method.getContainingClass())); - PsiMethod classMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, true); - if (classMethod == null || classMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - result.add(new InnerClassAbstractMethod(method, false)); - } else if ((myBaseClass.isInterface() && classMethod.getContainingClass() != myClass)) { // IDEADEV-19675 - result.add(new InnerClassAbstractMethod(method, true)); - } - } - } + } + return true; } + private List getInnerClassMethods() { + ArrayList result = new ArrayList(); + + // find all neccessary constructors + if (!myBaseClass.isInterface()) { + PsiMethod[] constructors = myClass.getConstructors(); + for (PsiMethod constructor : constructors) { + final PsiStatement[] statements = constructor.getBody().getStatements(); + if (statements.length > 0 && JavaHighlightUtil.isSuperOrThisCall(statements[0], true, false)) { + final PsiMethodCallExpression superConstructorCall = + (PsiMethodCallExpression)((PsiExpressionStatement)statements[0]).getExpression(); + PsiElement superConstructor = superConstructorCall.getMethodExpression().resolve(); + if (superConstructor instanceof PsiMethod && ((PsiMethod)superConstructor).isConstructor()) { + result.add(new InnerClassConstructor((PsiMethod)superConstructor)); + } + } + } + } - return result; - } - - private void showObjectUpcastedUsageView(final ObjectUpcastedUsageInfo[] usages) { - UsageViewPresentation presentation = new UsageViewPresentation(); - presentation.setTargetsNodeText(RefactoringLocalize.replacingInheritanceWithDelegation().get()); - presentation.setCodeUsagesString(RefactoringLocalize.instancesCastedToJavaLangObject().get()); - final LocalizeValue upcastedString = RefactoringLocalize.instancesUpcastedToObject(); - presentation.setUsagesString(upcastedString.get()); - presentation.setTabText(upcastedString.get()); - - UsageViewManager manager = UsageViewManager.getInstance(myProject); - manager.showUsages( - new UsageTarget[]{new PsiElement2UsageTargetAdapter(myClass)}, - UsageInfoToUsageConverter.convert(new UsageInfoToUsageConverter.TargetElementsDescriptor(myClass), usages), - presentation - ); - - WindowManager.getInstance().getStatusBar(myProject).setInfo(RefactoringLocalize.instancesUpcastedToJavaLangObjectFound().get()); - } - - /** - * @param methodSignature - * @return Visibility - */ - @PsiModifier.ModifierConstant - private String checkOuterClassAbstractMethod(MethodSignature methodSignature) { - String visibility = PsiModifier.PROTECTED; - for (PsiMethod method : myDelegatedMethods) { - MethodSignature otherSignature = method.getSignature(getSuperSubstitutor(method.getContainingClass())); - - if (MethodSignatureUtil.areSignaturesEqual(otherSignature, methodSignature)) { - visibility = VisibilityUtil.getHighestVisibility( - visibility, - VisibilityUtil.getVisibilityModifier(method.getModifierList()) - ); - myAbstractDelegatedMethods.add(method); - } - } - return visibility; - } + // find overriding/implementing method + { + class InnerClassOverridingMethod extends InnerClassMethod { + public InnerClassOverridingMethod(PsiMethod method) { + super(method); + } + + public void createMethod(PsiClass innerClass) + throws IncorrectOperationException { + OverriddenMethodClassMemberReferencesVisitor visitor = new OverriddenMethodClassMemberReferencesVisitor(); + myClass.accept(visitor); + final List actions = visitor.getPsiActions(); + for (PsiAction action : actions) { + action.run(); + } + innerClass.add(myMethod); + myMethod.delete(); + // myMethod.replace(delegateMethod(myMethod)); + } + } - private Set getOverriddenMethods() { - LinkedHashSet result = new LinkedHashSet(); + for (PsiMethod method : myOverriddenMethods) { + result.add(new InnerClassOverridingMethod(method)); + } + } - PsiMethod[] methods = myClass.getMethods(); - for (PsiMethod method : methods) { - if (findSuperMethodInBaseClass(method) != null) { - result.add(method); - } - } - return result; - } - - @Nullable - private PsiMethod findSuperMethodInBaseClass(PsiMethod method) { - final PsiMethod[] superMethods = method.findSuperMethods(); - for (PsiMethod superMethod : superMethods) { - PsiClass containingClass = superMethod.getContainingClass(); - if (InheritanceUtil.isInheritorOrSelf(myBaseClass, containingClass, true)) { - String qName = containingClass.getQualifiedName(); - if (qName == null || !CommonClassNames.JAVA_LANG_OBJECT.equals(qName)) { - return superMethod; - } - } - } - return null; - } - - - protected String getCommandName() { - return RefactoringLocalize.replaceInheritanceWithDelegationCommand(DescriptiveNameUtil.getDescriptiveName(myClass)).get(); - } - - private Set getAllBaseClassMembers() { - HashSet result = new HashSet(); - addAll(result, myBaseClass.getAllFields()); - addAll(result, myBaseClass.getAllInnerClasses()); - addAll(result, myBaseClass.getAllMethods()); - - //remove java.lang.Object members - for (Iterator iterator = result.iterator(); iterator.hasNext(); ) { - PsiMember member = iterator.next(); - if (CommonClassNames.JAVA_LANG_OBJECT.equals(member.getContainingClass().getQualifiedName())) { - iterator.remove(); - } - } - return Collections.unmodifiableSet(result); - } - - private Set getAllBases() { - HashSet temp = new HashSet(); - InheritanceUtil.getSuperClasses(myBaseClass, temp, true); - temp.add(myBaseClass); - return Collections.unmodifiableSet(temp); - } - - private static void addAll(Collection collection, T[] objs) { - for (T obj : objs) { - collection.add(obj); - } - } + // fix abstract methods + { + class InnerClassAbstractMethod extends InnerClassMethod { + private final boolean myImplicitImplementation; + + public InnerClassAbstractMethod(PsiMethod method, final boolean implicitImplementation) { + super(method); + myImplicitImplementation = implicitImplementation; + } + + public void createMethod(PsiClass innerClass) + throws IncorrectOperationException { + PsiSubstitutor substitutor = getSuperSubstitutor(myMethod.getContainingClass()); + PsiMethod method = delegateMethod(myClass.getName() + ".this", myMethod, substitutor); + final PsiClass containingClass = myMethod.getContainingClass(); + if (myBaseClass.isInterface() || containingClass.isInterface()) { + PsiUtil.setModifierProperty(method, PsiModifier.PUBLIC, true); + } + innerClass.add(method); + if (!myImplicitImplementation) { + final MethodSignature signature = myMethod.getSignature(substitutor); + PsiMethod outerMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, false); + if (outerMethod == null) { + String visibility = checkOuterClassAbstractMethod(signature); + PsiMethod newOuterMethod = (PsiMethod)myClass.add(myMethod); + PsiUtil.setModifierProperty(newOuterMethod, visibility, true); + final PsiDocComment docComment = newOuterMethod.getDocComment(); + if (docComment != null) { + docComment.delete(); + } + } + } + } + } + PsiMethod[] methods = myBaseClass.getAllMethods(); + + for (PsiMethod method : methods) { + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + final MethodSignature signature = method.getSignature(getSuperSubstitutor(method.getContainingClass())); + PsiMethod classMethod = MethodSignatureUtil.findMethodBySignature(myClass, signature, true); + if (classMethod == null || classMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + result.add(new InnerClassAbstractMethod(method, false)); + } + else if ((myBaseClass.isInterface() && classMethod.getContainingClass() != myClass)) { // IDEADEV-19675 + result.add(new InnerClassAbstractMethod(method, true)); + } + } + } + } - private boolean isDelegated(PsiMember classMember) { - if (!(classMember instanceof PsiMethod)) { - return false; - } - final PsiMethod method = (PsiMethod)classMember; - for (PsiMethod delegatedMethod : myDelegatedMethods) { - //methods reside in base class, so no substitutor needed - if (MethodSignatureUtil.areSignaturesEqual( - method.getSignature(PsiSubstitutor.EMPTY), - delegatedMethod.getSignature(PsiSubstitutor.EMPTY) - )) { - return true; - } + + return result; } - return false; - } - private class MyClassInheritorMemberReferencesVisitor extends ClassMemberReferencesVisitor { - private final List myUsageInfoStorage; - private final ClassInstanceScanner.ClassInstanceReferenceVisitor myInstanceVisitor; + private void showObjectUpcastedUsageView(final ObjectUpcastedUsageInfo[] usages) { + UsageViewPresentation presentation = new UsageViewPresentation(); + presentation.setTargetsNodeText(RefactoringLocalize.replacingInheritanceWithDelegation().get()); + presentation.setCodeUsagesString(RefactoringLocalize.instancesCastedToJavaLangObject().get()); + final LocalizeValue upcastedString = RefactoringLocalize.instancesUpcastedToObject(); + presentation.setUsagesString(upcastedString.get()); + presentation.setTabText(upcastedString.get()); - MyClassInheritorMemberReferencesVisitor( - PsiClass aClass, - List usageInfoStorage, - ClassInstanceScanner.ClassInstanceReferenceVisitor instanceScanner - ) { - super(aClass); + UsageViewManager manager = UsageViewManager.getInstance(myProject); + manager.showUsages( + new UsageTarget[]{new PsiElement2UsageTargetAdapter(myClass)}, + UsageInfoToUsageConverter.convert(new UsageInfoToUsageConverter.TargetElementsDescriptor(myClass), usages), + presentation + ); - myUsageInfoStorage = usageInfoStorage; - myInstanceVisitor = instanceScanner; + WindowManager.getInstance().getStatusBar(myProject).setInfo(RefactoringLocalize.instancesUpcastedToJavaLangObjectFound().get()); + } + + /** + * @param methodSignature + * @return Visibility + */ + @PsiModifier.ModifierConstant + private String checkOuterClassAbstractMethod(MethodSignature methodSignature) { + String visibility = PsiModifier.PROTECTED; + for (PsiMethod method : myDelegatedMethods) { + MethodSignature otherSignature = method.getSignature(getSuperSubstitutor(method.getContainingClass())); + + if (MethodSignatureUtil.areSignaturesEqual(otherSignature, methodSignature)) { + visibility = VisibilityUtil.getHighestVisibility( + visibility, + VisibilityUtil.getVisibilityModifier(method.getModifierList()) + ); + myAbstractDelegatedMethods.add(method); + } + } + return visibility; } - protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { - if ("super".equals(classMemberReference.getText()) && classMemberReference.getParent() instanceof PsiMethodCallExpression) { - return; - } - - if (classMember != null && myBaseClassMembers.contains(classMember) && !isDelegated(classMember)) { - final FieldAccessibility delegateFieldVisibility = new FieldAccessibility(true, getPsiClass()); - final InheritanceToDelegationUsageInfo usageInfo; - if (classMemberReference instanceof PsiReferenceExpression referenceExpression) { - if (referenceExpression.getQualifierExpression() == null) { - usageInfo = new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference, classMember, delegateFieldVisibility); - } else { - usageInfo = new NonDelegatedMemberUsageInfo( - referenceExpression.getQualifierExpression(), - classMember, delegateFieldVisibility - ); - } - myUsageInfoStorage.add(usageInfo); - } else /*if (classMemberReference instanceof PsiJavaCodeReferenceElement)*/ { - usageInfo = new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference, classMember, delegateFieldVisibility); - myUsageInfoStorage.add(usageInfo); - } - } + private Set getOverriddenMethods() { + LinkedHashSet result = new LinkedHashSet(); + + PsiMethod[] methods = myClass.getMethods(); + for (PsiMethod method : methods) { + if (findSuperMethodInBaseClass(method) != null) { + result.add(method); + } + } + return result; + } + + @Nullable + private PsiMethod findSuperMethodInBaseClass(PsiMethod method) { + final PsiMethod[] superMethods = method.findSuperMethods(); + for (PsiMethod superMethod : superMethods) { + PsiClass containingClass = superMethod.getContainingClass(); + if (InheritanceUtil.isInheritorOrSelf(myBaseClass, containingClass, true)) { + String qName = containingClass.getQualifiedName(); + if (qName == null || !CommonClassNames.JAVA_LANG_OBJECT.equals(qName)) { + return superMethod; + } + } + } + return null; } - @Override - public void visitThisExpression(PsiThisExpression expression) { - ClassInstanceScanner.processNonArrayExpression(myInstanceVisitor, expression, null); + + protected String getCommandName() { + return RefactoringLocalize.replaceInheritanceWithDelegationCommand(DescriptiveNameUtil.getDescriptiveName(myClass)).get(); } - } - private class MyClassMemberReferencesVisitor extends MyClassInheritorMemberReferencesVisitor { - MyClassMemberReferencesVisitor(List usageInfoStorage, ClassInstanceScanner.ClassInstanceReferenceVisitor instanceScanner) { - super(InheritanceToDelegationProcessor.this.myClass, usageInfoStorage, instanceScanner); + private Set getAllBaseClassMembers() { + HashSet result = new HashSet(); + addAll(result, myBaseClass.getAllFields()); + addAll(result, myBaseClass.getAllInnerClasses()); + addAll(result, myBaseClass.getAllMethods()); + + //remove java.lang.Object members + for (Iterator iterator = result.iterator(); iterator.hasNext(); ) { + PsiMember member = iterator.next(); + if (CommonClassNames.JAVA_LANG_OBJECT.equals(member.getContainingClass().getQualifiedName())) { + iterator.remove(); + } + } + return Collections.unmodifiableSet(result); } - @Override - public void visitMethod(PsiMethod method) { - if (!myOverriddenMethods.contains(method)) { - super.visitMethod(method); - } + private Set getAllBases() { + HashSet temp = new HashSet(); + InheritanceUtil.getSuperClasses(myBaseClass, temp, true); + temp.add(myBaseClass); + return Collections.unmodifiableSet(temp); } - } - - interface PsiAction { - void run() throws IncorrectOperationException; - } - - /** - * This visitor should be called for overriden methods before they are moved to an inner class - */ - private class OverriddenMethodClassMemberReferencesVisitor extends ClassMemberReferencesVisitor { - private final ArrayList myPsiActions; - private final PsiThisExpression myQualifiedThis; - - OverriddenMethodClassMemberReferencesVisitor() throws IncorrectOperationException { - super(myClass); - myPsiActions = new ArrayList(); - final PsiJavaCodeReferenceElement classReferenceElement = myFactory.createClassReferenceElement(myClass); - myQualifiedThis = (PsiThisExpression)myFactory.createExpressionFromText("A.this", null); - myQualifiedThis.getQualifier().replace(classReferenceElement); + + private static void addAll(Collection collection, T[] objs) { + for (T obj : objs) { + collection.add(obj); + } } - public List getPsiActions() { - return myPsiActions; + private boolean isDelegated(PsiMember classMember) { + if (!(classMember instanceof PsiMethod)) { + return false; + } + final PsiMethod method = (PsiMethod)classMember; + for (PsiMethod delegatedMethod : myDelegatedMethods) { + //methods reside in base class, so no substitutor needed + if (MethodSignatureUtil.areSignaturesEqual( + method.getSignature(PsiSubstitutor.EMPTY), + delegatedMethod.getSignature(PsiSubstitutor.EMPTY) + )) { + return true; + } + } + return false; } - class QualifyThis implements PsiAction { - private final PsiThisExpression myThisExpression; + private class MyClassInheritorMemberReferencesVisitor extends ClassMemberReferencesVisitor { + private final List myUsageInfoStorage; + private final ClassInstanceScanner.ClassInstanceReferenceVisitor myInstanceVisitor; - QualifyThis(PsiThisExpression thisExpression) { - myThisExpression = thisExpression; - } + MyClassInheritorMemberReferencesVisitor( + PsiClass aClass, + List usageInfoStorage, + ClassInstanceScanner.ClassInstanceReferenceVisitor instanceScanner + ) { + super(aClass); - public void run() throws IncorrectOperationException { - myThisExpression.replace(myQualifiedThis); - } - } + myUsageInfoStorage = usageInfoStorage; + myInstanceVisitor = instanceScanner; + } + + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if ("super".equals(classMemberReference.getText()) && classMemberReference.getParent() instanceof PsiMethodCallExpression) { + return; + } - class QualifyName implements PsiAction { - private final PsiReferenceExpression myRef; - private final String myReferencedName; - - QualifyName(PsiReferenceExpression ref, String name) { - myRef = ref; - myReferencedName = name; - } - - public void run() throws IncorrectOperationException { - PsiReferenceExpression newRef = - (PsiReferenceExpression)myFactory.createExpressionFromText("a." + myReferencedName, null); - newRef.getQualifierExpression().replace(myQualifiedThis); - myRef.replace(newRef); - } + if (classMember != null && myBaseClassMembers.contains(classMember) && !isDelegated(classMember)) { + final FieldAccessibility delegateFieldVisibility = new FieldAccessibility(true, getPsiClass()); + final InheritanceToDelegationUsageInfo usageInfo; + if (classMemberReference instanceof PsiReferenceExpression referenceExpression) { + if (referenceExpression.getQualifierExpression() == null) { + usageInfo = new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference, classMember, delegateFieldVisibility); + } + else { + usageInfo = new NonDelegatedMemberUsageInfo( + referenceExpression.getQualifierExpression(), + classMember, delegateFieldVisibility + ); + } + myUsageInfoStorage.add(usageInfo); + } + else /*if (classMemberReference instanceof PsiJavaCodeReferenceElement)*/ { + usageInfo = new UnqualifiedNonDelegatedMemberUsageInfo(classMemberReference, classMember, delegateFieldVisibility); + myUsageInfoStorage.add(usageInfo); + } + } + } + + @Override + public void visitThisExpression(PsiThisExpression expression) { + ClassInstanceScanner.processNonArrayExpression(myInstanceVisitor, expression, null); + } } - class QualifyWithField implements PsiAction { - private final PsiReferenceExpression myReference; - private final String myReferencedName; + private class MyClassMemberReferencesVisitor extends MyClassInheritorMemberReferencesVisitor { + MyClassMemberReferencesVisitor( + List usageInfoStorage, + ClassInstanceScanner.ClassInstanceReferenceVisitor instanceScanner + ) { + super(InheritanceToDelegationProcessor.this.myClass, usageInfoStorage, instanceScanner); + } - public QualifyWithField(final PsiReferenceExpression reference, final String name) { - myReference = reference; - myReferencedName = name; - } + @Override + public void visitMethod(PsiMethod method) { + if (!myOverriddenMethods.contains(method)) { + super.visitMethod(method); + } + } + } - public void run() throws IncorrectOperationException { - PsiReferenceExpression newRef = - (PsiReferenceExpression)myFactory.createExpressionFromText(myFieldName + "." + myReferencedName, null); - myReference.replace(newRef); - } + interface PsiAction { + void run() throws IncorrectOperationException; } - protected void visitClassMemberReferenceExpression(PsiMember classMember, PsiReferenceExpression classMemberReference) { - if (classMember instanceof PsiField) { - final PsiField field = (PsiField)classMember; + /** + * This visitor should be called for overriden methods before they are moved to an inner class + */ + private class OverriddenMethodClassMemberReferencesVisitor extends ClassMemberReferencesVisitor { + private final ArrayList myPsiActions; + private final PsiThisExpression myQualifiedThis; - if (field.getContainingClass().equals(myClass)) { - final String name = field.getName(); - final PsiField baseField = myBaseClass.findFieldByName(name, true); - if (baseField != null) { - myPsiActions.add(new QualifyName(classMemberReference, name)); - } else if (classMemberReference.getQualifierExpression() instanceof PsiThisExpression) { - myPsiActions.add(new QualifyThis((PsiThisExpression)classMemberReference.getQualifierExpression())); - } + OverriddenMethodClassMemberReferencesVisitor() throws IncorrectOperationException { + super(myClass); + myPsiActions = new ArrayList(); + final PsiJavaCodeReferenceElement classReferenceElement = myFactory.createClassReferenceElement(myClass); + myQualifiedThis = (PsiThisExpression)myFactory.createExpressionFromText("A.this", null); + myQualifiedThis.getQualifier().replace(classReferenceElement); } - } else if (classMember instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)classMember; - if (method.getContainingClass().equals(myClass)) { - if (!myOverriddenMethods.contains(method)) { - final PsiMethod baseMethod = findSuperMethodInBaseClass(method); - if (baseMethod != null) { - myPsiActions.add(new QualifyName(classMemberReference, baseMethod.getName())); - } else if (classMemberReference.getQualifierExpression() instanceof PsiThisExpression) { - myPsiActions.add(new QualifyThis((PsiThisExpression)classMemberReference.getQualifierExpression())); - } - } else if (!myDelegatedMethods.contains(method)) { - myPsiActions.add(new QualifyWithField(classMemberReference, method.getName())); - } + public List getPsiActions() { + return myPsiActions; } - } - } - @Override - public void visitThisExpression(final PsiThisExpression expression) { - class Visitor implements ClassInstanceScanner.ClassInstanceReferenceVisitor { - public void visitQualifier(PsiReferenceExpression qualified, PsiExpression instanceRef, PsiElement referencedInstance) { - LOG.assertTrue(false); + class QualifyThis implements PsiAction { + private final PsiThisExpression myThisExpression; + + QualifyThis(PsiThisExpression thisExpression) { + myThisExpression = thisExpression; + } + + public void run() throws IncorrectOperationException { + myThisExpression.replace(myQualifiedThis); + } } - public void visitTypeCast(PsiTypeCastExpression typeCastExpression, PsiExpression instanceRef, PsiElement referencedInstance) { - processType(typeCastExpression.getCastType().getType()); + class QualifyName implements PsiAction { + private final PsiReferenceExpression myRef; + private final String myReferencedName; + + QualifyName(PsiReferenceExpression ref, String name) { + myRef = ref; + myReferencedName = name; + } + + public void run() throws IncorrectOperationException { + PsiReferenceExpression newRef = + (PsiReferenceExpression)myFactory.createExpressionFromText("a." + myReferencedName, null); + newRef.getQualifierExpression().replace(myQualifiedThis); + myRef.replace(newRef); + } } - public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) { - processType(expectedType); + class QualifyWithField implements PsiAction { + private final PsiReferenceExpression myReference; + private final String myReferencedName; + + public QualifyWithField(final PsiReferenceExpression reference, final String name) { + myReference = reference; + myReferencedName = name; + } + + public void run() throws IncorrectOperationException { + PsiReferenceExpression newRef = + (PsiReferenceExpression)myFactory.createExpressionFromText(myFieldName + "." + myReferencedName, null); + myReference.replace(newRef); + } } - public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType, PsiElement referencedInstance) { - LOG.assertTrue(false); + protected void visitClassMemberReferenceExpression(PsiMember classMember, PsiReferenceExpression classMemberReference) { + if (classMember instanceof PsiField) { + final PsiField field = (PsiField)classMember; + + if (field.getContainingClass().equals(myClass)) { + final String name = field.getName(); + final PsiField baseField = myBaseClass.findFieldByName(name, true); + if (baseField != null) { + myPsiActions.add(new QualifyName(classMemberReference, name)); + } + else if (classMemberReference.getQualifierExpression() instanceof PsiThisExpression) { + myPsiActions.add(new QualifyThis((PsiThisExpression)classMemberReference.getQualifierExpression())); + } + } + } + else if (classMember instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)classMember; + + if (method.getContainingClass().equals(myClass)) { + if (!myOverriddenMethods.contains(method)) { + final PsiMethod baseMethod = findSuperMethodInBaseClass(method); + if (baseMethod != null) { + myPsiActions.add(new QualifyName(classMemberReference, baseMethod.getName())); + } + else if (classMemberReference.getQualifierExpression() instanceof PsiThisExpression) { + myPsiActions.add(new QualifyThis((PsiThisExpression)classMemberReference.getQualifierExpression())); + } + } + else if (!myDelegatedMethods.contains(method)) { + myPsiActions.add(new QualifyWithField(classMemberReference, method.getName())); + } + } + } } - private void processType(PsiType type) { - final PsiClass resolved = PsiUtil.resolveClassInType(type); - if (resolved != null && !myBaseClassBases.contains(resolved)) { - myPsiActions.add(new QualifyThis(expression)); - } + @Override + public void visitThisExpression(final PsiThisExpression expression) { + class Visitor implements ClassInstanceScanner.ClassInstanceReferenceVisitor { + public void visitQualifier(PsiReferenceExpression qualified, PsiExpression instanceRef, PsiElement referencedInstance) { + LOG.assertTrue(false); + } + + public void visitTypeCast( + PsiTypeCastExpression typeCastExpression, + PsiExpression instanceRef, + PsiElement referencedInstance + ) { + processType(typeCastExpression.getCastType().getType()); + } + + public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) { + processType(expectedType); + } + + public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType, PsiElement referencedInstance) { + LOG.assertTrue(false); + } + + private void processType(PsiType type) { + final PsiClass resolved = PsiUtil.resolveClassInType(type); + if (resolved != null && !myBaseClassBases.contains(resolved)) { + myPsiActions.add(new QualifyThis(expression)); + } + } + } + Visitor visitor = new Visitor(); + ClassInstanceScanner.processNonArrayExpression(visitor, expression, null); } - } - Visitor visitor = new Visitor(); - ClassInstanceScanner.processNonArrayExpression(visitor, expression, null); - } - protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + } } - } - private final class MyClassInstanceReferenceVisitor implements ClassInstanceScanner.ClassInstanceReferenceVisitor { - private final PsiClass myClass; - private final List myUsageInfoStorage; - private final Set myImplementedInterfaces; + private final class MyClassInstanceReferenceVisitor implements ClassInstanceScanner.ClassInstanceReferenceVisitor { + private final PsiClass myClass; + private final List myUsageInfoStorage; + private final Set myImplementedInterfaces; - public MyClassInstanceReferenceVisitor(PsiClass aClass, List usageInfoStorage) { - myClass = aClass; - myUsageInfoStorage = usageInfoStorage; - myImplementedInterfaces = getImplementedInterfaces(); - } + public MyClassInstanceReferenceVisitor(PsiClass aClass, List usageInfoStorage) { + myClass = aClass; + myUsageInfoStorage = usageInfoStorage; + myImplementedInterfaces = getImplementedInterfaces(); + } - public Set getImplementedInterfaces() { - PsiClass aClass = myClass; - HashSet result = new HashSet(); - while (aClass != null && !myManager.areElementsEquivalent(aClass, myBaseClass)) { - final PsiClassType[] implementsTypes = aClass.getImplementsListTypes(); - for (PsiClassType implementsType : implementsTypes) { - PsiClass resolved = implementsType.resolve(); - if (resolved != null && !myManager.areElementsEquivalent(resolved, myBaseClass)) { - result.add(resolved); - InheritanceUtil.getSuperClasses(resolved, result, true); - } - } - - aClass = aClass.getSuperClass(); - } - return result; - } + public Set getImplementedInterfaces() { + PsiClass aClass = myClass; + HashSet result = new HashSet(); + while (aClass != null && !myManager.areElementsEquivalent(aClass, myBaseClass)) { + final PsiClassType[] implementsTypes = aClass.getImplementsListTypes(); + for (PsiClassType implementsType : implementsTypes) { + PsiClass resolved = implementsType.resolve(); + if (resolved != null && !myManager.areElementsEquivalent(resolved, myBaseClass)) { + result.add(resolved); + InheritanceUtil.getSuperClasses(resolved, result, true); + } + } + + aClass = aClass.getSuperClass(); + } + return result; + } - public void visitQualifier(PsiReferenceExpression qualified, PsiExpression instanceRef, PsiElement referencedInstance) { - final PsiExpression qualifierExpression = qualified.getQualifierExpression(); + public void visitQualifier(PsiReferenceExpression qualified, PsiExpression instanceRef, PsiElement referencedInstance) { + final PsiExpression qualifierExpression = qualified.getQualifierExpression(); - // do not add usages inside a class - if (qualifierExpression == null - || qualifierExpression instanceof PsiThisExpression - || qualifierExpression instanceof PsiSuperExpression) { - return; - } + // do not add usages inside a class + if (qualifierExpression == null + || qualifierExpression instanceof PsiThisExpression + || qualifierExpression instanceof PsiSuperExpression) { + return; + } - PsiElement resolved = qualified.resolve(); - if (resolved != null && (myBaseClassMembers.contains(resolved) || myOverriddenMethods.contains(resolved)) - && !isDelegated((PsiMember)resolved)) { - myUsageInfoStorage.add(new NonDelegatedMemberUsageInfo(instanceRef, resolved, getFieldAccessibility(instanceRef))); - } - } + PsiElement resolved = qualified.resolve(); + if (resolved != null && (myBaseClassMembers.contains(resolved) || myOverriddenMethods.contains(resolved)) + && !isDelegated((PsiMember)resolved)) { + myUsageInfoStorage.add(new NonDelegatedMemberUsageInfo(instanceRef, resolved, getFieldAccessibility(instanceRef))); + } + } - public void visitTypeCast(PsiTypeCastExpression typeCastExpression, PsiExpression instanceRef, PsiElement referencedInstance) { - processTypedUsage(typeCastExpression.getCastType().getType(), instanceRef); - } + public void visitTypeCast(PsiTypeCastExpression typeCastExpression, PsiExpression instanceRef, PsiElement referencedInstance) { + processTypedUsage(typeCastExpression.getCastType().getType(), instanceRef); + } - public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) { - processTypedUsage(expectedType, instanceRef); - } + public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) { + processTypedUsage(expectedType, instanceRef); + } - public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType, PsiElement referencedInstance) { - } + public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType, PsiElement referencedInstance) { + } - private void processTypedUsage(PsiType type, PsiExpression instanceRef) { - final PsiClass aClass = PsiUtil.resolveClassInType(type); - if (aClass == null) { - return; - } - String qName = aClass.getQualifiedName(); - if (qName != null && CommonClassNames.JAVA_LANG_OBJECT.equals(qName)) { - myUsageInfoStorage.add(new ObjectUpcastedUsageInfo(instanceRef, aClass, getFieldAccessibility(instanceRef))); - } else { - if (myBaseClassBases.contains(aClass) - && !myImplementedInterfaces.contains(aClass) && !myDelegatedInterfaces.contains(aClass)) { - myUsageInfoStorage.add(new UpcastedUsageInfo(instanceRef, aClass, getFieldAccessibility(instanceRef))); - } - } + private void processTypedUsage(PsiType type, PsiExpression instanceRef) { + final PsiClass aClass = PsiUtil.resolveClassInType(type); + if (aClass == null) { + return; + } + String qName = aClass.getQualifiedName(); + if (qName != null && CommonClassNames.JAVA_LANG_OBJECT.equals(qName)) { + myUsageInfoStorage.add(new ObjectUpcastedUsageInfo(instanceRef, aClass, getFieldAccessibility(instanceRef))); + } + else { + if (myBaseClassBases.contains(aClass) + && !myImplementedInterfaces.contains(aClass) && !myDelegatedInterfaces.contains(aClass)) { + myUsageInfoStorage.add(new UpcastedUsageInfo(instanceRef, aClass, getFieldAccessibility(instanceRef))); + } + } + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java index 554d7651d4..1e5e732f67 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineConstantFieldProcessor.java @@ -53,8 +53,7 @@ * @author ven */ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.inline" + - ".InlineConstantFieldProcessor"); + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.inline.InlineConstantFieldProcessor"); private PsiField myField; private final PsiReferenceExpression myRefExpr; private final boolean myInlineThisOnly; @@ -86,8 +85,8 @@ public InlineConstantFieldProcessor( mySearchForTextOccurrences = searchForTextOccurrences; } - @Override @Nonnull + @Override protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { return new InlineViewDescriptor(myField); } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineMethodProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineMethodProcessor.java index 64137fcc3b..e9e49013ae 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineMethodProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineMethodProcessor.java @@ -59,13 +59,14 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.NonCodeUsageInfo; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; import consulo.util.dataholder.Key; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.jetbrains.annotations.NonNls; @@ -73,1041 +74,1173 @@ import java.util.*; public class InlineMethodProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(InlineMethodProcessor.class); - - private PsiMethod myMethod; - private PsiJavaCodeReferenceElement myReference; - private final Editor myEditor; - private final boolean myInlineThisOnly; - private final boolean mySearchInComments; - private final boolean mySearchForTextOccurrences; - - private final PsiManager myManager; - private final PsiElementFactory myFactory; - private final CodeStyleManager myCodeStyleManager; - private final JavaCodeStyleManager myJavaCodeStyle; - - private PsiCodeBlock[] myAddedBraces; - private final String myDescriptiveName; - private Map myAddedClassInitializers; - private PsiMethod myMethodCopy; - private Map myInliners; - - public InlineMethodProcessor(@Nonnull Project project, - @Nonnull PsiMethod method, - @Nullable PsiJavaCodeReferenceElement reference, - Editor editor, - boolean isInlineThisOnly) { - this(project, method, reference, editor, isInlineThisOnly, false, false); - } + private static final Logger LOG = Logger.getInstance(InlineMethodProcessor.class); + + private PsiMethod myMethod; + private PsiJavaCodeReferenceElement myReference; + private final Editor myEditor; + private final boolean myInlineThisOnly; + private final boolean mySearchInComments; + private final boolean mySearchForTextOccurrences; + + private final PsiManager myManager; + private final PsiElementFactory myFactory; + private final CodeStyleManager myCodeStyleManager; + private final JavaCodeStyleManager myJavaCodeStyle; + + private PsiCodeBlock[] myAddedBraces; + private final String myDescriptiveName; + private Map myAddedClassInitializers; + private PsiMethod myMethodCopy; + private Map myInliners; + + public InlineMethodProcessor( + @Nonnull Project project, + @Nonnull PsiMethod method, + @Nullable PsiJavaCodeReferenceElement reference, + Editor editor, + boolean isInlineThisOnly + ) { + this(project, method, reference, editor, isInlineThisOnly, false, false); + } + + public InlineMethodProcessor( + @Nonnull Project project, + @Nonnull PsiMethod method, + @Nullable PsiJavaCodeReferenceElement reference, + Editor editor, + boolean isInlineThisOnly, + boolean searchInComments, + boolean searchForTextOccurrences + ) { + super(project); + myMethod = method; + myReference = reference; + myEditor = editor; + myInlineThisOnly = isInlineThisOnly; + mySearchInComments = searchInComments; + mySearchForTextOccurrences = searchForTextOccurrences; + + myManager = PsiManager.getInstance(myProject); + myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); + myCodeStyleManager = CodeStyleManager.getInstance(myProject); + myJavaCodeStyle = JavaCodeStyleManager.getInstance(myProject); + myDescriptiveName = DescriptiveNameUtil.getDescriptiveName(myMethod); + } + + protected String getCommandName() { + return RefactoringLocalize.inlineMethodCommand(myDescriptiveName).get(); + } + + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new InlineViewDescriptor(myMethod); + } + + @Nonnull + protected UsageInfo[] findUsages() { + if (myInlineThisOnly) { + return new UsageInfo[]{new UsageInfo(myReference)}; + } + Set usages = new HashSet(); + if (myReference != null) { + usages.add(new UsageInfo(myReference)); + } + for (PsiReference reference : ReferencesSearch.search(myMethod)) { + usages.add(new UsageInfo(reference.getElement())); + } - public InlineMethodProcessor(@Nonnull Project project, - @Nonnull PsiMethod method, - @Nullable PsiJavaCodeReferenceElement reference, - Editor editor, - boolean isInlineThisOnly, - boolean searchInComments, - boolean searchForTextOccurrences) { - super(project); - myMethod = method; - myReference = reference; - myEditor = editor; - myInlineThisOnly = isInlineThisOnly; - mySearchInComments = searchInComments; - mySearchForTextOccurrences = searchForTextOccurrences; - - myManager = PsiManager.getInstance(myProject); - myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); - myCodeStyleManager = CodeStyleManager.getInstance(myProject); - myJavaCodeStyle = JavaCodeStyleManager.getInstance(myProject); - myDescriptiveName = DescriptiveNameUtil.getDescriptiveName(myMethod); - } + if (mySearchInComments || mySearchForTextOccurrences) { + final NonCodeUsageInfoFactory infoFactory = new NonCodeUsageInfoFactory(myMethod, myMethod.getName()) { + @Override + public UsageInfo createUsageInfo(@Nonnull PsiElement usage, int startOffset, int endOffset) { + if (PsiTreeUtil.isAncestor(myMethod, usage, false)) { + return null; + } + return super.createUsageInfo(usage, startOffset, endOffset); + } + }; + if (mySearchInComments) { + String stringToSearch = + ElementDescriptionUtil.getElementDescription(myMethod, NonCodeSearchDescriptionLocation.STRINGS_AND_COMMENTS); + TextOccurrencesUtil.addUsagesInStringsAndComments(myMethod, stringToSearch, usages, infoFactory); + } - protected String getCommandName() { - return RefactoringLocalize.inlineMethodCommand(myDescriptiveName).get(); - } + if (mySearchForTextOccurrences) { + String stringToSearch = ElementDescriptionUtil.getElementDescription(myMethod, NonCodeSearchDescriptionLocation.NON_JAVA); + TextOccurrencesUtil + .addTextOccurences(myMethod, stringToSearch, GlobalSearchScope.projectScope(myProject), usages, infoFactory); + } + } - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new InlineViewDescriptor(myMethod); - } + return usages.toArray(new UsageInfo[usages.size()]); + } - @Nonnull - protected UsageInfo[] findUsages() { - if (myInlineThisOnly) return new UsageInfo[]{new UsageInfo(myReference)}; - Set usages = new HashSet(); - if (myReference != null) { - usages.add(new UsageInfo(myReference)); + @Override + protected boolean isPreviewUsages(UsageInfo[] usages) { + for (UsageInfo usage : usages) { + if (usage instanceof NonCodeUsageInfo) { + return true; + } + } + return super.isPreviewUsages(usages); } - for (PsiReference reference : ReferencesSearch.search(myMethod)) { - usages.add(new UsageInfo(reference.getElement())); + + protected void refreshElements(PsiElement[] elements) { + boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod; + LOG.assertTrue(condition); + myMethod = (PsiMethod)elements[0]; } - if (mySearchInComments || mySearchForTextOccurrences) { - final NonCodeUsageInfoFactory infoFactory = new NonCodeUsageInfoFactory(myMethod, myMethod.getName()) { - @Override - public UsageInfo createUsageInfo(@Nonnull PsiElement usage, int startOffset, int endOffset) { - if (PsiTreeUtil.isAncestor(myMethod, usage, false)) return null; - return super.createUsageInfo(usage, startOffset, endOffset); - } - }; - if (mySearchInComments) { - String stringToSearch = ElementDescriptionUtil.getElementDescription(myMethod, NonCodeSearchDescriptionLocation.STRINGS_AND_COMMENTS); - TextOccurrencesUtil.addUsagesInStringsAndComments(myMethod, stringToSearch, usages, infoFactory); - } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + if (!myInlineThisOnly && checkReadOnly()) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myMethod)) { + return false; + } + } + final UsageInfo[] usagesIn = refUsages.get(); + final MultiMap conflicts = new MultiMap(); + + if (!myInlineThisOnly) { + final PsiMethod[] superMethods = myMethod.findSuperMethods(); + for (PsiMethod method : superMethods) { + final LocalizeValue message = method.hasModifierProperty(PsiModifier.ABSTRACT) + ? RefactoringLocalize.inlinedMethodImplementsMethodFrom0(method.getContainingClass().getQualifiedName()) + : RefactoringLocalize.inlinedMethodOverridesMethodFrom0(method.getContainingClass().getQualifiedName()); + conflicts.putValue(method, message.get()); + } - if (mySearchForTextOccurrences) { - String stringToSearch = ElementDescriptionUtil.getElementDescription(myMethod, NonCodeSearchDescriptionLocation.NON_JAVA); - TextOccurrencesUtil - .addTextOccurences(myMethod, stringToSearch, GlobalSearchScope.projectScope(myProject), usages, infoFactory); - } - } + for (UsageInfo info : usagesIn) { + final PsiElement element = info.getElement(); + if (element instanceof PsiDocMethodOrFieldRef && !PsiTreeUtil.isAncestor(myMethod, element, false)) { + conflicts.putValue(element, "Inlined method is used in javadoc"); + } + if (element instanceof PsiMethodReferenceExpression) { + conflicts.putValue(element, "Inlined method is used in method reference"); + } - return usages.toArray(new UsageInfo[usages.size()]); - } + final String errorMessage = checkCalledInSuperOrThisExpr(myMethod.getBody(), element); + if (errorMessage != null) { + conflicts.putValue(element, errorMessage); + } + } + } - @Override - protected boolean isPreviewUsages(UsageInfo[] usages) { - for (UsageInfo usage : usages) { - if (usage instanceof NonCodeUsageInfo) return true; - } - return super.isPreviewUsages(usages); - } + ArrayList refs = convertUsagesToRefs(usagesIn); + myInliners = GenericInlineHandler.initializeInliners(myMethod, () -> myInlineThisOnly, refs); - protected void refreshElements(PsiElement[] elements) { - boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod; - LOG.assertTrue(condition); - myMethod = (PsiMethod) elements[0]; - } + //hack to prevent conflicts 'Cannot inline reference from Java' + myInliners.put(JavaLanguage.INSTANCE, new InlineHandler.Inliner() { + @Nullable + @Override + public MultiMap getConflicts(PsiReference reference, PsiElement referenced) { + return MultiMap.empty(); + } - protected boolean preprocessUsages(Ref refUsages) { - if (!myInlineThisOnly && checkReadOnly()) { - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myMethod)) return false; - } - final UsageInfo[] usagesIn = refUsages.get(); - final MultiMap conflicts = new MultiMap(); - - if (!myInlineThisOnly) { - final PsiMethod[] superMethods = myMethod.findSuperMethods(); - for (PsiMethod method : superMethods) { - final LocalizeValue message = method.hasModifierProperty(PsiModifier.ABSTRACT) - ? RefactoringLocalize.inlinedMethodImplementsMethodFrom0(method.getContainingClass().getQualifiedName()) - : RefactoringLocalize.inlinedMethodOverridesMethodFrom0(method.getContainingClass().getQualifiedName()); - conflicts.putValue(method, message.get()); - } + @Override + public void inlineUsage(@Nonnull UsageInfo usage, @Nonnull PsiElement referenced) { + if (usage instanceof NonCodeUsageInfo) { + return; + } - for (UsageInfo info : usagesIn) { - final PsiElement element = info.getElement(); - if (element instanceof PsiDocMethodOrFieldRef && !PsiTreeUtil.isAncestor(myMethod, element, false)) { - conflicts.putValue(element, "Inlined method is used in javadoc"); - } - if (element instanceof PsiMethodReferenceExpression) { - conflicts.putValue(element, "Inlined method is used in method reference"); - } + throw new UnsupportedOperationException( + "usage: " + usage.getClass().getName() + ", referenced: " + referenced.getClass() + .getName() + "text: " + referenced.getText()); + } + }); - final String errorMessage = checkCalledInSuperOrThisExpr(myMethod.getBody(), element); - if (errorMessage != null) { - conflicts.putValue(element, errorMessage); + for (PsiReference ref : refs) { + GenericInlineHandler.collectConflicts(ref, myMethod, myInliners, conflicts); } - } - } - - ArrayList refs = convertUsagesToRefs(usagesIn); - myInliners = GenericInlineHandler.initializeInliners(myMethod, () -> myInlineThisOnly, refs); - //hack to prevent conflicts 'Cannot inline reference from Java' - myInliners.put(JavaLanguage.INSTANCE, new InlineHandler.Inliner() { - @Nullable - @Override - public MultiMap getConflicts(PsiReference reference, PsiElement referenced) { - return MultiMap.empty(); - } + final PsiReturnStatement[] returnStatements = RefactoringUtil.findReturnStatements(myMethod); + for (PsiReturnStatement statement : returnStatements) { + PsiExpression value = statement.getReturnValue(); + if (value != null && !(value instanceof PsiCallExpression)) { + for (UsageInfo info : usagesIn) { + PsiReference reference = info.getReference(); + if (reference != null) { + InlineUtil.TailCallType type = InlineUtil.getTailCallType(reference); + if (type == InlineUtil.TailCallType.Simple) { + conflicts.putValue(statement, "Inlined result would contain parse errors"); + break; + } + } + } + } + } - @Override - public void inlineUsage(@Nonnull UsageInfo usage, @Nonnull PsiElement referenced) { - if (usage instanceof NonCodeUsageInfo) return; + addInaccessibleMemberConflicts(myMethod, usagesIn, new ReferencedElementsCollector(), conflicts); - throw new UnsupportedOperationException( - "usage: " + usage.getClass().getName() + ", referenced: " + referenced.getClass().getName() + "text: " + referenced.getText()); - } - }); + addInaccessibleSuperCallsConflicts(usagesIn, conflicts); - for (PsiReference ref : refs) { - GenericInlineHandler.collectConflicts(ref, myMethod, myInliners, conflicts); + return showConflicts(conflicts, usagesIn); } - final PsiReturnStatement[] returnStatements = RefactoringUtil.findReturnStatements(myMethod); - for (PsiReturnStatement statement : returnStatements) { - PsiExpression value = statement.getReturnValue(); - if (value != null && !(value instanceof PsiCallExpression)) { + private static ArrayList convertUsagesToRefs(UsageInfo[] usagesIn) { + ArrayList refs = new ArrayList(); for (UsageInfo info : usagesIn) { - PsiReference reference = info.getReference(); - if (reference != null) { - InlineUtil.TailCallType type = InlineUtil.getTailCallType(reference); - if (type == InlineUtil.TailCallType.Simple) { - conflicts.putValue(statement, "Inlined result would contain parse errors"); - break; + final PsiReference ref = info.getReference(); + if (ref != null) { //ref can be null if it is conflict usage info + refs.add(ref); } - } } - } + return refs; } - addInaccessibleMemberConflicts(myMethod, usagesIn, new ReferencedElementsCollector(), conflicts); - - addInaccessibleSuperCallsConflicts(usagesIn, conflicts); - - return showConflicts(conflicts, usagesIn); - } - - private static ArrayList convertUsagesToRefs(UsageInfo[] usagesIn) { - ArrayList refs = new ArrayList(); - for (UsageInfo info : usagesIn) { - final PsiReference ref = info.getReference(); - if (ref != null) { //ref can be null if it is conflict usage info - refs.add(ref); - } + private boolean checkReadOnly() { + return myMethod.isWritable() || myMethod instanceof PsiCompiledElement; } - return refs; - } - private boolean checkReadOnly() { - return myMethod.isWritable() || myMethod instanceof PsiCompiledElement; - } + private void addInaccessibleSuperCallsConflicts(final UsageInfo[] usagesIn, final MultiMap conflicts) { - private void addInaccessibleSuperCallsConflicts(final UsageInfo[] usagesIn, final MultiMap conflicts) { + myMethod.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitClass(PsiClass aClass) { + } - myMethod.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitClass(PsiClass aClass) { - } + @Override + public void visitAnonymousClass(PsiAnonymousClass aClass) { + } - @Override - public void visitAnonymousClass(PsiAnonymousClass aClass) { - } + @Override + public void visitSuperExpression(PsiSuperExpression expression) { + super.visitSuperExpression(expression); + final PsiType type = expression.getType(); + final PsiClass superClass = PsiUtil.resolveClassInType(type); + if (superClass != null) { + final Set targetContainingClasses = new HashSet(); + for (UsageInfo info : usagesIn) { + final PsiElement element = info.getElement(); + if (element != null) { + final PsiClass targetContainingClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + if (targetContainingClass != null && !InheritanceUtil.isInheritorOrSelf( + targetContainingClass, + superClass, + true + )) { + targetContainingClasses.add(targetContainingClass); + } + } + } + if (!targetContainingClasses.isEmpty()) { + final PsiMethodCallExpression methodCallExpression = + PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class); + LOG.assertTrue(methodCallExpression != null); + conflicts.putValue( + expression, + "Inlined method calls " + methodCallExpression.getText() + " which won't be accessed in " + + StringUtil.join(targetContainingClasses, psiClass -> RefactoringUIUtil.getDescription(psiClass, false), ",") + ); + } + } + } + }); + } + + public static void addInaccessibleMemberConflicts( + final PsiElement element, + final UsageInfo[] usages, + final ReferencedElementsCollector collector, + final MultiMap conflicts + ) { + element.accept(collector); + final Map> containersToReferenced = getInaccessible(collector.myReferencedMembers, usages, element); + + final Set containers = containersToReferenced.keySet(); + for (PsiMember container : containers) { + Set referencedInaccessible = containersToReferenced.get(container); + for (PsiMember referenced : referencedInaccessible) { + final String referencedDescription = RefactoringUIUtil.getDescription(referenced, true); + final String containerDescription = RefactoringUIUtil.getDescription(container, true); + LocalizeValue message = RefactoringLocalize.zeroThatIsUsedInInlinedMethodIsNotAccessibleFromCallSiteSIn1( + referencedDescription, + containerDescription + ); + conflicts.putValue(container, CommonRefactoringUtil.capitalize(message.get())); + } + } + } - @Override - public void visitSuperExpression(PsiSuperExpression expression) { - super.visitSuperExpression(expression); - final PsiType type = expression.getType(); - final PsiClass superClass = PsiUtil.resolveClassInType(type); - if (superClass != null) { - final Set targetContainingClasses = new HashSet(); - for (UsageInfo info : usagesIn) { - final PsiElement element = info.getElement(); - if (element != null) { - final PsiClass targetContainingClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); - if (targetContainingClass != null && !InheritanceUtil.isInheritorOrSelf(targetContainingClass, superClass, true)) { - targetContainingClasses.add(targetContainingClass); - } - } - } - if (!targetContainingClasses.isEmpty()) { - final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class); - LOG.assertTrue(methodCallExpression != null); - conflicts.putValue(expression, "Inlined method calls " + methodCallExpression.getText() + " which won't be accessed in " + - StringUtil.join(targetContainingClasses, psiClass -> RefactoringUIUtil.getDescription(psiClass, false), ",")); - } + /** + * Given a set of referencedElements, returns a map from containers (in a sense of ConflictsUtil.getContainer) + * to subsets of referencedElemens that are not accessible from that container + * + * @param referencedElements + * @param usages + * @param elementToInline + */ + private static Map> getInaccessible( + HashSet referencedElements, + UsageInfo[] usages, + PsiElement elementToInline + ) { + Map> result = new HashMap>(); + + for (UsageInfo usage : usages) { + final PsiElement usageElement = usage.getElement(); + if (usageElement == null) { + continue; + } + final PsiElement container = ConflictsUtil.getContainer(usageElement); + if (!(container instanceof PsiMember)) { + continue; // usage in import statement + } + PsiMember memberContainer = (PsiMember)container; + Set inaccessibleReferenced = result.get(memberContainer); + if (inaccessibleReferenced == null) { + inaccessibleReferenced = new HashSet(); + result.put(memberContainer, inaccessibleReferenced); + for (PsiMember member : referencedElements) { + if (PsiTreeUtil.isAncestor(elementToInline, member, false)) { + continue; + } + if (!PsiUtil.isAccessible(usage.getProject(), member, usageElement, null)) { + inaccessibleReferenced.add(member); + } + } + } } - } - }); - } - public static void addInaccessibleMemberConflicts(final PsiElement element, - final UsageInfo[] usages, - final ReferencedElementsCollector collector, - final MultiMap conflicts) { - element.accept(collector); - final Map> containersToReferenced = getInaccessible(collector.myReferencedMembers, usages, element); - - final Set containers = containersToReferenced.keySet(); - for (PsiMember container : containers) { - Set referencedInaccessible = containersToReferenced.get(container); - for (PsiMember referenced : referencedInaccessible) { - final String referencedDescription = RefactoringUIUtil.getDescription(referenced, true); - final String containerDescription = RefactoringUIUtil.getDescription(container, true); - LocalizeValue message = - RefactoringLocalize.zeroThatIsUsedInInlinedMethodIsNotAccessibleFromCallSiteSIn1(referencedDescription, containerDescription); - conflicts.putValue(container, CommonRefactoringUtil.capitalize(message.get())); - } + return result; } - } - /** - * Given a set of referencedElements, returns a map from containers (in a sense of ConflictsUtil.getContainer) - * to subsets of referencedElemens that are not accessible from that container - * - * @param referencedElements - * @param usages - * @param elementToInline - */ - private static Map> getInaccessible(HashSet referencedElements, - UsageInfo[] usages, - PsiElement elementToInline) { - Map> result = new HashMap>(); - - for (UsageInfo usage : usages) { - final PsiElement usageElement = usage.getElement(); - if (usageElement == null) continue; - final PsiElement container = ConflictsUtil.getContainer(usageElement); - if (!(container instanceof PsiMember)) continue; // usage in import statement - PsiMember memberContainer = (PsiMember) container; - Set inaccessibleReferenced = result.get(memberContainer); - if (inaccessibleReferenced == null) { - inaccessibleReferenced = new HashSet(); - result.put(memberContainer, inaccessibleReferenced); - for (PsiMember member : referencedElements) { - if (PsiTreeUtil.isAncestor(elementToInline, member, false)) continue; - if (!PsiUtil.isAccessible(usage.getProject(), member, usageElement, null)) { - inaccessibleReferenced.add(member); - } + protected void performRefactoring(UsageInfo[] usages) { + int col = -1; + int line = -1; + if (myEditor != null) { + col = myEditor.getCaretModel().getLogicalPosition().column; + line = myEditor.getCaretModel().getLogicalPosition().line; + LogicalPosition pos = new LogicalPosition(0, 0); + myEditor.getCaretModel().moveToLogicalPosition(pos); } - } - } - return result; - } + LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); + try { + doRefactoring(usages); + } + finally { + a.finish(); + } - protected void performRefactoring(UsageInfo[] usages) { - int col = -1; - int line = -1; - if (myEditor != null) { - col = myEditor.getCaretModel().getLogicalPosition().column; - line = myEditor.getCaretModel().getLogicalPosition().line; - LogicalPosition pos = new LogicalPosition(0, 0); - myEditor.getCaretModel().moveToLogicalPosition(pos); + if (myEditor != null) { + LogicalPosition pos = new LogicalPosition(line, col); + myEditor.getCaretModel().moveToLogicalPosition(pos); + } } - LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName()); - try { - doRefactoring(usages); - } finally { - a.finish(); + private void doRefactoring(UsageInfo[] usages) { + try { + if (myInlineThisOnly) { + if (myMethod.isConstructor() && InlineMethodHandler.isChainingConstructor(myMethod)) { + PsiCall constructorCall = RefactoringUtil.getEnclosingConstructorCall(myReference); + if (constructorCall != null) { + inlineConstructorCall(constructorCall); + } + } + else { + myReference = addBracesWhenNeeded(new PsiReferenceExpression[]{(PsiReferenceExpression)myReference})[0]; + inlineMethodCall((PsiReferenceExpression)myReference); + } + } + else { + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); + if (myMethod.isConstructor()) { + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element instanceof PsiJavaCodeReferenceElement) { + PsiCall constructorCall = RefactoringUtil.getEnclosingConstructorCall((PsiJavaCodeReferenceElement)element); + if (constructorCall != null) { + inlineConstructorCall(constructorCall); + } + } + else if (element instanceof PsiEnumConstant) { + inlineConstructorCall((PsiEnumConstant)element); + } + else { + GenericInlineHandler.inlineReference(usage, myMethod, myInliners); + } + } + myMethod.delete(); + } + else { + List refExprList = new ArrayList(); + final List imports2Delete = new ArrayList(); + for (final UsageInfo usage : usages) { + final PsiElement element = usage.getElement(); + if (element instanceof PsiReferenceExpression) { + refExprList.add((PsiReferenceExpression)element); + } + else if (element instanceof PsiImportStaticReferenceElement) { + imports2Delete.add(PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class)); + } + else if (JavaLanguage.INSTANCE != element.getLanguage()) { + GenericInlineHandler.inlineReference(usage, myMethod, myInliners); + } + } + PsiReferenceExpression[] refs = refExprList.toArray(new PsiReferenceExpression[refExprList.size()]); + refs = addBracesWhenNeeded(refs); + for (PsiReferenceExpression ref : refs) { + if (ref instanceof PsiMethodReferenceExpression) { + continue; + } + inlineMethodCall(ref); + } + for (PsiElement psiElement : imports2Delete) { + if (psiElement != null && psiElement.isValid()) { + psiElement.delete(); + } + } + if (myMethod.isWritable()) { + myMethod.delete(); + } + } + } + removeAddedBracesWhenPossible(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - if (myEditor != null) { - LogicalPosition pos = new LogicalPosition(line, col); - myEditor.getCaretModel().moveToLogicalPosition(pos); - } - } + public static void inlineConstructorCall(PsiCall constructorCall) { + final PsiMethod oldConstructor = constructorCall.resolveMethod(); + LOG.assertTrue(oldConstructor != null); + PsiExpression[] instanceCreationArguments = constructorCall.getArgumentList().getExpressions(); + if (oldConstructor.isVarArgs()) { //wrap with explicit array + final PsiParameter[] parameters = oldConstructor.getParameterList().getParameters(); + final PsiType varargType = parameters[parameters.length - 1].getType(); + if (varargType instanceof PsiEllipsisType) { + final PsiType arrayType = + constructorCall.resolveMethodGenerics().getSubstitutor().substitute(((PsiEllipsisType)varargType).getComponentType()); + final PsiExpression[] exprs = new PsiExpression[parameters.length]; + System.arraycopy(instanceCreationArguments, 0, exprs, 0, parameters.length - 1); + StringBuilder varargs = new StringBuilder(); + for (int i = parameters.length - 1; i < instanceCreationArguments.length; i++) { + if (varargs.length() > 0) { + varargs.append(", "); + } + varargs.append(instanceCreationArguments[i].getText()); + } + + exprs[parameters.length - 1] = JavaPsiFacade.getElementFactory(constructorCall.getProject()) + .createExpressionFromText("new " + arrayType.getCanonicalText() + "[]{" + varargs.toString() + "}", constructorCall); - private void doRefactoring(UsageInfo[] usages) { - try { - if (myInlineThisOnly) { - if (myMethod.isConstructor() && InlineMethodHandler.isChainingConstructor(myMethod)) { - PsiCall constructorCall = RefactoringUtil.getEnclosingConstructorCall(myReference); - if (constructorCall != null) { - inlineConstructorCall(constructorCall); - } - } else { - myReference = addBracesWhenNeeded(new PsiReferenceExpression[]{(PsiReferenceExpression) myReference})[0]; - inlineMethodCall((PsiReferenceExpression) myReference); - } - } else { - CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); - if (myMethod.isConstructor()) { - for (UsageInfo usage : usages) { - PsiElement element = usage.getElement(); - if (element instanceof PsiJavaCodeReferenceElement) { - PsiCall constructorCall = RefactoringUtil.getEnclosingConstructorCall((PsiJavaCodeReferenceElement) element); - if (constructorCall != null) { - inlineConstructorCall(constructorCall); - } - } else if (element instanceof PsiEnumConstant) { - inlineConstructorCall((PsiEnumConstant) element); - } else { - GenericInlineHandler.inlineReference(usage, myMethod, myInliners); - } - } - myMethod.delete(); - } else { - List refExprList = new ArrayList(); - final List imports2Delete = new ArrayList(); - for (final UsageInfo usage : usages) { - final PsiElement element = usage.getElement(); - if (element instanceof PsiReferenceExpression) { - refExprList.add((PsiReferenceExpression) element); - } else if (element instanceof PsiImportStaticReferenceElement) { - imports2Delete.add(PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class)); - } else if (JavaLanguage.INSTANCE != element.getLanguage()) { - GenericInlineHandler.inlineReference(usage, myMethod, myInliners); - } - } - PsiReferenceExpression[] refs = refExprList.toArray(new PsiReferenceExpression[refExprList.size()]); - refs = addBracesWhenNeeded(refs); - for (PsiReferenceExpression ref : refs) { - if (ref instanceof PsiMethodReferenceExpression) continue; - inlineMethodCall(ref); - } - for (PsiElement psiElement : imports2Delete) { - if (psiElement != null && psiElement.isValid()) { - psiElement.delete(); - } - } - if (myMethod.isWritable()) myMethod.delete(); + instanceCreationArguments = exprs; + } } - } - removeAddedBracesWhenPossible(); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - public static void inlineConstructorCall(PsiCall constructorCall) { - final PsiMethod oldConstructor = constructorCall.resolveMethod(); - LOG.assertTrue(oldConstructor != null); - PsiExpression[] instanceCreationArguments = constructorCall.getArgumentList().getExpressions(); - if (oldConstructor.isVarArgs()) { //wrap with explicit array - final PsiParameter[] parameters = oldConstructor.getParameterList().getParameters(); - final PsiType varargType = parameters[parameters.length - 1].getType(); - if (varargType instanceof PsiEllipsisType) { - final PsiType arrayType = - constructorCall.resolveMethodGenerics().getSubstitutor().substitute(((PsiEllipsisType) varargType).getComponentType()); - final PsiExpression[] exprs = new PsiExpression[parameters.length]; - System.arraycopy(instanceCreationArguments, 0, exprs, 0, parameters.length - 1); - StringBuilder varargs = new StringBuilder(); - for (int i = parameters.length - 1; i < instanceCreationArguments.length; i++) { - if (varargs.length() > 0) varargs.append(", "); - varargs.append(instanceCreationArguments[i].getText()); - } - - exprs[parameters.length - 1] = JavaPsiFacade.getElementFactory(constructorCall.getProject()) - .createExpressionFromText("new " + arrayType.getCanonicalText() + "[]{" + varargs.toString() + "}", constructorCall); - - instanceCreationArguments = exprs; - } - } + PsiStatement[] statements = oldConstructor.getBody().getStatements(); + LOG.assertTrue(statements.length == 1 && statements[0] instanceof PsiExpressionStatement); + PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression(); + LOG.assertTrue(expression instanceof PsiMethodCallExpression); + ChangeContextUtil.encodeContextInfo(expression, true); - PsiStatement[] statements = oldConstructor.getBody().getStatements(); - LOG.assertTrue(statements.length == 1 && statements[0] instanceof PsiExpressionStatement); - PsiExpression expression = ((PsiExpressionStatement) statements[0]).getExpression(); - LOG.assertTrue(expression instanceof PsiMethodCallExpression); - ChangeContextUtil.encodeContextInfo(expression, true); + PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression.copy(); + final PsiExpression[] args = methodCall.getArgumentList().getExpressions(); + for (PsiExpression arg : args) { + replaceParameterReferences(arg, oldConstructor, instanceCreationArguments); + } - PsiMethodCallExpression methodCall = (PsiMethodCallExpression) expression.copy(); - final PsiExpression[] args = methodCall.getArgumentList().getExpressions(); - for (PsiExpression arg : args) { - replaceParameterReferences(arg, oldConstructor, instanceCreationArguments); + try { + final PsiExpressionList exprList = (PsiExpressionList)constructorCall.getArgumentList().replace(methodCall.getArgumentList()); + ChangeContextUtil.decodeContextInfo(exprList, PsiTreeUtil.getParentOfType(constructorCall, PsiClass.class), null); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + ChangeContextUtil.clearContextInfo(expression); + } + + private static void replaceParameterReferences( + final PsiElement element, + final PsiMethod oldConstructor, + final PsiExpression[] instanceCreationArguments + ) { + boolean isParameterReference = false; + if (element instanceof PsiReferenceExpression) { + final PsiReferenceExpression expression = (PsiReferenceExpression)element; + PsiElement resolved = expression.resolve(); + if (resolved instanceof PsiParameter && + element.getManager().areElementsEquivalent(((PsiParameter)resolved).getDeclarationScope(), oldConstructor)) { + isParameterReference = true; + PsiElement declarationScope = ((PsiParameter)resolved).getDeclarationScope(); + PsiParameter[] declarationParameters = ((PsiMethod)declarationScope).getParameterList().getParameters(); + for (int j = 0; j < declarationParameters.length; j++) { + if (declarationParameters[j] == resolved) { + try { + expression.replace(instanceCreationArguments[j]); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + } + } + if (!isParameterReference) { + PsiElement child = element.getFirstChild(); + while (child != null) { + PsiElement next = child.getNextSibling(); + replaceParameterReferences(child, oldConstructor, instanceCreationArguments); + child = next; + } + } } - try { - final PsiExpressionList exprList = (PsiExpressionList) constructorCall.getArgumentList().replace(methodCall.getArgumentList()); - ChangeContextUtil.decodeContextInfo(exprList, PsiTreeUtil.getParentOfType(constructorCall, PsiClass.class), null); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - ChangeContextUtil.clearContextInfo(expression); - } + public void inlineMethodCall(PsiReferenceExpression ref) throws IncorrectOperationException { + InlineUtil.TailCallType tailCall = InlineUtil.getTailCallType(ref); + ChangeContextUtil.encodeContextInfo(myMethod, false); + myMethodCopy = (PsiMethod)myMethod.copy(); + ChangeContextUtil.clearContextInfo(myMethod); - private static void replaceParameterReferences(final PsiElement element, - final PsiMethod oldConstructor, - final PsiExpression[] instanceCreationArguments) { - boolean isParameterReference = false; - if (element instanceof PsiReferenceExpression) { - final PsiReferenceExpression expression = (PsiReferenceExpression) element; - PsiElement resolved = expression.resolve(); - if (resolved instanceof PsiParameter && - element.getManager().areElementsEquivalent(((PsiParameter) resolved).getDeclarationScope(), oldConstructor)) { - isParameterReference = true; - PsiElement declarationScope = ((PsiParameter) resolved).getDeclarationScope(); - PsiParameter[] declarationParameters = ((PsiMethod) declarationScope).getParameterList().getParameters(); - for (int j = 0; j < declarationParameters.length; j++) { - if (declarationParameters[j] == resolved) { - try { - expression.replace(instanceCreationArguments[j]); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } + PsiMethodCallExpression methodCall = (PsiMethodCallExpression)ref.getParent(); + + PsiSubstitutor callSubstitutor = getCallSubstitutor(methodCall); + BlockData blockData = prepareBlock(ref, callSubstitutor, methodCall.getArgumentList(), tailCall); + solveVariableNameConflicts(blockData.block, ref); + if (callSubstitutor != PsiSubstitutor.EMPTY) { + substituteMethodTypeParams(blockData.block, callSubstitutor); } - } - } - if (!isParameterReference) { - PsiElement child = element.getFirstChild(); - while (child != null) { - PsiElement next = child.getNextSibling(); - replaceParameterReferences(child, oldConstructor, instanceCreationArguments); - child = next; - } - } - } + addParmAndThisVarInitializers(blockData, methodCall); + + PsiElement anchor = RefactoringUtil.getParentStatement(methodCall, true); + if (anchor == null) { + PsiEnumConstant enumConstant = PsiTreeUtil.getParentOfType(methodCall, PsiEnumConstant.class); + if (enumConstant != null) { + PsiExpression returnExpr = getSimpleReturnedExpression(myMethod); + if (returnExpr != null) { + methodCall.replace(returnExpr); + } + } + return; + } + PsiElement anchorParent = anchor.getParent(); + PsiLocalVariable thisVar = null; + PsiLocalVariable[] parmVars = new PsiLocalVariable[blockData.parmVars.length]; + PsiLocalVariable resultVar = null; + PsiStatement[] statements = blockData.block.getStatements(); + if (statements.length > 0) { + int last = statements.length - 1; + /*PsiElement first = statements[0]; + PsiElement last = statements[statements.length - 1];*/ - public void inlineMethodCall(PsiReferenceExpression ref) throws IncorrectOperationException { - InlineUtil.TailCallType tailCall = InlineUtil.getTailCallType(ref); - ChangeContextUtil.encodeContextInfo(myMethod, false); - myMethodCopy = (PsiMethod) myMethod.copy(); - ChangeContextUtil.clearContextInfo(myMethod); + if (statements.length > 0 && statements[statements.length - 1] instanceof PsiReturnStatement && + tailCall != InlineUtil.TailCallType.Return) { + last--; + } - PsiMethodCallExpression methodCall = (PsiMethodCallExpression) ref.getParent(); + int first = 0; + if (first <= last) { + final PsiElement rBraceOrReturnStatement = + PsiTreeUtil.skipSiblingsForward(statements[last], PsiWhiteSpace.class, PsiComment.class); + LOG.assertTrue(rBraceOrReturnStatement != null); + final PsiElement beforeRBraceStatement = rBraceOrReturnStatement.getPrevSibling(); + LOG.assertTrue(beforeRBraceStatement != null); + PsiElement firstAdded = anchorParent.addRangeBefore(statements[first], beforeRBraceStatement, anchor); + + PsiElement current = firstAdded.getPrevSibling(); + LOG.assertTrue(current != null); + if (blockData.thisVar != null) { + PsiDeclarationStatement statement = PsiTreeUtil.getNextSiblingOfType(current, PsiDeclarationStatement.class); + thisVar = (PsiLocalVariable)statement.getDeclaredElements()[0]; + current = statement; + } + for (int i = 0; i < parmVars.length; i++) { + PsiDeclarationStatement statement = PsiTreeUtil.getNextSiblingOfType(current, PsiDeclarationStatement.class); + parmVars[i] = (PsiLocalVariable)statement.getDeclaredElements()[0]; + current = statement; + } + if (blockData.resultVar != null) { + PsiDeclarationStatement statement = PsiTreeUtil.getNextSiblingOfType(current, PsiDeclarationStatement.class); + resultVar = (PsiLocalVariable)statement.getDeclaredElements()[0]; + } + } + if (statements.length > 0) { + final PsiStatement lastStatement = statements[statements.length - 1]; + if (lastStatement instanceof PsiReturnStatement && tailCall != InlineUtil.TailCallType.Return) { + final PsiExpression returnValue = ((PsiReturnStatement)lastStatement).getReturnValue(); + if (returnValue != null && PsiUtil.isStatement(returnValue)) { + PsiExpressionStatement exprStatement = (PsiExpressionStatement)myFactory.createStatementFromText("a;", null); + exprStatement.getExpression().replace(returnValue); + anchorParent.addBefore(exprStatement, anchor); + } + } + } + } - PsiSubstitutor callSubstitutor = getCallSubstitutor(methodCall); - BlockData blockData = prepareBlock(ref, callSubstitutor, methodCall.getArgumentList(), tailCall); - solveVariableNameConflicts(blockData.block, ref); - if (callSubstitutor != PsiSubstitutor.EMPTY) { - substituteMethodTypeParams(blockData.block, callSubstitutor); - } - addParmAndThisVarInitializers(blockData, methodCall); - PsiElement anchor = RefactoringUtil.getParentStatement(methodCall, true); - if (anchor == null) { - PsiEnumConstant enumConstant = PsiTreeUtil.getParentOfType(methodCall, PsiEnumConstant.class); - if (enumConstant != null) { - PsiExpression returnExpr = getSimpleReturnedExpression(myMethod); - if (returnExpr != null) { - methodCall.replace(returnExpr); + PsiClass thisClass = myMethod.getContainingClass(); + PsiExpression thisAccessExpr; + if (thisVar != null) { + if (!canInlineParmOrThisVariable(thisVar)) { + thisAccessExpr = myFactory.createExpressionFromText(thisVar.getName(), null); + } + else { + thisAccessExpr = thisVar.getInitializer(); + } } - } - return; - } - PsiElement anchorParent = anchor.getParent(); - PsiLocalVariable thisVar = null; - PsiLocalVariable[] parmVars = new PsiLocalVariable[blockData.parmVars.length]; - PsiLocalVariable resultVar = null; - PsiStatement[] statements = blockData.block.getStatements(); - if (statements.length > 0) { - int last = statements.length - 1; - /*PsiElement first = statements[0]; - PsiElement last = statements[statements.length - 1];*/ + else { + thisAccessExpr = null; + } + ChangeContextUtil.decodeContextInfo(anchorParent, thisClass, thisAccessExpr); - if (statements.length > 0 && statements[statements.length - 1] instanceof PsiReturnStatement && - tailCall != InlineUtil.TailCallType.Return) { - last--; - } + if (methodCall.getParent() instanceof PsiLambdaExpression) { + methodCall.delete(); + } + else if (methodCall.getParent() instanceof PsiExpressionStatement || tailCall == InlineUtil.TailCallType.Return) { + methodCall.getParent().delete(); + } + else { + if (blockData.resultVar != null) { + PsiExpression expr = myFactory.createExpressionFromText(blockData.resultVar.getName(), null); + methodCall.replace(expr); + } + else { + //?? + } + } - int first = 0; - if (first <= last) { - final PsiElement rBraceOrReturnStatement = - PsiTreeUtil.skipSiblingsForward(statements[last], PsiWhiteSpace.class, PsiComment.class); - LOG.assertTrue(rBraceOrReturnStatement != null); - final PsiElement beforeRBraceStatement = rBraceOrReturnStatement.getPrevSibling(); - LOG.assertTrue(beforeRBraceStatement != null); - PsiElement firstAdded = anchorParent.addRangeBefore(statements[first], beforeRBraceStatement, anchor); - - PsiElement current = firstAdded.getPrevSibling(); - LOG.assertTrue(current != null); - if (blockData.thisVar != null) { - PsiDeclarationStatement statement = PsiTreeUtil.getNextSiblingOfType(current, PsiDeclarationStatement.class); - thisVar = (PsiLocalVariable) statement.getDeclaredElements()[0]; - current = statement; + if (thisVar != null) { + inlineParmOrThisVariable(thisVar, false); } + final PsiParameter[] parameters = myMethod.getParameterList().getParameters(); for (int i = 0; i < parmVars.length; i++) { - PsiDeclarationStatement statement = PsiTreeUtil.getNextSiblingOfType(current, PsiDeclarationStatement.class); - parmVars[i] = (PsiLocalVariable) statement.getDeclaredElements()[0]; - current = statement; - } - if (blockData.resultVar != null) { - PsiDeclarationStatement statement = PsiTreeUtil.getNextSiblingOfType(current, PsiDeclarationStatement.class); - resultVar = (PsiLocalVariable) statement.getDeclaredElements()[0]; + final PsiParameter parameter = parameters[i]; + final boolean strictlyFinal = parameter.hasModifierProperty(PsiModifier.FINAL) && isStrictlyFinal(parameter); + inlineParmOrThisVariable(parmVars[i], strictlyFinal); } - } - if (statements.length > 0) { - final PsiStatement lastStatement = statements[statements.length - 1]; - if (lastStatement instanceof PsiReturnStatement && tailCall != InlineUtil.TailCallType.Return) { - final PsiExpression returnValue = ((PsiReturnStatement) lastStatement).getReturnValue(); - if (returnValue != null && PsiUtil.isStatement(returnValue)) { - PsiExpressionStatement exprStatement = (PsiExpressionStatement) myFactory.createStatementFromText("a;", null); - exprStatement.getExpression().replace(returnValue); - anchorParent.addBefore(exprStatement, anchor); - } + if (resultVar != null) { + inlineResultVariable(resultVar); } - } + + ChangeContextUtil.clearContextInfo(anchorParent); } + private PsiSubstitutor getCallSubstitutor(PsiMethodCallExpression methodCall) { + JavaResolveResult resolveResult = methodCall.getMethodExpression().advancedResolve(false); + LOG.assertTrue(myManager.areElementsEquivalent(resolveResult.getElement(), myMethod)); + if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { + Iterator oldTypeParameters = PsiUtil.typeParametersIterator(myMethod); + Iterator newTypeParameters = PsiUtil.typeParametersIterator(myMethodCopy); + PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + while (newTypeParameters.hasNext()) { + final PsiTypeParameter newTypeParameter = newTypeParameters.next(); + final PsiTypeParameter oldTypeParameter = oldTypeParameters.next(); + substitutor = substitutor.put(newTypeParameter, resolveResult.getSubstitutor().substitute(oldTypeParameter)); + } + return substitutor; + } - PsiClass thisClass = myMethod.getContainingClass(); - PsiExpression thisAccessExpr; - if (thisVar != null) { - if (!canInlineParmOrThisVariable(thisVar)) { - thisAccessExpr = myFactory.createExpressionFromText(thisVar.getName(), null); - } else { - thisAccessExpr = thisVar.getInitializer(); - } - } else { - thisAccessExpr = null; - } - ChangeContextUtil.decodeContextInfo(anchorParent, thisClass, thisAccessExpr); - - if (methodCall.getParent() instanceof PsiLambdaExpression) { - methodCall.delete(); - } else if (methodCall.getParent() instanceof PsiExpressionStatement || tailCall == InlineUtil.TailCallType.Return) { - methodCall.getParent().delete(); - } else { - if (blockData.resultVar != null) { - PsiExpression expr = myFactory.createExpressionFromText(blockData.resultVar.getName(), null); - methodCall.replace(expr); - } else { - //?? - } + return PsiSubstitutor.EMPTY; } - if (thisVar != null) { - inlineParmOrThisVariable(thisVar, false); - } - final PsiParameter[] parameters = myMethod.getParameterList().getParameters(); - for (int i = 0; i < parmVars.length; i++) { - final PsiParameter parameter = parameters[i]; - final boolean strictlyFinal = parameter.hasModifierProperty(PsiModifier.FINAL) && isStrictlyFinal(parameter); - inlineParmOrThisVariable(parmVars[i], strictlyFinal); - } - if (resultVar != null) { - inlineResultVariable(resultVar); + private void substituteMethodTypeParams(PsiElement scope, final PsiSubstitutor substitutor) { + InlineUtil.substituteTypeParams(scope, substitutor, myFactory); } - ChangeContextUtil.clearContextInfo(anchorParent); - } - - private PsiSubstitutor getCallSubstitutor(PsiMethodCallExpression methodCall) { - JavaResolveResult resolveResult = methodCall.getMethodExpression().advancedResolve(false); - LOG.assertTrue(myManager.areElementsEquivalent(resolveResult.getElement(), myMethod)); - if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { - Iterator oldTypeParameters = PsiUtil.typeParametersIterator(myMethod); - Iterator newTypeParameters = PsiUtil.typeParametersIterator(myMethodCopy); - PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - while (newTypeParameters.hasNext()) { - final PsiTypeParameter newTypeParameter = newTypeParameters.next(); - final PsiTypeParameter oldTypeParameter = oldTypeParameters.next(); - substitutor = substitutor.put(newTypeParameter, resolveResult.getSubstitutor().substitute(oldTypeParameter)); - } - return substitutor; + private boolean isStrictlyFinal(PsiParameter parameter) { + for (PsiReference reference : ReferencesSearch.search(parameter, GlobalSearchScope.projectScope(myProject), false)) { + final PsiElement refElement = reference.getElement(); + final PsiElement anonymousClass = PsiTreeUtil.getParentOfType(refElement, PsiAnonymousClass.class); + if (anonymousClass != null && PsiTreeUtil.isAncestor(myMethod, anonymousClass, true)) { + return true; + } + } + return false; } - return PsiSubstitutor.EMPTY; - } - - private void substituteMethodTypeParams(PsiElement scope, final PsiSubstitutor substitutor) { - InlineUtil.substituteTypeParams(scope, substitutor, myFactory); - } - private boolean isStrictlyFinal(PsiParameter parameter) { - for (PsiReference reference : ReferencesSearch.search(parameter, GlobalSearchScope.projectScope(myProject), false)) { - final PsiElement refElement = reference.getElement(); - final PsiElement anonymousClass = PsiTreeUtil.getParentOfType(refElement, PsiAnonymousClass.class); - if (anonymousClass != null && PsiTreeUtil.isAncestor(myMethod, anonymousClass, true)) { - return true; - } - } - return false; - } + private boolean syncNeeded(final PsiReferenceExpression ref) { + if (!myMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return false; + } + final PsiMethod containingMethod = Util.getContainingMethod(ref); + if (containingMethod == null) { + return true; + } + if (!containingMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return true; + } + final PsiClass sourceContainingClass = myMethod.getContainingClass(); + final PsiClass targetContainingClass = containingMethod.getContainingClass(); + return !sourceContainingClass.equals(targetContainingClass); + } + + private BlockData prepareBlock( + PsiReferenceExpression ref, + final PsiSubstitutor callSubstitutor, + final PsiExpressionList argumentList, + final InlineUtil.TailCallType tailCallType + ) + throws IncorrectOperationException { + final PsiCodeBlock block = myMethodCopy.getBody(); + final PsiStatement[] originalStatements = block.getStatements(); + + PsiLocalVariable resultVar = null; + PsiType returnType = callSubstitutor.substitute(myMethod.getReturnType()); + String resultName = null; + final int applicabilityLevel = PsiUtil.getApplicabilityLevel(myMethod, callSubstitutor, argumentList); + if (returnType != null && !PsiType.VOID.equals(returnType) && tailCallType == InlineUtil.TailCallType.None) { + resultName = myJavaCodeStyle.propertyNameToVariableName("result", VariableKind.LOCAL_VARIABLE); + resultName = myJavaCodeStyle.suggestUniqueVariableName(resultName, block.getFirstChild(), true); + PsiDeclarationStatement declaration = myFactory.createVariableDeclarationStatement(resultName, returnType, null); + declaration = (PsiDeclarationStatement)block.addAfter(declaration, null); + resultVar = (PsiLocalVariable)declaration.getDeclaredElements()[0]; + } + PsiParameter[] parms = myMethodCopy.getParameterList().getParameters(); + PsiLocalVariable[] parmVars = new PsiLocalVariable[parms.length]; + for (int i = parms.length - 1; i >= 0; i--) { + PsiParameter parm = parms[i]; + String parmName = parm.getName(); + String name = parmName; + name = myJavaCodeStyle.variableNameToPropertyName(name, VariableKind.PARAMETER); + name = myJavaCodeStyle.propertyNameToVariableName(name, VariableKind.LOCAL_VARIABLE); + if (!name.equals(parmName)) { + name = myJavaCodeStyle.suggestUniqueVariableName(name, block.getFirstChild(), true); + } + RefactoringUtil.renameVariableReferences(parm, name, new LocalSearchScope(myMethodCopy.getBody()), true); + PsiType paramType = parm.getType(); + @NonNls String defaultValue; + if (paramType instanceof PsiEllipsisType) { + final PsiEllipsisType ellipsisType = (PsiEllipsisType)paramType; + paramType = callSubstitutor.substitute(ellipsisType.toArrayType()); + if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS) { + defaultValue = "new " + ((PsiArrayType)paramType).getComponentType().getCanonicalText() + "[]{}"; + } + else { + defaultValue = PsiTypesUtil.getDefaultValueOfType(paramType); + } + } + else { + defaultValue = PsiTypesUtil.getDefaultValueOfType(paramType); + } - private boolean syncNeeded(final PsiReferenceExpression ref) { - if (!myMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) return false; - final PsiMethod containingMethod = Util.getContainingMethod(ref); - if (containingMethod == null) return true; - if (!containingMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) return true; - final PsiClass sourceContainingClass = myMethod.getContainingClass(); - final PsiClass targetContainingClass = containingMethod.getContainingClass(); - return !sourceContainingClass.equals(targetContainingClass); - } + PsiExpression initializer = myFactory.createExpressionFromText(defaultValue, null); + PsiDeclarationStatement declaration = + myFactory.createVariableDeclarationStatement(name, callSubstitutor.substitute(paramType), initializer); + declaration = (PsiDeclarationStatement)block.addAfter(declaration, null); + parmVars[i] = (PsiLocalVariable)declaration.getDeclaredElements()[0]; + PsiUtil.setModifierProperty(parmVars[i], PsiModifier.FINAL, parm.hasModifierProperty(PsiModifier.FINAL)); + } - private BlockData prepareBlock(PsiReferenceExpression ref, - final PsiSubstitutor callSubstitutor, - final PsiExpressionList argumentList, - final InlineUtil.TailCallType tailCallType) - throws IncorrectOperationException { - final PsiCodeBlock block = myMethodCopy.getBody(); - final PsiStatement[] originalStatements = block.getStatements(); - - PsiLocalVariable resultVar = null; - PsiType returnType = callSubstitutor.substitute(myMethod.getReturnType()); - String resultName = null; - final int applicabilityLevel = PsiUtil.getApplicabilityLevel(myMethod, callSubstitutor, argumentList); - if (returnType != null && !PsiType.VOID.equals(returnType) && tailCallType == InlineUtil.TailCallType.None) { - resultName = myJavaCodeStyle.propertyNameToVariableName("result", VariableKind.LOCAL_VARIABLE); - resultName = myJavaCodeStyle.suggestUniqueVariableName(resultName, block.getFirstChild(), true); - PsiDeclarationStatement declaration = myFactory.createVariableDeclarationStatement(resultName, returnType, null); - declaration = (PsiDeclarationStatement) block.addAfter(declaration, null); - resultVar = (PsiLocalVariable) declaration.getDeclaredElements()[0]; - } + PsiLocalVariable thisVar = null; + PsiClass containingClass = myMethod.getContainingClass(); + if (!myMethod.hasModifierProperty(PsiModifier.STATIC) && containingClass != null) { + PsiType thisType = myFactory.createType(containingClass, callSubstitutor); + String[] names = myJavaCodeStyle.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, thisType) + .names; + String thisVarName = names[0]; + thisVarName = myJavaCodeStyle.suggestUniqueVariableName(thisVarName, block.getFirstChild(), true); + PsiExpression initializer = myFactory.createExpressionFromText("null", null); + PsiDeclarationStatement declaration = myFactory.createVariableDeclarationStatement(thisVarName, thisType, initializer); + declaration = (PsiDeclarationStatement)block.addAfter(declaration, null); + thisVar = (PsiLocalVariable)declaration.getDeclaredElements()[0]; + } - PsiParameter[] parms = myMethodCopy.getParameterList().getParameters(); - PsiLocalVariable[] parmVars = new PsiLocalVariable[parms.length]; - for (int i = parms.length - 1; i >= 0; i--) { - PsiParameter parm = parms[i]; - String parmName = parm.getName(); - String name = parmName; - name = myJavaCodeStyle.variableNameToPropertyName(name, VariableKind.PARAMETER); - name = myJavaCodeStyle.propertyNameToVariableName(name, VariableKind.LOCAL_VARIABLE); - if (!name.equals(parmName)) { - name = myJavaCodeStyle.suggestUniqueVariableName(name, block.getFirstChild(), true); - } - RefactoringUtil.renameVariableReferences(parm, name, new LocalSearchScope(myMethodCopy.getBody()), true); - PsiType paramType = parm.getType(); - @NonNls String defaultValue; - if (paramType instanceof PsiEllipsisType) { - final PsiEllipsisType ellipsisType = (PsiEllipsisType) paramType; - paramType = callSubstitutor.substitute(ellipsisType.toArrayType()); - if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS) { - defaultValue = "new " + ((PsiArrayType) paramType).getComponentType().getCanonicalText() + "[]{}"; - } else { - defaultValue = PsiTypesUtil.getDefaultValueOfType(paramType); - } - } else { - defaultValue = PsiTypesUtil.getDefaultValueOfType(paramType); - } + String lockName = null; + if (thisVar != null) { + lockName = thisVar.getName(); + } + else if (myMethod.hasModifierProperty(PsiModifier.STATIC) && containingClass != null) { + lockName = containingClass.getQualifiedName() + ".class"; + } - PsiExpression initializer = myFactory.createExpressionFromText(defaultValue, null); - PsiDeclarationStatement declaration = - myFactory.createVariableDeclarationStatement(name, callSubstitutor.substitute(paramType), initializer); - declaration = (PsiDeclarationStatement) block.addAfter(declaration, null); - parmVars[i] = (PsiLocalVariable) declaration.getDeclaredElements()[0]; - PsiUtil.setModifierProperty(parmVars[i], PsiModifier.FINAL, parm.hasModifierProperty(PsiModifier.FINAL)); - } + if (lockName != null && syncNeeded(ref)) { + PsiSynchronizedStatement synchronizedStatement = + (PsiSynchronizedStatement)myFactory.createStatementFromText("synchronized(" + lockName + "){}", block); + synchronizedStatement = (PsiSynchronizedStatement)CodeStyleManager.getInstance(myProject).reformat(synchronizedStatement); + synchronizedStatement = (PsiSynchronizedStatement)block.add(synchronizedStatement); + final PsiCodeBlock synchronizedBody = synchronizedStatement.getBody(); + for (final PsiStatement originalStatement : originalStatements) { + synchronizedBody.add(originalStatement); + originalStatement.delete(); + } + } - PsiLocalVariable thisVar = null; - PsiClass containingClass = myMethod.getContainingClass(); - if (!myMethod.hasModifierProperty(PsiModifier.STATIC) && containingClass != null) { - PsiType thisType = myFactory.createType(containingClass, callSubstitutor); - String[] names = myJavaCodeStyle.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, thisType) - .names; - String thisVarName = names[0]; - thisVarName = myJavaCodeStyle.suggestUniqueVariableName(thisVarName, block.getFirstChild(), true); - PsiExpression initializer = myFactory.createExpressionFromText("null", null); - PsiDeclarationStatement declaration = myFactory.createVariableDeclarationStatement(thisVarName, thisType, initializer); - declaration = (PsiDeclarationStatement) block.addAfter(declaration, null); - thisVar = (PsiLocalVariable) declaration.getDeclaredElements()[0]; - } + if (resultName != null || tailCallType == InlineUtil.TailCallType.Simple) { + PsiReturnStatement[] returnStatements = RefactoringUtil.findReturnStatements(myMethodCopy); + for (PsiReturnStatement returnStatement : returnStatements) { + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue == null) { + continue; + } + PsiStatement statement; + if (tailCallType == InlineUtil.TailCallType.Simple) { + if (returnValue instanceof PsiExpression && returnStatement.getNextSibling() == myMethodCopy.getBody() + .getLastBodyElement()) { + PsiExpressionStatement exprStatement = (PsiExpressionStatement)myFactory.createStatementFromText("a;", null); + exprStatement.getExpression().replace(returnValue); + returnStatement.getParent().addBefore(exprStatement, returnStatement); + statement = myFactory.createStatementFromText("return;", null); + } + else { + statement = (PsiStatement)returnStatement.copy(); + } + } + else { + statement = myFactory.createStatementFromText(resultName + "=0;", null); + statement = (PsiStatement)myCodeStyleManager.reformat(statement); + PsiAssignmentExpression assignment = (PsiAssignmentExpression)((PsiExpressionStatement)statement).getExpression(); + assignment.getRExpression().replace(returnValue); + } + returnStatement.replace(statement); + } + } - String lockName = null; - if (thisVar != null) { - lockName = thisVar.getName(); - } else if (myMethod.hasModifierProperty(PsiModifier.STATIC) && containingClass != null) { - lockName = containingClass.getQualifiedName() + ".class"; + return new BlockData(block, thisVar, parmVars, resultVar); } - if (lockName != null && syncNeeded(ref)) { - PsiSynchronizedStatement synchronizedStatement = - (PsiSynchronizedStatement) myFactory.createStatementFromText("synchronized(" + lockName + "){}", block); - synchronizedStatement = (PsiSynchronizedStatement) CodeStyleManager.getInstance(myProject).reformat(synchronizedStatement); - synchronizedStatement = (PsiSynchronizedStatement) block.add(synchronizedStatement); - final PsiCodeBlock synchronizedBody = synchronizedStatement.getBody(); - for (final PsiStatement originalStatement : originalStatements) { - synchronizedBody.add(originalStatement); - originalStatement.delete(); - } - } + private void solveVariableNameConflicts(PsiElement scope, final PsiElement placeToInsert) throws IncorrectOperationException { + if (scope instanceof PsiVariable) { + PsiVariable var = (PsiVariable)scope; + String name = var.getName(); + String oldName = name; + while (true) { + String newName = myJavaCodeStyle.suggestUniqueVariableName(name, placeToInsert, true); + if (newName.equals(name)) { + break; + } + name = newName; + newName = myJavaCodeStyle.suggestUniqueVariableName(name, var, true); + if (newName.equals(name)) { + break; + } + name = newName; + } + if (!name.equals(oldName)) { + RefactoringUtil.renameVariableReferences(var, name, new LocalSearchScope(myMethodCopy.getBody()), true); + var.getNameIdentifier().replace(myFactory.createIdentifier(name)); + } + } - if (resultName != null || tailCallType == InlineUtil.TailCallType.Simple) { - PsiReturnStatement[] returnStatements = RefactoringUtil.findReturnStatements(myMethodCopy); - for (PsiReturnStatement returnStatement : returnStatements) { - final PsiExpression returnValue = returnStatement.getReturnValue(); - if (returnValue == null) continue; - PsiStatement statement; - if (tailCallType == InlineUtil.TailCallType.Simple) { - if (returnValue instanceof PsiExpression && returnStatement.getNextSibling() == myMethodCopy.getBody().getLastBodyElement()) { - PsiExpressionStatement exprStatement = (PsiExpressionStatement) myFactory.createStatementFromText("a;", null); - exprStatement.getExpression().replace(returnValue); - returnStatement.getParent().addBefore(exprStatement, returnStatement); - statement = myFactory.createStatementFromText("return;", null); - } else { - statement = (PsiStatement) returnStatement.copy(); - } - } else { - statement = myFactory.createStatementFromText(resultName + "=0;", null); - statement = (PsiStatement) myCodeStyleManager.reformat(statement); - PsiAssignmentExpression assignment = (PsiAssignmentExpression) ((PsiExpressionStatement) statement).getExpression(); - assignment.getRExpression().replace(returnValue); - } - returnStatement.replace(statement); - } + PsiElement[] children = scope.getChildren(); + for (PsiElement child : children) { + solveVariableNameConflicts(child, placeToInsert); + } } - return new BlockData(block, thisVar, parmVars, resultVar); - } + private void addParmAndThisVarInitializers(BlockData blockData, PsiMethodCallExpression methodCall) throws IncorrectOperationException { + PsiExpression[] args = methodCall.getArgumentList().getExpressions(); + if (blockData.parmVars.length > 0) { + for (int i = 0; i < args.length; i++) { + int j = Math.min(i, blockData.parmVars.length - 1); + final PsiExpression initializer = blockData.parmVars[j].getInitializer(); + LOG.assertTrue(initializer != null); + if (initializer instanceof PsiNewExpression && ((PsiNewExpression)initializer).getArrayInitializer() != null) { //varargs initializer + final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression)initializer).getArrayInitializer(); + arrayInitializer.add(args[i]); + continue; + } - private void solveVariableNameConflicts(PsiElement scope, final PsiElement placeToInsert) throws IncorrectOperationException { - if (scope instanceof PsiVariable) { - PsiVariable var = (PsiVariable) scope; - String name = var.getName(); - String oldName = name; - while (true) { - String newName = myJavaCodeStyle.suggestUniqueVariableName(name, placeToInsert, true); - if (newName.equals(name)) break; - name = newName; - newName = myJavaCodeStyle.suggestUniqueVariableName(name, var, true); - if (newName.equals(name)) break; - name = newName; - } - if (!name.equals(oldName)) { - RefactoringUtil.renameVariableReferences(var, name, new LocalSearchScope(myMethodCopy.getBody()), true); - var.getNameIdentifier().replace(myFactory.createIdentifier(name)); - } - } + initializer.replace(args[i]); + } + } - PsiElement[] children = scope.getChildren(); - for (PsiElement child : children) { - solveVariableNameConflicts(child, placeToInsert); + if (blockData.thisVar != null) { + PsiExpression qualifier = methodCall.getMethodExpression().getQualifierExpression(); + if (qualifier == null) { + PsiElement parent = methodCall.getContext(); + while (true) { + if (parent instanceof PsiClass) { + break; + } + if (parent instanceof PsiFile) { + break; + } + assert parent != null : methodCall; + parent = parent.getContext(); + } + if (parent instanceof PsiClass) { + PsiClass parentClass = (PsiClass)parent; + final PsiClass containingClass = myMethod.getContainingClass(); + if (InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { + qualifier = myFactory.createExpressionFromText("this", null); + } + else { + if (PsiTreeUtil.isAncestor(containingClass, parent, false)) { + String name = containingClass.getName(); + if (name != null) { + qualifier = myFactory.createExpressionFromText(name + ".this", null); + } + else { //? + qualifier = myFactory.createExpressionFromText("this", null); + } + } + else { // we are inside the inheritor + do { + parentClass = PsiTreeUtil.getParentOfType(parentClass, PsiClass.class, true); + if (InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { + LOG.assertTrue(parentClass != null); + final String childClassName = parentClass.getName(); + qualifier = myFactory.createExpressionFromText( + childClassName != null ? childClassName + ".this" : "this", + null + ); + break; + } + } + while (parentClass != null); + } + } + } + else { + qualifier = myFactory.createExpressionFromText("this", null); + } + } + else if (qualifier instanceof PsiSuperExpression) { + qualifier = myFactory.createExpressionFromText("this", null); + } + blockData.thisVar.getInitializer().replace(qualifier); + } } - } - private void addParmAndThisVarInitializers(BlockData blockData, PsiMethodCallExpression methodCall) throws IncorrectOperationException { - PsiExpression[] args = methodCall.getArgumentList().getExpressions(); - if (blockData.parmVars.length > 0) { - for (int i = 0; i < args.length; i++) { - int j = Math.min(i, blockData.parmVars.length - 1); - final PsiExpression initializer = blockData.parmVars[j].getInitializer(); - LOG.assertTrue(initializer != null); - if (initializer instanceof PsiNewExpression && ((PsiNewExpression) initializer).getArrayInitializer() != null) { //varargs initializer - final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression) initializer).getArrayInitializer(); - arrayInitializer.add(args[i]); - continue; + private boolean canInlineParmOrThisVariable(PsiLocalVariable variable) { + boolean isAccessedForWriting = false; + for (PsiReference ref : ReferencesSearch.search(variable)) { + PsiElement refElement = ref.getElement(); + if (refElement instanceof PsiExpression) { + if (PsiUtil.isAccessedForWriting((PsiExpression)refElement)) { + isAccessedForWriting = true; + } + } } - initializer.replace(args[i]); - } + PsiExpression initializer = variable.getInitializer(); + boolean shouldBeFinal = variable.hasModifierProperty(PsiModifier.FINAL) && false; + return canInlineParmOrThisVariable( + initializer, + shouldBeFinal, + false, + ReferencesSearch.search(variable).findAll().size(), + isAccessedForWriting + ); } - if (blockData.thisVar != null) { - PsiExpression qualifier = methodCall.getMethodExpression().getQualifierExpression(); - if (qualifier == null) { - PsiElement parent = methodCall.getContext(); - while (true) { - if (parent instanceof PsiClass) break; - if (parent instanceof PsiFile) break; - assert parent != null : methodCall; - parent = parent.getContext(); - } - if (parent instanceof PsiClass) { - PsiClass parentClass = (PsiClass) parent; - final PsiClass containingClass = myMethod.getContainingClass(); - if (InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { - qualifier = myFactory.createExpressionFromText("this", null); - } else { - if (PsiTreeUtil.isAncestor(containingClass, parent, false)) { - String name = containingClass.getName(); - if (name != null) { - qualifier = myFactory.createExpressionFromText(name + ".this", null); - } else { //? - qualifier = myFactory.createExpressionFromText("this", null); - } - } else { // we are inside the inheritor - do { - parentClass = PsiTreeUtil.getParentOfType(parentClass, PsiClass.class, true); - if (InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { - LOG.assertTrue(parentClass != null); - final String childClassName = parentClass.getName(); - qualifier = myFactory.createExpressionFromText(childClassName != null ? childClassName + ".this" : "this", null); - break; - } - } - while (parentClass != null); - } - } - } else { - qualifier = myFactory.createExpressionFromText("this", null); - } - } else if (qualifier instanceof PsiSuperExpression) { - qualifier = myFactory.createExpressionFromText("this", null); - } - blockData.thisVar.getInitializer().replace(qualifier); - } - } + private void inlineParmOrThisVariable(PsiLocalVariable variable, boolean strictlyFinal) throws IncorrectOperationException { + PsiReference firstRef = ReferencesSearch.search(variable).findFirst(); - private boolean canInlineParmOrThisVariable(PsiLocalVariable variable) { - boolean isAccessedForWriting = false; - for (PsiReference ref : ReferencesSearch.search(variable)) { - PsiElement refElement = ref.getElement(); - if (refElement instanceof PsiExpression) { - if (PsiUtil.isAccessedForWriting((PsiExpression) refElement)) { - isAccessedForWriting = true; + if (firstRef == null) { + variable.getParent().delete(); //Q: side effects? + return; } - } - } - - PsiExpression initializer = variable.getInitializer(); - boolean shouldBeFinal = variable.hasModifierProperty(PsiModifier.FINAL) && false; - return canInlineParmOrThisVariable(initializer, shouldBeFinal, false, ReferencesSearch.search(variable).findAll().size(), isAccessedForWriting); - } - private void inlineParmOrThisVariable(PsiLocalVariable variable, boolean strictlyFinal) throws IncorrectOperationException { - PsiReference firstRef = ReferencesSearch.search(variable).findFirst(); - if (firstRef == null) { - variable.getParent().delete(); //Q: side effects? - return; - } + boolean isAccessedForWriting = false; + final Collection refs = ReferencesSearch.search(variable).findAll(); + for (PsiReference ref : refs) { + PsiElement refElement = ref.getElement(); + if (refElement instanceof PsiExpression) { + if (PsiUtil.isAccessedForWriting((PsiExpression)refElement)) { + isAccessedForWriting = true; + } + } + } + PsiExpression initializer = variable.getInitializer(); + boolean shouldBeFinal = variable.hasModifierProperty(PsiModifier.FINAL) && strictlyFinal; + if (canInlineParmOrThisVariable(initializer, shouldBeFinal, strictlyFinal, refs.size(), isAccessedForWriting)) { + if (shouldBeFinal) { + declareUsedLocalsFinal(initializer, strictlyFinal); + } + for (PsiReference ref : refs) { + final PsiJavaCodeReferenceElement javaRef = (PsiJavaCodeReferenceElement)ref; + if (initializer instanceof PsiThisExpression && ((PsiThisExpression)initializer).getQualifier() == null) { + final PsiClass varThisClass = RefactoringChangeUtil.getThisClass(variable); + if (RefactoringChangeUtil.getThisClass(javaRef) != varThisClass) { + initializer = JavaPsiFacade.getInstance(myManager.getProject()) + .getElementFactory() + .createExpressionFromText(varThisClass.getName() + ".this", variable); + } + } - boolean isAccessedForWriting = false; - final Collection refs = ReferencesSearch.search(variable).findAll(); - for (PsiReference ref : refs) { - PsiElement refElement = ref.getElement(); - if (refElement instanceof PsiExpression) { - if (PsiUtil.isAccessedForWriting((PsiExpression) refElement)) { - isAccessedForWriting = true; + PsiExpression expr = InlineUtil.inlineVariable(variable, initializer, javaRef); + + InlineUtil.tryToInlineArrayCreationForVarargs(expr); + + //Q: move the following code to some util? (addition to inline?) + if (expr instanceof PsiThisExpression) { + if (expr.getParent() instanceof PsiReferenceExpression) { + PsiReferenceExpression refExpr = (PsiReferenceExpression)expr.getParent(); + PsiElement refElement = refExpr.resolve(); + PsiExpression exprCopy = (PsiExpression)refExpr.copy(); + refExpr = + (PsiReferenceExpression)refExpr.replace(myFactory.createExpressionFromText(refExpr.getReferenceName(), null)); + if (refElement != null) { + PsiElement newRefElement = refExpr.resolve(); + if (!refElement.equals(newRefElement)) { + // change back + refExpr.replace(exprCopy); + } + } + } + } + } + variable.getParent().delete(); } - } } - PsiExpression initializer = variable.getInitializer(); - boolean shouldBeFinal = variable.hasModifierProperty(PsiModifier.FINAL) && strictlyFinal; - if (canInlineParmOrThisVariable(initializer, shouldBeFinal, strictlyFinal, refs.size(), isAccessedForWriting)) { - if (shouldBeFinal) { - declareUsedLocalsFinal(initializer, strictlyFinal); - } - for (PsiReference ref : refs) { - final PsiJavaCodeReferenceElement javaRef = (PsiJavaCodeReferenceElement) ref; - if (initializer instanceof PsiThisExpression && ((PsiThisExpression) initializer).getQualifier() == null) { - final PsiClass varThisClass = RefactoringChangeUtil.getThisClass(variable); - if (RefactoringChangeUtil.getThisClass(javaRef) != varThisClass) { - initializer = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory().createExpressionFromText(varThisClass.getName() + ".this", variable); - } - } - - PsiExpression expr = InlineUtil.inlineVariable(variable, initializer, javaRef); - - InlineUtil.tryToInlineArrayCreationForVarargs(expr); - - //Q: move the following code to some util? (addition to inline?) - if (expr instanceof PsiThisExpression) { - if (expr.getParent() instanceof PsiReferenceExpression) { - PsiReferenceExpression refExpr = (PsiReferenceExpression) expr.getParent(); - PsiElement refElement = refExpr.resolve(); - PsiExpression exprCopy = (PsiExpression) refExpr.copy(); - refExpr = (PsiReferenceExpression) refExpr.replace(myFactory.createExpressionFromText(refExpr.getReferenceName(), null)); - if (refElement != null) { - PsiElement newRefElement = refExpr.resolve(); - if (!refElement.equals(newRefElement)) { - // change back - refExpr.replace(exprCopy); - } - } - } - } - } - variable.getParent().delete(); - } - } + private boolean canInlineParmOrThisVariable( + PsiExpression initializer, + boolean shouldBeFinal, + boolean strictlyFinal, + int accessCount, + boolean isAccessedForWriting + ) { + if (strictlyFinal) { + class CanAllLocalsBeDeclaredFinal extends JavaRecursiveElementWalkingVisitor { + boolean success = true; + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiElement psiElement = expression.resolve(); + if (psiElement instanceof PsiLocalVariable || psiElement instanceof PsiParameter) { + if (!RefactoringUtil.canBeDeclaredFinal((PsiVariable)psiElement)) { + success = false; + } + } + } - private boolean canInlineParmOrThisVariable(PsiExpression initializer, - boolean shouldBeFinal, - boolean strictlyFinal, - int accessCount, - boolean isAccessedForWriting) { - if (strictlyFinal) { - class CanAllLocalsBeDeclaredFinal extends JavaRecursiveElementWalkingVisitor { - boolean success = true; + @Override + public void visitElement(PsiElement element) { + if (success) { + super.visitElement(element); + } + } + } - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - final PsiElement psiElement = expression.resolve(); - if (psiElement instanceof PsiLocalVariable || psiElement instanceof PsiParameter) { - if (!RefactoringUtil.canBeDeclaredFinal((PsiVariable) psiElement)) { - success = false; + final CanAllLocalsBeDeclaredFinal canAllLocalsBeDeclaredFinal = new CanAllLocalsBeDeclaredFinal(); + initializer.accept(canAllLocalsBeDeclaredFinal); + if (!canAllLocalsBeDeclaredFinal.success) { + return false; } - } } - - @Override - public void visitElement(PsiElement element) { - if (success) { - super.visitElement(element); - } + if (initializer instanceof PsiMethodReferenceExpression) { + return true; } - } - - final CanAllLocalsBeDeclaredFinal canAllLocalsBeDeclaredFinal = new CanAllLocalsBeDeclaredFinal(); - initializer.accept(canAllLocalsBeDeclaredFinal); - if (!canAllLocalsBeDeclaredFinal.success) return false; - } - if (initializer instanceof PsiMethodReferenceExpression) return true; - if (initializer instanceof PsiReferenceExpression) { - PsiVariable refVar = (PsiVariable) ((PsiReferenceExpression) initializer).resolve(); - if (refVar == null) { - return !isAccessedForWriting; - } - if (refVar instanceof PsiField) { - if (isAccessedForWriting) return false; - /* - PsiField field = (PsiField)refVar; - if (isFieldNonModifiable(field)){ - return true; - } - //TODO: other cases - return false; - */ - return true; //TODO: "suspicous" places to review by user! - } else { - if (isAccessedForWriting) { - if (refVar.hasModifierProperty(PsiModifier.FINAL) || shouldBeFinal) return false; - PsiReference[] refs = - ReferencesSearch.search(refVar, GlobalSearchScope.projectScope(myProject), false).toArray(new PsiReference[0]); - return refs.length == 1; //TODO: control flow - } else { - if (shouldBeFinal) { - return refVar.hasModifierProperty(PsiModifier.FINAL) || RefactoringUtil.canBeDeclaredFinal(refVar); - } - return true; + if (initializer instanceof PsiReferenceExpression) { + PsiVariable refVar = (PsiVariable)((PsiReferenceExpression)initializer).resolve(); + if (refVar == null) { + return !isAccessedForWriting; + } + if (refVar instanceof PsiField) { + if (isAccessedForWriting) { + return false; + } + /* + PsiField field = (PsiField)refVar; + if (isFieldNonModifiable(field)){ + return true; + } + //TODO: other cases + return false; + */ + return true; //TODO: "suspicous" places to review by user! + } + else { + if (isAccessedForWriting) { + if (refVar.hasModifierProperty(PsiModifier.FINAL) || shouldBeFinal) { + return false; + } + PsiReference[] refs = + ReferencesSearch.search(refVar, GlobalSearchScope.projectScope(myProject), false).toArray(new PsiReference[0]); + return refs.length == 1; //TODO: control flow + } + else { + if (shouldBeFinal) { + return refVar.hasModifierProperty(PsiModifier.FINAL) || RefactoringUtil.canBeDeclaredFinal(refVar); + } + return true; + } + } } - } - } else if (isAccessedForWriting) { - return false; - } else if (initializer instanceof PsiCallExpression) { - if (accessCount > 1) return false; - if (initializer instanceof PsiNewExpression) { - final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression) initializer).getArrayInitializer(); - if (arrayInitializer != null) { - for (PsiExpression expression : arrayInitializer.getInitializers()) { - if (!canInlineParmOrThisVariable(expression, shouldBeFinal, strictlyFinal, accessCount, false)) { - return false; - } - } - return true; + else if (isAccessedForWriting) { + return false; } - } - final PsiExpressionList argumentList = ((PsiCallExpression) initializer).getArgumentList(); - if (argumentList == null) return false; - final PsiExpression[] expressions = argumentList.getExpressions(); - for (PsiExpression expression : expressions) { - if (!canInlineParmOrThisVariable(expression, shouldBeFinal, strictlyFinal, accessCount, false)) { - return false; + else if (initializer instanceof PsiCallExpression) { + if (accessCount > 1) { + return false; + } + if (initializer instanceof PsiNewExpression) { + final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression)initializer).getArrayInitializer(); + if (arrayInitializer != null) { + for (PsiExpression expression : arrayInitializer.getInitializers()) { + if (!canInlineParmOrThisVariable(expression, shouldBeFinal, strictlyFinal, accessCount, false)) { + return false; + } + } + return true; + } + } + final PsiExpressionList argumentList = ((PsiCallExpression)initializer).getArgumentList(); + if (argumentList == null) { + return false; + } + final PsiExpression[] expressions = argumentList.getExpressions(); + for (PsiExpression expression : expressions) { + if (!canInlineParmOrThisVariable(expression, shouldBeFinal, strictlyFinal, accessCount, false)) { + return false; + } + } + return true; //TODO: "suspicous" places to review by user! + } + else if (initializer instanceof PsiLiteralExpression) { + return true; + } + else if (initializer instanceof PsiArrayAccessExpression) { + final PsiExpression arrayExpression = ((PsiArrayAccessExpression)initializer).getArrayExpression(); + final PsiExpression indexExpression = ((PsiArrayAccessExpression)initializer).getIndexExpression(); + return canInlineParmOrThisVariable(arrayExpression, shouldBeFinal, strictlyFinal, accessCount, false) && + canInlineParmOrThisVariable(indexExpression, shouldBeFinal, strictlyFinal, accessCount, false); + } + else if (initializer instanceof PsiParenthesizedExpression) { + PsiExpression expr = ((PsiParenthesizedExpression)initializer).getExpression(); + return expr == null || canInlineParmOrThisVariable(expr, shouldBeFinal, strictlyFinal, accessCount, false); + } + else if (initializer instanceof PsiTypeCastExpression) { + PsiExpression operand = ((PsiTypeCastExpression)initializer).getOperand(); + return operand != null && canInlineParmOrThisVariable(operand, shouldBeFinal, strictlyFinal, accessCount, false); + } + else if (initializer instanceof PsiPolyadicExpression) { + PsiPolyadicExpression binExpr = (PsiPolyadicExpression)initializer; + for (PsiExpression op : binExpr.getOperands()) { + if (!canInlineParmOrThisVariable(op, shouldBeFinal, strictlyFinal, accessCount, false)) { + return false; + } + } + return true; + } + else if (initializer instanceof PsiClassObjectAccessExpression) { + return true; + } + else if (initializer instanceof PsiThisExpression) { + return true; + } + else if (initializer instanceof PsiSuperExpression) { + return true; + } + else { + return false; } - } - return true; //TODO: "suspicous" places to review by user! - } else if (initializer instanceof PsiLiteralExpression) { - return true; - } else if (initializer instanceof PsiArrayAccessExpression) { - final PsiExpression arrayExpression = ((PsiArrayAccessExpression) initializer).getArrayExpression(); - final PsiExpression indexExpression = ((PsiArrayAccessExpression) initializer).getIndexExpression(); - return canInlineParmOrThisVariable(arrayExpression, shouldBeFinal, strictlyFinal, accessCount, false) && - canInlineParmOrThisVariable(indexExpression, shouldBeFinal, strictlyFinal, accessCount, false); - } else if (initializer instanceof PsiParenthesizedExpression) { - PsiExpression expr = ((PsiParenthesizedExpression) initializer).getExpression(); - return expr == null || canInlineParmOrThisVariable(expr, shouldBeFinal, strictlyFinal, accessCount, false); - } else if (initializer instanceof PsiTypeCastExpression) { - PsiExpression operand = ((PsiTypeCastExpression) initializer).getOperand(); - return operand != null && canInlineParmOrThisVariable(operand, shouldBeFinal, strictlyFinal, accessCount, false); - } else if (initializer instanceof PsiPolyadicExpression) { - PsiPolyadicExpression binExpr = (PsiPolyadicExpression) initializer; - for (PsiExpression op : binExpr.getOperands()) { - if (!canInlineParmOrThisVariable(op, shouldBeFinal, strictlyFinal, accessCount, false)) return false; - } - return true; - } else if (initializer instanceof PsiClassObjectAccessExpression) { - return true; - } else if (initializer instanceof PsiThisExpression) { - return true; - } else if (initializer instanceof PsiSuperExpression) { - return true; - } else { - return false; } - } - private static void declareUsedLocalsFinal(PsiElement expr, boolean strictlyFinal) throws IncorrectOperationException { - if (expr instanceof PsiReferenceExpression) { - PsiElement refElement = ((PsiReferenceExpression) expr).resolve(); - if (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) { - if (strictlyFinal || RefactoringUtil.canBeDeclaredFinal((PsiVariable) refElement)) { - PsiUtil.setModifierProperty(((PsiVariable) refElement), PsiModifier.FINAL, true); + private static void declareUsedLocalsFinal(PsiElement expr, boolean strictlyFinal) throws IncorrectOperationException { + if (expr instanceof PsiReferenceExpression) { + PsiElement refElement = ((PsiReferenceExpression)expr).resolve(); + if (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) { + if (strictlyFinal || RefactoringUtil.canBeDeclaredFinal((PsiVariable)refElement)) { + PsiUtil.setModifierProperty(((PsiVariable)refElement), PsiModifier.FINAL, true); + } + } + } + PsiElement[] children = expr.getChildren(); + for (PsiElement child : children) { + declareUsedLocalsFinal(child, strictlyFinal); } - } - } - PsiElement[] children = expr.getChildren(); - for (PsiElement child : children) { - declareUsedLocalsFinal(child, strictlyFinal); } - } /* private boolean isFieldNonModifiable(PsiField field) { @@ -1134,354 +1267,407 @@ private boolean isFieldNonModifiable(PsiField field) { } */ - private void inlineResultVariable(PsiVariable resultVar) throws IncorrectOperationException { - PsiAssignmentExpression assignment = null; - PsiReferenceExpression resultUsage = null; - for (PsiReference ref1 : ReferencesSearch.search(resultVar, GlobalSearchScope.projectScope(myProject), false)) { - PsiReferenceExpression ref = (PsiReferenceExpression) ref1; - if (ref.getParent() instanceof PsiAssignmentExpression && ((PsiAssignmentExpression) ref.getParent()).getLExpression().equals(ref)) { - if (assignment != null) { - assignment = null; - break; - } else { - assignment = (PsiAssignmentExpression) ref.getParent(); - } - } else { - LOG.assertTrue(resultUsage == null, "old:" + resultUsage + "; new:" + ref); - resultUsage = ref; - } - } + private void inlineResultVariable(PsiVariable resultVar) throws IncorrectOperationException { + PsiAssignmentExpression assignment = null; + PsiReferenceExpression resultUsage = null; + for (PsiReference ref1 : ReferencesSearch.search(resultVar, GlobalSearchScope.projectScope(myProject), false)) { + PsiReferenceExpression ref = (PsiReferenceExpression)ref1; + if (ref.getParent() instanceof PsiAssignmentExpression + && ((PsiAssignmentExpression)ref.getParent()).getLExpression().equals(ref)) { + if (assignment != null) { + assignment = null; + break; + } + else { + assignment = (PsiAssignmentExpression)ref.getParent(); + } + } + else { + LOG.assertTrue(resultUsage == null, "old:" + resultUsage + "; new:" + ref); + resultUsage = ref; + } + } - if (assignment == null) return; - boolean condition = assignment.getParent() instanceof PsiExpressionStatement; - LOG.assertTrue(condition); - // SCR3175 fixed: inline only if declaration and assignment is in the same code block. - if (!(assignment.getParent().getParent() == resultVar.getParent().getParent())) return; - if (resultUsage != null) { - String name = resultVar.getName(); - PsiDeclarationStatement declaration = - myFactory.createVariableDeclarationStatement(name, resultVar.getType(), assignment.getRExpression()); - declaration = (PsiDeclarationStatement) assignment.getParent().replace(declaration); - resultVar.getParent().delete(); - resultVar = (PsiVariable) declaration.getDeclaredElements()[0]; - - PsiElement parentStatement = RefactoringUtil.getParentStatement(resultUsage, true); - PsiElement next = declaration.getNextSibling(); - boolean canInline = false; - while (true) { - if (next == null) break; - if (parentStatement.equals(next)) { - canInline = true; - break; - } - if (next instanceof PsiStatement) break; - next = next.getNextSibling(); - } + if (assignment == null) { + return; + } + boolean condition = assignment.getParent() instanceof PsiExpressionStatement; + LOG.assertTrue(condition); + // SCR3175 fixed: inline only if declaration and assignment is in the same code block. + if (!(assignment.getParent().getParent() == resultVar.getParent().getParent())) { + return; + } + if (resultUsage != null) { + String name = resultVar.getName(); + PsiDeclarationStatement declaration = + myFactory.createVariableDeclarationStatement(name, resultVar.getType(), assignment.getRExpression()); + declaration = (PsiDeclarationStatement)assignment.getParent().replace(declaration); + resultVar.getParent().delete(); + resultVar = (PsiVariable)declaration.getDeclaredElements()[0]; + + PsiElement parentStatement = RefactoringUtil.getParentStatement(resultUsage, true); + PsiElement next = declaration.getNextSibling(); + boolean canInline = false; + while (true) { + if (next == null) { + break; + } + if (parentStatement.equals(next)) { + canInline = true; + break; + } + if (next instanceof PsiStatement) { + break; + } + next = next.getNextSibling(); + } - if (canInline) { - InlineUtil.inlineVariable(resultVar, resultVar.getInitializer(), resultUsage); - declaration.delete(); - } - } else { - PsiExpression rExpression = assignment.getRExpression(); - while (rExpression instanceof PsiReferenceExpression) - rExpression = ((PsiReferenceExpression) rExpression).getQualifierExpression(); - if (rExpression == null || !PsiUtil.isStatement(rExpression)) { - assignment.delete(); - } else { - assignment.replace(rExpression); - } - resultVar.delete(); + if (canInline) { + InlineUtil.inlineVariable(resultVar, resultVar.getInitializer(), resultUsage); + declaration.delete(); + } + } + else { + PsiExpression rExpression = assignment.getRExpression(); + while (rExpression instanceof PsiReferenceExpression) + rExpression = ((PsiReferenceExpression)rExpression).getQualifierExpression(); + if (rExpression == null || !PsiUtil.isStatement(rExpression)) { + assignment.delete(); + } + else { + assignment.replace(rExpression); + } + resultVar.delete(); + } } - } - private static final Key MARK_KEY = Key.create(""); + private static final Key MARK_KEY = Key.create(""); - private PsiReferenceExpression[] addBracesWhenNeeded(PsiReferenceExpression[] refs) throws IncorrectOperationException { - ArrayList refsVector = new ArrayList(); - ArrayList addedBracesVector = new ArrayList(); - myAddedClassInitializers = new HashMap(); + private PsiReferenceExpression[] addBracesWhenNeeded(PsiReferenceExpression[] refs) throws IncorrectOperationException { + ArrayList refsVector = new ArrayList(); + ArrayList addedBracesVector = new ArrayList(); + myAddedClassInitializers = new HashMap(); - for (PsiReferenceExpression ref : refs) { - ref.putCopyableUserData(MARK_KEY, ""); - } + for (PsiReferenceExpression ref : refs) { + ref.putCopyableUserData(MARK_KEY, ""); + } + + RefLoop: + for (PsiReferenceExpression ref : refs) { + if (!ref.isValid()) { + continue; + } + + PsiElement parentStatement = RefactoringUtil.getParentStatement(ref, true); + if (parentStatement != null) { + PsiElement parent = ref.getParent(); + while (!parent.equals(parentStatement)) { + if (parent instanceof PsiStatement && !(parent instanceof PsiDeclarationStatement)) { + String text = "{\n}"; + PsiBlockStatement blockStatement = (PsiBlockStatement)myFactory.createStatementFromText(text, null); + blockStatement = (PsiBlockStatement)myCodeStyleManager.reformat(blockStatement); + blockStatement.getCodeBlock().add(parent); + blockStatement = (PsiBlockStatement)parent.replace(blockStatement); + + PsiElement newStatement = blockStatement.getCodeBlock().getStatements()[0]; + addMarkedElements(refsVector, newStatement); + addedBracesVector.add(blockStatement.getCodeBlock()); + continue RefLoop; + } + parent = parent.getParent(); + } + final PsiElement lambdaExpr = parentStatement.getParent(); + if (lambdaExpr instanceof PsiLambdaExpression) { + final PsiLambdaExpression newLambdaExpr = (PsiLambdaExpression)myFactory.createExpressionFromText( + ((PsiLambdaExpression)lambdaExpr).getParameterList().getText() + " -> " + "{\n}", lambdaExpr); + final PsiStatement statementFromText; + if (PsiType.VOID.equals(LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)lambdaExpr))) { + statementFromText = myFactory.createStatementFromText("a;", lambdaExpr); + ((PsiExpressionStatement)statementFromText).getExpression().replace(parentStatement); + } + else { + statementFromText = myFactory.createStatementFromText("return a;", lambdaExpr); + ((PsiReturnStatement)statementFromText).getReturnValue().replace(parentStatement); + } + + newLambdaExpr.getBody().add(statementFromText); + + final PsiCodeBlock body = (PsiCodeBlock)((PsiLambdaExpression)lambdaExpr.replace(newLambdaExpr)).getBody(); + PsiElement newStatement = body.getStatements()[0]; + addMarkedElements(refsVector, newStatement); + addedBracesVector.add(body); + continue; + + } + } + else { + final PsiField field = PsiTreeUtil.getParentOfType(ref, PsiField.class); + if (field != null) { + if (field instanceof PsiEnumConstant) { + inlineEnumConstantParameter(refsVector, ref); + continue; + } + field.normalizeDeclaration(); + final PsiExpression initializer = field.getInitializer(); + LOG.assertTrue(initializer != null); + PsiClassInitializer classInitializer = myFactory.createClassInitializer(); + final PsiClass containingClass = field.getContainingClass(); + classInitializer = (PsiClassInitializer)containingClass.addAfter(classInitializer, field); + containingClass.addAfter(CodeEditUtil.createLineFeed(field.getManager()), field); + final PsiCodeBlock body = classInitializer.getBody(); + PsiExpressionStatement statement = + (PsiExpressionStatement)myFactory.createStatementFromText(field.getName() + " = 0;", body); + statement = (PsiExpressionStatement)body.add(statement); + final PsiAssignmentExpression assignment = (PsiAssignmentExpression)statement.getExpression(); + assignment.getLExpression().replace(RenameJavaVariableProcessor.createMemberReference(field, assignment)); + assignment.getRExpression().replace(initializer); + addMarkedElements(refsVector, statement); + if (field.hasModifierProperty(PsiModifier.STATIC)) { + PsiUtil.setModifierProperty(classInitializer, PsiModifier.STATIC, true); + } + myAddedClassInitializers.put(field, classInitializer); + continue; + } + } - RefLoop: - for (PsiReferenceExpression ref : refs) { - if (!ref.isValid()) continue; - - PsiElement parentStatement = RefactoringUtil.getParentStatement(ref, true); - if (parentStatement != null) { - PsiElement parent = ref.getParent(); - while (!parent.equals(parentStatement)) { - if (parent instanceof PsiStatement && !(parent instanceof PsiDeclarationStatement)) { - String text = "{\n}"; - PsiBlockStatement blockStatement = (PsiBlockStatement) myFactory.createStatementFromText(text, null); - blockStatement = (PsiBlockStatement) myCodeStyleManager.reformat(blockStatement); - blockStatement.getCodeBlock().add(parent); - blockStatement = (PsiBlockStatement) parent.replace(blockStatement); - - PsiElement newStatement = blockStatement.getCodeBlock().getStatements()[0]; - addMarkedElements(refsVector, newStatement); - addedBracesVector.add(blockStatement.getCodeBlock()); - continue RefLoop; - } - parent = parent.getParent(); - } - final PsiElement lambdaExpr = parentStatement.getParent(); - if (lambdaExpr instanceof PsiLambdaExpression) { - final PsiLambdaExpression newLambdaExpr = (PsiLambdaExpression) myFactory.createExpressionFromText( - ((PsiLambdaExpression) lambdaExpr).getParameterList().getText() + " -> " + "{\n}", lambdaExpr); - final PsiStatement statementFromText; - if (PsiType.VOID.equals(LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression) lambdaExpr))) { - statementFromText = myFactory.createStatementFromText("a;", lambdaExpr); - ((PsiExpressionStatement) statementFromText).getExpression().replace(parentStatement); - } else { - statementFromText = myFactory.createStatementFromText("return a;", lambdaExpr); - ((PsiReturnStatement) statementFromText).getReturnValue().replace(parentStatement); - } - - newLambdaExpr.getBody().add(statementFromText); - - final PsiCodeBlock body = (PsiCodeBlock) ((PsiLambdaExpression) lambdaExpr.replace(newLambdaExpr)).getBody(); - PsiElement newStatement = body.getStatements()[0]; - addMarkedElements(refsVector, newStatement); - addedBracesVector.add(body); - continue; - - } - } else { - final PsiField field = PsiTreeUtil.getParentOfType(ref, PsiField.class); - if (field != null) { - if (field instanceof PsiEnumConstant) { - inlineEnumConstantParameter(refsVector, ref); - continue; - } - field.normalizeDeclaration(); - final PsiExpression initializer = field.getInitializer(); - LOG.assertTrue(initializer != null); - PsiClassInitializer classInitializer = myFactory.createClassInitializer(); - final PsiClass containingClass = field.getContainingClass(); - classInitializer = (PsiClassInitializer) containingClass.addAfter(classInitializer, field); - containingClass.addAfter(CodeEditUtil.createLineFeed(field.getManager()), field); - final PsiCodeBlock body = classInitializer.getBody(); - PsiExpressionStatement statement = (PsiExpressionStatement) myFactory.createStatementFromText(field.getName() + " = 0;", body); - statement = (PsiExpressionStatement) body.add(statement); - final PsiAssignmentExpression assignment = (PsiAssignmentExpression) statement.getExpression(); - assignment.getLExpression().replace(RenameJavaVariableProcessor.createMemberReference(field, assignment)); - assignment.getRExpression().replace(initializer); - addMarkedElements(refsVector, statement); - if (field.hasModifierProperty(PsiModifier.STATIC)) { - PsiUtil.setModifierProperty(classInitializer, PsiModifier.STATIC, true); - } - myAddedClassInitializers.put(field, classInitializer); - continue; + refsVector.add(ref); } - } - refsVector.add(ref); - } + for (PsiReferenceExpression ref : refs) { + ref.putCopyableUserData(MARK_KEY, null); + } - for (PsiReferenceExpression ref : refs) { - ref.putCopyableUserData(MARK_KEY, null); + myAddedBraces = addedBracesVector.toArray(new PsiCodeBlock[addedBracesVector.size()]); + return refsVector.toArray(new PsiReferenceExpression[refsVector.size()]); } - myAddedBraces = addedBracesVector.toArray(new PsiCodeBlock[addedBracesVector.size()]); - return refsVector.toArray(new PsiReferenceExpression[refsVector.size()]); - } + private void inlineEnumConstantParameter( + final List refsVector, + final PsiReferenceExpression ref + ) throws IncorrectOperationException { + PsiExpression expr = getSimpleReturnedExpression(myMethod); + if (expr != null) { + refsVector.add(ref); + } + else { + PsiCall call = PsiTreeUtil.getParentOfType(ref, PsiCall.class); + @NonNls String text = + "new Object() { " + myMethod.getReturnTypeElement().getText() + " evaluate() { return " + call.getText() + ";}}.evaluate"; + PsiExpression callExpr = JavaPsiFacade.getInstance(myProject).getParserFacade().createExpressionFromText(text, call); + PsiElement classExpr = ref.replace(callExpr); + classExpr.accept(new JavaRecursiveElementWalkingVisitor() { + public void visitReturnStatement(final PsiReturnStatement statement) { + super.visitReturnStatement(statement); + PsiExpression expr = statement.getReturnValue(); + if (expr instanceof PsiMethodCallExpression) { + refsVector.add(((PsiMethodCallExpression)expr).getMethodExpression()); + } + } + }); + if (classExpr.getParent() instanceof PsiMethodCallExpression) { + PsiExpressionList args = ((PsiMethodCallExpression)classExpr.getParent()).getArgumentList(); + PsiExpression[] argExpressions = args.getExpressions(); + if (argExpressions.length > 0) { + args.deleteChildRange(argExpressions[0], argExpressions[argExpressions.length - 1]); + } + } + } + } - private void inlineEnumConstantParameter(final List refsVector, - final PsiReferenceExpression ref) throws IncorrectOperationException { - PsiExpression expr = getSimpleReturnedExpression(myMethod); - if (expr != null) { - refsVector.add(ref); - } else { - PsiCall call = PsiTreeUtil.getParentOfType(ref, PsiCall.class); - @NonNls String text = "new Object() { " + myMethod.getReturnTypeElement().getText() + " evaluate() { return " + call.getText() + ";}}.evaluate"; - PsiExpression callExpr = JavaPsiFacade.getInstance(myProject).getParserFacade().createExpressionFromText(text, call); - PsiElement classExpr = ref.replace(callExpr); - classExpr.accept(new JavaRecursiveElementWalkingVisitor() { - public void visitReturnStatement(final PsiReturnStatement statement) { - super.visitReturnStatement(statement); - PsiExpression expr = statement.getReturnValue(); - if (expr instanceof PsiMethodCallExpression) { - refsVector.add(((PsiMethodCallExpression) expr).getMethodExpression()); - } - } - }); - if (classExpr.getParent() instanceof PsiMethodCallExpression) { - PsiExpressionList args = ((PsiMethodCallExpression) classExpr.getParent()).getArgumentList(); - PsiExpression[] argExpressions = args.getExpressions(); - if (argExpressions.length > 0) { - args.deleteChildRange(argExpressions[0], argExpressions[argExpressions.length - 1]); + @Nullable + private static PsiExpression getSimpleReturnedExpression(final PsiMethod method) { + PsiCodeBlock body = method.getBody(); + if (body == null) { + return null; } - } + PsiStatement[] psiStatements = body.getStatements(); + if (psiStatements.length != 1) { + return null; + } + PsiStatement statement = psiStatements[0]; + if (!(statement instanceof PsiReturnStatement)) { + return null; + } + return ((PsiReturnStatement)statement).getReturnValue(); } - } - @Nullable - private static PsiExpression getSimpleReturnedExpression(final PsiMethod method) { - PsiCodeBlock body = method.getBody(); - if (body == null) return null; - PsiStatement[] psiStatements = body.getStatements(); - if (psiStatements.length != 1) return null; - PsiStatement statement = psiStatements[0]; - if (!(statement instanceof PsiReturnStatement)) return null; - return ((PsiReturnStatement) statement).getReturnValue(); - } + private static void addMarkedElements(final List array, PsiElement scope) { + scope.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element.getCopyableUserData(MARK_KEY) != null) { + array.add((PsiReferenceExpression)element); + element.putCopyableUserData(MARK_KEY, null); + } + super.visitElement(element); + } + }); + } - private static void addMarkedElements(final List array, PsiElement scope) { - scope.accept(new PsiRecursiveElementWalkingVisitor() { - @Override - public void visitElement(PsiElement element) { - if (element.getCopyableUserData(MARK_KEY) != null) { - array.add((PsiReferenceExpression) element); - element.putCopyableUserData(MARK_KEY, null); + private void removeAddedBracesWhenPossible() throws IncorrectOperationException { + if (myAddedBraces == null) { + return; } - super.visitElement(element); - } - }); - } - private void removeAddedBracesWhenPossible() throws IncorrectOperationException { - if (myAddedBraces == null) return; - - for (PsiCodeBlock codeBlock : myAddedBraces) { - PsiStatement[] statements = codeBlock.getStatements(); - if (statements.length == 1) { - final PsiElement codeBlockParent = codeBlock.getParent(); - if (codeBlockParent instanceof PsiLambdaExpression) { - if (statements[0] instanceof PsiReturnStatement) { - final PsiExpression returnValue = ((PsiReturnStatement) statements[0]).getReturnValue(); - if (returnValue != null) { - codeBlock.replace(returnValue); - } - } else if (statements[0] instanceof PsiExpressionStatement) { - codeBlock.replace(((PsiExpressionStatement) statements[0]).getExpression()); - } - } else { - if (codeBlockParent instanceof PsiBlockStatement) { - codeBlockParent.replace(statements[0]); - } else { - codeBlock.replace(statements[0]); - } + for (PsiCodeBlock codeBlock : myAddedBraces) { + PsiStatement[] statements = codeBlock.getStatements(); + if (statements.length == 1) { + final PsiElement codeBlockParent = codeBlock.getParent(); + if (codeBlockParent instanceof PsiLambdaExpression) { + if (statements[0] instanceof PsiReturnStatement) { + final PsiExpression returnValue = ((PsiReturnStatement)statements[0]).getReturnValue(); + if (returnValue != null) { + codeBlock.replace(returnValue); + } + } + else if (statements[0] instanceof PsiExpressionStatement) { + codeBlock.replace(((PsiExpressionStatement)statements[0]).getExpression()); + } + } + else if (codeBlockParent instanceof PsiBlockStatement) { + codeBlockParent.replace(statements[0]); + } + else { + codeBlock.replace(statements[0]); + } + } } - } - } - final Set fields = myAddedClassInitializers.keySet(); + final Set fields = myAddedClassInitializers.keySet(); - for (PsiField psiField : fields) { - final PsiClassInitializer classInitializer = myAddedClassInitializers.get(psiField); - final PsiExpression initializer = getSimpleFieldInitializer(psiField, classInitializer); - if (initializer != null) { - psiField.getInitializer().replace(initializer); - classInitializer.delete(); - } else { - psiField.getInitializer().delete(); - } + for (PsiField psiField : fields) { + final PsiClassInitializer classInitializer = myAddedClassInitializers.get(psiField); + final PsiExpression initializer = getSimpleFieldInitializer(psiField, classInitializer); + if (initializer != null) { + psiField.getInitializer().replace(initializer); + classInitializer.delete(); + } + else { + psiField.getInitializer().delete(); + } + } } - } - - @Nullable - private PsiExpression getSimpleFieldInitializer(PsiField field, PsiClassInitializer initializer) { - final PsiStatement[] statements = initializer.getBody().getStatements(); - if (statements.length != 1) return null; - if (!(statements[0] instanceof PsiExpressionStatement)) return null; - final PsiExpression expression = ((PsiExpressionStatement) statements[0]).getExpression(); - if (!(expression instanceof PsiAssignmentExpression)) return null; - final PsiExpression lExpression = ((PsiAssignmentExpression) expression).getLExpression(); - if (!(lExpression instanceof PsiReferenceExpression)) return null; - final PsiElement resolved = ((PsiReferenceExpression) lExpression).resolve(); - if (!myManager.areElementsEquivalent(field, resolved)) return null; - return ((PsiAssignmentExpression) expression).getRExpression(); - } - public static String checkCalledInSuperOrThisExpr(PsiCodeBlock methodBody, final PsiElement element) { - if (methodBody.getStatements().length > 1) { - PsiExpression expr = PsiTreeUtil.getParentOfType(element, PsiExpression.class); - while (expr != null) { - if (RefactoringChangeUtil.isSuperOrThisMethodCall(expr)) { - return "Inline cannot be applied to multiline method in constructor call"; + @Nullable + private PsiExpression getSimpleFieldInitializer(PsiField field, PsiClassInitializer initializer) { + final PsiStatement[] statements = initializer.getBody().getStatements(); + if (statements.length != 1) { + return null; } - expr = PsiTreeUtil.getParentOfType(expr, PsiExpression.class, true); - } + if (!(statements[0] instanceof PsiExpressionStatement)) { + return null; + } + final PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression(); + if (!(expression instanceof PsiAssignmentExpression)) { + return null; + } + final PsiExpression lExpression = ((PsiAssignmentExpression)expression).getLExpression(); + if (!(lExpression instanceof PsiReferenceExpression)) { + return null; + } + final PsiElement resolved = ((PsiReferenceExpression)lExpression).resolve(); + if (!myManager.areElementsEquivalent(field, resolved)) { + return null; + } + return ((PsiAssignmentExpression)expression).getRExpression(); } - return null; - } - public static boolean checkBadReturns(PsiMethod method) { - PsiReturnStatement[] returns = RefactoringUtil.findReturnStatements(method); - if (returns.length == 0) return false; - PsiCodeBlock body = method.getBody(); - ControlFlow controlFlow; - try { - controlFlow = ControlFlowFactory.getInstance(body.getProject()).getControlFlow(body, new LocalsControlFlowPolicy(body), false); - } catch (AnalysisCanceledException e) { - return false; - } - if (LOG.isDebugEnabled()) { - LOG.debug("Control flow:"); - LOG.debug(controlFlow.toString()); + public static String checkCalledInSuperOrThisExpr(PsiCodeBlock methodBody, final PsiElement element) { + if (methodBody.getStatements().length > 1) { + PsiExpression expr = PsiTreeUtil.getParentOfType(element, PsiExpression.class); + while (expr != null) { + if (RefactoringChangeUtil.isSuperOrThisMethodCall(expr)) { + return "Inline cannot be applied to multiline method in constructor call"; + } + expr = PsiTreeUtil.getParentOfType(expr, PsiExpression.class, true); + } + } + return null; } - List instructions = new ArrayList(controlFlow.getInstructions()); + public static boolean checkBadReturns(PsiMethod method) { + PsiReturnStatement[] returns = RefactoringUtil.findReturnStatements(method); + if (returns.length == 0) { + return false; + } + PsiCodeBlock body = method.getBody(); + ControlFlow controlFlow; + try { + controlFlow = ControlFlowFactory.getInstance(body.getProject()).getControlFlow(body, new LocalsControlFlowPolicy(body), false); + } + catch (AnalysisCanceledException e) { + return false; + } + if (LOG.isDebugEnabled()) { + LOG.debug("Control flow:"); + LOG.debug(controlFlow.toString()); + } + + List instructions = new ArrayList(controlFlow.getInstructions()); - // temporary replace all return's with empty statements in the flow - for (PsiReturnStatement aReturn : returns) { - int offset = controlFlow.getStartOffset(aReturn); - int endOffset = controlFlow.getEndOffset(aReturn); - while (offset <= endOffset && !(instructions.get(offset) instanceof GoToInstruction)) { - offset++; - } - LOG.assertTrue(instructions.get(offset) instanceof GoToInstruction); - instructions.set(offset, EmptyInstruction.INSTANCE); - } + // temporary replace all return's with empty statements in the flow + for (PsiReturnStatement aReturn : returns) { + int offset = controlFlow.getStartOffset(aReturn); + int endOffset = controlFlow.getEndOffset(aReturn); + while (offset <= endOffset && !(instructions.get(offset) instanceof GoToInstruction)) { + offset++; + } + LOG.assertTrue(instructions.get(offset) instanceof GoToInstruction); + instructions.set(offset, EmptyInstruction.INSTANCE); + } - for (PsiReturnStatement aReturn : returns) { - int offset = controlFlow.getEndOffset(aReturn); - while (true) { - if (offset == instructions.size()) break; - Instruction instruction = instructions.get(offset); - if (instruction instanceof GoToInstruction) { - offset = ((GoToInstruction) instruction).offset; - } else if (instruction instanceof ThrowToInstruction) { - offset = ((ThrowToInstruction) instruction).offset; - } else if (instruction instanceof ConditionalThrowToInstruction) { - // In case of "conditional throw to", control flow will not be altered - // If exception handler is in method, we will inline it to ivokation site - // If exception handler is at invocation site, execution will continue to get there - offset++; - } else { - return true; + for (PsiReturnStatement aReturn : returns) { + int offset = controlFlow.getEndOffset(aReturn); + while (true) { + if (offset == instructions.size()) { + break; + } + Instruction instruction = instructions.get(offset); + if (instruction instanceof GoToInstruction) { + offset = ((GoToInstruction)instruction).offset; + } + else if (instruction instanceof ThrowToInstruction) { + offset = ((ThrowToInstruction)instruction).offset; + } + else if (instruction instanceof ConditionalThrowToInstruction) { + // In case of "conditional throw to", control flow will not be altered + // If exception handler is in method, we will inline it to ivokation site + // If exception handler is at invocation site, execution will continue to get there + offset++; + } + else { + return true; + } + } } - } + + return false; } - return false; - } + private static class BlockData { + final PsiCodeBlock block; + final PsiLocalVariable thisVar; + final PsiLocalVariable[] parmVars; + final PsiLocalVariable resultVar; - private static class BlockData { - final PsiCodeBlock block; - final PsiLocalVariable thisVar; - final PsiLocalVariable[] parmVars; - final PsiLocalVariable resultVar; - - public BlockData(PsiCodeBlock block, PsiLocalVariable thisVar, PsiLocalVariable[] parmVars, PsiLocalVariable resultVar) { - this.block = block; - this.thisVar = thisVar; - this.parmVars = parmVars; - this.resultVar = resultVar; + public BlockData(PsiCodeBlock block, PsiLocalVariable thisVar, PsiLocalVariable[] parmVars, PsiLocalVariable resultVar) { + this.block = block; + this.thisVar = thisVar; + this.parmVars = parmVars; + this.resultVar = resultVar; + } } - } - @Nonnull - protected Collection getElementsToWrite(@Nonnull final UsageViewDescriptor descriptor) { - if (myInlineThisOnly) { - return Collections.singletonList(myReference); - } else { - if (!checkReadOnly()) return Collections.emptyList(); - return myReference == null ? Collections.singletonList(myMethod) : Arrays.asList(myReference, myMethod); + @Nonnull + protected Collection getElementsToWrite(@Nonnull final UsageViewDescriptor descriptor) { + if (myInlineThisOnly) { + return Collections.singletonList(myReference); + } + else { + if (!checkReadOnly()) { + return Collections.emptyList(); + } + return myReference == null ? Collections.singletonList(myMethod) : Arrays.asList(myReference, myMethod); + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java index 4052e9e802..a621836cc8 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineParameterExpressionProcessor.java @@ -178,7 +178,7 @@ public void visitReferenceExpression(PsiReferenceExpression referenceExpression) @Override @RequiredUIAccess - protected boolean preprocessUsages(SimpleReference refUsages) { + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { MultiMap conflicts = new MultiMap<>(); UsageInfo[] usages = refUsages.get(); InaccessibleExpressionsDetector detector = new InaccessibleExpressionsDetector(conflicts); diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineToAnonymousClassProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineToAnonymousClassProcessor.java index d1a5d9bfbf..5bf1d61062 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineToAnonymousClassProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/inline/InlineToAnonymousClassProcessor.java @@ -31,10 +31,11 @@ import consulo.logging.Logger; import consulo.project.Project; import consulo.project.ui.wm.WindowManager; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -44,276 +45,298 @@ * @author yole */ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(InlineToAnonymousClassProcessor.class); + private static final Logger LOG = Logger.getInstance(InlineToAnonymousClassProcessor.class); - private PsiClass myClass; - private final PsiCall myCallToInline; - private final boolean myInlineThisOnly; - private final boolean mySearchInComments; - private final boolean mySearchInNonJavaFiles; + private PsiClass myClass; + private final PsiCall myCallToInline; + private final boolean myInlineThisOnly; + private final boolean mySearchInComments; + private final boolean mySearchInNonJavaFiles; - protected InlineToAnonymousClassProcessor(Project project, - PsiClass psiClass, - @Nullable final PsiCall callToInline, - boolean inlineThisOnly, - final boolean searchInComments, - final boolean searchInNonJavaFiles) { - super(project); - myClass = psiClass; - myCallToInline = callToInline; - myInlineThisOnly = inlineThisOnly; - if (myInlineThisOnly) assert myCallToInline != null; - mySearchInComments = searchInComments; - mySearchInNonJavaFiles = searchInNonJavaFiles; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new InlineViewDescriptor(myClass); - } - - @Nonnull - protected UsageInfo[] findUsages() { - if (myInlineThisOnly) { - return new UsageInfo[] { new UsageInfo(myCallToInline) }; - } - Set usages = new HashSet(); - for (PsiReference reference : ReferencesSearch.search(myClass)) { - usages.add(new UsageInfo(reference.getElement())); + protected InlineToAnonymousClassProcessor( + Project project, + PsiClass psiClass, + @Nullable final PsiCall callToInline, + boolean inlineThisOnly, + final boolean searchInComments, + final boolean searchInNonJavaFiles + ) { + super(project); + myClass = psiClass; + myCallToInline = callToInline; + myInlineThisOnly = inlineThisOnly; + if (myInlineThisOnly) { + assert myCallToInline != null; + } + mySearchInComments = searchInComments; + mySearchInNonJavaFiles = searchInNonJavaFiles; } - final String qName = myClass.getQualifiedName(); - if (qName != null) { - List nonCodeUsages = new ArrayList(); - if (mySearchInComments) { - TextOccurrencesUtil.addUsagesInStringsAndComments(myClass, qName, nonCodeUsages, - new NonCodeUsageInfoFactory(myClass, qName)); - } - - if (mySearchInNonJavaFiles) { - GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myClass.getProject()); - TextOccurrencesUtil.addTextOccurences(myClass, qName, projectScope, nonCodeUsages, - new NonCodeUsageInfoFactory(myClass, qName)); - } - usages.addAll(nonCodeUsages); + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new InlineViewDescriptor(myClass); } - return usages.toArray(new UsageInfo[usages.size()]); - } + @Nonnull + protected UsageInfo[] findUsages() { + if (myInlineThisOnly) { + return new UsageInfo[]{new UsageInfo(myCallToInline)}; + } + Set usages = new HashSet(); + for (PsiReference reference : ReferencesSearch.search(myClass)) { + usages.add(new UsageInfo(reference.getElement())); + } + + final String qName = myClass.getQualifiedName(); + if (qName != null) { + List nonCodeUsages = new ArrayList(); + if (mySearchInComments) { + TextOccurrencesUtil.addUsagesInStringsAndComments(myClass, qName, nonCodeUsages, + new NonCodeUsageInfoFactory(myClass, qName) + ); + } - protected void refreshElements(PsiElement[] elements) { - assert elements.length == 1; - myClass = (PsiClass) elements [0]; - } + if (mySearchInNonJavaFiles) { + GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myClass.getProject()); + TextOccurrencesUtil.addTextOccurences(myClass, qName, projectScope, nonCodeUsages, + new NonCodeUsageInfoFactory(myClass, qName) + ); + } + usages.addAll(nonCodeUsages); + } - protected boolean isPreviewUsages(UsageInfo[] usages) { - if (super.isPreviewUsages(usages)) return true; - for(UsageInfo usage: usages) { - if (isForcePreview(usage)) { - WindowManager.getInstance().getStatusBar(myProject) - .setInfo(RefactoringLocalize.occurrencesFoundInCommentsStringsAndNonJavaFiles().get()); - return true; - } + return usages.toArray(new UsageInfo[usages.size()]); } - return false; - } - private static boolean isForcePreview(final UsageInfo usage) { - if (usage.isNonCodeUsage) return true; - PsiElement element = usage.getElement(); - if (element != null) { - PsiFile file = element.getContainingFile(); - if (!(file instanceof PsiJavaFile)) { - return true; - } + protected void refreshElements(PsiElement[] elements) { + assert elements.length == 1; + myClass = (PsiClass)elements[0]; } - return false; - } - protected boolean preprocessUsages(final Ref refUsages) { - MultiMap conflicts = getConflicts(refUsages.get()); - if (!conflicts.isEmpty()) { - return showConflicts(conflicts, refUsages.get()); + protected boolean isPreviewUsages(UsageInfo[] usages) { + if (super.isPreviewUsages(usages)) { + return true; + } + for (UsageInfo usage : usages) { + if (isForcePreview(usage)) { + WindowManager.getInstance().getStatusBar(myProject) + .setInfo(RefactoringLocalize.occurrencesFoundInCommentsStringsAndNonJavaFiles().get()); + return true; + } + } + return false; } - return super.preprocessUsages(refUsages); - } - public MultiMap getConflicts(final UsageInfo[] usages) { - final MultiMap result = new MultiMap(); - ReferencedElementsCollector collector = new ReferencedElementsCollector() { - protected void checkAddMember(@Nonnull final PsiMember member) { - if (PsiTreeUtil.isAncestor(myClass, member, false)) { - return; + private static boolean isForcePreview(final UsageInfo usage) { + if (usage.isNonCodeUsage) { + return true; + } + PsiElement element = usage.getElement(); + if (element != null) { + PsiFile file = element.getContainingFile(); + if (!(file instanceof PsiJavaFile)) { + return true; + } } - final PsiModifierList modifierList = member.getModifierList(); - if (member.getContainingClass() == myClass.getSuperClass() && modifierList != null && - modifierList.hasModifierProperty(PsiModifier.PROTECTED)) { - // ignore access to protected members of superclass - they'll be accessible anyway - return; + return false; + } + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + MultiMap conflicts = getConflicts(refUsages.get()); + if (!conflicts.isEmpty()) { + return showConflicts(conflicts, refUsages.get()); } - super.checkAddMember(member); - } - }; - InlineMethodProcessor.addInaccessibleMemberConflicts(myClass, usages, collector, result); - myClass.accept(new JavaRecursiveElementVisitor(){ - @Override - public void visitParameter(PsiParameter parameter) { - super.visitParameter(parameter); - if (PsiUtil.resolveClassInType(parameter.getType()) != myClass) return; + return super.preprocessUsages(refUsages); + } - for (PsiReference psiReference : ReferencesSearch.search(parameter)) { - final PsiElement refElement = psiReference.getElement(); - if (refElement instanceof PsiExpression) { - final PsiReferenceExpression referenceExpression = PsiTreeUtil.getParentOfType(refElement, PsiReferenceExpression.class); - if (referenceExpression != null && referenceExpression.getQualifierExpression() == refElement) { - final PsiElement resolvedMember = referenceExpression.resolve(); - if (resolvedMember != null && PsiTreeUtil.isAncestor(myClass, resolvedMember, false)) { - if (resolvedMember instanceof PsiMethod) { - if (myClass.findMethodsBySignature((PsiMethod)resolvedMember, true).length > 1) { //skip inherited methods - continue; - } + public MultiMap getConflicts(final UsageInfo[] usages) { + final MultiMap result = new MultiMap(); + ReferencedElementsCollector collector = new ReferencedElementsCollector() { + protected void checkAddMember(@Nonnull final PsiMember member) { + if (PsiTreeUtil.isAncestor(myClass, member, false)) { + return; + } + final PsiModifierList modifierList = member.getModifierList(); + if (member.getContainingClass() == myClass.getSuperClass() && modifierList != null && + modifierList.hasModifierProperty(PsiModifier.PROTECTED)) { + // ignore access to protected members of superclass - they'll be accessible anyway + return; } - result.putValue(refElement, "Class cannot be inlined because a call to its member inside body"); - } + super.checkAddMember(member); } - } - } - } + }; + InlineMethodProcessor.addInaccessibleMemberConflicts(myClass, usages, collector, result); + myClass.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitParameter(PsiParameter parameter) { + super.visitParameter(parameter); + if (PsiUtil.resolveClassInType(parameter.getType()) != myClass) { + return; + } - @Override - public void visitNewExpression(PsiNewExpression expression) { - super.visitNewExpression(expression); - if (PsiUtil.resolveClassInType(expression.getType()) != myClass) return; - result.putValue(expression, "Class cannot be inlined because a call to its constructor inside body"); - } + for (PsiReference psiReference : ReferencesSearch.search(parameter)) { + final PsiElement refElement = psiReference.getElement(); + if (refElement instanceof PsiExpression) { + final PsiReferenceExpression referenceExpression = + PsiTreeUtil.getParentOfType(refElement, PsiReferenceExpression.class); + if (referenceExpression != null && referenceExpression.getQualifierExpression() == refElement) { + final PsiElement resolvedMember = referenceExpression.resolve(); + if (resolvedMember != null && PsiTreeUtil.isAncestor(myClass, resolvedMember, false)) { + if (resolvedMember instanceof PsiMethod) { + if (myClass.findMethodsBySignature( + (PsiMethod)resolvedMember, + true + ).length > 1) { //skip inherited methods + continue; + } + } + result.putValue(refElement, "Class cannot be inlined because a call to its member inside body"); + } + } + } + } + } - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - super.visitMethodCallExpression(expression); - final PsiReferenceExpression methodExpression = expression.getMethodExpression(); - final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); - if (qualifierExpression != null && PsiUtil.resolveClassInType(qualifierExpression.getType()) != myClass) return; - final PsiElement resolved = methodExpression.resolve(); - if (resolved instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)resolved; - if ("getClass".equals(method.getName()) && method.getParameterList().getParametersCount() == 0) { - result.putValue(methodExpression, "Result of getClass() invocation would be changed"); - } - } - } - }); - return result; - } + @Override + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + if (PsiUtil.resolveClassInType(expression.getType()) != myClass) { + return; + } + result.putValue(expression, "Class cannot be inlined because a call to its constructor inside body"); + } - protected void performRefactoring(UsageInfo[] usages) { - final PsiClassType superType = getSuperType(myClass); - LOG.assertTrue(superType != null); - List elementsToDelete = new ArrayList(); - List newExpressions = new ArrayList(); - for(UsageInfo info: usages) { - final PsiElement element = info.getElement(); - if (element instanceof PsiNewExpression) { - newExpressions.add((PsiNewExpression)element); - } - else if (element.getParent() instanceof PsiNewExpression) { - newExpressions.add((PsiNewExpression) element.getParent()); - } - else { - PsiImportStatement statement = PsiTreeUtil.getParentOfType(element, PsiImportStatement.class); - if (statement != null && !myInlineThisOnly) { - elementsToDelete.add(statement); - } - else { - PsiTypeElement typeElement = PsiTreeUtil.getParentOfType(element, PsiTypeElement.class); - if (typeElement != null) { - replaceWithSuperType(typeElement, superType); - } - } - } + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + if (qualifierExpression != null && PsiUtil.resolveClassInType(qualifierExpression.getType()) != myClass) { + return; + } + final PsiElement resolved = methodExpression.resolve(); + if (resolved instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)resolved; + if ("getClass".equals(method.getName()) && method.getParameterList().getParametersCount() == 0) { + result.putValue(methodExpression, "Result of getClass() invocation would be changed"); + } + } + } + }); + return result; } - Collections.sort(newExpressions, PsiUtil.BY_POSITION); - for(PsiNewExpression newExpression: newExpressions) { - replaceNewOrType(newExpression, superType); - } + protected void performRefactoring(UsageInfo[] usages) { + final PsiClassType superType = getSuperType(myClass); + LOG.assertTrue(superType != null); + List elementsToDelete = new ArrayList(); + List newExpressions = new ArrayList(); + for (UsageInfo info : usages) { + final PsiElement element = info.getElement(); + if (element instanceof PsiNewExpression) { + newExpressions.add((PsiNewExpression)element); + } + else if (element.getParent() instanceof PsiNewExpression) { + newExpressions.add((PsiNewExpression)element.getParent()); + } + else { + PsiImportStatement statement = PsiTreeUtil.getParentOfType(element, PsiImportStatement.class); + if (statement != null && !myInlineThisOnly) { + elementsToDelete.add(statement); + } + else { + PsiTypeElement typeElement = PsiTreeUtil.getParentOfType(element, PsiTypeElement.class); + if (typeElement != null) { + replaceWithSuperType(typeElement, superType); + } + } + } + } - for(PsiElement element: elementsToDelete) { - try { - if (element.isValid()) { - element.delete(); + Collections.sort(newExpressions, PsiUtil.BY_POSITION); + for (PsiNewExpression newExpression : newExpressions) { + replaceNewOrType(newExpression, superType); } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - if (!myInlineThisOnly) { - try { - myClass.delete(); - } - catch(IncorrectOperationException e) { - LOG.error(e); - } - } - } - private void replaceNewOrType(final PsiNewExpression psiNewExpression, final PsiClassType superType) { - try { - if (psiNewExpression.getArrayDimensions().length == 0 && psiNewExpression.getArrayInitializer() == null) { - new InlineToAnonymousConstructorProcessor(myClass, psiNewExpression, superType).run(); - } - else { - PsiJavaCodeReferenceElement element = - JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory().createClassReferenceElement(superType.resolve()); - psiNewExpression.getClassReference().replace(element); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); + for (PsiElement element : elementsToDelete) { + try { + if (element.isValid()) { + element.delete(); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + if (!myInlineThisOnly) { + try { + myClass.delete(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } } - } - private void replaceWithSuperType(final PsiTypeElement typeElement, final PsiClassType superType) { - PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); - PsiClassType psiType = (PsiClassType) typeElement.getType(); - PsiClassType.ClassResolveResult classResolveResult = psiType.resolveGenerics(); - PsiType substType = classResolveResult.getSubstitutor().substitute(superType); - assert classResolveResult.getElement() == myClass; - try { - typeElement.replace(factory.createTypeElement(substType)); + private void replaceNewOrType(final PsiNewExpression psiNewExpression, final PsiClassType superType) { + try { + if (psiNewExpression.getArrayDimensions().length == 0 && psiNewExpression.getArrayInitializer() == null) { + new InlineToAnonymousConstructorProcessor(myClass, psiNewExpression, superType).run(); + } + else { + PsiJavaCodeReferenceElement element = + JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory().createClassReferenceElement(superType.resolve()); + psiNewExpression.getClassReference().replace(element); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - catch(IncorrectOperationException e) { - LOG.error(e); + + private void replaceWithSuperType(final PsiTypeElement typeElement, final PsiClassType superType) { + PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); + PsiClassType psiType = (PsiClassType)typeElement.getType(); + PsiClassType.ClassResolveResult classResolveResult = psiType.resolveGenerics(); + PsiType substType = classResolveResult.getSubstitutor().substitute(superType); + assert classResolveResult.getElement() == myClass; + try { + typeElement.replace(factory.createTypeElement(substType)); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - } - @Nullable - public static PsiClassType getSuperType(final PsiClass aClass) { - PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); + @Nullable + public static PsiClassType getSuperType(final PsiClass aClass) { + PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); - PsiClassType superType; - PsiClass superClass = aClass.getSuperClass(); - PsiClassType[] interfaceTypes = aClass.getImplementsListTypes(); - if (interfaceTypes.length > 0 && !InlineToAnonymousClassHandler.isRedundantImplements(superClass, interfaceTypes [0])) { - superType = interfaceTypes [0]; - } - else { - PsiClassType[] classTypes = aClass.getExtendsListTypes(); - if (classTypes.length > 0) { - superType = classTypes [0]; - } - else { - if (superClass == null) { - //java.lang.Object was not found - return null; + PsiClassType superType; + PsiClass superClass = aClass.getSuperClass(); + PsiClassType[] interfaceTypes = aClass.getImplementsListTypes(); + if (interfaceTypes.length > 0 && !InlineToAnonymousClassHandler.isRedundantImplements(superClass, interfaceTypes[0])) { + superType = interfaceTypes[0]; + } + else { + PsiClassType[] classTypes = aClass.getExtendsListTypes(); + if (classTypes.length > 0) { + superType = classTypes[0]; + } + else { + if (superClass == null) { + //java.lang.Object was not found + return null; + } + superType = factory.createType(superClass); + } } - superType = factory.createType(superClass); - } + return superType; } - return superType; - } - protected String getCommandName() { - return RefactoringLocalize.inlineToAnonymousCommandName(myClass.getQualifiedName()).get(); - } + protected String getCommandName() { + return RefactoringLocalize.inlineToAnonymousCommandName(myClass.getQualifiedName()).get(); + } } 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 ddc7278332..2dbd6d4c70 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 @@ -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: 16.04.2002 - * Time: 15:37:30 - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.java.impl.refactoring.makeStatic; import com.intellij.java.impl.refactoring.util.ConflictsUtil; @@ -44,6 +35,7 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.usage.UsageViewUtil; @@ -51,275 +43,300 @@ import consulo.util.collection.MultiMap; import consulo.util.lang.StringUtil; import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +/* + * @author dsl + * @since 2002-04-16 + */ public abstract class MakeMethodOrClassStaticProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeMethodStaticProcessor"); - - protected T myMember; - protected Settings mySettings; - - public MakeMethodOrClassStaticProcessor(Project project, - T member, - Settings settings) { - super(project); - myMember = member; - mySettings = settings; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new MakeMethodOrClassStaticViewDescriptor(myMember); - } - - protected final boolean preprocessUsages(final Ref refUsages) { - UsageInfo[] usagesIn = refUsages.get(); - if (myPrepareSuccessfulSwingThreadCallback != null) { - MultiMap conflicts = getConflictDescriptions(usagesIn); - if (conflicts.size() > 0) { - ConflictsDialog conflictsDialog = prepareConflictsDialog(conflicts, refUsages.get()); - conflictsDialog.show(); - if (!conflictsDialog.isOK()) { - if (conflictsDialog.isShowConflicts()) prepareSuccessful(); - return false; - } - } - if (!mySettings.isChangeSignature()) { - refUsages.set(filterInternalUsages(usagesIn)); - } - } - refUsages.set(filterOverriding(usagesIn)); - - prepareSuccessful(); - return true; - } - - private static UsageInfo[] filterOverriding(UsageInfo[] usages) { - ArrayList result = new ArrayList(); - for (UsageInfo usage : usages) { - if (!(usage instanceof OverridingMethodUsageInfo)) { - result.add(usage); - } + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeMethodStaticProcessor"); + + protected T myMember; + protected Settings mySettings; + + public MakeMethodOrClassStaticProcessor(Project project, T member, Settings settings) { + super(project); + myMember = member; + mySettings = settings; } - return result.toArray(new UsageInfo[result.size()]); - } - - private static UsageInfo[] filterInternalUsages(UsageInfo[] usages) { - ArrayList result = new ArrayList(); - for (UsageInfo usage : usages) { - if (!(usage instanceof InternalUsageInfo)) { - result.add(usage); - } + + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new MakeMethodOrClassStaticViewDescriptor(myMember); } - return result.toArray(new UsageInfo[result.size()]); - } - - protected MultiMap getConflictDescriptions(UsageInfo[] usages) { - MultiMap conflicts = new MultiMap(); - HashSet processed = new HashSet(); - String typeString = StringUtil.capitalize(UsageViewUtil.getType(myMember)); - for (UsageInfo usageInfo : usages) { - if (usageInfo instanceof InternalUsageInfo && !(usageInfo instanceof SelfUsageInfo)) { - PsiElement referencedElement = ((InternalUsageInfo) usageInfo).getReferencedElement(); - if (!mySettings.isMakeClassParameter()) { - if (referencedElement instanceof PsiModifierListOwner) { - if (((PsiModifierListOwner) referencedElement).hasModifierProperty(PsiModifier.STATIC)) { - continue; + + @Override + @RequiredUIAccess + protected final boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + UsageInfo[] usagesIn = refUsages.get(); + if (myPrepareSuccessfulSwingThreadCallback != null) { + MultiMap conflicts = getConflictDescriptions(usagesIn); + if (conflicts.size() > 0) { + ConflictsDialog conflictsDialog = prepareConflictsDialog(conflicts, refUsages.get()); + conflictsDialog.show(); + if (!conflictsDialog.isOK()) { + if (conflictsDialog.isShowConflicts()) { + prepareSuccessful(); + } + return false; + } + } + if (!mySettings.isChangeSignature()) { + refUsages.set(filterInternalUsages(usagesIn)); } - } + } + refUsages.set(filterOverriding(usagesIn)); - if (processed.contains(referencedElement)) continue; - processed.add(referencedElement); - if (referencedElement instanceof PsiField) { - PsiField field = (PsiField) referencedElement; + prepareSuccessful(); + return true; + } - if (mySettings.getNameForField(field) == null) { - String description = RefactoringUIUtil.getDescription(field, true); - LocalizeValue message = RefactoringLocalize.zeroUsesNonStatic1WhichIsNotPassedAsAParameter(typeString, description); - conflicts.putValue(field, message.get()); + private static UsageInfo[] filterOverriding(UsageInfo[] usages) { + ArrayList result = new ArrayList(); + for (UsageInfo usage : usages) { + if (!(usage instanceof OverridingMethodUsageInfo)) { + result.add(usage); } - } else { - String description = RefactoringUIUtil.getDescription(referencedElement, true); - LocalizeValue message = RefactoringLocalize.zeroUses1WhichNeedsClassInstance(typeString, description); - conflicts.putValue(referencedElement, message.get()); - } - } - } - if (usageInfo instanceof OverridingMethodUsageInfo) { - LOG.assertTrue(myMember instanceof PsiMethod); - final PsiMethod overridingMethod = (PsiMethod) usageInfo.getElement(); - LocalizeValue message = RefactoringLocalize.method0IsOverriddenBy1( - RefactoringUIUtil.getDescription(myMember, false), - RefactoringUIUtil.getDescription(overridingMethod, true) - ); - conflicts.putValue(overridingMethod, message.get()); - } else { - PsiElement element = usageInfo.getElement(); - PsiElement container = ConflictsUtil.getContainer(element); - if (processed.contains(container)) continue; - processed.add(container); - List fieldParameters = mySettings.getParameterOrderList(); - ArrayList inaccessible = new ArrayList(); - - for (final Settings.FieldParameter fieldParameter : fieldParameters) { - if (!PsiUtil.isAccessible(fieldParameter.field, element, null)) { - inaccessible.add(fieldParameter.field); - } } + return result.toArray(new UsageInfo[result.size()]); + } - if (inaccessible.isEmpty()) continue; + private static UsageInfo[] filterInternalUsages(UsageInfo[] usages) { + ArrayList result = new ArrayList(); + for (UsageInfo usage : usages) { + if (!(usage instanceof InternalUsageInfo)) { + result.add(usage); + } + } + return result.toArray(new UsageInfo[result.size()]); + } - createInaccessibleFieldsConflictDescription(inaccessible, container, conflicts); - } + protected MultiMap getConflictDescriptions(UsageInfo[] usages) { + MultiMap conflicts = new MultiMap(); + HashSet processed = new HashSet(); + String typeString = StringUtil.capitalize(UsageViewUtil.getType(myMember)); + for (UsageInfo usageInfo : usages) { + if (usageInfo instanceof InternalUsageInfo && !(usageInfo instanceof SelfUsageInfo)) { + PsiElement referencedElement = ((InternalUsageInfo)usageInfo).getReferencedElement(); + if (!mySettings.isMakeClassParameter()) { + if (referencedElement instanceof PsiModifierListOwner) { + if (((PsiModifierListOwner)referencedElement).hasModifierProperty(PsiModifier.STATIC)) { + continue; + } + } + + if (processed.contains(referencedElement)) { + continue; + } + processed.add(referencedElement); + if (referencedElement instanceof PsiField) { + PsiField field = (PsiField)referencedElement; + + if (mySettings.getNameForField(field) == null) { + String description = RefactoringUIUtil.getDescription(field, true); + LocalizeValue message = + RefactoringLocalize.zeroUsesNonStatic1WhichIsNotPassedAsAParameter(typeString, description); + conflicts.putValue(field, message.get()); + } + } + else { + String description = RefactoringUIUtil.getDescription(referencedElement, true); + LocalizeValue message = RefactoringLocalize.zeroUses1WhichNeedsClassInstance(typeString, description); + conflicts.putValue(referencedElement, message.get()); + } + } + } + if (usageInfo instanceof OverridingMethodUsageInfo) { + LOG.assertTrue(myMember instanceof PsiMethod); + final PsiMethod overridingMethod = (PsiMethod)usageInfo.getElement(); + LocalizeValue message = RefactoringLocalize.method0IsOverriddenBy1( + RefactoringUIUtil.getDescription(myMember, false), + RefactoringUIUtil.getDescription(overridingMethod, true) + ); + conflicts.putValue(overridingMethod, message.get()); + } + else { + PsiElement element = usageInfo.getElement(); + PsiElement container = ConflictsUtil.getContainer(element); + if (processed.contains(container)) { + continue; + } + processed.add(container); + List fieldParameters = mySettings.getParameterOrderList(); + ArrayList inaccessible = new ArrayList(); + + for (final Settings.FieldParameter fieldParameter : fieldParameters) { + if (!PsiUtil.isAccessible(fieldParameter.field, element, null)) { + inaccessible.add(fieldParameter.field); + } + } + + if (inaccessible.isEmpty()) { + continue; + } + + createInaccessibleFieldsConflictDescription(inaccessible, container, conflicts); + } + } + return conflicts; } - return conflicts; - } - - private static void createInaccessibleFieldsConflictDescription(ArrayList inaccessible, PsiElement container, - MultiMap conflicts) { - if (inaccessible.size() == 1) { - final PsiField field = inaccessible.get(0); - conflicts.putValue( - field, - RefactoringLocalize.field0IsNotAccessible( - CommonRefactoringUtil.htmlEmphasize(field.getName()), - RefactoringUIUtil.getDescription(container, true) - ).get() - ); - } else { - for (PsiField field : inaccessible) { - conflicts.putValue( - field, - RefactoringLocalize.field0IsNotAccessible( - CommonRefactoringUtil.htmlEmphasize(field.getName()), - RefactoringUIUtil.getDescription(container, true) - ).get() - ); - } + + private static void createInaccessibleFieldsConflictDescription( + ArrayList inaccessible, + PsiElement container, + MultiMap conflicts + ) { + if (inaccessible.size() == 1) { + final PsiField field = inaccessible.get(0); + conflicts.putValue( + field, + RefactoringLocalize.field0IsNotAccessible( + CommonRefactoringUtil.htmlEmphasize(field.getName()), + RefactoringUIUtil.getDescription(container, true) + ).get() + ); + } + else { + for (PsiField field : inaccessible) { + conflicts.putValue( + field, + RefactoringLocalize.field0IsNotAccessible( + CommonRefactoringUtil.htmlEmphasize(field.getName()), + RefactoringUIUtil.getDescription(container, true) + ).get() + ); + } + } } - } - @Nonnull - protected UsageInfo[] findUsages() { - ArrayList result = new ArrayList(); + @Nonnull + protected UsageInfo[] findUsages() { + ArrayList result = new ArrayList(); - ContainerUtil.addAll(result, MakeStaticUtil.findClassRefsInMember(myMember, true)); + ContainerUtil.addAll(result, MakeStaticUtil.findClassRefsInMember(myMember, true)); - if (mySettings.isReplaceUsages()) { - findExternalUsages(result); - } + if (mySettings.isReplaceUsages()) { + findExternalUsages(result); + } - if (myMember instanceof PsiMethod) { - final PsiMethod[] overridingMethods = - OverridingMethodsSearch.search((PsiMethod) myMember, myMember.getUseScope(), false).toArray(PsiMethod.EMPTY_ARRAY); - for (PsiMethod overridingMethod : overridingMethods) { - if (overridingMethod != myMember) { - result.add(new OverridingMethodUsageInfo(overridingMethod)); + if (myMember instanceof PsiMethod) { + final PsiMethod[] overridingMethods = + OverridingMethodsSearch.search((PsiMethod)myMember, myMember.getUseScope(), false).toArray(PsiMethod.EMPTY_ARRAY); + for (PsiMethod overridingMethod : overridingMethods) { + if (overridingMethod != myMember) { + result.add(new OverridingMethodUsageInfo(overridingMethod)); + } + } } - } + + return result.toArray(new UsageInfo[result.size()]); } - return result.toArray(new UsageInfo[result.size()]); - } - - protected abstract void findExternalUsages(ArrayList result); - - protected void findExternalReferences(final PsiMethod method, final ArrayList result) { - for (PsiReference ref : ReferencesSearch.search(method)) { - PsiElement element = ref.getElement(); - PsiElement qualifier = null; - if (element instanceof PsiReferenceExpression) { - qualifier = ((PsiReferenceExpression) element).getQualifierExpression(); - if (qualifier instanceof PsiThisExpression) qualifier = null; - } - if (!PsiTreeUtil.isAncestor(myMember, element, true) || qualifier != null) { - result.add(new UsageInfo(element)); - } + protected abstract void findExternalUsages(ArrayList result); + + protected void findExternalReferences(final PsiMethod method, final ArrayList result) { + for (PsiReference ref : ReferencesSearch.search(method)) { + PsiElement element = ref.getElement(); + PsiElement qualifier = null; + if (element instanceof PsiReferenceExpression) { + qualifier = ((PsiReferenceExpression)element).getQualifierExpression(); + if (qualifier instanceof PsiThisExpression) { + qualifier = null; + } + } + if (!PsiTreeUtil.isAncestor(myMember, element, true) || qualifier != null) { + result.add(new UsageInfo(element)); + } + } } - } - - //should be called before setting static modifier - protected void setupTypeParameterList() throws IncorrectOperationException { - final PsiTypeParameterList list = myMember.getTypeParameterList(); - assert list != null; - final PsiTypeParameterList newList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(myMember); - if (newList != null) { - list.replace(newList); + + //should be called before setting static modifier + protected void setupTypeParameterList() throws IncorrectOperationException { + final PsiTypeParameterList list = myMember.getTypeParameterList(); + assert list != null; + final PsiTypeParameterList newList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(myMember); + if (newList != null) { + list.replace(newList); + } } - } - - protected boolean makeClassParameterFinal(UsageInfo[] usages) { - for (UsageInfo usage : usages) { - if (usage instanceof InternalUsageInfo) { - final InternalUsageInfo internalUsageInfo = (InternalUsageInfo) usage; - PsiElement referencedElement = internalUsageInfo.getReferencedElement(); - if (!(referencedElement instanceof PsiField) - || mySettings.getNameForField((PsiField) referencedElement) == null) { - if (internalUsageInfo.isInsideAnonymous()) { - return true; - } + + protected boolean makeClassParameterFinal(UsageInfo[] usages) { + for (UsageInfo usage : usages) { + if (usage instanceof InternalUsageInfo) { + final InternalUsageInfo internalUsageInfo = (InternalUsageInfo)usage; + PsiElement referencedElement = internalUsageInfo.getReferencedElement(); + if (!(referencedElement instanceof PsiField) + || mySettings.getNameForField((PsiField)referencedElement) == null) { + if (internalUsageInfo.isInsideAnonymous()) { + return true; + } + } + } } - } + return false; } - return false; - } - - protected static boolean makeFieldParameterFinal(PsiField field, UsageInfo[] usages) { - for (UsageInfo usage : usages) { - if (usage instanceof InternalUsageInfo) { - final InternalUsageInfo internalUsageInfo = (InternalUsageInfo) usage; - PsiElement referencedElement = internalUsageInfo.getReferencedElement(); - if (referencedElement instanceof PsiField && field.equals(referencedElement)) { - if (internalUsageInfo.isInsideAnonymous()) { - return true; - } + + protected static boolean makeFieldParameterFinal(PsiField field, UsageInfo[] usages) { + for (UsageInfo usage : usages) { + if (usage instanceof InternalUsageInfo) { + final InternalUsageInfo internalUsageInfo = (InternalUsageInfo)usage; + PsiElement referencedElement = internalUsageInfo.getReferencedElement(); + if (referencedElement instanceof PsiField && field.equals(referencedElement)) { + if (internalUsageInfo.isInsideAnonymous()) { + return true; + } + } + } } - } + return false; + } + + protected String getCommandName() { + return RefactoringLocalize.makeStaticCommand(DescriptiveNameUtil.getDescriptiveName(myMember)).get(); + } + + public T getMember() { + return myMember; + } + + public Settings getSettings() { + return mySettings; } - return false; - } - - protected String getCommandName() { - return RefactoringLocalize.makeStaticCommand(DescriptiveNameUtil.getDescriptiveName(myMember)).get(); - } - - public T getMember() { - return myMember; - } - - public Settings getSettings() { - return mySettings; - } - - protected void performRefactoring(UsageInfo[] usages) { - PsiManager manager = myMember.getManager(); - PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - - try { - for (UsageInfo usage : usages) { - if (usage instanceof SelfUsageInfo) { - changeSelfUsage((SelfUsageInfo) usage); - } else if (usage instanceof InternalUsageInfo) { - changeInternalUsage((InternalUsageInfo) usage, factory); - } else { - changeExternalUsage(usage, factory); + + protected void performRefactoring(UsageInfo[] usages) { + PsiManager manager = myMember.getManager(); + PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + + try { + for (UsageInfo usage : usages) { + if (usage instanceof SelfUsageInfo) { + changeSelfUsage((SelfUsageInfo)usage); + } + else if (usage instanceof InternalUsageInfo) { + changeInternalUsage((InternalUsageInfo)usage, factory); + } + else { + changeExternalUsage(usage, factory); + } + } + changeSelf(factory, usages); + } + catch (IncorrectOperationException ex) { + LOG.assertTrue(false); } - } - changeSelf(factory, usages); - } catch (IncorrectOperationException ex) { - LOG.assertTrue(false); } - } - protected abstract void changeSelf(PsiElementFactory factory, UsageInfo[] usages) throws IncorrectOperationException; + protected abstract void changeSelf(PsiElementFactory factory, UsageInfo[] usages) throws IncorrectOperationException; - protected abstract void changeSelfUsage(SelfUsageInfo usageInfo) throws IncorrectOperationException; + protected abstract void changeSelfUsage(SelfUsageInfo usageInfo) throws IncorrectOperationException; - protected abstract void changeInternalUsage(InternalUsageInfo usage, PsiElementFactory factory) throws IncorrectOperationException; + protected abstract void changeInternalUsage(InternalUsageInfo usage, PsiElementFactory factory) throws IncorrectOperationException; - protected abstract void changeExternalUsage(UsageInfo usage, PsiElementFactory factory) throws IncorrectOperationException; + protected abstract void changeExternalUsage(UsageInfo usage, PsiElementFactory factory) throws IncorrectOperationException; } 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 55423529e1..b827839f1c 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 @@ -51,436 +51,462 @@ import consulo.usage.UsageViewDescriptor; import consulo.util.dataholder.Key; import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.*; public class PushDownProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(PushDownProcessor.class); + private static final Logger LOG = Logger.getInstance(PushDownProcessor.class); - private final MemberInfo[] myMemberInfos; - private PsiClass myClass; - private final DocCommentPolicy myJavaDocPolicy; - private CreateClassDialog myCreateClassDlg; + private final MemberInfo[] myMemberInfos; + private PsiClass myClass; + private final DocCommentPolicy myJavaDocPolicy; + private CreateClassDialog myCreateClassDlg; - public PushDownProcessor( - Project project, - MemberInfo[] memberInfos, - PsiClass aClass, - DocCommentPolicy javaDocPolicy - ) { - super(project); - myMemberInfos = memberInfos; - myClass = aClass; - myJavaDocPolicy = javaDocPolicy; - } - - @Nonnull - protected String getCommandName() { - return JavaPushDownHandler.REFACTORING_NAME; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { - return new PushDownUsageViewDescriptor(myClass); - } + public PushDownProcessor( + Project project, + MemberInfo[] memberInfos, + PsiClass aClass, + DocCommentPolicy javaDocPolicy + ) { + super(project); + myMemberInfos = memberInfos; + myClass = aClass; + myJavaDocPolicy = javaDocPolicy; + } - @Nonnull - protected UsageInfo[] findUsages() { - final PsiClass[] inheritors = ClassInheritorsSearch.search(myClass, false).toArray(PsiClass.EMPTY_ARRAY); - UsageInfo[] usages = new UsageInfo[inheritors.length]; - for (int i = 0; i < inheritors.length; i++) { - usages[i] = new UsageInfo(inheritors[i]); + @Nonnull + protected String getCommandName() { + return JavaPushDownHandler.REFACTORING_NAME; } - return usages; - } - @RequiredUIAccess - protected boolean preprocessUsages(final Ref refUsages) { - final UsageInfo[] usagesIn = refUsages.get(); - final PushDownConflicts pushDownConflicts = new PushDownConflicts(myClass, myMemberInfos); - pushDownConflicts.checkSourceClassConflicts(); + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new PushDownUsageViewDescriptor(myClass); + } - if (usagesIn.length == 0) { - if (myClass.isEnum() || myClass.hasModifierProperty(PsiModifier.FINAL)) { - if (Messages.showOkCancelDialog( - ( - myClass.isEnum() - ? "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, - UIUtil.getWarningIcon() - ) != DialogWrapper.OK_EXIT_CODE) { - return false; + @Nonnull + protected UsageInfo[] findUsages() { + final PsiClass[] inheritors = ClassInheritorsSearch.search(myClass, false).toArray(PsiClass.EMPTY_ARRAY); + UsageInfo[] usages = new UsageInfo[inheritors.length]; + for (int i = 0; i < inheritors.length; i++) { + usages[i] = new UsageInfo(inheritors[i]); } - } else { - LocalizeValue noInheritors = myClass.isInterface() - ? RefactoringLocalize.interface0DoesNotHaveInheritors(myClass.getQualifiedName()) - : RefactoringLocalize.class0DoesNotHaveInheritors(myClass.getQualifiedName()); - final String message = noInheritors + "\n" + RefactoringLocalize.pushDownWillDeleteMembers(); - final int answer = Messages.showYesNoCancelDialog(message, JavaPushDownHandler.REFACTORING_NAME, UIUtil.getWarningIcon()); - if (answer == DialogWrapper.OK_EXIT_CODE) { - myCreateClassDlg = CreateSubclassAction.chooseSubclassToCreate(myClass); - if (myCreateClassDlg != null) { - pushDownConflicts.checkTargetClassConflicts(null, false, myCreateClassDlg.getTargetDirectory()); - return showConflicts(pushDownConflicts.getConflicts(), usagesIn); - } else { - return false; - } - } else if (answer != 1) return false; - } + return usages; } - Runnable runnable = () -> { - for (UsageInfo usage : usagesIn) { - final PsiElement element = usage.getElement(); - if (element instanceof PsiClass psiClass) { - pushDownConflicts.checkTargetClassConflicts(psiClass, usagesIn.length > 1, element); - } - } - }; - boolean processFinished = ProgressManager.getInstance().runProcessWithProgressSynchronously( - runnable, - RefactoringLocalize.detectingPossibleConflicts().get(), - true, - myProject - ); - return processFinished && showConflicts(pushDownConflicts.getConflicts(), usagesIn); - } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + final UsageInfo[] usagesIn = refUsages.get(); + final PushDownConflicts pushDownConflicts = new PushDownConflicts(myClass, myMemberInfos); + pushDownConflicts.checkSourceClassConflicts(); - protected void refreshElements(PsiElement[] elements) { - if (elements.length == 1 && elements[0] instanceof PsiClass) { - myClass = (PsiClass) elements[0]; - } - else { - LOG.assertTrue(false); + if (usagesIn.length == 0) { + if (myClass.isEnum() || myClass.hasModifierProperty(PsiModifier.FINAL)) { + if (Messages.showOkCancelDialog( + ( + myClass.isEnum() + ? "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, + UIUtil.getWarningIcon() + ) != DialogWrapper.OK_EXIT_CODE) { + return false; + } + } + else { + LocalizeValue noInheritors = myClass.isInterface() + ? RefactoringLocalize.interface0DoesNotHaveInheritors(myClass.getQualifiedName()) + : RefactoringLocalize.class0DoesNotHaveInheritors(myClass.getQualifiedName()); + final String message = noInheritors + "\n" + RefactoringLocalize.pushDownWillDeleteMembers(); + final int answer = Messages.showYesNoCancelDialog(message, JavaPushDownHandler.REFACTORING_NAME, UIUtil.getWarningIcon()); + if (answer == DialogWrapper.OK_EXIT_CODE) { + myCreateClassDlg = CreateSubclassAction.chooseSubclassToCreate(myClass); + if (myCreateClassDlg != null) { + pushDownConflicts.checkTargetClassConflicts(null, false, myCreateClassDlg.getTargetDirectory()); + return showConflicts(pushDownConflicts.getConflicts(), usagesIn); + } + else { + return false; + } + } + else if (answer != 1) { + return false; + } + } + } + Runnable runnable = () -> { + for (UsageInfo usage : usagesIn) { + final PsiElement element = usage.getElement(); + if (element instanceof PsiClass psiClass) { + pushDownConflicts.checkTargetClassConflicts(psiClass, usagesIn.length > 1, element); + } + } + }; + + boolean processFinished = ProgressManager.getInstance().runProcessWithProgressSynchronously( + runnable, + RefactoringLocalize.detectingPossibleConflicts().get(), + true, + myProject + ); + return processFinished && showConflicts(pushDownConflicts.getConflicts(), usagesIn); } - } - @RequiredUIAccess - protected void performRefactoring(@Nonnull UsageInfo[] usages) { - try { - encodeRefs(); - if (myCreateClassDlg != null) { //usages.length == 0 - final PsiClass psiClass = - CreateSubclassAction.createSubclass(myClass, myCreateClassDlg.getTargetDirectory(), myCreateClassDlg.getClassName()); - if (psiClass != null) { - pushDownToClass(psiClass); + protected void refreshElements(PsiElement[] elements) { + if (elements.length == 1 && elements[0] instanceof PsiClass) { + myClass = (PsiClass)elements[0]; } - } - for (UsageInfo usage : usages) { - if (usage.getElement() instanceof PsiClass) { - final PsiClass targetClass = (PsiClass)usage.getElement(); - pushDownToClass(targetClass); + else { + LOG.assertTrue(false); } - } - removeFromTargetClass(); } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - private static final Key REMOVE_QUALIFIER_KEY = Key.create("REMOVE_QUALIFIER_KEY"); - private static final Key REPLACE_QUALIFIER_KEY = Key.create("REPLACE_QUALIFIER_KEY"); - protected void encodeRefs() { - final Set movedMembers = new HashSet<>(); - for (MemberInfo memberInfo : myMemberInfos) { - movedMembers.add(memberInfo.getMember()); + @RequiredUIAccess + protected void performRefactoring(@Nonnull UsageInfo[] usages) { + try { + encodeRefs(); + if (myCreateClassDlg != null) { //usages.length == 0 + final PsiClass psiClass = + CreateSubclassAction.createSubclass(myClass, myCreateClassDlg.getTargetDirectory(), myCreateClassDlg.getClassName()); + if (psiClass != null) { + pushDownToClass(psiClass); + } + } + for (UsageInfo usage : usages) { + if (usage.getElement() instanceof PsiClass) { + final PsiClass targetClass = (PsiClass)usage.getElement(); + pushDownToClass(targetClass); + } + } + removeFromTargetClass(); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - for (MemberInfo memberInfo : myMemberInfos) { - final PsiMember member = memberInfo.getMember(); - member.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - encodeRef(expression, movedMembers, expression); - super.visitReferenceExpression(expression); - } + private static final Key REMOVE_QUALIFIER_KEY = Key.create("REMOVE_QUALIFIER_KEY"); + private static final Key REPLACE_QUALIFIER_KEY = Key.create("REPLACE_QUALIFIER_KEY"); - @Override - public void visitNewExpression(@Nonnull PsiNewExpression expression) { - final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); - if (classReference != null) { - encodeRef(classReference, movedMembers, expression); - } - super.visitNewExpression(expression); + protected void encodeRefs() { + final Set movedMembers = new HashSet<>(); + for (MemberInfo memberInfo : myMemberInfos) { + movedMembers.add(memberInfo.getMember()); } - @Override - public void visitTypeElement(@Nonnull final PsiTypeElement type) { - final PsiJavaCodeReferenceElement referenceElement = type.getInnermostComponentReferenceElement(); - if (referenceElement != null) { - encodeRef(referenceElement, movedMembers, type); - } - super.visitTypeElement(type); + for (MemberInfo memberInfo : myMemberInfos) { + final PsiMember member = memberInfo.getMember(); + member.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + encodeRef(expression, movedMembers, expression); + super.visitReferenceExpression(expression); + } + + @Override + public void visitNewExpression(@Nonnull PsiNewExpression expression) { + final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); + if (classReference != null) { + encodeRef(classReference, movedMembers, expression); + } + super.visitNewExpression(expression); + } + + @Override + public void visitTypeElement(@Nonnull final PsiTypeElement type) { + final PsiJavaCodeReferenceElement referenceElement = type.getInnermostComponentReferenceElement(); + if (referenceElement != null) { + encodeRef(referenceElement, movedMembers, type); + } + super.visitTypeElement(type); + } + }); + ChangeContextUtil.encodeContextInfo(member, false); } - }); - ChangeContextUtil.encodeContextInfo(member, false); } - } - @RequiredReadAction - private void encodeRef(final PsiJavaCodeReferenceElement expression, final Set movedMembers, final PsiElement toPut) { - final PsiElement resolved = expression.resolve(); - if (resolved == null) return; - final PsiElement qualifier = expression.getQualifier(); - for (PsiMember movedMember : movedMembers) { - if (movedMember.equals(resolved)) { - 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 (movedMember instanceof PsiClass movedClass - && PsiTreeUtil.getParentOfType(resolved, PsiClass.class, false) == movedClass) { - if (qualifier instanceof PsiJavaCodeReferenceElement reference && reference.isReferenceTo(movedClass)) { - toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, movedClass); + @RequiredReadAction + private void encodeRef(final PsiJavaCodeReferenceElement expression, final Set movedMembers, final PsiElement toPut) { + final PsiElement resolved = expression.resolve(); + if (resolved == null) { + return; } - } else { - if (qualifier instanceof PsiThisExpression thisExpression) { - final PsiJavaCodeReferenceElement qElement = thisExpression.getQualifier(); - if (qElement != null && qElement.isReferenceTo(myClass)) { - toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, myClass); - } + final PsiElement qualifier = expression.getQualifier(); + for (PsiMember movedMember : movedMembers) { + if (movedMember.equals(resolved)) { + 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 (movedMember instanceof PsiClass movedClass + && PsiTreeUtil.getParentOfType(resolved, PsiClass.class, false) == movedClass) { + if (qualifier instanceof PsiJavaCodeReferenceElement reference && reference.isReferenceTo(movedClass)) { + toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, movedClass); + } + } + else { + if (qualifier instanceof PsiThisExpression thisExpression) { + final PsiJavaCodeReferenceElement qElement = thisExpression.getQualifier(); + if (qElement != null && qElement.isReferenceTo(myClass)) { + toPut.putCopyableUserData(REPLACE_QUALIFIER_KEY, myClass); + } + } + } } - } } - } - - private void decodeRefs(final PsiMember member, final PsiClass targetClass) { - try { - ChangeContextUtil.decodeContextInfo(member, null, null); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - - final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); - member.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { - decodeRef(expression, factory, targetClass, expression); - super.visitReferenceExpression(expression); - } - @Override public void visitNewExpression(@Nonnull PsiNewExpression expression) { - final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); - if (classReference != null) decodeRef(classReference, factory, targetClass, expression); - super.visitNewExpression(expression); - } + private void decodeRefs(final PsiMember member, final PsiClass targetClass) { + try { + ChangeContextUtil.decodeContextInfo(member, null, null); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } - @Override - public void visitTypeElement(@Nonnull final PsiTypeElement type) { - final PsiJavaCodeReferenceElement referenceElement = type.getInnermostComponentReferenceElement(); - if (referenceElement != null) decodeRef(referenceElement, factory, targetClass, type); - super.visitTypeElement(type); - } - }); - } + final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); + member.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + decodeRef(expression, factory, targetClass, expression); + super.visitReferenceExpression(expression); + } - @RequiredReadAction - private void decodeRef( - final PsiJavaCodeReferenceElement ref, - final PsiElementFactory factory, - final PsiClass targetClass, - final PsiElement toGet - ) { - try { - if (toGet.getCopyableUserData(REMOVE_QUALIFIER_KEY) != null) { - toGet.putCopyableUserData(REMOVE_QUALIFIER_KEY, null); - final PsiElement qualifier = ref.getQualifier(); - if (qualifier != null) qualifier.delete(); - } - else { - PsiClass psiClass = toGet.getCopyableUserData(REPLACE_QUALIFIER_KEY); - if (psiClass != null) { - toGet.putCopyableUserData(REPLACE_QUALIFIER_KEY, null); - PsiElement qualifier = ref.getQualifier(); - if (qualifier != null) { + @Override + public void visitNewExpression(@Nonnull PsiNewExpression expression) { + final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); + if (classReference != null) { + decodeRef(classReference, factory, targetClass, expression); + } + super.visitNewExpression(expression); + } - if (psiClass == myClass) { - psiClass = targetClass; - } else if (psiClass.getContainingClass() == myClass) { - psiClass = targetClass.findInnerClassByName(psiClass.getName(), false); - LOG.assertTrue(psiClass != null); + @Override + public void visitTypeElement(@Nonnull final PsiTypeElement type) { + final PsiJavaCodeReferenceElement referenceElement = type.getInnermostComponentReferenceElement(); + if (referenceElement != null) { + decodeRef(referenceElement, factory, targetClass, type); + } + super.visitTypeElement(type); } + }); + } - if (!(qualifier instanceof PsiThisExpression) && ref instanceof PsiReferenceExpression referenceExpression) { - referenceExpression.setQualifierExpression(factory.createReferenceExpression(psiClass)); + @RequiredReadAction + private void decodeRef( + final PsiJavaCodeReferenceElement ref, + final PsiElementFactory factory, + final PsiClass targetClass, + final PsiElement toGet + ) { + try { + if (toGet.getCopyableUserData(REMOVE_QUALIFIER_KEY) != null) { + toGet.putCopyableUserData(REMOVE_QUALIFIER_KEY, null); + final PsiElement qualifier = ref.getQualifier(); + if (qualifier != null) { + qualifier.delete(); + } } else { - if (qualifier instanceof PsiThisExpression thisExpression) { - qualifier = thisExpression.getQualifier(); - } - qualifier.replace(factory.createReferenceElementByType(factory.createType(psiClass))); - } - } - } - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } + PsiClass psiClass = toGet.getCopyableUserData(REPLACE_QUALIFIER_KEY); + if (psiClass != null) { + toGet.putCopyableUserData(REPLACE_QUALIFIER_KEY, null); + PsiElement qualifier = ref.getQualifier(); + if (qualifier != null) { - private void removeFromTargetClass() throws IncorrectOperationException { - for (MemberInfo memberInfo : myMemberInfos) { - final PsiElement member = memberInfo.getMember(); + if (psiClass == myClass) { + psiClass = targetClass; + } + else if (psiClass.getContainingClass() == myClass) { + psiClass = targetClass.findInnerClassByName(psiClass.getName(), false); + LOG.assertTrue(psiClass != null); + } - if (member instanceof PsiField) { - member.delete(); - } - else if (member instanceof PsiMethod) { - if (memberInfo.isToAbstract()) { - final PsiMethod method = (PsiMethod)member; - if (method.hasModifierProperty(PsiModifier.PRIVATE)) { - PsiUtil.setModifierProperty(method, PsiModifier.PROTECTED, true); - } - RefactoringUtil.makeMethodAbstract(myClass, method); - myJavaDocPolicy.processOldJavaDoc(method.getDocComment()); - } - else { - member.delete(); - } - } - else if (member instanceof PsiClass psiClass) { - if (Boolean.FALSE.equals(memberInfo.getOverrides())) { - RefactoringUtil.removeFromReferenceList(myClass.getImplementsList(), psiClass); + if (!(qualifier instanceof PsiThisExpression) && ref instanceof PsiReferenceExpression referenceExpression) { + referenceExpression.setQualifierExpression(factory.createReferenceExpression(psiClass)); + } + else { + if (qualifier instanceof PsiThisExpression thisExpression) { + qualifier = thisExpression.getQualifier(); + } + qualifier.replace(factory.createReferenceElementByType(factory.createType(psiClass))); + } + } + } + } } - else { - member.delete(); + catch (IncorrectOperationException e) { + LOG.error(e); } - } } - } - @RequiredUIAccess - protected void pushDownToClass(PsiClass targetClass) throws IncorrectOperationException { - final PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); - final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(myClass, targetClass, PsiSubstitutor.EMPTY); - for (MemberInfo memberInfo : myMemberInfos) { - PsiMember member = memberInfo.getMember(); - final List refsToRebind = new ArrayList<>(); - final PsiModifierList list = member.getModifierList(); - LOG.assertTrue(list != null); - if (list.hasModifierProperty(PsiModifier.STATIC)) { - for (final PsiReference reference : ReferencesSearch.search(member)) { - final PsiElement element = reference.getElement(); - if (element instanceof PsiReferenceExpression referenceExpression) { - final PsiExpression qualifierExpression = referenceExpression.getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression refExpr && !(refExpr.resolve() instanceof PsiClass)) { - continue; + private void removeFromTargetClass() throws IncorrectOperationException { + for (MemberInfo memberInfo : myMemberInfos) { + final PsiElement member = memberInfo.getMember(); + + if (member instanceof PsiField) { + member.delete(); } - } - refsToRebind.add(reference); - } - } - 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); - } - else if (member instanceof PsiMethod method) { - PsiMethod methodBySignature = - MethodSignatureUtil.findMethodBySuperSignature(targetClass, method.getSignature(substitutor), false); - if (methodBySignature == null) { - newMember = (PsiMethod)targetClass.add(method); - if (myClass.isInterface()) { - if (!targetClass.isInterface()) { - PsiUtil.setModifierProperty(newMember, PsiModifier.PUBLIC, true); - if (newMember.hasModifierProperty(PsiModifier.DEFAULT)) { - PsiUtil.setModifierProperty(newMember, PsiModifier.DEFAULT, false); - } - else { - PsiUtil.setModifierProperty(newMember, PsiModifier.ABSTRACT, true); - } + else if (member instanceof PsiMethod) { + if (memberInfo.isToAbstract()) { + final PsiMethod method = (PsiMethod)member; + if (method.hasModifierProperty(PsiModifier.PRIVATE)) { + PsiUtil.setModifierProperty(method, PsiModifier.PROTECTED, true); + } + RefactoringUtil.makeMethodAbstract(myClass, method); + myJavaDocPolicy.processOldJavaDoc(method.getDocComment()); + } + else { + member.delete(); + } } - } - else if (memberInfo.isToAbstract()) { - if (newMember.hasModifierProperty(PsiModifier.PRIVATE)) { - PsiUtil.setModifierProperty(newMember, PsiModifier.PROTECTED, true); + else if (member instanceof PsiClass psiClass) { + if (Boolean.FALSE.equals(memberInfo.getOverrides())) { + RefactoringUtil.removeFromReferenceList(myClass.getImplementsList(), psiClass); + } + else { + member.delete(); + } } - myJavaDocPolicy.processNewJavaDoc(((PsiMethod)newMember).getDocComment()); - } } - else { //abstract method: remove @Override - final PsiAnnotation annotation = AnnotationUtil.findAnnotation(methodBySignature, CommonClassNames.JAVA_LANG_OVERRIDE); - if (annotation != null && !leaveOverrideAnnotation(substitutor, method)) { - annotation.delete(); - } - final PsiDocComment oldDocComment = method.getDocComment(); - if (oldDocComment != null) { - final PsiDocComment docComment = methodBySignature.getDocComment(); - final int policy = myJavaDocPolicy.getJavaDocPolicy(); - if (policy == DocCommentPolicy.COPY || policy == DocCommentPolicy.MOVE) { - if (docComment != null) { - docComment.replace(oldDocComment); - } - else { - methodBySignature.getParent().addBefore(oldDocComment, methodBySignature); - } + } + + @RequiredUIAccess + protected void pushDownToClass(PsiClass targetClass) throws IncorrectOperationException { + final PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory(); + final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(myClass, targetClass, PsiSubstitutor.EMPTY); + for (MemberInfo memberInfo : myMemberInfos) { + PsiMember member = memberInfo.getMember(); + final List refsToRebind = new ArrayList<>(); + final PsiModifierList list = member.getModifierList(); + LOG.assertTrue(list != null); + if (list.hasModifierProperty(PsiModifier.STATIC)) { + for (final PsiReference reference : ReferencesSearch.search(member)) { + final PsiElement element = reference.getElement(); + if (element instanceof PsiReferenceExpression referenceExpression) { + final PsiExpression qualifierExpression = referenceExpression.getQualifierExpression(); + if (qualifierExpression instanceof PsiReferenceExpression refExpr && !(refExpr.resolve() instanceof PsiClass)) { + continue; + } + } + refsToRebind.add(reference); + } } - } - } - } - else if (member instanceof PsiClass) { - if (Boolean.FALSE.equals(memberInfo.getOverrides())) { - final PsiClass aClass = (PsiClass)memberInfo.getMember(); - PsiClassType classType = null; - if (!targetClass.isInheritor(aClass, false)) { - final PsiClassType[] types = memberInfo.getSourceReferenceList().getReferencedTypes(); - for (PsiClassType type : types) { - if (type.resolve() == aClass) { - classType = (PsiClassType)substitutor.substitute(type); - } + 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); } - PsiJavaCodeReferenceElement classRef = classType != null - ? factory.createReferenceElementByType(classType) : factory.createClassReferenceElement(aClass); - if (aClass.isInterface()) { - targetClass.getImplementsList().add(classRef); - } else { - targetClass.getExtendsList().add(classRef); + else if (member instanceof PsiMethod method) { + PsiMethod methodBySignature = + MethodSignatureUtil.findMethodBySuperSignature(targetClass, method.getSignature(substitutor), false); + if (methodBySignature == null) { + newMember = (PsiMethod)targetClass.add(method); + if (myClass.isInterface()) { + if (!targetClass.isInterface()) { + PsiUtil.setModifierProperty(newMember, PsiModifier.PUBLIC, true); + if (newMember.hasModifierProperty(PsiModifier.DEFAULT)) { + PsiUtil.setModifierProperty(newMember, PsiModifier.DEFAULT, false); + } + else { + PsiUtil.setModifierProperty(newMember, PsiModifier.ABSTRACT, true); + } + } + } + else if (memberInfo.isToAbstract()) { + if (newMember.hasModifierProperty(PsiModifier.PRIVATE)) { + PsiUtil.setModifierProperty(newMember, PsiModifier.PROTECTED, true); + } + myJavaDocPolicy.processNewJavaDoc(((PsiMethod)newMember).getDocComment()); + } + } + else { //abstract method: remove @Override + final PsiAnnotation annotation = AnnotationUtil.findAnnotation(methodBySignature, CommonClassNames.JAVA_LANG_OVERRIDE); + if (annotation != null && !leaveOverrideAnnotation(substitutor, method)) { + annotation.delete(); + } + final PsiDocComment oldDocComment = method.getDocComment(); + if (oldDocComment != null) { + final PsiDocComment docComment = methodBySignature.getDocComment(); + final int policy = myJavaDocPolicy.getJavaDocPolicy(); + if (policy == DocCommentPolicy.COPY || policy == DocCommentPolicy.MOVE) { + if (docComment != null) { + docComment.replace(oldDocComment); + } + else { + methodBySignature.getParent().addBefore(oldDocComment, methodBySignature); + } + } + } + } + } + else if (member instanceof PsiClass) { + if (Boolean.FALSE.equals(memberInfo.getOverrides())) { + final PsiClass aClass = (PsiClass)memberInfo.getMember(); + PsiClassType classType = null; + if (!targetClass.isInheritor(aClass, false)) { + final PsiClassType[] types = memberInfo.getSourceReferenceList().getReferencedTypes(); + for (PsiClassType type : types) { + if (type.resolve() == aClass) { + classType = (PsiClassType)substitutor.substitute(type); + } + } + PsiJavaCodeReferenceElement classRef = classType != null + ? factory.createReferenceElementByType(classType) : factory.createClassReferenceElement(aClass); + if (aClass.isInterface()) { + targetClass.getImplementsList().add(classRef); + } + else { + targetClass.getExtendsList().add(classRef); + } + } + } + else { + newMember = (PsiMember)targetClass.add(member); + } } - } - } - else { - newMember = (PsiMember)targetClass.add(member); - } - } - if (newMember != null) { - decodeRefs(newMember, targetClass); - //rebind imports first - Collections.sort(refsToRebind, (o1, o2) -> PsiUtil.BY_POSITION.compare(o1.getElement(), o2.getElement())); - for (PsiReference psiReference : refsToRebind) { - JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(psiReference.bindToElement(newMember)); + if (newMember != null) { + decodeRefs(newMember, targetClass); + //rebind imports first + Collections.sort(refsToRebind, (o1, o2) -> PsiUtil.BY_POSITION.compare(o1.getElement(), o2.getElement())); + for (PsiReference psiReference : refsToRebind) { + JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(psiReference.bindToElement(newMember)); + } + final JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance(newMember.getProject()); + ((JavaRefactoringListenerManagerImpl)listenerManager).fireMemberMoved(myClass, newMember); + } } - final JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance(newMember.getProject()); - ((JavaRefactoringListenerManagerImpl)listenerManager).fireMemberMoved(myClass, newMember); - } } - } - private boolean leaveOverrideAnnotation(PsiSubstitutor substitutor, PsiMethod method) { - final PsiMethod methodBySignature = MethodSignatureUtil.findMethodBySignature(myClass, method.getSignature(substitutor), false); - if (methodBySignature == null) return false; - final PsiMethod[] superMethods = methodBySignature.findDeepestSuperMethods(); - if (superMethods.length == 0) return false; - final boolean is15 = !PsiUtil.isLanguageLevel6OrHigher(methodBySignature); - if (is15) { - for (PsiMethod psiMethod : superMethods) { - final PsiClass aClass = psiMethod.getContainingClass(); - if (aClass != null && aClass.isInterface()) { - return false; + private boolean leaveOverrideAnnotation(PsiSubstitutor substitutor, PsiMethod method) { + final PsiMethod methodBySignature = MethodSignatureUtil.findMethodBySignature(myClass, method.getSignature(substitutor), false); + if (methodBySignature == null) { + return false; + } + final PsiMethod[] superMethods = methodBySignature.findDeepestSuperMethods(); + if (superMethods.length == 0) { + return false; + } + final boolean is15 = !PsiUtil.isLanguageLevel6OrHigher(methodBySignature); + if (is15) { + for (PsiMethod psiMethod : superMethods) { + final PsiClass aClass = psiMethod.getContainingClass(); + if (aClass != null && aClass.isInterface()) { + return false; + } + } } - } + return true; } - return true; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/JavaMoveDirectoryWithClassesHelper.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/JavaMoveDirectoryWithClassesHelper.java index 6eb1648a15..89860f5a29 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/JavaMoveDirectoryWithClassesHelper.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/JavaMoveDirectoryWithClassesHelper.java @@ -21,114 +21,123 @@ @ExtensionImpl public class JavaMoveDirectoryWithClassesHelper extends MoveDirectoryWithClassesHelper { - @Override - public void findUsages(Collection filesToMove, - PsiDirectory[] directoriesToMove, - Collection usages, - boolean searchInComments, - boolean searchInNonJavaFiles, - Project project) { - final Set packageNames = new HashSet(); - for (PsiFile psiFile : filesToMove) { - if (psiFile instanceof PsiClassOwner) { - final PsiClass[] classes = ((PsiClassOwner) psiFile).getClasses(); - for (PsiClass aClass : classes) { - Collections - .addAll(usages, MoveClassesOrPackagesUtil.findUsages(aClass, searchInComments, searchInNonJavaFiles, aClass.getName())); + @Override + public void findUsages( + Collection filesToMove, + PsiDirectory[] directoriesToMove, + Collection usages, + boolean searchInComments, + boolean searchInNonJavaFiles, + Project project + ) { + final Set packageNames = new HashSet(); + for (PsiFile psiFile : filesToMove) { + if (psiFile instanceof PsiClassOwner) { + final PsiClass[] classes = ((PsiClassOwner)psiFile).getClasses(); + for (PsiClass aClass : classes) { + Collections + .addAll( + usages, + MoveClassesOrPackagesUtil.findUsages(aClass, searchInComments, searchInNonJavaFiles, aClass.getName()) + ); + } + packageNames.add(((PsiClassOwner)psiFile).getPackageName()); + } } - packageNames.add(((PsiClassOwner) psiFile).getPackageName()); - } - } - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - for (String packageName : packageNames) { - final PsiJavaPackage aPackage = psiFacade.findPackage(packageName); - if (aPackage != null) { - boolean remainsNothing = true; - for (PsiDirectory packageDirectory : aPackage.getDirectories()) { - if (!isUnderRefactoring(packageDirectory, directoriesToMove)) { - remainsNothing = false; - break; - } - } - if (remainsNothing) { - for (PsiReference reference : ReferencesSearch.search(aPackage)) { - final PsiElement element = reference.getElement(); - final PsiImportStatementBase statementBase = PsiTreeUtil.getParentOfType(element, PsiImportStatementBase.class); - if (statementBase != null && statementBase.isOnDemand()) { - usages.add(new RemoveOnDemandImportStatementsUsageInfo(statementBase)); + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + for (String packageName : packageNames) { + final PsiJavaPackage aPackage = psiFacade.findPackage(packageName); + if (aPackage != null) { + boolean remainsNothing = true; + for (PsiDirectory packageDirectory : aPackage.getDirectories()) { + if (!isUnderRefactoring(packageDirectory, directoriesToMove)) { + remainsNothing = false; + break; + } + } + if (remainsNothing) { + for (PsiReference reference : ReferencesSearch.search(aPackage)) { + final PsiElement element = reference.getElement(); + final PsiImportStatementBase statementBase = PsiTreeUtil.getParentOfType(element, PsiImportStatementBase.class); + if (statementBase != null && statementBase.isOnDemand()) { + usages.add(new RemoveOnDemandImportStatementsUsageInfo(statementBase)); + } + } + } } - } } - } } - } - private static boolean isUnderRefactoring(PsiDirectory packageDirectory, PsiDirectory[] directoriesToMove) { - for (PsiDirectory directory : directoriesToMove) { - if (PsiTreeUtil.isAncestor(directory, packageDirectory, true)) { - return true; - } + private static boolean isUnderRefactoring(PsiDirectory packageDirectory, PsiDirectory[] directoriesToMove) { + for (PsiDirectory directory : directoriesToMove) { + if (PsiTreeUtil.isAncestor(directory, packageDirectory, true)) { + return true; + } + } + return false; } - return false; - } - @Override - public boolean move(PsiFile file, - PsiDirectory moveDestination, - Map oldToNewElementsMapping, - List movedFiles, - RefactoringElementListener listener) { - if (!(file instanceof PsiClassOwner)) { - return false; - } + @Override + public boolean move( + PsiFile file, + PsiDirectory moveDestination, + Map oldToNewElementsMapping, + List movedFiles, + RefactoringElementListener listener + ) { + if (!(file instanceof PsiClassOwner)) { + return false; + } - //if (!JspPsiUtil.isInJspFile(file)) { - return false; - /* } + //if (!JspPsiUtil.isInJspFile(file)) { + return false; + /*} - for (PsiClass psiClass : ((PsiClassOwner)file).getClasses()) { - final PsiClass newClass = MoveClassesOrPackagesUtil.doMoveClass(psiClass, moveDestination); - oldToNewElementsMapping.put(psiClass, newClass); - listener.elementMoved(newClass); + for (PsiClass psiClass : ((PsiClassOwner)file).getClasses()) { + final PsiClass newClass = MoveClassesOrPackagesUtil.doMoveClass(psiClass, moveDestination); + oldToNewElementsMapping.put(psiClass, newClass); + listener.elementMoved(newClass); + } + return true;*/ } - return true; */ - } - @Override - public void postProcessUsages(UsageInfo[] usages, Function newDirMapper) { - for (UsageInfo usage : usages) { - if (usage instanceof RemoveOnDemandImportStatementsUsageInfo) { - final PsiElement element = usage.getElement(); - if (element != null) { - element.delete(); + @Override + public void postProcessUsages(UsageInfo[] usages, Function newDirMapper) { + for (UsageInfo usage : usages) { + if (usage instanceof RemoveOnDemandImportStatementsUsageInfo) { + final PsiElement element = usage.getElement(); + if (element != null) { + element.delete(); + } + } } - } } - } - @Override - public void preprocessUsages(Project project, - Set files, - UsageInfo[] infos, - PsiDirectory directory, - MultiMap conflicts) { - RefactoringConflictsUtil.analyzeModuleConflicts(project, files, infos, directory, conflicts); - } + @Override + public void preprocessUsages( + Project project, + Set files, + UsageInfo[] infos, + PsiDirectory directory, + MultiMap conflicts + ) { + RefactoringConflictsUtil.analyzeModuleConflicts(project, files, infos, directory, conflicts); + } - @Override - public void beforeMove(PsiFile psiFile) { - ChangeContextUtil.encodeContextInfo(psiFile, true); - } + @Override + public void beforeMove(PsiFile psiFile) { + ChangeContextUtil.encodeContextInfo(psiFile, true); + } - @Override - public void afterMove(PsiElement newElement) { - ChangeContextUtil.decodeContextInfo(newElement, null, null); - } + @Override + public void afterMove(PsiElement newElement) { + ChangeContextUtil.decodeContextInfo(newElement, null, null); + } - private static class RemoveOnDemandImportStatementsUsageInfo extends UsageInfo { - public RemoveOnDemandImportStatementsUsageInfo(PsiImportStatementBase statementBase) { - super(statementBase); + private static class RemoveOnDemandImportStatementsUsageInfo extends UsageInfo { + public RemoveOnDemandImportStatementsUsageInfo(PsiImportStatementBase statementBase) { + super(statementBase); + } } - } } 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 c73273f39f..a393ff51d0 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 @@ -121,7 +121,7 @@ public UsageInfo[] findUsages() { @Override @RequiredUIAccess - protected boolean preprocessUsages(SimpleReference refUsages) { + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { UsageInfo[] usages = refUsages.get(); return showConflicts(getConflicts(usages), usages); } 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 2a10f551e6..5099645cee 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 @@ -52,7 +52,7 @@ import consulo.util.collection.MultiMap; import consulo.util.lang.Comparing; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -226,8 +226,9 @@ public Collection getConflicts() { } } + @Override @RequiredUIAccess - protected boolean preprocessUsages(Ref refUsages) { + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { UsageInfo[] usages = refUsages.get(); MultiMap conflicts = new MultiMap<>(); ArrayList filteredUsages = new ArrayList<>(); diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java index 20638a18f5..cd0975f00d 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java @@ -29,6 +29,7 @@ import consulo.usage.UsageInfo; import jakarta.annotation.Nonnull; + import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -38,111 +39,114 @@ */ @ExtensionImpl(id = "java") public class MoveJavaClassHandler implements MoveClassHandler { - private static final Logger LOG = Logger.getInstance(MoveJavaClassHandler.class); + private static final Logger LOG = Logger.getInstance(MoveJavaClassHandler.class); - @Override - public void finishMoveClass(@Nonnull PsiClass aClass) { - if (aClass.getContainingFile() instanceof PsiJavaFile) { - ChangeContextUtil.decodeContextInfo(aClass, null, null); + @Override + public void finishMoveClass(@Nonnull PsiClass aClass) { + if (aClass.getContainingFile() instanceof PsiJavaFile) { + ChangeContextUtil.decodeContextInfo(aClass, null, null); + } } - } - @Override - public void prepareMove(@Nonnull PsiClass aClass) { - if (aClass.getContainingFile() instanceof PsiJavaFile) { - ChangeContextUtil.encodeContextInfo(aClass, true); + @Override + public void prepareMove(@Nonnull PsiClass aClass) { + if (aClass.getContainingFile() instanceof PsiJavaFile) { + ChangeContextUtil.encodeContextInfo(aClass, true); + } } - } - public PsiClass doMoveClass(@Nonnull final PsiClass aClass, @Nonnull PsiDirectory moveDestination) throws IncorrectOperationException { - PsiFile file = aClass.getContainingFile(); - final PsiJavaPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination); + public PsiClass doMoveClass(@Nonnull final PsiClass aClass, @Nonnull PsiDirectory moveDestination) throws IncorrectOperationException { + PsiFile file = aClass.getContainingFile(); + final PsiJavaPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination); - PsiClass newClass = null; - if (file instanceof PsiJavaFile) { - if (!moveDestination.equals(file.getContainingDirectory()) && - moveDestination.findFile(file.getName()) != null) { - // moving second of two classes which were in the same file to a different directory (IDEADEV-3089) - correctSelfReferences(aClass, newPackage); - final PsiFile newFile = moveDestination.findFile(file.getName()); - LOG.assertTrue(newFile != null); - newClass = (PsiClass)newFile.add(aClass); - correctOldClassReferences(newClass, aClass); - aClass.delete(); - } - else if (((PsiJavaFile)file).getClasses().length > 1) { - correctSelfReferences(aClass, newPackage); - final PsiClass created = JavaDirectoryService.getInstance().createClass(moveDestination, aClass.getName()); - if (aClass.getDocComment() == null) { - final PsiDocComment createdDocComment = created.getDocComment(); - if (createdDocComment != null) { - aClass.addAfter(createdDocComment, null); - } + PsiClass newClass = null; + if (file instanceof PsiJavaFile) { + if (!moveDestination.equals(file.getContainingDirectory()) && + moveDestination.findFile(file.getName()) != null) { + // moving second of two classes which were in the same file to a different directory (IDEADEV-3089) + correctSelfReferences(aClass, newPackage); + final PsiFile newFile = moveDestination.findFile(file.getName()); + LOG.assertTrue(newFile != null); + newClass = (PsiClass)newFile.add(aClass); + correctOldClassReferences(newClass, aClass); + aClass.delete(); + } + else if (((PsiJavaFile)file).getClasses().length > 1) { + correctSelfReferences(aClass, newPackage); + final PsiClass created = JavaDirectoryService.getInstance().createClass(moveDestination, aClass.getName()); + if (aClass.getDocComment() == null) { + final PsiDocComment createdDocComment = created.getDocComment(); + if (createdDocComment != null) { + aClass.addAfter(createdDocComment, null); + } + } + newClass = (PsiClass)created.replace(aClass); + correctOldClassReferences(newClass, aClass); + aClass.delete(); + } } - newClass = (PsiClass)created.replace(aClass); - correctOldClassReferences(newClass, aClass); - aClass.delete(); - } + return newClass; } - return newClass; - } - private static void correctOldClassReferences(final PsiClass newClass, final PsiClass oldClass) { - final Set importsToDelete = new HashSet(); - newClass.getContainingFile().accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - if (reference.isValid() && reference.isReferenceTo(oldClass)) { - final PsiImportStatementBase importStatement = PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class); - if (importStatement != null) { - importsToDelete.add(importStatement); - return; - } - try { - reference.bindToElement(newClass); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } + private static void correctOldClassReferences(final PsiClass newClass, final PsiClass oldClass) { + final Set importsToDelete = new HashSet(); + newClass.getContainingFile().accept(new JavaRecursiveElementVisitor() { + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + if (reference.isValid() && reference.isReferenceTo(oldClass)) { + final PsiImportStatementBase importStatement = PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class); + if (importStatement != null) { + importsToDelete.add(importStatement); + return; + } + try { + reference.bindToElement(newClass); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + super.visitReferenceElement(reference); + } + }); + for (PsiImportStatementBase importStatement : importsToDelete) { + importStatement.delete(); } - super.visitReferenceElement(reference); - } - }); - for (PsiImportStatementBase importStatement : importsToDelete) { - importStatement.delete(); } - } - private static void correctSelfReferences(final PsiClass aClass, final PsiJavaPackage newContainingPackage) { - final PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(aClass.getContainingFile().getContainingDirectory()); - if (aPackage != null) { - aClass.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - if (reference.isQualified() && reference.isReferenceTo(aClass)) { - final PsiElement qualifier = reference.getQualifier(); - if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).isReferenceTo(aPackage)) { - try { - ((PsiJavaCodeReferenceElement)qualifier).bindToElement(newContainingPackage); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - super.visitReferenceElement(reference); + private static void correctSelfReferences(final PsiClass aClass, final PsiJavaPackage newContainingPackage) { + final PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(aClass.getContainingFile().getContainingDirectory()); + if (aPackage != null) { + aClass.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + if (reference.isQualified() && reference.isReferenceTo(aClass)) { + final PsiElement qualifier = reference.getQualifier(); + if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).isReferenceTo( + aPackage)) { + try { + ((PsiJavaCodeReferenceElement)qualifier).bindToElement(newContainingPackage); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + super.visitReferenceElement(reference); + } + }); } - }); } - } - public String getName(PsiClass clazz) { - final PsiFile file = clazz.getContainingFile(); - if (!(file instanceof PsiJavaFile)) return null; - return ((PsiJavaFile)file).getClasses().length > 1 ? clazz.getName() + "." + JavaFileType.INSTANCE.getDefaultExtension() : file.getName(); - } + public String getName(PsiClass clazz) { + final PsiFile file = clazz.getContainingFile(); + if (!(file instanceof PsiJavaFile)) { + return null; + } + return ((PsiJavaFile)file).getClasses().length > 1 ? clazz.getName() + "." + JavaFileType.INSTANCE.getDefaultExtension() : file.getName(); + } - @Override - public void preprocessUsages(Collection results) { - } + @Override + public void preprocessUsages(Collection results) { + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInner/MoveInnerProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInner/MoveInnerProcessor.java index d3cf22f8d0..8e35a8b4ad 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInner/MoveInnerProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInner/MoveInnerProcessor.java @@ -44,12 +44,13 @@ import consulo.navigation.OpenFileDescriptor; import consulo.navigation.OpenFileDescriptorFactory; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.NonCodeUsageInfo; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.jetbrains.annotations.NonNls; @@ -58,480 +59,516 @@ import java.util.function.Function; /** - * created at Sep 24, 2001 - * * @author Jeka + * @since 2001-09-24 */ public class MoveInnerProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(MoveInnerProcessor.class); - - private MoveCallback myMoveCallback; - - private PsiClass myInnerClass; - private PsiClass myOuterClass; - private PsiElement myTargetContainer; - private String myParameterNameOuterClass; - private String myFieldNameOuterClass; - private String myDescriptiveName = ""; - private String myNewClassName; - private boolean mySearchInComments; - private boolean mySearchInNonJavaFiles; - private NonCodeUsageInfo[] myNonCodeUsages; - - public MoveInnerProcessor(Project project, MoveCallback moveCallback) { - super(project); - myMoveCallback = moveCallback; - } - - public MoveInnerProcessor(Project project, - PsiClass innerClass, - String name, - boolean passOuterClass, - String parameterName, - final PsiElement targetContainer) { - super(project); - setup(innerClass, name, passOuterClass, parameterName, true, true, targetContainer); - } - - protected String getCommandName() { - return RefactoringLocalize.moveInnerClassCommand(myDescriptiveName).get(); - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new MoveInnerViewDescriptor(myInnerClass); - } - - @Nonnull - protected UsageInfo[] findUsages() { - LOG.assertTrue(myTargetContainer != null); - - Collection innerClassRefs = ReferencesSearch.search(myInnerClass).findAll(); - ArrayList usageInfos = new ArrayList(innerClassRefs.size()); - for (PsiReference innerClassRef : innerClassRefs) { - PsiElement ref = innerClassRef.getElement(); - if (!PsiTreeUtil.isAncestor(myInnerClass, ref, true)) { // do not show self-references - usageInfos.add(new UsageInfo(ref)); - } + private static final Logger LOG = Logger.getInstance(MoveInnerProcessor.class); + + private MoveCallback myMoveCallback; + + private PsiClass myInnerClass; + private PsiClass myOuterClass; + private PsiElement myTargetContainer; + private String myParameterNameOuterClass; + private String myFieldNameOuterClass; + private String myDescriptiveName = ""; + private String myNewClassName; + private boolean mySearchInComments; + private boolean mySearchInNonJavaFiles; + private NonCodeUsageInfo[] myNonCodeUsages; + + public MoveInnerProcessor(Project project, MoveCallback moveCallback) { + super(project); + myMoveCallback = moveCallback; + } + + public MoveInnerProcessor( + Project project, + PsiClass innerClass, + String name, + boolean passOuterClass, + String parameterName, + final PsiElement targetContainer + ) { + super(project); + setup(innerClass, name, passOuterClass, parameterName, true, true, targetContainer); } - final String newQName; - if (myTargetContainer instanceof PsiDirectory) { - final PsiDirectory targetDirectory = (PsiDirectory) myTargetContainer; - final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(targetDirectory); - LOG.assertTrue(aPackage != null); - newQName = aPackage.getQualifiedName() + "." + myNewClassName; - } else if (myTargetContainer instanceof PsiClass) { - final String qName = ((PsiClass) myTargetContainer).getQualifiedName(); - if (qName != null) { - newQName = qName + "." + myNewClassName; - } else { - newQName = myNewClassName; - } - } else { - newQName = myNewClassName; + protected String getCommandName() { + return RefactoringLocalize.moveInnerClassCommand(myDescriptiveName).get(); } - MoveClassesOrPackagesUtil.findNonCodeUsages(mySearchInComments, mySearchInNonJavaFiles, - myInnerClass, newQName, usageInfos); - return usageInfos.toArray(new UsageInfo[usageInfos.size()]); - } - - protected void refreshElements(PsiElement[] elements) { - boolean condition = elements.length == 1 && elements[0] instanceof PsiClass; - LOG.assertTrue(condition); - myInnerClass = (PsiClass) elements[0]; - } - - public boolean isSearchInComments() { - return mySearchInComments; - } - - public void setSearchInComments(boolean searchInComments) { - mySearchInComments = searchInComments; - } - - public boolean isSearchInNonJavaFiles() { - return mySearchInNonJavaFiles; - } - - public void setSearchInNonJavaFiles(boolean searchInNonJavaFiles) { - mySearchInNonJavaFiles = searchInNonJavaFiles; - } - - protected void performRefactoring(final UsageInfo[] usages) { - final PsiManager manager = PsiManager.getInstance(myProject); - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - - final RefactoringElementListener elementListener = getTransaction().getElementListener(myInnerClass); - try { - PsiField field = null; - if (myParameterNameOuterClass != null) { - // pass outer as a parameter - field = factory.createField(myFieldNameOuterClass, factory.createType(myOuterClass)); - field = addOuterField(field); - myInnerClass = field.getContainingClass(); - addFieldInitializationToConstructors(myInnerClass, field, myParameterNameOuterClass); - } - - ChangeContextUtil.encodeContextInfo(myInnerClass, false); - - myInnerClass = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(myInnerClass); - - final MoveInnerOptions moveInnerOptions = new MoveInnerOptions(myInnerClass, myOuterClass, myTargetContainer, myNewClassName); - final MoveInnerHandler handler = MoveInnerHandler.forLanguage(myInnerClass.getLanguage()); - final PsiClass newClass; - try { - newClass = handler.copyClass(moveInnerOptions); - } catch (IncorrectOperationException e) { - RefactoringUIUtil.processIncorrectOperation(myProject, e); - return; - } - - // replace references in a new class to old inner class with references to itself - for (PsiReference ref : ReferencesSearch.search(myInnerClass, new LocalSearchScope(newClass), true)) { - PsiElement element = ref.getElement(); - if (element.getParent() instanceof PsiJavaCodeReferenceElement) { - PsiJavaCodeReferenceElement parentRef = (PsiJavaCodeReferenceElement) element.getParent(); - PsiElement parentRefElement = parentRef.resolve(); - if (parentRefElement instanceof PsiClass) { // reference to inner class inside our inner - parentRef.getQualifier().delete(); - continue; - } + + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new MoveInnerViewDescriptor(myInnerClass); + } + + @Nonnull + protected UsageInfo[] findUsages() { + LOG.assertTrue(myTargetContainer != null); + + Collection innerClassRefs = ReferencesSearch.search(myInnerClass).findAll(); + ArrayList usageInfos = new ArrayList(innerClassRefs.size()); + for (PsiReference innerClassRef : innerClassRefs) { + PsiElement ref = innerClassRef.getElement(); + if (!PsiTreeUtil.isAncestor(myInnerClass, ref, true)) { // do not show self-references + usageInfos.add(new UsageInfo(ref)); + } } - ref.bindToElement(newClass); - } - - List referencesToRebind = new ArrayList(); - for (UsageInfo usage : usages) { - if (usage.isNonCodeUsage) continue; - PsiElement refElement = usage.getElement(); - PsiReference[] references = refElement.getReferences(); - for (PsiReference reference : references) { - if (reference.isReferenceTo(myInnerClass)) { - referencesToRebind.add(reference); - } + + final String newQName; + if (myTargetContainer instanceof PsiDirectory) { + final PsiDirectory targetDirectory = (PsiDirectory)myTargetContainer; + final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(targetDirectory); + LOG.assertTrue(aPackage != null); + newQName = aPackage.getQualifiedName() + "." + myNewClassName; } - } - - myInnerClass.delete(); - - // correct references in usages - for (UsageInfo usage : usages) { - if (usage.isNonCodeUsage) continue; - PsiElement refElement = usage.getElement(); - if (myParameterNameOuterClass != null) { // should pass outer as parameter - PsiElement refParent = refElement.getParent(); - if (refParent instanceof PsiNewExpression || refParent instanceof PsiAnonymousClass) { - PsiNewExpression newExpr = refParent instanceof PsiNewExpression - ? (PsiNewExpression) refParent - : (PsiNewExpression) refParent.getParent(); - - PsiExpressionList argList = newExpr.getArgumentList(); - - if (argList != null) { // can happen in incomplete code - if (newExpr.getQualifier() == null) { - PsiThisExpression thisExpr; - PsiClass parentClass = RefactoringChangeUtil.getThisClass(newExpr); - if (myOuterClass.equals(parentClass)) { - thisExpr = RefactoringChangeUtil.createThisExpression(manager, null); - } else { - thisExpr = RefactoringChangeUtil.createThisExpression(manager, myOuterClass); - } - argList.addAfter(thisExpr, null); - } else { - argList.addAfter(newExpr.getQualifier(), null); - newExpr.getQualifier().delete(); - } + else if (myTargetContainer instanceof PsiClass) { + final String qName = ((PsiClass)myTargetContainer).getQualifiedName(); + if (qName != null) { + newQName = qName + "." + myNewClassName; } - } + else { + newQName = myNewClassName; + } + } + else { + newQName = myNewClassName; } - } - - for (PsiReference reference : referencesToRebind) { - reference.bindToElement(newClass); - } - - if (field != null) { - final PsiExpression paramAccessExpression = factory.createExpressionFromText(myParameterNameOuterClass, null); - for (final PsiMethod constructor : newClass.getConstructors()) { - final PsiStatement[] statements = constructor.getBody().getStatements(); - if (statements.length > 0) { - if (statements[0] instanceof PsiExpressionStatement) { - PsiExpression expression = ((PsiExpressionStatement) statements[0]).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - @NonNls String text = ((PsiMethodCallExpression) expression).getMethodExpression().getText(); - if ("this".equals(text) || "super".equals(text)) { - ChangeContextUtil.decodeContextInfo(expression, myOuterClass, paramAccessExpression); + MoveClassesOrPackagesUtil.findNonCodeUsages( + mySearchInComments, + mySearchInNonJavaFiles, + myInnerClass, + newQName, + usageInfos + ); + return usageInfos.toArray(new UsageInfo[usageInfos.size()]); + } + + protected void refreshElements(PsiElement[] elements) { + boolean condition = elements.length == 1 && elements[0] instanceof PsiClass; + LOG.assertTrue(condition); + myInnerClass = (PsiClass)elements[0]; + } + + public boolean isSearchInComments() { + return mySearchInComments; + } + + public void setSearchInComments(boolean searchInComments) { + mySearchInComments = searchInComments; + } + + public boolean isSearchInNonJavaFiles() { + return mySearchInNonJavaFiles; + } + + public void setSearchInNonJavaFiles(boolean searchInNonJavaFiles) { + mySearchInNonJavaFiles = searchInNonJavaFiles; + } + + protected void performRefactoring(final UsageInfo[] usages) { + final PsiManager manager = PsiManager.getInstance(myProject); + final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + + final RefactoringElementListener elementListener = getTransaction().getElementListener(myInnerClass); + try { + PsiField field = null; + if (myParameterNameOuterClass != null) { + // pass outer as a parameter + field = factory.createField(myFieldNameOuterClass, factory.createType(myOuterClass)); + field = addOuterField(field); + myInnerClass = field.getContainingClass(); + addFieldInitializationToConstructors(myInnerClass, field, myParameterNameOuterClass); + } + + ChangeContextUtil.encodeContextInfo(myInnerClass, false); + + myInnerClass = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(myInnerClass); + + final MoveInnerOptions moveInnerOptions = new MoveInnerOptions(myInnerClass, myOuterClass, myTargetContainer, myNewClassName); + final MoveInnerHandler handler = MoveInnerHandler.forLanguage(myInnerClass.getLanguage()); + final PsiClass newClass; + try { + newClass = handler.copyClass(moveInnerOptions); + } + catch (IncorrectOperationException e) { + RefactoringUIUtil.processIncorrectOperation(myProject, e); + return; + } + + // replace references in a new class to old inner class with references to itself + for (PsiReference ref : ReferencesSearch.search(myInnerClass, new LocalSearchScope(newClass), true)) { + PsiElement element = ref.getElement(); + if (element.getParent() instanceof PsiJavaCodeReferenceElement) { + PsiJavaCodeReferenceElement parentRef = (PsiJavaCodeReferenceElement)element.getParent(); + PsiElement parentRefElement = parentRef.resolve(); + if (parentRefElement instanceof PsiClass) { // reference to inner class inside our inner + parentRef.getQualifier().delete(); + continue; + } } - } + ref.bindToElement(newClass); } - } - } - PsiExpression accessExpression = factory.createExpressionFromText(myFieldNameOuterClass, null); - ChangeContextUtil.decodeContextInfo(newClass, myOuterClass, accessExpression); - } else { - ChangeContextUtil.decodeContextInfo(newClass, null, null); - } - - PsiFile targetFile = newClass.getContainingFile(); - OpenFileDescriptor descriptor = OpenFileDescriptorFactory.getInstance(myProject).builder(targetFile.getVirtualFile()).offset(newClass.getTextOffset()).build(); - FileEditorManager.getInstance(myProject).openTextEditor(descriptor, true); - - if (myMoveCallback != null) { - myMoveCallback.refactoringCompleted(); - } - elementListener.elementMoved(newClass); - - List nonCodeUsages = new ArrayList(); - for (UsageInfo usage : usages) { - if (usage instanceof NonCodeUsageInfo) { - nonCodeUsages.add((NonCodeUsageInfo) usage); + List referencesToRebind = new ArrayList(); + for (UsageInfo usage : usages) { + if (usage.isNonCodeUsage) { + continue; + } + PsiElement refElement = usage.getElement(); + PsiReference[] references = refElement.getReferences(); + for (PsiReference reference : references) { + if (reference.isReferenceTo(myInnerClass)) { + referencesToRebind.add(reference); + } + } + } + + myInnerClass.delete(); + + // correct references in usages + for (UsageInfo usage : usages) { + if (usage.isNonCodeUsage) { + continue; + } + PsiElement refElement = usage.getElement(); + if (myParameterNameOuterClass != null) { // should pass outer as parameter + PsiElement refParent = refElement.getParent(); + if (refParent instanceof PsiNewExpression || refParent instanceof PsiAnonymousClass) { + PsiNewExpression newExpr = refParent instanceof PsiNewExpression + ? (PsiNewExpression)refParent + : (PsiNewExpression)refParent.getParent(); + + PsiExpressionList argList = newExpr.getArgumentList(); + + if (argList != null) { // can happen in incomplete code + if (newExpr.getQualifier() == null) { + PsiThisExpression thisExpr; + PsiClass parentClass = RefactoringChangeUtil.getThisClass(newExpr); + if (myOuterClass.equals(parentClass)) { + thisExpr = RefactoringChangeUtil.createThisExpression(manager, null); + } + else { + thisExpr = RefactoringChangeUtil.createThisExpression(manager, myOuterClass); + } + argList.addAfter(thisExpr, null); + } + else { + argList.addAfter(newExpr.getQualifier(), null); + newExpr.getQualifier().delete(); + } + } + } + } + } + + for (PsiReference reference : referencesToRebind) { + reference.bindToElement(newClass); + } + + if (field != null) { + final PsiExpression paramAccessExpression = factory.createExpressionFromText(myParameterNameOuterClass, null); + for (final PsiMethod constructor : newClass.getConstructors()) { + final PsiStatement[] statements = constructor.getBody().getStatements(); + if (statements.length > 0) { + if (statements[0] instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + @NonNls String text = ((PsiMethodCallExpression)expression).getMethodExpression().getText(); + if ("this".equals(text) || "super".equals(text)) { + ChangeContextUtil.decodeContextInfo(expression, myOuterClass, paramAccessExpression); + } + } + } + } + } + + PsiExpression accessExpression = factory.createExpressionFromText(myFieldNameOuterClass, null); + ChangeContextUtil.decodeContextInfo(newClass, myOuterClass, accessExpression); + } + else { + ChangeContextUtil.decodeContextInfo(newClass, null, null); + } + + PsiFile targetFile = newClass.getContainingFile(); + OpenFileDescriptor descriptor = OpenFileDescriptorFactory.getInstance(myProject) + .builder(targetFile.getVirtualFile()) + .offset(newClass.getTextOffset()) + .build(); + FileEditorManager.getInstance(myProject).openTextEditor(descriptor, true); + + if (myMoveCallback != null) { + myMoveCallback.refactoringCompleted(); + } + elementListener.elementMoved(newClass); + + List nonCodeUsages = new ArrayList(); + for (UsageInfo usage : usages) { + if (usage instanceof NonCodeUsageInfo) { + nonCodeUsages.add((NonCodeUsageInfo)usage); + } + } + myNonCodeUsages = nonCodeUsages.toArray(new NonCodeUsageInfo[nonCodeUsages.size()]); } - } - myNonCodeUsages = nonCodeUsages.toArray(new NonCodeUsageInfo[nonCodeUsages.size()]); - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - private PsiField addOuterField(PsiField field) { - final PsiMember[] members = PsiTreeUtil.getChildrenOfType(myInnerClass, PsiMember.class); - if (members != null) { - for (PsiMember member : members) { - if (!member.hasModifierProperty(PsiModifier.STATIC)) { - return (PsiField) myInnerClass.addBefore(field, member); + catch (IncorrectOperationException e) { + LOG.error(e); } - } } - return (PsiField) myInnerClass.add(field); - } + private PsiField addOuterField(PsiField field) { + final PsiMember[] members = PsiTreeUtil.getChildrenOfType(myInnerClass, PsiMember.class); + if (members != null) { + for (PsiMember member : members) { + if (!member.hasModifierProperty(PsiModifier.STATIC)) { + return (PsiField)myInnerClass.addBefore(field, member); + } + } + } - protected void performPsiSpoilingRefactoring() { - if (myNonCodeUsages != null) { - RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages); + return (PsiField)myInnerClass.add(field); } - } - protected boolean preprocessUsages(Ref refUsages) { - final MultiMap conflicts = new MultiMap(); - final HashMap> reported = new HashMap>(); - class Visitor extends JavaRecursiveElementWalkingVisitor { + protected void performPsiSpoilingRefactoring() { + if (myNonCodeUsages != null) { + RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages); + } + } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + final MultiMap conflicts = new MultiMap(); + final HashMap> reported = new HashMap>(); + class Visitor extends JavaRecursiveElementWalkingVisitor { + + + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + PsiElement resolved = reference.resolve(); + if (resolved instanceof PsiMember && + PsiTreeUtil.isAncestor(myInnerClass, resolved, true) && + becomesInaccessible((PsiMember)resolved)) { + registerConflict(reference, resolved, reported, conflicts); + } + } - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - PsiElement resolved = reference.resolve(); - if (resolved instanceof PsiMember && - PsiTreeUtil.isAncestor(myInnerClass, resolved, true) && - becomesInaccessible((PsiMember) resolved)) { - registerConflict(reference, resolved, reported, conflicts); + @Override + public void visitClass(PsiClass aClass) { + if (aClass == myInnerClass) { + return; + } + super.visitClass(aClass); + } } - } +// if (myInnerClass.hasModifierProperty(PsiModifier.)) { + myOuterClass.accept(new Visitor()); + myInnerClass.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + super.visitReferenceElement(reference); + final PsiElement resolve = reference.resolve(); + if (resolve instanceof PsiMember) { + if (PsiTreeUtil.isAncestor(myOuterClass, resolve, true) && !PsiTreeUtil.isAncestor(myInnerClass, resolve, false)) { + if (becomesInaccessible((PsiMember)resolve)) { + registerConflict(reference, resolve, reported, conflicts); + } + } + } + } + }); - @Override - public void visitClass(PsiClass aClass) { - if (aClass == myInnerClass) return; - super.visitClass(aClass); - } + return showConflicts(conflicts, refUsages.get()); } -// if (myInnerClass.hasModifierProperty(PsiModifier.)) { - myOuterClass.accept(new Visitor()); - myInnerClass.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - super.visitReferenceElement(reference); - final PsiElement resolve = reference.resolve(); - if (resolve instanceof PsiMember) { - if (PsiTreeUtil.isAncestor(myOuterClass, resolve, true) && !PsiTreeUtil.isAncestor(myInnerClass, resolve, false)) { - if (becomesInaccessible((PsiMember) resolve)) { - registerConflict(reference, resolve, reported, conflicts); + private static void registerConflict( + PsiJavaCodeReferenceElement reference, + PsiElement resolved, + HashMap> reported, MultiMap conflicts + ) { + final PsiElement container = ConflictsUtil.getContainer(reference); + HashSet containerSet = reported.get(container); + if (containerSet == null) { + containerSet = new HashSet(); + reported.put(container, containerSet); + } + if (!containerSet.contains(resolved)) { + containerSet.add(resolved); + String placesDescription; + if (containerSet.size() == 1) { + placesDescription = RefactoringUIUtil.getDescription(resolved, true); + } + else { + placesDescription = "
  1. " + StringUtil.join(containerSet, new Function() { + @Override + public String apply(PsiElement element) { + return RefactoringUIUtil.getDescription(element, true); + } + }, "
  2. ") + "
"; } - } + LocalizeValue message = + RefactoringLocalize.zeroWillBecomeInaccessibleFrom1(placesDescription, RefactoringUIUtil.getDescription(container, true)); + conflicts.put(container, Collections.singletonList(message.get())); } - } - }); - - return showConflicts(conflicts, refUsages.get()); - } - - private static void registerConflict(PsiJavaCodeReferenceElement reference, - PsiElement resolved, - HashMap> reported, MultiMap conflicts) { - final PsiElement container = ConflictsUtil.getContainer(reference); - HashSet containerSet = reported.get(container); - if (containerSet == null) { - containerSet = new HashSet(); - reported.put(container, containerSet); } - if (!containerSet.contains(resolved)) { - containerSet.add(resolved); - String placesDescription; - if (containerSet.size() == 1) { - placesDescription = RefactoringUIUtil.getDescription(resolved, true); - } else { - placesDescription = "
  1. " + StringUtil.join(containerSet, new Function() { - @Override - public String apply(PsiElement element) { - return RefactoringUIUtil.getDescription(element, true); - } - }, "
  2. ") + "
"; - } - LocalizeValue message = - RefactoringLocalize.zeroWillBecomeInaccessibleFrom1(placesDescription, RefactoringUIUtil.getDescription(container, true)); - conflicts.put(container, Collections.singletonList(message.get())); - } - } - - private boolean becomesInaccessible(PsiMember element) { - final String visibilityModifier = VisibilityUtil.getVisibilityModifier(element.getModifierList()); - if (PsiModifier.PRIVATE.equals(visibilityModifier)) return true; - if (PsiModifier.PUBLIC.equals(visibilityModifier)) return false; - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); - if (myTargetContainer instanceof PsiDirectory) { - final PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory) myTargetContainer); - assert aPackage != null : myTargetContainer; - return !psiFacade.isInPackage(myOuterClass, aPackage); - } - // target container is a class - PsiFile targetFile = myTargetContainer.getContainingFile(); - if (targetFile != null) { - final PsiDirectory containingDirectory = targetFile.getContainingDirectory(); - if (containingDirectory != null) { - final PsiJavaPackage targetPackage = JavaDirectoryService.getInstance().getPackage(containingDirectory); - assert targetPackage != null : myTargetContainer; - return psiFacade.isInPackage(myOuterClass, targetPackage); - } + + private boolean becomesInaccessible(PsiMember element) { + final String visibilityModifier = VisibilityUtil.getVisibilityModifier(element.getModifierList()); + if (PsiModifier.PRIVATE.equals(visibilityModifier)) { + return true; + } + if (PsiModifier.PUBLIC.equals(visibilityModifier)) { + return false; + } + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); + if (myTargetContainer instanceof PsiDirectory) { + final PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory)myTargetContainer); + assert aPackage != null : myTargetContainer; + return !psiFacade.isInPackage(myOuterClass, aPackage); + } + // target container is a class + PsiFile targetFile = myTargetContainer.getContainingFile(); + if (targetFile != null) { + final PsiDirectory containingDirectory = targetFile.getContainingDirectory(); + if (containingDirectory != null) { + final PsiJavaPackage targetPackage = JavaDirectoryService.getInstance().getPackage(containingDirectory); + assert targetPackage != null : myTargetContainer; + return psiFacade.isInPackage(myOuterClass, targetPackage); + } + } + return false; } - return false; - } - - public void setup(final PsiClass innerClass, - final String className, - final boolean passOuterClass, - final String parameterName, - boolean searchInComments, - boolean searchInNonJava, - @Nonnull final PsiElement targetContainer) { - myNewClassName = className; - myInnerClass = innerClass; - myDescriptiveName = DescriptiveNameUtil.getDescriptiveName(myInnerClass); - myOuterClass = myInnerClass.getContainingClass(); - myTargetContainer = targetContainer; - JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject); - myParameterNameOuterClass = passOuterClass ? parameterName : null; - if (myParameterNameOuterClass != null) { - myFieldNameOuterClass = - codeStyleManager.variableNameToPropertyName(myParameterNameOuterClass, VariableKind.PARAMETER); - myFieldNameOuterClass = codeStyleManager.propertyNameToVariableName(myFieldNameOuterClass, VariableKind.FIELD); + + public void setup( + final PsiClass innerClass, + final String className, + final boolean passOuterClass, + final String parameterName, + boolean searchInComments, + boolean searchInNonJava, + @Nonnull final PsiElement targetContainer + ) { + myNewClassName = className; + myInnerClass = innerClass; + myDescriptiveName = DescriptiveNameUtil.getDescriptiveName(myInnerClass); + myOuterClass = myInnerClass.getContainingClass(); + myTargetContainer = targetContainer; + JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject); + myParameterNameOuterClass = passOuterClass ? parameterName : null; + if (myParameterNameOuterClass != null) { + myFieldNameOuterClass = + codeStyleManager.variableNameToPropertyName(myParameterNameOuterClass, VariableKind.PARAMETER); + myFieldNameOuterClass = codeStyleManager.propertyNameToVariableName(myFieldNameOuterClass, VariableKind.FIELD); + } + mySearchInComments = searchInComments; + mySearchInNonJavaFiles = searchInNonJava; } - mySearchInComments = searchInComments; - mySearchInNonJavaFiles = searchInNonJava; - } - - private void addFieldInitializationToConstructors(PsiClass aClass, PsiField field, String parameterName) - throws IncorrectOperationException { - - PsiMethod[] constructors = aClass.getConstructors(); - PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); - if (constructors.length > 0) { - for (PsiMethod constructor : constructors) { - if (parameterName != null) { - PsiParameterList parameterList = constructor.getParameterList(); - PsiParameter parameter = factory.createParameter(parameterName, field.getType()); - parameterList.addAfter(parameter, null); + + private void addFieldInitializationToConstructors(PsiClass aClass, PsiField field, String parameterName) + throws IncorrectOperationException { + + PsiMethod[] constructors = aClass.getConstructors(); + PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); + if (constructors.length > 0) { + for (PsiMethod constructor : constructors) { + if (parameterName != null) { + PsiParameterList parameterList = constructor.getParameterList(); + PsiParameter parameter = factory.createParameter(parameterName, field.getType()); + parameterList.addAfter(parameter, null); + } + PsiCodeBlock body = constructor.getBody(); + if (body == null) { + continue; + } + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0) { + PsiStatement first = statements[0]; + if (first instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement)first).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + @NonNls String text = ((PsiMethodCallExpression)expression).getMethodExpression().getText(); + if ("this".equals(text)) { + continue; + } + } + } + } + createAssignmentStatement(constructor, field.getName(), parameterName); + } } - PsiCodeBlock body = constructor.getBody(); - if (body == null) continue; - PsiStatement[] statements = body.getStatements(); - if (statements.length > 0) { - PsiStatement first = statements[0]; - if (first instanceof PsiExpressionStatement) { - PsiExpression expression = ((PsiExpressionStatement) first).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - @NonNls String text = ((PsiMethodCallExpression) expression).getMethodExpression().getText(); - if ("this".equals(text)) { - continue; - } + else { + PsiMethod constructor = factory.createConstructor(); + if (parameterName != null) { + PsiParameterList parameterList = constructor.getParameterList(); + PsiParameter parameter = factory.createParameter(parameterName, field.getType()); + parameterList.add(parameter); } - } + createAssignmentStatement(constructor, field.getName(), parameterName); + aClass.add(constructor); } - createAssignmentStatement(constructor, field.getName(), parameterName); - } - } else { - PsiMethod constructor = factory.createConstructor(); - if (parameterName != null) { - PsiParameterList parameterList = constructor.getParameterList(); - PsiParameter parameter = factory.createParameter(parameterName, field.getType()); - parameterList.add(parameter); - } - createAssignmentStatement(constructor, field.getName(), parameterName); - aClass.add(constructor); } - } - private PsiStatement createAssignmentStatement(PsiMethod constructor, String fieldName, String parameterName) - throws IncorrectOperationException { + private PsiStatement createAssignmentStatement(PsiMethod constructor, String fieldName, String parameterName) + throws IncorrectOperationException { - PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); - @NonNls String pattern = fieldName + "=a;"; - if (fieldName.equals(parameterName)) { - pattern = "this." + pattern; + PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); + @NonNls String pattern = fieldName + "=a;"; + if (fieldName.equals(parameterName)) { + pattern = "this." + pattern; + } + + PsiExpressionStatement statement = (PsiExpressionStatement)factory.createStatementFromText(pattern, null); + statement = (PsiExpressionStatement)CodeStyleManager.getInstance(myProject).reformat(statement); + + PsiCodeBlock body = constructor.getBody(); + assert body != null : constructor; + statement = (PsiExpressionStatement)body.addAfter(statement, getAnchorElement(body)); + + PsiAssignmentExpression assignment = (PsiAssignmentExpression)statement.getExpression(); + PsiReferenceExpression rExpr = (PsiReferenceExpression)assignment.getRExpression(); + assert rExpr != null : assignment; + PsiIdentifier identifier = (PsiIdentifier)rExpr.getReferenceNameElement(); + assert identifier != null : assignment; + identifier.replace(factory.createIdentifier(parameterName)); + return statement; } - PsiExpressionStatement statement = (PsiExpressionStatement) factory.createStatementFromText(pattern, null); - statement = (PsiExpressionStatement) CodeStyleManager.getInstance(myProject).reformat(statement); - - PsiCodeBlock body = constructor.getBody(); - assert body != null : constructor; - statement = (PsiExpressionStatement) body.addAfter(statement, getAnchorElement(body)); - - PsiAssignmentExpression assignment = (PsiAssignmentExpression) statement.getExpression(); - PsiReferenceExpression rExpr = (PsiReferenceExpression) assignment.getRExpression(); - assert rExpr != null : assignment; - PsiIdentifier identifier = (PsiIdentifier) rExpr.getReferenceNameElement(); - assert identifier != null : assignment; - identifier.replace(factory.createIdentifier(parameterName)); - return statement; - } - - @Nullable - private static PsiElement getAnchorElement(PsiCodeBlock body) { - PsiStatement[] statements = body.getStatements(); - if (statements.length > 0) { - PsiStatement first = statements[0]; - if (first instanceof PsiExpressionStatement) { - - PsiExpression expression = ((PsiExpressionStatement) first).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - PsiReferenceExpression methodCall = ((PsiMethodCallExpression) expression).getMethodExpression(); - @NonNls String text = methodCall.getText(); - if ("super".equals(text)) { - return first; - } + @Nullable + private static PsiElement getAnchorElement(PsiCodeBlock body) { + PsiStatement[] statements = body.getStatements(); + if (statements.length > 0) { + PsiStatement first = statements[0]; + if (first instanceof PsiExpressionStatement) { + + PsiExpression expression = ((PsiExpressionStatement)first).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + PsiReferenceExpression methodCall = ((PsiMethodCallExpression)expression).getMethodExpression(); + @NonNls String text = methodCall.getText(); + if ("super".equals(text)) { + return first; + } + } + } } - } + return null; } - return null; - } - public PsiClass getInnerClass() { - return myInnerClass; - } + public PsiClass getInnerClass() { + return myInnerClass; + } - public String getNewClassName() { - return myNewClassName; - } + public String getNewClassName() { + return myNewClassName; + } - public boolean shouldPassParameter() { - return myParameterNameOuterClass != null; - } + public boolean shouldPassParameter() { + return myParameterNameOuterClass != null; + } - public String getParameterName() { - return myParameterNameOuterClass; - } + public String getParameterName() { + return myParameterNameOuterClass; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java index fbd837e44d..0cd9ee5522 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java @@ -41,12 +41,13 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.usage.UsageViewUtil; import consulo.util.collection.MultiMap; import consulo.util.lang.Comparing; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import org.jetbrains.annotations.NonNls; @@ -56,476 +57,539 @@ * @author ven */ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(MoveInstanceMethodProcessor.class); - - public PsiMethod getMethod() { - return myMethod; - } - - public PsiVariable getTargetVariable() { - return myTargetVariable; - } - - private PsiMethod myMethod; - private PsiVariable myTargetVariable; - private PsiClass myTargetClass; - private final String myNewVisibility; - private final Map myOldClassParameterNames; - - public MoveInstanceMethodProcessor(final Project project, final PsiMethod method, final PsiVariable targetVariable, final String newVisibility, final Map oldClassParameterNames) { - super(project); - myMethod = method; - myTargetVariable = targetVariable; - myOldClassParameterNames = oldClassParameterNames; - LOG.assertTrue(myTargetVariable instanceof PsiParameter || myTargetVariable instanceof PsiField); - LOG.assertTrue(myTargetVariable.getType() instanceof PsiClassType); - final PsiType type = myTargetVariable.getType(); - LOG.assertTrue(type instanceof PsiClassType); - myTargetClass = ((PsiClassType) type).resolve(); - myNewVisibility = newVisibility; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new MoveInstanceMethodViewDescriptor(myMethod, myTargetVariable, myTargetClass); - } - - protected boolean preprocessUsages(Ref refUsages) { - final UsageInfo[] usages = refUsages.get(); - MultiMap conflicts = new MultiMap(); - final Set members = new HashSet(); - members.add(myMethod); - if (myTargetVariable instanceof PsiField) { - members.add((PsiMember) myTargetVariable); - } - if (!myTargetClass.isInterface()) { - RefactoringConflictsUtil.analyzeAccessibilityConflicts(members, myTargetClass, conflicts, myNewVisibility); - } else { - for (final UsageInfo usage : usages) { - if (usage instanceof InheritorUsageInfo) { - RefactoringConflictsUtil.analyzeAccessibilityConflicts(members, ((InheritorUsageInfo) usage).getInheritor(), conflicts, myNewVisibility); - } - } - } + private static final Logger LOG = Logger.getInstance(MoveInstanceMethodProcessor.class); - if (myTargetVariable instanceof PsiParameter) { - PsiParameter parameter = (PsiParameter) myTargetVariable; - for (final UsageInfo usageInfo : usages) { - if (usageInfo instanceof MethodCallUsageInfo) { - final PsiElement methodCall = ((MethodCallUsageInfo) usageInfo).getMethodCallExpression(); - if (methodCall instanceof PsiMethodCallExpression) { - final PsiExpression[] expressions = ((PsiMethodCallExpression) methodCall).getArgumentList().getExpressions(); - final int index = myMethod.getParameterList().getParameterIndex(parameter); - if (index < expressions.length) { - PsiExpression instanceValue = expressions[index]; - instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); - if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression) instanceValue).getValue() == null) { - LocalizeValue message = RefactoringLocalize.zeroContainsCallWithNullArgumentForParameter1( - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true), - CommonRefactoringUtil.htmlEmphasize(parameter.getName()) - ); - conflicts.putValue(instanceValue, message.get()); - } - } - } else if (methodCall instanceof PsiMethodReferenceExpression) { - conflicts.putValue(methodCall, "Method reference would be broken after move"); - } - } - } + public PsiMethod getMethod() { + return myMethod; } - try { - ConflictsUtil.checkMethodConflicts(myTargetClass, myMethod, getPatternMethod(), conflicts); - } catch (IncorrectOperationException e) { + public PsiVariable getTargetVariable() { + return myTargetVariable; } - return showConflicts(conflicts, usages); - } - - @Nonnull - protected UsageInfo[] findUsages() { - final PsiManager manager = myMethod.getManager(); - final GlobalSearchScope searchScope = GlobalSearchScope.allScope(manager.getProject()); - final List usages = new ArrayList(); - for (PsiReference ref : ReferencesSearch.search(myMethod, searchScope, false)) { - final PsiElement element = ref.getElement(); - if (element instanceof PsiReferenceExpression) { - boolean isInternal = PsiTreeUtil.isAncestor(myMethod, element, true); - usages.add(new MethodCallUsageInfo((PsiReferenceExpression) element, isInternal)); - } else if (element instanceof PsiDocTagValue) { - usages.add(new JavadocUsageInfo(((PsiDocTagValue) element))); - } else { - throw new UnknownReferenceTypeException(element.getLanguage()); - } + private PsiMethod myMethod; + private PsiVariable myTargetVariable; + private PsiClass myTargetClass; + private final String myNewVisibility; + private final Map myOldClassParameterNames; + + public MoveInstanceMethodProcessor( + final Project project, + final PsiMethod method, + final PsiVariable targetVariable, + final String newVisibility, + final Map oldClassParameterNames + ) { + super(project); + myMethod = method; + myTargetVariable = targetVariable; + myOldClassParameterNames = oldClassParameterNames; + LOG.assertTrue(myTargetVariable instanceof PsiParameter || myTargetVariable instanceof PsiField); + LOG.assertTrue(myTargetVariable.getType() instanceof PsiClassType); + final PsiType type = myTargetVariable.getType(); + LOG.assertTrue(type instanceof PsiClassType); + myTargetClass = ((PsiClassType)type).resolve(); + myNewVisibility = newVisibility; } - if (myTargetClass.isInterface()) { - addInheritorUsages(myTargetClass, searchScope, usages); + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new MoveInstanceMethodViewDescriptor(myMethod, myTargetVariable, myTargetClass); } - final PsiCodeBlock body = myMethod.getBody(); - if (body != null) { - body.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitNewExpression(PsiNewExpression expression) { - if (MoveInstanceMembersUtil.getClassReferencedByThis(expression) != null) { - usages.add(new InternalUsageInfo(expression)); - } - super.visitNewExpression(expression); + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + final UsageInfo[] usages = refUsages.get(); + MultiMap conflicts = new MultiMap(); + final Set members = new HashSet(); + members.add(myMethod); + if (myTargetVariable instanceof PsiField) { + members.add((PsiMember)myTargetVariable); + } + if (!myTargetClass.isInterface()) { + RefactoringConflictsUtil.analyzeAccessibilityConflicts(members, myTargetClass, conflicts, myNewVisibility); + } + else { + for (final UsageInfo usage : usages) { + if (usage instanceof InheritorUsageInfo) { + RefactoringConflictsUtil.analyzeAccessibilityConflicts( + members, + ((InheritorUsageInfo)usage).getInheritor(), + conflicts, + myNewVisibility + ); + } + } } - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - if (MoveInstanceMembersUtil.getClassReferencedByThis(expression) != null) { - usages.add(new InternalUsageInfo(expression)); - } else if (!expression.isQualified()) { - final PsiElement resolved = expression.resolve(); - if (myTargetVariable.equals(resolved)) { - usages.add(new InternalUsageInfo(expression)); + if (myTargetVariable instanceof PsiParameter) { + PsiParameter parameter = (PsiParameter)myTargetVariable; + for (final UsageInfo usageInfo : usages) { + if (usageInfo instanceof MethodCallUsageInfo) { + final PsiElement methodCall = ((MethodCallUsageInfo)usageInfo).getMethodCallExpression(); + if (methodCall instanceof PsiMethodCallExpression) { + final PsiExpression[] expressions = ((PsiMethodCallExpression)methodCall).getArgumentList().getExpressions(); + final int index = myMethod.getParameterList().getParameterIndex(parameter); + if (index < expressions.length) { + PsiExpression instanceValue = expressions[index]; + instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); + if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression)instanceValue).getValue() == null) { + LocalizeValue message = RefactoringLocalize.zeroContainsCallWithNullArgumentForParameter1( + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true), + CommonRefactoringUtil.htmlEmphasize(parameter.getName()) + ); + conflicts.putValue(instanceValue, message.get()); + } + } + } + else if (methodCall instanceof PsiMethodReferenceExpression) { + conflicts.putValue(methodCall, "Method reference would be broken after move"); + } + } } - } + } - super.visitReferenceExpression(expression); + try { + ConflictsUtil.checkMethodConflicts(myTargetClass, myMethod, getPatternMethod(), conflicts); + } + catch (IncorrectOperationException e) { } - }); + + return showConflicts(conflicts, usages); } - return usages.toArray(new UsageInfo[usages.size()]); - } + @Nonnull + protected UsageInfo[] findUsages() { + final PsiManager manager = myMethod.getManager(); + final GlobalSearchScope searchScope = GlobalSearchScope.allScope(manager.getProject()); + final List usages = new ArrayList(); + for (PsiReference ref : ReferencesSearch.search(myMethod, searchScope, false)) { + final PsiElement element = ref.getElement(); + if (element instanceof PsiReferenceExpression) { + boolean isInternal = PsiTreeUtil.isAncestor(myMethod, element, true); + usages.add(new MethodCallUsageInfo((PsiReferenceExpression)element, isInternal)); + } + else if (element instanceof PsiDocTagValue) { + usages.add(new JavadocUsageInfo(((PsiDocTagValue)element))); + } + else { + throw new UnknownReferenceTypeException(element.getLanguage()); + } + } - private static void addInheritorUsages(PsiClass aClass, final GlobalSearchScope searchScope, final List usages) { - for (PsiClass inheritor : ClassInheritorsSearch.search(aClass, searchScope, false).findAll()) { - if (!inheritor.isInterface()) { - usages.add(new InheritorUsageInfo(inheritor)); - } else { - addInheritorUsages(inheritor, searchScope, usages); - } - } - } - - protected void refreshElements(PsiElement[] elements) { - LOG.assertTrue(elements.length == 3); - myMethod = (PsiMethod) elements[0]; - myTargetVariable = (PsiVariable) elements[1]; - myTargetClass = (PsiClass) elements[2]; - } - - protected String getCommandName() { - return RefactoringLocalize.moveInstanceMethodCommand().get(); - } - - public PsiClass getTargetClass() { - return myTargetClass; - } - - protected void performRefactoring(UsageInfo[] usages) { - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myTargetClass)) { - return; + if (myTargetClass.isInterface()) { + addInheritorUsages(myTargetClass, searchScope, usages); + } + + final PsiCodeBlock body = myMethod.getBody(); + if (body != null) { + body.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitNewExpression(PsiNewExpression expression) { + if (MoveInstanceMembersUtil.getClassReferencedByThis(expression) != null) { + usages.add(new InternalUsageInfo(expression)); + } + super.visitNewExpression(expression); + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + if (MoveInstanceMembersUtil.getClassReferencedByThis(expression) != null) { + usages.add(new InternalUsageInfo(expression)); + } + else if (!expression.isQualified()) { + final PsiElement resolved = expression.resolve(); + if (myTargetVariable.equals(resolved)) { + usages.add(new InternalUsageInfo(expression)); + } + } + + super.visitReferenceExpression(expression); + } + }); + } + + return usages.toArray(new UsageInfo[usages.size()]); } - PsiMethod patternMethod = createMethodToAdd(); - final List docRefs = new ArrayList(); - for (UsageInfo usage : usages) { - if (usage instanceof InheritorUsageInfo) { - final PsiClass inheritor = ((InheritorUsageInfo) usage).getInheritor(); - addMethodToClass(inheritor, patternMethod, true); - } else if (usage instanceof MethodCallUsageInfo && !((MethodCallUsageInfo) usage).isInternal()) { - final PsiElement expression = ((MethodCallUsageInfo) usage).getMethodCallExpression(); - if (expression instanceof PsiMethodCallExpression) { - correctMethodCall((PsiMethodCallExpression) expression, false); - } else if (expression instanceof PsiMethodReferenceExpression) { - PsiExpression newQualifier = JavaPsiFacade.getInstance(myProject).getElementFactory().createExpressionFromText(myTargetVariable.getType().getCanonicalText(), null); - ((PsiMethodReferenceExpression) expression).setQualifierExpression(newQualifier); + private static void addInheritorUsages(PsiClass aClass, final GlobalSearchScope searchScope, final List usages) { + for (PsiClass inheritor : ClassInheritorsSearch.search(aClass, searchScope, false).findAll()) { + if (!inheritor.isInterface()) { + usages.add(new InheritorUsageInfo(inheritor)); + } + else { + addInheritorUsages(inheritor, searchScope, usages); + } } - } else if (usage instanceof JavadocUsageInfo) { - docRefs.add(usage.getElement().getReference()); - } } - try { - if (myTargetClass.isInterface()) { - patternMethod.getBody().delete(); - } - - final PsiMethod method = addMethodToClass(myTargetClass, patternMethod, false); - myMethod.delete(); - for (PsiReference reference : docRefs) { - reference.bindToElement(method); - } - VisibilityUtil.fixVisibility(UsageViewUtil.toElements(usages), method, myNewVisibility); - } catch (IncorrectOperationException e) { - LOG.error(e); + protected void refreshElements(PsiElement[] elements) { + LOG.assertTrue(elements.length == 3); + myMethod = (PsiMethod)elements[0]; + myTargetVariable = (PsiVariable)elements[1]; + myTargetClass = (PsiClass)elements[2]; } - } - - private void correctMethodCall(final PsiMethodCallExpression expression, final boolean isInternalCall) { - try { - final PsiManager manager = myMethod.getManager(); - PsiReferenceExpression methodExpression = expression.getMethodExpression(); - if (!methodExpression.isReferenceTo(myMethod)) { - return; - } - final PsiExpression oldQualifier = methodExpression.getQualifierExpression(); - PsiExpression newQualifier = null; - final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(methodExpression); - if (myTargetVariable instanceof PsiParameter) { - final int index = myMethod.getParameterList().getParameterIndex((PsiParameter) myTargetVariable); - final PsiExpression[] arguments = expression.getArgumentList().getExpressions(); - if (index < arguments.length) { - newQualifier = (PsiExpression) arguments[index].copy(); - arguments[index].delete(); - } - } else { - VisibilityUtil.escalateVisibility((PsiField) myTargetVariable, expression); - String newQualifierName = myTargetVariable.getName(); - if (myTargetVariable instanceof PsiField && oldQualifier != null) { - final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(oldQualifier.getType()); - if (aClass == ((PsiField) myTargetVariable).getContainingClass()) { - newQualifierName = oldQualifier.getText() + "." + newQualifierName; - } - } - newQualifier = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createExpressionFromText(newQualifierName, null); - } - - PsiExpression newArgument = null; - - if (classReferencedByThis != null) { - @NonNls String thisArgumentText = null; - if (manager.areElementsEquivalent(myMethod.getContainingClass(), classReferencedByThis)) { - if (myOldClassParameterNames.containsKey(myMethod.getContainingClass())) { - thisArgumentText = "this"; - } - } else { - thisArgumentText = classReferencedByThis.getName() + ".this"; - } - if (thisArgumentText != null) { - newArgument = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createExpressionFromText(thisArgumentText, null); + protected String getCommandName() { + return RefactoringLocalize.moveInstanceMethodCommand().get(); + } + + public PsiClass getTargetClass() { + return myTargetClass; + } + + protected void performRefactoring(UsageInfo[] usages) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myTargetClass)) { + return; } - } else { - if (!isInternalCall && oldQualifier != null) { - final PsiType type = oldQualifier.getType(); - if (type instanceof PsiClassType) { - final PsiClass resolved = ((PsiClassType) type).resolve(); - if (resolved != null && getParameterNameToCreate(resolved) != null) { - newArgument = replaceRefsToTargetVariable(oldQualifier); //replace is needed in case old qualifier is e.g. the same as field as target variable + + PsiMethod patternMethod = createMethodToAdd(); + final List docRefs = new ArrayList(); + for (UsageInfo usage : usages) { + if (usage instanceof InheritorUsageInfo) { + final PsiClass inheritor = ((InheritorUsageInfo)usage).getInheritor(); + addMethodToClass(inheritor, patternMethod, true); + } + else if (usage instanceof MethodCallUsageInfo && !((MethodCallUsageInfo)usage).isInternal()) { + final PsiElement expression = ((MethodCallUsageInfo)usage).getMethodCallExpression(); + if (expression instanceof PsiMethodCallExpression) { + correctMethodCall((PsiMethodCallExpression)expression, false); + } + else if (expression instanceof PsiMethodReferenceExpression) { + PsiExpression newQualifier = JavaPsiFacade.getInstance(myProject) + .getElementFactory() + .createExpressionFromText(myTargetVariable.getType().getCanonicalText(), null); + ((PsiMethodReferenceExpression)expression).setQualifierExpression(newQualifier); + } + } + else if (usage instanceof JavadocUsageInfo) { + docRefs.add(usage.getElement().getReference()); } - } - } - } - - - if (newArgument != null) { - expression.getArgumentList().add(newArgument); - } - - if (newQualifier != null) { - if (newQualifier instanceof PsiThisExpression && ((PsiThisExpression) newQualifier).getQualifier() == null) { - //Remove now redundant 'this' qualifier - if (oldQualifier != null) { - oldQualifier.delete(); - } - } else { - final PsiReferenceExpression refExpr = (PsiReferenceExpression) JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createExpressionFromText("q." + myMethod - .getName(), null); - refExpr.getQualifierExpression().replace(newQualifier); - methodExpression.replace(refExpr); } - } - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - private PsiExpression replaceRefsToTargetVariable(final PsiExpression expression) { - final PsiManager manager = expression.getManager(); - if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression) expression).isReferenceTo(myTargetVariable)) { - return createThisExpr(manager); - } + try { + if (myTargetClass.isInterface()) { + patternMethod.getBody().delete(); + } - expression.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - if (expression.isReferenceTo(myTargetVariable)) { - try { - expression.replace(createThisExpr(manager)); - } catch (IncorrectOperationException e) { + final PsiMethod method = addMethodToClass(myTargetClass, patternMethod, false); + myMethod.delete(); + for (PsiReference reference : docRefs) { + reference.bindToElement(method); + } + VisibilityUtil.fixVisibility(UsageViewUtil.toElements(usages), method, myNewVisibility); + } + catch (IncorrectOperationException e) { LOG.error(e); - } } - } - }); - - return expression; - } - - private static PsiExpression createThisExpr(final PsiManager manager) { - try { - return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createExpressionFromText("this", null); - } catch (IncorrectOperationException e) { - LOG.error(e); - return null; - } - } - - private static PsiMethod addMethodToClass(final PsiClass aClass, final PsiMethod patternMethod, boolean canAddOverride) { - try { - final PsiMethod method = (PsiMethod) aClass.add(patternMethod); - ChangeContextUtil.decodeContextInfo(method, null, null); - if (canAddOverride && OverrideImplementUtil.isInsertOverride(method, aClass)) { - method.getModifierList().addAnnotation(CommonClassNames.JAVA_LANG_OVERRIDE); - } - return method; - } catch (IncorrectOperationException e) { - LOG.error(e); } - return null; - } - - private PsiMethod createMethodToAdd() { - ChangeContextUtil.encodeContextInfo(myMethod, true); - try { - final PsiManager manager = myMethod.getManager(); - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - - //correct internal references - final PsiCodeBlock body = myMethod.getBody(); - if (body != null) { - final Map replaceMap = new HashMap(); - body.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitThisExpression(PsiThisExpression expression) { - final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); - if (classReferencedByThis != null && !PsiTreeUtil.isAncestor(myMethod, classReferencedByThis, false)) { - final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); - String paramName = getParameterNameToCreate(classReferencedByThis); - try { - final PsiExpression refExpression = factory.createExpressionFromText(paramName, null); - replaceMap.put(expression, refExpression); - } catch (IncorrectOperationException e) { - LOG.error(e); - } + private void correctMethodCall(final PsiMethodCallExpression expression, final boolean isInternalCall) { + try { + final PsiManager manager = myMethod.getManager(); + PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (!methodExpression.isReferenceTo(myMethod)) { + return; } - } - - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - try { - final PsiExpression qualifier = expression.getQualifierExpression(); - final PsiElement resolved = expression.resolve(); - if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression) qualifier).isReferenceTo(myTargetVariable)) { - if (resolved instanceof PsiField) { - for (PsiParameter parameter : myMethod.getParameterList().getParameters()) { - if (Comparing.strEqual(parameter.getName(), ((PsiField) resolved).getName())) { - qualifier.replace(factory.createExpressionFromText("this", null)); - return; + final PsiExpression oldQualifier = methodExpression.getQualifierExpression(); + PsiExpression newQualifier = null; + final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(methodExpression); + if (myTargetVariable instanceof PsiParameter) { + final int index = myMethod.getParameterList().getParameterIndex((PsiParameter)myTargetVariable); + final PsiExpression[] arguments = expression.getArgumentList().getExpressions(); + if (index < arguments.length) { + newQualifier = (PsiExpression)arguments[index].copy(); + arguments[index].delete(); + } + } + else { + VisibilityUtil.escalateVisibility((PsiField)myTargetVariable, expression); + String newQualifierName = myTargetVariable.getName(); + if (myTargetVariable instanceof PsiField && oldQualifier != null) { + final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(oldQualifier.getType()); + if (aClass == ((PsiField)myTargetVariable).getContainingClass()) { + newQualifierName = oldQualifier.getText() + "." + newQualifierName; } - } } - //Target is a field, replace target.m -> m - qualifier.delete(); - return; - } - if (myTargetVariable.equals(resolved)) { - PsiThisExpression thisExpression = RefactoringChangeUtil.createThisExpression(manager, PsiTreeUtil.isAncestor(myMethod, PsiTreeUtil.getParentOfType(expression, - PsiClass.class), true) ? myTargetClass : null); - replaceMap.put(expression, thisExpression); - return; - } else if (myMethod.equals(resolved)) { - } else { - PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); - if (classReferencedByThis != null) { - final String paramName = getParameterNameToCreate(classReferencedByThis); - if (paramName != null) { - PsiReferenceExpression newQualifier = (PsiReferenceExpression) factory.createExpressionFromText(paramName, null); - expression.setQualifierExpression(newQualifier); - return; - } + newQualifier = + JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createExpressionFromText(newQualifierName, null); + } + + PsiExpression newArgument = null; + + if (classReferencedByThis != null) { + @NonNls String thisArgumentText = null; + if (manager.areElementsEquivalent(myMethod.getContainingClass(), classReferencedByThis)) { + if (myOldClassParameterNames.containsKey(myMethod.getContainingClass())) { + thisArgumentText = "this"; + } + } + else { + thisArgumentText = classReferencedByThis.getName() + ".this"; + } + + if (thisArgumentText != null) { + newArgument = JavaPsiFacade.getInstance(manager.getProject()) + .getElementFactory() + .createExpressionFromText(thisArgumentText, null); } - } - super.visitReferenceExpression(expression); - } catch (IncorrectOperationException e) { - LOG.error(e); } - } - - @Override - public void visitNewExpression(PsiNewExpression expression) { - try { - final PsiExpression qualifier = expression.getQualifier(); - if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression) qualifier).isReferenceTo(myTargetVariable)) { - //Target is a field, replace target.new A() -> new A() - qualifier.delete(); - } else { - final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); - if (classReferencedByThis != null) { - if (qualifier != null) { - qualifier.delete(); - } - final String paramName = getParameterNameToCreate(classReferencedByThis); - final PsiExpression newExpression = factory.createExpressionFromText(paramName + "." + expression.getText(), null); - replaceMap.put(expression, newExpression); + else { + if (!isInternalCall && oldQualifier != null) { + final PsiType type = oldQualifier.getType(); + if (type instanceof PsiClassType) { + final PsiClass resolved = ((PsiClassType)type).resolve(); + if (resolved != null && getParameterNameToCreate(resolved) != null) { + newArgument = + replaceRefsToTargetVariable(oldQualifier); //replace is needed in case old qualifier is e.g. the same as field as target variable + } + } } - } - super.visitNewExpression(expression); - } catch (IncorrectOperationException e) { - LOG.error(e); } - } - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - correctMethodCall(expression, true); - super.visitMethodCallExpression(expression); - } + + if (newArgument != null) { + expression.getArgumentList().add(newArgument); + } + + if (newQualifier != null) { + if (newQualifier instanceof PsiThisExpression && ((PsiThisExpression)newQualifier).getQualifier() == null) { + //Remove now redundant 'this' qualifier + if (oldQualifier != null) { + oldQualifier.delete(); + } + } + else { + final PsiReferenceExpression refExpr = (PsiReferenceExpression)JavaPsiFacade.getInstance(manager.getProject()) + .getElementFactory() + .createExpressionFromText("q." + myMethod + .getName(), null); + refExpr.getQualifierExpression().replace(newQualifier); + methodExpression.replace(refExpr); + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + private PsiExpression replaceRefsToTargetVariable(final PsiExpression expression) { + final PsiManager manager = expression.getManager(); + if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).isReferenceTo(myTargetVariable)) { + return createThisExpr(manager); + } + + expression.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (expression.isReferenceTo(myTargetVariable)) { + try { + expression.replace(createThisExpr(manager)); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } }); - for (PsiElement element : replaceMap.keySet()) { - final PsiElement replacement = replaceMap.get(element); - element.replace(replacement); + + return expression; + } + + private static PsiExpression createThisExpr(final PsiManager manager) { + try { + return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createExpressionFromText("this", null); } - } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; + } + } - final PsiMethod methodCopy = getPatternMethod(); + private static PsiMethod addMethodToClass(final PsiClass aClass, final PsiMethod patternMethod, boolean canAddOverride) { + try { + final PsiMethod method = (PsiMethod)aClass.add(patternMethod); + ChangeContextUtil.decodeContextInfo(method, null, null); + if (canAddOverride && OverrideImplementUtil.isInsertOverride(method, aClass)) { + method.getModifierList().addAnnotation(CommonClassNames.JAVA_LANG_OVERRIDE); + } + return method; + } + catch (IncorrectOperationException e) { + LOG.error(e); + } - final List newParameters = Arrays.asList(methodCopy.getParameterList().getParameters()); - RefactoringUtil.fixJavadocsForParams(methodCopy, new HashSet(newParameters)); - return methodCopy; - } catch (IncorrectOperationException e) { - LOG.error(e); - return myMethod; + return null; } - } - private PsiMethod getPatternMethod() throws IncorrectOperationException { - final PsiMethod methodCopy = (PsiMethod) myMethod.copy(); - String name = myTargetClass.isInterface() ? PsiModifier.PUBLIC : !Comparing.strEqual(myNewVisibility, VisibilityUtil.ESCALATE_VISIBILITY) ? myNewVisibility : null; - if (name != null) { - PsiUtil.setModifierProperty(methodCopy, name, true); + private PsiMethod createMethodToAdd() { + ChangeContextUtil.encodeContextInfo(myMethod, true); + try { + final PsiManager manager = myMethod.getManager(); + final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + + //correct internal references + final PsiCodeBlock body = myMethod.getBody(); + if (body != null) { + final Map replaceMap = new HashMap(); + body.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitThisExpression(PsiThisExpression expression) { + final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); + if (classReferencedByThis != null && !PsiTreeUtil.isAncestor(myMethod, classReferencedByThis, false)) { + final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); + String paramName = getParameterNameToCreate(classReferencedByThis); + try { + final PsiExpression refExpression = factory.createExpressionFromText(paramName, null); + replaceMap.put(expression, refExpression); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + try { + final PsiExpression qualifier = expression.getQualifierExpression(); + final PsiElement resolved = expression.resolve(); + if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifier).isReferenceTo( + myTargetVariable)) { + if (resolved instanceof PsiField) { + for (PsiParameter parameter : myMethod.getParameterList().getParameters()) { + if (Comparing.strEqual(parameter.getName(), ((PsiField)resolved).getName())) { + qualifier.replace(factory.createExpressionFromText("this", null)); + return; + } + } + } + //Target is a field, replace target.m -> m + qualifier.delete(); + return; + } + if (myTargetVariable.equals(resolved)) { + PsiThisExpression thisExpression = RefactoringChangeUtil.createThisExpression( + manager, + PsiTreeUtil.isAncestor(myMethod, PsiTreeUtil.getParentOfType( + expression, + PsiClass.class + ), true) ? myTargetClass : null + ); + replaceMap.put(expression, thisExpression); + return; + } + else if (myMethod.equals(resolved)) { + } + else { + PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); + if (classReferencedByThis != null) { + final String paramName = getParameterNameToCreate(classReferencedByThis); + if (paramName != null) { + PsiReferenceExpression newQualifier = + (PsiReferenceExpression)factory.createExpressionFromText(paramName, null); + expression.setQualifierExpression(newQualifier); + return; + } + } + } + super.visitReferenceExpression(expression); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + @Override + public void visitNewExpression(PsiNewExpression expression) { + try { + final PsiExpression qualifier = expression.getQualifier(); + if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifier).isReferenceTo( + myTargetVariable)) { + //Target is a field, replace target.new A() -> new A() + qualifier.delete(); + } + else { + final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); + if (classReferencedByThis != null) { + if (qualifier != null) { + qualifier.delete(); + } + final String paramName = getParameterNameToCreate(classReferencedByThis); + final PsiExpression newExpression = + factory.createExpressionFromText(paramName + "." + expression.getText(), null); + replaceMap.put(expression, newExpression); + } + } + super.visitNewExpression(expression); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + correctMethodCall(expression, true); + super.visitMethodCallExpression(expression); + } + }); + for (PsiElement element : replaceMap.keySet()) { + final PsiElement replacement = replaceMap.get(element); + element.replace(replacement); + } + } + + final PsiMethod methodCopy = getPatternMethod(); + + final List newParameters = Arrays.asList(methodCopy.getParameterList().getParameters()); + RefactoringUtil.fixJavadocsForParams(methodCopy, new HashSet(newParameters)); + return methodCopy; + } + catch (IncorrectOperationException e) { + LOG.error(e); + return myMethod; + } } - if (myTargetVariable instanceof PsiParameter) { - final int index = myMethod.getParameterList().getParameterIndex((PsiParameter) myTargetVariable); - methodCopy.getParameterList().getParameters()[index].delete(); + + private PsiMethod getPatternMethod() throws IncorrectOperationException { + final PsiMethod methodCopy = (PsiMethod)myMethod.copy(); + String name = myTargetClass.isInterface() ? PsiModifier.PUBLIC : !Comparing.strEqual( + myNewVisibility, + VisibilityUtil.ESCALATE_VISIBILITY + ) ? myNewVisibility : null; + if (name != null) { + PsiUtil.setModifierProperty(methodCopy, name, true); + } + if (myTargetVariable instanceof PsiParameter) { + final int index = myMethod.getParameterList().getParameterIndex((PsiParameter)myTargetVariable); + methodCopy.getParameterList().getParameters()[index].delete(); + } + + addParameters(JavaPsiFacade.getInstance(myProject).getElementFactory(), methodCopy, myTargetClass.isInterface()); + return methodCopy; } - addParameters(JavaPsiFacade.getInstance(myProject).getElementFactory(), methodCopy, myTargetClass.isInterface()); - return methodCopy; - } - - private void addParameters(final PsiElementFactory factory, final PsiMethod methodCopy, final boolean isInterface) throws IncorrectOperationException { - final Set> entries = myOldClassParameterNames.entrySet(); - for (final Map.Entry entry : entries) { - final PsiClassType type = factory.createType(entry.getKey()); - final PsiParameter parameter = factory.createParameter(entry.getValue(), type); - if (isInterface) { - PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, false); - } - methodCopy.getParameterList().add(parameter); + private void addParameters( + final PsiElementFactory factory, + final PsiMethod methodCopy, + final boolean isInterface + ) throws IncorrectOperationException { + final Set> entries = myOldClassParameterNames.entrySet(); + for (final Map.Entry entry : entries) { + final PsiClassType type = factory.createType(entry.getKey()); + final PsiParameter parameter = factory.createParameter(entry.getValue(), type); + if (isInterface) { + PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, false); + } + methodCopy.getParameterList().add(parameter); + } } - } - private String getParameterNameToCreate(@Nonnull PsiClass aClass) { - return myOldClassParameterNames.get(aClass); - } + private String getParameterNameToCreate(@Nonnull PsiClass aClass) { + return myOldClassParameterNames.get(aClass); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersProcessor.java index 9172de56be..d2436786a2 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveMembers/MoveMembersProcessor.java @@ -20,7 +20,6 @@ import com.intellij.java.language.psi.*; import com.intellij.java.language.util.VisibilityUtil; import consulo.language.editor.refactoring.BaseRefactoringProcessor; -import consulo.language.editor.refactoring.RefactoringBundle; import consulo.language.editor.refactoring.event.RefactoringElementListener; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.move.MoveCallback; @@ -43,348 +42,380 @@ import consulo.usage.UsageViewUtil; import consulo.util.collection.ContainerUtil; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; - +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.util.*; /** - * created at Sep 11, 2001 - * * @author Jeka + * @since 2001-09-11 */ public class MoveMembersProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(MoveMembersProcessor.class); - - private PsiClass myTargetClass; - private final Set myMembersToMove = new LinkedHashSet(); - private final MoveCallback myMoveCallback; - private final boolean myOpenInEditor; - private String myNewVisibility; // "null" means "as is" - private String myCommandName = MoveMembersImpl.REFACTORING_NAME; - private MoveMembersOptions myOptions; - - public MoveMembersProcessor(Project project, MoveMembersOptions options) { - this(project, null, options); - } - - public MoveMembersProcessor(Project project, @Nullable MoveCallback moveCallback, MoveMembersOptions options) { - this(project, moveCallback, options, false); - } - - public MoveMembersProcessor(Project project, @Nullable MoveCallback moveCallback, MoveMembersOptions options, boolean openInEditor) { - super(project); - myMoveCallback = moveCallback; - myOpenInEditor = openInEditor; - setOptions(options); - } - - protected String getCommandName() { - return myCommandName; - } - - private void setOptions(MoveMembersOptions dialog) { - myOptions = dialog; - - PsiMember[] members = dialog.getSelectedMembers(); - myMembersToMove.clear(); - ContainerUtil.addAll(myMembersToMove, members); - - setCommandName(members); - - final String targetClassName = dialog.getTargetClassName(); - myTargetClass = JavaPsiFacade.getInstance(myProject).findClass(targetClassName, GlobalSearchScope.projectScope(myProject)); - LOG.assertTrue(myTargetClass != null, "target class: " + targetClassName); - myNewVisibility = dialog.getMemberVisibility(); - } - - private void setCommandName(final PsiMember[] members) { - StringBuilder commandName = new StringBuilder(); - commandName.append(MoveHandler.REFACTORING_NAME); - commandName.append(" "); - boolean first = true; - for (PsiMember member : members) { - if (!first) { - commandName.append(", "); - } - commandName.append(UsageViewUtil.getType(member)); - commandName.append(' '); - commandName.append(UsageViewUtil.getShortName(member)); - first = false; + private static final Logger LOG = Logger.getInstance(MoveMembersProcessor.class); + + private PsiClass myTargetClass; + private final Set myMembersToMove = new LinkedHashSet(); + private final MoveCallback myMoveCallback; + private final boolean myOpenInEditor; + private String myNewVisibility; // "null" means "as is" + private String myCommandName = MoveMembersImpl.REFACTORING_NAME; + private MoveMembersOptions myOptions; + + public MoveMembersProcessor(Project project, MoveMembersOptions options) { + this(project, null, options); } - myCommandName = commandName.toString(); - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { - return new MoveMemberViewDescriptor(PsiUtilCore.toPsiElementArray(myMembersToMove)); - } - - @Nonnull - protected UsageInfo[] findUsages() { - final List usagesList = new ArrayList(); - for (PsiMember member : myMembersToMove) { - for (PsiReference psiReference : ReferencesSearch.search(member)) { - PsiElement ref = psiReference.getElement(); - final MoveMemberHandler handler = MoveMemberHandler.forLanguage(ref.getLanguage()); - MoveMembersUsageInfo usage = null; - if (handler != null && myTargetClass != null) { - usage = handler.getUsage(member, psiReference, myMembersToMove, myTargetClass); - } - if (usage != null) { - usagesList.add(usage); - } else { - if (!isInMovedElement(ref)) { - usagesList.add(new MoveMembersUsageInfo(member, ref, null, ref, psiReference)); - } - } - } + public MoveMembersProcessor(Project project, @Nullable MoveCallback moveCallback, MoveMembersOptions options) { + this(project, moveCallback, options, false); } - UsageInfo[] usageInfos = usagesList.toArray(new UsageInfo[usagesList.size()]); - usageInfos = UsageViewUtil.removeDuplicatedUsages(usageInfos); - return usageInfos; - } - - protected void refreshElements(@Nonnull PsiElement[] elements) { - LOG.assertTrue(myMembersToMove.size() == elements.length); - myMembersToMove.clear(); - for (PsiElement resolved : elements) { - myMembersToMove.add((PsiMember) resolved); + + public MoveMembersProcessor(Project project, @Nullable MoveCallback moveCallback, MoveMembersOptions options, boolean openInEditor) { + super(project); + myMoveCallback = moveCallback; + myOpenInEditor = openInEditor; + setOptions(options); } - } - private boolean isInMovedElement(PsiElement element) { - for (PsiMember member : myMembersToMove) { - if (PsiTreeUtil.isAncestor(member, element, false)) { - return true; - } + protected String getCommandName() { + return myCommandName; } - return false; - } - - protected void performRefactoring(@Nonnull final UsageInfo[] usages) { - try { - PsiClass targetClass = JavaPsiFacade.getInstance(myProject).findClass(myOptions.getTargetClassName(), GlobalSearchScope.projectScope(myProject)); - if (targetClass == null) { - return; - } - - // collect anchors to place moved members at - final Map> anchors = new HashMap>(); - final Map anchorsInSourceClass = new HashMap(); - for (PsiMember member : myMembersToMove) { - final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); - if (handler != null) { - final PsiElement anchor = handler.getAnchor(member, targetClass, myMembersToMove); - if (anchor instanceof PsiMember && myMembersToMove.contains((PsiMember) anchor)) { - anchorsInSourceClass.put(member, (PsiMember) anchor); - } else { - anchors.put(member, anchor == null ? null : SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(anchor)); - } + + private void setOptions(MoveMembersOptions dialog) { + myOptions = dialog; + + PsiMember[] members = dialog.getSelectedMembers(); + myMembersToMove.clear(); + ContainerUtil.addAll(myMembersToMove, members); + + setCommandName(members); + + final String targetClassName = dialog.getTargetClassName(); + myTargetClass = JavaPsiFacade.getInstance(myProject).findClass(targetClassName, GlobalSearchScope.projectScope(myProject)); + LOG.assertTrue(myTargetClass != null, "target class: " + targetClassName); + myNewVisibility = dialog.getMemberVisibility(); + } + + private void setCommandName(final PsiMember[] members) { + StringBuilder commandName = new StringBuilder(); + commandName.append(MoveHandler.REFACTORING_NAME); + commandName.append(" "); + boolean first = true; + for (PsiMember member : members) { + if (!first) { + commandName.append(", "); + } + commandName.append(UsageViewUtil.getType(member)); + commandName.append(' '); + commandName.append(UsageViewUtil.getShortName(member)); + first = false; } - } - - // correct references to moved members from the outside - ArrayList otherUsages = new ArrayList(); - for (UsageInfo usageInfo : usages) { - MoveMembersUsageInfo usage = (MoveMembersUsageInfo) usageInfo; - if (!usage.reference.isValid()) { - continue; + + myCommandName = commandName.toString(); + } + + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { + return new MoveMemberViewDescriptor(PsiUtilCore.toPsiElementArray(myMembersToMove)); + } + + @Nonnull + protected UsageInfo[] findUsages() { + final List usagesList = new ArrayList(); + for (PsiMember member : myMembersToMove) { + for (PsiReference psiReference : ReferencesSearch.search(member)) { + PsiElement ref = psiReference.getElement(); + final MoveMemberHandler handler = MoveMemberHandler.forLanguage(ref.getLanguage()); + MoveMembersUsageInfo usage = null; + if (handler != null && myTargetClass != null) { + usage = handler.getUsage(member, psiReference, myMembersToMove, myTargetClass); + } + if (usage != null) { + usagesList.add(usage); + } + else if (!isInMovedElement(ref)) { + usagesList.add(new MoveMembersUsageInfo(member, ref, null, ref, psiReference)); + } + } } - final MoveMemberHandler handler = MoveMemberHandler.forLanguage(usageInfo.getElement().getLanguage()); - if (handler != null) { - if (handler.changeExternalUsage(myOptions, usage)) { - continue; - } + UsageInfo[] usageInfos = usagesList.toArray(new UsageInfo[usagesList.size()]); + usageInfos = UsageViewUtil.removeDuplicatedUsages(usageInfos); + return usageInfos; + } + + protected void refreshElements(@Nonnull PsiElement[] elements) { + LOG.assertTrue(myMembersToMove.size() == elements.length); + myMembersToMove.clear(); + for (PsiElement resolved : elements) { + myMembersToMove.add((PsiMember)resolved); } - otherUsages.add(usage); - } - - // correct references inside moved members and outer references to Inner Classes - final Map movedMembers = new HashMap(); - for (PsiMember member : myMembersToMove) { - ArrayList refsToBeRebind = new ArrayList(); - for (Iterator iterator = otherUsages.iterator(); iterator.hasNext(); ) { - MoveMembersUsageInfo info = iterator.next(); - if (member.equals(info.member)) { - PsiReference ref = info.getReference(); - if (ref != null) { - refsToBeRebind.add(ref); + } + + private boolean isInMovedElement(PsiElement element) { + for (PsiMember member : myMembersToMove) { + if (PsiTreeUtil.isAncestor(member, element, false)) { + return true; } - iterator.remove(); - } } - final RefactoringElementListener elementListener = getTransaction().getElementListener(member); - final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); - if (handler != null) { - - final PsiElement anchor; - if (anchorsInSourceClass.containsKey(member)) { - final PsiMember memberInSourceClass = anchorsInSourceClass.get(member); - //anchor should be already moved as myMembersToMove contains members in order they appear in source class - anchor = memberInSourceClass != null ? movedMembers.get(memberInSourceClass) : null; - } else { - final SmartPsiElementPointer pointer = anchors.get(member); - anchor = pointer != null ? pointer.getElement() : null; - } - - PsiMember newMember = handler.doMove(myOptions, member, anchor, targetClass); - - movedMembers.put(member, newMember); - elementListener.elementMoved(newMember); - - fixModifierList(member, newMember, usages); - for (PsiReference reference : refsToBeRebind) { - reference.bindToElement(newMember); - } + return false; + } + + protected void performRefactoring(@Nonnull final UsageInfo[] usages) { + try { + PsiClass targetClass = + JavaPsiFacade.getInstance(myProject).findClass(myOptions.getTargetClassName(), GlobalSearchScope.projectScope(myProject)); + if (targetClass == null) { + return; + } + + // collect anchors to place moved members at + final Map> anchors = new HashMap>(); + final Map anchorsInSourceClass = new HashMap(); + for (PsiMember member : myMembersToMove) { + final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); + if (handler != null) { + final PsiElement anchor = handler.getAnchor(member, targetClass, myMembersToMove); + if (anchor instanceof PsiMember && myMembersToMove.contains((PsiMember)anchor)) { + anchorsInSourceClass.put(member, (PsiMember)anchor); + } + else { + anchors.put( + member, + anchor == null ? null : SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(anchor) + ); + } + } + } + + // correct references to moved members from the outside + ArrayList otherUsages = new ArrayList(); + for (UsageInfo usageInfo : usages) { + MoveMembersUsageInfo usage = (MoveMembersUsageInfo)usageInfo; + if (!usage.reference.isValid()) { + continue; + } + final MoveMemberHandler handler = MoveMemberHandler.forLanguage(usageInfo.getElement().getLanguage()); + if (handler != null) { + if (handler.changeExternalUsage(myOptions, usage)) { + continue; + } + } + otherUsages.add(usage); + } + + // correct references inside moved members and outer references to Inner Classes + final Map movedMembers = new HashMap(); + for (PsiMember member : myMembersToMove) { + ArrayList refsToBeRebind = new ArrayList(); + for (Iterator iterator = otherUsages.iterator(); iterator.hasNext(); ) { + MoveMembersUsageInfo info = iterator.next(); + if (member.equals(info.member)) { + PsiReference ref = info.getReference(); + if (ref != null) { + refsToBeRebind.add(ref); + } + iterator.remove(); + } + } + final RefactoringElementListener elementListener = getTransaction().getElementListener(member); + final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); + if (handler != null) { + + final PsiElement anchor; + if (anchorsInSourceClass.containsKey(member)) { + final PsiMember memberInSourceClass = anchorsInSourceClass.get(member); + //anchor should be already moved as myMembersToMove contains members in order they appear in source class + anchor = memberInSourceClass != null ? movedMembers.get(memberInSourceClass) : null; + } + else { + final SmartPsiElementPointer pointer = anchors.get(member); + anchor = pointer != null ? pointer.getElement() : null; + } + + PsiMember newMember = handler.doMove(myOptions, member, anchor, targetClass); + + movedMembers.put(member, newMember); + elementListener.elementMoved(newMember); + + fixModifierList(member, newMember, usages); + for (PsiReference reference : refsToBeRebind) { + reference.bindToElement(newMember); + } + } + } + + // qualifier info must be decoded after members are moved + final MoveMemberHandler handler = MoveMemberHandler.forLanguage(myTargetClass.getLanguage()); + if (handler != null) { + handler.decodeContextInfo(myTargetClass); + } + + myMembersToMove.clear(); + if (myMoveCallback != null) { + myMoveCallback.refactoringCompleted(); + } + + if (myOpenInEditor && !movedMembers.isEmpty()) { + final PsiMember item = ContainerUtil.getFirstItem(movedMembers.values()); + if (item != null) { + EditorHelper.openInEditor(item); + } + } } - } - - // qualifier info must be decoded after members are moved - final MoveMemberHandler handler = MoveMemberHandler.forLanguage(myTargetClass.getLanguage()); - if (handler != null) { - handler.decodeContextInfo(myTargetClass); - } - - myMembersToMove.clear(); - if (myMoveCallback != null) { - myMoveCallback.refactoringCompleted(); - } - - if (myOpenInEditor && !movedMembers.isEmpty()) { - final PsiMember item = ContainerUtil.getFirstItem(movedMembers.values()); - if (item != null) { - EditorHelper.openInEditor(item); + catch (IncorrectOperationException e) { + LOG.error(e); } - } - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - private void fixModifierList(PsiMember member, PsiMember newMember, final UsageInfo[] usages) throws IncorrectOperationException { - PsiModifierList modifierList = newMember.getModifierList(); - - if (modifierList != null && myTargetClass.isInterface()) { - modifierList.setModifierProperty(PsiModifier.PUBLIC, false); - modifierList.setModifierProperty(PsiModifier.PROTECTED, false); - modifierList.setModifierProperty(PsiModifier.PRIVATE, false); - if (newMember instanceof PsiClass) { - modifierList.setModifierProperty(PsiModifier.STATIC, false); - } - return; } - if (myNewVisibility == null) { - return; - } + private void fixModifierList(PsiMember member, PsiMember newMember, final UsageInfo[] usages) throws IncorrectOperationException { + PsiModifierList modifierList = newMember.getModifierList(); - final List filtered = new ArrayList(); - for (UsageInfo usage : usages) { - if (usage instanceof MoveMembersUsageInfo && member == ((MoveMembersUsageInfo) usage).member) { - filtered.add(usage); - } - } - UsageInfo[] infos = filtered.toArray(new UsageInfo[filtered.size()]); - VisibilityUtil.fixVisibility(UsageViewUtil.toElements(infos), newMember, myNewVisibility); - } + if (modifierList != null && myTargetClass.isInterface()) { + modifierList.setModifierProperty(PsiModifier.PUBLIC, false); + modifierList.setModifierProperty(PsiModifier.PROTECTED, false); + modifierList.setModifierProperty(PsiModifier.PRIVATE, false); + if (newMember instanceof PsiClass) { + modifierList.setModifierProperty(PsiModifier.STATIC, false); + } + return; + } - protected boolean preprocessUsages(@Nonnull Ref refUsages) { - final MultiMap conflicts = new MultiMap(); - final UsageInfo[] usages = refUsages.get(); + if (myNewVisibility == null) { + return; + } - String newVisibility = myNewVisibility; - if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { // still need to check for access object - newVisibility = PsiModifier.PUBLIC; + final List filtered = new ArrayList(); + for (UsageInfo usage : usages) { + if (usage instanceof MoveMembersUsageInfo && member == ((MoveMembersUsageInfo)usage).member) { + filtered.add(usage); + } + } + UsageInfo[] infos = filtered.toArray(new UsageInfo[filtered.size()]); + VisibilityUtil.fixVisibility(UsageViewUtil.toElements(infos), newMember, myNewVisibility); } - final Map modifierListCopies = new HashMap(); - for (PsiMember member : myMembersToMove) { - PsiModifierList modifierListCopy = member.getModifierList(); - if (modifierListCopy != null) { - modifierListCopy = (PsiModifierList) modifierListCopy.copy(); - } - if (modifierListCopy != null && newVisibility != null) { - try { - VisibilityUtil.setVisibility(modifierListCopy, newVisibility); - } catch (IncorrectOperationException e) { - LOG.error(e); + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + final MultiMap conflicts = new MultiMap(); + final UsageInfo[] usages = refUsages.get(); + + String newVisibility = myNewVisibility; + if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { // still need to check for access object + newVisibility = PsiModifier.PUBLIC; } - } - modifierListCopies.put(member, modifierListCopy); - } - analyzeConflictsOnUsages(usages, myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts); - analyzeConflictsOnMembers(myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts); - - RefactoringConflictsUtil.analyzeModuleConflicts(myProject, myMembersToMove, usages, myTargetClass, conflicts); - - return showConflicts(conflicts, usages); - } - - private static void analyzeConflictsOnUsages(UsageInfo[] usages, - Set membersToMove, - String newVisibility, - @Nonnull PsiClass targetClass, - Map modifierListCopies, - MultiMap conflicts) { - for (UsageInfo usage : usages) { - if (!(usage instanceof MoveMembersUsageInfo)) { - continue; - } - final MoveMembersUsageInfo usageInfo = (MoveMembersUsageInfo) usage; - final PsiMember member = usageInfo.member; - final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); - if (handler != null) { - handler.checkConflictsOnUsage(usageInfo, newVisibility, modifierListCopies.get(member), targetClass, membersToMove, conflicts); - } + final Map modifierListCopies = new HashMap(); + for (PsiMember member : myMembersToMove) { + PsiModifierList modifierListCopy = member.getModifierList(); + if (modifierListCopy != null) { + modifierListCopy = (PsiModifierList)modifierListCopy.copy(); + } + if (modifierListCopy != null && newVisibility != null) { + try { + VisibilityUtil.setVisibility(modifierListCopy, newVisibility); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + modifierListCopies.put(member, modifierListCopy); + } + + analyzeConflictsOnUsages(usages, myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts); + analyzeConflictsOnMembers(myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts); + + RefactoringConflictsUtil.analyzeModuleConflicts(myProject, myMembersToMove, usages, myTargetClass, conflicts); + + return showConflicts(conflicts, usages); } - } - - private static void analyzeConflictsOnMembers(Set membersToMove, - String newVisibility, - PsiClass targetClass, - Map modifierListCopies, - MultiMap conflicts) { - for (final PsiMember member : membersToMove) { - final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); - if (handler != null) { - handler.checkConflictsOnMember(member, newVisibility, modifierListCopies.get(member), targetClass, membersToMove, conflicts); - } + + private static void analyzeConflictsOnUsages( + UsageInfo[] usages, + Set membersToMove, + String newVisibility, + @Nonnull PsiClass targetClass, + Map modifierListCopies, + MultiMap conflicts + ) { + for (UsageInfo usage : usages) { + if (!(usage instanceof MoveMembersUsageInfo)) { + continue; + } + final MoveMembersUsageInfo usageInfo = (MoveMembersUsageInfo)usage; + final PsiMember member = usageInfo.member; + final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); + if (handler != null) { + handler.checkConflictsOnUsage( + usageInfo, + newVisibility, + modifierListCopies.get(member), + targetClass, + membersToMove, + conflicts + ); + } + } } - } - - @RequiredUIAccess - public void doRun() { - if (myMembersToMove.isEmpty()) { - LocalizeValue message = RefactoringLocalize.noMembersSelected(); - CommonRefactoringUtil.showErrorMessage(MoveMembersImpl.REFACTORING_NAME, message.get(), HelpID.MOVE_MEMBERS, myProject); - return; + + private static void analyzeConflictsOnMembers( + Set membersToMove, + String newVisibility, + PsiClass targetClass, + Map modifierListCopies, + MultiMap conflicts + ) { + for (final PsiMember member : membersToMove) { + final MoveMemberHandler handler = MoveMemberHandler.forLanguage(member.getLanguage()); + if (handler != null) { + handler.checkConflictsOnMember( + member, + newVisibility, + modifierListCopies.get(member), + targetClass, + membersToMove, + conflicts + ); + } + } } - super.doRun(); - } - public List getMembers() { - return new ArrayList(myMembersToMove); - } + @RequiredUIAccess + public void doRun() { + if (myMembersToMove.isEmpty()) { + LocalizeValue message = RefactoringLocalize.noMembersSelected(); + CommonRefactoringUtil.showErrorMessage(MoveMembersImpl.REFACTORING_NAME, message.get(), HelpID.MOVE_MEMBERS, myProject); + return; + } + super.doRun(); + } - public PsiClass getTargetClass() { - return myTargetClass; - } + public List getMembers() { + return new ArrayList(myMembersToMove); + } + public PsiClass getTargetClass() { + return myTargetClass; + } - public static class MoveMembersUsageInfo extends MoveRenameUsageInfo { - public final PsiClass qualifierClass; - public final PsiElement reference; - public final PsiMember member; - public MoveMembersUsageInfo(PsiMember member, PsiElement element, PsiClass qualifierClass, PsiElement highlightElement, final PsiReference ref) { - super(highlightElement, ref, member); - this.member = member; - this.qualifierClass = qualifierClass; - reference = element; + public static class MoveMembersUsageInfo extends MoveRenameUsageInfo { + public final PsiClass qualifierClass; + public final PsiElement reference; + public final PsiMember member; + + public MoveMembersUsageInfo( + PsiMember member, + PsiElement element, + PsiClass qualifierClass, + PsiElement highlightElement, + final PsiReference ref + ) { + super(highlightElement, ref, member); + this.member = member; + this.qualifierClass = qualifierClass; + reference = element; + } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java index 629ea002ad..54931c19c5 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java @@ -34,10 +34,11 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import org.jetbrains.annotations.NonNls; @@ -50,276 +51,296 @@ * @author dsl */ public class ReplaceConstructorWithFactoryProcessor extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance( - ReplaceConstructorWithFactoryProcessor.class); - private final PsiMethod myConstructor; - private final String myFactoryName; - private final PsiElementFactory myFactory; - private final PsiClass myOriginalClass; - private final PsiClass myTargetClass; - private final PsiManager myManager; - private final boolean myIsInner; - - public ReplaceConstructorWithFactoryProcessor(Project project, - PsiMethod originalConstructor, - PsiClass originalClass, - PsiClass targetClass, - @NonNls String factoryName) { - super(project); - myOriginalClass = originalClass; - myConstructor = originalConstructor; - myTargetClass = targetClass; - myFactoryName = factoryName; - myManager = PsiManager.getInstance(project); - myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); - - myIsInner = isInner(myOriginalClass); - } - - private boolean isInner(PsiClass originalClass) { - final boolean result = PsiUtil.isInnerClass(originalClass); - if (result) { - LOG.assertTrue(PsiTreeUtil.isAncestor(myTargetClass, originalClass, false)); + private static final Logger LOG = Logger.getInstance(ReplaceConstructorWithFactoryProcessor.class); + private final PsiMethod myConstructor; + private final String myFactoryName; + private final PsiElementFactory myFactory; + private final PsiClass myOriginalClass; + private final PsiClass myTargetClass; + private final PsiManager myManager; + private final boolean myIsInner; + + public ReplaceConstructorWithFactoryProcessor( + Project project, + PsiMethod originalConstructor, + PsiClass originalClass, + PsiClass targetClass, + @NonNls String factoryName + ) { + super(project); + myOriginalClass = originalClass; + myConstructor = originalConstructor; + myTargetClass = targetClass; + myFactoryName = factoryName; + myManager = PsiManager.getInstance(project); + myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); + + myIsInner = isInner(myOriginalClass); } - return result; - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - if (myConstructor != null) { - return new ReplaceConstructorWithFactoryViewDescriptor(myConstructor); - } else { - return new ReplaceConstructorWithFactoryViewDescriptor(myOriginalClass); - } - } - - private List myNonNewConstructorUsages; - - @Nonnull - protected UsageInfo[] findUsages() { - GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject); - - ArrayList usages = new ArrayList(); - myNonNewConstructorUsages = new ArrayList(); - - for (PsiReference reference : ReferencesSearch.search(myConstructor == null ? myOriginalClass : myConstructor, projectScope, false)) { - PsiElement element = reference.getElement(); - if (element.getParent() instanceof PsiNewExpression) { - usages.add(new UsageInfo(element.getParent())); - } else if ("super".equals(element.getText()) || "this".equals(element.getText())) { - myNonNewConstructorUsages.add(element); - } else if (element instanceof PsiMethod && ((PsiMethod) element).isConstructor()) { - myNonNewConstructorUsages.add(element); - } else if (element instanceof PsiClass) { - myNonNewConstructorUsages.add(element); - } + private boolean isInner(PsiClass originalClass) { + final boolean result = PsiUtil.isInnerClass(originalClass); + if (result) { + LOG.assertTrue(PsiTreeUtil.isAncestor(myTargetClass, originalClass, false)); + } + return result; } - //if (myConstructor != null && myConstructor.getParameterList().getParametersCount() == 0) { - // RefactoringUtil.visitImplicitConstructorUsages(getConstructorContainingClass(), new RefactoringUtil.ImplicitConstructorUsageVisitor() { - // @Override public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) { - // myNonNewConstructorUsages.add(constructor); - // } - // - // @Override public void visitClassWithoutConstructors(PsiClass aClass) { - // myNonNewConstructorUsages.add(aClass); - // } - // }); - //} - - return usages.toArray(new UsageInfo[usages.size()]); - } - - protected boolean preprocessUsages(Ref refUsages) { - UsageInfo[] usages = refUsages.get(); - - MultiMap conflicts = new MultiMap(); - final PsiResolveHelper helper = JavaPsiFacade.getInstance(myProject).getResolveHelper(); - final PsiClass constructorContainingClass = getConstructorContainingClass(); - if (!helper.isAccessible(constructorContainingClass, myTargetClass, null)) { - LocalizeValue message = RefactoringLocalize.class0IsNotAccessibleFromTarget1( - RefactoringUIUtil.getDescription(constructorContainingClass, true), - RefactoringUIUtil.getDescription(myTargetClass, true) - ); - conflicts.putValue(constructorContainingClass, message.get()); + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + if (myConstructor != null) { + return new ReplaceConstructorWithFactoryViewDescriptor(myConstructor); + } + else { + return new ReplaceConstructorWithFactoryViewDescriptor(myOriginalClass); + } } - HashSet reportedContainers = new HashSet(); - final String targetClassDescription = RefactoringUIUtil.getDescription(myTargetClass, true); - for (UsageInfo usage : usages) { - final PsiElement container = ConflictsUtil.getContainer(usage.getElement()); - if (!reportedContainers.contains(container)) { - reportedContainers.add(container); - if (!helper.isAccessible(myTargetClass, usage.getElement(), null)) { - LocalizeValue message = RefactoringLocalize.target0IsNotAccessibleFrom1( - targetClassDescription, - RefactoringUIUtil.getDescription(container, true) - ); - conflicts.putValue(myTargetClass, message.get()); + private List myNonNewConstructorUsages; + + @Nonnull + protected UsageInfo[] findUsages() { + GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject); + + ArrayList usages = new ArrayList(); + myNonNewConstructorUsages = new ArrayList(); + + for (PsiReference reference : ReferencesSearch.search( + myConstructor == null ? myOriginalClass : myConstructor, + projectScope, + false + )) { + PsiElement element = reference.getElement(); + + if (element.getParent() instanceof PsiNewExpression) { + usages.add(new UsageInfo(element.getParent())); + } + else if ("super".equals(element.getText()) || "this".equals(element.getText())) { + myNonNewConstructorUsages.add(element); + } + else if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) { + myNonNewConstructorUsages.add(element); + } + else if (element instanceof PsiClass) { + myNonNewConstructorUsages.add(element); + } } - } - } - if (myIsInner) { - for (UsageInfo usage : usages) { - final PsiField field = PsiTreeUtil.getParentOfType(usage.getElement(), PsiField.class); - if (field != null) { - final PsiClass containingClass = field.getContainingClass(); + //if (myConstructor != null && myConstructor.getParameterList().getParametersCount() == 0) { + // RefactoringUtil.visitImplicitConstructorUsages(getConstructorContainingClass(), new RefactoringUtil.ImplicitConstructorUsageVisitor() { + // @Override public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) { + // myNonNewConstructorUsages.add(constructor); + // } + // + // @Override public void visitClassWithoutConstructors(PsiClass aClass) { + // myNonNewConstructorUsages.add(aClass); + // } + // }); + //} + + return usages.toArray(new UsageInfo[usages.size()]); + } - if (PsiTreeUtil.isAncestor(containingClass, myTargetClass, true)) { - LocalizeValue message = RefactoringLocalize.constructorBeingRefactoredIsUsedInInitializerOf0( - RefactoringUIUtil.getDescription(field, true), - RefactoringUIUtil.getDescription(constructorContainingClass, false) + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + UsageInfo[] usages = refUsages.get(); + + MultiMap conflicts = new MultiMap(); + final PsiResolveHelper helper = JavaPsiFacade.getInstance(myProject).getResolveHelper(); + final PsiClass constructorContainingClass = getConstructorContainingClass(); + if (!helper.isAccessible(constructorContainingClass, myTargetClass, null)) { + LocalizeValue message = RefactoringLocalize.class0IsNotAccessibleFromTarget1( + RefactoringUIUtil.getDescription(constructorContainingClass, true), + RefactoringUIUtil.getDescription(myTargetClass, true) ); - conflicts.putValue(field, message.get()); - } + conflicts.putValue(constructorContainingClass, message.get()); } - } - } + HashSet reportedContainers = new HashSet(); + final String targetClassDescription = RefactoringUIUtil.getDescription(myTargetClass, true); + for (UsageInfo usage : usages) { + final PsiElement container = ConflictsUtil.getContainer(usage.getElement()); + if (!reportedContainers.contains(container)) { + reportedContainers.add(container); + if (!helper.isAccessible(myTargetClass, usage.getElement(), null)) { + LocalizeValue message = RefactoringLocalize.target0IsNotAccessibleFrom1( + targetClassDescription, + RefactoringUIUtil.getDescription(container, true) + ); + conflicts.putValue(myTargetClass, message.get()); + } + } + } + + if (myIsInner) { + for (UsageInfo usage : usages) { + final PsiField field = PsiTreeUtil.getParentOfType(usage.getElement(), PsiField.class); + if (field != null) { + final PsiClass containingClass = field.getContainingClass(); + + if (PsiTreeUtil.isAncestor(containingClass, myTargetClass, true)) { + LocalizeValue message = RefactoringLocalize.constructorBeingRefactoredIsUsedInInitializerOf0( + RefactoringUIUtil.getDescription(field, true), + RefactoringUIUtil.getDescription(constructorContainingClass, false) + ); + conflicts.putValue(field, message.get()); + } + } + } + } - return showConflicts(conflicts, usages); - } - private PsiClass getConstructorContainingClass() { - if (myConstructor != null) { - return myConstructor.getContainingClass(); - } else { - return myOriginalClass; + return showConflicts(conflicts, usages); } - } - - protected void performRefactoring(UsageInfo[] usages) { - - try { - PsiReferenceExpression classReferenceExpression = - myFactory.createReferenceExpression(myTargetClass); - PsiReferenceExpression qualifiedMethodReference = - (PsiReferenceExpression) myFactory.createExpressionFromText("A." + myFactoryName, null); - PsiMethod factoryMethod = (PsiMethod) myTargetClass.add(createFactoryMethod()); - if (myConstructor != null) { - PsiUtil.setModifierProperty(myConstructor, PsiModifier.PRIVATE, true); - VisibilityUtil.escalateVisibility(myConstructor, factoryMethod); - for (PsiElement place : myNonNewConstructorUsages) { - VisibilityUtil.escalateVisibility(myConstructor, place); + + private PsiClass getConstructorContainingClass() { + if (myConstructor != null) { + return myConstructor.getContainingClass(); } - } - - if (myConstructor == null) { - PsiMethod constructor = myFactory.createConstructor(); - PsiUtil.setModifierProperty(constructor, PsiModifier.PRIVATE, true); - constructor = (PsiMethod) getConstructorContainingClass().add(constructor); - VisibilityUtil.escalateVisibility(constructor, myTargetClass); - } - - for (UsageInfo usage : usages) { - PsiNewExpression newExpression = (PsiNewExpression) usage.getElement(); - if (newExpression == null) continue; - - VisibilityUtil.escalateVisibility(factoryMethod, newExpression); - PsiMethodCallExpression factoryCall = - (PsiMethodCallExpression) myFactory.createExpressionFromText(myFactoryName + "()", newExpression); - factoryCall.getArgumentList().replace(newExpression.getArgumentList()); - - boolean replaceMethodQualifier = false; - PsiExpression newQualifier = newExpression.getQualifier(); - - PsiElement resolvedFactoryMethod = factoryCall.getMethodExpression().resolve(); - if (resolvedFactoryMethod != factoryMethod || newQualifier != null) { - factoryCall.getMethodExpression().replace(qualifiedMethodReference); - replaceMethodQualifier = true; + else { + return myOriginalClass; } + } - if (replaceMethodQualifier) { - if (newQualifier == null) { - factoryCall.getMethodExpression().getQualifierExpression().replace(classReferenceExpression); - } else { - factoryCall.getMethodExpression().getQualifierExpression().replace(newQualifier); - } + protected void performRefactoring(UsageInfo[] usages) { + + try { + PsiReferenceExpression classReferenceExpression = + myFactory.createReferenceExpression(myTargetClass); + PsiReferenceExpression qualifiedMethodReference = + (PsiReferenceExpression)myFactory.createExpressionFromText("A." + myFactoryName, null); + PsiMethod factoryMethod = (PsiMethod)myTargetClass.add(createFactoryMethod()); + if (myConstructor != null) { + PsiUtil.setModifierProperty(myConstructor, PsiModifier.PRIVATE, true); + VisibilityUtil.escalateVisibility(myConstructor, factoryMethod); + for (PsiElement place : myNonNewConstructorUsages) { + VisibilityUtil.escalateVisibility(myConstructor, place); + } + } + + if (myConstructor == null) { + PsiMethod constructor = myFactory.createConstructor(); + PsiUtil.setModifierProperty(constructor, PsiModifier.PRIVATE, true); + constructor = (PsiMethod)getConstructorContainingClass().add(constructor); + VisibilityUtil.escalateVisibility(constructor, myTargetClass); + } + + for (UsageInfo usage : usages) { + PsiNewExpression newExpression = (PsiNewExpression)usage.getElement(); + if (newExpression == null) { + continue; + } + + VisibilityUtil.escalateVisibility(factoryMethod, newExpression); + PsiMethodCallExpression factoryCall = + (PsiMethodCallExpression)myFactory.createExpressionFromText(myFactoryName + "()", newExpression); + factoryCall.getArgumentList().replace(newExpression.getArgumentList()); + + boolean replaceMethodQualifier = false; + PsiExpression newQualifier = newExpression.getQualifier(); + + PsiElement resolvedFactoryMethod = factoryCall.getMethodExpression().resolve(); + if (resolvedFactoryMethod != factoryMethod || newQualifier != null) { + factoryCall.getMethodExpression().replace(qualifiedMethodReference); + replaceMethodQualifier = true; + } + + if (replaceMethodQualifier) { + if (newQualifier == null) { + factoryCall.getMethodExpression().getQualifierExpression().replace(classReferenceExpression); + } + else { + factoryCall.getMethodExpression().getQualifierExpression().replace(newQualifier); + } + } + + newExpression.replace(factoryCall); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); } - - newExpression.replace(factoryCall); - } - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - private PsiMethod createFactoryMethod() throws IncorrectOperationException { - final PsiClass containingClass = getConstructorContainingClass(); - PsiClassType type = myFactory.createType(containingClass, PsiSubstitutor.EMPTY); - final PsiMethod factoryMethod = myFactory.createMethod(myFactoryName, type); - if (myConstructor != null) { - factoryMethod.getParameterList().replace(myConstructor.getParameterList()); - factoryMethod.getThrowsList().replace(myConstructor.getThrowsList()); } - Collection names = new HashSet(); - for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(myConstructor != null ? myConstructor : containingClass)) { - if (!names.contains(typeParameter.getName())) { //Otherwise type parameter is hidden in the constructor - names.add(typeParameter.getName()); - factoryMethod.getTypeParameterList().addAfter(typeParameter, null); - } - } + private PsiMethod createFactoryMethod() throws IncorrectOperationException { + final PsiClass containingClass = getConstructorContainingClass(); + PsiClassType type = myFactory.createType(containingClass, PsiSubstitutor.EMPTY); + final PsiMethod factoryMethod = myFactory.createMethod(myFactoryName, type); + if (myConstructor != null) { + factoryMethod.getParameterList().replace(myConstructor.getParameterList()); + factoryMethod.getThrowsList().replace(myConstructor.getThrowsList()); + } - PsiReturnStatement returnStatement = - (PsiReturnStatement) myFactory.createStatementFromText("return new A();", null); - PsiNewExpression newExpression = (PsiNewExpression) returnStatement.getReturnValue(); - PsiJavaCodeReferenceElement classRef = myFactory.createReferenceElementByType(type); - newExpression.getClassReference().replace(classRef); - final PsiExpressionList argumentList = newExpression.getArgumentList(); + Collection names = new HashSet(); + for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(myConstructor != null ? myConstructor : containingClass)) { + if (!names.contains(typeParameter.getName())) { //Otherwise type parameter is hidden in the constructor + names.add(typeParameter.getName()); + factoryMethod.getTypeParameterList().addAfter(typeParameter, null); + } + } - PsiParameter[] params = factoryMethod.getParameterList().getParameters(); + PsiReturnStatement returnStatement = + (PsiReturnStatement)myFactory.createStatementFromText("return new A();", null); + PsiNewExpression newExpression = (PsiNewExpression)returnStatement.getReturnValue(); + PsiJavaCodeReferenceElement classRef = myFactory.createReferenceElementByType(type); + newExpression.getClassReference().replace(classRef); + final PsiExpressionList argumentList = newExpression.getArgumentList(); - for (PsiParameter parameter : params) { - PsiExpression paramRef = myFactory.createExpressionFromText(parameter.getName(), null); - argumentList.add(paramRef); - } - factoryMethod.getBody().add(returnStatement); + PsiParameter[] params = factoryMethod.getParameterList().getParameters(); - PsiUtil.setModifierProperty(factoryMethod, getDefaultFactoryVisibility(), true); + for (PsiParameter parameter : params) { + PsiExpression paramRef = myFactory.createExpressionFromText(parameter.getName(), null); + argumentList.add(paramRef); + } + factoryMethod.getBody().add(returnStatement); - if (!myIsInner) { - PsiUtil.setModifierProperty(factoryMethod, PsiModifier.STATIC, true); - } + PsiUtil.setModifierProperty(factoryMethod, getDefaultFactoryVisibility(), true); + + if (!myIsInner) { + PsiUtil.setModifierProperty(factoryMethod, PsiModifier.STATIC, true); + } - return (PsiMethod) CodeStyleManager.getInstance(myProject).reformat(factoryMethod); - } + return (PsiMethod)CodeStyleManager.getInstance(myProject).reformat(factoryMethod); + } - @PsiModifier.ModifierConstant - private String getDefaultFactoryVisibility() { - final PsiModifierList modifierList; - if (myConstructor != null) { - modifierList = myConstructor.getModifierList(); - } else { - modifierList = myOriginalClass.getModifierList(); + @PsiModifier.ModifierConstant + private String getDefaultFactoryVisibility() { + final PsiModifierList modifierList; + if (myConstructor != null) { + modifierList = myConstructor.getModifierList(); + } + else { + modifierList = myOriginalClass.getModifierList(); + } + return VisibilityUtil.getVisibilityModifier(modifierList); } - return VisibilityUtil.getVisibilityModifier(modifierList); - } - protected String getCommandName() { - if (myConstructor != null) { - return RefactoringLocalize.replaceConstructor0WithAFactoryMethod(DescriptiveNameUtil.getDescriptiveName(myConstructor)).get(); - } else { - return RefactoringLocalize.replaceDefaultConstructorOf0WithAFactoryMethod(DescriptiveNameUtil.getDescriptiveName(myOriginalClass)).get(); + protected String getCommandName() { + if (myConstructor != null) { + return RefactoringLocalize.replaceConstructor0WithAFactoryMethod(DescriptiveNameUtil.getDescriptiveName(myConstructor)).get(); + } + else { + return RefactoringLocalize.replaceDefaultConstructorOf0WithAFactoryMethod( + DescriptiveNameUtil.getDescriptiveName(myOriginalClass) + ).get(); + } } - } - public PsiClass getOriginalClass() { - return getConstructorContainingClass(); - } + public PsiClass getOriginalClass() { + return getConstructorContainingClass(); + } - public PsiClass getTargetClass() { - return myTargetClass; - } + public PsiClass getTargetClass() { + return myTargetClass; + } - public PsiMethod getConstructor() { - return myConstructor; - } + public PsiMethod getConstructor() { + return myConstructor; + } - public String getFactoryName() { - return myFactoryName; - } + public String getFactoryName() { + return myFactoryName; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/safeDelete/JavaSafeDeleteProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/safeDelete/JavaSafeDeleteProcessor.java index 473bcd7aa4..07dfd06d28 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/safeDelete/JavaSafeDeleteProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/safeDelete/JavaSafeDeleteProcessor.java @@ -62,714 +62,782 @@ @ExtensionImpl(id = "javaProcessor") public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { - private static final Logger LOG = Logger.getInstance(JavaSafeDeleteProcessor.class); - - public boolean handlesElement(final PsiElement element) { - return element instanceof PsiClass || element instanceof PsiMethod || element instanceof PsiField - || element instanceof PsiParameter || element instanceof PsiLocalVariable || element instanceof PsiPackage; - } - - @Nullable - @RequiredUIAccess - public NonCodeUsageSearchInfo findUsages(final PsiElement element, final PsiElement[] allElementsToDelete, final List usages) { - Condition insideDeletedCondition = getUsageInsideDeletedFilter(allElementsToDelete); - if (element instanceof PsiClass psiClass) { - findClassUsages(psiClass, allElementsToDelete, usages); - if (element instanceof PsiTypeParameter typeParameter) { - findTypeParameterExternalUsages(typeParameter, usages); - } - } else if (element instanceof PsiMethod method) { - insideDeletedCondition = findMethodUsages(method, allElementsToDelete, usages); - } else if (element instanceof PsiField field) { - insideDeletedCondition = findFieldUsages(field, usages, allElementsToDelete); - } else if (element instanceof PsiParameter parameter) { - LOG.assertTrue(parameter.getDeclarationScope() instanceof PsiMethod); - findParameterUsages(parameter, usages); - } else if (element instanceof PsiLocalVariable localVariable) { - for (PsiReference reference : ReferencesSearch.search(element)) { - PsiReferenceExpression referencedElement = (PsiReferenceExpression)reference.getElement(); - final PsiStatement statement = PsiTreeUtil.getParentOfType(referencedElement, PsiStatement.class); - - boolean isSafeToDelete = PsiUtil.isAccessedForWriting(referencedElement); - boolean hasSideEffects = false; - if (PsiUtil.isOnAssignmentLeftHand(referencedElement)) { - hasSideEffects = RemoveUnusedVariableUtil.checkSideEffects( - ((PsiAssignmentExpression) referencedElement.getParent()).getRExpression(), - localVariable, - new ArrayList<>() - ); - } - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(statement, element, isSafeToDelete && !hasSideEffects)); - } - } - return new NonCodeUsageSearchInfo(insideDeletedCondition, element); - } - - @Nullable - @Override - @RequiredUIAccess - public Collection getElementsToSearch( - PsiElement element, - @Nullable Module module, - Collection allElementsToDelete - ) { - Project project = element.getProject(); - if (element instanceof PsiPackage psiPackage && module != null) { - final PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.moduleScope(module)); - if (directories.length == 0) return null; - return Arrays.asList(directories); - } else if (element instanceof PsiMethod method) { - final PsiMethod[] methods = SuperMethodWarningUtil.checkSuperMethods( - method, - RefactoringLocalize.toDeleteWithUsageSearch().get(), - allElementsToDelete - ); - if (methods.length == 0) return null; - final ArrayList psiMethods = new ArrayList<>(Arrays.asList(methods)); - psiMethods.add(method); - return psiMethods; - } else if (element instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiMethod method) { - final Set parametersToDelete = new HashSet<>(); - parametersToDelete.add(parameter); - final int parameterIndex = method.getParameterList().getParameterIndex((PsiParameter) element); - final List superMethods = new ArrayList<>(Arrays.asList(method.findDeepestSuperMethods())); - if (superMethods.isEmpty()) { - superMethods.add(method); - } - for (PsiMethod superMethod : superMethods) { - parametersToDelete.add(superMethod.getParameterList().getParameters()[parameterIndex]); - OverridingMethodsSearch.search(superMethod).forEach(overrider -> { - parametersToDelete.add(overrider.getParameterList().getParameters()[parameterIndex]); - return true; - }); - } - - if (parametersToDelete.size() > 1 && !project.getApplication().isUnitTestMode()) { - LocalizeValue message = - RefactoringLocalize.zeroIsAPartOfMethodHierarchyDoYouWantToDeleteMultipleParameters(UsageViewUtil.getLongName(method)); - if (Messages.showYesNoDialog( - project, - message.get(), - SafeDeleteHandler.REFACTORING_NAME.get(), - UIUtil.getQuestionIcon() - ) != DialogWrapper.OK_EXIT_CODE) { - return null; - } - } - return parametersToDelete; - } else { - return Collections.singletonList(element); - } - } - - @Override - public UsageView showUsages(UsageInfo[] usages, UsageViewPresentation presentation, UsageViewManager manager, PsiElement[] elements) { - final List overridingMethods = new ArrayList<>(); - final List others = new ArrayList<>(); - for (UsageInfo usage : usages) { - if (usage instanceof SafeDeleteOverridingMethodUsageInfo safeDeleteOverridingMethodUsageInfo) { - overridingMethods.add(safeDeleteOverridingMethodUsageInfo.getOverridingMethod()); - } else { - others.add(usage); - } - } + private static final Logger LOG = Logger.getInstance(JavaSafeDeleteProcessor.class); + + public boolean handlesElement(final PsiElement element) { + return element instanceof PsiClass || element instanceof PsiMethod || element instanceof PsiField + || element instanceof PsiParameter || element instanceof PsiLocalVariable || element instanceof PsiPackage; + } + + @Nullable + @RequiredUIAccess + public NonCodeUsageSearchInfo findUsages( + final PsiElement element, + final PsiElement[] allElementsToDelete, + final List usages + ) { + Condition insideDeletedCondition = getUsageInsideDeletedFilter(allElementsToDelete); + if (element instanceof PsiClass psiClass) { + findClassUsages(psiClass, allElementsToDelete, usages); + if (element instanceof PsiTypeParameter typeParameter) { + findTypeParameterExternalUsages(typeParameter, usages); + } + } + else if (element instanceof PsiMethod method) { + insideDeletedCondition = findMethodUsages(method, allElementsToDelete, usages); + } + else if (element instanceof PsiField field) { + insideDeletedCondition = findFieldUsages(field, usages, allElementsToDelete); + } + else if (element instanceof PsiParameter parameter) { + LOG.assertTrue(parameter.getDeclarationScope() instanceof PsiMethod); + findParameterUsages(parameter, usages); + } + else if (element instanceof PsiLocalVariable localVariable) { + for (PsiReference reference : ReferencesSearch.search(element)) { + PsiReferenceExpression referencedElement = (PsiReferenceExpression)reference.getElement(); + final PsiStatement statement = PsiTreeUtil.getParentOfType(referencedElement, PsiStatement.class); + + boolean isSafeToDelete = PsiUtil.isAccessedForWriting(referencedElement); + boolean hasSideEffects = false; + if (PsiUtil.isOnAssignmentLeftHand(referencedElement)) { + hasSideEffects = RemoveUnusedVariableUtil.checkSideEffects( + ((PsiAssignmentExpression)referencedElement.getParent()).getRExpression(), + localVariable, + new ArrayList<>() + ); + } + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(statement, element, isSafeToDelete && !hasSideEffects)); + } + } + return new NonCodeUsageSearchInfo(insideDeletedCondition, element); + } + + @Nullable + @Override + @RequiredUIAccess + public Collection getElementsToSearch( + PsiElement element, + @Nullable Module module, + Collection allElementsToDelete + ) { + Project project = element.getProject(); + if (element instanceof PsiPackage psiPackage && module != null) { + final PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.moduleScope(module)); + if (directories.length == 0) { + return null; + } + return Arrays.asList(directories); + } + else if (element instanceof PsiMethod method) { + final PsiMethod[] methods = SuperMethodWarningUtil.checkSuperMethods( + method, + RefactoringLocalize.toDeleteWithUsageSearch().get(), + allElementsToDelete + ); + if (methods.length == 0) { + return null; + } + final ArrayList psiMethods = new ArrayList<>(Arrays.asList(methods)); + psiMethods.add(method); + return psiMethods; + } + else if (element instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiMethod method) { + final Set parametersToDelete = new HashSet<>(); + parametersToDelete.add(parameter); + final int parameterIndex = method.getParameterList().getParameterIndex((PsiParameter)element); + final List superMethods = new ArrayList<>(Arrays.asList(method.findDeepestSuperMethods())); + if (superMethods.isEmpty()) { + superMethods.add(method); + } + for (PsiMethod superMethod : superMethods) { + parametersToDelete.add(superMethod.getParameterList().getParameters()[parameterIndex]); + OverridingMethodsSearch.search(superMethod).forEach(overrider -> { + parametersToDelete.add(overrider.getParameterList().getParameters()[parameterIndex]); + return true; + }); + } - UsageTarget[] targets = new UsageTarget[elements.length + overridingMethods.size()]; - for (int i = 0; i < targets.length; i++) { - if (i < elements.length) { - targets[i] = new PsiElement2UsageTargetAdapter(elements[i]); - } else { - targets[i] = new PsiElement2UsageTargetAdapter(overridingMethods.get(i - elements.length)); - } + if (parametersToDelete.size() > 1 && !project.getApplication().isUnitTestMode()) { + LocalizeValue message = + RefactoringLocalize.zeroIsAPartOfMethodHierarchyDoYouWantToDeleteMultipleParameters(UsageViewUtil.getLongName(method)); + if (Messages.showYesNoDialog( + project, + message.get(), + SafeDeleteHandler.REFACTORING_NAME.get(), + UIUtil.getQuestionIcon() + ) != DialogWrapper.OK_EXIT_CODE) { + return null; + } + } + return parametersToDelete; + } + else { + return Collections.singletonList(element); + } } - return manager.showUsages(targets, - UsageInfoToUsageConverter.convert(new UsageInfoToUsageConverter.TargetElementsDescriptor(elements), - others.toArray(new UsageInfo[others.size()])), - presentation - ); - } - - @RequiredUIAccess - public Collection getAdditionalElementsToDelete( - final PsiElement element, - final Collection allElementsToDelete, - final boolean askUser - ) { - if (element instanceof PsiField field) { - final Project project = element.getProject(); - String propertyName = JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(field.getName(), VariableKind.FIELD); - - PsiClass aClass = field.getContainingClass(); - if (aClass != null) { - boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); - PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(aClass, propertyName, isStatic); - if (getters != null) { - final List validGetters = new ArrayList<>(1); - for (PsiMethod getter : getters) { - if (!allElementsToDelete.contains(getter) && (getter != null && getter.isPhysical())) { - validGetters.add(getter); - } - } - getters = validGetters.isEmpty() ? null : validGetters.toArray(new PsiMethod[validGetters.size()]); - } - - PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); - if (allElementsToDelete.contains(setter) || setter != null && !setter.isPhysical()) setter = null; - if (askUser && (getters != null || setter != null)) { - final String message = - RefactoringMessageUtil.getGetterSetterMessage( - field.getName(), - RefactoringLocalize.deleteTitle().get(), - getters != null ? getters[0] : null, - setter - ); - if (!project.getApplication().isUnitTestMode() - && Messages.showYesNoDialog(project, message, RefactoringLocalize.safeDeleteTitle().get(), UIUtil.getQuestionIcon()) != 0) { - getters = null; - setter = null; - } - } - List elements = new ArrayList<>(); - if (setter != null) elements.add(setter); - if (getters != null) Collections.addAll(elements, getters); - return elements; - } - } - return null; - } - - public Collection findConflicts(final PsiElement element, final PsiElement[] allElementsToDelete) { - if (element instanceof PsiMethod method) { - final PsiClass containingClass = method.getContainingClass(); - - if (!containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { - final PsiMethod[] superMethods = method.findSuperMethods(); - for (PsiMethod superMethod : superMethods) { - if (isInside(superMethod, allElementsToDelete)) continue; - if (superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - LocalizeValue message = RefactoringLocalize.zeroImplements1( - RefactoringUIUtil.getDescription(element, true), - RefactoringUIUtil.getDescription(superMethod, true) - ); - return Collections.singletonList(message.get()); - } + @Override + public UsageView showUsages(UsageInfo[] usages, UsageViewPresentation presentation, UsageViewManager manager, PsiElement[] elements) { + final List overridingMethods = new ArrayList<>(); + final List others = new ArrayList<>(); + for (UsageInfo usage : usages) { + if (usage instanceof SafeDeleteOverridingMethodUsageInfo safeDeleteOverridingMethodUsageInfo) { + overridingMethods.add(safeDeleteOverridingMethodUsageInfo.getOverridingMethod()); + } + else { + others.add(usage); + } } - } - } - return null; - } - - @Nullable - @RequiredUIAccess - public UsageInfo[] preprocessUsages(final Project project, final UsageInfo[] usages) { - ArrayList result = new ArrayList<>(); - ArrayList overridingMethods = new ArrayList<>(); - for (UsageInfo usage : usages) { - if (usage.isNonCodeUsage) { - result.add(usage); - } else if (usage instanceof SafeDeleteOverridingMethodUsageInfo) { - overridingMethods.add(usage); - } else { - result.add(usage); - } - } - if (!overridingMethods.isEmpty()) { - if (project.getApplication().isUnitTestMode()) { - result.addAll(overridingMethods); - } else { - OverridingMethodsDialog dialog = new OverridingMethodsDialog(project, overridingMethods); - dialog.show(); - if (!dialog.isOK()) return null; - result.addAll(dialog.getSelected()); - } + UsageTarget[] targets = new UsageTarget[elements.length + overridingMethods.size()]; + for (int i = 0; i < targets.length; i++) { + if (i < elements.length) { + targets[i] = new PsiElement2UsageTargetAdapter(elements[i]); + } + else { + targets[i] = new PsiElement2UsageTargetAdapter(overridingMethods.get(i - elements.length)); + } + } + + return manager.showUsages( + targets, + UsageInfoToUsageConverter.convert( + new UsageInfoToUsageConverter.TargetElementsDescriptor(elements), + others.toArray(new UsageInfo[others.size()]) + ), + presentation + ); + } + + @RequiredUIAccess + public Collection getAdditionalElementsToDelete( + final PsiElement element, + final Collection allElementsToDelete, + final boolean askUser + ) { + if (element instanceof PsiField field) { + final Project project = element.getProject(); + String propertyName = JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(field.getName(), VariableKind.FIELD); + + PsiClass aClass = field.getContainingClass(); + if (aClass != null) { + boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); + PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(aClass, propertyName, isStatic); + if (getters != null) { + final List validGetters = new ArrayList<>(1); + for (PsiMethod getter : getters) { + if (!allElementsToDelete.contains(getter) && (getter != null && getter.isPhysical())) { + validGetters.add(getter); + } + } + getters = validGetters.isEmpty() ? null : validGetters.toArray(new PsiMethod[validGetters.size()]); + } + + PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); + if (allElementsToDelete.contains(setter) || setter != null && !setter.isPhysical()) { + setter = null; + } + if (askUser && (getters != null || setter != null)) { + final String message = + RefactoringMessageUtil.getGetterSetterMessage( + field.getName(), + RefactoringLocalize.deleteTitle().get(), + getters != null ? getters[0] : null, + setter + ); + if (!project.getApplication().isUnitTestMode() + && Messages.showYesNoDialog( + project, + message, + RefactoringLocalize.safeDeleteTitle().get(), + UIUtil.getQuestionIcon() + ) != 0) { + getters = null; + setter = null; + } + } + List elements = new ArrayList<>(); + if (setter != null) { + elements.add(setter); + } + if (getters != null) { + Collections.addAll(elements, getters); + } + return elements; + } + } + return null; + } + + public Collection findConflicts(final PsiElement element, final PsiElement[] allElementsToDelete) { + if (element instanceof PsiMethod method) { + final PsiClass containingClass = method.getContainingClass(); + + if (!containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + final PsiMethod[] superMethods = method.findSuperMethods(); + for (PsiMethod superMethod : superMethods) { + if (isInside(superMethod, allElementsToDelete)) { + continue; + } + if (superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + LocalizeValue message = RefactoringLocalize.zeroImplements1( + RefactoringUIUtil.getDescription(element, true), + RefactoringUIUtil.getDescription(superMethod, true) + ); + return Collections.singletonList(message.get()); + } + } + } + } + return null; } - return result.toArray(new UsageInfo[result.size()]); - } + @Nullable + @RequiredUIAccess + public UsageInfo[] preprocessUsages(final Project project, final UsageInfo[] usages) { + ArrayList result = new ArrayList<>(); + ArrayList overridingMethods = new ArrayList<>(); + for (UsageInfo usage : usages) { + if (usage.isNonCodeUsage) { + result.add(usage); + } + else if (usage instanceof SafeDeleteOverridingMethodUsageInfo) { + overridingMethods.add(usage); + } + else { + result.add(usage); + } + } - public void prepareForDeletion(final PsiElement element) throws IncorrectOperationException { - if (element instanceof PsiVariable variable) { - variable.normalizeDeclaration(); + if (!overridingMethods.isEmpty()) { + if (project.getApplication().isUnitTestMode()) { + result.addAll(overridingMethods); + } + else { + OverridingMethodsDialog dialog = new OverridingMethodsDialog(project, overridingMethods); + dialog.show(); + if (!dialog.isOK()) { + return null; + } + result.addAll(dialog.getSelected()); + } + } + + return result.toArray(new UsageInfo[result.size()]); } - } - - @Override - public boolean isToSearchInComments(PsiElement element) { - if (element instanceof PsiClass) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS; - } else if (element instanceof PsiMethod) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD; - } else if (element instanceof PsiVariable) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE; - } else if (element instanceof PsiPackage) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_PACKAGE; + + public void prepareForDeletion(final PsiElement element) throws IncorrectOperationException { + if (element instanceof PsiVariable variable) { + variable.normalizeDeclaration(); + } } - return false; - } - - @Override - public void setToSearchInComments(PsiElement element, boolean enabled) { - if (element instanceof PsiClass) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS = enabled; - } else if (element instanceof PsiMethod) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled; - } else if (element instanceof PsiVariable) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE = enabled; - } else if (element instanceof PsiPackage) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_PACKAGE = enabled; + + @Override + public boolean isToSearchInComments(PsiElement element) { + if (element instanceof PsiClass) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS; + } + else if (element instanceof PsiMethod) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD; + } + else if (element instanceof PsiVariable) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE; + } + else if (element instanceof PsiPackage) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_PACKAGE; + } + return false; } - } - - @Override - public boolean isToSearchForTextOccurrences(PsiElement element) { - if (element instanceof PsiClass) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS; - } else if (element instanceof PsiMethod) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD; - } else if (element instanceof PsiVariable) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_VARIABLE; - } else if (element instanceof PsiPackage) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_PACKAGE; + + @Override + public void setToSearchInComments(PsiElement element, boolean enabled) { + if (element instanceof PsiClass) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS = enabled; + } + else if (element instanceof PsiMethod) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled; + } + else if (element instanceof PsiVariable) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE = enabled; + } + else if (element instanceof PsiPackage) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_PACKAGE = enabled; + } } - return false; - } - - @Override - public void setToSearchForTextOccurrences(PsiElement element, boolean enabled) { - if (element instanceof PsiClass) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS = enabled; - } else if (element instanceof PsiMethod) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled; - } else if (element instanceof PsiVariable) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_VARIABLE = enabled; - } else if (element instanceof PsiPackage) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_PACKAGE = enabled; + + @Override + public boolean isToSearchForTextOccurrences(PsiElement element) { + if (element instanceof PsiClass) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS; + } + else if (element instanceof PsiMethod) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD; + } + else if (element instanceof PsiVariable) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_VARIABLE; + } + else if (element instanceof PsiPackage) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_PACKAGE; + } + return false; } - } - public static Condition getUsageInsideDeletedFilter(final PsiElement[] allElementsToDelete) { - return usage -> !(usage instanceof PsiFile) && isInside(usage, allElementsToDelete); - } + @Override + public void setToSearchForTextOccurrences(PsiElement element, boolean enabled) { + if (element instanceof PsiClass) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS = enabled; + } + else if (element instanceof PsiMethod) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled; + } + else if (element instanceof PsiVariable) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_VARIABLE = enabled; + } + else if (element instanceof PsiPackage) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_PACKAGE = enabled; + } + } - private static void findClassUsages(final PsiClass psiClass, final PsiElement[] allElementsToDelete, final List usages) { - final boolean justPrivates = containsOnlyPrivates(psiClass); + public static Condition getUsageInsideDeletedFilter(final PsiElement[] allElementsToDelete) { + return usage -> !(usage instanceof PsiFile) && isInside(usage, allElementsToDelete); + } - ReferencesSearch.search(psiClass).forEach(reference -> { - final PsiElement element = reference.getElement(); + private static void findClassUsages(final PsiClass psiClass, final PsiElement[] allElementsToDelete, final List usages) { + final boolean justPrivates = containsOnlyPrivates(psiClass); - if (!isInside(element, allElementsToDelete)) { - PsiElement parent = element.getParent(); - if (parent instanceof PsiReferenceList && parent.getParent() instanceof PsiClass inheritor) { - //If psiClass contains only private members, then it is safe to remove it and change inheritor's extends/implements accordingly - if (justPrivates && (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList()))) { - usages.add(new SafeDeleteExtendsClassUsageInfo((PsiJavaCodeReferenceElement)element, psiClass, inheritor)); - return true; - } - } - LOG.assertTrue(element.getTextRange() != null); - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, psiClass, isInNonStaticImport(element))); - } - return true; - }); - } - - private static boolean isInNonStaticImport(PsiElement element) { - return ImportSearcher.getImport(element, true) != null; - } - - @RequiredReadAction - private static boolean containsOnlyPrivates(final PsiClass aClass) { - final PsiField[] fields = aClass.getFields(); - for (PsiField field : fields) { - if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false; - } + ReferencesSearch.search(psiClass).forEach(reference -> { + final PsiElement element = reference.getElement(); - final PsiMethod[] methods = aClass.getMethods(); - for (PsiMethod method : methods) { - if (!method.hasModifierProperty(PsiModifier.PRIVATE)) { - if (method.isConstructor()) { //skip non-private constructors with call to super only - final PsiCodeBlock body = method.getBody(); - if (body != null) { - final PsiStatement[] statements = body.getStatements(); - if (statements.length == 0) continue; - if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement expressionStatement) { - final PsiExpression expression = expressionStatement.getExpression(); - if (expression instanceof PsiMethodCallExpression methodCallExpression) { - PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); - if (methodExpression.getText().equals(PsiKeyword.SUPER)) { - continue; + if (!isInside(element, allElementsToDelete)) { + PsiElement parent = element.getParent(); + if (parent instanceof PsiReferenceList && parent.getParent() instanceof PsiClass inheritor) { + //If psiClass contains only private members, then it is safe to remove it and change inheritor's extends/implements accordingly + if (justPrivates && (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList()))) { + usages.add(new SafeDeleteExtendsClassUsageInfo((PsiJavaCodeReferenceElement)element, psiClass, inheritor)); + return true; + } } - } + LOG.assertTrue(element.getTextRange() != null); + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, psiClass, isInNonStaticImport(element))); } - } - } - return false; - } + return true; + }); } - final PsiClass[] inners = aClass.getInnerClasses(); - for (PsiClass inner : inners) { - if (!inner.hasModifierProperty(PsiModifier.PRIVATE)) return false; + private static boolean isInNonStaticImport(PsiElement element) { + return ImportSearcher.getImport(element, true) != null; } - return true; - } - - private static void findTypeParameterExternalUsages(final PsiTypeParameter typeParameter, final Collection usages) { - PsiTypeParameterListOwner owner = typeParameter.getOwner(); - if (owner != null) { - final PsiTypeParameterList parameterList = owner.getTypeParameterList(); - if (parameterList != null) { - final int paramsCount = parameterList.getTypeParameters().length; - final int index = parameterList.getTypeParameterIndex(typeParameter); - - ReferencesSearch.search(owner).forEach(reference -> { - if (reference instanceof PsiJavaCodeReferenceElement javaCodeReferenceElement) { - final PsiReferenceParameterList parameterList1 = javaCodeReferenceElement.getParameterList(); - if (parameterList1 != null) { - PsiTypeElement[] typeArgs = parameterList1.getTypeParameterElements(); - if (typeArgs.length > index) { - if (typeArgs.length == 1 && paramsCount > 1 && typeArgs[0].getType() instanceof PsiDiamondType) { - return true; + @RequiredReadAction + private static boolean containsOnlyPrivates(final PsiClass aClass) { + final PsiField[] fields = aClass.getFields(); + for (PsiField field : fields) { + if (!field.hasModifierProperty(PsiModifier.PRIVATE)) { + return false; + } + } + + final PsiMethod[] methods = aClass.getMethods(); + for (PsiMethod method : methods) { + if (!method.hasModifierProperty(PsiModifier.PRIVATE)) { + if (method.isConstructor()) { //skip non-private constructors with call to super only + final PsiCodeBlock body = method.getBody(); + if (body != null) { + final PsiStatement[] statements = body.getStatements(); + if (statements.length == 0) { + continue; + } + if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement expressionStatement) { + final PsiExpression expression = expressionStatement.getExpression(); + if (expression instanceof PsiMethodCallExpression methodCallExpression) { + PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + if (methodExpression.getText().equals(PsiKeyword.SUPER)) { + continue; + } + } + } + } } - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(typeArgs[index], typeParameter, true)); - } + return false; } - } - return true; - }); - } - } - } - - @Nullable - @RequiredReadAction - private static Condition findMethodUsages( - PsiMethod psiMethod, - final PsiElement[] allElementsToDelete, - List usages - ) { - final Collection references = ReferencesSearch.search(psiMethod).findAll(); - - if (psiMethod.isConstructor()) { - return findConstructorUsages(psiMethod, references, usages, allElementsToDelete); - } - final PsiMethod[] overridingMethods = - removeDeletedMethods(OverridingMethodsSearch.search(psiMethod, true).toArray(PsiMethod.EMPTY_ARRAY), allElementsToDelete); + } - final HashMap> methodToReferences = new HashMap<>(); - for (PsiMethod overridingMethod : overridingMethods) { - final Collection overridingReferences = ReferencesSearch.search(overridingMethod).findAll(); - methodToReferences.put(overridingMethod, overridingReferences); - } - final Set validOverriding = validateOverridingMethods( - psiMethod, - references, - Arrays.asList(overridingMethods), - methodToReferences, - usages, - allElementsToDelete - ); - for (PsiReference reference : references) { - final PsiElement element = reference.getElement(); - if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) { - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo( - element, - psiMethod, - PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null - )); - } + final PsiClass[] inners = aClass.getInnerClasses(); + for (PsiClass inner : inners) { + if (!inner.hasModifierProperty(PsiModifier.PRIVATE)) { + return false; + } + } + + return true; } - return usage -> !(usage instanceof PsiFile) && (isInside(usage, allElementsToDelete) || isInside(usage, validOverriding)); - } - - private static PsiMethod[] removeDeletedMethods(PsiMethod[] methods, final PsiElement[] allElementsToDelete) { - ArrayList list = new ArrayList<>(); - for (PsiMethod method : methods) { - boolean isDeleted = false; - for (PsiElement element : allElementsToDelete) { - if (element == method) { - isDeleted = true; - break; - } - } - if (!isDeleted) { - list.add(method); - } + + private static void findTypeParameterExternalUsages(final PsiTypeParameter typeParameter, final Collection usages) { + PsiTypeParameterListOwner owner = typeParameter.getOwner(); + if (owner != null) { + final PsiTypeParameterList parameterList = owner.getTypeParameterList(); + if (parameterList != null) { + final int paramsCount = parameterList.getTypeParameters().length; + final int index = parameterList.getTypeParameterIndex(typeParameter); + + ReferencesSearch.search(owner).forEach(reference -> { + if (reference instanceof PsiJavaCodeReferenceElement javaCodeReferenceElement) { + final PsiReferenceParameterList parameterList1 = javaCodeReferenceElement.getParameterList(); + if (parameterList1 != null) { + PsiTypeElement[] typeArgs = parameterList1.getTypeParameterElements(); + if (typeArgs.length > index) { + if (typeArgs.length == 1 && paramsCount > 1 && typeArgs[0].getType() instanceof PsiDiamondType) { + return true; + } + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(typeArgs[index], typeParameter, true)); + } + } + } + return true; + }); + } + } } - return list.toArray(new PsiMethod[list.size()]); - } - - @Nullable - @RequiredReadAction - private static Condition findConstructorUsages( - PsiMethod constructor, Collection originalReferences, List usages, - final PsiElement[] allElementsToDelete - ) { - HashMap> constructorsToRefs = new HashMap<>(); - HashSet newConstructors = new HashSet<>(); - if (isTheOnlyEmptyDefaultConstructor(constructor)) return null; - - newConstructors.add(constructor); - constructorsToRefs.put(constructor, originalReferences); - HashSet passConstructors = new HashSet<>(); - do { - passConstructors.clear(); - for (PsiMethod method : newConstructors) { - final Collection references = constructorsToRefs.get(method); + + @Nullable + @RequiredReadAction + private static Condition findMethodUsages( + PsiMethod psiMethod, + final PsiElement[] allElementsToDelete, + List usages + ) { + final Collection references = ReferencesSearch.search(psiMethod).findAll(); + + if (psiMethod.isConstructor()) { + return findConstructorUsages(psiMethod, references, usages, allElementsToDelete); + } + final PsiMethod[] overridingMethods = + removeDeletedMethods(OverridingMethodsSearch.search(psiMethod, true).toArray(PsiMethod.EMPTY_ARRAY), allElementsToDelete); + + final HashMap> methodToReferences = new HashMap<>(); + for (PsiMethod overridingMethod : overridingMethods) { + final Collection overridingReferences = ReferencesSearch.search(overridingMethod).findAll(); + methodToReferences.put(overridingMethod, overridingReferences); + } + final Set validOverriding = validateOverridingMethods( + psiMethod, + references, + Arrays.asList(overridingMethods), + methodToReferences, + usages, + allElementsToDelete + ); for (PsiReference reference : references) { - PsiMethod overridingConstructor = getOverridingConstructorOfSuperCall(reference.getElement()); - if (overridingConstructor != null && !constructorsToRefs.containsKey(overridingConstructor)) { - Collection overridingConstructorReferences = ReferencesSearch.search(overridingConstructor).findAll(); - constructorsToRefs.put(overridingConstructor, overridingConstructorReferences); - passConstructors.add(overridingConstructor); - } - } - } - newConstructors.clear(); - newConstructors.addAll(passConstructors); - } - while (!newConstructors.isEmpty()); - - final Set validOverriding = validateOverridingMethods( - constructor, - originalReferences, - constructorsToRefs.keySet(), - constructorsToRefs, - usages, - allElementsToDelete - ); - - return usage -> !(usage instanceof PsiFile) && (isInside(usage, allElementsToDelete) || isInside(usage, validOverriding)); - } - - private static boolean isTheOnlyEmptyDefaultConstructor(final PsiMethod constructor) { - if (constructor.getParameterList().getParameters().length > 0) return false; - final PsiCodeBlock body = constructor.getBody(); - return !(body != null && body.getStatements().length > 0) && constructor.getContainingClass().getConstructors().length == 1; - } - - @RequiredReadAction - private static Set validateOverridingMethods( - PsiMethod originalMethod, - final Collection originalReferences, - Collection overridingMethods, - HashMap> methodToReferences, - List usages, - final PsiElement[] allElementsToDelete - ) { - Set validOverriding = new LinkedHashSet<>(overridingMethods); - Set multipleInterfaceImplementations = new HashSet<>(); - boolean anyNewBadRefs; - do { - anyNewBadRefs = false; - for (PsiMethod overridingMethod : overridingMethods) { - if (validOverriding.contains(overridingMethod)) { - final Collection overridingReferences = methodToReferences.get(overridingMethod); - boolean anyOverridingRefs = false; - for (final PsiReference overridingReference : overridingReferences) { - final PsiElement element = overridingReference.getElement(); + final PsiElement element = reference.getElement(); if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) { - anyOverridingRefs = true; - break; + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo( + element, + psiMethod, + PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null + )); } - } - if (!anyOverridingRefs && isMultipleInterfacesImplementation(overridingMethod, originalMethod, allElementsToDelete)) { - anyOverridingRefs = true; - multipleInterfaceImplementations.add(overridingMethod); - } + } + return usage -> !(usage instanceof PsiFile) && (isInside(usage, allElementsToDelete) || isInside(usage, validOverriding)); + } - if (anyOverridingRefs) { - validOverriding.remove(overridingMethod); - anyNewBadRefs = true; + private static PsiMethod[] removeDeletedMethods(PsiMethod[] methods, final PsiElement[] allElementsToDelete) { + ArrayList list = new ArrayList<>(); + for (PsiMethod method : methods) { + boolean isDeleted = false; + for (PsiElement element : allElementsToDelete) { + if (element == method) { + isDeleted = true; + break; + } + } + if (!isDeleted) { + list.add(method); + } + } + return list.toArray(new PsiMethod[list.size()]); + } + + @Nullable + @RequiredReadAction + private static Condition findConstructorUsages( + PsiMethod constructor, Collection originalReferences, List usages, + final PsiElement[] allElementsToDelete + ) { + HashMap> constructorsToRefs = new HashMap<>(); + HashSet newConstructors = new HashSet<>(); + if (isTheOnlyEmptyDefaultConstructor(constructor)) { + return null; + } - for (PsiReference reference : originalReferences) { - final PsiElement element = reference.getElement(); - if (!isInside(element, allElementsToDelete) && !isInside(element, overridingMethods)) { - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, originalMethod, false)); - validOverriding.clear(); - } + newConstructors.add(constructor); + constructorsToRefs.put(constructor, originalReferences); + HashSet passConstructors = new HashSet<>(); + do { + passConstructors.clear(); + for (PsiMethod method : newConstructors) { + final Collection references = constructorsToRefs.get(method); + for (PsiReference reference : references) { + PsiMethod overridingConstructor = getOverridingConstructorOfSuperCall(reference.getElement()); + if (overridingConstructor != null && !constructorsToRefs.containsKey(overridingConstructor)) { + Collection overridingConstructorReferences = ReferencesSearch.search(overridingConstructor).findAll(); + constructorsToRefs.put(overridingConstructor, overridingConstructorReferences); + passConstructors.add(overridingConstructor); + } + } } - } + newConstructors.clear(); + newConstructors.addAll(passConstructors); } - } - } - while (anyNewBadRefs && !validOverriding.isEmpty()); + while (!newConstructors.isEmpty()); - for (PsiMethod method : validOverriding) { - if (method != originalMethod) { + final Set validOverriding = validateOverridingMethods( + constructor, + originalReferences, + constructorsToRefs.keySet(), + constructorsToRefs, + usages, + allElementsToDelete + ); - usages.add(new SafeDeleteOverridingMethodUsageInfo(method, originalMethod)); - } + return usage -> !(usage instanceof PsiFile) && (isInside(usage, allElementsToDelete) || isInside(usage, validOverriding)); } - for (PsiMethod method : overridingMethods) { - if (!validOverriding.contains(method) && - !multipleInterfaceImplementations.contains(method) && - canBePrivate(method, methodToReferences.get(method), validOverriding, allElementsToDelete)) { - usages.add(new SafeDeletePrivatizeMethod(method, originalMethod)); - } else { - usages.add(new SafeDeleteOverrideAnnotation(method, originalMethod)); - } + private static boolean isTheOnlyEmptyDefaultConstructor(final PsiMethod constructor) { + if (constructor.getParameterList().getParameters().length > 0) { + return false; + } + final PsiCodeBlock body = constructor.getBody(); + return !(body != null && body.getStatements().length > 0) && constructor.getContainingClass().getConstructors().length == 1; + } + + @RequiredReadAction + private static Set validateOverridingMethods( + PsiMethod originalMethod, + final Collection originalReferences, + Collection overridingMethods, + HashMap> methodToReferences, + List usages, + final PsiElement[] allElementsToDelete + ) { + Set validOverriding = new LinkedHashSet<>(overridingMethods); + Set multipleInterfaceImplementations = new HashSet<>(); + boolean anyNewBadRefs; + do { + anyNewBadRefs = false; + for (PsiMethod overridingMethod : overridingMethods) { + if (validOverriding.contains(overridingMethod)) { + final Collection overridingReferences = methodToReferences.get(overridingMethod); + boolean anyOverridingRefs = false; + for (final PsiReference overridingReference : overridingReferences) { + final PsiElement element = overridingReference.getElement(); + if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) { + anyOverridingRefs = true; + break; + } + } + if (!anyOverridingRefs && isMultipleInterfacesImplementation(overridingMethod, originalMethod, allElementsToDelete)) { + anyOverridingRefs = true; + multipleInterfaceImplementations.add(overridingMethod); + } + + if (anyOverridingRefs) { + validOverriding.remove(overridingMethod); + anyNewBadRefs = true; + + for (PsiReference reference : originalReferences) { + final PsiElement element = reference.getElement(); + if (!isInside(element, allElementsToDelete) && !isInside(element, overridingMethods)) { + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, originalMethod, false)); + validOverriding.clear(); + } + } + } + } + } + } + while (anyNewBadRefs && !validOverriding.isEmpty()); + + for (PsiMethod method : validOverriding) { + if (method != originalMethod) { + + usages.add(new SafeDeleteOverridingMethodUsageInfo(method, originalMethod)); + } + } + + for (PsiMethod method : overridingMethods) { + if (!validOverriding.contains(method) && + !multipleInterfaceImplementations.contains(method) && + canBePrivate(method, methodToReferences.get(method), validOverriding, allElementsToDelete)) { + usages.add(new SafeDeletePrivatizeMethod(method, originalMethod)); + } + else { + usages.add(new SafeDeleteOverrideAnnotation(method, originalMethod)); + } + } + return validOverriding; + } + + private static boolean isMultipleInterfacesImplementation( + final PsiMethod method, + PsiMethod originalMethod, + final PsiElement[] allElementsToDelete + ) { + final PsiMethod[] methods = method.findSuperMethods(); + for (PsiMethod superMethod : methods) { + if (ArrayUtil.find(allElementsToDelete, superMethod) < 0 && !MethodSignatureUtil.isSuperMethod(originalMethod, superMethod)) { + return true; + } + } + return false; } - return validOverriding; - } - - private static boolean isMultipleInterfacesImplementation( - final PsiMethod method, - PsiMethod originalMethod, - final PsiElement[] allElementsToDelete - ) { - final PsiMethod[] methods = method.findSuperMethods(); - for (PsiMethod superMethod : methods) { - if (ArrayUtil.find(allElementsToDelete, superMethod) < 0 && !MethodSignatureUtil.isSuperMethod(originalMethod, superMethod)) { + + @Nullable + @RequiredReadAction + private static PsiMethod getOverridingConstructorOfSuperCall(final PsiElement element) { + if (element instanceof PsiReferenceExpression refExpr && "super".equals(element.getText()) + && refExpr.getParent() instanceof PsiMethodCallExpression methodCall + && methodCall.getParent() instanceof PsiExpressionStatement expr + && expr.getParent() instanceof PsiCodeBlock codeBlock + && codeBlock.getParent() instanceof PsiMethod method + && method.isConstructor()) { + return method; + } + return null; + } + + @RequiredReadAction + private static boolean canBePrivate( + PsiMethod method, + Collection references, + Collection deleted, + final PsiElement[] allElementsToDelete + ) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return false; + } + + PsiManager manager = method.getManager(); + final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); + final PsiElementFactory factory = facade.getElementFactory(); + final PsiModifierList privateModifierList; + try { + final PsiMethod newMethod = factory.createMethod("x3", PsiType.VOID); + privateModifierList = newMethod.getModifierList(); + privateModifierList.setModifierProperty(PsiModifier.PRIVATE, true); + } + catch (IncorrectOperationException e) { + LOG.assertTrue(false); + return false; + } + for (PsiReference reference : references) { + final PsiElement element = reference.getElement(); + if (!isInside(element, allElementsToDelete) && !isInside(element, deleted) + && !facade.getResolveHelper().isAccessible(method, privateModifierList, element, null, null)) { + return false; + } + } return true; - } } - return false; - } - - @Nullable - @RequiredReadAction - private static PsiMethod getOverridingConstructorOfSuperCall(final PsiElement element) { - if (element instanceof PsiReferenceExpression refExpr && "super".equals(element.getText()) - && refExpr.getParent() instanceof PsiMethodCallExpression methodCall - && methodCall.getParent() instanceof PsiExpressionStatement expr - && expr.getParent() instanceof PsiCodeBlock codeBlock - && codeBlock.getParent() instanceof PsiMethod method - && method.isConstructor()) { - return method; + + private static Condition findFieldUsages( + final PsiField psiField, + final List usages, + final PsiElement[] allElementsToDelete + ) { + final Condition isInsideDeleted = getUsageInsideDeletedFilter(allElementsToDelete); + ReferencesSearch.search(psiField).forEach(reference -> { + if (!isInsideDeleted.value(reference.getElement())) { + final PsiElement element = reference.getElement(); + final PsiElement parent = element.getParent(); + if (parent instanceof PsiAssignmentExpression assignment && element == assignment.getLExpression()) { + usages.add(new SafeDeleteFieldWriteReference(assignment, psiField)); + } + else { + TextRange range = reference.getRangeInElement(); + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo( + reference.getElement(), + psiField, + range.getStartOffset(), + range.getEndOffset(), + false, + PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null + )); + } + } + + return true; + }); + + return isInsideDeleted; } - return null; - } - - @RequiredReadAction - private static boolean canBePrivate( - PsiMethod method, - Collection references, - Collection deleted, - final PsiElement[] allElementsToDelete - ) { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass == null) { - return false; + + private static void findParameterUsages(final PsiParameter parameter, final List usages) { + final PsiMethod method = (PsiMethod)parameter.getDeclarationScope(); + //search for refs to current method only, do not search for refs to overriding methods, they'll be searched separately + ReferencesSearch.search(method).forEach(reference -> { + PsiElement element = reference.getElement(); + if (element != null) { + JavaSafeDeleteDelegate.forLanguage(element.getLanguage()).createUsageInfoForParameter(reference, usages, parameter, method); + } + return true; + }); + + ReferencesSearch.search(parameter).forEach(reference -> { + PsiElement element = reference.getElement(); + final PsiDocTag docTag = PsiTreeUtil.getParentOfType(element, PsiDocTag.class); + if (docTag != null) { + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(docTag, parameter, true)); + return true; + } + + boolean isSafeDelete = false; + if (element.getParent().getParent() instanceof PsiMethodCallExpression call) { + PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression.getText().equals(PsiKeyword.SUPER)) { + isSafeDelete = true; + } + else if (methodExpression.getQualifierExpression() instanceof PsiSuperExpression) { + final PsiMethod superMethod = call.resolveMethod(); + if (superMethod != null && MethodSignatureUtil.isSuperMethod(superMethod, method)) { + isSafeDelete = true; + } + } + } + + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, parameter, isSafeDelete)); + return true; + }); } - PsiManager manager = method.getManager(); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); - final PsiElementFactory factory = facade.getElementFactory(); - final PsiModifierList privateModifierList; - try { - final PsiMethod newMethod = factory.createMethod("x3", PsiType.VOID); - privateModifierList = newMethod.getModifierList(); - privateModifierList.setModifierProperty(PsiModifier.PRIVATE, true); - } catch (IncorrectOperationException e) { - LOG.assertTrue(false); - return false; + private static boolean isInside(PsiElement place, PsiElement[] ancestors) { + return isInside(place, Arrays.asList(ancestors)); } - for (PsiReference reference : references) { - final PsiElement element = reference.getElement(); - if (!isInside(element, allElementsToDelete) && !isInside(element, deleted) - && !facade.getResolveHelper().isAccessible(method, privateModifierList, element, null, null)) { + + private static boolean isInside(PsiElement place, Collection ancestors) { + for (PsiElement element : ancestors) { + if (isInside(place, element)) { + return true; + } + } return false; - } - } - return true; - } - - private static Condition findFieldUsages( - final PsiField psiField, - final List usages, - final PsiElement[] allElementsToDelete - ) { - final Condition isInsideDeleted = getUsageInsideDeletedFilter(allElementsToDelete); - ReferencesSearch.search(psiField).forEach(reference -> { - if (!isInsideDeleted.value(reference.getElement())) { - final PsiElement element = reference.getElement(); - final PsiElement parent = element.getParent(); - if (parent instanceof PsiAssignmentExpression assignment && element == assignment.getLExpression()) { - usages.add(new SafeDeleteFieldWriteReference(assignment, psiField)); - } else { - TextRange range = reference.getRangeInElement(); - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo( - reference.getElement(), - psiField, - range.getStartOffset(), - range.getEndOffset(), - false, - PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null - )); - } - } - - return true; - }); - - return isInsideDeleted; - } - - private static void findParameterUsages(final PsiParameter parameter, final List usages) { - final PsiMethod method = (PsiMethod) parameter.getDeclarationScope(); - //search for refs to current method only, do not search for refs to overriding methods, they'll be searched separately - ReferencesSearch.search(method).forEach(reference -> { - PsiElement element = reference.getElement(); - if (element != null) { - JavaSafeDeleteDelegate.forLanguage(element.getLanguage()).createUsageInfoForParameter(reference, usages, parameter, method); - } - return true; - }); - - ReferencesSearch.search(parameter).forEach(reference -> { - PsiElement element = reference.getElement(); - final PsiDocTag docTag = PsiTreeUtil.getParentOfType(element, PsiDocTag.class); - if (docTag != null) { - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(docTag, parameter, true)); - return true; - } - - boolean isSafeDelete = false; - if (element.getParent().getParent() instanceof PsiMethodCallExpression call) { - PsiReferenceExpression methodExpression = call.getMethodExpression(); - if (methodExpression.getText().equals(PsiKeyword.SUPER)) { - isSafeDelete = true; - } else if (methodExpression.getQualifierExpression() instanceof PsiSuperExpression) { - final PsiMethod superMethod = call.resolveMethod(); - if (superMethod != null && MethodSignatureUtil.isSuperMethod(superMethod, method)) { - isSafeDelete = true; - } - } - } - - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, parameter, isSafeDelete)); - return true; - }); - } - - private static boolean isInside(PsiElement place, PsiElement[] ancestors) { - return isInside(place, Arrays.asList(ancestors)); - } - - private static boolean isInside(PsiElement place, Collection ancestors) { - for (PsiElement element : ancestors) { - if (isInside(place, element)) return true; } - return false; - } - - public static boolean isInside(PsiElement place, PsiElement ancestor) { - if (SafeDeleteProcessor.isInside(place, ancestor)) return true; - if (PsiTreeUtil.getParentOfType(place, PsiComment.class, false) != null && ancestor instanceof PsiClass aClass) { - if (aClass.getParent() instanceof PsiJavaFile file) { - if (PsiTreeUtil.isAncestor(file, place, false)) { - if (file.getClasses().length == 1) { // file will be deleted on class deletion + + public static boolean isInside(PsiElement place, PsiElement ancestor) { + if (SafeDeleteProcessor.isInside(place, ancestor)) { return true; - } } - } - } + if (PsiTreeUtil.getParentOfType(place, PsiComment.class, false) != null && ancestor instanceof PsiClass aClass) { + if (aClass.getParent() instanceof PsiJavaFile file) { + if (PsiTreeUtil.isAncestor(file, place, false)) { + if (file.getClasses().length == 1) { // file will be deleted on class deletion + return true; + } + } + } + } - return false; - } + return false; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java index 86e07f2d7b..5197af7d68 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessor.java @@ -30,11 +30,12 @@ import consulo.language.util.IncorrectOperationException; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awt.Messages; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.usage.UsageViewUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.ArrayList; @@ -42,113 +43,128 @@ import java.util.Collections; public class TurnRefsToSuperProcessor extends TurnRefsToSuperProcessorBase { - private static final Logger LOG = Logger.getInstance(TurnRefsToSuperProcessor.class); - - private PsiClass mySuper; - public TurnRefsToSuperProcessor(Project project, - @Nonnull PsiClass aClass, - @Nonnull PsiClass aSuper, - boolean replaceInstanceOf) { - super(project, replaceInstanceOf, aSuper.getName()); - myClass = aClass; - mySuper = aSuper; - } - - protected String getCommandName() { - return RefactoringLocalize.turnRefsToSuperCommand( - DescriptiveNameUtil.getDescriptiveName(myClass), - DescriptiveNameUtil.getDescriptiveName(mySuper) - ).get(); - } - - @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { - return new RefsToSuperViewDescriptor(myClass, mySuper); - } - - private void setClasses(@Nonnull final PsiClass aClass, @Nonnull final PsiClass aSuper) { - myClass = aClass; - mySuper = aSuper; - } - - @Nonnull - protected UsageInfo[] findUsages() { - final PsiReference[] refs = ReferencesSearch.search(myClass, GlobalSearchScope.projectScope(myProject), false).toArray(new PsiReference[0]); - - final ArrayList result = detectTurnToSuperRefs(refs, new ArrayList()); - - final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); - return UsageViewUtil.removeDuplicatedUsages(usageInfos); - } - - protected void refreshElements(final PsiElement[] elements) { - LOG.assertTrue(elements.length == 2 && elements[0] instanceof PsiClass && elements[1] instanceof PsiClass); - setClasses ((PsiClass) elements[0], (PsiClass) elements[1]); - } - - protected boolean preprocessUsages(@Nonnull Ref refUsages) { - if (!ApplicationManager.getApplication().isUnitTestMode() && refUsages.get().length == 0) { - String message = RefactoringLocalize.noUsagesCanBeReplaced(myClass.getQualifiedName(), mySuper.getQualifiedName()).get(); - Messages.showInfoMessage(myProject, message, TurnRefsToSuperHandler.REFACTORING_NAME); - return false; + private static final Logger LOG = Logger.getInstance(TurnRefsToSuperProcessor.class); + + private PsiClass mySuper; + + public TurnRefsToSuperProcessor( + Project project, + @Nonnull PsiClass aClass, + @Nonnull PsiClass aSuper, + boolean replaceInstanceOf + ) { + super(project, replaceInstanceOf, aSuper.getName()); + myClass = aClass; + mySuper = aSuper; } - return super.preprocessUsages(refUsages); - } + protected String getCommandName() { + return RefactoringLocalize.turnRefsToSuperCommand( + DescriptiveNameUtil.getDescriptiveName(myClass), + DescriptiveNameUtil.getDescriptiveName(mySuper) + ).get(); + } + + @Nonnull + protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + return new RefsToSuperViewDescriptor(myClass, mySuper); + } + + private void setClasses(@Nonnull final PsiClass aClass, @Nonnull final PsiClass aSuper) { + myClass = aClass; + mySuper = aSuper; + } + + @Nonnull + protected UsageInfo[] findUsages() { + final PsiReference[] refs = + ReferencesSearch.search(myClass, GlobalSearchScope.projectScope(myProject), false).toArray(new PsiReference[0]); + + final ArrayList result = detectTurnToSuperRefs(refs, new ArrayList()); + + final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); + return UsageViewUtil.removeDuplicatedUsages(usageInfos); + } + + protected void refreshElements(final PsiElement[] elements) { + LOG.assertTrue(elements.length == 2 && elements[0] instanceof PsiClass && elements[1] instanceof PsiClass); + setClasses((PsiClass)elements[0], (PsiClass)elements[1]); + } - protected boolean canTurnToSuper(final PsiElement refElement) { - return super.canTurnToSuper(refElement) && - JavaPsiFacade.getInstance(myProject).getResolveHelper().isAccessible(mySuper, refElement, null); - } + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + if (!ApplicationManager.getApplication().isUnitTestMode() && refUsages.get().length == 0) { + String message = RefactoringLocalize.noUsagesCanBeReplaced(myClass.getQualifiedName(), mySuper.getQualifiedName()).get(); + Messages.showInfoMessage(myProject, message, TurnRefsToSuperHandler.REFACTORING_NAME); + return false; + } - protected void performRefactoring(UsageInfo[] usages) { - try { - final PsiClass aSuper = mySuper; - processTurnToSuperRefs(usages, aSuper); + return super.preprocessUsages(refUsages); + } - } catch (IncorrectOperationException e) { - LOG.error(e); + protected boolean canTurnToSuper(final PsiElement refElement) { + return super.canTurnToSuper(refElement) && + JavaPsiFacade.getInstance(myProject).getResolveHelper().isAccessible(mySuper, refElement, null); } - performVariablesRenaming(); - } - - protected boolean isInSuper(PsiElement member) { - if (!(member instanceof PsiMember)) return false; - final PsiManager manager = member.getManager(); - if (InheritanceUtil.isInheritorOrSelf(mySuper, ((PsiMember)member).getContainingClass(), true)) return true; - - if (member instanceof PsiField) { - final PsiClass containingClass = ((PsiField) member).getContainingClass(); - LanguageLevel languageLevel = PsiUtil.getLanguageLevel(member); - if (manager.areElementsEquivalent(containingClass, JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().getArrayClass(languageLevel))) { - return true; - } - } else if (member instanceof PsiMethod) { - return mySuper.findMethodBySignature((PsiMethod) member, true) != null; + protected void performRefactoring(UsageInfo[] usages) { + try { + final PsiClass aSuper = mySuper; + processTurnToSuperRefs(usages, aSuper); + + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + + performVariablesRenaming(); } - return false; - } + protected boolean isInSuper(PsiElement member) { + if (!(member instanceof PsiMember)) { + return false; + } + final PsiManager manager = member.getManager(); + if (InheritanceUtil.isInheritorOrSelf(mySuper, ((PsiMember)member).getContainingClass(), true)) { + return true; + } + + if (member instanceof PsiField) { + final PsiClass containingClass = ((PsiField)member).getContainingClass(); + LanguageLevel languageLevel = PsiUtil.getLanguageLevel(member); + if (manager.areElementsEquivalent( + containingClass, + JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().getArrayClass(languageLevel) + )) { + return true; + } + } + else if (member instanceof PsiMethod) { + return mySuper.findMethodBySignature((PsiMethod)member, true) != null; + } + + return false; + } - protected boolean isSuperInheritor(PsiClass aClass) { - return InheritanceUtil.isInheritorOrSelf(mySuper, aClass, true); - } + protected boolean isSuperInheritor(PsiClass aClass) { + return InheritanceUtil.isInheritorOrSelf(mySuper, aClass, true); + } - public PsiClass getSuper() { - return mySuper; - } + public PsiClass getSuper() { + return mySuper; + } - public PsiClass getTarget() { - return myClass; - } + public PsiClass getTarget() { + return myClass; + } - public boolean isReplaceInstanceOf() { - return myReplaceInstanceOf; - } + public boolean isReplaceInstanceOf() { + return myReplaceInstanceOf; + } - @Nonnull - protected Collection getElementsToWrite(@Nonnull final UsageViewDescriptor descriptor) { - return Collections.emptyList(); // neither myClass nor mySuper are subject to change, it's just references that are going to change - } + @Nonnull + protected Collection getElementsToWrite(@Nonnull final UsageViewDescriptor descriptor) { + return Collections.emptyList(); // neither myClass nor mySuper are subject to change, it's just references that are going to change + } } \ No newline at end of file diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java index a0f07f29be..b930c46ec6 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java @@ -44,10 +44,12 @@ import consulo.language.util.IncorrectOperationException; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.MoveRenameUsageInfo; import consulo.usage.UsageInfo; import consulo.util.collection.Queue; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; +import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.jetbrains.annotations.NonNls; @@ -57,729 +59,780 @@ * @author dsl */ public abstract class TurnRefsToSuperProcessorBase extends BaseRefactoringProcessor { - private static final Logger LOG = Logger.getInstance(TurnRefsToSuperProcessorBase.class); - protected PsiClass myClass; - protected final boolean myReplaceInstanceOf; - protected PsiManager myManager; - protected PsiSearchHelper mySearchHelper; - protected HashSet myMarkedNodes = new HashSet(); - private Queue myExpressionsQueue; - protected HashMap myElementToNode = new HashMap(); - protected Map myVariablesRenames = new HashMap(); - private final String mySuperClassName; - private final List myVariablesUsages = new ArrayList(); - - protected boolean preprocessUsages(Ref refUsages) { - UsageInfo[] usages = refUsages.get(); - List filtered = new ArrayList(); - for (UsageInfo usage : usages) { - if (usage instanceof TurnToSuperReferenceUsageInfo) { - filtered.add(usage); - } - } + private static final Logger LOG = Logger.getInstance(TurnRefsToSuperProcessorBase.class); + protected PsiClass myClass; + protected final boolean myReplaceInstanceOf; + protected PsiManager myManager; + protected PsiSearchHelper mySearchHelper; + protected HashSet myMarkedNodes = new HashSet(); + private Queue myExpressionsQueue; + protected HashMap myElementToNode = new HashMap(); + protected Map myVariablesRenames = new HashMap(); + private final String mySuperClassName; + private final List myVariablesUsages = new ArrayList(); + + @Override + @RequiredUIAccess + protected boolean preprocessUsages(@Nonnull SimpleReference refUsages) { + UsageInfo[] usages = refUsages.get(); + List filtered = new ArrayList(); + for (UsageInfo usage : usages) { + if (usage instanceof TurnToSuperReferenceUsageInfo) { + filtered.add(usage); + } + } + + myVariableRenamer = new AutomaticVariableRenamer(myClass, mySuperClassName, filtered); + if (!ApplicationManager.getApplication().isUnitTestMode() && + myVariableRenamer.hasAnythingToRename()) { + final AutomaticRenamingDialog dialog = new AutomaticRenamingDialog(myProject, myVariableRenamer); + dialog.show(); + if (!dialog.isOK()) { + return false; + } + + final List variables = myVariableRenamer.getElements(); + for (final PsiNamedElement namedElement : variables) { + final PsiVariable variable = (PsiVariable)namedElement; + final SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(variable); + myVariablesRenames.put(pointer, myVariableRenamer.getNewName(variable)); + } - myVariableRenamer = new AutomaticVariableRenamer(myClass, mySuperClassName, filtered); - if (!ApplicationManager.getApplication().isUnitTestMode() && - myVariableRenamer.hasAnythingToRename()) { - final AutomaticRenamingDialog dialog = new AutomaticRenamingDialog(myProject, myVariableRenamer); - dialog.show(); - if (!dialog.isOK()) return false; - - final List variables = myVariableRenamer.getElements(); - for (final PsiNamedElement namedElement : variables) { - final PsiVariable variable = (PsiVariable)namedElement; - final SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(variable); - myVariablesRenames.put(pointer, myVariableRenamer.getNewName(variable)); - } - - Runnable runnable = new Runnable() { - public void run() { - myVariableRenamer.findUsages(myVariablesUsages, false, false); - } - }; - - if (!ProgressManager.getInstance() - .runProcessWithProgressSynchronously(runnable, RefactoringLocalize.searchingForVariables().get(), true, myProject)) { - return false; - } + Runnable runnable = new Runnable() { + public void run() { + myVariableRenamer.findUsages(myVariablesUsages, false, false); + } + }; + + if (!ProgressManager.getInstance() + .runProcessWithProgressSynchronously(runnable, RefactoringLocalize.searchingForVariables().get(), true, myProject)) { + return false; + } + } + + prepareSuccessful(); + return true; } - prepareSuccessful(); - return true; - } - - private AutomaticVariableRenamer myVariableRenamer; - - protected void performVariablesRenaming() { - try { - //forget about smart pointers - Map variableRenames = new HashMap(); - for (Map.Entry entry : myVariablesRenames.entrySet()) { - variableRenames.put(entry.getKey().getElement(), entry.getValue()); - } - - for (UsageInfo usage : myVariablesUsages) { - if (usage instanceof MoveRenameUsageInfo) { - final MoveRenameUsageInfo renameUsageInfo = ((MoveRenameUsageInfo)usage); - final String newName = variableRenames.get(renameUsageInfo.getUpToDateReferencedElement()); - final PsiReference reference = renameUsageInfo.getReference(); - if (reference != null) { - reference.handleElementRename(newName); - } - } - } - - for (Map.Entry entry : myVariablesRenames.entrySet()) { - final String newName = entry.getValue(); - if (newName != null) { - final PsiVariable variable = (PsiVariable)entry.getKey().getElement(); - variable.setName(newName); - } - } + private AutomaticVariableRenamer myVariableRenamer; + + protected void performVariablesRenaming() { + try { + //forget about smart pointers + Map variableRenames = new HashMap(); + for (Map.Entry entry : myVariablesRenames.entrySet()) { + variableRenames.put(entry.getKey().getElement(), entry.getValue()); + } + + for (UsageInfo usage : myVariablesUsages) { + if (usage instanceof MoveRenameUsageInfo) { + final MoveRenameUsageInfo renameUsageInfo = ((MoveRenameUsageInfo)usage); + final String newName = variableRenames.get(renameUsageInfo.getUpToDateReferencedElement()); + final PsiReference reference = renameUsageInfo.getReference(); + if (reference != null) { + reference.handleElementRename(newName); + } + } + } + + for (Map.Entry entry : myVariablesRenames.entrySet()) { + final String newName = entry.getValue(); + if (newName != null) { + final PsiVariable variable = (PsiVariable)entry.getKey().getElement(); + variable.setName(newName); + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } - catch (IncorrectOperationException e) { - LOG.error(e); + + protected TurnRefsToSuperProcessorBase(Project project, boolean replaceInstanceOf, String superClassName) { + super(project); + mySuperClassName = superClassName; + myManager = PsiManager.getInstance(project); + mySearchHelper = PsiSearchHelper.SERVICE.getInstance(myManager.getProject()); + myManager = PsiManager.getInstance(myProject); + myReplaceInstanceOf = replaceInstanceOf; } - } - - protected TurnRefsToSuperProcessorBase(Project project, boolean replaceInstanceOf, String superClassName) { - super(project); - mySuperClassName = superClassName; - myManager = PsiManager.getInstance(project); - mySearchHelper = PsiSearchHelper.SERVICE.getInstance(myManager.getProject()); - myManager = PsiManager.getInstance(myProject); - myReplaceInstanceOf = replaceInstanceOf; - } - - protected ArrayList detectTurnToSuperRefs(PsiReference[] refs, final ArrayList result) { - buildGraph(refs); - - for (PsiReference ref : refs) { - final PsiElement element = ref.getElement(); - if (canTurnToSuper(element)) { - result.add(new TurnToSuperReferenceUsageInfo(element)); - } + + protected ArrayList detectTurnToSuperRefs(PsiReference[] refs, final ArrayList result) { + buildGraph(refs); + + for (PsiReference ref : refs) { + final PsiElement element = ref.getElement(); + if (canTurnToSuper(element)) { + result.add(new TurnToSuperReferenceUsageInfo(element)); + } + } + return result; } - return result; - } - protected boolean canTurnToSuper(PsiElement ref) { - return !myMarkedNodes.contains(ref); - } + protected boolean canTurnToSuper(PsiElement ref) { + return !myMarkedNodes.contains(ref); + } - protected static void processTurnToSuperRefs(UsageInfo[] usages, final PsiClass aSuper) throws IncorrectOperationException { - for (UsageInfo usage : usages) { - if (usage instanceof TurnToSuperReferenceUsageInfo) { - final PsiElement element = usage.getElement(); - if (element != null) { - final PsiReference ref = element.getReference(); - assert ref != null; - PsiElement newElement = ref.bindToElement(aSuper); + protected static void processTurnToSuperRefs(UsageInfo[] usages, final PsiClass aSuper) throws IncorrectOperationException { + for (UsageInfo usage : usages) { + if (usage instanceof TurnToSuperReferenceUsageInfo) { + final PsiElement element = usage.getElement(); + if (element != null) { + final PsiReference ref = element.getReference(); + assert ref != null; + PsiElement newElement = ref.bindToElement(aSuper); - if (newElement.getParent() instanceof PsiTypeElement) { - if (newElement.getParent().getParent() instanceof PsiTypeCastExpression) { - fixPossiblyRedundantCast((PsiTypeCastExpression)newElement.getParent().getParent()); + if (newElement.getParent() instanceof PsiTypeElement) { + if (newElement.getParent().getParent() instanceof PsiTypeCastExpression) { + fixPossiblyRedundantCast((PsiTypeCastExpression)newElement.getParent().getParent()); + } + } + } } - } } - } - } - } - - private static void fixPossiblyRedundantCast(PsiTypeCastExpression cast) throws IncorrectOperationException { - PsiTypeElement castTypeElement = cast.getCastType(); - if (castTypeElement == null) return; - PsiClass castClass = PsiUtil.resolveClassInType(castTypeElement.getType()); - if (castClass == null) return; - - PsiExpression operand = cast.getOperand(); - if (operand == null) return; - PsiClass operandClass = PsiUtil.resolveClassInType(RefactoringUtil.getTypeByExpression(operand)); - if (operandClass == null) return; - - if (!castClass.getManager().areElementsEquivalent(castClass, operandClass) && - !operandClass.isInheritor(castClass, true)) { - return; } - // OK, cast is redundant - PsiExpression exprToReplace = cast; - while (exprToReplace.getParent() instanceof PsiParenthesizedExpression) { - exprToReplace = (PsiExpression)exprToReplace.getParent(); + + private static void fixPossiblyRedundantCast(PsiTypeCastExpression cast) throws IncorrectOperationException { + PsiTypeElement castTypeElement = cast.getCastType(); + if (castTypeElement == null) { + return; + } + PsiClass castClass = PsiUtil.resolveClassInType(castTypeElement.getType()); + if (castClass == null) { + return; + } + + PsiExpression operand = cast.getOperand(); + if (operand == null) { + return; + } + PsiClass operandClass = PsiUtil.resolveClassInType(RefactoringUtil.getTypeByExpression(operand)); + if (operandClass == null) { + return; + } + + if (!castClass.getManager().areElementsEquivalent(castClass, operandClass) && + !operandClass.isInheritor(castClass, true)) { + return; + } + // OK, cast is redundant + PsiExpression exprToReplace = cast; + while (exprToReplace.getParent() instanceof PsiParenthesizedExpression) { + exprToReplace = (PsiExpression)exprToReplace.getParent(); + } + exprToReplace.replace(operand); } - exprToReplace.replace(operand); - } - - private void buildGraph(PsiReference[] refs) { - myMarkedNodes.clear(); - myExpressionsQueue = new Queue(refs.length); - myElementToNode.clear(); - for (PsiReference ref : refs) { - processUsage(ref.getElement()); + + private void buildGraph(PsiReference[] refs) { + myMarkedNodes.clear(); + myExpressionsQueue = new Queue(refs.length); + myElementToNode.clear(); + for (PsiReference ref : refs) { + processUsage(ref.getElement()); + } + + processQueue(); + + markNodes(); + + spreadMarks(); } - processQueue(); + private void processUsage(PsiElement ref) { + if (ref instanceof PsiReferenceExpression) { + final PsiElement parent = ref.getParent(); + if (parent instanceof PsiReferenceExpression) { + final PsiReferenceExpression refExpr = (PsiReferenceExpression)parent; + final PsiElement refMember = refExpr.resolve(); + if (!isInSuper(refMember)) { + markNode(ref); + } + } + return; + } - markNodes(); + PsiElement parent = ref.getParent(); + if (parent instanceof PsiTypeElement) { + PsiElement pparent = parent.getParent(); + while (pparent instanceof PsiTypeElement) { + addLink(pparent, parent); + addLink(parent, pparent); + parent = pparent; + pparent = parent.getParent(); + } + final PsiTypeElement typeElement = (PsiTypeElement)parent; - spreadMarks(); - } + addLink(typeElement, ref); + addLink(ref, typeElement); - private void processUsage(PsiElement ref) { - if (ref instanceof PsiReferenceExpression) { - final PsiElement parent = ref.getParent(); - if (parent instanceof PsiReferenceExpression) { - final PsiReferenceExpression refExpr = (PsiReferenceExpression)parent; - final PsiElement refMember = refExpr.resolve(); - if (!isInSuper(refMember)) { - markNode(ref); + if (pparent instanceof PsiVariable) { + processVariableType((PsiVariable)pparent); + } + else if (pparent instanceof PsiMethod) { + processMethodReturnType((PsiMethod)pparent); + } + else if (pparent instanceof PsiTypeCastExpression) { + addLink(pparent, typeElement); + addLink(typeElement, pparent); + } + else if (pparent instanceof PsiReferenceParameterList) { + final PsiReferenceParameterList refParameterList = ((PsiReferenceParameterList)pparent); + final PsiElement ppparent = pparent.getParent(); + if (ppparent instanceof PsiJavaCodeReferenceElement) { + final PsiJavaCodeReferenceElement classReference = (PsiJavaCodeReferenceElement)ppparent; + if (classReference.getParent() instanceof PsiReferenceList) { + final PsiReferenceList referenceList = ((PsiReferenceList)ppparent.getParent()); + final PsiClass parentClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); + if (parentClass != null) { + if (referenceList.equals(parentClass.getExtendsList()) || referenceList.equals(parentClass.getImplementsList())) { + final PsiTypeElement[] typeParameterElements = refParameterList.getTypeParameterElements(); + for (int i = 0; i < typeParameterElements.length; i++) { + if (typeParameterElements[i] == typeElement) { + final PsiElement resolved = classReference.resolve(); + if (resolved instanceof PsiClass) { + final PsiTypeParameter[] typeParameters = ((PsiClass)resolved).getTypeParameters(); + if (typeParameters.length > i) { + linkTypeParameterInstantiations(typeParameters[i], typeElement, parentClass); + return; + } + } + } + } + } + } + } + else if (classReference.getParent() instanceof PsiTypeElement) { + processUsage(classReference); + return; + } + else if (classReference.getParent() instanceof PsiNewExpression) { + final PsiVariable variable = PsiTreeUtil.getParentOfType(classReference, PsiVariable.class); + if (variable != null) { + processUsage(variable); + return; + } + } + else if (classReference.getParent() instanceof PsiAnonymousClass) { + processUsage(classReference); + return; + } + } + markNode(ref); //??? + } + } + else if (parent instanceof PsiNewExpression) { + PsiNewExpression newExpression = (PsiNewExpression)parent; + if (newExpression.getType() instanceof PsiArrayType) { + addLink(newExpression, ref); + addLink(ref, newExpression); + PsiArrayInitializerExpression initializer = newExpression.getArrayInitializer(); + if (initializer != null) { + addLink(ref, initializer); + } + checkToArray(ref, newExpression); + } + else { + markNode(ref); + } + } + else if (parent instanceof PsiJavaCodeReferenceElement && ref.equals(((PsiJavaCodeReferenceElement)parent).getQualifier())) { + final PsiElement resolved = ((PsiJavaCodeReferenceElement)parent).resolve(); + if (resolved == null || !isInSuper(resolved)) { + markNode(ref); + } + } + else { + markNode(ref); } - } - return; } - PsiElement parent = ref.getParent(); - if (parent instanceof PsiTypeElement) { - PsiElement pparent = parent.getParent(); - while (pparent instanceof PsiTypeElement) { - addLink(pparent, parent); - addLink(parent, pparent); - parent = pparent; - pparent = parent.getParent(); - } - final PsiTypeElement typeElement = (PsiTypeElement)parent; - - addLink(typeElement, ref); - addLink(ref, typeElement); - - if (pparent instanceof PsiVariable) { - processVariableType((PsiVariable)pparent); - } - else if (pparent instanceof PsiMethod) { - processMethodReturnType((PsiMethod)pparent); - } - else if (pparent instanceof PsiTypeCastExpression) { - addLink(pparent, typeElement); - addLink(typeElement, pparent); - } - else if (pparent instanceof PsiReferenceParameterList) { - final PsiReferenceParameterList refParameterList = ((PsiReferenceParameterList)pparent); - final PsiElement ppparent = pparent.getParent(); - if (ppparent instanceof PsiJavaCodeReferenceElement) { - final PsiJavaCodeReferenceElement classReference = (PsiJavaCodeReferenceElement)ppparent; - if (classReference.getParent() instanceof PsiReferenceList) { - final PsiReferenceList referenceList = ((PsiReferenceList)ppparent.getParent()); - final PsiClass parentClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); - if (parentClass != null) { - if (referenceList.equals(parentClass.getExtendsList()) || referenceList.equals(parentClass.getImplementsList())) { - final PsiTypeElement[] typeParameterElements = refParameterList.getTypeParameterElements(); - for (int i = 0; i < typeParameterElements.length; i++) { - if (typeParameterElements[i] == typeElement) { - final PsiElement resolved = classReference.resolve(); - if (resolved instanceof PsiClass) { - final PsiTypeParameter[] typeParameters = ((PsiClass)resolved).getTypeParameters(); - if (typeParameters.length > i) { - linkTypeParameterInstantiations(typeParameters[i], typeElement, parentClass); - return; - } + private void linkTypeParameterInstantiations( + PsiTypeParameter typeParameter, + final PsiTypeElement instantiation, + final PsiClass inheritingClass + ) { + final PsiTypeParameterListOwner owner = typeParameter.getOwner(); + if (owner instanceof PsiClass) { + final PsiClass ownerClass = ((PsiClass)owner); + final LocalSearchScope derivedScope = new LocalSearchScope(inheritingClass); + final PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(ownerClass, inheritingClass, PsiSubstitutor.EMPTY); + if (substitutor == null) { + return; + } + final LocalSearchScope baseScope = new LocalSearchScope(ownerClass); + ReferencesSearch.search(typeParameter, baseScope).forEach(new Processor() { + public boolean process(final PsiReference ref) { + final PsiElement element = ref.getElement(); + final PsiElement parent = element.getParent(); + if (parent instanceof PsiTypeElement) { + final PsiElement pparent = parent.getParent(); + if (pparent instanceof PsiMethod && parent.equals(((PsiMethod)pparent).getReturnTypeElement())) { + final PsiMethod method = (PsiMethod)pparent; + final MethodSignature signature = method.getSignature(substitutor); + if (PsiUtil.isAccessible(method, inheritingClass, null)) { + final PsiMethod inInheritor = MethodSignatureUtil.findMethodBySignature(inheritingClass, signature, false); + if (inInheritor != null && inInheritor.getReturnTypeElement() != null) { + addLink(instantiation, method.getReturnTypeElement()); + addLink(method.getReturnTypeElement(), instantiation); + } + } + } + else if (pparent instanceof PsiParameter) { + final PsiParameter parameter = (PsiParameter)pparent; + if (parameter.getDeclarationScope() instanceof PsiMethod) { + PsiMethod method = (PsiMethod)parameter.getDeclarationScope(); + final int index = ((PsiParameterList)parameter.getParent()).getParameterIndex(parameter); + final MethodSignature signature = method.getSignature(substitutor); + if (PsiUtil.isAccessible(method, inheritingClass, null)) { + final PsiMethod inInheritor = + MethodSignatureUtil.findMethodBySignature(inheritingClass, signature, false); + if (inInheritor != null) { + final PsiParameter[] inheritorParams = inInheritor.getParameterList().getParameters(); + LOG.assertTrue(inheritorParams.length > index); + final PsiTypeElement hisTypeElement = inheritorParams[index].getTypeElement(); + addLink(instantiation, hisTypeElement); + addLink(hisTypeElement, instantiation); + } + } + } + } } - } + + return true; } - } + }); + } + } + + private void addArgumentParameterLink(PsiElement arg, PsiExpressionList actualArgsList, PsiMethod method) { + PsiParameter[] params = method.getParameterList().getParameters(); + PsiExpression[] actualArgs = actualArgsList.getExpressions(); + int argIndex = -1; + for (int i = 0; i < actualArgs.length; i++) { + PsiExpression actualArg = actualArgs[i]; + if (actualArg.equals(arg)) { + argIndex = i; + break; } - } else if (classReference.getParent() instanceof PsiTypeElement) { - processUsage(classReference); + } + + if (argIndex >= 0 && argIndex < params.length) { + addLink(params[argIndex], arg); + } + else if (method.isVarArgs() && argIndex >= params.length) { + addLink(params[params.length - 1], arg); + } + } + + private void checkToArray(PsiElement ref, PsiNewExpression newExpression) { + PsiElement tmp; + + final PsiClass javaUtilCollectionClass = + JavaPsiFacade.getInstance(myManager.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, ref.getResolveScope()); + if (javaUtilCollectionClass == null) { + return; + } + tmp = newExpression.getParent(); + if (!(tmp instanceof PsiExpressionList)) { return; - } else if (classReference.getParent() instanceof PsiNewExpression) { - final PsiVariable variable = PsiTreeUtil.getParentOfType(classReference, PsiVariable.class); - if (variable != null) { - processUsage(variable); - return; - } - } else if (classReference.getParent() instanceof PsiAnonymousClass) { - processUsage(classReference); + } + tmp = tmp.getParent(); + if (!(tmp instanceof PsiMethodCallExpression)) { + return; + } + PsiMethodCallExpression methodCall = (PsiMethodCallExpression)tmp; + tmp = tmp.getParent(); + if (!(tmp instanceof PsiTypeCastExpression)) { return; - } } - markNode(ref); //??? - } + PsiTypeCastExpression typeCast = (PsiTypeCastExpression)tmp; + + PsiReferenceExpression methodRef = methodCall.getMethodExpression(); + tmp = methodRef.resolve(); + if (!(tmp instanceof PsiMethod)) { + return; + } + PsiMethod method = (PsiMethod)tmp; + @NonNls final String name = method.getName(); + if (!name.equals("toArray")) { + return; + } + + PsiClass methodClass = method.getContainingClass(); + if (!methodClass.isInheritor(javaUtilCollectionClass, true)) { + return; + } + + // ok, this is an implementation of java.util.Collection.toArray + addLink(typeCast, ref); + } - else if (parent instanceof PsiNewExpression) { - PsiNewExpression newExpression = (PsiNewExpression)parent; - if (newExpression.getType() instanceof PsiArrayType) { - addLink(newExpression, ref); - addLink(ref, newExpression); - PsiArrayInitializerExpression initializer = newExpression.getArrayInitializer(); + + private void processVariableType(PsiVariable variable) { + final PsiTypeElement type = variable.getTypeElement(); + final PsiExpression initializer = variable.getInitializer(); if (initializer != null) { - addLink(ref, initializer); + addLink(type, initializer); } - checkToArray(ref, newExpression); - } - else { - markNode(ref); - } - } - else if (parent instanceof PsiJavaCodeReferenceElement && ref.equals(((PsiJavaCodeReferenceElement)parent).getQualifier())) { - final PsiElement resolved = ((PsiJavaCodeReferenceElement)parent).resolve(); - if (resolved == null || !isInSuper(resolved)) { - markNode(ref); - } - } - else { - markNode(ref); - } - } - - private void linkTypeParameterInstantiations (PsiTypeParameter typeParameter, final PsiTypeElement instantiation, final PsiClass inheritingClass) { - final PsiTypeParameterListOwner owner = typeParameter.getOwner(); - if (owner instanceof PsiClass) { - final PsiClass ownerClass = ((PsiClass)owner); - final LocalSearchScope derivedScope = new LocalSearchScope(inheritingClass); - final PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(ownerClass, inheritingClass, PsiSubstitutor.EMPTY); - if (substitutor == null) return; - final LocalSearchScope baseScope = new LocalSearchScope(ownerClass); - ReferencesSearch.search(typeParameter, baseScope).forEach(new Processor() { - public boolean process(final PsiReference ref) { - final PsiElement element = ref.getElement(); - final PsiElement parent = element.getParent(); - if (parent instanceof PsiTypeElement) { - final PsiElement pparent = parent.getParent(); - if (pparent instanceof PsiMethod && parent.equals(((PsiMethod)pparent).getReturnTypeElement())) { - final PsiMethod method = (PsiMethod)pparent; - final MethodSignature signature = method.getSignature(substitutor); - if (PsiUtil.isAccessible(method, inheritingClass, null)) { - final PsiMethod inInheritor = MethodSignatureUtil.findMethodBySignature(inheritingClass, signature, false); - if (inInheritor != null && inInheritor.getReturnTypeElement() != null) { - addLink(instantiation, method.getReturnTypeElement()); - addLink(method.getReturnTypeElement(), instantiation); + + for (PsiReference ref : ReferencesSearch.search(variable)) { + final PsiElement element = ref.getElement(); + addLink(element, type); + addLink(type, element); + analyzeVarUsage(element); + } + + if (variable instanceof PsiParameter) { + final PsiElement declScope = ((PsiParameter)variable).getDeclarationScope(); + if (declScope instanceof PsiCatchSection) { + markNode(type); + } + else if (declScope instanceof PsiForeachStatement) { + final PsiExpression iteratedValue = ((PsiForeachStatement)declScope).getIteratedValue(); + addLink(type, iteratedValue); + addLink(iteratedValue, type); + } + else if (declScope instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)declScope; + final int index = method.getParameterList().getParameterIndex((PsiParameter)variable); + + { + for (PsiReference call : ReferencesSearch.search(method)) { + PsiElement ref = call.getElement(); + PsiExpressionList argumentList; + if (ref.getParent() instanceof PsiCall) { + argumentList = ((PsiCall)ref.getParent()).getArgumentList(); + } + else if (ref.getParent() instanceof PsiAnonymousClass) { + argumentList = ((PsiConstructorCall)ref.getParent().getParent()).getArgumentList(); + } + else { + continue; + } + if (argumentList == null) { + continue; + } + PsiExpression[] args = argumentList.getExpressions(); + if (index >= args.length) { + continue; + } + addLink(type, args[index]); + } } - } - } else if (pparent instanceof PsiParameter) { - final PsiParameter parameter = (PsiParameter)pparent; - if (parameter.getDeclarationScope() instanceof PsiMethod) { - PsiMethod method = (PsiMethod)parameter.getDeclarationScope(); - final int index = ((PsiParameterList)parameter.getParent()).getParameterIndex(parameter); - final MethodSignature signature = method.getSignature(substitutor); - if (PsiUtil.isAccessible(method, inheritingClass, null)) { - final PsiMethod inInheritor = MethodSignatureUtil.findMethodBySignature(inheritingClass, signature, false); - if (inInheritor != null) { - final PsiParameter[] inheritorParams = inInheritor.getParameterList().getParameters(); - LOG.assertTrue(inheritorParams.length > index); - final PsiTypeElement hisTypeElement = inheritorParams[index].getTypeElement(); - addLink(instantiation, hisTypeElement); - addLink(hisTypeElement, instantiation); - } + + final class Inner { + void linkInheritors(final PsiMethod[] methods) { + for (final PsiMethod superMethod : methods) { + final PsiParameter[] parameters = superMethod.getParameterList().getParameters(); + if (index >= parameters.length) { + continue; + } + final PsiTypeElement superType = parameters[index].getTypeElement(); + addLink(superType, type); + addLink(type, superType); + } + } } - } - } - } - return true; + final PsiMethod[] superMethods = method.findSuperMethods(); + new Inner().linkInheritors(superMethods); + PsiClass containingClass = method.getContainingClass(); + List subClasses = new ArrayList(ClassInheritorsSearch.search(containingClass, false).findAll()); + // ??? In the theory this is non-efficient way: too many inheritors can be processed. + // ??? But in real use it seems reasonably fast. If poor performance problems emerged, + // ??? should be optimized + for (int i1 = 0; i1 != subClasses.size(); ++i1) { + final PsiMethod[] mBSs = subClasses.get(i1).findMethodsBySignature(method, true); + new Inner().linkInheritors(mBSs); + } + } + else { + LOG.error("Unexpected scope: " + declScope); + } + } + else if (variable instanceof PsiResourceVariable) { + final PsiJavaParserFacade facade = JavaPsiFacade.getInstance(myProject).getParserFacade(); + checkConstrainingType(type, facade.createTypeFromText(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, variable)); } - }); - } - } - - private void addArgumentParameterLink(PsiElement arg, PsiExpressionList actualArgsList, PsiMethod method) { - PsiParameter[] params = method.getParameterList().getParameters(); - PsiExpression[] actualArgs = actualArgsList.getExpressions(); - int argIndex = -1; - for (int i = 0; i < actualArgs.length; i++) { - PsiExpression actualArg = actualArgs[i]; - if (actualArg.equals(arg)) { - argIndex = i; - break; - } } - if (argIndex >= 0 && argIndex < params.length) { - addLink(params[argIndex], arg); - } - else if (method.isVarArgs() && argIndex >= params.length) { - addLink(params[params.length - 1], arg); - } - } - - private void checkToArray(PsiElement ref, PsiNewExpression newExpression) { - PsiElement tmp; - - final PsiClass javaUtilCollectionClass = - JavaPsiFacade.getInstance(myManager.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, ref.getResolveScope()); - if (javaUtilCollectionClass == null) return; - tmp = newExpression.getParent(); - if (!(tmp instanceof PsiExpressionList)) return; - tmp = tmp.getParent(); - if (!(tmp instanceof PsiMethodCallExpression)) return; - PsiMethodCallExpression methodCall = (PsiMethodCallExpression)tmp; - tmp = tmp.getParent(); - if (!(tmp instanceof PsiTypeCastExpression)) return; - PsiTypeCastExpression typeCast = (PsiTypeCastExpression)tmp; - - PsiReferenceExpression methodRef = methodCall.getMethodExpression(); - tmp = methodRef.resolve(); - if (!(tmp instanceof PsiMethod)) return; - PsiMethod method = (PsiMethod)tmp; - @NonNls final String name = method.getName(); - if (!name.equals("toArray")) return; - - PsiClass methodClass = method.getContainingClass(); - if (!methodClass.isInheritor(javaUtilCollectionClass, true)) return; - - // ok, this is an implementation of java.util.Collection.toArray - addLink(typeCast, ref); - - } - - private void processVariableType(PsiVariable variable) { - final PsiTypeElement type = variable.getTypeElement(); - final PsiExpression initializer = variable.getInitializer(); - if (initializer != null) { - addLink(type, initializer); + private void analyzeVarUsage(final PsiElement element) { + PsiType constrainingType = null; + + final PsiElement parent = element.getParent(); + if (parent instanceof PsiReturnStatement) { + final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); + assert method != null; + constrainingType = method.getReturnType(); + } + else if (parent instanceof PsiAssignmentExpression) { + constrainingType = ((PsiAssignmentExpression)parent).getLExpression().getType(); + } + //todo[ann] this works for AImpl->A but fails on List (see testForEach1() and testIDEADEV23807()). + //else if (parent instanceof PsiForeachStatement) { + // final PsiType exprType = ((PsiExpression)element).getType(); + // if (!(exprType instanceof PsiArrayType)) { + // final PsiJavaParserFacade facade = JavaPsiFacade.getInstance(myProject).getParserFacade(); + // constrainingType = facade.createTypeFromText(CommonClassNames.JAVA_LANG_ITERABLE, parent); + // } + //} + else if (parent instanceof PsiLocalVariable) { + constrainingType = ((PsiLocalVariable)parent).getType(); + } + + checkConstrainingType(element, constrainingType); } - for (PsiReference ref : ReferencesSearch.search(variable)) { - final PsiElement element = ref.getElement(); - addLink(element, type); - addLink(type, element); - analyzeVarUsage(element); + private void checkConstrainingType(PsiElement element, @Nullable PsiType constrainingType) { + if (constrainingType instanceof PsiClassType) { + final PsiClass resolved = ((PsiClassType)constrainingType).resolve(); + if (!myClass.equals(resolved)) { + if (resolved == null || !isSuperInheritor(resolved)) { + markNode(element); + } + } + } } - if (variable instanceof PsiParameter) { - final PsiElement declScope = ((PsiParameter)variable).getDeclarationScope(); - if (declScope instanceof PsiCatchSection) { - markNode(type); - } - else if (declScope instanceof PsiForeachStatement) { - final PsiExpression iteratedValue = ((PsiForeachStatement)declScope).getIteratedValue(); - addLink(type, iteratedValue); - addLink(iteratedValue, type); - } - else if (declScope instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)declScope; - final int index = method.getParameterList().getParameterIndex((PsiParameter)variable); - - { - for (PsiReference call : ReferencesSearch.search(method)) { - PsiElement ref = call.getElement(); - PsiExpressionList argumentList; - if (ref.getParent() instanceof PsiCall) { - argumentList = ((PsiCall)ref.getParent()).getArgumentList(); - } - else if (ref.getParent() instanceof PsiAnonymousClass) { - argumentList = ((PsiConstructorCall)ref.getParent().getParent()).getArgumentList(); + private void processMethodReturnType(final PsiMethod method) { + final PsiTypeElement returnType = method.getReturnTypeElement(); + for (PsiReference call : ReferencesSearch.search(method)) { + final PsiElement ref = call.getElement(); + if (PsiTreeUtil.getParentOfType(ref, PsiDocComment.class) != null) { + continue; } - else { - continue; + final PsiElement parent = ref.getParent(); + addLink(parent, returnType); + } + + final PsiReturnStatement[] returnStatements = RefactoringUtil.findReturnStatements(method); + for (final PsiReturnStatement returnStatement : returnStatements) { + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue != null) { + addLink(returnType, returnValue); } - if (argumentList == null) continue; - PsiExpression[] args = argumentList.getExpressions(); - if (index >= args.length) continue; - addLink(type, args[index]); - } } + final PsiMethod[] superMethods = method.findSuperMethods(); final class Inner { - void linkInheritors(final PsiMethod[] methods) { - for (final PsiMethod superMethod : methods) { - final PsiParameter[] parameters = superMethod.getParameterList().getParameters(); - if (index >= parameters.length) continue; - final PsiTypeElement superType = parameters[index].getTypeElement(); - addLink(superType, type); - addLink(type, superType); + public void linkInheritors(final PsiMethod[] methods) { + for (final PsiMethod superMethod : methods) { + final PsiTypeElement superType = superMethod.getReturnTypeElement(); + addLink(superType, returnType); + addLink(returnType, superType); + } } - } } - final PsiMethod[] superMethods = method.findSuperMethods(); new Inner().linkInheritors(superMethods); - PsiClass containingClass = method.getContainingClass(); - List subClasses = new ArrayList(ClassInheritorsSearch.search(containingClass, false).findAll()); - // ??? In the theory this is non-efficient way: too many inheritors can be processed. + // ??? In the theory this is non-efficient way: too many inheritors can be processed (and multiple times). // ??? But in real use it seems reasonably fast. If poor performance problems emerged, // ??? should be optimized - for (int i1 = 0; i1 != subClasses.size(); ++i1) { - final PsiMethod[] mBSs = subClasses.get(i1).findMethodsBySignature(method, true); - new Inner().linkInheritors(mBSs); - } - } - else { - LOG.error("Unexpected scope: " + declScope); - } - } - else if (variable instanceof PsiResourceVariable) { - final PsiJavaParserFacade facade = JavaPsiFacade.getInstance(myProject).getParserFacade(); - checkConstrainingType(type, facade.createTypeFromText(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, variable)); - } - } - - private void analyzeVarUsage(final PsiElement element) { - PsiType constrainingType = null; - - final PsiElement parent = element.getParent(); - if (parent instanceof PsiReturnStatement) { - final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); - assert method != null; - constrainingType = method.getReturnType(); - } - else if (parent instanceof PsiAssignmentExpression) { - constrainingType = ((PsiAssignmentExpression)parent).getLExpression().getType(); - } - //todo[ann] this works for AImpl->A but fails on List (see testForEach1() and testIDEADEV23807()). - //else if (parent instanceof PsiForeachStatement) { - // final PsiType exprType = ((PsiExpression)element).getType(); - // if (!(exprType instanceof PsiArrayType)) { - // final PsiJavaParserFacade facade = JavaPsiFacade.getInstance(myProject).getParserFacade(); - // constrainingType = facade.createTypeFromText(CommonClassNames.JAVA_LANG_ITERABLE, parent); - // } - //} - else if (parent instanceof PsiLocalVariable) { - constrainingType = ((PsiLocalVariable)parent).getType(); - } - - checkConstrainingType(element, constrainingType); - } - - private void checkConstrainingType(PsiElement element, @Nullable PsiType constrainingType) { - if (constrainingType instanceof PsiClassType) { - final PsiClass resolved = ((PsiClassType)constrainingType).resolve(); - if (!myClass.equals(resolved)) { - if (resolved == null || !isSuperInheritor(resolved)) { - markNode(element); + PsiClass containingClass = method.getContainingClass(); + final PsiClass[] subClasses = ClassInheritorsSearch.search(containingClass, false).toArray(PsiClass.EMPTY_ARRAY); + for (int i1 = 0; i1 != subClasses.length; ++i1) { + final PsiMethod[] mBSs = subClasses[i1].findMethodsBySignature(method, true); + new Inner().linkInheritors(mBSs); } - } - } - } - - private void processMethodReturnType(final PsiMethod method) { - final PsiTypeElement returnType = method.getReturnTypeElement(); - for (PsiReference call : ReferencesSearch.search(method)) { - final PsiElement ref = call.getElement(); - if (PsiTreeUtil.getParentOfType(ref, PsiDocComment.class) != null) continue; - final PsiElement parent = ref.getParent(); - addLink(parent, returnType); - } - - final PsiReturnStatement[] returnStatements = RefactoringUtil.findReturnStatements(method); - for (final PsiReturnStatement returnStatement : returnStatements) { - final PsiExpression returnValue = returnStatement.getReturnValue(); - if (returnValue != null) { - addLink(returnType, returnValue); - } } - final PsiMethod[] superMethods = method.findSuperMethods(); - final class Inner { - public void linkInheritors(final PsiMethod[] methods) { - for (final PsiMethod superMethod : methods) { - final PsiTypeElement superType = superMethod.getReturnTypeElement(); - addLink(superType, returnType); - addLink(returnType, superType); + private void processQueue() { + while (!myExpressionsQueue.isEmpty()) { + PsiExpression expr = myExpressionsQueue.pullFirst(); + PsiElement parent = expr.getParent(); + if (parent instanceof PsiAssignmentExpression) { + PsiAssignmentExpression assignment = (PsiAssignmentExpression)parent; + if (assignment.getRExpression() != null) { + addLink(assignment.getLExpression(), assignment.getRExpression()); + } + addLink(assignment, assignment.getLExpression()); + addLink(assignment.getLExpression(), assignment); + } + else if (parent instanceof PsiArrayAccessExpression) { + PsiArrayAccessExpression arrayAccess = (PsiArrayAccessExpression)parent; + if (expr.equals(arrayAccess.getArrayExpression())) { + addLink(arrayAccess, expr); + addLink(expr, arrayAccess); + } + } + else if (parent instanceof PsiParenthesizedExpression) { + addLink(parent, expr); + addLink(expr, parent); + } + else if (parent instanceof PsiArrayInitializerExpression) { + PsiArrayInitializerExpression arrayInitializerExpr = (PsiArrayInitializerExpression)parent; + PsiExpression[] initializers = arrayInitializerExpr.getInitializers(); + for (PsiExpression initializer : initializers) { + addLink(arrayInitializerExpr, initializer); + } + } + else if (parent instanceof PsiExpressionList) { + PsiElement pparent = parent.getParent(); + if (pparent instanceof PsiCallExpression) { + PsiMethod method = ((PsiCallExpression)pparent).resolveMethod(); + if (method != null) { + addArgumentParameterLink(expr, (PsiExpressionList)parent, method); + } + } + } } - } } - new Inner().linkInheritors(superMethods); - // ??? In the theory this is non-efficient way: too many inheritors can be processed (and multiple times). - // ??? But in real use it seems reasonably fast. If poor performance problems emerged, - // ??? should be optimized - PsiClass containingClass = method.getContainingClass(); - final PsiClass[] subClasses = ClassInheritorsSearch.search(containingClass, false).toArray(PsiClass.EMPTY_ARRAY); - for (int i1 = 0; i1 != subClasses.length; ++i1) { - final PsiMethod[] mBSs = subClasses[i1].findMethodsBySignature(method, true); - new Inner().linkInheritors(mBSs); - } - } - - private void processQueue() { - while (!myExpressionsQueue.isEmpty()) { - PsiExpression expr = myExpressionsQueue.pullFirst(); - PsiElement parent = expr.getParent(); - if (parent instanceof PsiAssignmentExpression) { - PsiAssignmentExpression assignment = (PsiAssignmentExpression)parent; - if (assignment.getRExpression() != null) { - addLink(assignment.getLExpression(), assignment.getRExpression()); - } - addLink(assignment, assignment.getLExpression()); - addLink(assignment.getLExpression(), assignment); - } - else if (parent instanceof PsiArrayAccessExpression) { - PsiArrayAccessExpression arrayAccess = (PsiArrayAccessExpression)parent; - if (expr.equals(arrayAccess.getArrayExpression())) { - addLink(arrayAccess, expr); - addLink(expr, arrayAccess); - } - } - else if (parent instanceof PsiParenthesizedExpression) { - addLink(parent, expr); - addLink(expr, parent); - } - else if (parent instanceof PsiArrayInitializerExpression) { - PsiArrayInitializerExpression arrayInitializerExpr = (PsiArrayInitializerExpression)parent; - PsiExpression[] initializers = arrayInitializerExpr.getInitializers(); - for (PsiExpression initializer : initializers) { - addLink(arrayInitializerExpr, initializer); - } - } - else if (parent instanceof PsiExpressionList) { - PsiElement pparent = parent.getParent(); - if (pparent instanceof PsiCallExpression) { - PsiMethod method = ((PsiCallExpression)pparent).resolveMethod(); - if (method != null) { - addArgumentParameterLink(expr, (PsiExpressionList)parent, method); - } - } - } + protected void markNodes() { + //for (Iterator iterator = myDependencyMap.keySet().getSectionsIterator(); getSectionsIterator.hasNext();) { + for (final PsiElement element : myElementToNode.keySet()) { + if (element instanceof PsiExpression) { + final PsiElement parent = element.getParent(); + if (parent instanceof PsiReferenceExpression) { + final PsiReferenceExpression refExpr = (PsiReferenceExpression)parent; + if (element.equals(refExpr.getQualifierExpression())) { + final PsiElement refElement = refExpr.resolve(); + if (refElement != null && !isInSuper(refElement)) { + markNode(element); + } + } + } + } + else if (!myReplaceInstanceOf && element.getParent() != null + && element.getParent().getParent() instanceof PsiInstanceOfExpression) { + markNode(element); + } + else if (element.getParent() instanceof PsiClassObjectAccessExpression) { + markNode(element); + } + else if (element instanceof PsiParameter) { + final PsiType type = TypeConversionUtil.erasure(((PsiParameter)element).getType()); + final PsiClass aClass = PsiUtil.resolveClassInType(type); + if (aClass != null) { + if (!myManager.isInProject(element) || !myManager.areElementsEquivalent(aClass, myClass)) { + if (!isSuperInheritor(aClass)) { + markNode(element); + } + } + } + else { // unresolvable class + markNode(element); + } + } + } } - } - protected void markNodes() { - //for (Iterator iterator = myDependencyMap.keySet().getSectionsIterator(); getSectionsIterator.hasNext();) { - for (final PsiElement element : myElementToNode.keySet()) { - if (element instanceof PsiExpression) { - final PsiElement parent = element.getParent(); - if (parent instanceof PsiReferenceExpression) { - final PsiReferenceExpression refExpr = (PsiReferenceExpression)parent; - if (element.equals(refExpr.getQualifierExpression())) { - final PsiElement refElement = refExpr.resolve(); - if (refElement != null && !isInSuper(refElement)) { - markNode(element); - } - } - } - } - else if (!myReplaceInstanceOf && element.getParent() != null - && element.getParent().getParent() instanceof PsiInstanceOfExpression) { - markNode(element); - } - else if (element.getParent() instanceof PsiClassObjectAccessExpression) { - markNode(element); - } - else if (element instanceof PsiParameter) { - final PsiType type = TypeConversionUtil.erasure(((PsiParameter)element).getType()); - final PsiClass aClass = PsiUtil.resolveClassInType(type); - if (aClass != null) { - if (!myManager.isInProject(element) || !myManager.areElementsEquivalent(aClass, myClass)) { - if (!isSuperInheritor(aClass)) { - markNode(element); - } - } - } - else { // unresolvable class - markNode(element); - } - } - } - } + protected abstract boolean isSuperInheritor(PsiClass aClass); - protected abstract boolean isSuperInheritor(PsiClass aClass); + protected abstract boolean isInSuper(PsiElement member); - protected abstract boolean isInSuper(PsiElement member); + protected void addLink(PsiElement source, PsiElement target) { + Node from = myElementToNode.get(source); + Node to = myElementToNode.get(target); - protected void addLink(PsiElement source, PsiElement target) { - Node from = myElementToNode.get(source); - Node to = myElementToNode.get(target); + if (from == null) { + from = new Node(source); + if (source instanceof PsiExpression) { + myExpressionsQueue.addLast((PsiExpression)source); + } + myElementToNode.put(source, from); + } - if (from == null) { - from = new Node(source); - if (source instanceof PsiExpression) myExpressionsQueue.addLast((PsiExpression)source); - myElementToNode.put(source, from); - } + if (to == null) { + to = new Node(target); + if (target instanceof PsiExpression) { + myExpressionsQueue.addLast((PsiExpression)target); + } + myElementToNode.put(target, to); + } - if (to == null) { - to = new Node(target); - if (target instanceof PsiExpression) myExpressionsQueue.addLast((PsiExpression)target); - myElementToNode.put(target, to); + Edge.connect(from, to); } - Edge.connect(from, to); - } + private void spreadMarks() { + final LinkedList markedNodes = new LinkedList(); - private void spreadMarks() { - final LinkedList markedNodes = new LinkedList(); + for (final PsiElement markedNode : myMarkedNodes) { + final Node node = myElementToNode.get(markedNode); + if (node != null) { + markedNodes.addFirst(node); + } + } - for (final PsiElement markedNode : myMarkedNodes) { - final Node node = myElementToNode.get(markedNode); - if (node != null) markedNodes.addFirst(node); + GlobalAnalyzer.doOneEnd(markedNodes, new Colorer()); } - GlobalAnalyzer.doOneEnd(markedNodes, new Colorer()); - } - - private void markNode(final PsiElement node) { - myMarkedNodes.add(node); - } + private void markNode(final PsiElement node) { + myMarkedNodes.add(node); + } - class Colorer implements OneEndFunctor { - public Mark compute(Mark from, Mark edge, Mark to) { - VisitMark mark = new VisitMark((VisitMark)to); + class Colorer implements OneEndFunctor { + public Mark compute(Mark from, Mark edge, Mark to) { + VisitMark mark = new VisitMark((VisitMark)to); - myMarkedNodes.add(mark.getElement()); - mark.switchOn(); + myMarkedNodes.add(mark.getElement()); + mark.switchOn(); - return mark; + return mark; + } } - } - private static class Edge extends EdgeImpl { - private Edge(Node from, Node to) { - super(from, to); - } + private static class Edge extends EdgeImpl { + private Edge(Node from, Node to) { + super(from, to); + } - public static boolean connect(Node from, Node to) { - if (from.mySuccessors.add(to)) { - new Edge(from, to); - return true; - } + public static boolean connect(Node from, Node to) { + if (from.mySuccessors.add(to)) { + new Edge(from, to); + return true; + } - return false; + return false; + } } - } - private static class VisitMark implements Mark { - private boolean myVisited; - private final PsiElement myElement; + private static class VisitMark implements Mark { + private boolean myVisited; + private final PsiElement myElement; - public boolean coincidesWith(Mark x) { - return ((VisitMark)x).myVisited == myVisited; - } + public boolean coincidesWith(Mark x) { + return ((VisitMark)x).myVisited == myVisited; + } - public VisitMark(VisitMark m) { - myVisited = false; - myElement = m.myElement; - } + public VisitMark(VisitMark m) { + myVisited = false; + myElement = m.myElement; + } - public VisitMark(PsiElement e) { - myVisited = false; - myElement = e; - } + public VisitMark(PsiElement e) { + myVisited = false; + myElement = e; + } - public void switchOn() { - myVisited = true; - } + public void switchOn() { + myVisited = true; + } - public void switchOff() { - myVisited = false; - } + public void switchOff() { + myVisited = false; + } - public PsiElement getElement() { - return myElement; + public PsiElement getElement() { + return myElement; + } } - } - private static class Node extends NodeImpl { - private final HashSet mySuccessors = new HashSet(); - private VisitMark myMark; + private static class Node extends NodeImpl { + private final HashSet mySuccessors = new HashSet(); + private VisitMark myMark; - public Node(PsiElement x) { - super(); - myMark = new VisitMark(x); - } + public Node(PsiElement x) { + super(); + myMark = new VisitMark(x); + } - public Mark getMark() { - return myMark; - } + public Mark getMark() { + return myMark; + } - public void setMark(Mark x) { - myMark = (VisitMark)x; + public void setMark(Mark x) { + myMark = (VisitMark)x; + } } - } }