Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.RedundantThrowsCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
RedundantThrowsCheck
95%
38/40
100%
24/24
3
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2014  Oliver Burn
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 package com.puppycrawl.tools.checkstyle.checks.coding;
 20  
 
 21  
 import com.google.common.collect.Lists;
 22  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 23  
 import com.puppycrawl.tools.checkstyle.api.FullIdent;
 24  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 25  
 import com.puppycrawl.tools.checkstyle.checks.AbstractTypeAwareCheck;
 26  
 import java.util.Iterator;
 27  
 import java.util.List;
 28  
 
 29  
 /**
 30  
  * Checks for redundant exceptions declared in throws clause
 31  
  * such as duplicates, unchecked exceptions or subclasses of
 32  
  * another declared exception.
 33  
  *
 34  
  * <p>
 35  
  * An example of how to configure the check is:
 36  
  * </p>
 37  
  * <pre>
 38  
  * &lt;module name="RedundantThrows"&gt;
 39  
  *    &lt;property name=&quot;allowUnchecked&quot; value=&quot;true&quot;/&gt;
 40  
  *    &lt;property name=&quot;allowSubclasses&quot; value=&quot;true&quot;/&gt;
 41  
  * &lt;/module&gt;
 42  
  * </pre>
 43  
  * @author o_sukhodolsky
 44  
  */
 45  10
 public class RedundantThrowsCheck extends AbstractTypeAwareCheck
 46  
 {
 47  
     /**
 48  
      * whether unchecked exceptions in throws
 49  
      * are allowed or not
 50  
      */
 51  
     private boolean mAllowUnchecked;
 52  
 
 53  
     /**
 54  
      * whether subclass of another declared
 55  
      * exception is allowed in throws clause
 56  
      */
 57  
     private boolean mAllowSubclasses;
 58  
 
 59  
     /**
 60  
      * Getter for allowUnchecked property.
 61  
      * @param aAllowUnchecked whether unchecked excpetions in throws
 62  
      *                         are allowed or not
 63  
      */
 64  
     public void setAllowUnchecked(boolean aAllowUnchecked)
 65  
     {
 66  2
         mAllowUnchecked = aAllowUnchecked;
 67  2
     }
 68  
 
 69  
     /**
 70  
      * Getter for allowSubclasses property.
 71  
      * @param aAllowSubclasses whether subclass of another declared
 72  
      *                         exception is allowed in throws clause
 73  
      */
 74  
     public void setAllowSubclasses(boolean aAllowSubclasses)
 75  
     {
 76  2
         mAllowSubclasses = aAllowSubclasses;
 77  2
     }
 78  
 
 79  
     @Override
 80  
     public int[] getDefaultTokens()
 81  
     {
 82  10
         return new int[] {
 83  
             TokenTypes.PACKAGE_DEF,
 84  
             TokenTypes.IMPORT,
 85  
             TokenTypes.CLASS_DEF,
 86  
             TokenTypes.ENUM_DEF,
 87  
             TokenTypes.METHOD_DEF,
 88  
             TokenTypes.CTOR_DEF,
 89  
         };
 90  
     }
 91  
 
 92  
     @Override
 93  
     protected final void processAST(DetailAST aAST)
 94  
     {
 95  46
         final List<ClassInfo> knownExcs = Lists.newLinkedList();
 96  46
         final DetailAST throwsAST =
 97  
             aAST.findFirstToken(TokenTypes.LITERAL_THROWS);
 98  46
         if (throwsAST != null) {
 99  39
             DetailAST child = throwsAST.getFirstChild();
 100  120
             while (child != null) {
 101  81
                 if ((child.getType() == TokenTypes.IDENT)
 102  
                     || (child.getType() == TokenTypes.DOT))
 103  
                 {
 104  60
                     final FullIdent fi = FullIdent.createFullIdent(child);
 105  60
                     checkException(fi, knownExcs);
 106  
                 }
 107  81
                 child = child.getNextSibling();
 108  
             }
 109  
         }
 110  46
     }
 111  
 
 112  
     @Override
 113  
     protected final void logLoadError(Token aIdent)
 114  
     {
 115  0
         logLoadErrorImpl(aIdent.getLineNo(), aIdent.getColumnNo(),
 116  
                          "redundant.throws.classInfo", aIdent.getText());
 117  0
     }
 118  
 
 119  
     /**
 120  
      * Checks if an exception is already know (list of known
 121  
      * exceptions contains it or its superclass) and it's not
 122  
      * a superclass for some known exception and it's not
 123  
      * an unchecked exception.
 124  
      * If it's unknown then it will be added to ist of known exception.
 125  
      * All subclasses of this exception will be deleted from known
 126  
      * and the exception  will be added instead.
 127  
      *
 128  
      * @param aExc <code>FullIdent</code> of exception to check
 129  
      * @param aKnownExcs list of already known exception
 130  
      */
 131  
     private void checkException(FullIdent aExc, List<ClassInfo> aKnownExcs)
 132  
     {
 133  
         // Let's try to load class.
 134  60
         final ClassInfo newClassInfo =
 135  
             createClassInfo(new Token(aExc), getCurrentClassName());
 136  
 
 137  60
         if (!mAllowUnchecked && isUnchecked(newClassInfo.getClazz())) {
 138  13
             log(aExc.getLineNo(), aExc.getColumnNo(),
 139  
                 "redundant.throws.unchecked", aExc.getText());
 140  
         }
 141  
 
 142  60
         boolean shouldAdd = true;
 143  60
         for (final Iterator<ClassInfo> known = aKnownExcs.iterator(); known
 144  81
                 .hasNext();)
 145  
         {
 146  21
             final ClassInfo ci = known.next();
 147  21
             final Token fi = ci.getName();
 148  
 
 149  21
             if (ci.getClazz() == newClassInfo.getClazz()) {
 150  5
                 shouldAdd = false;
 151  5
                 log(aExc.getLineNo(), aExc.getColumnNo(),
 152  
                     "redundant.throws.duplicate", aExc.getText());
 153  
             }
 154  16
             else if (!mAllowSubclasses) {
 155  10
                 if (isSubclass(ci.getClazz(), newClassInfo.getClazz())) {
 156  4
                     known.remove();
 157  4
                     log(fi.getLineNo(), fi.getColumnNo(),
 158  
                         "redundant.throws.subclass",
 159  
                         fi.getText(), aExc.getText());
 160  
                 }
 161  6
                 else if (isSubclass(newClassInfo.getClazz(), ci.getClazz())) {
 162  3
                     shouldAdd = false;
 163  3
                     log(aExc.getLineNo(), aExc.getColumnNo(),
 164  
                         "redundant.throws.subclass",
 165  
                         aExc.getText(), fi.getText());
 166  
                 }
 167  
             }
 168  21
         }
 169  
 
 170  60
         if (shouldAdd) {
 171  52
             aKnownExcs.add(newClassInfo);
 172  
         }
 173  60
     }
 174  
 }