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 if (frame instanceof ClassFrame) { 124 final String name = ast.findFirstToken(TokenTypes.IDENT).getText(); 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 LexicalFrame frame = null; 220 if (current != null) { 221 frame = current.getIfContains(name); 222 } 223 return frame; 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 = new HashSet<>(); 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 protected 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 = new HashSet<>(); 331 instanceMethods = new HashSet<>(); 332 staticMembers = new HashSet<>(); 333 staticMethods = new HashSet<>(); 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 protected 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}