IDEA-112398 (Yellow code is green: Inspection "Overly broad 'catch' clause" and Runti...
authorBas Leijdekkers <basleijdekkers@gmail.com>
Wed, 21 Aug 2013 20:07:40 +0000 (22:07 +0200)
committerBas Leijdekkers <basleijdekkers@gmail.com>
Wed, 21 Aug 2013 20:07:40 +0000 (22:07 +0200)
plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java
plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/toobroadcatch/TooBroadCatchBlock.java
plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/toobroadcatch/expected.xml

index 2fba528ccc53a5275ba0f087e7f2f575a2dc4b58..c2e0b5e1f18f88fa7e8cb99708ef4c6b406983f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import com.siyeh.InspectionGadgetsBundle;
 import com.siyeh.ig.BaseInspection;
 import com.siyeh.ig.BaseInspectionVisitor;
 import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ClassUtils;
 import com.siyeh.ig.psiutils.ExceptionUtils;
 import com.siyeh.ig.psiutils.TestUtils;
 import org.jetbrains.annotations.NotNull;
@@ -86,7 +87,12 @@ public class TooBroadCatchInspection extends BaseInspection {
     final List<PsiClass> maskedTypes = (List<PsiClass>)infos[0];
     final List<InspectionGadgetsFix> fixes = new ArrayList();
     for (PsiClass thrown : maskedTypes) {
-      fixes.add(new AddCatchSectionFix(thrown));
+      if (CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION.equals(maskedTypes.get(0).getQualifiedName())) {
+        fixes.add(new ReplaceWithRuntimeExceptionFix());
+      }
+      else {
+        fixes.add(new AddCatchSectionFix(thrown));
+      }
     }
     return fixes.toArray(new InspectionGadgetsFix[fixes.size()]);
   }
@@ -100,6 +106,33 @@ public class TooBroadCatchInspection extends BaseInspection {
     return panel;
   }
 
+  private static class ReplaceWithRuntimeExceptionFix extends InspectionGadgetsFix {
+    @NotNull
+    @Override
+    public String getName() {
+      return "Replace with 'catch' clause for 'RuntimeException'";
+    }
+
+    @NotNull
+    @Override
+    public String getFamilyName() {
+      return getName();
+    }
+
+    @Override
+    protected void doFix(Project project, ProblemDescriptor descriptor) {
+      final PsiElement element = descriptor.getPsiElement();
+      if (!(element instanceof PsiTypeElement)) {
+        return;
+      }
+      final PsiTypeElement typeElement = (PsiTypeElement)element;
+      final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
+      final PsiClassType type = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION);
+      final PsiTypeElement newTypeElement = factory.createTypeElement(type);
+      typeElement.replace(newTypeElement);
+    }
+  }
+
   private static class AddCatchSectionFix extends InspectionGadgetsFix {
 
     private final SmartPsiElementPointer<PsiClass> myThrown;
@@ -207,31 +240,42 @@ public class TooBroadCatchInspection extends BaseInspection {
       if (ignoreInTestCode && TestUtils.isInTestCode(statement)) {
         return;
       }
-      final Set<PsiClassType> exceptionsThrown = ExceptionUtils.calculateExceptionsThrown(tryBlock);
-      final int numExceptionsThrown = exceptionsThrown.size();
-      final Set<PsiType> exceptionsCaught = new HashSet<PsiType>(numExceptionsThrown);
+      final Set<PsiClassType> thrownTypes = ExceptionUtils.calculateExceptionsThrown(tryBlock);
+      final Set<PsiType> caughtTypes = new HashSet<PsiType>(thrownTypes.size());
       final PsiCatchSection[] catchSections = statement.getCatchSections();
       for (final PsiCatchSection catchSection : catchSections) {
         final PsiParameter parameter = catchSection.getParameter();
         if (parameter == null) {
           continue;
         }
-        final PsiType typeCaught = parameter.getType();
-        if (typeCaught instanceof PsiDisjunctionType) {
-          final PsiDisjunctionType disjunctionType = (PsiDisjunctionType)typeCaught;
+        final PsiType caughtType = parameter.getType();
+        if (caughtType instanceof PsiDisjunctionType) {
+          final PsiDisjunctionType disjunctionType = (PsiDisjunctionType)caughtType;
           final List<PsiType> types = disjunctionType.getDisjunctions();
           for (PsiType type : types) {
-            check(exceptionsThrown, exceptionsCaught, parameter, type);
+            check(thrownTypes, caughtTypes, parameter, type);
           }
         }
         else {
-          check(exceptionsThrown, exceptionsCaught, parameter, typeCaught);
+          if (thrownTypes.isEmpty()) {
+            if (CommonClassNames.JAVA_LANG_EXCEPTION.equals(caughtType.getCanonicalText())) {
+              final PsiTypeElement typeElement = parameter.getTypeElement();
+              if (typeElement == null) {
+                continue;
+              }
+              final PsiClass runtimeExceptionClass = ClassUtils.findClass(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, parameter);
+              registerError(typeElement, Collections.singletonList(runtimeExceptionClass));
+            }
+          }
+          else {
+            check(thrownTypes, caughtTypes, parameter, caughtType);
+          }
         }
       }
     }
 
-    private void check(Set<PsiClassType> exceptionsThrown, Set<PsiType> exceptionsCaught, PsiParameter parameter, PsiType type) {
-      final List<PsiClass> maskedExceptions = findMaskedExceptions(exceptionsThrown, exceptionsCaught, type);
+    private void check(Set<PsiClassType> thrownTypes, Set<PsiType> caughtTypes, PsiParameter parameter, PsiType caughtType) {
+      final List<PsiClass> maskedExceptions = findMaskedExceptions(thrownTypes, caughtTypes, caughtType);
       if (maskedExceptions.isEmpty()) {
         return;
       }
@@ -242,30 +286,30 @@ public class TooBroadCatchInspection extends BaseInspection {
       registerError(typeElement, maskedExceptions);
     }
 
-    private List<PsiClass> findMaskedExceptions(Set<PsiClassType> exceptionsThrown, Set<PsiType> exceptionsCaught, PsiType typeCaught) {
-      if (exceptionsThrown.contains(typeCaught)) {
+    private List<PsiClass> findMaskedExceptions(Set<PsiClassType> thrownTypes, Set<PsiType> caughtTypes, PsiType caughtType) {
+      if (thrownTypes.contains(caughtType)) {
         if (ignoreThrown) {
           return Collections.emptyList();
         }
-        exceptionsCaught.add(typeCaught);
-        exceptionsThrown.remove(typeCaught);
+        caughtTypes.add(caughtType);
+        thrownTypes.remove(caughtType);
       }
       if (onlyWarnOnRootExceptions) {
-        if (!ExceptionUtils.isGenericExceptionClass(typeCaught)) {
+        if (!ExceptionUtils.isGenericExceptionClass(caughtType)) {
           return Collections.emptyList();
         }
       }
-      final List<PsiClass> typesMasked = new ArrayList();
-      for (PsiClassType typeThrown : exceptionsThrown) {
-        if (!exceptionsCaught.contains(typeThrown) && typeCaught.isAssignableFrom(typeThrown)) {
-          exceptionsCaught.add(typeThrown);
+      final List<PsiClass> maskedTypes = new ArrayList();
+      for (PsiClassType typeThrown : thrownTypes) {
+        if (!caughtTypes.contains(typeThrown) && caughtType.isAssignableFrom(typeThrown)) {
+          caughtTypes.add(typeThrown);
           final PsiClass aClass = typeThrown.resolve();
           if (aClass != null) {
-            typesMasked.add(aClass);
+            maskedTypes.add(aClass);
           }
         }
       }
-      return typesMasked;
+      return maskedTypes;
     }
   }
 }
index 06672fac42f852268bb3215c972485dfe398bc77..c292cbcbc5bcbed049c4ced29e67404b9256d15f 100644 (file)
@@ -62,4 +62,24 @@ public class TooBroadCatchBlock{
       try (java.io.FileInputStream in = new java.io.FileInputStream("asdf")) {}
     } catch (IOException e) {}
   }
+
+  boolean m() {
+    try {
+      new java.io.FileInputStream("");
+      return new java.io.File("can_reset").isFile();
+    } catch (FileNotFoundException e) {
+      return false;
+    } catch (Exception e ) {
+      return false;
+    }
+  }
+
+  boolean m2() {
+    try {
+      new java.io.FileInputStream("");
+      return new java.io.File("can_reset").isFile();
+    } catch (Exception e ) {
+      return false;
+    }
+  }
 }
index 55b5b0ed11ce1053db16d9b801f4db5f9001a728..6c49ec83fc88cc27514988ceb2b0df22a8affed3 100644 (file)
     <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Overly broad 'catch' block</problem_class>
     <description>'catch' of &lt;code&gt;IOException&lt;/code&gt; is too broad, masking exception 'FileNotFoundException' #loc</description>
   </problem>
+
+  <problem>
+    <file>TooBroadCatchBlock.java</file>
+    <line>72</line>
+    <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Overly broad 'catch' block</problem_class>
+    <description>'catch' of &lt;code&gt;Exception&lt;/code&gt; is too broad, masking exception 'RuntimeException' #loc</description>
+  </problem>
+
+  <problem>
+    <file>TooBroadCatchBlock.java</file>
+    <line>81</line>
+    <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Overly broad 'catch' block</problem_class>
+    <description>'catch' of &lt;code&gt;Exception&lt;/code&gt; is too broad, masking exception 'FileNotFoundException' #loc</description>
+  </problem>
 </problems>
\ No newline at end of file