Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
RequireThisCheck
91%
34/37
97%
43/44
4.222
 
 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.puppycrawl.tools.checkstyle.api.DetailAST;
 22  
 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
 23  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 24  
 import com.puppycrawl.tools.checkstyle.checks.DeclarationCollector;
 25  
 
 26  
 /**
 27  
  * <p>Checks that code doesn't rely on the &quot;this&quot; default.
 28  
  * That is references to instance variables and methods of the present
 29  
  * object are explicitly of the form &quot;this.varName&quot; or
 30  
  * &quot;this.methodName(args)&quot;.
 31  
  *</p>
 32  
  * <p>Examples of use:
 33  
  * <pre>
 34  
  * &lt;module name=&quot;RequireThis&quot;/&gt;
 35  
  * </pre>
 36  
  * An example of how to configure to check <code>this</code> qualifier for
 37  
  * methods only:
 38  
  * <pre>
 39  
  * &lt;module name=&quot;RequireThis&quot;&gt;
 40  
  *   &lt;property name=&quot;checkFields&quot; value=&quot;false&quot;/&gt;
 41  
  *   &lt;property name=&quot;checkMethods&quot; value=&quot;true&quot;/&gt;
 42  
  * &lt;/module&gt;
 43  
  * </pre>
 44  
  * </p>
 45  
  * <p>Limitations: I'm not currently doing anything about static variables
 46  
  * or catch-blocks.  Static methods invoked on a class name seem to be OK;
 47  
  * both the class name and the method name have a DOT parent.
 48  
  * Non-static methods invoked on either this or a variable name seem to be
 49  
  * OK, likewise.</p>
 50  
  * <p>Much of the code for this check was cribbed from Rick Giles's
 51  
  * <code>HiddenFieldCheck</code>.</p>
 52  
  *
 53  
  * @author Stephen Bloch
 54  
  * @author o_sukhodolsky
 55  
  */
 56  
 public class RequireThisCheck extends DeclarationCollector
 57  
 {
 58  
     /** whether we should check fields usage. */
 59  5
     private boolean mCheckFields = true;
 60  
     /** whether we should check methods usage. */
 61  5
     private boolean mCheckMethods = true;
 62  
 
 63  
     /**
 64  
      * Setter for checkFields property.
 65  
      * @param aCheckFields should we check fields usage or not.
 66  
      */
 67  
     public void setCheckFields(boolean aCheckFields)
 68  
     {
 69  1
         mCheckFields = aCheckFields;
 70  1
     }
 71  
     /**
 72  
      * @return true if we should check fields usage false otherwise.
 73  
      */
 74  
     public boolean getCheckFields()
 75  
     {
 76  0
         return mCheckFields;
 77  
     }
 78  
 
 79  
     /**
 80  
      * Setter for checkMethods property.
 81  
      * @param aCheckMethods should we check methods usage or not.
 82  
      */
 83  
     public void setCheckMethods(boolean aCheckMethods)
 84  
     {
 85  1
         mCheckMethods = aCheckMethods;
 86  1
     }
 87  
     /**
 88  
      * @return true if we should check methods usage false otherwise.
 89  
      */
 90  
     public boolean getCheckMethods()
 91  
     {
 92  0
         return mCheckMethods;
 93  
     }
 94  
 
 95  
     /** Creates new instance of the check. */
 96  
     public RequireThisCheck()
 97  5
     {
 98  5
     }
 99  
 
 100  
     @Override
 101  
     public int[] getDefaultTokens()
 102  
     {
 103  5
         return new int[] {
 104  
             TokenTypes.CLASS_DEF,
 105  
             TokenTypes.CTOR_DEF,
 106  
             TokenTypes.ENUM_DEF,
 107  
             TokenTypes.IDENT,
 108  
             TokenTypes.INTERFACE_DEF,
 109  
             TokenTypes.METHOD_DEF,
 110  
             TokenTypes.PARAMETER_DEF,
 111  
             TokenTypes.SLIST,
 112  
             TokenTypes.VARIABLE_DEF,
 113  
         };
 114  
     }
 115  
 
 116  
     @Override
 117  
     public int[] getRequiredTokens()
 118  
     {
 119  0
         return getDefaultTokens();
 120  
     }
 121  
 
 122  
     @Override
 123  
     public void visitToken(DetailAST aAST)
 124  
     {
 125  368
         super.visitToken(aAST);
 126  368
         if (aAST.getType() == TokenTypes.IDENT) {
 127  245
             processIDENT(aAST);
 128  
         }
 129  368
     } // end visitToken
 130  
 
 131  
     /**
 132  
      * Checks if a given IDENT is method call or field name which
 133  
      * require explicit <code>this</code> qualifier.
 134  
      *
 135  
      * @param aAST IDENT to check.
 136  
      */
 137  
     private void processIDENT(DetailAST aAST)
 138  
     {
 139  245
         final int parentType = aAST.getParent().getType();
 140  
 
 141  245
         if (parentType == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR
 142  
             || parentType == TokenTypes.ANNOTATION
 143  
             || parentType == TokenTypes.ANNOTATION_FIELD_DEF)
 144  
         {
 145  
             //cannot refer to 'this' from annotations
 146  26
             return;
 147  
         }
 148  
 
 149  
         // let's check method calls
 150  219
         if (parentType == TokenTypes.METHOD_CALL) {
 151  7
             if (mCheckMethods && isClassField(aAST.getText())) {
 152  3
                 log(aAST, "require.this.method", aAST.getText());
 153  
             }
 154  7
             return;
 155  
         }
 156  
 
 157  
         // let's check fields
 158  212
         if (!mCheckFields) {
 159  
             // we shouldn't check fields
 160  60
             return;
 161  
         }
 162  
 
 163  152
         if (ScopeUtils.getSurroundingScope(aAST) == null) {
 164  
             // it is not a class or interface it's
 165  
             // either import or package
 166  
             // we shouldn't checks this
 167  21
             return;
 168  
         }
 169  
 
 170  131
         if ((parentType == TokenTypes.DOT)
 171  
             && (aAST.getPreviousSibling() != null))
 172  
         {
 173  
             // it's the method name in a method call; no problem
 174  14
             return;
 175  
         }
 176  117
         if ((parentType == TokenTypes.TYPE)
 177  
             || (parentType == TokenTypes.LITERAL_NEW))
 178  
         {
 179  
             // it's a type name; no problem
 180  10
             return;
 181  
         }
 182  107
         if ((parentType == TokenTypes.VARIABLE_DEF)
 183  
             || (parentType == TokenTypes.CTOR_DEF)
 184  
             || (parentType == TokenTypes.METHOD_DEF)
 185  
             || (parentType == TokenTypes.CLASS_DEF)
 186  
             || (parentType == TokenTypes.ENUM_DEF)
 187  
             || (parentType == TokenTypes.INTERFACE_DEF)
 188  
             || (parentType == TokenTypes.PARAMETER_DEF)
 189  
             || (parentType == TokenTypes.TYPE_ARGUMENT))
 190  
         {
 191  
             // it's being declared; no problem
 192  65
             return;
 193  
         }
 194  
 
 195  42
         final String name = aAST.getText();
 196  42
         if (isClassField(name)) {
 197  9
             log(aAST, "require.this.variable", name);
 198  
         }
 199  42
     }
 200  
 } // end class RequireThis