mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-229843 Change signature refactoring for records
Known problems: when removing record component getter is not removed; getter/field usages are not reported GitOrigin-RevId: 3babf3e316209232be416a28b52e77ab470fe2a3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
27e8c38041
commit
e08eb714bd
+1
-1
@@ -153,7 +153,7 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase<Paramet
|
||||
|
||||
@Override
|
||||
protected VisibilityPanelBase<String> createVisibilityControl() {
|
||||
return new JavaComboBoxVisibilityPanel();
|
||||
return new JavaComboBoxVisibilityPanel(myMethod.getAllowedModifiers());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-1
@@ -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) {
|
||||
|
||||
+110
-13
@@ -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<PsiRecordComponent> 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<Pair<PsiParameter, String>> 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<String> 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<PsiRecordHeader, PsiRecordComponent> {
|
||||
public static final RecordHeader INSTANCE = new RecordHeader();
|
||||
|
||||
@Override
|
||||
public List<PsiRecordComponent> getChildren(PsiRecordHeader header) {
|
||||
return Arrays.asList(header.getRecordComponents());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceList, PsiJavaCodeReferenceElement> {
|
||||
public static final ThrowsList INSTANCE = new ThrowsList();
|
||||
|
||||
|
||||
+32
-3
@@ -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<? super UsageInfo> 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<? super UsageInfo> results, ParameterInfo info) {
|
||||
private static void addParameterUsages(PsiNamedElement parameter, ArrayList<? super UsageInfo> results, ParameterInfo info) {
|
||||
PsiManager manager = parameter.getManager();
|
||||
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());
|
||||
for (PsiReference psiReference : ReferencesSearch.search(parameter, projectScope, false)) {
|
||||
|
||||
+8
-2
@@ -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<ParameterInfoImpl,
|
||||
|
||||
@Override
|
||||
public boolean canChangeVisibility() {
|
||||
PsiClass containingClass = myMethod.getContainingClass();
|
||||
return containingClass != null && !containingClass.isInterface();
|
||||
return AccessModifier.getAvailableModifiers(myMethod).size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,4 +80,8 @@ public class JavaMethodDescriptor implements MethodDescriptor<ParameterInfoImpl,
|
||||
public boolean canChangeName() {
|
||||
return !myMethod.isConstructor();
|
||||
}
|
||||
|
||||
public List<AccessModifier> getAllowedModifiers() {
|
||||
return AccessModifier.getAvailableModifiers(myMethod);
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<String> {
|
||||
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<AccessModifier> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1137,11 +1137,18 @@ public class RefactoringUtil {
|
||||
fixJavadocsForParams(method, newParameters, eqCondition, Conditions.alwaysTrue());
|
||||
}
|
||||
|
||||
public static void fixJavadocsForParams(PsiMethod method,
|
||||
Set<? extends PsiParameter> newParameters,
|
||||
Condition<? super Pair<PsiParameter, String>> eqCondition,
|
||||
Condition<? super String> matchedToOldParam) throws IncorrectOperationException {
|
||||
final PsiDocComment docComment = method.getDocComment();
|
||||
public static void fixJavadocsForParams(@NotNull PsiMethod method,
|
||||
@NotNull Set<? extends PsiParameter> newParameters,
|
||||
@NotNull Condition<? super Pair<PsiParameter, String>> eqCondition,
|
||||
@NotNull Condition<? super String> matchedToOldParam) throws IncorrectOperationException {
|
||||
fixJavadocsForParams(method, method.getDocComment(), newParameters, eqCondition, matchedToOldParam);
|
||||
}
|
||||
|
||||
public static void fixJavadocsForParams(@NotNull PsiMethod method,
|
||||
@Nullable PsiDocComment docComment,
|
||||
@NotNull Set<? extends PsiParameter> newParameters,
|
||||
@NotNull Condition<? super Pair<PsiParameter, String>> eqCondition,
|
||||
@NotNull Condition<? super String> matchedToOldParam) throws IncorrectOperationException {
|
||||
if (docComment == null) return;
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
final PsiDocTag[] paramTags = docComment.findTagsByName("param");
|
||||
|
||||
@@ -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<AccessModifier> ALL_MODIFIERS = ContainerUtil.immutableList(values());
|
||||
|
||||
private static final List<AccessModifier> PUBLIC_PACKAGE = ContainerUtil.immutableList(PUBLIC, PACKAGE_LOCAL);
|
||||
private static final List<AccessModifier> 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<AccessModifier> 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;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Record javadoc
|
||||
* @param x x
|
||||
*/
|
||||
record Rec(int x) {
|
||||
public R<caret>ec(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
}
|
||||
|
||||
class Use {
|
||||
public static void main(String[] args) {
|
||||
Rec rec = new Rec(1);
|
||||
System.out.println(rec.x());
|
||||
}
|
||||
}
|
||||
+17
@@ -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());
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @param x x
|
||||
* @param y y
|
||||
* @param z z
|
||||
*/
|
||||
record Rec(int x, int y, int z) {
|
||||
public R<caret>ec(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());
|
||||
}
|
||||
}
|
||||
+25
@@ -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());
|
||||
}
|
||||
}
|
||||
+32
@@ -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 R<caret>ec(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());
|
||||
}
|
||||
}
|
||||
+32
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @param x x
|
||||
* @param y y
|
||||
* @param z z
|
||||
*/
|
||||
record R<caret>ec(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());
|
||||
}
|
||||
}
|
||||
+16
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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("<caret> is not on method name", targetElement instanceof PsiMethod);
|
||||
PsiMethod method = (PsiMethod)targetElement;
|
||||
PsiType newType = newReturnType != null ? myFactory.createTypeFromText(newReturnType, method) : method.getReturnType();
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<AccessModifier> ALL_MODIFIERS = ContainerUtil.immutableList(AccessModifier.values());
|
||||
private static final List<AccessModifier> PUBLIC_PRIVATE = ContainerUtil.immutableList(AccessModifier.PUBLIC, AccessModifier.PRIVATE);
|
||||
private static final List<AccessModifier> 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<AccessModifier> modifiers = new ArrayList<>(getAvailableModifiers(member));
|
||||
List<AccessModifier> 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<AccessModifier> 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<AccessModifier> modifiers = getAvailableModifiers(member);
|
||||
List<AccessModifier> 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user