001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.checks.coding; 020 021import com.puppycrawl.tools.checkstyle.api.DetailAST; 022import com.puppycrawl.tools.checkstyle.api.ScopeUtils; 023import com.puppycrawl.tools.checkstyle.api.TokenTypes; 024import com.puppycrawl.tools.checkstyle.checks.DeclarationCollector; 025 026/** 027 * <p>Checks that code doesn't rely on the "this" default. 028 * That is references to instance variables and methods of the present 029 * object are explicitly of the form "this.varName" or 030 * "this.methodName(args)". 031 *</p> 032 * <p>Examples of use: 033 * <pre> 034 * <module name="RequireThis"/> 035 * </pre> 036 * An example of how to configure to check <code>this</code> qualifier for 037 * methods only: 038 * <pre> 039 * <module name="RequireThis"> 040 * <property name="checkFields" value="false"/> 041 * <property name="checkMethods" value="true"/> 042 * </module> 043 * </pre> 044 * 045 * <p>Limitations: I'm not currently doing anything about static variables 046 * or catch-blocks. Static methods invoked on a class name seem to be OK; 047 * both the class name and the method name have a DOT parent. 048 * Non-static methods invoked on either this or a variable name seem to be 049 * OK, likewise.</p> 050 * <p>Much of the code for this check was cribbed from Rick Giles's 051 * <code>HiddenFieldCheck</code>.</p> 052 * 053 * @author Stephen Bloch 054 * @author o_sukhodolsky 055 */ 056public class RequireThisCheck extends DeclarationCollector 057{ 058 /** whether we should check fields usage. */ 059 private boolean checkFields = true; 060 /** whether we should check methods usage. */ 061 private boolean checkMethods = true; 062 063 /** 064 * Setter for checkFields property. 065 * @param checkFields should we check fields usage or not. 066 */ 067 public void setCheckFields(boolean checkFields) 068 { 069 this.checkFields = checkFields; 070 } 071 /** 072 * @return true if we should check fields usage false otherwise. 073 */ 074 public boolean getCheckFields() 075 { 076 return checkFields; 077 } 078 079 /** 080 * Setter for checkMethods property. 081 * @param checkMethods should we check methods usage or not. 082 */ 083 public void setCheckMethods(boolean checkMethods) 084 { 085 this.checkMethods = checkMethods; 086 } 087 /** 088 * @return true if we should check methods usage false otherwise. 089 */ 090 public boolean getCheckMethods() 091 { 092 return checkMethods; 093 } 094 095 /** Creates new instance of the check. */ 096 public RequireThisCheck() 097 { 098 } 099 100 @Override 101 public int[] getDefaultTokens() 102 { 103 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 return getDefaultTokens(); 120 } 121 122 @Override 123 public void visitToken(DetailAST ast) 124 { 125 super.visitToken(ast); 126 if (ast.getType() == TokenTypes.IDENT) { 127 processIDENT(ast); 128 } 129 } // 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 ast IDENT to check. 136 */ 137 private void processIDENT(DetailAST ast) 138 { 139 final int parentType = ast.getParent().getType(); 140 141 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 return; 147 } 148 149 // let's check method calls 150 if (parentType == TokenTypes.METHOD_CALL) { 151 if (checkMethods && isClassMethod(ast.getText())) { 152 log(ast, "require.this.method", ast.getText()); 153 } 154 return; 155 } 156 157 // let's check fields 158 if (!checkFields) { 159 // we shouldn't check fields 160 return; 161 } 162 163 if (ScopeUtils.getSurroundingScope(ast) == null) { 164 // it is not a class or interface it's 165 // either import or package 166 // we shouldn't checks this 167 return; 168 } 169 170 if ((parentType == TokenTypes.DOT) 171 && (ast.getPreviousSibling() != null)) 172 { 173 // it's the method name in a method call; no problem 174 return; 175 } 176 if ((parentType == TokenTypes.TYPE) 177 || (parentType == TokenTypes.LITERAL_NEW)) 178 { 179 // it's a type name; no problem 180 return; 181 } 182 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 return; 193 } 194 195 final String name = ast.getText(); 196 if (isClassField(name)) { 197 log(ast, "require.this.variable", name); 198 } 199 } 200} // end class RequireThis