com.puppycrawl.tools.checkstyle.checks.usage.transmogrify.Resolver.java Source code

Java tutorial

Introduction

Here is the source code for com.puppycrawl.tools.checkstyle.checks.usage.transmogrify.Resolver.java

Source

// 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.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogConfigurationException;
import org.apache.commons.logging.LogFactory;

import com.puppycrawl.tools.checkstyle.api.TokenTypes;

/**
 * The resolver is responsible for traversing all the various
 * definitions in a symbol table and resolving references in them.
 *
 * @see SymbolTable
 */

public class Resolver extends DefinitionTraverser {

    /** true if the log factory has been initialized */
    private boolean mInitialized = false;

    /** Factory for creating org.apache.commons.logging.Log instances */
    private LogFactory mLogFactory;

    /**
     * constructor with <code>SymbolTable</code> to be resolved
     */
    public Resolver(SymbolTable symbolTable) {
        super(symbolTable);

        try {
            mLogFactory = LogFactory.getFactory();
        } catch (LogConfigurationException e) {
            System.out.println("log configuration exception" + e);
        }
        mInitialized = true;

    }

    /**
     * resolves the symbol table
     * @return <code>void</code>
     * @see #traverse()
     */
    public void resolve() {
        traverse();
    }

    protected void handleSList(SymTabAST node, Scope scope) {
        SymTabASTIterator iterator = node.getChildren();
        while (iterator.hasNext()) {
            SymTabAST current = iterator.nextChild();
            resolveExpression(current, scope, null, true);
        }
    }

    protected void handleAnonymousInnerClass(AnonymousInnerClass innerClass) {
        SymTabAST objblock = innerClass.getTreeNode();
        SymTabAST expression = (SymTabAST) objblock.getFirstChild();
        while (expression != null) {
            resolveExpression(expression, innerClass, null, true);
            expression = (SymTabAST) expression.getNextSibling();
        }
    }

    /**
     * processes a <code>ClassDef</code> and resolves references in it
     *
     * @param classDef the <code>ClassDef</code> to process
     */
    protected void handleClass(ClassDef classDef) {
        SymTabAST node = classDef.getTreeNode();

        if (node != null) {
            SymTabAST nameNode = node.findFirstToken(TokenTypes.IDENT);
            nameNode.setDefinition(classDef, classDef, true);

            SymTabAST extendsClause = node.findFirstToken(TokenTypes.EXTENDS_CLAUSE);
            SymTabAST extendedClassNode = (SymTabAST) extendsClause.getFirstChild();

            while (extendedClassNode != null) {
                IClass superClass = resolveClass(extendedClassNode, classDef, null, true);
                extendedClassNode.setDefinition(superClass, classDef, true);
                extendedClassNode = (SymTabAST) extendedClassNode.getNextSibling();
            }

            SymTabAST implementsNode = node.findFirstToken(TokenTypes.IMPLEMENTS_CLAUSE);

            if (implementsNode != null) {
                SymTabAST interfaceNode = (SymTabAST) (implementsNode.getFirstChild());
                while (interfaceNode != null) {
                    resolveClass(interfaceNode, classDef, null, true);
                    interfaceNode = (SymTabAST) (interfaceNode.getNextSibling());
                }
            }
        }
    }

    /**
     * processes a <code>MethodDef</code> and resolves references in it
     *
     * @param method the <code>MethodDef</code> to process
     */
    protected void handleMethod(MethodDef method) {
        SymTabAST node = method.getTreeNode();

        SymTabAST nameNode = node.findFirstToken(TokenTypes.IDENT);
        nameNode.setDefinition(method, method, true);

        // references to classes in return type
        SymTabAST returnTypeNode = node.findFirstToken(TokenTypes.TYPE);

        if (returnTypeNode != null) {
            // this is not a constructor
            resolveExpression(returnTypeNode, method, null, true);
        }

        SymTabAST throwsNode = node.findFirstToken(TokenTypes.LITERAL_THROWS);
        if (throwsNode != null) {
            SymTabAST exception = (SymTabAST) throwsNode.getFirstChild();
            while (exception != null) {
                // handle Checkstyle grammar
                if (exception.getType() != TokenTypes.COMMA) {
                    resolveClass(exception, method, null, true);
                }
                exception = (SymTabAST) exception.getNextSibling();
            }
        }

        // references to classes in parameters

        // the body -- this would be better its own function
        SymTabAST slist = node.findFirstToken(TokenTypes.SLIST);

        if (slist != null) {
            handleSList(slist, method);
        }
    }

    /**
     * processes a <code>BlockDef</code> and resolves references in it
     *
     * @param block the <code>BlockDef</code> to process
     */
    protected void handleBlock(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        switch (node.getType()) {

        case TokenTypes.LITERAL_FOR:
            handleFor(block);
            break;

        case TokenTypes.LITERAL_IF:
            handleIf(block);
            break;

        case TokenTypes.LITERAL_WHILE:
            handleWhileAndSynchronized(block);
            break;

        case TokenTypes.LITERAL_DO:
            handleDoWhile(block);
            break;

        case TokenTypes.LITERAL_TRY:
        case TokenTypes.LITERAL_FINALLY:
            SymTabAST slist = node.findFirstToken(TokenTypes.SLIST);

            handleSList(slist, block);
            break;

        case TokenTypes.LITERAL_CATCH:
            handleCatch(block);
            break;

        case TokenTypes.LITERAL_SWITCH:
            handleSwitch(block);
            break;

        case TokenTypes.SLIST:
            handleSList(node, block);
            break;

        case TokenTypes.EXPR:
            resolveExpression(node, block, null, true);
            break;

        case TokenTypes.INSTANCE_INIT:
        case TokenTypes.STATIC_INIT:
            handleSList((SymTabAST) node.getFirstChild(), block);
            break;

        case TokenTypes.LITERAL_SYNCHRONIZED:
            handleWhileAndSynchronized(block);
            break;

        case TokenTypes.LITERAL_ASSERT:
            handleAssert(block);
            break;

        default:
            if (mInitialized) {
                final Log log = mLogFactory.getInstance(this.getClass());
                log.error("Unhandled block " + block + " of type " + node.getType());
            }
        }
    }

    /**
     * @param block
     */
    private void handleAssert(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        SymTabAST conditional = (node.findFirstToken(TokenTypes.EXPR));
        resolveExpression(conditional, block, null, true);

        SymTabAST message = (SymTabAST) conditional.getNextSibling();
        while ((message != null) && (message.getType() != TokenTypes.EXPR)) {
            message = (SymTabAST) message.getNextSibling();
        }
        if (message != null) {
            resolveExpression(message, block, null, true);
        }
    }

    /**
     * processes a switch statement and resolves references in it
     *
     * @param block the <code>BlockDef</code> to process
     */
    private void handleSwitch(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        SymTabAST expr = node.findFirstToken(TokenTypes.EXPR);
        resolveExpression(expr, block, null, true);

        SymTabAST caseGroup = (SymTabAST) (expr.getNextSibling());
        while (caseGroup != null && (caseGroup.getType() != TokenTypes.CASE_GROUP)) {
            caseGroup = (SymTabAST) caseGroup.getNextSibling();
        }
        if (caseGroup != null) {
            while (caseGroup.getType() == TokenTypes.CASE_GROUP) {
                SymTabAST caseNode = caseGroup.findFirstToken(TokenTypes.LITERAL_CASE);
                while (caseNode != null && caseNode.getType() == TokenTypes.LITERAL_CASE) {
                    resolveExpression((SymTabAST) caseNode.getFirstChild(), block, null, true);
                    caseNode = (SymTabAST) caseNode.getNextSibling();
                }

                SymTabAST caseSlist = caseGroup.findFirstToken(TokenTypes.SLIST);
                handleSList(caseSlist, block);

                caseGroup = (SymTabAST) (caseGroup.getNextSibling());
            }
        }
    }

    /**
     * processes a catch block and resolves references in it
     *
     * @param block the <code>BlockDef</code> to process
     */
    private void handleCatch(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        SymTabAST slist = node.findFirstToken(TokenTypes.SLIST);
        handleSList(slist, block);
    }

    /**
     * processes a for loop and resolves references in it
     *
     * @param block the <code>BlockDef</code> to process
     */
    private void handleFor(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        SymTabAST body;
        SymTabAST forEach = node.findFirstToken(TokenTypes.FOR_EACH_CLAUSE);
        if (forEach == null) {
            SymTabAST init = node.findFirstToken(TokenTypes.FOR_INIT);
            // only need to handle the elist case.  if the init node is a variable
            // definition, the variable def will be handled later on in the resolution
            if (init.getFirstChild() != null) {
                if (init.getFirstChild().getType() == TokenTypes.ELIST) {
                    resolveExpression((SymTabAST) (init.getFirstChild()), block, null, true);
                }
            }

            SymTabAST cond = node.findFirstToken(TokenTypes.FOR_CONDITION);
            if (cond.getFirstChild() != null) {
                resolveExpression((SymTabAST) (cond.getFirstChild()), block, null, true);
            }

            SymTabAST iterator = node.findFirstToken(TokenTypes.FOR_ITERATOR);
            if (iterator.getFirstChild() != null) {
                resolveExpression((SymTabAST) (iterator.getFirstChild()), block, null, true);
            }
            body = (SymTabAST) (iterator.getNextSibling());
        } else {
            resolveExpression((forEach.findFirstToken(TokenTypes.EXPR)), block, null, true);
            body = (SymTabAST) (forEach.getNextSibling());
        }
        //could be an SLIST, EXPR or an EMPTY_STAT
        if (body.getType() == TokenTypes.RPAREN) {
            body = (SymTabAST) body.getNextSibling();
        }
        if (body.getType() == TokenTypes.SLIST) {
            handleSList(body, block);
        } else {
            resolveExpression(body, block, null, true);
        }

    }

    /**
     * processes an if statement and resolves references in it
     *
     * @param block the <code>BlockDef</code> to process
     */
    private void handleIf(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        SymTabAST conditional = (node.findFirstToken(TokenTypes.EXPR));
        resolveExpression(conditional, block, null, true);

        SymTabAST body = (SymTabAST) conditional.getNextSibling();
        // Handle Checkstyle grammar
        if (body.getType() == TokenTypes.RPAREN) {
            body = (SymTabAST) body.getNextSibling();
        }
        if (body != null) {
            if (body.getType() == TokenTypes.SLIST) {
                handleSList(body, block);
            } else {
                resolveExpression(body, block, null, true);
            }

            SymTabAST elseBody = (SymTabAST) body.getNextSibling();
            //handle Checkstyle grammar
            while ((elseBody != null) && (elseBody.getType() != TokenTypes.LITERAL_ELSE)) {
                elseBody = (SymTabAST) elseBody.getNextSibling();
            }
            /*
             if (elseBody != null && elseBody.getType() == TokenTypes.SLIST) {
            handleSList(elseBody, block);
             }else{
            resolveExpression(elseBody, block, null, true);
             }
             */
            if (elseBody != null) {
                elseBody = (SymTabAST) elseBody.getFirstChild();
            }
            if (elseBody != null) {
                resolveExpression(elseBody, block.getParentScope(), null, true);
            }
        }
    }

    /**
     * processes a while loop and resolves references in it
     *
     * @param block the <code>BlockDef</code> to process
     */
    private void handleWhileAndSynchronized(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        SymTabAST condition = (node.findFirstToken(TokenTypes.EXPR));
        SymTabAST slist = (SymTabAST) (condition.getNextSibling());
        // handle Checkstyle grammar
        if (slist.getType() == TokenTypes.RPAREN) {
            slist = (SymTabAST) slist.getNextSibling();
        }

        resolveExpression(condition, block, null, true);
        handleSList(slist, block);
    }

    private void handleDoWhile(BlockDef block) {
        SymTabAST node = block.getTreeNode();

        SymTabAST slist = (SymTabAST) node.getFirstChild();
        SymTabAST condition = node.findFirstToken(TokenTypes.EXPR);

        handleSList(slist, block);
        resolveExpression(condition, block, null, true);
    }

    /**
     * processes a variable definition and resolves references in it
     *
     * @param variable the <code>VariableDef</code> to process
     */
    protected void handleVariable(VariableDef variable) {
        SymTabAST node = variable.getTreeNode();
        Scope location = variable.getParentScope();

        SymTabAST nameNode = node.findFirstToken(TokenTypes.IDENT);
        nameNode.setDefinition(variable, location, true);

        SymTabAST typeNode = node.findFirstToken(TokenTypes.TYPE);
        resolveType(typeNode, location, null, true);

        SymTabAST assignmentNode = node.findFirstToken(TokenTypes.ASSIGN);
        if (assignmentNode != null) {
            resolveExpression((SymTabAST) (assignmentNode.getFirstChild()), variable.getParentScope(), null, true);
        }
    }

    /**
     * processes a label and resolves references in it
     *
     * @param label the <code>LabelDef</code> to process
     */
    protected void handleLabel(LabelDef label) {
        SymTabAST node = label.getTreeNode();
        ((SymTabAST) node.getFirstChild()).setDefinition(label, label.getParentScope(), true);
    }

    /**
     * Resolves Java expressions, returning the type to which the expression
     * evalutes.  If this is the reference creation phase, any references found during resolution are created and
     * resolved.
     *
     * @param expression the <code>SymTabAST</code> representing the expression
     * @param location the <code>Scope</code> in which the expression occours.
     * @param context the <code>Scope</code> in which the search for the
     *                definition will start
     * @param referencePhase whether or not this is the reference phase of
     *                       table construction
     *
     * @return the <code>ClassDef</code> representing the type to which the
     *         expression evalutes.
     */
    public IClass resolveExpression(SymTabAST expression, Scope location, IClass context, boolean referencePhase) {
        IClass result = null;

        try {

            switch (expression.getType()) {

            case TokenTypes.TYPECAST:
                result = resolveTypecast(expression, location, context, referencePhase);
                break;
            case TokenTypes.EXPR:
            case TokenTypes.LITERAL_RETURN:
                if (expression.getFirstChild() != null) {
                    result = resolveExpression((SymTabAST) expression.getFirstChild(), location, context,
                            referencePhase);
                } else {
                    // YOU WRITE BAD CODE!
                }
                break;

            case TokenTypes.ELIST:

                SymTabAST child = (SymTabAST) (expression.getFirstChild());
                while (child != null) {
                    if (child.getType() != TokenTypes.COMMA) {
                        resolveExpression(child, location, context, referencePhase);
                    }
                    child = (SymTabAST) (child.getNextSibling());
                }
                break;

            case TokenTypes.IDENT:
                result = resolveIdent(expression, location, context, referencePhase);
                break;

            case TokenTypes.TYPE:
                result = resolveType(expression, location, context, referencePhase);
                break;

            case TokenTypes.METHOD_CALL:
                //case TokenTypes.SUPER_CTOR_CALL :
                result = resolveMethod(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_THIS:
                result = resolveLiteralThis(expression, location, context);
                break;

            case TokenTypes.LITERAL_SUPER:
                result = resolveLiteralSuper(expression, location, context);
                break;

            case TokenTypes.DOT:
                result = resolveDottedName(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_NEW:
            case TokenTypes.CTOR_CALL:
            case TokenTypes.SUPER_CTOR_CALL:
                result = resolveNew(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_BOOLEAN:
            case TokenTypes.LITERAL_DOUBLE:
            case TokenTypes.LITERAL_FLOAT:
            case TokenTypes.LITERAL_LONG:
            case TokenTypes.LITERAL_INT:
            case TokenTypes.LITERAL_SHORT:
            case TokenTypes.LITERAL_BYTE:
            case TokenTypes.LITERAL_CHAR:
                result = resolvePrimitiveType(expression, location, context, referencePhase);
                break;

            case TokenTypes.NUM_INT:
            case TokenTypes.NUM_LONG:
                result = resolveNumInt(expression, location, context);
                break;

            case TokenTypes.NUM_FLOAT:
            case TokenTypes.NUM_DOUBLE:
                result = resolveNumFloat(expression, location, context);
                break;

            case TokenTypes.STRING_LITERAL:
                result = resolveStringLiteral(expression, location, context);
                break;

            case TokenTypes.CHAR_LITERAL:
                result = resolveCharLiteral(expression, location, context);
                break;

            case TokenTypes.ASSIGN:
            case TokenTypes.PLUS_ASSIGN:
            case TokenTypes.MINUS_ASSIGN:
            case TokenTypes.STAR_ASSIGN:
            case TokenTypes.DIV_ASSIGN:
            case TokenTypes.MOD_ASSIGN:
            case TokenTypes.SR_ASSIGN:
            case TokenTypes.BSR_ASSIGN:
            case TokenTypes.SL_ASSIGN:
            case TokenTypes.BAND_ASSIGN:
            case TokenTypes.BXOR_ASSIGN:
            case TokenTypes.BOR_ASSIGN:
                resolveAssignment(expression, location, context, referencePhase);
                break;

            case TokenTypes.LOR:
            case TokenTypes.LAND:
            case TokenTypes.NOT_EQUAL:
            case TokenTypes.EQUAL:
            case TokenTypes.LT:
            case TokenTypes.GT:
            case TokenTypes.LE:
            case TokenTypes.GE:
                result = resolveBooleanExpression(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_INSTANCEOF:
                result = resolveInstanceOf(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_TRUE:
            case TokenTypes.LITERAL_FALSE:
                result = resolveBooleanLiteral(expression, location, context);
                break;

            case TokenTypes.LNOT:
                result = resolveBooleanUnary(expression, location, context, referencePhase);
                break;

            case TokenTypes.INC:
            case TokenTypes.POST_INC:
            case TokenTypes.DEC:
            case TokenTypes.POST_DEC:
            case TokenTypes.UNARY_PLUS:
            case TokenTypes.UNARY_MINUS:
                result = resolveUnaryExpression(expression, location, context, referencePhase);
                break;

            case TokenTypes.PLUS:
            case TokenTypes.MINUS:
            case TokenTypes.DIV:
            case TokenTypes.STAR:
            case TokenTypes.BAND:
            case TokenTypes.BOR:
            case TokenTypes.BXOR:
            case TokenTypes.MOD:
                result = resolveArithmeticExpression(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_BREAK:
            case TokenTypes.LITERAL_CONTINUE:
                resolveGoto(expression, location, context, referencePhase);
                break;

            case TokenTypes.LPAREN:
                result = resolveExpression(
                        //TODO: child || sibling?
                        (SymTabAST) (expression.getNextSibling()),
                        //(SymTabAST) (expression.getFirstChild()),
                        location, context, referencePhase);
                break;

            case TokenTypes.INDEX_OP:
                result = resolveArrayAccess(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_NULL:
                result = new NullClass();
                break;

            case TokenTypes.QUESTION:
                result = resolveQuestion(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_CLASS:
                result = resolveLiteralClass();
                break;

            case TokenTypes.ARRAY_INIT:
                resolveArrayInitializer(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_THROW:
                resolveThrowExpression(expression, location, context, referencePhase);
                break;

            case TokenTypes.SL:
            case TokenTypes.SR:
            case TokenTypes.BSR:
                result = resolveShiftOperator(expression, location, context, referencePhase);
                break;

            case TokenTypes.BNOT:
                resolveBitwiseNot(expression, location, context, referencePhase);
                break;

            case TokenTypes.LITERAL_ASSERT:
                //                                        resolveAssert(
                //                                            expression,
                //                                            location,
                //                                            context,
                //                                            referencePhase);
                break;

            case TokenTypes.RPAREN:
            case TokenTypes.EMPTY_STAT:
                //    case TokenTypes.ML_COMMENT:
                //    case TokenTypes.SL_COMMENT:
            case TokenTypes.VARIABLE_DEF:
            case TokenTypes.METHOD_DEF:
            case TokenTypes.CLASS_DEF:
            case TokenTypes.LITERAL_FOR:
            case TokenTypes.LITERAL_WHILE:
            case TokenTypes.LITERAL_IF:
            case TokenTypes.LITERAL_VOID:
                //    case TokenTypes.LITERAL_INTERFACE:
            case TokenTypes.LITERAL_DO:
            case TokenTypes.LITERAL_SWITCH:
            case TokenTypes.LITERAL_STATIC:
            case TokenTypes.LITERAL_TRANSIENT:
            case TokenTypes.LITERAL_NATIVE:
                //    case TokenTypes.LITERAL_threadsafe:
            case TokenTypes.LITERAL_SYNCHRONIZED:
            case TokenTypes.LITERAL_VOLATILE:
            case TokenTypes.LITERAL_TRY:
            case TokenTypes.LITERAL_CATCH:
            case TokenTypes.LITERAL_FINALLY:
            case TokenTypes.LABELED_STAT:
            case TokenTypes.LCURLY:
            case TokenTypes.RCURLY:
            case TokenTypes.SLIST:
            case TokenTypes.SEMI:
            case TokenTypes.COMMA:
            case TokenTypes.ARRAY_DECLARATOR:
                break;

            default:
                //TODO: throw exception
                if (mInitialized) {
                    final Log log = mLogFactory.getInstance(this.getClass());
                    log.error("Unhandled expression type: " + expression.getType());
                }
                break;
            }
        } catch (Exception e) {

            result = new UnknownClass(expression.getText(), expression);
            //          TODO: This really should be logged
            //            if (mInitialized) {
            //                final Log log = mLogFactory.getInstance(this.getClass());
            //                log.error("Error resolving near " + expression);
            //            }
        }

        return result;
    }

    private IClass resolveTypecast(SymTabAST node, Scope location, IClass context, boolean referencePhase) {
        SymTabAST typeNode = (SymTabAST) node.getFirstChild();
        SymTabAST exprNode = (SymTabAST) typeNode.getNextSibling();
        //handle Checkstyle grammar
        if (exprNode.getType() == TokenTypes.RPAREN) {
            exprNode = (SymTabAST) exprNode.getNextSibling();
        }

        IClass type = null;

        final SymTabAST child = (SymTabAST) typeNode.getFirstChild();
        // TODO: Checkstyle change.
        // Do not create references from typecast.
        // Original transmogrify code is equivalent to
        // final boolean createReference = referencePhase;
        // which creates non-existant references for variables.
        final boolean createReference = false;
        if (child.getType() == TokenTypes.ARRAY_DECLARATOR) {
            type = new ArrayDef(
                    resolveType((SymTabAST) typeNode.getFirstChild(), location, context, createReference));
        } else {
            type = resolveType(typeNode, location, context, createReference);
        }

        resolveExpression(exprNode, location, context, referencePhase);
        //TODO: Checkstyle change. Can this be ignored?
        if (type != null) {
            ((SymTabAST) typeNode.getFirstChild()).setDefinition(type, location, referencePhase);
        }

        return type;
    }

    private IClass resolveArrayAccess(SymTabAST node, Scope location, IClass context, boolean referencePhase) {

        SymTabAST arrayNode = (SymTabAST) (node.getFirstChild());
        SymTabAST exprNode = (SymTabAST) (arrayNode.getNextSibling());

        //resolve index expressions
        while (arrayNode.getType() == TokenTypes.INDEX_OP) {
            resolveExpression(exprNode, location, context, referencePhase);
            arrayNode = (SymTabAST) (arrayNode.getFirstChild());
            exprNode = (SymTabAST) (arrayNode.getNextSibling());
        }

        ArrayDef array = (ArrayDef) resolveExpression(arrayNode, location, context, referencePhase);

        resolveExpression(exprNode, location, context, referencePhase);

        return array.getType();
    }

    private IClass resolveLiteralClass() {
        return new ExternalClass(Class.class);
    }

    /**
     * Resolves any dotted reference, returning the <code>Scope</code>
     * identified by the reference.
     *
     * @param tree the root node of the dotted reference
     * @param location the <code>Scope</code> in which the expression occours.
     * @param context the <code>Scope</code> in which the search for the
     *                definition will start
     * @return the <code>Scope</code> indentified by the reference
     */
    private IClass resolveDottedName(SymTabAST tree, Scope location, IClass context, boolean referencePhase) {
        IClass result = null;

        IClass localContext = context;
        String name = null;

        DotIterator it = new DotIterator(tree);
        while (it.hasNext()) {
            SymTabAST node = it.nextNode();
            if (node.getType() != TokenTypes.COMMA) {
                localContext = resolveExpression(node, location, localContext, referencePhase);
                if (localContext == null) {
                    node.setMeaningfulness(false);
                    name = node.getText();
                    while (localContext == null && it.hasNext()) {
                        SymTabAST next = it.nextNode();
                        name = name + "." + next.getText();
                        localContext = location.getClassDefinition(name);
                        if (localContext != null && referencePhase) {
                            next.setDefinition(localContext, location, referencePhase);
                        } else {
                            next.setMeaningfulness(false);
                        }
                    }
                }
            }
        }

        if (localContext != null) {
            result = localContext;
        } else {
            result = new UnknownClass(name, tree);
        }

        return result;
    }

    /**
     * Resolves a method call.
     *
     * @param methodNode the <code>SymTabAST</code> for the METHOD_CALL node
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     * @param referencePhase whether or not this is the reference phase of
     *                       table construction
     *
     * @return the <code>ClassDef</code> for the type returned by the method
     */
    private IClass resolveMethod(SymTabAST methodNode, Scope location, IClass context, boolean referencePhase) {
        IClass result = new UnknownClass(methodNode.getText(), methodNode);
        IClass newContext = null;

        if (context == null) {
            newContext = location.getEnclosingClass();
        } else {
            newContext = context;
        }

        String name = null;
        boolean createReference = true;

        SymTabAST nameNode = (SymTabAST) (methodNode.getFirstChild());
        SymTabAST parametersNode = (SymTabAST) (nameNode.getNextSibling());

        ISignature signature = resolveParameters(parametersNode, location, context, referencePhase);

        if (nameNode.getType() == TokenTypes.IDENT) {
            name = nameNode.getText();
        } else if (nameNode.getType() == TokenTypes.LITERAL_SUPER
                || (nameNode.getType() == TokenTypes.SUPER_CTOR_CALL)) {
            IClass superclass = location.getEnclosingClass().getSuperclass();
            newContext = superclass;
            name = superclass.getName();
            createReference = false;
        } else if (nameNode.getType() == TokenTypes.LITERAL_THIS) {
            newContext = location.getEnclosingClass();
            name = newContext.getName();
            createReference = false;
        } else {
            // REDTAG -- doing dotted name resolution on its own
            SymTabAST contextNode = (SymTabAST) (nameNode.getFirstChild());
            //TODO: handle Checkstyle grammar
            nameNode = (SymTabAST) contextNode.getNextSibling();
            //skip to IDENT
            while (nameNode.getType() != TokenTypes.IDENT) {
                nameNode = (SymTabAST) nameNode.getNextSibling();
            }

            name = nameNode.getText();
            newContext = resolveExpression(contextNode, location, context, referencePhase);
        }

        if (newContext != null) {
            IMethod method = newContext.getMethodDefinition(name, signature);

            if (method != null) {
                if (createReference && referencePhase) {
                    nameNode.setDefinition(method, location, referencePhase);
                }
                result = method.getType();
            }
        }

        if (result == null) {
            result = new UnknownClass(methodNode.getText(), methodNode);
        }

        return result;
    }

    /**
     * resolves a literal "this"
     *
     * @param expression the <code>SymTabAST</code> of the expression
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the resulting scope of the expression (the type to which it evaluates)
     */
    private IClass resolveLiteralThis(SymTabAST thisNode, Scope location, IClass context) {
        return location.getEnclosingClass();
    }

    /**
     * resolves a literal "super"
     *
     * @param expression the <code>SymTabAST</code> of the expression
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the resulting scope of the expression (the type to which it evaluates)
     */
    private IClass resolveLiteralSuper(SymTabAST superNode, Scope location, IClass context) {
        return location.getEnclosingClass().getSuperclass();
    }

    private boolean newIsConstructor(SymTabAST newNode) {
        boolean result = false;

        SymTabAST typeNode = (SymTabAST) (newNode.getFirstChild().getNextSibling());
        //handle Checkstyle grammar
        if (typeNode.getType() == TokenTypes.LPAREN) {
            typeNode = (SymTabAST) typeNode.getNextSibling();
        }
        if (typeNode.getType() == TokenTypes.ELIST) {
            result = true;
        }
        return result;

    }

    /**
     * resolves and expression of type TokenTypes.TYPE
     *
     * @param expression the <code>SymTabAST</code> of the expression
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     * @param referencePhase whether or not this is the reference phase of
     *                       table construction
     * @return the resulting scope of the expression (the type to which it evaluates)
     * @see #resolveDottedName(SymTabAST, Scope, IClass, boolean)
     * @see #resolveClassIdent(SymTabAST, Scope, IClass, boolean)
     */
    public IClass resolveType(SymTabAST expr, Scope location, IClass context, boolean referencePhase) {
        IClass result = null;
        SymTabAST nameNode = (SymTabAST) expr.getFirstChild();

        // TODO: Checkstyle change.
        // Do not create references from typecast.
        // Original transmogrify code is equivalent to
        // final boolean createReference = referencePhase;
        // which creates non-existant references for variables.
        final boolean createReference = false;
        if (nameNode.getType() == TokenTypes.DOT) {
            result = resolveDottedName(nameNode, location, context, createReference);
        } else {
            result = resolveClassIdent(nameNode, location, context, createReference);
        }

        return result;
    }

    /**
     * resolves Class type expression
     * @param expr node to be resolved
     * @param location scope of the <code>expr</code>
     * @param context context of the <code>expr</code> if exists
     * @param referencePhase <code>true</code> if this method is used to during
     *                                         finding reference phase
     *                       <code>false</code> otherwise
     * @return <code>IClass</code> representing the type to which the
     *         expression evalutes.
     * @see #resolveDottedName(SymTabAST, Scope, IClass, boolean)
     */
    public IClass resolveClass(SymTabAST expr, Scope location, IClass context, boolean referencePhase) {

        IClass result = resolveDottedName(expr, location, context, referencePhase);
        if (result != null && referencePhase) {
            expr.setDefinition(result, location, referencePhase);
        }

        return result;
    }

    /**
     * resolves expression with <code>JavaTokenTypes<code> other than <code>DOT</code>
     * @param expr expression to be resolved
     * @param location scope of the expression
     * @param context context of the expression if any
     * @param referencePhase <code>true</code> if this method is used to during
     *                                         finding reference phase
     *                       <code>false</code> otherwise
     * @return <code>IClass</code> representing the type to which the
     *         expression evalutes.
     */
    public IClass resolveClassIdent(SymTabAST expr, Scope location, IClass context, boolean referencePhase) {

        IClass result = location.getClassDefinition(expr.getText());
        if (result != null) {
            expr.setDefinition(result, location, referencePhase);
        }

        return result;
    }

    private IClass resolveNew(SymTabAST newNode, Scope location, IClass context, boolean referencePhase) {

        IClass result;

        if (newIsConstructor(newNode)) {
            result = resolveConstructor(newNode, location, context, referencePhase);
        } else {
            result = resolveNewArray(newNode, location, context, referencePhase);
        }

        return result;
    }

    private IClass resolveNewArray(SymTabAST newNode, Scope location, IClass context, boolean referencePhase) {
        IClass arrayType;

        SymTabAST typeNode = (SymTabAST) (newNode.getFirstChild());
        SymTabAST declaratorNode = (SymTabAST) (typeNode.getNextSibling());
        SymTabAST initializerNode = (SymTabAST) (declaratorNode.getNextSibling());

        arrayType = resolveClass(typeNode, location, context, referencePhase);

        if (declaratorNode.getFirstChild() != null) {
            resolveExpression(((SymTabAST) declaratorNode.getFirstChild()), location, context, referencePhase);
        }

        if (initializerNode != null) {
            resolveArrayInitializer(initializerNode, location, context, referencePhase);
        }

        return new ArrayDef(arrayType);
    }

    private IClass resolveQuestion(SymTabAST question, Scope location, IClass context, boolean referencePhase) {
        SymTabAST test = (SymTabAST) question.getFirstChild();
        while (test.getType() == TokenTypes.LPAREN) {
            test = (SymTabAST) test.getNextSibling();
        }
        SymTabAST leftBranch = (SymTabAST) test.getNextSibling();
        while (leftBranch.getType() == TokenTypes.RPAREN) {
            leftBranch = (SymTabAST) leftBranch.getNextSibling();
        }
        SymTabAST rightBranch = (SymTabAST) leftBranch.getNextSibling();
        while (rightBranch.getType() != TokenTypes.COLON) {
            rightBranch = (SymTabAST) rightBranch.getNextSibling();
        }
        rightBranch = (SymTabAST) rightBranch.getNextSibling();

        resolveExpression(test, location, context, referencePhase);
        IClass leftClass = resolveExpression(leftBranch, location, context, referencePhase);
        IClass rightClass = resolveExpression(rightBranch, location, context, referencePhase);

        return moreGeneral(leftClass, rightClass);
    }

    private IClass moreGeneral(IClass a, IClass b) {
        return (a.isCompatibleWith(b)) ? b : a;
    }

    /**
     * Resolves a constructor call.
     *
     * @param tree the root node of the constructor call
     * @return the <code>ClassDef</code> for the class instantiated by the
     *         constructor
     */
    private IClass resolveConstructor(SymTabAST constructor, Scope location, IClass context,
            boolean referencePhase) {

        IClass classConstructed = null;

        SymTabAST nameNode = (SymTabAST) (constructor.getFirstChild());
        //SymTabAST parametersNode = (SymTabAST) (nameNode.getNextSibling());
        SymTabAST parametersNode = constructor.findFirstToken(TokenTypes.ELIST);
        SymTabAST nameIdent = null;
        if (nameNode.getType() == TokenTypes.IDENT) {
            nameIdent = nameNode;
        } else {
            nameIdent = (SymTabAST) nameNode.getFirstChild().getNextSibling();
        }

        classConstructed = resolveClass(nameNode, location, context, false);
        if (classConstructed != null) {
            MethodSignature signature = resolveParameters(parametersNode, location, context, referencePhase);

            IMethod constructorDef = classConstructed.getMethodDefinition(nameIdent.getText(), signature);

            if (constructorDef != null && referencePhase) {
                nameIdent.setDefinition(constructorDef, location, referencePhase);
            }
        }

        return classConstructed;
    }

    /**
     * Resolves the types found in a method call. Any references found
     * in the process are created.  Returns a <code>MethodSignature</code> for
     * the types of the parameters.
     *
     * @param elist The <code>SymTabAST</code> for the list of parameters
     * @return the signature of the parameters
     */
    private MethodSignature resolveParameters(SymTabAST elist, Scope location, IClass context,
            boolean referencePhase) {
        Vector parameters = new Vector();

        SymTabAST expr = (SymTabAST) (elist.getFirstChild());
        while (expr != null) {
            if (expr.getType() != TokenTypes.COMMA) {
                IClass parameter = resolveExpression((SymTabAST) (expr.getFirstChild()), location, context,
                        referencePhase);
                parameters.add(parameter);
            }

            expr = (SymTabAST) (expr.getNextSibling());
        }

        return new MethodSignature(parameters);
    }

    /**
     * Resolves an IDENT node of an AST, creating the appropriate reference and
     * returning the scope of the identifer.
     *
     * @param ident the IDENT node
     * @param location the <code>Scope</code> in which the IDENT is found
     * @return the <code>Scope</code> the identifier identifies
     */
    private IClass resolveIdent(SymTabAST ident, Scope location, IClass context, boolean referencePhase) {

        IClass result = null;
        IDefinition def = null;
        String name = ident.getText();

        // look for var
        if (context != null) {
            def = context.getVariableDefinition(name);
        } else {
            def = location.getVariableDefinition(name);
        }

        if (def != null) {
            result = ((IVariable) def).getType();
        } else {
            // look for class
            if (context != null) {
                result = context.getClassDefinition(name);
            } else {
                result = location.getClassDefinition(name);
            }
            def = result;
        }

        if (def != null) {
            ident.setDefinition(def, location, referencePhase);
        }

        return result;
    }

    /**
     * Resolves a (binary) boolean expression.  The left and right sides of the
     * expression
     * are resolved in the process.
     *
     * @param expression the <code>SymTabAST</code> representing the boolean
     *                   expression.
     * @return the <code>Scope</code> for the boolean primitive type.
     */
    private IClass resolveBooleanExpression(SymTabAST expression, Scope location, IClass context,
            boolean referencePhase) {
        IClass result = null;

        SymTabAST leftChild = findLeftChild(expression);
        resolveExpression(leftChild, location, context, referencePhase);
        SymTabAST rightChild = findRightSibling(leftChild);

        resolveExpression(rightChild, location, context, referencePhase);

        result = LiteralResolver.getDefinition(TokenTypes.LITERAL_BOOLEAN);

        return result;
    }

    /**
     * resolves references in an assignment expression
     *
     * @param expression the <code>SymTabAST</code> of the expression
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the resulting scope of the expression (the type to which it evaluates)
     */
    private IClass resolveAssignment(SymTabAST expression, Scope location, IClass context, boolean referencePhase) {
        IClass result = null;

        SymTabAST leftNode = (SymTabAST) (expression.getFirstChild());
        SymTabAST rightNode = (SymTabAST) (leftNode.getNextSibling());

        result = resolveExpression(leftNode, location, context, referencePhase);
        resolveExpression(rightNode, location, context, referencePhase);

        return result;
    }

    /**
     * Resolves a unary expression.  Returns the type of the expression,
     * creating any references found along the way.  Unary expressions are
     * increment (x++), decrement (x--), unary plus (+x), and unary minus (-x)
     *
     * @param expression the <code>SymTabAST</code> of the unary expression.
     * @return the <code>Scope</code> for the type to which the expression
     * evalutes.
     */
    private IClass resolveUnaryExpression(SymTabAST expression, Scope location, IClass context,
            boolean referencePhase) {
        SymTabAST operatee = (SymTabAST) (expression.getFirstChild());
        return resolveExpression(operatee, location, context, referencePhase);
    }

    /**
     * Resolves an arithmetic expression.  Returns the <code>Scope</code> for
     * the type to which the expression resolves.  Any references found during
     * resolution are created and resolved.
     *
     * @param expression the <code>SymTabAST</code> representing the arithmetic
     *                   expression.
     *
     * @return the <code>Scope</code> for the type to which the expression
     *         evaluates.
     */
    private IClass resolveArithmeticExpression(SymTabAST expression, Scope location, IClass context,
            boolean referencePhase) {
        IClass result = null;

        SymTabAST leftChild = findLeftChild(expression);

        IClass leftType = (resolveExpression(leftChild, location, context, referencePhase));

        SymTabAST rightChild = findRightSibling(leftChild);

        IClass rightType = (resolveExpression(rightChild, location, context, referencePhase));

        result = binaryResultType(leftType, rightType);

        return result;
    }

    /**
     * Finds the left child of a binary operator, skipping parentheses.
     * @param aExpression the node for the binary operator.
     * @return the node for the left child.
     */
    private SymTabAST findLeftChild(SymTabAST aExpression) {
        SymTabAST leftChild = (SymTabAST) (aExpression.getFirstChild());
        // handle Checkstyle grammar
        while (leftChild.getType() == TokenTypes.LPAREN) {
            leftChild = (SymTabAST) leftChild.getNextSibling();
        }
        return leftChild;
    }

    /**
     * Finds the right sibling of the left child of a binary operator,
     * skipping parentheses.
     * @param aLeftChild the left child of a binary operator.
     * @return the node of the right sibling.
     */
    private SymTabAST findRightSibling(SymTabAST aLeftChild) {
        SymTabAST rightChild = (SymTabAST) (aLeftChild.getNextSibling());
        // handle Checkstyle grammar
        while ((rightChild != null) && (rightChild.getType() == TokenTypes.RPAREN)) {
            rightChild = (SymTabAST) rightChild.getNextSibling();
        }
        return rightChild;
    }

    /**
     * Returns the <code>ClassDef</code> for the type to which arithmetic
     * expressions evaluate.
     *
     * @param a the <code>ClassDef</code> of the first operand.
     * @param b the <code>ClassDef</code> of the second operand.
     *
     * @return the <code>ClassDef</code> to which the expression evaluates.
     */
    private IClass binaryResultType(IClass a, IClass b) {

        IClass result = null;

        // These may or may not be in line with the rules set forth in the java
        // language specification.  Not being in line would be a BadThing(r).

        IClass string = new ExternalClass(java.lang.String.class);

        if (a.equals(string) || b.equals(string)) {
            result = string;
        } else if (a.equals(PrimitiveClasses.BOOLEAN)) {
            result = PrimitiveClasses.BOOLEAN;
        } else {
            result = PrimitiveClasses.binaryPromote(a, b);
        }

        return result;
    }

    /**
     * resolves references in an instanceof expression
     *
     * @param expression the <code>SymTabAST</code> of the expression
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the resulting scope of the expression (the type to which it evaluates)
     */
    private IClass resolveInstanceOf(SymTabAST expression, Scope location, IClass context, boolean referencePhase) {
        SymTabAST leftNode = (SymTabAST) (expression.getFirstChild());
        SymTabAST rightNode = (SymTabAST) (leftNode.getNextSibling());

        resolveExpression(leftNode, location, context, referencePhase);

        SymTabAST classNameNode = (SymTabAST) (rightNode.getFirstChild());
        resolveClass(classNameNode, location, context, referencePhase);

        return LiteralResolver.getDefinition(TokenTypes.LITERAL_BOOLEAN);
    }

    /**
     * resolves references in a a break statement
     *
     * @param expression the <code>SymTabAST</code> for the expression
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the <code>Scope</code> for the int primitive type
     */
    private IClass resolveGoto(SymTabAST expression, Scope location, IClass context, boolean referencePhase) {
        SymTabAST label = (SymTabAST) (expression.getFirstChild());
        // handle Checkstyle grammar
        if (label != null && (label.getType() != TokenTypes.SEMI)) {
            LabelDef def = location.getLabelDefinition(label.getText());
            if (def != null) {
                label.setDefinition(def, location, referencePhase);
            }
        }

        return null;
    }

    private IClass resolvePrimitiveType(SymTabAST primitive, Scope location, IClass context,
            boolean referencePhase) {
        IClass result = LiteralResolver.getDefinition(primitive.getType());

        primitive.setDefinition(result, location, referencePhase);
        return result;
    }

    /**
     * Returns the <code>ClassDef</code> of the int primitive type.  This may
     * need to be amended, based on the Java Language spec, to return a long
     * if the literal is larger than an int can hold.
     *
     * @param expression the <code>SymTabAST</code> for the integer literal
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the <code>Scope</code> for the int primitive type
     */
    private IClass resolveNumInt(SymTabAST expression, Scope location, IClass context) {
        return PrimitiveClasses.INT;
    }

    /**
     * Returns the <code>ClassDef</code> type of the float primitive type.
     * This may need to be amended, based on the Java Language spec, to return
     * a double if the literal is larger than a float can hold.
     *
     * @param expression the <code>SymTabAST</code> for the floating point
      literal
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the <code>Scope</code> for the float primitive type
     */
    private IClass resolveNumFloat(SymTabAST expression, Scope location, IClass context) {
        return PrimitiveClasses.DOUBLE;
    }

    /**
     * Returns the <code>ClassDef</code> type of a string literal
     *
     * @param expression the <code>SymTabAST</code> for a string literal
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the <code>Scope</code> type of a string literal
     */
    private IClass resolveStringLiteral(SymTabAST expression, Scope location, IClass context) {
        return LiteralResolver.getDefinition(TokenTypes.STRING_LITERAL);
    }

    /**
     * Returns the <code>ClassDef</code> type of a character literal
     *
     * @param expression the <code>SymTabAST</code> for a string literal
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the <code>Scope</code> type of a character literal
     */
    private IClass resolveCharLiteral(SymTabAST expression, Scope location, IClass context) {
        return LiteralResolver.getDefinition(TokenTypes.LITERAL_CHAR);
    }

    /**
     * Describe <code>resolveBooleanLiteral</code> method here.
     *
     * @param expression the <code>SymTabAST</code> of the expression
     * @param location the <code>Scope</code> where the expression occurs
     * @param context the <code>Scope</code> in which the expression occurs
     *                (where the search for a defintion begins)
     *
     * @return the <code>Scope</code> for the boolean primitive.
     */
    private IClass resolveBooleanLiteral(SymTabAST expression, Scope location, IClass context) {
        return LiteralResolver.getDefinition(TokenTypes.LITERAL_BOOLEAN);
    }

    private IClass resolveBooleanUnary(SymTabAST expression, Scope location, IClass context,
            boolean referencePhase) {
        SymTabAST child = (SymTabAST) expression.getFirstChild();
        resolveExpression(child, location, context, referencePhase);

        return LiteralResolver.getDefinition(TokenTypes.LITERAL_BOOLEAN);
    }

    /**
     * Resolves a constructor call.
     *
     * @param tree the root node of the constructor call
     * @return the <code>ClassDef</code> for the class instantiated by the
     *         constructor
     */
    private void resolveArrayInitializer(SymTabAST initializerNode, Scope location, IClass context,
            boolean referencePhase) {
        SymTabAST child = (SymTabAST) (initializerNode.getFirstChild());
        while (child != null) {
            if (child.getType() != TokenTypes.COMMA) {
                resolveExpression(child, location, context, referencePhase);
            }
            child = (SymTabAST) (child.getNextSibling());
        }
    }

    /**
     * Resolves a constructor call.
     *
     * @param tree the root node of the constructor call
     * @return the <code>ClassDef</code> for the class instantiated by the
     *         constructor
     */
    private void resolveThrowExpression(SymTabAST throwNode, Scope location, IClass context,
            boolean referencePhase) {

        SymTabAST nameNode = (SymTabAST) (throwNode.getFirstChild());
        resolveExpression(nameNode, location, context, referencePhase);
    }

    private IClass resolveShiftOperator(SymTabAST expression, Scope location, IClass context,
            boolean referencePhase) {
        IClass result = null;

        SymTabAST leftChild = findLeftChild(expression);
        SymTabAST rightChild = findRightSibling(leftChild);

        result = resolveExpression(leftChild, location, context, referencePhase);
        resolveExpression(rightChild, location, context, referencePhase);

        result = PrimitiveClasses.unaryPromote(result);

        return result;
    }

    private IClass resolveBitwiseNot(SymTabAST expression, Scope location, IClass context, boolean referencePhase) {
        IClass result = null;
        SymTabAST child = (SymTabAST) expression.getFirstChild();
        result = resolveExpression(child, location, context, referencePhase);

        result = PrimitiveClasses.unaryPromote(result);

        return result;
    }
}