com.puppycrawl.tools.checkstyle.checks.AbstractDeclarationCollector Maven / Gradle / Ivy
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2015 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.checks;
import java.util.Deque;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.utils.ScopeUtils;
/**
* Abstract class for checks which need to collect information about
* declared members/parameters/variables.
* @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead.
* @author o_sukhodolsky
* @noinspection AbstractClassNeverImplemented
*/
@Deprecated
public abstract class AbstractDeclarationCollector extends Check {
/**
* Tree of all the parsed frames.
*/
private Map frames;
/**
* Frame for the currently processed AST.
*/
private LexicalFrame current;
@Override
public void beginTree(DetailAST rootAST) {
final Deque frameStack = Lists.newLinkedList();
frameStack.add(new GlobalFrame());
frames = Maps.newHashMap();
DetailAST curNode = rootAST;
while (curNode != null) {
collectDeclarations(frameStack, curNode);
DetailAST toVisit = curNode.getFirstChild();
while (curNode != null && toVisit == null) {
endCollectingDeclarations(frameStack, curNode);
toVisit = curNode.getNextSibling();
if (toVisit == null) {
curNode = curNode.getParent();
}
}
curNode = toVisit;
}
}
@Override
public void visitToken(DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.CLASS_DEF :
case TokenTypes.INTERFACE_DEF :
case TokenTypes.ENUM_DEF :
case TokenTypes.ANNOTATION_DEF :
case TokenTypes.SLIST :
case TokenTypes.METHOD_DEF :
case TokenTypes.CTOR_DEF :
current = frames.get(ast);
break;
default :
// do nothing
}
}
/**
* Parse the next AST for declarations.
*
* @param frameStack Stack containing the FrameTree being built
* @param ast AST to parse
*/
private static void collectDeclarations(Deque frameStack,
DetailAST ast) {
final LexicalFrame frame = frameStack.peek();
switch (ast.getType()) {
case TokenTypes.VARIABLE_DEF :
collectVariableDeclarations(ast, frame);
break;
case TokenTypes.PARAMETER_DEF :
final DetailAST parameterAST = ast.findFirstToken(TokenTypes.IDENT);
frame.addName(parameterAST.getText());
break;
case TokenTypes.CLASS_DEF :
case TokenTypes.INTERFACE_DEF :
case TokenTypes.ENUM_DEF :
case TokenTypes.ANNOTATION_DEF :
final DetailAST classAST = ast.findFirstToken(TokenTypes.IDENT);
frame.addName(classAST.getText());
frameStack.addFirst(new ClassFrame(frame));
break;
case TokenTypes.SLIST :
frameStack.addFirst(new BlockFrame(frame));
break;
case TokenTypes.METHOD_DEF :
final String name = ast.findFirstToken(TokenTypes.IDENT).getText();
if (frame instanceof ClassFrame) {
final DetailAST mods =
ast.findFirstToken(TokenTypes.MODIFIERS);
if (mods.branchContains(TokenTypes.LITERAL_STATIC)) {
((ClassFrame) frame).addStaticMethod(name);
}
else {
((ClassFrame) frame).addInstanceMethod(name);
}
}
frameStack.addFirst(new MethodFrame(frame));
break;
case TokenTypes.CTOR_DEF :
frameStack.addFirst(new MethodFrame(frame));
break;
default:
// do nothing
}
}
/**
* Collect Variable Declarations.
* @param ast variable token
* @param frame current frame
*/
private static void collectVariableDeclarations(DetailAST ast, LexicalFrame frame) {
final String name =
ast.findFirstToken(TokenTypes.IDENT).getText();
if (frame instanceof ClassFrame) {
final DetailAST mods =
ast.findFirstToken(TokenTypes.MODIFIERS);
if (ScopeUtils.isInInterfaceBlock(ast)
|| mods.branchContains(TokenTypes.LITERAL_STATIC)) {
((ClassFrame) frame).addStaticMember(name);
}
else {
((ClassFrame) frame).addInstanceMember(name);
}
}
else {
frame.addName(name);
}
}
/**
* End parsing of the AST for declarations.
*
* @param frameStack Stack containing the FrameTree being built
* @param ast AST that was parsed
*/
private void endCollectingDeclarations(Queue frameStack,
DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.CLASS_DEF :
case TokenTypes.INTERFACE_DEF :
case TokenTypes.ENUM_DEF :
case TokenTypes.ANNOTATION_DEF :
case TokenTypes.SLIST :
case TokenTypes.METHOD_DEF :
case TokenTypes.CTOR_DEF :
frames.put(ast, frameStack.poll());
break;
default :
// do nothing
}
}
/**
* Check if given name is a name for class field in current environment.
* @param name a name to check
* @return true is the given name is name of member.
*/
protected final boolean isClassField(String name) {
final LexicalFrame frame = findFrame(name);
return frame instanceof ClassFrame
&& ((ClassFrame) frame).hasInstanceMember(name);
}
/**
* Check if given name is a name for class method in current environment.
* @param name a name to check
* @return true is the given name is name of method.
*/
protected final boolean isClassMethod(String name) {
final LexicalFrame frame = findFrame(name);
return frame instanceof ClassFrame
&& ((ClassFrame) frame).hasInstanceMethod(name);
}
/**
* Find frame containing declaration.
* @param name name of the declaration to find
* @return LexicalFrame containing declaration or null
*/
private LexicalFrame findFrame(String name) {
if (current == null) {
return null;
}
else {
return current.getIfContains(name);
}
}
/**
* A declaration frame.
* @author Stephen Bloch
*/
private static class LexicalFrame {
/** Set of name of variables declared in this frame. */
private final Set varNames;
/**
* Parent frame.
*/
private final LexicalFrame parent;
/**
* Constructor -- invokable only via super() from subclasses.
*
* @param parent parent frame
*/
protected LexicalFrame(LexicalFrame parent) {
this.parent = parent;
varNames = Sets.newHashSet();
}
/** Add a name to the frame.
* @param nameToAdd the name we're adding
*/
private void addName(String nameToAdd) {
varNames.add(nameToAdd);
}
/** Check whether the frame contains a given name.
* @param nameToFind the name we're looking for
* @return whether it was found
*/
boolean contains(String nameToFind) {
return varNames.contains(nameToFind);
}
/** Check whether the frame contains a given name.
* @param nameToFind the name we're looking for
* @return whether it was found
*/
private LexicalFrame getIfContains(String nameToFind) {
LexicalFrame frame = null;
if (contains(nameToFind)) {
frame = this;
}
else if (parent != null) {
frame = parent.getIfContains(nameToFind);
}
return frame;
}
}
/**
* The global frame; should hold only class names.
* @author Stephen Bloch
*/
private static class GlobalFrame extends LexicalFrame {
/**
* Constructor for the root of the FrameTree.
*/
protected GlobalFrame() {
super(null);
}
}
/**
* A frame initiated at method definition; holds parameter names.
* @author Stephen Bloch
*/
private static class MethodFrame extends LexicalFrame {
/**
* Creates method frame.
* @param parent parent frame
*/
protected MethodFrame(LexicalFrame parent) {
super(parent);
}
}
/**
* A frame initiated at class definition; holds instance variable
* names. For the present, I'm not worried about other class names,
* method names, etc.
* @author Stephen Bloch
*/
private static class ClassFrame extends LexicalFrame {
/** Set of name of instance members declared in this frame. */
private final Set instanceMembers;
/** Set of name of instance methods declared in this frame. */
private final Set instanceMethods;
/** Set of name of variables declared in this frame. */
private final Set staticMembers;
/** Set of name of static methods declared in this frame. */
private final Set staticMethods;
/**
* Creates new instance of ClassFrame.
* @param parent parent frame
*/
ClassFrame(LexicalFrame parent) {
super(parent);
instanceMembers = Sets.newHashSet();
instanceMethods = Sets.newHashSet();
staticMembers = Sets.newHashSet();
staticMethods = Sets.newHashSet();
}
/**
* Adds static member's name.
* @param name a name of static member of the class
*/
public void addStaticMember(final String name) {
staticMembers.add(name);
}
/**
* Adds static method's name.
* @param name a name of static method of the class
*/
public void addStaticMethod(final String name) {
staticMethods.add(name);
}
/**
* Adds instance member's name.
* @param name a name of instance member of the class
*/
public void addInstanceMember(final String name) {
instanceMembers.add(name);
}
/**
* Adds instance method's name.
* @param name a name of instance method of the class
*/
public void addInstanceMethod(final String name) {
instanceMethods.add(name);
}
/**
* Checks if a given name is a known instance member of the class.
* @param name a name to check
* @return true is the given name is a name of a known
* instance member of the class
*/
public boolean hasInstanceMember(final String name) {
return instanceMembers.contains(name);
}
/**
* Checks if a given name is a known instance method of the class.
* @param name a name to check
* @return true is the given name is a name of a known
* instance method of the class
*/
public boolean hasInstanceMethod(final String name) {
return instanceMethods.contains(name);
}
@Override
boolean contains(String nameToFind) {
return super.contains(nameToFind)
|| instanceMembers.contains(nameToFind)
|| instanceMethods.contains(nameToFind)
|| staticMembers.contains(nameToFind)
|| staticMethods.contains(nameToFind);
}
}
/**
* A frame initiated on entering a statement list; holds local variable
* names. For the present, I'm not worried about other class names,
* method names, etc.
* @author Stephen Bloch
*/
private static class BlockFrame extends LexicalFrame {
/**
* Creates block frame.
* @param parent parent frame
*/
protected BlockFrame(LexicalFrame parent) {
super(parent);
}
}
}