diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java index 0c60958d4e73..66ca9bbe38a7 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java @@ -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); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index ad16aafb6ae9..108891839f94 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1596,6 +1596,7 @@ loop.with.implicit.termination.condition.dowhile.problem.descriptor=#ref-w loop.with.implicit.termination.condition.problem.descriptor=#ref 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 #ref is unnecessary in this context #loc unnecessary.super.qualifier.quickfix=Remove unnecessary 'super' qualifier diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchMayIgnoreExceptionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchMayIgnoreExceptionInspection.java index 7192b8e1d5d6..4cd27e06bb8b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchMayIgnoreExceptionInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchMayIgnoreExceptionInspection.java @@ -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; } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/CatchWithComment.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/CatchWithComment.java new file mode 100644 index 000000000000..39ed552baed2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/CatchWithComment.java @@ -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()); + } catch (IOException ex) { + // foo + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/EmptyCatch.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/EmptyCatch.after.java new file mode 100644 index 000000000000..72f8c506a4e8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/EmptyCatch.after.java @@ -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()); + } catch (IOException ex) { + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/EmptyCatch.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/EmptyCatch.java new file mode 100644 index 000000000000..28959d3f7bc2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/EmptyCatch.java @@ -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()); + } catch (IOException ex) { + + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnored.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnored.after.java new file mode 100644 index 000000000000..aa8d9d99ae3c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnored.after.java @@ -0,0 +1,11 @@ +import java.io.IOException; + +class AAA { + public static void main(String[] args) { + try { + System.out.println(System.in.read()); + } catch (IOException ignored) { + + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnored.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnored.java new file mode 100644 index 000000000000..59e81dbac0be --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnored.java @@ -0,0 +1,11 @@ +import java.io.IOException; + +class AAA { + public static void main(String[] args) { + try { + System.out.println(System.in.read()); + } catch (IOException ex) { + + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnoredNameConflict.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnoredNameConflict.after.java new file mode 100644 index 000000000000..d0723b5a8565 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnoredNameConflict.after.java @@ -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()); + } catch (IOException ignored1) { + + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnoredNameConflict.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnoredNameConflict.java new file mode 100644 index 000000000000..28959d3f7bc2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/errorhandling/ignore_exception/RenameToIgnoredNameConflict.java @@ -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()); + } catch (IOException ex) { + + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/errorhandling/CatchMayIgnoreExceptionInspectionFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/errorhandling/CatchMayIgnoreExceptionInspectionFixTest.java new file mode 100644 index 000000000000..9218aab572cb --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/errorhandling/CatchMayIgnoreExceptionInspectionFixTest.java @@ -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")); + } +}