Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.CovariantEqualsCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
CovariantEqualsCheck
93%
27/29
95%
19/20
3.5
 
 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.Sets;
 22  
 import com.puppycrawl.tools.checkstyle.api.Check;
 23  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 24  
 import com.puppycrawl.tools.checkstyle.api.FullIdent;
 25  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 26  
 import com.puppycrawl.tools.checkstyle.checks.CheckUtils;
 27  
 import java.util.Set;
 28  
 
 29  
 /**
 30  
  * <p>Checks that if a class defines a covariant method equals,
 31  
  * then it defines method equals(java.lang.Object).
 32  
  * Inspired by findbugs,
 33  
  * http://www.cs.umd.edu/~pugh/java/bugs/docs/findbugsPaper.pdf
 34  
  * </p>
 35  
  * <p>
 36  
  * An example of how to configure the check is:
 37  
  * </p>
 38  
  * <pre>
 39  
  * &lt;module name="CovariantEquals"/&gt;
 40  
  * </pre>
 41  
  * @author Rick Giles
 42  
  * @version 1.0
 43  
  */
 44  1
 public class CovariantEqualsCheck extends Check
 45  
 {
 46  
     /** Set of equals method definitions */
 47  1
     private final Set<DetailAST> mEqualsMethods = Sets.newHashSet();
 48  
 
 49  
     @Override
 50  
     public int[] getDefaultTokens()
 51  
     {
 52  1
         return new int[] {TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, };
 53  
     }
 54  
 
 55  
     @Override
 56  
     public int[] getRequiredTokens()
 57  
     {
 58  0
         return getDefaultTokens();
 59  
     }
 60  
 
 61  
     @Override
 62  
     public void visitToken(DetailAST aAST)
 63  
     {
 64  12
         mEqualsMethods.clear();
 65  12
         boolean hasEqualsObject = false;
 66  
 
 67  
         // examine method definitions for equals methods
 68  12
         final DetailAST objBlock = aAST.findFirstToken(TokenTypes.OBJBLOCK);
 69  12
         if (objBlock != null) {
 70  11
             DetailAST child = objBlock.getFirstChild();
 71  54
             while (child != null) {
 72  43
                 if (child.getType() == TokenTypes.METHOD_DEF
 73  
                         && CheckUtils.isEqualsMethod(child))
 74  
                 {
 75  15
                     if (hasObjectParameter(child)) {
 76  6
                         hasEqualsObject = true;
 77  
                     }
 78  
                     else {
 79  9
                         mEqualsMethods.add(child);
 80  
                     }
 81  
                 }
 82  43
                 child = child.getNextSibling();
 83  
             }
 84  
 
 85  
             // report equals method definitions
 86  11
             if (!hasEqualsObject) {
 87  5
                 for (DetailAST equalsAST : mEqualsMethods) {
 88  4
                     final DetailAST nameNode = equalsAST
 89  
                             .findFirstToken(TokenTypes.IDENT);
 90  4
                     log(nameNode.getLineNo(), nameNode.getColumnNo(),
 91  
                             "covariant.equals");
 92  4
                 }
 93  
             }
 94  
         }
 95  12
     }
 96  
 
 97  
     /**
 98  
      * Tests whether a method definition AST has exactly one
 99  
      * parameter of type Object.
 100  
      * @param aAST the method definition AST to test.
 101  
      * Precondition: aAST is a TokenTypes.METHOD_DEF node.
 102  
      * @return true if aAST has exactly one parameter of type Object.
 103  
      */
 104  
     private boolean hasObjectParameter(DetailAST aAST)
 105  
     {
 106  
         // one parameter?
 107  15
         final DetailAST paramsNode = aAST.findFirstToken(TokenTypes.PARAMETERS);
 108  15
         if (paramsNode.getChildCount() != 1) {
 109  0
             return false;
 110  
         }
 111  
 
 112  
         // parameter type "Object"?
 113  15
         final DetailAST paramNode =
 114  
             paramsNode.findFirstToken(TokenTypes.PARAMETER_DEF);
 115  15
         final DetailAST typeNode = paramNode.findFirstToken(TokenTypes.TYPE);
 116  15
         final FullIdent fullIdent = FullIdent.createFullIdentBelow(typeNode);
 117  15
         final String name = fullIdent.getText();
 118  15
         return ("Object".equals(name) || "java.lang.Object".equals(name));
 119  
     }
 120  
 }