📄 tablemaker.java
字号:
// Transmogrify License
//
// Copyright (c) 2001, ThoughtWorks, Inc.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the ThoughtWorks, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.puppycrawl.tools.checkstyle.checks.usage.transmogrify;
import java.io.File;
import java.util.Enumeration;
import java.util.Vector;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
* this is the class that does the work of the "walking" step --
* going through the SymTabAST and constructing the definitions and
* references. The SymTabAST is constructed in a DOMish fashion, i.e.
* each node knows about its first child and its next sibling. The
* DFS search is carried out by two functions -- walkTree, which
* deals with a single SymTabAST node, and walkSibilngs, which deals with
* all the siblings of an SymTabAST node.
*/
public class TableMaker {
private SymbolTable symbolTable;
private SymTabAST _tree;
private File currentFile;
private Vector imports = new Vector();
/**
* Constructor for the TableMaker class
*
* @param tree is the<code>SymTabAST</code> from which to
* build the <code>TableMaker</code>. It is the tree which wil be walked
* in order to build definitions and references.
*/
public TableMaker(SymTabAST tree)
{
_tree = tree;
}
/**
* returns the <code> SymTabAST </code> which is the
* SymTabAST generated from the parsed Java Source files.
*
* @return <code>SymTabAST</code>
*/
public SymTabAST getTree() {
return _tree;
}
/**
* returns the <code>SymbolTable</code> that has been constructed by
* this <code>TableMaker</code>
*
* @return <code>SymbolTable</code>
* @throws <code>SymbolTableException</code>
*/
public SymbolTable getTable() throws SymbolTableException {
if (symbolTable == null) {
symbolTable = new SymbolTable( _tree );
createDefinitions();
resolveReferences();
}
return symbolTable;
}
/**
* walks the tree and finishes creating definitions.
*
* @return <code>void</code>
* @throws <code>SymbolTableException</code>
* @see #walkTree()
* @see #finishCreatingDefinitions()
*/
private void createDefinitions() throws SymbolTableException {
walkTree();
finishCreatingDefinitions();
}
/**
* finishes up creating definitions process
* starts at the base of the Table
*
* @return <code>void</code>
* @throws <code>SymbolTableException</code>
* @see net.sourceforge.transmogrify.symtab.SymbolTable
* @see #finishCreatingDefinition(Definition)
*/
private void finishCreatingDefinitions() throws SymbolTableException {
finishCreatingDefinition(symbolTable.getBaseScope());
}
/**
* begins at the base of the Table and starts finishing definition creation.
*
* @param def <code>Definition</code> needs to be completed
* @return <code>void</code>
* @throws <code>SymbolTableException</code>
* @see ClassFinisher
* @see VariableFinisher
* @see MethodFinisher
* @see CatchFinisher
*/
private void finishCreatingDefinition(Definition def) throws SymbolTableException {
if (def instanceof AnonymousInnerClass) {
AnonymousInnerClass innerClass = (AnonymousInnerClass)def;
innerClass.finishMakingDefinition();
}
else if (def instanceof ClassDef) {
new ClassFinisher(def).finish();
}
else if ( def instanceof VariableDef ) {
new VariableFinisher( def ).finish();
}
else if (def instanceof DefaultConstructor) {}
else if ( def instanceof MethodDef ) {
new MethodFinisher( def ).finish();
}
else if (def instanceof BlockDef) {
SymTabAST firstChild = (SymTabAST)def.getTreeNode().getFirstChild();
//handle Checkstyle grammar
if (firstChild.getType() == TokenTypes.LPAREN) {
firstChild = (SymTabAST) firstChild.getNextSibling();
}
if (firstChild.getType() == TokenTypes.PARAMETER_DEF) {
// this is a catch block
new CatchFinisher((BlockDef)def).finish();
}
}
if ( def instanceof Scope ) {
finishCreatingChildren((Scope)def);
}
}
/**
* iterates through all the definitions in the <code> Scope </code>
* finishes creating each <code>Scope</code>.
*
* @param scope <code> Scope </code> where defininitions will be finished.
* @return <code>void</code>
* @throws <code>SymbolTableException</code>
* @see net.sourceforge.transmogrify.symtab.Scope
* @see #finishCreatingDefinition(Definition)
*/
private void finishCreatingChildren( Scope scope ) throws SymbolTableException {
Enumeration definitions = scope.getDefinitions();
while ( definitions.hasMoreElements() ) {
Definition child = (Definition)(definitions.nextElement());
finishCreatingDefinition(child);
}
}
/**
* resolves <code>SymbolTable</code> using <code>Resolver</code>
*
* @return <code>void</code>
* @see net.sourceforge.transmogrify.symtab.Resolver
* @see net.sourceforge.transmogrify.symtab.SymbolTable
*/
private void resolveReferences() {
new Resolver( symbolTable ).resolve();
}
/**
* starts walking the <code> SymTabAST </code>
*
* @return <code>void</code>
* @see #walkSiblings(SymTabAST,boolean)
* @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
*/
public void walkTree() {
walkSiblings((SymTabAST)_tree.getFirstChild(), false);
}
/**
* processes a single SymTabAST node based on its type and passes of its
* children for further processing where appropriate.
*
* @param tree the <code>SymTabAST</code> node to process
* @param makeAnonymousScopes sets to <code>false</code> after walking Class,
* Methods and Try otherwise sets to <code>true</code>
* @return <code>void</code>
* @see #walkSiblings(SymTabAST, boolean)
* @see #processAnonymousInnerClass(SymTabAST, SymTabAST)
* @see #processBlock(SymTabAST, boolean)
* @see #processClass(SymTabAST)
* @see #processConstructorDef(SymTabAST)
* @see #processElse(SymTabAST)
* @see #processFile(SymTabAST)
* @see #processFinally(SymTabAST)
* @see #processFor(SymTabAST)
* @see #processImplicitPackage(SymTabAST)
* @see #processImport(SymTabAST)
* @see #processLabel(SymTabAST)
* @see #processMethodDef(SymTabAST)
* @see #processPackage(SymTabAST)
* @see #processTry(SymTabAST)
* @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
* @see net.sourceforge.transmogrify.symtab.antlr.JavaTokenTypes
*/
public void walkTree(SymTabAST tree, boolean makeAnonymousScopes) {
if (tree != null) {
tree.setScope( symbolTable.getCurrentScope() );
switch(tree.getType()) {
case 0:
processFile(tree);
if ( tree.getFirstChild().getType() != TokenTypes.PACKAGE_DEF ) {
processImplicitPackage( tree.getFile() );
}
walkSiblings((SymTabAST)tree.getFirstChild(), false);
// pop package scope
symbolTable.popScope();
clearImports();
break;
case TokenTypes.LITERAL_NEW:
SymTabAST symtabTree = tree;
//walk parameters, in case of anonymous inner class
walkTree(symtabTree.findFirstToken(TokenTypes.ELIST),
makeAnonymousScopes);
SymTabAST objblock
= symtabTree.findFirstToken(TokenTypes.OBJBLOCK);
if (objblock != null) {
SymTabAST classExtended
= symtabTree.findFirstToken(TokenTypes.IDENT);
processAnonymousInnerClass(objblock, classExtended);
}
break;
case TokenTypes.SLIST:
if (makeAnonymousScopes) {
processBlock(tree, true);
}
else {
walkSiblings((SymTabAST)tree.getFirstChild(), true);
}
break;
case TokenTypes.CTOR_DEF:
processConstructorDef(tree);
break;
case TokenTypes.METHOD_DEF:
processMethodDef(tree);
break;
case TokenTypes.LITERAL_FINALLY:
processFinally(tree);
break;
case TokenTypes.LITERAL_TRY:
processTry(tree);
break;
case TokenTypes.VARIABLE_DEF:
processVariableDef(tree);
break;
case TokenTypes.PACKAGE_DEF:
processPackage(tree);
break;
case TokenTypes.LABELED_STAT:
processLabel(tree);
break;
case TokenTypes.IMPORT:
processImport(tree);
break;
case TokenTypes.CLASS_DEF:
case TokenTypes.INTERFACE_DEF:
processClass(tree);
break;
case TokenTypes.LITERAL_FOR:
processFor(tree);
break;
case TokenTypes.LITERAL_IF:
processIf(tree);
break;
case TokenTypes.LITERAL_ASSERT:
processAssert(tree);
break;
case TokenTypes.LITERAL_CATCH:
case TokenTypes.LITERAL_WHILE:
case TokenTypes.LITERAL_SWITCH:
case TokenTypes.LITERAL_DO:
case TokenTypes.LITERAL_SYNCHRONIZED:
case TokenTypes.STATIC_INIT:
case TokenTypes.INSTANCE_INIT:
processBlock(tree, false);
break;
default:
walkSiblings((SymTabAST)tree.getFirstChild(), false);
}
}
}
/**
* @param tree
*/
public void processAssert(SymTabAST tree) {
BlockDef block = makeBlock(tree);
SymTabAST expr = tree.findFirstToken(TokenTypes.EXPR);
SymTabAST message = (SymTabAST)expr.getNextSibling();
while ((message != null) && (message.getType() != TokenTypes.EXPR)) {
message = (SymTabAST) message.getNextSibling();
}
symbolTable.pushScope( block );
walkTree(expr, false);
if (message != null) {
walkTree(message, false);
}
symbolTable.popScope();
}
/**
* processes the given <code>SymTabAST</code> and each of its siblings
*
* @param tree <code>SymTabAST</code> node to process
* @param makeAnonymousScopes
*
* @return <code>void</code>
* @see #walkTree(SymTabAST, boolean)
* @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
*/
public void walkSiblings(SymTabAST tree, boolean makeAnonymousScopes) {
while(tree != null) {
walkTree(tree, makeAnonymousScopes);
tree = (SymTabAST)tree.getNextSibling();
}
}
/**
* processes the given <code>SymTabAST</code> as a package defintion
*
* @param tree the <code>SymTabAST</code> to process
* @return <code>void</code>
* @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
* @see net.sourceforge.transmogrify.symtab.PackageDef
* @see net.sourceforge.transmogrify.symtab.SymbolTable
*/
public void processPackage(SymTabAST tree) {
SymTabAST firstChild = (SymTabAST)tree.getFirstChild();
String name = ASTUtil.constructDottedName(firstChild);
firstChild.ignoreChildren();
PackageDef pkg = symbolTable.getPackage(name);
if (pkg == null) {
pkg = createPackage( (SymTabAST)(tree.getFirstChild()) );
}
symbolTable.pushScope(pkg);
}
/**
* processes a java class that use default no package
*
* @param file <code>File</code> object of the java class
* @return <code>void</code>
* @see net.sourceforge.transmogrify.symtab.PackageDef
* @see net.sourceforge.transmogrify.symtab.SymbolTable
*/
public void processImplicitPackage( File file ) {
String name = file.getParent();
if (name == null) {
name = "";
}
PackageDef pkg = symbolTable.getPackage( name );
if ( pkg == null ) {
pkg = new PackageDef( name, symbolTable.getBaseScope(), null );
symbolTable.definePackage( pkg, symbolTable.getBaseScope() );
}
symbolTable.pushScope( pkg );
}
/**
* gets the package represented by the tree. The method
* analyzes the tree, constructs an appropriate package name
* and fetches it from the internal package list. If the package does not
* exist it is created.
*
* @param tree <code>SymTabAST</code> to consider
*
* @return <code>PackageDef</code> the resulting package definition
* @see #getPackage(Scope, SymTabAST)
*/
private PackageDef createPackage( SymTabAST tree ) {
PackageDef result = null;
if (tree.getType() == TokenTypes.DOT) {
// find the package result of left child
SymTabAST leftChild = (SymTabAST)tree.getFirstChild();
SymTabAST rightChild = (SymTabAST)leftChild.getNextSibling();
PackageDef context = createPackage(leftChild);
result = getPackage( context, rightChild );
}
else {
result = getPackage(symbolTable.getBaseScope(), tree);
}
return result;
}
/**
* gets the package determined by the tree and parent package def.
* The method analyzes the tree and parent scope and retrieves the
* appropriate package definition from the internal package list.
* If the package does not exist it is created.
*
* @param tree <code>SymTabAST</code> to consider
* @param parent the parent package definition
*
* @return PackageDef the resulting package definition
* @see net.sourceforge.transmogrify.symtab.PackageDef
* @see net.sourceforge.transmogrify.symtab.SymbolTable
* @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
*/
private PackageDef getPackage(Scope parent, SymTabAST tree ) {
String name = tree.getText();
PackageDef result = null;
if (!(parent instanceof BaseScope)) {
result = symbolTable.getPackage(parent.getQualifiedName() + "." + name);
}
else {
result = symbolTable.getPackage(name);
}
if (result == null) {
result = new PackageDef(tree.getText(), parent, tree);
symbolTable.definePackage(result, parent);
}
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -