org.eclipse.objectteams.otdt.debug.ui.internal.actions.OTValidBreakpointLocationLocator.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.objectteams.otdt.debug.ui.internal.actions.OTValidBreakpointLocationLocator.java

Source

/*******************************************************************************
 * Copyright (c) 2003, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: OTValidBreakpointLocationLocator.java 23432 2010-02-03 23:13:42Z stephan $
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Fraunhofer FIRST - extended API and implementation
 *     Technical University Berlin - extended API and implementation
 *******************************************************************************/
package org.eclipse.objectteams.otdt.debug.ui.internal.actions;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.core.dom.PrefixExpression.Operator;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;

/**
 * Compute a valid location where to put a breakpoint from an JDOM CompilationUnit.
 * The result is the first valid location with a line number greater or equals than the given position.
 *
 * The Visitor visits now also OT-nodes like Callout-/CallinMappingDeclaration and decides wheather a breakpoint
 * is allowed in this node or not.
*
 * @author ike
 * $Id: OTValidBreakpointLocationLocator.java 23432 2010-02-03 23:13:42Z stephan $
 */
//{OT_COPY_PASTE from org.eclipse.jdt.internal.debug.ui.action.ValidBreakpointLocationLocator
// due to private visibility of visit(ASTNode, boolean) (added visitor-methods can't call it)
// -> could easily be ported to OT, together with OTBreakpointLocationVerifierJob
public class OTValidBreakpointLocationLocator extends ASTVisitor {

    public static final int LOCATION_NOT_FOUND = 0;
    public static final int LOCATION_LINE = 1;
    public static final int LOCATION_METHOD = 2;
    public static final int LOCATION_FIELD = 3;

    private CompilationUnit fCompilationUnit;
    private int fLineNumber;
    private boolean fBindingsResolved;
    private boolean fNeedBindings = false;
    private boolean fBestMatch;

    private int fLocationType;
    private boolean fLocationFound;
    private String fTypeName;
    private int fLineLocation;
    private int fMemberOffset;
    private List fLabels;

    /**
     * @param compilationUnit the JDOM CompilationUnit of the source code.
     * @param lineNumber the line number in the source code where to put the breakpoint.
     * @param bestMatch if <code>true</code> look for the best match, otherwise look only for a valid line
     */
    public OTValidBreakpointLocationLocator(CompilationUnit compilationUnit, int lineNumber,
            boolean bindingsResolved, boolean bestMatch) {
        fCompilationUnit = compilationUnit;
        fLineNumber = lineNumber;
        fBindingsResolved = bindingsResolved;
        fBestMatch = bestMatch;
        fLocationFound = false;
    }

    /**
     * Returns whether binding information would be helpful in validating a breakpoint
     * location. If this locator makes a pass of the tree and determines that binding
     * information would be helpful but was not available, this method returns
     * <code>true</code>.
     * 
     * @return whether binding information would be helpful in validating a breakpoint location
     */
    public boolean isBindingsRequired() {
        return fNeedBindings;
    }

    /**
     * Return the type of the valid location found
     * @return one of LOCATION_NOT_FOUND, LOCATION_LINE, LOCATION_METHOD or LOCATION_FIELD
     */
    public int getLocationType() {
        return fLocationType;
    }

    /**
     * Return of the type where the valid location is.
     */
    public String getFullyQualifiedTypeName() {
        return fTypeName;
    }

    /**
     * Return the line number of the computed valid location, if the location type is LOCATION_LINE.
     */
    public int getLineLocation() {
        if (fLocationType == LOCATION_LINE) {
            return fLineLocation;
        }
        return -1;
    }

    /**
     * Return the offset of the member which is the valid location,
     * if the location type is LOCATION_METHOD or LOCATION_FIELD.
     */
    public int getMemberOffset() {
        return fMemberOffset;
    }

    /**
     * Compute the name of the type which contains this node.
     * Result will be the name of the type or the inner type which contains this node, but not of the local or anonymous type.
     */
    static protected String computeTypeName(ASTNode node) {
        //{ObjectTeams: several modifications to cope with role classes (inline and role file):

        // type part:
        String typeName = null;
        while (!(node instanceof CompilationUnit)) {
            if (node instanceof AbstractTypeDeclaration) {
                String identifier = ((AbstractTypeDeclaration) node).getName().getIdentifier();
                if (typeName == null) {
                    typeName = identifier;
                    if (node instanceof RoleTypeDeclaration && !typeName.startsWith(IOTConstants.OT_DELIM))
                        typeName = IOTConstants.OT_DELIM + typeName;
                } else {
                    typeName = identifier + '$' + typeName;
                }
            } else {
                typeName = null;
            }
            node = node.getParent();
        }

        // package part (may be team package):
        PackageDeclaration packageDecl = ((CompilationUnit) node).getPackage();
        char sep = '.'; // for regular toplevel types
        if (typeName.startsWith(IOTConstants.OT_DELIM))
            sep = '$'; // for role files
        String packageIdentifier = ""; //$NON-NLS-1$
        if (packageDecl != null) {
            Name packageName = packageDecl.getName();
            while (packageName.isQualifiedName()) {
                QualifiedName qualifiedName = (QualifiedName) packageName;
                packageIdentifier = qualifiedName.getName().getIdentifier() + sep + packageIdentifier;
                sep = '.';
                packageName = qualifiedName.getQualifier();
            }
            packageIdentifier = ((SimpleName) packageName).getIdentifier() + sep + packageIdentifier;
        }

        return packageIdentifier + typeName;
        // SH}
    }

    /**
     * Return <code>true</code> if this node children may contain a valid location
     * for the breakpoint.
     * @param node the node.
     * @param isCode true indicated that the first line of the given node always
     *   contains some executable code, even if split in multiple lines.
     */
    private boolean visit(ASTNode node, boolean isCode) {
        // if we already found a correct location
        // no need to check the element inside.
        if (fLocationFound) {
            return false;
        }
        int startPosition = node.getStartPosition();
        int endLine = lineNumber(startPosition + node.getLength() - 1);
        // if the position is not in this part of the code
        // no need to check the element inside.
        if (endLine < fLineNumber) {
            return false;
        }
        // if the first line of this node always represents some executable code and the
        // breakpoint is requested on this line or on a previous line, this is a valid 
        // location
        int startLine = lineNumber(startPosition);
        if (isCode && (fLineNumber <= startLine)) {
            fLineLocation = startLine;
            fLocationFound = true;
            fLocationType = LOCATION_LINE;
            fTypeName = computeTypeName(node);
            return false;
        }
        return true;
    }

    private boolean isReplacedByConstantValue(Expression node) {
        switch (node.getNodeType()) {
        // litterals are constant
        case ASTNode.BOOLEAN_LITERAL:
        case ASTNode.CHARACTER_LITERAL:
        case ASTNode.NUMBER_LITERAL:
        case ASTNode.STRING_LITERAL:
            return true;
        case ASTNode.SIMPLE_NAME:
        case ASTNode.QUALIFIED_NAME:
            return isReplacedByConstantValue((Name) node);
        case ASTNode.FIELD_ACCESS:
            return isReplacedByConstantValue((FieldAccess) node);
        case ASTNode.SUPER_FIELD_ACCESS:
            return isReplacedByConstantValue((SuperFieldAccess) node);
        case ASTNode.INFIX_EXPRESSION:
            return isReplacedByConstantValue((InfixExpression) node);
        case ASTNode.PREFIX_EXPRESSION:
            return isReplacedByConstantValue((PrefixExpression) node);
        case ASTNode.CAST_EXPRESSION:
            return isReplacedByConstantValue(((CastExpression) node).getExpression());
        default:
            return false;
        }
    }

    private boolean isReplacedByConstantValue(InfixExpression node) {
        // if all operands are constant value, the expression is replaced by a constant value
        if (!(isReplacedByConstantValue(node.getLeftOperand())
                && isReplacedByConstantValue(node.getRightOperand()))) {
            return false;
        }
        if (node.hasExtendedOperands()) {
            for (Iterator iter = node.extendedOperands().iterator(); iter.hasNext();) {
                if (!isReplacedByConstantValue((Expression) iter.next())) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isReplacedByConstantValue(PrefixExpression node) {
        // for '-', '+', '~' and '!', if the operand is a constant value,
        // the expression is replaced by a constant value
        Operator operator = node.getOperator();
        if (operator != PrefixExpression.Operator.INCREMENT && operator != PrefixExpression.Operator.DECREMENT) {
            return isReplacedByConstantValue(node.getOperand());
        }
        return false;
    }

    private boolean isReplacedByConstantValue(Name node) {
        if (!fBindingsResolved) {
            fNeedBindings = true;
            return false;
        }
        // if node is a variable with a constant value (static final field)
        IBinding binding = node.resolveBinding();
        if (binding != null && binding.getKind() == IBinding.VARIABLE) {
            return ((IVariableBinding) binding).getConstantValue() != null;
        }
        return false;
    }

    private boolean isReplacedByConstantValue(FieldAccess node) {
        if (!fBindingsResolved) {
            fNeedBindings = true;
            return false;
        }
        // if the node is 'this.<field>', and the field is static final
        Expression expression = node.getExpression();
        IVariableBinding binding = node.resolveFieldBinding();
        if (binding != null && expression.getNodeType() == ASTNode.THIS_EXPRESSION) {
            return binding.getConstantValue() != null;
        }
        return false;
    }

    private boolean isReplacedByConstantValue(SuperFieldAccess node) {
        if (!fBindingsResolved) {
            fNeedBindings = true;
            return false;
        }
        // if the field is static final
        IVariableBinding binding = node.resolveFieldBinding();
        if (binding != null) {
            return binding.getConstantValue() != null;
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration)
     */
    public boolean visit(AnnotationTypeDeclaration node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration)
     */
    public boolean visit(AnnotationTypeMemberDeclaration node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnonymousClassDeclaration)
     */
    public boolean visit(AnonymousClassDeclaration node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayAccess)
     */
    public boolean visit(ArrayAccess node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayCreation)
     */
    public boolean visit(ArrayCreation node) {
        return visit(node, node.getInitializer() == null);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayInitializer)
     */
    public boolean visit(ArrayInitializer node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayType)
     */
    public boolean visit(ArrayType node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AssertStatement)
     */
    public boolean visit(AssertStatement node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Assignment)
     */
    public boolean visit(Assignment node) {
        if (visit(node, false)) {
            // if the left hand side represent a local variable, or a static field
            // and the breakpoint was requested on a line before the line where
            // starts the assigment, set the location to be the first executable
            // instruction of the right hand side, as it will be the first part of
            // this assigment to be executed
            Expression leftHandSide = node.getLeftHandSide();
            if (leftHandSide instanceof Name) {
                int startLine = lineNumber(node.getStartPosition());
                if (fLineNumber < startLine) {
                    if (fBindingsResolved) {
                        IVariableBinding binding = (IVariableBinding) ((Name) leftHandSide).resolveBinding();
                        if (binding != null && (!binding.isField() || Modifier.isStatic(binding.getModifiers()))) {
                            node.getRightHandSide().accept(this);
                        }
                    } else {
                        fNeedBindings = true;
                    }
                }
            }
            return true;
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Block)
     */
    public boolean visit(Block node) {
        if (visit(node, false)) {
            if (node.statements().isEmpty() && node.getParent().getNodeType() == ASTNode.METHOD_DECLARATION) {
                // in case of an empty method, set the breakpoint on the last line of the empty block.
                fLineLocation = lineNumber(node.getStartPosition() + node.getLength() - 1);
                fLocationFound = true;
                fLocationType = LOCATION_LINE;
                fTypeName = computeTypeName(node);
                return false;
            }
            return true;
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BlockComment)
     */
    public boolean visit(BlockComment node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BooleanLiteral)
     */
    public boolean visit(BooleanLiteral node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BreakStatement)
     */
    public boolean visit(BreakStatement node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CastExpression)
     */
    public boolean visit(CastExpression node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CatchClause)
     */
    public boolean visit(CatchClause node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CharacterLiteral)
     */
    public boolean visit(CharacterLiteral node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ClassInstanceCreation)
     */
    public boolean visit(ClassInstanceCreation node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CompilationUnit)
     */
    public boolean visit(CompilationUnit node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConditionalExpression)
     */
    public boolean visit(ConditionalExpression node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConstructorInvocation)
     */
    public boolean visit(ConstructorInvocation node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ContinueStatement)
     */
    public boolean visit(ContinueStatement node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.DoStatement)
     */
    public boolean visit(DoStatement node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EmptyStatement)
     */
    public boolean visit(EmptyStatement node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnhancedForStatement)
     */
    public boolean visit(EnhancedForStatement node) {
        if (visit(node, false)) {
            node.getExpression().accept(this);
            node.getBody().accept(this);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumConstantDeclaration)
     */
    public boolean visit(EnumConstantDeclaration node) {
        if (visit(node, false)) {
            List arguments = node.arguments();
            for (Iterator iter = arguments.iterator(); iter.hasNext();) {
                ((Expression) iter.next()).accept(this);
            }
            AnonymousClassDeclaration decl = node.getAnonymousClassDeclaration();
            if (decl != null) {
                decl.accept(this);
            }
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumDeclaration)
     */
    public boolean visit(EnumDeclaration node) {
        if (visit(node, false)) {
            List enumConstants = node.enumConstants();
            for (Iterator iter = enumConstants.iterator(); iter.hasNext();) {
                ((EnumConstantDeclaration) iter.next()).accept(this);
            }
            List bodyDeclaration = node.bodyDeclarations();
            for (Iterator iter = bodyDeclaration.iterator(); iter.hasNext();) {
                ((BodyDeclaration) iter.next()).accept(this);
            }
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ExpressionStatement)
     */
    public boolean visit(ExpressionStatement node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldAccess)
     */
    public boolean visit(FieldAccess node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration)
     */
    public boolean visit(FieldDeclaration node) {
        if (visit(node, false)) {
            if (fBestMatch) {
                // check if the line contains a single field declaration.
                List fragments = node.fragments();
                if (fragments.size() == 1) {
                    int offset = ((VariableDeclarationFragment) fragments.get(0)).getName().getStartPosition();
                    // check if the breakpoint is to be set on the line which contains the name of the field
                    if (lineNumber(offset) == fLineNumber) {
                        fMemberOffset = offset;
                        fLocationType = LOCATION_FIELD;
                        fLocationFound = true;
                        return false;
                    }
                }
            }
            // visit only the variable declaration fragments, no the variable names.
            List fragments = node.fragments();
            for (Iterator iter = fragments.iterator(); iter.hasNext();) {
                ((VariableDeclarationFragment) iter.next()).accept(this);
            }
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ForStatement)
     */
    public boolean visit(ForStatement node) {
        // in case on a "for(;;)", the breakpoint can be set on the first token of the node.
        return visit(node,
                node.initializers().isEmpty() && node.getExpression() == null && node.updaters().isEmpty());
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.IfStatement)
     */
    public boolean visit(IfStatement node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ImportDeclaration)
     */
    public boolean visit(ImportDeclaration node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.InfixExpression)
     */
    public boolean visit(InfixExpression node) {
        // if the breakpoint is to be set on a constant operand, the breakpoint needs to be
        // set on the first constant operand after the previous non-constant operand
        // (or the beginning of the expression, if there is no non-constant operand before).
        // ex:   foo() +    // previous non-constant operand
        //       1 +        // breakpoint set here
        //       2          // breakpoint asked to be set here
        if (visit(node, false)) {
            Expression leftOperand = node.getLeftOperand();
            Expression firstConstant = null;
            if (visit(leftOperand, false)) {
                leftOperand.accept(this);
                return false;
            }
            if (isReplacedByConstantValue(leftOperand)) {
                firstConstant = leftOperand;
            }
            Expression rightOperand = node.getRightOperand();
            if (visit(rightOperand, false)) {
                if (firstConstant == null || !isReplacedByConstantValue(rightOperand)) {
                    rightOperand.accept(this);
                    return false;
                }
            } else {
                if (isReplacedByConstantValue(rightOperand)) {
                    if (firstConstant == null) {
                        firstConstant = rightOperand;
                    }
                } else {
                    firstConstant = null;
                }
                List extendedOperands = node.extendedOperands();
                for (Iterator iter = extendedOperands.iterator(); iter.hasNext();) {
                    Expression operand = (Expression) iter.next();
                    if (visit(operand, false)) {
                        if (firstConstant == null || !isReplacedByConstantValue(operand)) {
                            operand.accept(this);
                            return false;
                        }
                        break;
                    }
                    if (isReplacedByConstantValue(operand)) {
                        if (firstConstant == null) {
                            firstConstant = operand;
                        }
                    } else {
                        firstConstant = null;
                    }

                }
            }
            fLineLocation = lineNumber(firstConstant.getStartPosition());
            fLocationFound = true;
            fLocationType = LOCATION_LINE;
            fTypeName = computeTypeName(firstConstant);
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Initializer)
     */
    public boolean visit(Initializer node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.InstanceofExpression)
     */
    public boolean visit(InstanceofExpression node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Javadoc)
     */
    public boolean visit(Javadoc node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.LabeledStatement)
     */
    public boolean visit(LabeledStatement node) {
        nestLabel(node.getLabel().getFullyQualifiedName());
        return visit(node, false);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.LabeledStatement)
     */
    public void endVisit(LabeledStatement node) {
        popLabel();
        super.endVisit(node);
    }

    private String getLabel() {
        if (fLabels == null || fLabels.isEmpty()) {
            return null;
        }
        return (String) fLabels.get(fLabels.size() - 1);
    }

    private void nestLabel(String label) {
        if (fLabels == null) {
            fLabels = new ArrayList();
        }
        fLabels.add(label);
    }

    private void popLabel() {
        if (fLabels == null || fLabels.isEmpty()) {
            return;
        }
        fLabels.remove(fLabels.size() - 1);
    }

    /* (non-Javadoc)
    * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.LineComment)
    */
    public boolean visit(LineComment node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
     */
    public boolean visit(MarkerAnnotation node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef)
     */
    public boolean visit(MemberRef node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberValuePair)
     */
    public boolean visit(MemberValuePair node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
     */
    public boolean visit(MethodDeclaration node) {
        if (visit(node, false)) {
            if (fBestMatch) {
                // check if we are on the line which contains the method name
                int nameOffset = node.getName().getStartPosition();
                if (lineNumber(nameOffset) == fLineNumber) {
                    fMemberOffset = nameOffset;
                    fLocationType = LOCATION_METHOD;
                    fLocationFound = true;
                    return false;
                }
            }
            // visit only the body
            Block body = node.getBody();
            if (body != null) { // body is null for abstract methods
                body.accept(this);
            }
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodInvocation)
     */
    public boolean visit(MethodInvocation node) {
        return visit(node, true);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef)
     */
    public boolean visit(MethodRef node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRefParameter)
     */
    public boolean visit(MethodRefParameter node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier)
     */
    public boolean visit(Modifier node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.NormalAnnotation)
     */
    public boolean visit(NormalAnnotation node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.NullLiteral)
     */
    public boolean visit(NullLiteral node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.NumberLiteral)
     */
    public boolean visit(NumberLiteral node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PackageDeclaration)
     */
    public boolean visit(PackageDeclaration node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ParameterizedType)
     */
    public boolean visit(ParameterizedType node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ParenthesizedExpression)
     */
    public boolean visit(ParenthesizedExpression node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PostfixExpression)
     */
    public boolean visit(PostfixExpression node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PrefixExpression)
     */
    public boolean visit(PrefixExpression node) {
        if (visit(node, false)) {
            if (isReplacedByConstantValue(node)) {
                fLineLocation = lineNumber(node.getStartPosition());
                fLocationFound = true;
                fLocationType = LOCATION_LINE;
                fTypeName = computeTypeName(node);
                return false;
            }
            return true;
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PrimitiveType)
     */
    public boolean visit(PrimitiveType node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedName)
     */
    public boolean visit(QualifiedName node) {
        visit(node, true);
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedType)
     */
    public boolean visit(QualifiedType node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ReturnStatement)
     */
    public boolean visit(ReturnStatement node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SimpleName)
     */
    public boolean visit(SimpleName node) {
        // the name is only code if its not the current label (if any)
        return visit(node, !node.getFullyQualifiedName().equals(getLabel()));
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SimpleType)
     */
    public boolean visit(SimpleType node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleMemberAnnotation)
     */
    public boolean visit(SingleMemberAnnotation node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleVariableDeclaration)
     */
    public boolean visit(SingleVariableDeclaration node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.StringLiteral)
     */
    public boolean visit(StringLiteral node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperConstructorInvocation)
     */
    public boolean visit(SuperConstructorInvocation node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperFieldAccess)
     */
    public boolean visit(SuperFieldAccess node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperMethodInvocation)
     */
    public boolean visit(SuperMethodInvocation node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SwitchCase)
     */
    public boolean visit(SwitchCase node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SwitchStatement)
     */
    public boolean visit(SwitchStatement node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SynchronizedStatement)
     */
    public boolean visit(SynchronizedStatement node) {
        return visit(node, false);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement)
     */
    public boolean visit(TagElement node) {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TextElement)
     */
    public boolean visit(TextElement node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ThisExpression)
     */
    public boolean visit(ThisExpression node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ThrowStatement)
     */
    public boolean visit(ThrowStatement node) {
        return visit(node, true);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TryStatement)
     */
    public boolean visit(TryStatement node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration)
     */
    public boolean visit(TypeDeclaration node) {
        if (visit(node, false)) {
            // visit only the elements of the type declaration
            List bodyDeclaration = node.bodyDeclarations();
            for (Iterator iter = bodyDeclaration.iterator(); iter.hasNext();) {
                ((BodyDeclaration) iter.next()).accept(this);
            }
        }
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclarationStatement)
     */
    public boolean visit(TypeDeclarationStatement node) {
        return visit(node, false);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeParameter)
     */
    public boolean visit(TypeParameter node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeLiteral)
     */
    public boolean visit(TypeLiteral node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationExpression)
     */
    public boolean visit(VariableDeclarationExpression node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationFragment)
     */
    public boolean visit(VariableDeclarationFragment node) {
        Expression initializer = node.getInitializer();
        if (visit(node, false) && initializer != null) {
            int startLine = lineNumber(node.getName().getStartPosition());

            if (fLineNumber == startLine) {
                fLineLocation = startLine;
                fLocationFound = true;
                fLocationType = LOCATION_LINE;
                fTypeName = computeTypeName(node);
                return false;
            }
            initializer.accept(this);
        }
        return false;
    }

    private int lineNumber(int offset) {
        int lineNumber = fCompilationUnit.getLineNumber(offset);
        return lineNumber < 1 ? 1 : lineNumber;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.WildcardType)
     */
    public boolean visit(WildcardType node) {
        return false;
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationStatement)
     */
    public boolean visit(VariableDeclarationStatement node) {
        return visit(node, false);
    }

    /**
     * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.WhileStatement)
     */
    public boolean visit(WhileStatement node) {
        return visit(node, false);
    }

    //{ObjectTeams: visit also ot-specific nodes or skip some

    public boolean visit(GuardPredicateDeclaration node) {
        // visit only the expression (don't want a method-entry breakpoint but stop directly at the expression).
        ASTNode expression = node.getExpression();
        expression.accept(this);
        return false;
    }

    public boolean visit(CallinMappingDeclaration node) {
        return visit(node, false);
    }

    public boolean visit(CalloutMappingDeclaration node) {
        return visit(node, false);
    }

    public boolean visit(FieldAccessSpec node) {
        return visit(node, false);
    }

    public boolean visit(LiftingType node) {
        return false;
    }

    public boolean visit(TypeAnchor node) {
        return false;
    }

    public boolean visit(MethodSpec node) {
        return visit(node, false);
    }

    public boolean visit(ParameterMapping node) {
        return false;
    }

    public boolean visit(RoleTypeDeclaration node) {
        if (visit(node, false)) {
            // guards first: appear before body declarations:
            GuardPredicateDeclaration guard = node.getGuardPredicate();
            if (guard != null)
                guard.accept(this);
            // visit only the elements of the type declaration
            List bodyDeclaration = node.bodyDeclarations();
            for (Iterator iter = bodyDeclaration.iterator(); iter.hasNext();) {
                ((BodyDeclaration) iter.next()).accept(this);
            }
        }
        return false;
    }

    public boolean visit(WithinStatement node) {
        return visit(node, false);
    }
    //ike}
}
//ike}