Coverage Report - com.puppycrawl.tools.checkstyle.checks.CheckUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
CheckUtils
96%
82/85
85%
61/71
3.571
 
 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;
 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 java.util.List;
 26  
 
 27  
 /**
 28  
  * Contains utility methods for the checks.
 29  
  *
 30  
  * @author Oliver Burn
 31  
  * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
 32  
  * @author o_sukhodolsky
 33  
  */
 34  
 public final class CheckUtils
 35  
 {
 36  
     /** prevent instances */
 37  
     private CheckUtils()
 38  0
     {
 39  0
         throw new UnsupportedOperationException();
 40  
     }
 41  
 
 42  
     /**
 43  
      * Tests whether a method definition AST defines an equals covariant.
 44  
      * @param aAST the method definition AST to test.
 45  
      * Precondition: aAST is a TokenTypes.METHOD_DEF node.
 46  
      * @return true if aAST defines an equals covariant.
 47  
      */
 48  
     public static boolean isEqualsMethod(DetailAST aAST)
 49  
     {
 50  24
         if (aAST.getType() != TokenTypes.METHOD_DEF) {
 51  
             // A node must be method def
 52  0
             return false;
 53  
         }
 54  
 
 55  
         // non-static, non-abstract?
 56  24
         final DetailAST modifiers = aAST.findFirstToken(TokenTypes.MODIFIERS);
 57  24
         if (modifiers.branchContains(TokenTypes.LITERAL_STATIC)
 58  
             || modifiers.branchContains(TokenTypes.ABSTRACT))
 59  
         {
 60  1
             return false;
 61  
         }
 62  
 
 63  
         // named "equals"?
 64  23
         final DetailAST nameNode = aAST.findFirstToken(TokenTypes.IDENT);
 65  23
         final String name = nameNode.getText();
 66  23
         if (!"equals".equals(name)) {
 67  6
             return false;
 68  
         }
 69  
 
 70  
         // one parameter?
 71  17
         final DetailAST paramsNode = aAST.findFirstToken(TokenTypes.PARAMETERS);
 72  17
         return (paramsNode.getChildCount() == 1);
 73  
     }
 74  
 
 75  
     /**
 76  
      * Returns whether a token represents an ELSE as part of an ELSE / IF set.
 77  
      * @param aAST the token to check
 78  
      * @return whether it is
 79  
      */
 80  
     public static boolean isElseIf(DetailAST aAST)
 81  
     {
 82  68
         final DetailAST parentAST = aAST.getParent();
 83  
 
 84  68
         return (aAST.getType() == TokenTypes.LITERAL_IF)
 85  
             && (isElse(parentAST) || isElseWithCurlyBraces(parentAST));
 86  
     }
 87  
 
 88  
     /**
 89  
      * Returns whether a token represents an ELSE.
 90  
      * @param aAST the token to check
 91  
      * @return whether the token represents an ELSE
 92  
      */
 93  
     private static boolean isElse(DetailAST aAST)
 94  
     {
 95  112
         return aAST.getType() == TokenTypes.LITERAL_ELSE;
 96  
     }
 97  
 
 98  
     /**
 99  
      * Returns whether a token represents an SLIST as part of an ELSE
 100  
      * statement.
 101  
      * @param aAST the token to check
 102  
      * @return whether the toke does represent an SLIST as part of an ELSE
 103  
      */
 104  
     private static boolean isElseWithCurlyBraces(DetailAST aAST)
 105  
     {
 106  68
         return (aAST.getType() == TokenTypes.SLIST)
 107  
             && (aAST.getChildCount() == 2)
 108  
             && isElse(aAST.getParent());
 109  
     }
 110  
 
 111  
     /**
 112  
      * Creates <code>FullIdent</code> for given type node.
 113  
      * @param aTypeAST a type node.
 114  
      * @return <code>FullIdent</code> for given type.
 115  
      */
 116  
     public static FullIdent createFullType(DetailAST aTypeAST)
 117  
     {
 118  117
         final DetailAST arrayDeclAST =
 119  
             aTypeAST.findFirstToken(TokenTypes.ARRAY_DECLARATOR);
 120  
 
 121  117
         return createFullTypeNoArrays(arrayDeclAST == null ? aTypeAST
 122  
                                                            : arrayDeclAST);
 123  
     }
 124  
 
 125  
     /**
 126  
      * @param aTypeAST a type node (no array)
 127  
      * @return <code>FullIdent</code> for given type.
 128  
      */
 129  
     private static FullIdent createFullTypeNoArrays(DetailAST aTypeAST)
 130  
     {
 131  117
         return FullIdent.createFullIdent(aTypeAST.getFirstChild());
 132  
     }
 133  
 
 134  
     // constants for parseDouble()
 135  
     /** octal radix */
 136  
     private static final int BASE_8 = 8;
 137  
 
 138  
     /** decimal radix */
 139  
     private static final int BASE_10 = 10;
 140  
 
 141  
     /** hex radix */
 142  
     private static final int BASE_16 = 16;
 143  
 
 144  
     /**
 145  
      * Returns the value represented by the specified string of the specified
 146  
      * type. Returns 0 for types other than float, double, int, and long.
 147  
      * @param aText the string to be parsed.
 148  
      * @param aType the token type of the text. Should be a constant of
 149  
      * {@link com.puppycrawl.tools.checkstyle.api.TokenTypes}.
 150  
      * @return the double value represented by the string argument.
 151  
      */
 152  
     public static double parseDouble(String aText, int aType)
 153  
     {
 154  515
         String txt = aText;
 155  515
         double result = 0;
 156  515
         switch (aType) {
 157  
         case TokenTypes.NUM_FLOAT:
 158  
         case TokenTypes.NUM_DOUBLE:
 159  62
             result = Double.parseDouble(txt);
 160  62
             break;
 161  
         case TokenTypes.NUM_INT:
 162  
         case TokenTypes.NUM_LONG:
 163  453
             int radix = BASE_10;
 164  453
             if (txt.startsWith("0x") || txt.startsWith("0X")) {
 165  72
                 radix = BASE_16;
 166  72
                 txt = txt.substring(2);
 167  
             }
 168  381
             else if (txt.charAt(0) == '0') {
 169  77
                 radix = BASE_8;
 170  77
                 txt = txt.substring(1);
 171  
             }
 172  453
             if ((txt.endsWith("L")) || (txt.endsWith("l"))) {
 173  85
                 txt = txt.substring(0, txt.length() - 1);
 174  
             }
 175  453
             if (txt.length() > 0) {
 176  430
                 if (aType == TokenTypes.NUM_INT) {
 177  358
                     result = parseInt(txt, radix);
 178  
                 }
 179  
                 else {
 180  72
                     result = parseLong(txt, radix);
 181  
                 }
 182  
             }
 183  
             break;
 184  
         default:
 185  
             break;
 186  
         }
 187  515
         return result;
 188  
     }
 189  
 
 190  
     /**
 191  
      * Parses the string argument as a signed integer in the radix specified by
 192  
      * the second argument. The characters in the string must all be digits of
 193  
      * the specified radix. Handles negative values, which method
 194  
      * java.lang.Integer.parseInt(String, int) does not.
 195  
      * @param aText the String containing the integer representation to be
 196  
      * parsed. Precondition: aText contains a parsable int.
 197  
      * @param aRadix the radix to be used while parsing aText.
 198  
      * @return the integer represented by the string argument in the specified
 199  
      * radix.
 200  
      */
 201  
     public static int parseInt(String aText, int aRadix)
 202  
     {
 203  358
         int result = 0;
 204  358
         final int max = aText.length();
 205  1059
         for (int i = 0; i < max; i++) {
 206  701
             final int digit = Character.digit(aText.charAt(i), aRadix);
 207  701
             result *= aRadix;
 208  701
             result += digit;
 209  
         }
 210  358
         return result;
 211  
     }
 212  
 
 213  
     /**
 214  
      * Parses the string argument as a signed long in the radix specified by
 215  
      * the second argument. The characters in the string must all be digits of
 216  
      * the specified radix. Handles negative values, which method
 217  
      * java.lang.Integer.parseInt(String, int) does not.
 218  
      * @param aText the String containing the integer representation to be
 219  
      * parsed. Precondition: aText contains a parsable int.
 220  
      * @param aRadix the radix to be used while parsing aText.
 221  
      * @return the long represented by the string argument in the specified
 222  
      * radix.
 223  
      */
 224  
     public static long parseLong(String aText, int aRadix)
 225  
     {
 226  72
         long result = 0;
 227  72
         final int max = aText.length();
 228  666
         for (int i = 0; i < max; i++) {
 229  594
             final int digit = Character.digit(aText.charAt(i), aRadix);
 230  594
             result *= aRadix;
 231  594
             result += digit;
 232  
         }
 233  72
         return result;
 234  
     }
 235  
 
 236  
     /**
 237  
      * Returns the value represented by the specified string of the specified
 238  
      * type. Returns 0 for types other than float, double, int, and long.
 239  
      * @param aText the string to be parsed.
 240  
      * @param aType the token type of the text. Should be a constant of
 241  
      * {@link com.puppycrawl.tools.checkstyle.api.TokenTypes}.
 242  
      * @return the float value represented by the string argument.
 243  
      */
 244  
     public static double parseFloat(String aText, int aType)
 245  
     {
 246  10
         return (float) parseDouble(aText, aType);
 247  
     }
 248  
 
 249  
     /**
 250  
      * Finds sub-node for given node minimal (line, column) pair.
 251  
      * @param aNode the root of tree for search.
 252  
      * @return sub-node with minimal (line, column) pair.
 253  
      */
 254  
     public static DetailAST getFirstNode(final DetailAST aNode)
 255  
     {
 256  547
         DetailAST currentNode = aNode;
 257  547
         DetailAST child = aNode.getFirstChild();
 258  1026
         while (child != null) {
 259  479
             final DetailAST newNode = getFirstNode(child);
 260  479
             if ((newNode.getLineNo() < currentNode.getLineNo())
 261  
                 || ((newNode.getLineNo() == currentNode.getLineNo())
 262  
                     && (newNode.getColumnNo() < currentNode.getColumnNo())))
 263  
             {
 264  79
                 currentNode = newNode;
 265  
             }
 266  479
             child = child.getNextSibling();
 267  479
         }
 268  
 
 269  547
         return currentNode;
 270  
     }
 271  
 
 272  
     /**
 273  
      * Retrieves the names of the type parameters to the node.
 274  
      * @param aNode the parameterised AST node
 275  
      * @return a list of type parameter names
 276  
      */
 277  
     public static List<String> getTypeParameterNames(final DetailAST aNode)
 278  
     {
 279  217
         final DetailAST typeParameters =
 280  
             aNode.findFirstToken(TokenTypes.TYPE_PARAMETERS);
 281  
 
 282  217
         final List<String> typeParamNames = Lists.newArrayList();
 283  217
         if (typeParameters != null) {
 284  27
             final DetailAST typeParam =
 285  
                 typeParameters.findFirstToken(TokenTypes.TYPE_PARAMETER);
 286  27
             typeParamNames.add(
 287  
                 typeParam.findFirstToken(TokenTypes.IDENT).getText());
 288  
 
 289  27
             DetailAST sibling = typeParam.getNextSibling();
 290  72
             while (sibling != null) {
 291  45
                 if (sibling.getType() == TokenTypes.TYPE_PARAMETER) {
 292  9
                     typeParamNames.add(
 293  
                         sibling.findFirstToken(TokenTypes.IDENT).getText());
 294  
                 }
 295  45
                 sibling = sibling.getNextSibling();
 296  
             }
 297  
         }
 298  
 
 299  217
         return typeParamNames;
 300  
     }
 301  
 
 302  
     /**
 303  
      * Retrieves the type parameters to the node.
 304  
      * @param aNode the parameterised AST node
 305  
      * @return a list of type parameter names
 306  
      */
 307  
     public static List<DetailAST> getTypeParameters(final DetailAST aNode)
 308  
     {
 309  134
         final DetailAST typeParameters =
 310  
             aNode.findFirstToken(TokenTypes.TYPE_PARAMETERS);
 311  
 
 312  134
         final List<DetailAST> typeParams = Lists.newArrayList();
 313  134
         if (typeParameters != null) {
 314  6
             final DetailAST typeParam =
 315  
                 typeParameters.findFirstToken(TokenTypes.TYPE_PARAMETER);
 316  6
             typeParams.add(typeParam);
 317  
 
 318  6
             DetailAST sibling = typeParam.getNextSibling();
 319  14
             while (sibling != null) {
 320  8
                 if (sibling.getType() == TokenTypes.TYPE_PARAMETER) {
 321  1
                     typeParams.add(sibling);
 322  
                 }
 323  8
                 sibling = sibling.getNextSibling();
 324  
             }
 325  
         }
 326  
 
 327  134
         return typeParams;
 328  
     }
 329  
 }