mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-05 08:06:56 +07:00
[java-intention] IDEA-357879 "Replace catch sections with throw" intention doesn't check ancestors
GitOrigin-RevId: ab1f6d8c13b76850481b38c3fe0137f22fc11071
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b08201f587
commit
6d84f1e4df
@@ -68,7 +68,10 @@ replace.on.demand.import.intention.name=Replace with single class imports
|
||||
replace.on.demand.import.intention.family.name=Replace on demand import with single class imports
|
||||
replace.operator.assignment.with.assignment.intention.family.name=Replace operator assignment with assignment
|
||||
convert.catch.to.throws.intention.name=Replace 'catch' section with 'throws' declaration
|
||||
convert.catch.to.throws.intention.name.capitalized=Replace 'catch' Section With 'throws' Declaration
|
||||
convert.catch.to.throws.intention.family.name=Replace catch section with throws declaration
|
||||
convert.catch.to.throws.only.current.method=Add throws declaration only to the current method
|
||||
convert.catch.to.throws.super.and.current.methods=Add throws declaration to the current method and super methods
|
||||
wrap.vararg.arguments.with.explicit.array.intention.name=Wrap vararg arguments with explicit array creation
|
||||
wrap.vararg.arguments.with.explicit.array.intention.family.name=Wrap vararg arguments with explicit array creation
|
||||
extract.while.loop.condition.to.if.statement.intention.name=Extract condition to internal 'if' statement
|
||||
|
||||
@@ -2,20 +2,28 @@
|
||||
package com.siyeh.ipp.exceptions;
|
||||
|
||||
import com.intellij.codeInsight.BlockUtils;
|
||||
import com.intellij.modcommand.ActionContext;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.Presentation;
|
||||
import com.intellij.modcommand.PsiBasedModCommandAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.IntentionPowerPackBundle;
|
||||
import com.siyeh.ipp.base.MCIntention;
|
||||
import com.siyeh.ipp.base.PsiElementPredicate;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public final class ConvertCatchToThrowsIntention extends MCIntention {
|
||||
public final class ConvertCatchToThrowsIntention extends PsiBasedModCommandAction<PsiElement> {
|
||||
|
||||
public ConvertCatchToThrowsIntention() {
|
||||
super(PsiElement.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
@@ -23,18 +31,73 @@ public final class ConvertCatchToThrowsIntention extends MCIntention {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull String getTextForElement(@NotNull PsiElement element) {
|
||||
return IntentionPowerPackBundle.message("convert.catch.to.throws.intention.name");
|
||||
protected boolean isElementApplicable(@NotNull PsiElement element, @NotNull ActionContext context) {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (!(parent instanceof PsiCatchSection)) {
|
||||
return false;
|
||||
}
|
||||
if (element instanceof PsiCodeBlock) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement owner = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiClass.class, PsiLambdaExpression.class);
|
||||
if (owner instanceof PsiLambdaExpression) {
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(owner);
|
||||
return !(method instanceof PsiCompiledElement);
|
||||
}
|
||||
return owner instanceof PsiMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull PsiElementPredicate getElementPredicate() {
|
||||
return new ConvertCatchToThrowsPredicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invoke(@NotNull PsiElement element) {
|
||||
protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull PsiElement element) {
|
||||
final PsiCatchSection catchSection = (PsiCatchSection)element.getParent();
|
||||
final PsiMethod method = getMethod(catchSection);
|
||||
if (method == null) return ModCommand.nop();
|
||||
PsiType catchType = catchSection.getCatchType();
|
||||
if (catchType == null) return ModCommand.nop();
|
||||
PsiMethod[] superMethods = method.findSuperMethods(true);
|
||||
if (superMethods.length == 0) {
|
||||
return ModCommand.psiUpdate(catchSection, (copyCatchSection, upd) -> {
|
||||
deleteCatchAndAddToCurrentMethod(copyCatchSection, catchType);
|
||||
});
|
||||
}
|
||||
return ModCommand.chooseAction(
|
||||
IntentionPowerPackBundle.message("convert.catch.to.throws.intention.name.capitalized"),
|
||||
ModCommand.psiUpdateStep(catchSection,
|
||||
IntentionPowerPackBundle.message("convert.catch.to.throws.super.and.current.methods"),
|
||||
(copyCatchSection, upd) -> {
|
||||
List<PsiMethod> superMethodsToModify = new ArrayList<>();
|
||||
PsiFile containingFile = catchSection.getContainingFile();
|
||||
PsiFile copyCatchSectionContainingFile = copyCatchSection.getContainingFile();
|
||||
for (PsiMethod superMethod : superMethods) {
|
||||
if (!superMethod.isWritable() || !superMethod.isPhysical()) continue;
|
||||
if (superMethod.getContainingFile() == containingFile) {
|
||||
superMethodsToModify.add(
|
||||
PsiTreeUtil.findSameElementInCopy(superMethod, copyCatchSectionContainingFile));
|
||||
}
|
||||
else {
|
||||
PsiMethod copySuperMethod = upd.getWritable(superMethod);
|
||||
superMethodsToModify.add(copySuperMethod);
|
||||
}
|
||||
}
|
||||
deleteCatchAndAddToCurrentMethod(copyCatchSection, catchType);
|
||||
for (PsiMethod superMethod : superMethodsToModify) {
|
||||
addToThrowsList(superMethod.getThrowsList(), catchType);
|
||||
}
|
||||
}),
|
||||
ModCommand.psiUpdateStep(catchSection,
|
||||
IntentionPowerPackBundle.message("convert.catch.to.throws.only.current.method"),
|
||||
(copyCatchSection, upd) -> deleteCatchAndAddToCurrentMethod(copyCatchSection, catchType))
|
||||
);
|
||||
}
|
||||
|
||||
private static void deleteCatchAndAddToCurrentMethod(@NotNull PsiCatchSection copyCatchSection, @NotNull PsiType catchType) {
|
||||
PsiMethod copyMethod = getMethod(copyCatchSection);
|
||||
deleteCatchSection(copyCatchSection);
|
||||
if (copyMethod == null) return;
|
||||
addToThrowsList(copyMethod.getThrowsList(), catchType);
|
||||
}
|
||||
|
||||
private static @Nullable PsiMethod getMethod(@NotNull PsiCatchSection catchSection) {
|
||||
final NavigatablePsiElement owner = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class, PsiLambdaExpression.class);
|
||||
final PsiMethod method;
|
||||
if (owner instanceof PsiMethod) {
|
||||
@@ -44,17 +107,15 @@ public final class ConvertCatchToThrowsIntention extends MCIntention {
|
||||
method = LambdaUtil.getFunctionalInterfaceMethod(owner);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (method == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// todo warn if method implements or overrides some base method
|
||||
// Warning
|
||||
// "Method xx() of class XX implements/overrides method of class
|
||||
// YY. Do you want to modify the base method?"
|
||||
// [Yes][No][Cancel]
|
||||
addToThrowsList(method.getThrowsList(), catchSection.getCatchType());
|
||||
return method;
|
||||
}
|
||||
|
||||
private static void deleteCatchSection(PsiCatchSection catchSection) {
|
||||
final PsiTryStatement tryStatement = catchSection.getTryStatement();
|
||||
if (tryStatement.getCatchSections().length > 1 || tryStatement.getResourceList() != null || tryStatement.getFinallyBlock() != null) {
|
||||
catchSection.delete();
|
||||
@@ -64,6 +125,11 @@ public final class ConvertCatchToThrowsIntention extends MCIntention {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiElement element) {
|
||||
return Presentation.of(IntentionPowerPackBundle.message("convert.catch.to.throws.intention.name"));
|
||||
}
|
||||
|
||||
private static void addToThrowsList(PsiReferenceList throwsList, PsiType catchType) {
|
||||
if (catchType instanceof PsiClassType classType) {
|
||||
final PsiClassType[] types = throwsList.getReferencedTypes();
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.siyeh.ipp.exceptions;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.ipp.base.PsiElementPredicate;
|
||||
|
||||
class ConvertCatchToThrowsPredicate implements PsiElementPredicate {
|
||||
|
||||
@Override
|
||||
public boolean satisfiedBy(PsiElement element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (!(parent instanceof PsiCatchSection)) {
|
||||
return false;
|
||||
}
|
||||
if (element instanceof PsiCodeBlock) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement owner = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiClass.class, PsiLambdaExpression.class);
|
||||
if (owner instanceof PsiLambdaExpression) {
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(owner);
|
||||
return !(method instanceof PsiCompiledElement);
|
||||
}
|
||||
return owner instanceof PsiMethod;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user