/*******************************************************************************
* Copyright (c) 2009 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
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org2.eclipse.php.internal.core.search;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org2.eclipse.php.internal.core.ast.locator.PhpElementConciliator;
import org2.eclipse.php.internal.core.ast.nodes.*;
/**
* Constants occurrences finder.
*
* @author shalom
*/
public class ConstantsOccurrencesFinder extends AbstractOccurrencesFinder {
public static final String ID = "ConstantsOccurrencesFinder"; //$NON-NLS-1$
private boolean defineFound;
private boolean isCaseSensitiveConstant = true; // The default is true
private String constantName;
private ASTNode nameNode;
private Map<ASTNode, String> nodeToFullName = new HashMap<ASTNode, String>();
private Map<ASTNode, OccurrenceLocation> nodeToOccurrence = new HashMap<ASTNode, OccurrenceLocation>();
/**
* @param root
* the AST root
* @param node
* the selected node (must be an {@link Scalar} instance)
* @return returns a message if there is a problem
*/
public String initialize(Program root, ASTNode node) {
fASTRoot = root;
defineFound = false;
isCaseSensitiveConstant = true;
if (node.getType() == ASTNode.SCALAR) {
nameNode = (Scalar) node;
constantName = ((Scalar) nameNode).getStringValue();
if (isQuoted(constantName)) {
constantName = constantName.substring(1,
constantName.length() - 1);
}
return null;
} else if (node.getType() == ASTNode.IDENTIFIER
&& node.getParent().getType() == ASTNode.NAMESPACE_NAME) {
nameNode = node;
constantName = ((Identifier) node).getName();
return null;
}
fDescription = "OccurrencesFinder_occurrence_description"; //$NON-NLS-1$
return fDescription;
}
/*
* (non-Javadoc)
*
* @see
* org2.eclipse.php.internal.ui.search.AbstractOccurrencesFinder#findOccurrences
* ()
*/
protected void findOccurrences() {
fDescription = Messages.format(BASE_DESCRIPTION, constantName);
fASTRoot.accept(this);
if (nodeToFullName.containsKey(nameNode)) {
String fullName = nodeToFullName.get(nameNode);
for (Iterator<ASTNode> iterator = nodeToFullName.keySet()
.iterator(); iterator.hasNext();) {
ASTNode nameNode = iterator.next();
if (nodeToFullName.get(nameNode).equalsIgnoreCase(fullName)) {
fResult.add(nodeToOccurrence.get(nameNode));
}
}
}
}
public boolean visit(Identifier identifier) {
if (checkEquality(identifier.getName())
&& PhpElementConciliator.isGlobalConstant(identifier)) {
nodeToFullName.put(identifier, getFullName((Identifier) identifier
.getParent(), fLastUseParts, fCurrentNamespace));
nodeToOccurrence.put(identifier, new OccurrenceLocation(identifier
.getStart(), identifier.getLength(),
getOccurrenceType(identifier), fDescription));
}
return true;
}
/**
* Visit the scalars in the program.
*/
public boolean visit(Scalar scalar) {
String scalarValue = scalar.getStringValue();
if (scalar.getScalarType() == Scalar.TYPE_STRING && scalarValue != null) {
// disregard strings
if (!isQuoted(scalarValue)
&& (scalar.getParent().getType() != ASTNode.QUOTE)) {
if (checkEquality(scalarValue)) {
// Usage of the scalar
nodeToFullName.put(scalar, getFullName(scalarValue,
fLastUseParts, fCurrentNamespace));
nodeToOccurrence.put(scalar, new OccurrenceLocation(scalar
.getStart(), scalar.getLength(),
getOccurrenceType(scalar), fDescription));
// fResult.add(new OccurrenceLocation(scalar.getStart(),
// scalar.getLength(), getOccurrenceType(scalar),
// fDescription));
}
} else {
// The scalar is quoted, so it might be in a 'define' or a
// 'constant' call.
if (isQuoted(scalarValue)) {
scalarValue = scalarValue.substring(1,
scalarValue.length() - 1);
}
if (checkEquality(scalarValue)) {
ASTNode parent = scalar.getParent();
if (parent.getType() == ASTNode.FUNCTION_INVOCATION) {
// Check if this is the definition function of the
// scalar (define).
FunctionInvocation functionInvocation = (FunctionInvocation) parent;
Expression name = functionInvocation.getFunctionName()
.getName();
if (name instanceof Identifier) {
String functionName = ((Identifier) name).getName();
if ("define".equalsIgnoreCase(functionName)) {//$NON-NLS-1$
defineFound = true;
// check if the 'define' has a case sensitivity
// definition
isCaseSensitiveConstant = isCaseSensitiveDefined(functionInvocation
.parameters());
if (!isCaseSensitiveConstant
|| isCaseSensitiveConstant
&& constantName.equals(scalarValue)) {
String writeDescription = Messages.format(
BASE_WRITE_DESCRIPTION, scalar
.getStringValue());
nodeToFullName.put(scalar, getFullName(
scalarValue, fLastUseParts,
fCurrentNamespace));
nodeToOccurrence
.put(
scalar,
new OccurrenceLocation(
scalar.getStart(),
scalar.getLength(),
IOccurrencesFinder.F_WRITE_OCCURRENCE,
writeDescription));
// fResult
// .add(new OccurrenceLocation(
// scalar.getStart(),
// scalar.getLength(),
// IOccurrencesFinder.F_WRITE_OCCURRENCE,
// writeDescription));
}
} else if ("constant".equalsIgnoreCase(functionName)) { //$NON-NLS-1$
if (!isCaseSensitiveConstant
|| isCaseSensitiveConstant
&& constantName.equals(scalarValue)) {
nodeToFullName.put(scalar, getFullName(
scalarValue, fLastUseParts,
fCurrentNamespace));
nodeToOccurrence
.put(
scalar,
new OccurrenceLocation(
scalar.getStart(),
scalar.getLength(),
IOccurrencesFinder.F_READ_OCCURRENCE,
fDescription));
// fResult
// .add(new OccurrenceLocation(
// scalar.getStart(),
// scalar.getLength(),
// IOccurrencesFinder.F_READ_OCCURRENCE,
// fDescription));
}
}
}
}
}
}
}
return true;
}
/*
* Check the function invocation parameters to see if the case-sensitive
* parameter is true or false. Define signature: { define ( string $name ,
* mixed $value [, bool $case_insensitive ] ) }
*
* @param parameters The function invocation parameters.
*
* @return True, if the 'define' call does not contain a case parameter or
* contains it as true; False, in case that the parameters contain a 'false'
* case parameter.
*/
private boolean isCaseSensitiveDefined(List<Expression> parameters) {
if (parameters.size() != 3) {
// default behavior is case sensitive.
return true;
}
Expression expression = parameters.get(2);
if (expression.getType() == ASTNode.SCALAR) {
Scalar scalar = (Scalar) expression;
String value = scalar.getStringValue();
return "true".equalsIgnoreCase(value); //$NON-NLS-1$
}
return false;
}
/*
* Check that the given name is equal to the searched constant name. The
* equality check is done according to these rules: 1. In case that the
* case-sensitive flag is false, or in case that the scalar appears before a
* 'define' call, we check for case-insensitive equality. 2. In any other
* case, the equality check is case sensitive.
*
* @param scalarValue The value to compare.
*
* @return True, if equals according to the conditions; False, otherwise.
*/
private boolean checkEquality(String scalarValue) {
if (!isCaseSensitiveConstant || !defineFound) {
return constantName.equalsIgnoreCase(scalarValue);
}
return constantName.equals(scalarValue);
}
private static boolean isQuoted(String str) {
if (str == null || str.length() < 3) {
return false;
}
char first = str.charAt(0);
char last = str.charAt(str.length() - 1);
return (first == '\'' || first == '\"')
&& (last == '\'' || last == '\"');
}
/*
* (non-Javadoc)
*
* @see org2.eclipse.php.internal.ui.search.AbstractOccurrencesFinder#
* getOccurrenceReadWriteType
* (org2.eclipse.php.internal.core.ast.nodes.ASTNode)
*/
protected int getOccurrenceType(ASTNode node) {
// Default return is F_READ_OCCURRENCE, although the implementation of
// the Scalar visit might also use F_WRITE_OCCURRENCE
return IOccurrencesFinder.F_READ_OCCURRENCE;
}
/*
* (non-Javadoc)
*
* @see
* org2.eclipse.php.internal.ui.search.IOccurrencesFinder#getElementName()
*/
public String getElementName() {
return constantName;
}
/*
* (non-Javadoc)
*
* @see org2.eclipse.php.internal.ui.search.IOccurrencesFinder#getID()
*/
public String getID() {
return ID;
}
}