Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.AbstractSuperCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractSuperCheck
90%
46/51
78%
36/46
3.909
AbstractSuperCheck$MethodNode
100%
8/8
N/A
3.909
 
 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  
 
 20  
 package com.puppycrawl.tools.checkstyle.checks.coding;
 21  
 
 22  
 import antlr.collections.AST;
 23  
 import com.google.common.collect.Lists;
 24  
 import com.puppycrawl.tools.checkstyle.api.Check;
 25  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 26  
 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
 27  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 28  
 import java.util.LinkedList;
 29  
 
 30  
 /**
 31  
  * <p>
 32  
  * Abstract class for checking that an overriding method with no parameters
 33  
  * invokes the super method.
 34  
  * </p>
 35  
  * @author Rick Giles
 36  
  */
 37  2
 public abstract class AbstractSuperCheck
 38  
         extends Check
 39  
 {
 40  
     /**
 41  
      * Stack node for a method definition and a record of
 42  
      * whether the method has a call to the super method.
 43  
      * @author Rick Giles
 44  
      */
 45  
     private static class MethodNode
 46  
     {
 47  
         /** method definition */
 48  
         private final DetailAST mMethod;
 49  
 
 50  
         /** true if the overriding method calls the super method */
 51  
         private boolean mCallsSuper;
 52  
 
 53  
         /**
 54  
          * Constructs a stack node for a method definition.
 55  
          * @param aAST AST for the method definition.
 56  
          */
 57  
         public MethodNode(DetailAST aAST)
 58  10
         {
 59  10
             mMethod = aAST;
 60  10
             mCallsSuper = false;
 61  10
         }
 62  
 
 63  
         /**
 64  
          * Records that the overriding method has a call to the super method.
 65  
          */
 66  
         public void setCallsSuper()
 67  
         {
 68  5
             mCallsSuper = true;
 69  5
         }
 70  
 
 71  
         /**
 72  
          * Determines whether the overriding method has a call to the super
 73  
          * method.
 74  
          * @return true if the overriding method has a call to the super
 75  
          * method.
 76  
          */
 77  
         public boolean getCallsSuper()
 78  
         {
 79  10
             return mCallsSuper;
 80  
         }
 81  
 
 82  
         /**
 83  
          * Returns the overriding method definition AST.
 84  
          * @return the overriding method definition AST.
 85  
          */
 86  
         public DetailAST getMethod()
 87  
         {
 88  5
             return mMethod;
 89  
         }
 90  
     }
 91  
 
 92  
     /** stack of methods */
 93  2
     private final LinkedList<MethodNode> mMethodStack = Lists.newLinkedList();
 94  
 
 95  
     @Override
 96  
     public int[] getDefaultTokens()
 97  
     {
 98  2
         return new int[] {
 99  
             TokenTypes.METHOD_DEF,
 100  
             TokenTypes.LITERAL_SUPER,
 101  
         };
 102  
     }
 103  
 
 104  
     /**
 105  
      * Returns the name of the overriding method.
 106  
      * @return the name of the overriding method.
 107  
      */
 108  
     protected abstract String getMethodName();
 109  
 
 110  
     @Override
 111  
     public void beginTree(DetailAST aRootAST)
 112  
     {
 113  2
         mMethodStack.clear();
 114  2
     }
 115  
 
 116  
     @Override
 117  
     public void visitToken(DetailAST aAST)
 118  
     {
 119  29
         if (isOverridingMethod(aAST)) {
 120  10
             mMethodStack.add(new MethodNode(aAST));
 121  
         }
 122  19
         else if (isSuperCall(aAST)) {
 123  5
             final MethodNode methodNode = mMethodStack.getLast();
 124  5
             methodNode.setCallsSuper();
 125  
         }
 126  29
     }
 127  
 
 128  
     /**
 129  
      *  Determines whether a 'super' literal is a call to the super method
 130  
      * for this check.
 131  
      * @param aAST the AST node of a 'super' literal.
 132  
      * @return true if aAST is a call to the super method
 133  
      * for this check.
 134  
      */
 135  
     private boolean isSuperCall(DetailAST aAST)
 136  
     {
 137  19
         if (aAST.getType() != TokenTypes.LITERAL_SUPER) {
 138  6
             return false;
 139  
         }
 140  
         // dot operator?
 141  13
         DetailAST parent = aAST.getParent();
 142  13
         if ((parent == null) || (parent.getType() != TokenTypes.DOT)) {
 143  0
             return false;
 144  
         }
 145  
 
 146  
         // same name of method
 147  13
         AST sibling = aAST.getNextSibling();
 148  
         // ignore type parameters
 149  13
         if ((sibling != null)
 150  
             && (sibling.getType() == TokenTypes.TYPE_ARGUMENTS))
 151  
         {
 152  1
             sibling = sibling.getNextSibling();
 153  
         }
 154  13
         if ((sibling == null) || (sibling.getType() != TokenTypes.IDENT)) {
 155  0
             return false;
 156  
         }
 157  13
         final String name = sibling.getText();
 158  13
         if (!getMethodName().equals(name)) {
 159  2
             return false;
 160  
         }
 161  
 
 162  
         // 0 parameters?
 163  11
         final DetailAST args = parent.getNextSibling();
 164  11
         if ((args == null) || (args.getType() != TokenTypes.ELIST)) {
 165  0
             return false;
 166  
         }
 167  11
         if (args.getChildCount() != 0) {
 168  0
             return false;
 169  
         }
 170  
 
 171  
         // in an overriding method for this check?
 172  58
         while (parent != null) {
 173  58
             if (parent.getType() == TokenTypes.METHOD_DEF) {
 174  7
                 return isOverridingMethod(parent);
 175  
             }
 176  51
             else if ((parent.getType() == TokenTypes.CTOR_DEF)
 177  
                 || (parent.getType() == TokenTypes.INSTANCE_INIT))
 178  
             {
 179  4
                 return false;
 180  
             }
 181  47
             parent = parent.getParent();
 182  
         }
 183  0
         return false;
 184  
     }
 185  
 
 186  
     @Override
 187  
     public void leaveToken(DetailAST aAST)
 188  
     {
 189  29
         if (isOverridingMethod(aAST)) {
 190  10
             final MethodNode methodNode =
 191  
                 mMethodStack.removeLast();
 192  10
             if (!methodNode.getCallsSuper()) {
 193  5
                 final DetailAST methodAST = methodNode.getMethod();
 194  5
                 final DetailAST nameAST =
 195  
                     methodAST.findFirstToken(TokenTypes.IDENT);
 196  5
                 log(nameAST.getLineNo(), nameAST.getColumnNo(),
 197  
                     "missing.super.call", nameAST.getText());
 198  
             }
 199  
         }
 200  29
     }
 201  
 
 202  
     /**
 203  
      * Determines whether an AST is a method definition for this check,
 204  
      * with 0 parameters.
 205  
      * @param aAST the method definition AST.
 206  
      * @return true if the method of aAST is a method for this check.
 207  
      */
 208  
     private boolean isOverridingMethod(DetailAST aAST)
 209  
     {
 210  65
         if ((aAST.getType() != TokenTypes.METHOD_DEF)
 211  
             || ScopeUtils.inInterfaceOrAnnotationBlock(aAST))
 212  
         {
 213  26
             return false;
 214  
         }
 215  39
         final DetailAST nameAST = aAST.findFirstToken(TokenTypes.IDENT);
 216  39
         final String name = nameAST.getText();
 217  39
         if (!getMethodName().equals(name)) {
 218  10
             return false;
 219  
         }
 220  29
         final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS);
 221  29
         return (params.getChildCount() == 0);
 222  
     }
 223  
 }