Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.CovariantEqualsCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
CovariantEqualsCheck
100%
31/31
100%
18/18
2.6
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 the original author or authors.
 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 java.util.HashSet;
 23  
 import java.util.Set;
 24  
 
 25  
 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
 26  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 27  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 28  
 import com.puppycrawl.tools.checkstyle.api.FullIdent;
 29  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 30  
 import com.puppycrawl.tools.checkstyle.utils.CheckUtils;
 31  
 
 32  
 /**
 33  
  * <p>Checks that if a class defines a covariant method equals,
 34  
  * then it defines method equals(java.lang.Object).
 35  
  * Inspired by findbugs,
 36  
  * http://findbugs.sourceforge.net/bugDescriptions.html#EQ_SELF_NO_OBJECT
 37  
  * </p>
 38  
  * <p>
 39  
  * An example of how to configure the check is:
 40  
  * </p>
 41  
  * <pre>
 42  
  * &lt;module name="CovariantEquals"/&gt;
 43  
  * </pre>
 44  
  * @author Rick Giles
 45  
  */
 46  
 @FileStatefulCheck
 47  9
 public class CovariantEqualsCheck extends AbstractCheck {
 48  
 
 49  
     /**
 50  
      * A key is pointing to the warning message text in "messages.properties"
 51  
      * file.
 52  
      */
 53  
     public static final String MSG_KEY = "covariant.equals";
 54  
 
 55  
     /** Set of equals method definitions. */
 56  9
     private final Set<DetailAST> equalsMethods = new HashSet<>();
 57  
 
 58  
     @Override
 59  
     public int[] getDefaultTokens() {
 60  11
         return getRequiredTokens();
 61  
     }
 62  
 
 63  
     @Override
 64  
     public int[] getRequiredTokens() {
 65  27
         return new int[] {TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, TokenTypes.ENUM_DEF, };
 66  
     }
 67  
 
 68  
     @Override
 69  
     public int[] getAcceptableTokens() {
 70  5
         return getRequiredTokens();
 71  
     }
 72  
 
 73  
     @Override
 74  
     public void visitToken(DetailAST ast) {
 75  13
         equalsMethods.clear();
 76  
 
 77  
         // examine method definitions for equals methods
 78  13
         final DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK);
 79  13
         if (objBlock != null) {
 80  12
             DetailAST child = objBlock.getFirstChild();
 81  12
             boolean hasEqualsObject = false;
 82  61
             while (child != null) {
 83  49
                 if (child.getType() == TokenTypes.METHOD_DEF
 84  20
                         && CheckUtils.isEqualsMethod(child)) {
 85  17
                     if (isFirstParameterObject(child)) {
 86  6
                         hasEqualsObject = true;
 87  
                     }
 88  
                     else {
 89  11
                         equalsMethods.add(child);
 90  
                     }
 91  
                 }
 92  49
                 child = child.getNextSibling();
 93  
             }
 94  
 
 95  
             // report equals method definitions
 96  12
             if (!hasEqualsObject) {
 97  6
                 for (DetailAST equalsAST : equalsMethods) {
 98  6
                     final DetailAST nameNode = equalsAST
 99  6
                             .findFirstToken(TokenTypes.IDENT);
 100  6
                     log(nameNode.getLineNo(), nameNode.getColumnNo(),
 101  
                             MSG_KEY);
 102  6
                 }
 103  
             }
 104  
         }
 105  13
     }
 106  
 
 107  
     /**
 108  
      * Tests whether a method's first parameter is an Object.
 109  
      * @param methodDefAst the method definition AST to test.
 110  
      *     Precondition: ast is a TokenTypes.METHOD_DEF node.
 111  
      * @return true if ast has first parameter of type Object.
 112  
      */
 113  
     private static boolean isFirstParameterObject(DetailAST methodDefAst) {
 114  17
         final DetailAST paramsNode = methodDefAst.findFirstToken(TokenTypes.PARAMETERS);
 115  
 
 116  
         // parameter type "Object"?
 117  17
         final DetailAST paramNode =
 118  17
             paramsNode.findFirstToken(TokenTypes.PARAMETER_DEF);
 119  17
         final DetailAST typeNode = paramNode.findFirstToken(TokenTypes.TYPE);
 120  17
         final FullIdent fullIdent = FullIdent.createFullIdentBelow(typeNode);
 121  17
         final String name = fullIdent.getText();
 122  17
         return "Object".equals(name) || "java.lang.Object".equals(name);
 123  
     }
 124  
 }