private static Condition<PsiElement> findFieldUsages( final PsiField psiField, final List<UsageInfo> usages, final PsiElement[] allElementsToDelete) { final Condition<PsiElement> isInsideDeleted = getUsageInsideDeletedFilter(allElementsToDelete); ReferencesSearch.search(psiField) .forEach( reference -> { if (!isInsideDeleted.value(reference.getElement())) { final PsiElement element = reference.getElement(); final PsiElement parent = element.getParent(); if (parent instanceof PsiAssignmentExpression && element == ((PsiAssignmentExpression) parent).getLExpression()) { usages.add( new SafeDeleteFieldWriteReference( (PsiAssignmentExpression) parent, psiField)); } else { TextRange range = reference.getRangeInElement(); usages.add( new SafeDeleteReferenceJavaDeleteUsageInfo( reference.getElement(), psiField, range.getStartOffset(), range.getEndOffset(), false, PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null)); } } return true; }); return isInsideDeleted; }
@NotNull public Collection<String> getMessages() { List<String> result = new ArrayList<>(messages); for (int i = 0; i < messages.size(); i++) { result.set(i, result.get(i).replaceAll("<[^>]+>", "")); } return result; }
private static void findClassUsages( final PsiClass psiClass, final PsiElement[] allElementsToDelete, final List<UsageInfo> usages) { final boolean justPrivates = containsOnlyPrivates(psiClass); final String qualifiedName = psiClass.getQualifiedName(); final boolean annotationType = psiClass.isAnnotationType() && qualifiedName != null; ReferencesSearch.search(psiClass) .forEach( reference -> { final PsiElement element = reference.getElement(); if (!isInside(element, allElementsToDelete)) { PsiElement parent = element.getParent(); if (parent instanceof PsiReferenceList) { final PsiElement pparent = parent.getParent(); if (pparent instanceof PsiClass && element instanceof PsiJavaCodeReferenceElement) { final PsiClass inheritor = (PsiClass) pparent; // If psiClass contains only private members, then it is safe to remove it and // change inheritor's extends/implements accordingly if (justPrivates) { if (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList())) { usages.add( new SafeDeleteExtendsClassUsageInfo( (PsiJavaCodeReferenceElement) element, psiClass, inheritor)); return true; } } } } LOG.assertTrue(element.getTextRange() != null); final PsiFile containingFile = psiClass.getContainingFile(); boolean sameFileWithSingleClass = false; if (containingFile instanceof PsiClassOwner) { final PsiClass[] classes = ((PsiClassOwner) containingFile).getClasses(); sameFileWithSingleClass = classes.length == 1 && classes[0] == psiClass && element.getContainingFile() == containingFile; } final boolean safeDelete = sameFileWithSingleClass || isInNonStaticImport(element); if (annotationType && parent instanceof PsiAnnotation) { usages.add( new SafeDeleteAnnotation((PsiAnnotation) parent, psiClass, safeDelete)); } else { usages.add( new SafeDeleteReferenceJavaDeleteUsageInfo(element, psiClass, safeDelete)); } } return true; }); }
@Nullable private static Condition<PsiElement> findMethodUsages( final PsiMethod psiMethod, final PsiElement[] allElementsToDelete, List<UsageInfo> usages) { final Collection<PsiReference> references = ReferencesSearch.search(psiMethod).findAll(); if (psiMethod.isConstructor()) { return findConstructorUsages(psiMethod, references, usages, allElementsToDelete); } final PsiMethod[] overridingMethods = removeDeletedMethods( OverridingMethodsSearch.search(psiMethod).toArray(PsiMethod.EMPTY_ARRAY), allElementsToDelete); findFunctionalExpressions(usages, ArrayUtil.prepend(psiMethod, overridingMethods)); final HashMap<PsiMethod, Collection<PsiReference>> methodToReferences = new HashMap<>(); for (PsiMethod overridingMethod : overridingMethods) { final Collection<PsiReference> overridingReferences = ReferencesSearch.search(overridingMethod).findAll(); methodToReferences.put(overridingMethod, overridingReferences); } final Set<PsiMethod> validOverriding = validateOverridingMethods( psiMethod, references, Arrays.asList(overridingMethods), methodToReferences, usages, allElementsToDelete); for (PsiReference reference : references) { final PsiElement element = reference.getElement(); if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) { usages.add( new SafeDeleteReferenceJavaDeleteUsageInfo( element, psiMethod, PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null)); } } final List<PsiMethod> calleesSafeToDelete = SafeDeleteJavaCalleeChooser.computeCalleesSafeToDelete(psiMethod); if (calleesSafeToDelete != null) { for (PsiMethod method : calleesSafeToDelete) { usages.add(new SafeDeleteMethodCalleeUsageInfo(method, psiMethod)); } } return usage -> { if (usage instanceof PsiFile) return false; return isInside(usage, allElementsToDelete) || isInside(usage, validOverriding); }; }
@Override public UsageView showUsages( UsageInfo[] usages, UsageViewPresentation presentation, UsageViewManager manager, PsiElement[] elements) { final List<PsiElement> overridingMethods = new ArrayList<>(); final List<UsageInfo> others = new ArrayList<>(); for (UsageInfo usage : usages) { if (usage instanceof SafeDeleteOverridingMethodUsageInfo) { overridingMethods.add(((SafeDeleteOverridingMethodUsageInfo) usage).getOverridingMethod()); } else { others.add(usage); } } UsageTarget[] targets = new UsageTarget[elements.length + overridingMethods.size()]; for (int i = 0; i < targets.length; i++) { if (i < elements.length) { targets[i] = new PsiElement2UsageTargetAdapter(elements[i]); } else { targets[i] = new PsiElement2UsageTargetAdapter(overridingMethods.get(i - elements.length)); } } return manager.showUsages( targets, UsageInfoToUsageConverter.convert(elements, others.toArray(new UsageInfo[others.size()])), presentation); }
public Collection<PsiElement> getAdditionalElementsToDelete( @NotNull final PsiElement element, @NotNull final Collection<PsiElement> allElementsToDelete, final boolean askUser) { if (element instanceof PsiField) { PsiField field = (PsiField) element; final Project project = element.getProject(); String propertyName = JavaCodeStyleManager.getInstance(project) .variableNameToPropertyName(field.getName(), VariableKind.FIELD); PsiClass aClass = field.getContainingClass(); if (aClass != null) { boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(aClass, propertyName, isStatic); if (getters != null) { final List<PsiMethod> validGetters = new ArrayList<>(1); for (PsiMethod getter : getters) { if (!allElementsToDelete.contains(getter) && (getter != null && getter.isPhysical())) { validGetters.add(getter); } } getters = validGetters.isEmpty() ? null : validGetters.toArray(new PsiMethod[validGetters.size()]); } PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); if (allElementsToDelete.contains(setter) || setter != null && !setter.isPhysical()) setter = null; if (askUser && (getters != null || setter != null)) { final String message = RefactoringMessageUtil.getGetterSetterMessage( field.getName(), RefactoringBundle.message("delete.title"), getters != null ? getters[0] : null, setter); if (!ApplicationManager.getApplication().isUnitTestMode() && Messages.showYesNoDialog( project, message, RefactoringBundle.message("safe.delete.title"), Messages.getQuestionIcon()) != Messages.YES) { getters = null; setter = null; } } List<PsiElement> elements = new ArrayList<>(); if (setter != null) elements.add(setter); if (getters != null) Collections.addAll(elements, getters); return elements; } } return null; }
private static void findFunctionalExpressions( final List<UsageInfo> usages, PsiMethod... methods) { for (PsiMethod method : methods) { final PsiClass containingClass = method.getContainingClass(); FunctionalExpressionSearch.search(method) .forEach( expression -> { usages.add( new SafeDeleteFunctionalExpressionUsageInfo(expression, containingClass)); return true; }); } }
@Override @NotNull protected UsageInfo[] findUsages() { List<UsageInfo> usages = Collections.synchronizedList(new ArrayList<UsageInfo>()); for (PsiElement element : myElements) { boolean handled = false; for (SafeDeleteProcessorDelegate delegate : Extensions.getExtensions(SafeDeleteProcessorDelegate.EP_NAME)) { if (delegate.handlesElement(element)) { final NonCodeUsageSearchInfo filter = delegate.findUsages(element, myElements, usages); if (filter != null) { for (PsiElement nonCodeUsageElement : filter.getElementsToSearch()) { addNonCodeUsages( nonCodeUsageElement, usages, filter.getInsideDeletedCondition(), mySearchNonJava, mySearchInCommentsAndStrings); } } handled = true; break; } } if (!handled && element instanceof PsiNamedElement) { findGenericElementUsages(element, usages, myElements); addNonCodeUsages( element, usages, getDefaultInsideDeletedCondition(myElements), mySearchNonJava, mySearchInCommentsAndStrings); } } final UsageInfo[] result = usages.toArray(new UsageInfo[usages.size()]); return UsageViewUtil.removeDuplicatedUsages(result); }
public static void findGenericElementUsages( final PsiElement element, final List<UsageInfo> usages, final PsiElement[] allElementsToDelete) { ReferencesSearch.search(element) .forEach( reference -> { final PsiElement refElement = reference.getElement(); if (!isInside(refElement, allElementsToDelete)) { usages.add( new SafeDeleteReferenceSimpleDeleteUsageInfo(refElement, element, false)); } return true; }); }
@Nullable public NonCodeUsageSearchInfo findUsages( @NotNull final PsiElement element, @NotNull final PsiElement[] allElementsToDelete, @NotNull final List<UsageInfo> usages) { Condition<PsiElement> insideDeletedCondition = getUsageInsideDeletedFilter(allElementsToDelete); if (element instanceof PsiClass) { findClassUsages((PsiClass) element, allElementsToDelete, usages); if (element instanceof PsiTypeParameter) { findTypeParameterExternalUsages((PsiTypeParameter) element, usages); } } else if (element instanceof PsiMethod) { insideDeletedCondition = findMethodUsages((PsiMethod) element, allElementsToDelete, usages); } else if (element instanceof PsiField) { insideDeletedCondition = findFieldUsages((PsiField) element, usages, allElementsToDelete); } else if (element instanceof PsiParameter) { LOG.assertTrue(((PsiParameter) element).getDeclarationScope() instanceof PsiMethod); findParameterUsages((PsiParameter) element, usages); } else if (element instanceof PsiLocalVariable) { for (PsiReference reference : ReferencesSearch.search(element)) { PsiReferenceExpression referencedElement = (PsiReferenceExpression) reference.getElement(); final PsiStatement statement = PsiTreeUtil.getParentOfType(referencedElement, PsiStatement.class); boolean isSafeToDelete = PsiUtil.isAccessedForWriting(referencedElement); boolean hasSideEffects = false; if (PsiUtil.isOnAssignmentLeftHand(referencedElement)) { hasSideEffects = RemoveUnusedVariableUtil.checkSideEffects( ((PsiAssignmentExpression) referencedElement.getParent()).getRExpression(), ((PsiLocalVariable) element), new ArrayList<>()); } usages.add( new SafeDeleteReferenceJavaDeleteUsageInfo( statement, element, isSafeToDelete && !hasSideEffects)); } } return new NonCodeUsageSearchInfo(insideDeletedCondition, element); }
private void replaceWithPrompt(final ReplaceContext replaceContext) { final List<Usage> _usages = replaceContext.getUsageView().getSortedUsages(); if (hasReadOnlyUsages(_usages)) { WindowManager.getInstance() .getStatusBar(myProject) .setInfo(FindBundle.message("find.replace.occurrences.found.in.read.only.files.status")); return; } final Usage[] usages = _usages.toArray(new Usage[_usages.size()]); // usageView.expandAll(); for (int i = 0; i < usages.length; ++i) { final Usage usage = usages[i]; final UsageInfo usageInfo = ((UsageInfo2UsageAdapter) usage).getUsageInfo(); final PsiElement elt = usageInfo.getElement(); if (elt == null) continue; final PsiFile psiFile = elt.getContainingFile(); if (!psiFile.isWritable()) continue; Runnable selectOnEditorRunnable = new Runnable() { @Override public void run() { final VirtualFile virtualFile = psiFile.getVirtualFile(); if (virtualFile != null && ApplicationManager.getApplication() .runReadAction( new Computable<Boolean>() { @Override public Boolean compute() { return virtualFile.isValid() ? Boolean.TRUE : Boolean.FALSE; } }) .booleanValue()) { if (usage.isValid()) { usage.highlightInEditor(); replaceContext.getUsageView().selectUsages(new Usage[] {usage}); } } } }; CommandProcessor.getInstance() .executeCommand( myProject, selectOnEditorRunnable, FindBundle.message("find.replace.select.on.editor.command"), null); String title = FindBundle.message("find.replace.found.usage.title", i + 1, usages.length); int result; try { replaceUsage( usage, replaceContext.getFindModel(), replaceContext.getExcludedSetCached(), true); result = FindManager.getInstance(myProject) .showPromptDialog(replaceContext.getFindModel(), title); } catch (FindManager.MalformedReplacementStringException e) { markAsMalformedReplacement(replaceContext, usage); result = FindManager.getInstance(myProject) .showMalformedReplacementPrompt(replaceContext.getFindModel(), title, e); } if (result == FindManager.PromptResult.CANCEL) { return; } if (result == FindManager.PromptResult.SKIP) { continue; } final int currentNumber = i; if (result == FindManager.PromptResult.OK) { final Ref<Boolean> success = Ref.create(); Runnable runnable = new Runnable() { @Override public void run() { success.set(replaceUsageAndRemoveFromView(usage, replaceContext)); } }; CommandProcessor.getInstance() .executeCommand(myProject, runnable, FindBundle.message("find.replace.command"), null); if (closeUsageViewIfEmpty(replaceContext.getUsageView(), success.get())) { return; } } if (result == FindManager.PromptResult.ALL_IN_THIS_FILE) { final int[] nextNumber = new int[1]; Runnable runnable = new Runnable() { @Override public void run() { int j = currentNumber; boolean success = true; for (; j < usages.length; j++) { final Usage usage = usages[j]; final UsageInfo usageInfo = ((UsageInfo2UsageAdapter) usage).getUsageInfo(); final PsiElement elt = usageInfo.getElement(); if (elt == null) continue; PsiFile otherPsiFile = elt.getContainingFile(); if (!otherPsiFile.equals(psiFile)) { break; } if (!replaceUsageAndRemoveFromView(usage, replaceContext)) { success = false; } } closeUsageViewIfEmpty(replaceContext.getUsageView(), success); nextNumber[0] = j; } }; CommandProcessor.getInstance() .executeCommand(myProject, runnable, FindBundle.message("find.replace.command"), null); //noinspection AssignmentToForLoopParameter i = nextNumber[0] - 1; } if (result == FindManager.PromptResult.ALL_FILES) { CommandProcessor.getInstance() .executeCommand( myProject, new Runnable() { @Override public void run() { final boolean success = replaceUsages(replaceContext, _usages); closeUsageViewIfEmpty(replaceContext.getUsageView(), success); } }, FindBundle.message("find.replace.command"), null); break; } } }
private static Set<PsiMethod> validateOverridingMethods( PsiMethod originalMethod, final Collection<PsiReference> originalReferences, Collection<PsiMethod> overridingMethods, HashMap<PsiMethod, Collection<PsiReference>> methodToReferences, List<UsageInfo> usages, final PsiElement[] allElementsToDelete) { Set<PsiMethod> validOverriding = new LinkedHashSet<>(overridingMethods); Set<PsiMethod> multipleInterfaceImplementations = new HashSet<>(); boolean anyNewBadRefs; do { anyNewBadRefs = false; for (PsiMethod overridingMethod : overridingMethods) { if (validOverriding.contains(overridingMethod)) { final Collection<PsiReference> overridingReferences = methodToReferences.get(overridingMethod); boolean anyOverridingRefs = false; for (final PsiReference overridingReference : overridingReferences) { final PsiElement element = overridingReference.getElement(); if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) { anyOverridingRefs = true; break; } } if (!anyOverridingRefs && isMultipleInterfacesImplementation( overridingMethod, originalMethod, allElementsToDelete)) { anyOverridingRefs = true; multipleInterfaceImplementations.add(overridingMethod); } if (anyOverridingRefs) { validOverriding.remove(overridingMethod); anyNewBadRefs = true; for (PsiReference reference : originalReferences) { final PsiElement element = reference.getElement(); if (!isInside(element, allElementsToDelete) && !isInside(element, overridingMethods)) { usages.add( new SafeDeleteReferenceJavaDeleteUsageInfo(element, originalMethod, false)); validOverriding.clear(); } } } } } } while (anyNewBadRefs && !validOverriding.isEmpty()); for (PsiMethod method : validOverriding) { if (method != originalMethod) { usages.add(new SafeDeleteOverridingMethodUsageInfo(method, originalMethod)); } } for (PsiMethod method : overridingMethods) { if (!validOverriding.contains(method) && !multipleInterfaceImplementations.contains(method) && canBePrivate( method, methodToReferences.get(method), validOverriding, allElementsToDelete)) { usages.add(new SafeDeletePrivatizeMethod(method, originalMethod)); } else { usages.add(new SafeDeleteOverrideAnnotation(method, originalMethod)); } } return validOverriding; }
@Nullable public UsageInfo[] preprocessUsages(final Project project, final UsageInfo[] usages) { final ArrayList<UsageInfo> result = new ArrayList<>(); final ArrayList<UsageInfo> overridingMethods = new ArrayList<>(); final ArrayList<SafeDeleteParameterCallHierarchyUsageInfo> delegatingParams = new ArrayList<>(); final ArrayList<SafeDeleteMethodCalleeUsageInfo> calleesSafeToDelete = new ArrayList<>(); for (UsageInfo usage : usages) { if (usage.isNonCodeUsage) { result.add(usage); } else if (usage instanceof SafeDeleteMethodCalleeUsageInfo) { calleesSafeToDelete.add((SafeDeleteMethodCalleeUsageInfo) usage); } else if (usage instanceof SafeDeleteOverridingMethodUsageInfo) { overridingMethods.add(usage); } else if (usage instanceof SafeDeleteParameterCallHierarchyUsageInfo) { delegatingParams.add((SafeDeleteParameterCallHierarchyUsageInfo) usage); } else if (usage instanceof SafeDeleteAnnotation) { result.add( new SafeDeleteAnnotation( (PsiAnnotation) usage.getElement(), ((SafeDeleteAnnotation) usage).getReferencedElement(), true)); } else { result.add(usage); } } if (!overridingMethods.isEmpty()) { if (ApplicationManager.getApplication().isUnitTestMode()) { result.addAll(overridingMethods); } else { OverridingMethodsDialog dialog = new OverridingMethodsDialog(project, overridingMethods); if (!dialog.showAndGet()) { return null; } final ArrayList<UsageInfo> selected = dialog.getSelected(); final Set<UsageInfo> unselected = new HashSet<>(overridingMethods); unselected.removeAll(selected); if (!unselected.isEmpty()) { final List<PsiMethod> unselectedMethods = ContainerUtil.map( unselected, info -> ((SafeDeleteOverridingMethodUsageInfo) info).getOverridingMethod()); for (Iterator<UsageInfo> iterator = result.iterator(); iterator.hasNext(); ) { final UsageInfo info = iterator.next(); if (info instanceof SafeDeleteOverrideAnnotation && !allSuperMethodsSelectedToDelete( unselectedMethods, ((SafeDeleteOverrideAnnotation) info).getMethod())) { iterator.remove(); } } } result.addAll(selected); } } if (!delegatingParams.isEmpty()) { final SafeDeleteParameterCallHierarchyUsageInfo parameterHierarchyUsageInfo = delegatingParams.get(0); if (ApplicationManager.getApplication().isUnitTestMode()) { result.addAll(delegatingParams); } else { final PsiMethod method = parameterHierarchyUsageInfo.getCalledMethod(); final PsiParameter parameter = parameterHierarchyUsageInfo.getReferencedElement(); final int parameterIndex = method.getParameterList().getParameterIndex(parameter); final JavaCallerChooser chooser = new SafeDeleteJavaCallerChooser(method, project, result) { @Override protected ArrayList<SafeDeleteParameterCallHierarchyUsageInfo> getTopLevelItems() { return delegatingParams; } @Override protected int getParameterIdx() { return parameterIndex; } }; TreeUtil.expand(chooser.getTree(), 2); if (!chooser.showAndGet()) { return null; } } } if (!calleesSafeToDelete.isEmpty()) { if (ApplicationManager.getApplication().isUnitTestMode()) { result.addAll(calleesSafeToDelete); } else { final PsiMethod method = calleesSafeToDelete.get(0).getCallerMethod(); final ArrayList<UsageInfo> list = new ArrayList<>(); JavaCallerChooser chooser = new SafeDeleteJavaCalleeChooser(method, project, list) { @Override protected ArrayList<SafeDeleteMethodCalleeUsageInfo> getTopLevelItems() { return calleesSafeToDelete; } }; TreeUtil.expand(chooser.getTree(), 2); if (!chooser.showAndGet()) { return null; } result.addAll(list); final List<PsiElement> methodsToDelete = new ArrayList<>(); for (UsageInfo info : list) { methodsToDelete.add(info.getElement()); } methodsToDelete.add(method); final Condition<PsiElement> insideDeletedCondition = getUsageInsideDeletedFilter( methodsToDelete.toArray(new PsiElement[methodsToDelete.size()])); for (UsageInfo info : list) { SafeDeleteProcessor.addNonCodeUsages( info.getElement(), result, insideDeletedCondition, JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD, JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD); } } } return result.toArray(new UsageInfo[result.size()]); }
@Nullable @Override public Collection<? extends PsiElement> getElementsToSearch( @NotNull PsiElement element, @Nullable Module module, @NotNull Collection<PsiElement> allElementsToDelete) { Project project = element.getProject(); if (element instanceof PsiPackage && module != null) { final PsiDirectory[] directories = ((PsiPackage) element).getDirectories(module.getModuleScope()); if (directories.length == 0) return null; return Arrays.asList(directories); } else if (element instanceof PsiMethod) { final PsiMethod[] methods = SuperMethodWarningUtil.checkSuperMethods( (PsiMethod) element, RefactoringBundle.message("to.delete.with.usage.search"), allElementsToDelete); if (methods.length == 0) return null; final ArrayList<PsiMethod> psiMethods = new ArrayList<>(Arrays.asList(methods)); psiMethods.add((PsiMethod) element); return psiMethods; } else if (element instanceof PsiParameter && ((PsiParameter) element).getDeclarationScope() instanceof PsiMethod) { PsiMethod method = (PsiMethod) ((PsiParameter) element).getDeclarationScope(); final Set<PsiParameter> parametersToDelete = new HashSet<>(); parametersToDelete.add((PsiParameter) element); final int parameterIndex = method.getParameterList().getParameterIndex((PsiParameter) element); final List<PsiMethod> superMethods = new ArrayList<>(Arrays.asList(method.findDeepestSuperMethods())); if (superMethods.isEmpty()) { superMethods.add(method); } for (PsiMethod superMethod : superMethods) { parametersToDelete.add(superMethod.getParameterList().getParameters()[parameterIndex]); OverridingMethodsSearch.search(superMethod) .forEach( overrider -> { parametersToDelete.add( overrider.getParameterList().getParameters()[parameterIndex]); return true; }); } if (parametersToDelete.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode()) { String message = RefactoringBundle.message( "0.is.a.part.of.method.hierarchy.do.you.want.to.delete.multiple.parameters", UsageViewUtil.getLongName(method)); int result = Messages.showYesNoCancelDialog( project, message, SafeDeleteHandler.REFACTORING_NAME, Messages.getQuestionIcon()); if (result == Messages.CANCEL) return null; if (result == Messages.NO) return Collections.singletonList(element); } return parametersToDelete; } else if (element instanceof PsiTypeParameter) { final PsiTypeParameterListOwner owner = ((PsiTypeParameter) element).getOwner(); if (owner instanceof PsiMethod && !owner.hasModifierProperty(PsiModifier.STATIC)) { final PsiTypeParameterList typeParameterList = owner.getTypeParameterList(); if (typeParameterList != null) { final int index = typeParameterList.getTypeParameterIndex((PsiTypeParameter) element); if (index >= 0) { final ArrayList<PsiTypeParameter> overriders = new ArrayList<>(); overriders.add((PsiTypeParameter) element); OverridingMethodsSearch.search((PsiMethod) owner) .forEach( overrider -> { final PsiTypeParameter[] typeParameters = overrider.getTypeParameters(); if (index < typeParameters.length) { overriders.add(typeParameters[index]); } return true; }); if (overriders.size() > 1) { String message = RefactoringBundle.message( "0.is.a.part.of.method.hierarchy.do.you.want.to.delete.multiple.type.parameters", UsageViewUtil.getLongName(owner)); int result = ApplicationManager.getApplication().isUnitTestMode() ? Messages.YES : Messages.showYesNoCancelDialog( project, message, SafeDeleteHandler.REFACTORING_NAME, Messages.getQuestionIcon()); if (result == Messages.CANCEL) return null; if (result == Messages.YES) return overriders; } } } } } return Collections.singletonList(element); }
private static void findParameterUsages( final PsiParameter parameter, final List<UsageInfo> usages) { final PsiMethod method = (PsiMethod) parameter.getDeclarationScope(); final int parameterIndex = method.getParameterList().getParameterIndex(parameter); // search for refs to current method only, do not search for refs to overriding methods, they'll // be searched separately ReferencesSearch.search(method) .forEach( reference -> { PsiElement element = reference.getElement(); if (element != null) { final JavaSafeDeleteDelegate safeDeleteDelegate = JavaSafeDeleteDelegate.EP.forLanguage(element.getLanguage()); if (safeDeleteDelegate != null) { safeDeleteDelegate.createUsageInfoForParameter( reference, usages, parameter, method); } if (!parameter.isVarArgs() && !RefactoringChangeUtil.isSuperMethodCall(element.getParent())) { final PsiParameter paramInCaller = SafeDeleteJavaCallerChooser.isTheOnlyOneParameterUsage( element.getParent(), parameterIndex, method); if (paramInCaller != null) { final PsiMethod callerMethod = (PsiMethod) paramInCaller.getDeclarationScope(); if (ApplicationManager.getApplication().isUnitTestMode()) { usages.add( new SafeDeleteParameterCallHierarchyUsageInfo( callerMethod, paramInCaller, callerMethod)); } else { usages.add( new SafeDeleteParameterCallHierarchyUsageInfo( method, parameter, callerMethod)); } } } } return true; }); ReferencesSearch.search(parameter) .forEach( reference -> { PsiElement element = reference.getElement(); final PsiDocTag docTag = PsiTreeUtil.getParentOfType(element, PsiDocTag.class); if (docTag != null) { usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(docTag, parameter, true)); return true; } boolean isSafeDelete = false; if (element.getParent().getParent() instanceof PsiMethodCallExpression) { PsiMethodCallExpression call = (PsiMethodCallExpression) element.getParent().getParent(); PsiReferenceExpression methodExpression = call.getMethodExpression(); if (methodExpression.getText().equals(PsiKeyword.SUPER)) { isSafeDelete = true; } else if (methodExpression.getQualifierExpression() instanceof PsiSuperExpression) { final PsiMethod superMethod = call.resolveMethod(); if (superMethod != null && MethodSignatureUtil.isSuperMethod(superMethod, method)) { isSafeDelete = true; } } } usages.add( new SafeDeleteReferenceJavaDeleteUsageInfo(element, parameter, isSafeDelete)); return true; }); findFunctionalExpressions(usages, method); }