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.api; 020 021import antlr.collections.AST; 022 023/** 024 * Contains utility methods for working on scope. 025 * 026 * @author Oliver Burn 027 * @version 1.0 028 */ 029public final class ScopeUtils 030{ 031 ///CLOVER:OFF 032 /** prevent instantiation */ 033 private ScopeUtils() 034 { 035 } 036 ///CLOVER:ON 037 038 /** 039 * Returns the Scope specified by the modifier set. 040 * 041 * @param aMods root node of a modifier set 042 * @return a <code>Scope</code> value 043 */ 044 public static Scope getScopeFromMods(DetailAST aMods) 045 { 046 Scope retVal = Scope.PACKAGE; // default scope 047 for (AST token = aMods.getFirstChild(); 048 token != null; 049 token = token.getNextSibling()) 050 { 051 if ("public".equals(token.getText())) { 052 retVal = Scope.PUBLIC; 053 break; 054 } 055 else if ("protected".equals(token.getText())) { 056 retVal = Scope.PROTECTED; 057 break; 058 } 059 else if ("private".equals(token.getText())) { 060 retVal = Scope.PRIVATE; 061 break; 062 } 063 } 064 return retVal; 065 } 066 067 /** 068 * Returns the scope of the surrounding "block". 069 * @param aAST the node to return the scope for 070 * @return the Scope of the surrounding block 071 */ 072 public static Scope getSurroundingScope(DetailAST aAST) 073 { 074 Scope retVal = null; 075 for (DetailAST token = aAST.getParent(); 076 token != null; 077 token = token.getParent()) 078 { 079 final int type = token.getType(); 080 if ((type == TokenTypes.CLASS_DEF) 081 || (type == TokenTypes.INTERFACE_DEF) 082 || (type == TokenTypes.ANNOTATION_DEF) 083 || (type == TokenTypes.ENUM_DEF)) 084 { 085 final DetailAST mods = 086 token.findFirstToken(TokenTypes.MODIFIERS); 087 final Scope modScope = ScopeUtils.getScopeFromMods(mods); 088 if ((retVal == null) || (retVal.isIn(modScope))) { 089 retVal = modScope; 090 } 091 } 092 else if (type == TokenTypes.LITERAL_NEW) { 093 retVal = Scope.ANONINNER; 094 break; //because Scope.ANONINNER is not in any other Scope 095 } 096 } 097 098 return retVal; 099 } 100 101 /** 102 * Returns whether a node is directly contained within an interface block. 103 * 104 * @param aAST the node to check if directly contained within an interface 105 * block 106 * @return a <code>boolean</code> value 107 */ 108 public static boolean inInterfaceBlock(DetailAST aAST) 109 { 110 boolean retVal = false; 111 112 // Loop up looking for a containing interface block 113 for (DetailAST token = aAST.getParent(); 114 token != null; 115 token = token.getParent()) 116 { 117 final int type = token.getType(); 118 if ((type == TokenTypes.CLASS_DEF) 119 || (type == TokenTypes.ENUM_DEF) 120 || (type == TokenTypes.ANNOTATION_DEF)) 121 { 122 break; // in a class, enum or annotation 123 } 124 else if (type == TokenTypes.LITERAL_NEW) { 125 break; // inner implementation 126 } 127 else if (type == TokenTypes.INTERFACE_DEF) { 128 retVal = true; 129 break; 130 } 131 } 132 133 return retVal; 134 } 135 136 /** 137 * Returns whether a node is directly contained within an annotation block. 138 * 139 * @param aAST the node to check if directly contained within an annotation 140 * block 141 * @return a <code>boolean</code> value 142 */ 143 public static boolean inAnnotationBlock(DetailAST aAST) 144 { 145 boolean retVal = false; 146 147 // Loop up looking for a containing interface block 148 for (DetailAST token = aAST.getParent(); 149 token != null; 150 token = token.getParent()) 151 { 152 final int type = token.getType(); 153 if ((type == TokenTypes.CLASS_DEF) 154 || (type == TokenTypes.ENUM_DEF) 155 || (type == TokenTypes.INTERFACE_DEF)) 156 { 157 break; // in a class, enum or interface 158 } 159 else if (type == TokenTypes.LITERAL_NEW) { 160 break; // inner implementation 161 } 162 else if (type == TokenTypes.ANNOTATION_DEF) { 163 retVal = true; 164 break; 165 } 166 } 167 168 return retVal; 169 } 170 171 /** 172 * Returns whether a node is directly contained within an interface or 173 * annotation block. 174 * 175 * @param aAST the node to check if directly contained within an interface 176 * or annotation block 177 * @return a <code>boolean</code> value 178 */ 179 public static boolean inInterfaceOrAnnotationBlock(DetailAST aAST) 180 { 181 return inInterfaceBlock(aAST) || inAnnotationBlock(aAST); 182 } 183 184 /** 185 * Returns whether a node is directly contained within an enum block. 186 * 187 * @param aAST the node to check if directly contained within an enum 188 * block 189 * @return a <code>boolean</code> value 190 */ 191 public static boolean inEnumBlock(DetailAST aAST) 192 { 193 boolean retVal = false; 194 195 // Loop up looking for a containing interface block 196 for (DetailAST token = aAST.getParent(); 197 token != null; 198 token = token.getParent()) 199 { 200 final int type = token.getType(); 201 if ((type == TokenTypes.INTERFACE_DEF) 202 || (type == TokenTypes.ANNOTATION_DEF) 203 || (type == TokenTypes.CLASS_DEF)) 204 { 205 break; // in an interface, annotation or class 206 } 207 else if (type == TokenTypes.LITERAL_NEW) { 208 break; // inner implementation, enums can't be inner classes 209 } 210 else if (type == TokenTypes.ENUM_DEF) { 211 retVal = true; 212 break; 213 } 214 } 215 216 return retVal; 217 } 218 219 /** 220 * Returns whether the scope of a node is restricted to a code block. 221 * A code block is a method or constructor body, or a initialiser block. 222 * 223 * @param aAST the node to check 224 * @return a <code>boolean</code> value 225 */ 226 public static boolean inCodeBlock(DetailAST aAST) 227 { 228 boolean retVal = false; 229 230 // Loop up looking for a containing code block 231 for (DetailAST token = aAST.getParent(); 232 token != null; 233 token = token.getParent()) 234 { 235 final int type = token.getType(); 236 if ((type == TokenTypes.METHOD_DEF) 237 || (type == TokenTypes.CTOR_DEF) 238 || (type == TokenTypes.INSTANCE_INIT) 239 || (type == TokenTypes.STATIC_INIT)) 240 { 241 retVal = true; 242 break; 243 } 244 } 245 246 return retVal; 247 } 248 249 /** 250 * Returns whether a node is contained in the outer most type block. 251 * 252 * @param aAST the node to check 253 * @return a <code>boolean</code> value 254 */ 255 public static boolean isOuterMostType(DetailAST aAST) 256 { 257 boolean retVal = true; 258 for (DetailAST parent = aAST.getParent(); 259 parent != null; 260 parent = parent.getParent()) 261 { 262 if ((parent.getType() == TokenTypes.CLASS_DEF) 263 || (parent.getType() == TokenTypes.INTERFACE_DEF) 264 || (parent.getType() == TokenTypes.ANNOTATION_DEF) 265 || (parent.getType() == TokenTypes.ENUM_DEF)) 266 { 267 retVal = false; 268 break; 269 } 270 } 271 272 return retVal; 273 } 274 275 /** 276 * Determines whether a node is a local variable definition. 277 * I.e. if it is declared in a code block, a for initializer, 278 * or a catch parameter. 279 * @param aAST the node to check. 280 * @return whether aAST is a local variable definition. 281 */ 282 public static boolean isLocalVariableDef(DetailAST aAST) 283 { 284 // variable declaration? 285 if (aAST.getType() == TokenTypes.VARIABLE_DEF) { 286 final DetailAST parent = aAST.getParent(); 287 if (parent != null) { 288 final int type = parent.getType(); 289 return (type == TokenTypes.SLIST) 290 || (type == TokenTypes.FOR_INIT) 291 || (type == TokenTypes.FOR_EACH_CLAUSE); 292 } 293 } 294 // catch parameter? 295 else if (aAST.getType() == TokenTypes.PARAMETER_DEF) { 296 final DetailAST parent = aAST.getParent(); 297 if (parent != null) { 298 return (parent.getType() == TokenTypes.LITERAL_CATCH); 299 } 300 } 301 return false; 302 } 303}