public static boolean isInside(PsiElement place, PsiElement ancestor) { if (SafeDeleteProcessor.isInside(place, ancestor)) return true; if (PsiTreeUtil.getParentOfType(place, PsiComment.class, false) != null && ancestor instanceof PsiClass) { final PsiClass aClass = (PsiClass) ancestor; if (aClass.getParent() instanceof PsiJavaFile) { final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); if (PsiTreeUtil.isAncestor(file, place, false)) { if (file.getClasses().length == 1) { // file will be deleted on class deletion return true; } } } } return false; }
private static boolean containsOnlyPrivates(final PsiClass aClass) { final PsiField[] fields = aClass.getFields(); for (PsiField field : fields) { if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false; } final PsiMethod[] methods = aClass.getMethods(); for (PsiMethod method : methods) { if (!method.hasModifierProperty(PsiModifier.PRIVATE)) { if (method.isConstructor()) { // skip non-private constructors with call to super only final PsiCodeBlock body = method.getBody(); if (body != null) { final PsiStatement[] statements = body.getStatements(); if (statements.length == 0) continue; if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement) { final PsiExpression expression = ((PsiExpressionStatement) statements[0]).getExpression(); if (expression instanceof PsiMethodCallExpression) { PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) expression).getMethodExpression(); if (methodExpression.getText().equals(PsiKeyword.SUPER)) { continue; } } } } } return false; } } final PsiClass[] inners = aClass.getInnerClasses(); for (PsiClass inner : inners) { if (!inner.hasModifierProperty(PsiModifier.PRIVATE)) return false; } return true; }
public Collection<String> findConflicts( @NotNull final PsiElement element, @NotNull final PsiElement[] allElementsToDelete) { if (element instanceof PsiMethod) { final PsiClass containingClass = ((PsiMethod) element).getContainingClass(); if (containingClass != null && !containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { final PsiMethod[] superMethods = ((PsiMethod) element).findSuperMethods(); for (PsiMethod superMethod : superMethods) { if (isInside(superMethod, allElementsToDelete)) continue; if (superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { String message = RefactoringBundle.message( "0.implements.1", RefactoringUIUtil.getDescription(element, true), RefactoringUIUtil.getDescription(superMethod, true)); return Collections.singletonList(message); } } } } else if (element instanceof PsiParameter) { final PsiElement scope = ((PsiParameter) element).getDeclarationScope(); if (scope instanceof PsiMethod) { final PsiMethod method = (PsiMethod) scope; final PsiClass containingClass = method.getContainingClass(); if (containingClass != null) { final int parameterIndex = method.getParameterList().getParameterIndex((PsiParameter) element); final PsiMethod methodCopy = (PsiMethod) method.copy(); methodCopy.getParameterList().getParameters()[parameterIndex].delete(); final MultiMap<PsiElement, String> conflicts = new MultiMap<>(); ConflictsUtil.checkMethodConflicts(containingClass, method, methodCopy, conflicts); return (Collection<String>) conflicts.values(); } } } return null; }
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; }); }