001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2015 the original author or authors. 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//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks; 021 022import java.util.Deque; 023import java.util.Map; 024import java.util.Queue; 025import java.util.Set; 026 027import com.google.common.collect.Lists; 028import com.google.common.collect.Maps; 029import com.google.common.collect.Sets; 030import com.puppycrawl.tools.checkstyle.api.Check; 031import com.puppycrawl.tools.checkstyle.api.DetailAST; 032import com.puppycrawl.tools.checkstyle.api.TokenTypes; 033import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; 034 035/** 036 * Abstract class for checks which need to collect information about 037 * declared members/parameters/variables. 038 * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead. 039 * @author o_sukhodolsky 040 * @noinspection AbstractClassNeverImplemented 041 */ 042@Deprecated 043public abstract class AbstractDeclarationCollector extends Check { 044 /** 045 * Tree of all the parsed frames. 046 */ 047 private Map<DetailAST, LexicalFrame> frames; 048 049 /** 050 * Frame for the currently processed AST. 051 */ 052 private LexicalFrame current; 053 054 @Override 055 public void beginTree(DetailAST rootAST) { 056 final Deque<LexicalFrame> frameStack = Lists.newLinkedList(); 057 frameStack.add(new GlobalFrame()); 058 059 frames = Maps.newHashMap(); 060 061 DetailAST curNode = rootAST; 062 while (curNode != null) { 063 collectDeclarations(frameStack, curNode); 064 DetailAST toVisit = curNode.getFirstChild(); 065 while (curNode != null && toVisit == null) { 066 endCollectingDeclarations(frameStack, curNode); 067 toVisit = curNode.getNextSibling(); 068 if (toVisit == null) { 069 curNode = curNode.getParent(); 070 } 071 } 072 curNode = toVisit; 073 } 074 } 075 076 @Override 077 public void visitToken(DetailAST ast) { 078 switch (ast.getType()) { 079 case TokenTypes.CLASS_DEF : 080 case TokenTypes.INTERFACE_DEF : 081 case TokenTypes.ENUM_DEF : 082 case TokenTypes.ANNOTATION_DEF : 083 case TokenTypes.SLIST : 084 case TokenTypes.METHOD_DEF : 085 case TokenTypes.CTOR_DEF : 086 current = frames.get(ast); 087 break; 088 default : 089 // do nothing 090 } 091 } 092 093 /** 094 * Parse the next AST for declarations. 095 * 096 * @param frameStack Stack containing the FrameTree being built 097 * @param ast AST to parse 098 */ 099 private static void collectDeclarations(Deque<LexicalFrame> frameStack, 100 DetailAST ast) { 101 final LexicalFrame frame = frameStack.peek(); 102 switch (ast.getType()) { 103 case TokenTypes.VARIABLE_DEF : 104 collectVariableDeclarations(ast, frame); 105 break; 106 case TokenTypes.PARAMETER_DEF : 107 final DetailAST parameterAST = ast.findFirstToken(TokenTypes.IDENT); 108 frame.addName(parameterAST.getText()); 109 break; 110 case TokenTypes.CLASS_DEF : 111 case TokenTypes.INTERFACE_DEF : 112 case TokenTypes.ENUM_DEF : 113 case TokenTypes.ANNOTATION_DEF : 114 final DetailAST classAST = ast.findFirstToken(TokenTypes.IDENT); 115 frame.addName(classAST.getText()); 116 frameStack.addFirst(new ClassFrame(frame)); 117 break; 118 case TokenTypes.SLIST : 119 frameStack.addFirst(new BlockFrame(frame)); 120 break; 121 case TokenTypes.METHOD_DEF : 122 final String name = ast.findFirstToken(TokenTypes.IDENT).getText(); 123 if (frame instanceof ClassFrame) { 124 final DetailAST mods = 125 ast.findFirstToken(TokenTypes.MODIFIERS); 126 if (mods.branchContains(TokenTypes.LITERAL_STATIC)) { 127 ((ClassFrame) frame).addStaticMethod(name); 128 } 129 else { 130 ((ClassFrame) frame).addInstanceMethod(name); 131 } 132 } 133 frameStack.addFirst(new MethodFrame(frame)); 134 break; 135 case TokenTypes.CTOR_DEF : 136 frameStack.addFirst(new MethodFrame(frame)); 137 break; 138 default: 139 // do nothing 140 } 141 } 142 143 /** 144 * Collect Variable Declarations. 145 * @param ast variable token 146 * @param frame current frame 147 */ 148 private static void collectVariableDeclarations(DetailAST ast, LexicalFrame frame) { 149 final String name = 150 ast.findFirstToken(TokenTypes.IDENT).getText(); 151 if (frame instanceof ClassFrame) { 152 final DetailAST mods = 153 ast.findFirstToken(TokenTypes.MODIFIERS); 154 if (ScopeUtils.isInInterfaceBlock(ast) 155 || mods.branchContains(TokenTypes.LITERAL_STATIC)) { 156 ((ClassFrame) frame).addStaticMember(name); 157 } 158 else { 159 ((ClassFrame) frame).addInstanceMember(name); 160 } 161 } 162 else { 163 frame.addName(name); 164 } 165 } 166 167 /** 168 * End parsing of the AST for declarations. 169 * 170 * @param frameStack Stack containing the FrameTree being built 171 * @param ast AST that was parsed 172 */ 173 private void endCollectingDeclarations(Queue<LexicalFrame> frameStack, 174 DetailAST ast) { 175 switch (ast.getType()) { 176 case TokenTypes.CLASS_DEF : 177 case TokenTypes.INTERFACE_DEF : 178 case TokenTypes.ENUM_DEF : 179 case TokenTypes.ANNOTATION_DEF : 180 case TokenTypes.SLIST : 181 case TokenTypes.METHOD_DEF : 182 case TokenTypes.CTOR_DEF : 183 frames.put(ast, frameStack.poll()); 184 break; 185 default : 186 // do nothing 187 } 188 } 189 190 /** 191 * Check if given name is a name for class field in current environment. 192 * @param name a name to check 193 * @return true is the given name is name of member. 194 */ 195 protected final boolean isClassField(String name) { 196 final LexicalFrame frame = findFrame(name); 197 return frame instanceof ClassFrame 198 && ((ClassFrame) frame).hasInstanceMember(name); 199 } 200 201 /** 202 * Check if given name is a name for class method in current environment. 203 * @param name a name to check 204 * @return true is the given name is name of method. 205 */ 206 protected final boolean isClassMethod(String name) { 207 final LexicalFrame frame = findFrame(name); 208 return frame instanceof ClassFrame 209 && ((ClassFrame) frame).hasInstanceMethod(name); 210 } 211 212 /** 213 * Find frame containing declaration. 214 * @param name name of the declaration to find 215 * @return LexicalFrame containing declaration or null 216 */ 217 private LexicalFrame findFrame(String name) { 218 if (current == null) { 219 return null; 220 } 221 else { 222 return current.getIfContains(name); 223 } 224 } 225 226 /** 227 * A declaration frame. 228 * @author Stephen Bloch 229 */ 230 private static class LexicalFrame { 231 /** Set of name of variables declared in this frame. */ 232 private final Set<String> varNames; 233 /** 234 * Parent frame. 235 */ 236 private final LexicalFrame parent; 237 238 /** 239 * Constructor -- invokable only via super() from subclasses. 240 * 241 * @param parent parent frame 242 */ 243 protected LexicalFrame(LexicalFrame parent) { 244 this.parent = parent; 245 varNames = Sets.newHashSet(); 246 } 247 248 /** Add a name to the frame. 249 * @param nameToAdd the name we're adding 250 */ 251 private void addName(String nameToAdd) { 252 varNames.add(nameToAdd); 253 } 254 255 /** Check whether the frame contains a given name. 256 * @param nameToFind the name we're looking for 257 * @return whether it was found 258 */ 259 boolean contains(String nameToFind) { 260 return varNames.contains(nameToFind); 261 } 262 263 /** Check whether the frame contains a given name. 264 * @param nameToFind the name we're looking for 265 * @return whether it was found 266 */ 267 private LexicalFrame getIfContains(String nameToFind) { 268 LexicalFrame frame = null; 269 270 if (contains(nameToFind)) { 271 frame = this; 272 } 273 else if (parent != null) { 274 frame = parent.getIfContains(nameToFind); 275 } 276 return frame; 277 } 278 } 279 280 /** 281 * The global frame; should hold only class names. 282 * @author Stephen Bloch 283 */ 284 private static class GlobalFrame extends LexicalFrame { 285 286 /** 287 * Constructor for the root of the FrameTree. 288 */ 289 protected GlobalFrame() { 290 super(null); 291 } 292 } 293 294 /** 295 * A frame initiated at method definition; holds parameter names. 296 * @author Stephen Bloch 297 */ 298 private static class MethodFrame extends LexicalFrame { 299 /** 300 * Creates method frame. 301 * @param parent parent frame 302 */ 303 protected MethodFrame(LexicalFrame parent) { 304 super(parent); 305 } 306 } 307 308 /** 309 * A frame initiated at class definition; holds instance variable 310 * names. For the present, I'm not worried about other class names, 311 * method names, etc. 312 * @author Stephen Bloch 313 */ 314 private static class ClassFrame extends LexicalFrame { 315 /** Set of name of instance members declared in this frame. */ 316 private final Set<String> instanceMembers; 317 /** Set of name of instance methods declared in this frame. */ 318 private final Set<String> instanceMethods; 319 /** Set of name of variables declared in this frame. */ 320 private final Set<String> staticMembers; 321 /** Set of name of static methods declared in this frame. */ 322 private final Set<String> staticMethods; 323 324 /** 325 * Creates new instance of ClassFrame. 326 * @param parent parent frame 327 */ 328 ClassFrame(LexicalFrame parent) { 329 super(parent); 330 instanceMembers = Sets.newHashSet(); 331 instanceMethods = Sets.newHashSet(); 332 staticMembers = Sets.newHashSet(); 333 staticMethods = Sets.newHashSet(); 334 } 335 336 /** 337 * Adds static member's name. 338 * @param name a name of static member of the class 339 */ 340 public void addStaticMember(final String name) { 341 staticMembers.add(name); 342 } 343 344 /** 345 * Adds static method's name. 346 * @param name a name of static method of the class 347 */ 348 public void addStaticMethod(final String name) { 349 staticMethods.add(name); 350 } 351 352 /** 353 * Adds instance member's name. 354 * @param name a name of instance member of the class 355 */ 356 public void addInstanceMember(final String name) { 357 instanceMembers.add(name); 358 } 359 360 /** 361 * Adds instance method's name. 362 * @param name a name of instance method of the class 363 */ 364 public void addInstanceMethod(final String name) { 365 instanceMethods.add(name); 366 } 367 368 /** 369 * Checks if a given name is a known instance member of the class. 370 * @param name a name to check 371 * @return true is the given name is a name of a known 372 * instance member of the class 373 */ 374 public boolean hasInstanceMember(final String name) { 375 return instanceMembers.contains(name); 376 } 377 378 /** 379 * Checks if a given name is a known instance method of the class. 380 * @param name a name to check 381 * @return true is the given name is a name of a known 382 * instance method of the class 383 */ 384 public boolean hasInstanceMethod(final String name) { 385 return instanceMethods.contains(name); 386 } 387 388 @Override 389 boolean contains(String nameToFind) { 390 return super.contains(nameToFind) 391 || instanceMembers.contains(nameToFind) 392 || instanceMethods.contains(nameToFind) 393 || staticMembers.contains(nameToFind) 394 || staticMethods.contains(nameToFind); 395 } 396 } 397 398 /** 399 * A frame initiated on entering a statement list; holds local variable 400 * names. For the present, I'm not worried about other class names, 401 * method names, etc. 402 * @author Stephen Bloch 403 */ 404 private static class BlockFrame extends LexicalFrame { 405 406 /** 407 * Creates block frame. 408 * @param parent parent frame 409 */ 410 protected BlockFrame(LexicalFrame parent) { 411 super(parent); 412 } 413 } 414}