CatchMayIgnoreException: ability to insert catch body from TEMPLATE_CATCH_BODY

Fixes IDEA-217215 Add new quick fix for inspection "Empty catch block"

GitOrigin-RevId: e1097d92d42406dc92cc375affb6c719388afae9
This commit is contained in:
Tagir Valeev
2019-10-03 04:32:43 +00:00
committed by intellij-monorepo-bot
parent 95ebbf6ba3
commit 8b1b040a7a
11 changed files with 215 additions and 3 deletions
@@ -128,8 +128,19 @@ public abstract class FileTemplateManager{
@NotNull
public abstract FileTemplate[] getInternalTemplates();
/**
* @param templateName template name
* @return a template by name
* @throws IllegalStateException if template is not found
*/
@NotNull
public abstract FileTemplate getJ2eeTemplate(@NotNull @NonNls String templateName);
/**
* @param templateName template name
* @return a template by name
* @throws IllegalStateException if template is not found
*/
@NotNull
public abstract FileTemplate getCodeTemplate(@NotNull @NonNls String templateName);
@@ -1596,6 +1596,7 @@ loop.with.implicit.termination.condition.dowhile.problem.descriptor=<code>#ref-w
loop.with.implicit.termination.condition.problem.descriptor=<code>#ref</code> loop with implicit termination condition #loc
loop.with.implicit.termination.condition.quickfix=Make condition explicit
rename.catch.parameter.to.ignored=Rename ''catch'' parameter to ''{0}''
inspection.empty.catch.block.generate.body=Generate 'catch' body from template
unnecessary.super.qualifier.display.name=Unnecessary 'super' qualifier
unnecessary.super.qualifier.problem.descriptor=Qualifier <code>#ref</code> is unnecessary in this context #loc
unnecessary.super.qualifier.quickfix=Remove unnecessary 'super' qualifier
@@ -2,6 +2,7 @@
package com.siyeh.ig.errorhandling;
import com.intellij.codeInsight.Nullability;
import com.intellij.codeInsight.intention.LowPriorityAction;
import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
@@ -13,12 +14,19 @@ import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.JavaTemplateUtil;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.impl.light.LightParameter;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.fixes.RenameFix;
import com.siyeh.ig.fixes.SuppressForTestsScopeFix;
@@ -33,6 +41,8 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Consumer;
public class CatchMayIgnoreExceptionInspection extends AbstractBaseJavaLocalInspectionTool {
@@ -90,8 +100,10 @@ public class CatchMayIgnoreExceptionInspection extends AbstractBaseJavaLocalInsp
if (block == null) return;
SuppressForTestsScopeFix fix = SuppressForTestsScopeFix.build(CatchMayIgnoreExceptionInspection.this, section);
if (ControlFlowUtils.isEmpty(block, m_ignoreCatchBlocksWithComments, true)) {
RenameCatchParameterFix renameFix = new RenameCatchParameterFix(generateName(block));
AddCatchBodyFix addBodyFix = getAddBodyFix(block);
holder.registerProblem(catchToken, InspectionGadgetsBundle.message("inspection.catch.ignores.exception.empty.message"),
new EmptyCatchBlockFix(generateName(block)), fix);
renameFix, addBodyFix, fix);
}
else if (!VariableAccessUtils.variableIsUsed(parameter, section)) {
if (!m_ignoreNonEmptyCatchBlock &&
@@ -105,6 +117,21 @@ public class CatchMayIgnoreExceptionInspection extends AbstractBaseJavaLocalInsp
}
}
@Nullable
private AddCatchBodyFix getAddBodyFix(PsiCodeBlock block) {
if (ControlFlowUtils.isEmpty(block, true, true)) {
try {
FileTemplate template =
FileTemplateManager.getInstance(holder.getProject()).getCodeTemplate(JavaTemplateUtil.TEMPLATE_CATCH_BODY);
if (!StringUtil.isEmptyOrSpaces(template.getText())) {
return new AddCatchBodyFix();
}
}
catch (IllegalStateException ignored) { }
}
return null;
}
/**
* Returns true if given catch block may ignore VM exception such as NullPointerException
*
@@ -190,10 +217,50 @@ public class CatchMayIgnoreExceptionInspection extends AbstractBaseJavaLocalInsp
}
}
private static class EmptyCatchBlockFix implements LocalQuickFix {
private static class AddCatchBodyFix implements LocalQuickFix, LowPriorityAction {
@Nls(capitalization = Nls.Capitalization.Sentence)
@Override
@NotNull
public String getFamilyName() {
return InspectionGadgetsBundle.message("inspection.empty.catch.block.generate.body");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiCatchSection catchSection = ObjectUtils.tryCast(descriptor.getPsiElement().getParent(), PsiCatchSection.class);
if (catchSection == null) return;
PsiParameter parameter = catchSection.getParameter();
if (parameter == null) return;
String parameterName = parameter.getName();
if (parameterName == null) return;
FileTemplate template = FileTemplateManager.getInstance(project).getCodeTemplate(JavaTemplateUtil.TEMPLATE_CATCH_BODY);
Properties props = FileTemplateManager.getInstance(project).getDefaultProperties();
props.setProperty(FileTemplate.ATTRIBUTE_EXCEPTION, parameterName);
props.setProperty(FileTemplate.ATTRIBUTE_EXCEPTION_TYPE, parameter.getType().getCanonicalText());
PsiDirectory directory = catchSection.getContainingFile().getContainingDirectory();
if (directory != null) {
JavaTemplateUtil.setPackageNameAttribute(props, directory);
}
try {
PsiCodeBlock block =
PsiElementFactory.getInstance(project).createCodeBlockFromText("{\n" + template.getText(props) + "\n}", null);
Objects.requireNonNull(catchSection.getCatchBlock()).replace(block);
}
catch (ProcessCanceledException ce) {
throw ce;
}
catch (Exception e) {
throw new IncorrectOperationException("Incorrect file template", (Throwable)e);
}
}
}
private static class RenameCatchParameterFix implements LocalQuickFix {
private final String myName;
private EmptyCatchBlockFix(String name) {
private RenameCatchParameterFix(String name) {
myName = name;
}
@@ -0,0 +1,12 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
final Object ignored;
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ex) {
// foo
}
}
}
@@ -0,0 +1,12 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
final Object ignored;
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ex) {
ex.printStackTrace();
}
}
}
@@ -0,0 +1,12 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
final Object ignored;
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ex) {
}
}
}
@@ -0,0 +1,11 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ignored) {
}
}
}
@@ -0,0 +1,11 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ex) {
}
}
}
@@ -0,0 +1,12 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
final Object ignored;
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ignored1) {
}
}
}
@@ -0,0 +1,12 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
final Object ignored;
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ex) {
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.fixes.errorhandling;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.IGQuickFixesTestCase;
import com.siyeh.ig.errorhandling.CatchMayIgnoreExceptionInspection;
public class CatchMayIgnoreExceptionInspectionFixTest extends IGQuickFixesTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
CatchMayIgnoreExceptionInspection inspection = new CatchMayIgnoreExceptionInspection();
inspection.m_ignoreCatchBlocksWithComments = false;
myFixture.enableInspections(inspection);
}
@Override
protected String getRelativePath() {
return "errorhandling/ignore_exception";
}
public void testEmptyCatch() {
doTest(InspectionGadgetsBundle.message("inspection.empty.catch.block.generate.body"));
}
public void testCatchWithComment() {
assertQuickfixNotAvailable(InspectionGadgetsBundle.message("inspection.empty.catch.block.generate.body"));
}
public void testRenameToIgnored() {
doTest(InspectionGadgetsBundle.message("rename.catch.parameter.to.ignored", "ignored"));
}
public void testRenameToIgnoredNameConflict() {
doTest(InspectionGadgetsBundle.message("rename.catch.parameter.to.ignored", "ignored1"));
}
}