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