/******************************************************************************* * Copyright (c) 2013 Zend Technologies 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 * * Contributors: * Zend Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.php.internal.core.compiler.ast.parser; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.ASTVisitor; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.declarations.TypeDeclaration; import org.eclipse.dltk.ast.expressions.Expression; import org.eclipse.dltk.ast.statements.Block; import org.eclipse.dltk.ast.statements.Statement; import org.eclipse.php.core.compiler.ast.nodes.NamespaceDeclaration; import org.eclipse.php.core.compiler.ast.nodes.UsePart; import org.eclipse.php.core.compiler.ast.nodes.UseStatement; /** * Base AST visitor for finding use statements in PHP source modules. * * <p> * This visitor is optimized for performance to look not deeper than the * necessary level in the AST tree. As described in the * <a href="http://php.net/manual/en/language.namespaces.importing.php">PHP * Manual</a> use statements can be legally placed only in the global scope of a * file or inside namespace declarations. * </p> * * <p> * This visitor also accepts an <code>offset</code> parameter. Searching is not * performed after the <code>offset</code>. * </p> * * @author Kaloyan Raev * */ public abstract class AbstractUseStatementASTVisitor extends ASTVisitor { /** * The position in the AST tree after which the search stops. */ protected int offset; /** * Constructor of the visitor * * @param offset * the position in the AST tree after which the search stops */ protected AbstractUseStatementASTVisitor(int offset) { this.offset = offset; } /** * The visitor must always look inside {@link ModuleDeclaration}s. */ @Override public boolean visit(ModuleDeclaration s) throws Exception { return isBeforeOffset(s); } /** * The visitor must check if a {@link Statement} is an {@link UseStatement}. * If yes then call {@link #visit(UseStatement)}. Otherwise the visitor must * not look deeper in the AST tree. */ @Override public boolean visit(Statement s) throws Exception { if (s instanceof UseStatement && isBeforeOffset(s)) { UseStatement useStatement = (UseStatement) s; visit(useStatement); } return false; } /** * The visitor must look into an {@link Expression} only if it is a * {@link Block} (because it can be a block of namespace declaration). */ @Override public boolean visit(Expression s) throws Exception { return s instanceof Block && isBeforeOffset(s); } /** * The visitor must look into a {@link TypeDeclaration} only if it a * {@link NamespaceDeclaration}. */ @Override public boolean visit(TypeDeclaration s) throws Exception { return s instanceof NamespaceDeclaration && isBeforeOffset(s); } /** * In all other cases the visitor must not look deeper into the AST tree - * there is no chance to find an {@link UseStatement} there. */ @Override public boolean visitGeneral(ASTNode node) throws Exception { return false; } /** * Visits a {@link UseStatement} node. * * <p> * This is a default implementation that calls {@link #visit(UsePart)} for * each <code>UsePart<code> in the <code>UseStatement</code>. It can be * overridden by subclasses. * </p> * * @param UseStatement * the <code>UseStatement</code> node that is being visited */ protected void visit(UseStatement s) throws Exception { for (UsePart usePart : s.getParts()) { if (!visit(usePart)) { // do not visit the rest of the use parts break; } } } /** * Visits a {@link UsePart} node. * * <p> * This is a default implementation that can be overridden by subclasses. * </p> * * @param usePart * the <code>UsePart</code> node that is being visited * @return <code>true</code> if the next <code>UsePart</code> in a * <code>UseStatament</code> should be visited, <code>false</code> - * otherwise. */ protected boolean visit(UsePart usePart) { return false; } /** * Checks if the specified node position is before the offset. * * @param node * the <code>ASTNode<code> to check * @return <code>true</code> if the node's start position is before the * offset, <code>false</code> - otherwise. */ protected boolean isBeforeOffset(ASTNode node) { return node.sourceStart() < offset; } }