diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java index 096f2b3f27bf..7a9c4a09c07c 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java @@ -153,7 +153,7 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase createVisibilityControl() { - return new JavaComboBoxVisibilityPanel(); + return new JavaComboBoxVisibilityPanel(myMethod.getAllowedModifiers()); } @Override diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java index 05a7028f6be3..5b63a5d1ef95 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java @@ -13,6 +13,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; +import com.intellij.psi.util.JavaPsiRecordUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.HelpID; @@ -79,7 +80,9 @@ public class JavaChangeSignatureHandler implements ChangeSignatureHandler { final PsiClass containingClass = method.getContainingClass(); final PsiReferenceExpression refExpr = editor != null ? JavaTargetElementEvaluator.findReferenceExpression(editor) : null; - final boolean allowDelegation = containingClass != null && (!containingClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(containingClass)); + final boolean allowDelegation = containingClass != null && + (!containingClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(containingClass)) && + !method.equals(JavaPsiRecordUtil.findCanonicalConstructor(containingClass)); InplaceChangeSignature inplaceChangeSignature = editor != null ? InplaceChangeSignature.getCurrentRefactoring(editor) : null; ChangeInfo initialChange = inplaceChangeSignature != null ? inplaceChangeSignature.getStableChange() : null; @@ -156,6 +159,14 @@ public class JavaChangeSignatureHandler implements ChangeSignatureHandler { if (PsiTreeUtil.getParentOfType(element, PsiParameterList.class) != null) { return PsiTreeUtil.getParentOfType(element, PsiMethod.class); } + PsiRecordHeader header = PsiTreeUtil.getParentOfType(element, PsiRecordHeader.class); + if (header != null) { + PsiClass aClass = header.getContainingClass(); + if (aClass != null) { + return JavaPsiRecordUtil.findCanonicalConstructor(aClass); + } + return null; + } final PsiTypeParameterList typeParameterList = PsiTreeUtil.getParentOfType(element, PsiTypeParameterList.class); if (typeParameterList != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java index ab851fb5cfd0..a29990d6a65f 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java @@ -13,6 +13,8 @@ import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.ReadActionProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -181,6 +183,10 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr processParameterUsage((PsiReferenceExpression)element, oldName, newName); return true; } + else if (usage instanceof RecordGetterDeclarationUsageInfo) { + processRecordGetter((PsiMethod)element, ((RecordGetterDeclarationUsageInfo)usage).myNewName, + ((RecordGetterDeclarationUsageInfo)usage).myNewType); + } else if (usage instanceof CallReferenceUsageInfo) { ((CallReferenceUsageInfo)usage).getReference().handleChangeSignature(changeInfo); return true; @@ -202,6 +208,20 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr return false; } + private static void processRecordGetter(PsiMethod method, String newName, String type) { + Project project = method.getProject(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + if (newName != null && !newName.equals(method.getName())) { + final PsiIdentifier nameId = method.getNameIdentifier(); + assert nameId != null : method; + nameId.replace(factory.createIdentifier(newName)); + } + PsiTypeElement element = method.getReturnTypeElement(); + if (element != null && !element.textMatches(type)) { + JavaCodeStyleManager.getInstance(project).shortenClassReferences(element.replace(factory.createTypeElementFromText(type, method))); + } + } + private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName) throws IncorrectOperationException { @@ -788,7 +808,20 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr } PsiParameterList list = method.getParameterList(); - int newParamsLength = processMethodParams(changeInfo, baseMethod, factory, substitutor, list, method.getBody()); + PsiClass aClass = method.getContainingClass(); + boolean isRecordCanonicalConstructor = aClass != null && method.equals(JavaPsiRecordUtil.findCanonicalConstructor(aClass)); + boolean shouldChangeParameters = !isRecordCanonicalConstructor || JavaPsiRecordUtil.isExplicitCanonicalConstructor(method); + int newParamsLength = getNewParametersCount(changeInfo, baseMethod, list); + + if (shouldChangeParameters) { + processMethodParams(changeInfo, baseMethod, factory, substitutor, list, method.getBody()); + } + if (isRecordCanonicalConstructor) { + processRecordHeader(factory, Objects.requireNonNull(aClass.getRecordHeader()), changeInfo); + if (method instanceof SyntheticElement) { + method = Objects.requireNonNull(JavaPsiRecordUtil.findCanonicalConstructor(aClass)); + } + } fixJavadocsForChangedMethod(method, changeInfo, newParamsLength); if (changeInfo.isExceptionSetOrOrderChanged()) { final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo); @@ -805,17 +838,66 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr } } - private static int processMethodParams(JavaChangeInfo changeInfo, - PsiMethod baseMethod, - PsiElementFactory factory, - PsiSubstitutor substitutor, - PsiParameterList list, - PsiElement methodBody) { + private static void processRecordHeader(@NotNull PsiElementFactory factory, + @NotNull PsiRecordHeader header, + @NotNull JavaChangeInfo changeInfo) { + PsiRecordComponent[] components = header.getRecordComponents(); + JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters(); + List newComponents = new ArrayList<>(); + String[] oldParameterNames = changeInfo.getOldParameterNames(); + String[] oldParameterTypes = changeInfo.getOldParameterTypes(); + for (JavaParameterInfo info : parameterInfos) { + int index = info.getOldIndex(); + if (index >= 0) { + PsiRecordComponent component = components[index]; + newComponents.add(component); + + String oldName = oldParameterNames[index]; + if (!oldName.equals(info.getName()) && oldName.equals(component.getName())) { + PsiIdentifier newIdentifier = factory.createIdentifier(info.getName()); + Objects.requireNonNull(component.getNameIdentifier()).replace(newIdentifier); + } + + PsiTypeElement typeElement = component.getTypeElement(); + if (typeElement != null) { + component.normalizeDeclaration(); + typeElement = component.getTypeElement(); + String oldType = oldParameterTypes[index]; + if (!oldType.equals(info.getTypeText())) { + PsiType newType = info.createType(header, changeInfo.getMethod().getManager()); + if (newType != null) { + typeElement.replace(factory.createTypeElement(newType)); + } + } + } + } + else { + String componentText = info.getTypeText() + " " + info.getName(); + PsiRecordComponent[] dummyComponents = factory.createRecordHeaderFromText(componentText, header).getRecordComponents(); + if (dummyComponents.length != 1) { + throw new IncorrectOperationException(componentText + " is not a valid component"); + } + newComponents.add(dummyComponents[0]); + } + } + ChangeSignatureUtil.synchronizeList(header, newComponents, RecordHeader.INSTANCE, changeInfo.toRemoveParm()); + } + + private static int getNewParametersCount(JavaChangeInfo changeInfo, PsiMethod baseMethod, PsiParameterList list) { + final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - list.getParametersCount() : 0; + return Math.max(changeInfo.getNewParameters().length - delta, 0); + } + + private static void processMethodParams(JavaChangeInfo changeInfo, + PsiMethod baseMethod, + PsiElementFactory factory, + PsiSubstitutor substitutor, + PsiParameterList list, + PsiElement methodBody) { PsiParameter[] parameters = list.getParameters(); final JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters(); - final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - list.getParametersCount() : 0; - PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)]; + PsiParameter[] newParms = new PsiParameter[getNewParametersCount(changeInfo, baseMethod, list)]; final String[] oldParameterNames = changeInfo.getOldParameterNames(); final String[] oldParameterTypes = changeInfo.getOldParameterTypes(); for (int i = 0; i < newParms.length; i++) { @@ -855,9 +937,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr } } - resolveParameterVsFieldsConflicts(newParms, list, changeInfo.toRemoveParm(), methodBody); - return newParms.length; } private static PsiClassType[] getPrimaryChangedExceptionInfo(JavaChangeInfo changeInfo) throws IncorrectOperationException { @@ -945,13 +1025,21 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr newParameters.add(parameters[i]); } } - RefactoringUtil.fixJavadocsForParams(method, newParameters, pair -> { + Condition> eqCondition = pair -> { final PsiParameter parameter = pair.first; final String oldParamName = pair.second; final int oldIdx = ArrayUtil.find(oldParameterNames, oldParamName); int newIndex = method.getParameterList().getParameterIndex(parameter); return oldIdx >= 0 && newIndex >= 0 && changeInfo.getNewParameters()[newIndex].getOldIndex() == oldIdx; - }, paramName -> ArrayUtil.find(oldParameterNames, paramName) >= 0); + }; + Condition matchedToOldParam = paramName -> ArrayUtil.find(oldParameterNames, paramName) >= 0; + if (!(method instanceof SyntheticElement)) { + RefactoringUtil.fixJavadocsForParams(method, newParameters, eqCondition, matchedToOldParam); + } + PsiClass aClass = method.getContainingClass(); + if (aClass != null && method.equals(JavaPsiRecordUtil.findCanonicalConstructor(aClass))) { + RefactoringUtil.fixJavadocsForParams(method, aClass.getDocComment(), newParameters, eqCondition, matchedToOldParam); + } if (changeInfo.isReturnTypeChanged()) { PsiDocComment docComment = method.getDocComment(); @@ -1016,6 +1104,15 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr } } + private static class RecordHeader implements ChangeSignatureUtil.ChildrenGenerator { + public static final RecordHeader INSTANCE = new RecordHeader(); + + @Override + public List getChildren(PsiRecordHeader header) { + return Arrays.asList(header.getRecordComponents()); + } + } + private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator { public static final ThrowsList INSTANCE = new ThrowsList(); diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageSearcher.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageSearcher.java index 71684e1a7336..02468b0d7ab9 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageSearcher.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageSearcher.java @@ -25,6 +25,7 @@ import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.JavaPsiRecordUtil; import com.intellij.psi.xml.XmlElement; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.rename.JavaUnresolvableLocalCollisionDetector; @@ -37,6 +38,7 @@ import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewUtil; import com.intellij.util.containers.ContainerUtil; +import com.siyeh.ig.psiutils.VariableAccessUtils; import java.util.ArrayList; import java.util.Arrays; @@ -161,13 +163,18 @@ class JavaChangeSignatureUsageSearcher { private void findParametersUsage(final PsiMethod method, ArrayList result, PsiMethod[] overriders) { if (JavaLanguage.INSTANCE.equals(myChangeInfo.getLanguage())) { + PsiClass aClass = method.getContainingClass(); + PsiRecordComponent[] components = null; + if (aClass != null && method.equals(JavaPsiRecordUtil.findCanonicalConstructor(aClass))) { + components = aClass.getRecordComponents(); + } PsiParameter[] parameters = method.getParameterList().getParameters(); for (ParameterInfo info : myChangeInfo.getNewParameters()) { if (info.getOldIndex() >= 0) { PsiParameter parameter = parameters[info.getOldIndex()]; - if (!info.getName().equals(parameter.getName())) { + boolean nameChanged = !info.getName().equals(parameter.getName()); + if (nameChanged) { addParameterUsages(parameter, result, info); - for (PsiMethod overrider : overriders) { PsiParameter parameter1 = overrider.getParameterList().getParameters()[info.getOldIndex()]; if (parameter1 != null && Comparing.strEqual(parameter.getName(), parameter1.getName())) { @@ -175,6 +182,28 @@ class JavaChangeSignatureUsageSearcher { } } } + if (components != null && components.length > info.getOldIndex()) { + PsiRecordComponent component = components[info.getOldIndex()]; + if (nameChanged) { + PsiField field = JavaPsiRecordUtil.getFieldForComponent(component); + if (field != null) { + for (PsiReferenceExpression reference : VariableAccessUtils.getVariableReferences(field, aClass)) { + UsageInfo usageInfo = new ChangeSignatureParameterUsageInfo(reference, parameter.getName(), info.getName()); + result.add(usageInfo); + } + } + } + PsiMethod explicitGetter = ContainerUtil + .find(aClass.findMethodsByName(parameter.getName(), false), m -> m.getParameterList().isEmpty()); + if (explicitGetter != null) { + if (nameChanged) { + addParameterUsages(explicitGetter, result, info); + } + if (!(explicitGetter instanceof SyntheticElement) && (nameChanged || !parameter.getType().equalsToText(info.getTypeText()))) { + result.add(new RecordGetterDeclarationUsageInfo(explicitGetter, info.getName(), info.getTypeText())); + } + } + } } } } @@ -297,7 +326,7 @@ class JavaChangeSignatureUsageSearcher { } - private static void addParameterUsages(PsiParameter parameter, ArrayList results, ParameterInfo info) { + private static void addParameterUsages(PsiNamedElement parameter, ArrayList results, ParameterInfo info) { PsiManager manager = parameter.getManager(); GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject()); for (PsiReference psiReference : ReferencesSearch.search(parameter, projectScope, false)) { diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java index e19e63679a24..a55fe521c970 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java @@ -5,6 +5,9 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiParameter; import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.util.AccessModifier; +import com.intellij.psi.util.JavaPsiRecordUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.Nullable; @@ -60,8 +63,7 @@ public class JavaMethodDescriptor implements MethodDescriptor 1; } @Override @@ -78,4 +80,8 @@ public class JavaMethodDescriptor implements MethodDescriptor getAllowedModifiers() { + return AccessModifier.getAvailableModifiers(myMethod); + } } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/RecordGetterDeclarationUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/RecordGetterDeclarationUsageInfo.java new file mode 100644 index 000000000000..d57bfb157c41 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/RecordGetterDeclarationUsageInfo.java @@ -0,0 +1,16 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.refactoring.changeSignature; + +import com.intellij.psi.PsiElement; +import com.intellij.usageView.UsageInfo; + +public class RecordGetterDeclarationUsageInfo extends UsageInfo { + public final String myNewName; + public final String myNewType; + + public RecordGetterDeclarationUsageInfo(PsiElement element, String newName, String newType) { + super(element); + myNewName = newName; + myNewType = newType; + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java b/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java index aa9f0cb87222..927a05c48f14 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java @@ -16,22 +16,22 @@ package com.intellij.refactoring.ui; import com.intellij.psi.PsiModifier; +import com.intellij.psi.util.AccessModifier; import com.intellij.util.VisibilityUtil; +import com.intellij.util.containers.ContainerUtil; + +import java.util.List; /** * @author Konstantin Bulenkov */ public class JavaComboBoxVisibilityPanel extends ComboBoxVisibilityPanel { - private static final String[] MODIFIERS = {PsiModifier.PRIVATE, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PUBLIC}; - - private static final String[] PRESENTABLE_NAMES = { - VisibilityUtil.toPresentableText(PsiModifier.PRIVATE), - VisibilityUtil.toPresentableText(PsiModifier.PACKAGE_LOCAL), - VisibilityUtil.toPresentableText(PsiModifier.PROTECTED), - VisibilityUtil.toPresentableText(PsiModifier.PUBLIC) - }; + public JavaComboBoxVisibilityPanel(List modifiers) { + super(ContainerUtil.map2Array(modifiers, String.class, AccessModifier::toPsiModifier), + ContainerUtil.map2Array(modifiers, String.class, AccessModifier::toString)); + } public JavaComboBoxVisibilityPanel() { - super(MODIFIERS, PRESENTABLE_NAMES); + this(AccessModifier.ALL_MODIFIERS); } } diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index 3669d2cd1a83..5523e3f023d2 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -1137,11 +1137,18 @@ public class RefactoringUtil { fixJavadocsForParams(method, newParameters, eqCondition, Conditions.alwaysTrue()); } - public static void fixJavadocsForParams(PsiMethod method, - Set newParameters, - Condition> eqCondition, - Condition matchedToOldParam) throws IncorrectOperationException { - final PsiDocComment docComment = method.getDocComment(); + public static void fixJavadocsForParams(@NotNull PsiMethod method, + @NotNull Set newParameters, + @NotNull Condition> eqCondition, + @NotNull Condition matchedToOldParam) throws IncorrectOperationException { + fixJavadocsForParams(method, method.getDocComment(), newParameters, eqCondition, matchedToOldParam); + } + + public static void fixJavadocsForParams(@NotNull PsiMethod method, + @Nullable PsiDocComment docComment, + @NotNull Set newParameters, + @NotNull Condition> eqCondition, + @NotNull Condition matchedToOldParam) throws IncorrectOperationException { if (docComment == null) return; final PsiParameter[] parameters = method.getParameterList().getParameters(); final PsiDocTag[] paramTags = docComment.findTagsByName("param"); diff --git a/java/java-psi-impl/src/com/intellij/psi/util/AccessModifier.java b/java/java-psi-impl/src/com/intellij/psi/util/AccessModifier.java new file mode 100644 index 000000000000..a9a3df1db6db --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/util/AccessModifier.java @@ -0,0 +1,161 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.psi.util; + +import com.intellij.psi.*; +import com.intellij.psi.impl.light.LightRecordCanonicalConstructor; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +/** + * Java access modifiers: public, protected, private, package-local + */ +public enum AccessModifier { + PUBLIC(PsiModifier.PUBLIC), PROTECTED(PsiModifier.PROTECTED), PACKAGE_LOCAL(PsiModifier.PACKAGE_LOCAL), PRIVATE(PsiModifier.PRIVATE); + public static final List ALL_MODIFIERS = ContainerUtil.immutableList(values()); + + private static final List PUBLIC_PACKAGE = ContainerUtil.immutableList(PUBLIC, PACKAGE_LOCAL); + private static final List PUBLIC_PRIVATE = ContainerUtil.immutableList(PUBLIC, PRIVATE); + + @NotNull @PsiModifier.ModifierConstant + private final String myModifier; + + AccessModifier(@PsiModifier.ModifierConstant @NotNull String modifier) { + myModifier = modifier; + } + + /** + * @return a {@link PsiModifier} string constant which corresponds to this access modifier. + */ + @NotNull @PsiModifier.ModifierConstant + public String toPsiModifier() { + return myModifier; + } + + /** + * Checks whether given modifier owner has this access modifier (probably implicit) + * @param owner element to check (e.g. class member) + * @return true if it has current modifier + */ + public boolean hasModifier(@NotNull PsiModifierListOwner owner) { + return owner.hasModifierProperty(toPsiModifier()); + } + + /** + * Returns an {@link AccessModifier} which corresponds to the given keyword; + * null if supplied keyword is null or don't correspond to access modifier + * @param keyword keyword to convert to access modifier + * @return a corresponding access modifier + */ + @Contract(value = "null -> null", pure = true) + @Nullable + public static AccessModifier fromKeyword(@Nullable PsiKeyword keyword) { + return keyword == null ? null : fromPsiModifier(keyword.getText()); + } + + /** + * Returns an {@link AccessModifier} which corresponds to the given String constant declared in + * {@link PsiModifier} class. + * @param modifier a modifier string + * @return an access modifier or null if supplied string doesn't correspond to any access modifier. + */ + @Contract(value = "null -> null", pure = true) + @Nullable + public static AccessModifier fromPsiModifier(@Nullable String modifier) { + if (modifier == null) return null; + switch (modifier) { + case PsiModifier.PUBLIC: + return PUBLIC; + case PsiModifier.PROTECTED: + return PROTECTED; + case PsiModifier.PACKAGE_LOCAL: + return PACKAGE_LOCAL; + case PsiModifier.PRIVATE: + return PRIVATE; + default: + return null; + } + } + + public static AccessModifier fromModifierList(@NotNull PsiModifierList modifierList) { + if (modifierList.hasModifierProperty(PsiModifier.PRIVATE)) { + return PRIVATE; + } + if (modifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { + return PACKAGE_LOCAL; + } + if (modifierList.hasModifierProperty(PsiModifier.PROTECTED)) { + return PROTECTED; + } + return PUBLIC; + } + + public boolean isWeaker(@NotNull AccessModifier other) { + return ordinal() < other.ordinal(); + } + + @Override + public String toString() { + return PsiBundle.visibilityPresentation(toPsiModifier()); + } + + @NotNull + public static List getAvailableModifiers(PsiMember member) { + if (member == null) return Collections.emptyList(); + PsiClass containingClass = member.getContainingClass(); + if (member instanceof PsiField) { + if (member instanceof PsiEnumConstant || containingClass == null || containingClass.isInterface()) return Collections.emptyList(); + return ALL_MODIFIERS; + } + if (member instanceof PsiMethod) { + PsiMethod method = (PsiMethod)member; + if (containingClass == null || containingClass.isEnum() && method.isConstructor()) return Collections.emptyList(); + if (JavaPsiRecordUtil.getRecordComponentForAccessor(method) != null || + JavaPsiRecordUtil.isCompactConstructor(method) || + JavaPsiRecordUtil.isExplicitCanonicalConstructor(method) || + method instanceof LightRecordCanonicalConstructor) { + return Collections.singletonList(PUBLIC); + } + if (containingClass.isInterface()) { + if (PsiUtil.isLanguageLevel9OrHigher(member)) { + return PUBLIC_PRIVATE; + } + return Collections.singletonList(PUBLIC); + } + AccessModifier minAccess = getMinAccess(method); + if (minAccess != PRIVATE) { + return ContainerUtil.filter(ALL_MODIFIERS, mod -> mod.compareTo(minAccess) <= 0); + } + return ALL_MODIFIERS; + } + if (member instanceof PsiClass) { + if (PsiUtil.isLocalOrAnonymousClass((PsiClass)member)) return Collections.emptyList(); + if (containingClass == null) return PUBLIC_PACKAGE; + return ALL_MODIFIERS; + } + return Collections.emptyList(); + } + + @NotNull + private static AccessModifier getMinAccess(PsiMethod method) { + if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) return PRIVATE; + HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature(); + AccessModifier lowest = PRIVATE; + for (HierarchicalMethodSignature superSignature : signature.getSuperSignatures()) { + PsiMethod superMethod = superSignature.getMethod(); + AccessModifier current = fromModifierList(superMethod.getModifierList()); + if (!current.isWeaker(lowest)) continue; + if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(superMethod, method)) continue; + if (!PsiUtil.isAccessible(method.getProject(), superMethod, method, null)) continue; + lowest = current; + if (lowest == PUBLIC) { + break; + } + } + return lowest; + } +} diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorAddParameter.java b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorAddParameter.java new file mode 100644 index 000000000000..310da4570745 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorAddParameter.java @@ -0,0 +1,16 @@ +/** + * Record javadoc + * @param x x + */ +record Rec(int x) { + public Rec(int x) { + this.x = x; + } +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(1); + System.out.println(rec.x()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorAddParameter_after.java b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorAddParameter_after.java new file mode 100644 index 000000000000..58afb7a5b7cf --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorAddParameter_after.java @@ -0,0 +1,17 @@ +/** + * Record javadoc + * @param x x + * @param y + */ +record Rec(int x, int y) { + public Rec(int x, int y) { + this.x = x; + } +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(1, ); + System.out.println(rec.x()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorRename.java b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorRename.java new file mode 100644 index 000000000000..9564b69b3c55 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorRename.java @@ -0,0 +1,25 @@ +/** + * @param x x + * @param y y + * @param z z + */ +record Rec(int x, int y, int z) { + public Rec(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int x() {return x;} + public int y() {return y;} + public int z() {return z;} +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(1, 2, 3); + System.out.println(rec.x()); + System.out.println(rec.y()); + System.out.println(rec.z()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorRename_after.java b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorRename_after.java new file mode 100644 index 000000000000..bd24852e7e6b --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorRename_after.java @@ -0,0 +1,25 @@ +/** + * @param y y + * @param z z + * @param x x + */ +record Rec(int y, int z, int x) { + public Rec(int y, int z, int x) { + this.y = y; + this.z = z; + this.x = x; + } + + public int y() {return y;} + public int z() {return z;} + public int x() {return x;} +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(1, 2, 3); + System.out.println(rec.y()); + System.out.println(rec.z()); + System.out.println(rec.x()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorReorder.java b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorReorder.java new file mode 100644 index 000000000000..e67e3ef23ba8 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorReorder.java @@ -0,0 +1,32 @@ +/** + * Record javadoc + * @param x x + * @param y y + * @param z z + */ +record Rec(int x, int y, int z) { + /** + * Constructor javadoc + * @param x x + * @param y y + * @param z z + */ + public Rec(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int x() {return x;} + public int y() {return y;} + public int z() {return z;} +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(1, 2, 3); + System.out.println(rec.x()); + System.out.println(rec.y()); + System.out.println(rec.z()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorReorder_after.java b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorReorder_after.java new file mode 100644 index 000000000000..db512d089008 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordCanonicalConstructorReorder_after.java @@ -0,0 +1,32 @@ +/** + * Record javadoc + * @param y y + * @param z z + * @param x x + */ +record Rec(int y, int z, int x) { + /** + * Constructor javadoc + * @param y y + * @param z z + * @param x x + */ + public Rec(int y, int z, int x) { + this.x = x; + this.y = y; + this.z = z; + } + + public int x() {return x;} + public int y() {return y;} + public int z() {return z;} +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(2, 3, 1); + System.out.println(rec.x()); + System.out.println(rec.y()); + System.out.println(rec.z()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordHeaderDeleteRename.java b/java/java-tests/testData/refactoring/changeSignature/RecordHeaderDeleteRename.java new file mode 100644 index 000000000000..012bac868898 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordHeaderDeleteRename.java @@ -0,0 +1,17 @@ +/** + * @param x x + * @param y y + * @param z z + */ +record Rec(int x, int y, int z) { + public int y() { + return this.y; + } +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(1, 2, 3); + System.out.println(rec.y()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/RecordHeaderDeleteRename_after.java b/java/java-tests/testData/refactoring/changeSignature/RecordHeaderDeleteRename_after.java new file mode 100644 index 000000000000..8745cf71ecba --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/RecordHeaderDeleteRename_after.java @@ -0,0 +1,16 @@ +/** + * @param yyy y + * + */ +record Rec(long yyy) { + public long yyy() { + return this.yyy; + } +} + +class Use { + public static void main(String[] args) { + Rec rec = new Rec(2); + System.out.println(rec.yyy()); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureBaseTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureBaseTest.java index 653d2684db64..912c44c75f7f 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureBaseTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureBaseTest.java @@ -5,6 +5,7 @@ import com.intellij.JavaTestUtil; import com.intellij.codeInsight.TargetElementUtil; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; +import com.intellij.psi.util.JavaPsiRecordUtil; import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor; import com.intellij.refactoring.changeSignature.JavaThrownExceptionInfo; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; @@ -15,8 +16,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import static com.intellij.refactoring.changeSignature.ParameterInfo.NEW_PARAMETER; - public abstract class ChangeSignatureBaseTest extends LightRefactoringTestCase { protected PsiElementFactory myFactory; @@ -105,6 +104,9 @@ public abstract class ChangeSignatureBaseTest extends LightRefactoringTestCase { String basePath = getRelativePath() + getTestName(false); configureByFile(basePath + ".java"); PsiElement targetElement = TargetElementUtil.findTargetElement(getEditor(), TargetElementUtil.ELEMENT_NAME_ACCEPTED); + if (targetElement instanceof PsiClass) { + targetElement = JavaPsiRecordUtil.findCanonicalConstructor((PsiClass)targetElement); + } assertTrue(" is not on method name", targetElement instanceof PsiMethod); PsiMethod method = (PsiMethod)targetElement; PsiType newType = newReturnType != null ? myFactory.createTypeFromText(newReturnType, method) : method.getReturnType(); diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureTest.java index 54519e034108..b5e3305461db 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/ChangeSignatureTest.java @@ -11,13 +11,22 @@ import com.intellij.refactoring.changeSignature.JavaThrownExceptionInfo; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; import com.intellij.refactoring.changeSignature.ThrownExceptionInfo; import com.intellij.refactoring.util.CanonicalTypes; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; import java.util.HashSet; +import static com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase.JAVA_14; + /** * @author dsl */ public class ChangeSignatureTest extends ChangeSignatureBaseTest { + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return JAVA_14; + } private CommonCodeStyleSettings getJavaSettings() { return getCurrentCodeStyleSettings().getCommonSettings(JavaLanguage.INSTANCE); @@ -499,7 +508,7 @@ public class ChangeSignatureTest extends ChangeSignatureBaseTest { //String[] ex = {"@TA(42) IllegalArgumentException", "java.lang.@TA(43) IllegalStateException"}; //doTest("java.util.@TA(0) List<@TA(1) C.@TA(1) Inner>", ps, ex, false); String[] ps = {"@TA(2) int @TA(3) []", "@TA(4) List<@TA(5) Class<@TA(6) ?>>", "@TA(7) String @TA(8) ..."}; - String[] ex = {}; + String[] ex = ArrayUtil.EMPTY_STRING_ARRAY; doTest("@TA(0) List<@TA(1) Inner>", ps, ex, false); } @@ -514,6 +523,43 @@ public class ChangeSignatureTest extends ChangeSignatureBaseTest { }; doTest(null, null, null, genParams, new SimpleExceptionsGen(), false, false); } + + public void testRecordHeaderDeleteRename() { + doTest(null, null, null, method -> { + return new ParameterInfoImpl[]{ + ParameterInfoImpl.create(1).withName("yyy").withType(PsiType.LONG) + }; + }, false); + } + + public void testRecordCanonicalConstructorRename() { + doTest(null, null, null, method -> { + return new ParameterInfoImpl[]{ + ParameterInfoImpl.create(0).withName("y").withType(PsiType.INT), + ParameterInfoImpl.create(1).withName("z").withType(PsiType.INT), + ParameterInfoImpl.create(2).withName("x").withType(PsiType.INT) + }; + }, false); + } + + public void testRecordCanonicalConstructorReorder() { + doTest(null, null, null, method -> { + return new ParameterInfoImpl[]{ + ParameterInfoImpl.create(1).withName("y").withType(PsiType.INT), + ParameterInfoImpl.create(2).withName("z").withType(PsiType.INT), + ParameterInfoImpl.create(0).withName("x").withType(PsiType.INT) + }; + }, false); + } + + public void testRecordCanonicalConstructorAddParameter() { + doTest(null, null, null, method -> { + return new ParameterInfoImpl[]{ + ParameterInfoImpl.create(0).withName("x").withType(PsiType.INT), + ParameterInfoImpl.create(-1).withName("y").withType(PsiType.INT) + }; + }, false); + } /* workers */ } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/modifiers/AccessModifier.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/modifiers/AccessModifier.java deleted file mode 100644 index 457b6069d40c..000000000000 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/modifiers/AccessModifier.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.siyeh.ipp.modifiers; - -import com.intellij.psi.PsiKeyword; -import com.intellij.psi.PsiModifier; -import com.intellij.psi.PsiModifierList; -import com.intellij.psi.PsiModifierListOwner; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Java access modifiers: public, protected, private, package-local - */ -enum AccessModifier { - PUBLIC(PsiModifier.PUBLIC), PROTECTED(PsiModifier.PROTECTED), PACKAGE_LOCAL(PsiModifier.PACKAGE_LOCAL), PRIVATE(PsiModifier.PRIVATE); - - @NotNull @PsiModifier.ModifierConstant - private final String myModifier; - - AccessModifier(@PsiModifier.ModifierConstant @NotNull String modifier) { - myModifier = modifier; - } - - /** - * @return a {@link PsiModifier} string constant which corresponds to this access modifier. - */ - @NotNull @PsiModifier.ModifierConstant - public String toPsiModifier() { - return myModifier; - } - - /** - * Checks whether given modifier owner has this access modifier (probably implicit) - * @param owner element to check (e.g. class member) - * @return true if it has current modifier - */ - public boolean hasModifier(@NotNull PsiModifierListOwner owner) { - return owner.hasModifierProperty(toPsiModifier()); - } - - /** - * Returns an {@link AccessModifier} which corresponds to the given keyword; - * null if supplied keyword is null or don't correspond to access modifier - * @param keyword keyword to convert to access modifier - * @return a corresponding access modifier - */ - @Contract(value = "null -> null", pure = true) - @Nullable - public static AccessModifier fromKeyword(@Nullable PsiKeyword keyword) { - return keyword == null ? null : fromPsiModifier(keyword.getText()); - } - - /** - * Returns an {@link AccessModifier} which corresponds to the given String constant declared in - * {@link PsiModifier} class. - * @param modifier a modifier string - * @return an access modifier or null if supplied string doesn't correspond to any access modifier. - */ - @Contract(value = "null -> null", pure = true) - @Nullable - public static AccessModifier fromPsiModifier(@Nullable String modifier) { - if (modifier == null) return null; - switch (modifier) { - case PsiModifier.PUBLIC: - return PUBLIC; - case PsiModifier.PROTECTED: - return PROTECTED; - case PsiModifier.PACKAGE_LOCAL: - return PACKAGE_LOCAL; - case PsiModifier.PRIVATE: - return PRIVATE; - default: - return null; - } - } - - public static AccessModifier fromModifierList(@NotNull PsiModifierList modifierList) { - if (modifierList.hasModifierProperty(PsiModifier.PRIVATE)) { - return PRIVATE; - } - if (modifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { - return PACKAGE_LOCAL; - } - if (modifierList.hasModifierProperty(PsiModifier.PROTECTED)) { - return PROTECTED; - } - return PUBLIC; - } - - public boolean isWeaker(@NotNull AccessModifier other) { - return ordinal() < other.ordinal(); - } - - @Override - public String toString() { - return this == PACKAGE_LOCAL ? "package-private" : toPsiModifier(); - } -} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/modifiers/ChangeModifierIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/modifiers/ChangeModifierIntention.java index 45e8299847c9..8252ed3781eb 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/modifiers/ChangeModifierIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/modifiers/ChangeModifierIntention.java @@ -38,10 +38,8 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.JavaPsiRecordUtil; -import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.AccessModifier; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor; @@ -63,14 +61,9 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class ChangeModifierIntention extends BaseElementAtCaretIntentionAction { - private static final List ALL_MODIFIERS = ContainerUtil.immutableList(AccessModifier.values()); - private static final List PUBLIC_PRIVATE = ContainerUtil.immutableList(AccessModifier.PUBLIC, AccessModifier.PRIVATE); - private static final List PUBLIC_PACKAGE = - ContainerUtil.immutableList(AccessModifier.PUBLIC, AccessModifier.PACKAGE_LOCAL); private final boolean myErrorFix; private AccessModifier myTarget; @@ -92,7 +85,7 @@ public class ChangeModifierIntention extends BaseElementAtCaretIntentionAction { if (!(member instanceof PsiNameIdentifierOwner)) return false; PsiElement identifier = ((PsiNameIdentifierOwner)member).getNameIdentifier(); if (identifier == null || identifier.getTextRange().getEndOffset() <= element.getTextRange().getStartOffset()) return false; - List modifiers = new ArrayList<>(getAvailableModifiers(member)); + List modifiers = new ArrayList<>(AccessModifier.getAvailableModifiers(member)); if (modifiers.isEmpty()) return false; if (!myErrorFix && modifiers.stream().noneMatch(mod -> mod.hasModifier(member))) return false; modifiers.removeIf(mod -> mod.hasModifier(member)); @@ -120,61 +113,6 @@ public class ChangeModifierIntention extends BaseElementAtCaretIntentionAction { } } - @NotNull - private static List getAvailableModifiers(PsiMember member) { - if (member == null) return Collections.emptyList(); - PsiClass containingClass = member.getContainingClass(); - if (member instanceof PsiField) { - if (member instanceof PsiEnumConstant || containingClass == null || containingClass.isInterface()) return Collections.emptyList(); - return ALL_MODIFIERS; - } - if (member instanceof PsiMethod) { - PsiMethod method = (PsiMethod)member; - if (containingClass == null || containingClass.isEnum() && method.isConstructor()) return Collections.emptyList(); - if (JavaPsiRecordUtil.getRecordComponentForAccessor(method) != null || - JavaPsiRecordUtil.isCompactConstructor(method) || - JavaPsiRecordUtil.isExplicitCanonicalConstructor(method)) { - return Collections.singletonList(AccessModifier.PUBLIC); - } - if (containingClass.isInterface()) { - if (PsiUtil.isLanguageLevel9OrHigher(member)) { - return PUBLIC_PRIVATE; - } - return Collections.singletonList(AccessModifier.PUBLIC); - } - AccessModifier minAccess = getMinAccess(method); - if (minAccess != AccessModifier.PRIVATE) { - return ContainerUtil.filter(ALL_MODIFIERS, mod -> mod.compareTo(minAccess) <= 0); - } - return ALL_MODIFIERS; - } - if (member instanceof PsiClass) { - if (PsiUtil.isLocalOrAnonymousClass((PsiClass)member)) return Collections.emptyList(); - if (containingClass == null) return PUBLIC_PACKAGE; - return ALL_MODIFIERS; - } - return Collections.emptyList(); - } - - @NotNull - private static AccessModifier getMinAccess(PsiMethod method) { - if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) return AccessModifier.PRIVATE; - HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature(); - AccessModifier lowest = AccessModifier.PRIVATE; - for (HierarchicalMethodSignature superSignature : signature.getSuperSignatures()) { - PsiMethod superMethod = superSignature.getMethod(); - AccessModifier current = AccessModifier.fromModifierList(superMethod.getModifierList()); - if (!current.isWeaker(lowest)) continue; - if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(superMethod, method)) continue; - if (!PsiUtil.isAccessible(method.getProject(), superMethod, method, null)) continue; - lowest = current; - if (lowest == AccessModifier.PUBLIC) { - break; - } - } - return lowest; - } - @Nullable @Override public PsiElement getElementToMakeWritable(@NotNull PsiFile currentFile) { @@ -192,7 +130,7 @@ public class ChangeModifierIntention extends BaseElementAtCaretIntentionAction { if (member == null) return; PsiFile file = member.getContainingFile(); if (file == null) return; - List modifiers = getAvailableModifiers(member); + List modifiers = AccessModifier.getAvailableModifiers(member); if (modifiers.isEmpty()) return; AccessModifier target = myTarget; if (modifiers.contains(target)) { @@ -356,7 +294,7 @@ public class ChangeModifierIntention extends BaseElementAtCaretIntentionAction { @Nullable private static PsiKeyword getAnchorKeyword(PsiModifierList modifierList) { for (PsiElement child = modifierList.getFirstChild(); child != null; child = child.getNextSibling()) { - if (ALL_MODIFIERS.contains(AccessModifier.fromKeyword(ObjectUtils.tryCast(child, PsiKeyword.class)))) { + if (AccessModifier.ALL_MODIFIERS.contains(AccessModifier.fromKeyword(ObjectUtils.tryCast(child, PsiKeyword.class)))) { return (PsiKeyword)child; } }