// $codepro.audit.disable platformSpecificLineSeparator
package com.aptana.editor.php.internal.indexer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java_cup.runtime.Symbol;
import org.apache.tools.ant.filters.StringInputStream;
import org.eclipse.core.resources.IProject;
import org2.eclipse.php.core.compiler.IPHPModifiers;
import org2.eclipse.php.core.compiler.PHPFlags;
import org2.eclipse.php.internal.core.PHPVersion;
import org2.eclipse.php.internal.core.ast.nodes.ASTNode;
import org2.eclipse.php.internal.core.ast.nodes.ASTParser;
import org2.eclipse.php.internal.core.ast.nodes.Assignment;
import org2.eclipse.php.internal.core.ast.nodes.Block;
import org2.eclipse.php.internal.core.ast.nodes.CatchClause;
import org2.eclipse.php.internal.core.ast.nodes.ClassDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.ClassInstanceCreation;
import org2.eclipse.php.internal.core.ast.nodes.ClassName;
import org2.eclipse.php.internal.core.ast.nodes.Comment;
import org2.eclipse.php.internal.core.ast.nodes.ConstantDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.Dispatch;
import org2.eclipse.php.internal.core.ast.nodes.DoStatement;
import org2.eclipse.php.internal.core.ast.nodes.Expression;
import org2.eclipse.php.internal.core.ast.nodes.ExpressionStatement;
import org2.eclipse.php.internal.core.ast.nodes.FieldAccess;
import org2.eclipse.php.internal.core.ast.nodes.FieldsDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.ForEachStatement;
import org2.eclipse.php.internal.core.ast.nodes.ForStatement;
import org2.eclipse.php.internal.core.ast.nodes.FormalParameter;
import org2.eclipse.php.internal.core.ast.nodes.FunctionDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.FunctionInvocation;
import org2.eclipse.php.internal.core.ast.nodes.FunctionName;
import org2.eclipse.php.internal.core.ast.nodes.GlobalStatement;
import org2.eclipse.php.internal.core.ast.nodes.Identifier;
import org2.eclipse.php.internal.core.ast.nodes.IfStatement;
import org2.eclipse.php.internal.core.ast.nodes.Include;
import org2.eclipse.php.internal.core.ast.nodes.InfixExpression;
import org2.eclipse.php.internal.core.ast.nodes.InterfaceDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.LambdaFunctionDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.MethodDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.MethodInvocation;
import org2.eclipse.php.internal.core.ast.nodes.NamespaceDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.NamespaceName;
import org2.eclipse.php.internal.core.ast.nodes.ParenthesisExpression;
import org2.eclipse.php.internal.core.ast.nodes.Program;
import org2.eclipse.php.internal.core.ast.nodes.Quote;
import org2.eclipse.php.internal.core.ast.nodes.ReturnStatement;
import org2.eclipse.php.internal.core.ast.nodes.Scalar;
import org2.eclipse.php.internal.core.ast.nodes.StaticDispatch;
import org2.eclipse.php.internal.core.ast.nodes.StaticFieldAccess;
import org2.eclipse.php.internal.core.ast.nodes.StaticStatement;
import org2.eclipse.php.internal.core.ast.nodes.SwitchStatement;
import org2.eclipse.php.internal.core.ast.nodes.TraitDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.TraitUseStatement;
import org2.eclipse.php.internal.core.ast.nodes.TryStatement;
import org2.eclipse.php.internal.core.ast.nodes.TypeDeclaration;
import org2.eclipse.php.internal.core.ast.nodes.UnaryOperation;
import org2.eclipse.php.internal.core.ast.nodes.UseStatementPart;
import org2.eclipse.php.internal.core.ast.nodes.Variable;
import org2.eclipse.php.internal.core.ast.nodes.VariableBase;
import org2.eclipse.php.internal.core.ast.nodes.WhileStatement;
import org2.eclipse.php.internal.core.ast.scanner.AstLexer;
import org2.eclipse.php.internal.core.ast.scanner.php53.ParserConstants;
import org2.eclipse.php.internal.core.ast.visitor.AbstractVisitor;
import org2.eclipse.php.internal.core.compiler.ast.nodes.PHPDocBlock;
import org2.eclipse.php.internal.core.compiler.ast.nodes.VarComment;
import com.aptana.build.util.BuildHelper;
import com.aptana.core.build.IBuildParticipant.BuildType;
import com.aptana.core.logging.IdeLog;
import com.aptana.core.util.CollectionsUtil;
import com.aptana.editor.php.PHPEditorPlugin;
import com.aptana.editor.php.core.PHPVersionProvider;
import com.aptana.editor.php.core.ast.ASTFactory;
import com.aptana.editor.php.indexer.ASTVisitorRegistry;
import com.aptana.editor.php.indexer.IElementEntry;
import com.aptana.editor.php.indexer.IElementsIndex;
import com.aptana.editor.php.indexer.IIndexReporter;
import com.aptana.editor.php.indexer.IIndexingASTVisitor;
import com.aptana.editor.php.indexer.IModuleIndexer;
import com.aptana.editor.php.indexer.IPHPIndexConstants;
import com.aptana.editor.php.indexer.IProgramIndexer;
import com.aptana.editor.php.internal.builder.ProjectBuildPath;
import com.aptana.editor.php.internal.core.builder.IModule;
import com.aptana.editor.php.internal.model.utils.ModelUtils;
import com.aptana.editor.php.internal.parser.phpdoc.FunctionDocumentation;
import com.aptana.editor.php.internal.parser.phpdoc.TypedDescription;
import com.aptana.editor.php.util.EncodingUtils;
/**
* PDTPHPModuleIndexer
*
* @author Denis Denisenko
*/
@SuppressWarnings("unused")
public class PDTPHPModuleIndexer implements IModuleIndexer, IProgramIndexer
{
private static final String DOLLAR_SIGN = "$"; //$NON-NLS-1$
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static final TaskTagsUpdater updater = new TaskTagsUpdater();
/**
* This.
*/
private static final String THIS = "this"; //$NON-NLS-1$
/**
* Self.
*/
private static final String SELF = "self"; //$NON-NLS-1$
/**
* Define function name.
*/
private static final String DEFINE = "define"; //$NON-NLS-1$
/**
* Variable info.
*
* @author Denis Denisenko
*/
private class VariableInfo
{
/**
* Variable name.
*/
private String variableName;
/**
* Variable types.
*/
private Set<Object> variableTypes;
/**
* Variable scope.
*/
private Scope scope;
/**
* Node start.
*/
private int nodeStart = 0;
private int modifier = 0;
/**
* VariableInfo constructor.
*
* @param variableName
* - variable name.
* @param variableType
* - variable type.
* @param scope
* @param pos
*/
private VariableInfo(String variableName, Object variableType, Scope scope, int pos)
{
this.variableName = variableName;
variableTypes = new HashSet<Object>(1);
if (variableType != null)
{
variableTypes.add(variableType);
}
this.scope = scope;
nodeStart = pos;
grabDockedTypes();
}
/**
* VariableInfo constructor.
*
* @param variableName
* - variable name.
* @param variableTypes
* - variable types.
* @param scope
* @param pos
*/
private VariableInfo(String variableName, Set<Object> variableTypes, Scope scope, int pos)
{
this.variableName = variableName;
this.variableTypes = variableTypes;
this.scope = scope;
nodeStart = pos;
grabDockedTypes();
}
/**
* VariableInfo constructor.
*
* @param variableName
* - variable name.
* @param variableTypes
* - variable types.
* @param scope
* - variable scope.
* @param pos
* - variable declaration position.
* @param modifier
* - variable modifier.
*/
private VariableInfo(String variableName, Set<Object> variableTypes, Scope scope, int pos, int modifier)
{
this.variableName = variableName;
this.variableTypes = variableTypes;
this.scope = scope;
nodeStart = pos;
this.modifier = modifier;
grabDockedTypes();
}
/**
* Gets variable type.
*
* @return variable type.
*/
public Set<Object> getVariableTypes()
{
if (variableTypes != null)
{
return variableTypes;
}
else
{
return Collections.emptySet();
}
}
/**
* Sets variable type.
*
* @param variableType
* - type to set.
*/
public void setVariableType(Object variableType)
{
variableTypes = new HashSet<Object>(1);
variableTypes.add(variableType);
}
/**
* Sets variable types.
*
* @param variableType
*/
public void setVariableTypes(Collection<Object> variableType)
{
variableTypes = new HashSet<Object>();
variableTypes.addAll(variableType);
}
/**
* Adds variable type.
*
* @param variableType
* - type to add.
*/
public void addVariableType(Object variableType)
{
if (variableTypes == null)
{
variableTypes = new HashSet<Object>();
}
variableTypes.add(variableType);
}
/**
* Gets variable name.
*
* @return variable name.
*/
public String getName()
{
return variableName;
}
/**
* Gets scope.
*
* @return scope.
*/
public Scope getScope()
{
return scope;
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append(variableName);
buffer.append(" types:"); //$NON-NLS-1$
buffer.append(variableTypes.toString());
return buffer.toString();
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((variableName == null) ? 0 : variableName.hashCode());
return result;
}
/**
* Gets node start.
*
* @return node start.
*/
public int getNodeStart()
{
return nodeStart;
}
// /**
// * Sets node start.
// * @param nodeStart - node start to set.
// */
// public void setNodeStart(int nodeStart)
// {
// this.nodeStart = nodeStart;
// }
/**
* Gets node modifier.
*
* @return modifier
*/
public int getModifier()
{
return modifier;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final VariableInfo other = (VariableInfo) obj;
if (variableName == null)
{
if (other.variableName != null)
return false;
}
else if (!variableName.equals(other.variableName))
return false;
return true;
}
/**
* Checks if there are any documented types for a variable.
*/
private void grabDockedTypes()
{
PHPDocBlock comment = PHPDocUtils.findPHPDocComment(_comments, this.nodeStart, _contents);
if (comment != null)
{
FunctionDocumentation documentation = PHPDocUtils.getFunctionDocumentation(comment);
if (documentation != null)
{
List<TypedDescription> vars = documentation.getVars();
if (vars != null && vars.size() != 0)
{
if (this.variableTypes == null)
{
variableTypes = new HashSet<Object>();
}
for (TypedDescription descr : vars)
{
String[] types = descr.getTypes();
for (String type : types)
{
variableTypes.add(type);
}
}
}
}
}
}
}
/**
* Variables scope.
*
* @author Denis Denisenko
*/
private static class Scope
{
/**
* Scope root.
*/
private ASTNode root;
/**
* Root entry.
*/
private IElementEntry entry;
/**
* Scope variables.
*/
private Map<String, VariableInfo> variables;
/**
* Scope parent.
*/
private Scope parent;
/**
* Set of variables imported from global scope.
*/
private Set<String> globalImports = new HashSet<String>();
private Map<String, String> aliases = new HashMap<String, String>();
/**
* Scope constructor.
*
* @param root
* - scope root.
* @param parent
* - scope parent.
*/
private Scope(ASTNode root, Scope parent)
{
this.root = root;
this.parent = parent;
this.entry = null;
variables = new HashMap<String, VariableInfo>(1);
}
/**
* Scope constructor.
*
* @param root
* - scope root.
* @param parent
* - scope parent.
* @param entry
* - root entry if exist. null is acceptable.
*/
private Scope(ASTNode root, Scope parent, IElementEntry entry)
{
this.root = root;
this.parent = parent;
this.entry = entry;
variables = new HashMap<String, VariableInfo>(1);
}
/**
* Gets scope global imports.
*
* @return scope golobal imports.
*/
public Set<String> getGlobalImports()
{
return globalImports;
}
/**
* Gets scope global imports.
*
* @return scope golobal imports.
*/
public Map<String, String> getAliases()
{
return aliases;
}
/**
* Adds variables to import from global scope.
*
* @param imports
* - set of imports.
*/
public void addGlobalImports(Set<String> imports)
{
globalImports.addAll(imports);
}
/**
* Adds variable to import from global scope.
*
* @param importVariable
* - name of variable to import.
*/
public void addGlobalImport(String importVariable)
{
globalImports.add(importVariable);
}
/**
* Gets whether this scope is global.
*
* @return true if global, false otherwise.
*/
public boolean isGlobalScope()
{
return root instanceof Program;
}
/**
* Adds variable to the scope. If variable has a type specified and this or parent scopes do contain such a
* variable, current type would be added to the list of variable types.
*
* @param variable
* - variable info.
*/
public void addVariable(VariableInfo variable)
{
VariableInfo existingVariable = getVariable(variable.getName());
if (existingVariable != null)
{
if (variable.getVariableTypes() != null && !variable.getVariableTypes().isEmpty())
{
if (this.equals(existingVariable.getScope()))
{
existingVariable.setVariableTypes(variable.getVariableTypes());
}
else
{
for (Object type : variable.getVariableTypes())
{
existingVariable.addVariableType(type);
}
}
}
}
else
{
variables.put(variable.getName(), variable);
}
}
/**
* Gets variable by name from current scope or nearest of the parent scopes.
*
* @param name
* - variable name.
* @return variable info.
*/
public VariableInfo getVariable(String name)
{
return getVariable(name, new HashSet<String>());
}
/**
* Gets variable by name from current scope or nearest of the parent scopes.
*
* @param name
* - variable name.
* @param importsFromGlobal
* - set of variables that might be imported from global scope. This set will not be modified during
* this call.
* @return variable info.
*/
public VariableInfo getVariable(String name, Set<String> importsFromGlobal)
{
// Copy the given set to avoid any concurrent modification exception in case the caller is calling this one
// in an iteration.
return innerGetVariable(name, new HashSet<String>(importsFromGlobal));
}
private VariableInfo innerGetVariable(String name, Set<String> importsFromGlobal)
{
if (globalImports != null && !globalImports.isEmpty())
{
importsFromGlobal.addAll(globalImports);
}
VariableInfo info = variables.get(name);
if (info != null)
{
return info;
}
if (parent != null)
{
if (parent.isGlobalScope())
{
if (importsFromGlobal.contains(name)
|| !(root instanceof FunctionDeclaration || root instanceof ClassDeclaration))
{
return parent.getVariable(name, importsFromGlobal);
}
}
else
{
return parent.getVariable(name, importsFromGlobal);
}
/*
* if (!parent.isGlobalScope() || importsFromGlobal.contains(name)) { return parent.getVariable(name,
* importsFromGlobal); }
*/
}
return null;
}
/**
* Gets root element entry.
*
* @return rooot element entry.
*/
public IElementEntry getEntry()
{
return entry;
}
/**
* Gets scope root.
*
* @return scope root node.
*/
public ASTNode getRoot()
{
return root;
}
/**
* Gets scope parent scope or null if parent not exist.
*
* @return scope parent.
*/
public Scope getParent()
{
return parent;
}
/**
* Gets unmodifiable variables set including variables from the upper scope being aware of global statement.
*
* @return unmodifiable variables set.
*/
public Set<VariableInfo> getVariables()
{
return getVariables(new HashSet<String>());
}
/**
* Gets variables or nearest of the parent scopes.
*
* @param importsFromGlobal
* - set of variables that might be imported from global scope.
* @return variables.
*/
private Set<VariableInfo> getVariables(Set<String> importsFromGlobal)
{
if (globalImports != null && !globalImports.isEmpty())
{
importsFromGlobal.addAll(globalImports);
}
Set<VariableInfo> result = new HashSet<VariableInfo>();
for (VariableInfo variable : variables.values())
{
result.add(variable);
}
if (parent != null)
{
if (!parent.isGlobalScope())
{
result.addAll(parent.getVariables(importsFromGlobal));
}
else
{
if (automaticallyDeriveGlobalVariables())
{
result.addAll(parent.getVariables(new HashSet<String>()));
}
else
{
for (String var : importsFromGlobal)
{
VariableInfo varInfo = parent.getVariable(var, importsFromGlobal);
if (varInfo != null)
{
result.add(varInfo);
}
}
}
}
}
return result;
}
/**
* Checks whether this node must automatically derive variables from the global scope.
*
* @return true if this node must automatically derive variables from the global scope, false otherwise.
*/
private boolean automaticallyDeriveGlobalVariables()
{
if (!parent.isGlobalScope())
{
return false;
}
if (this.getRoot() instanceof TypeDeclaration || this.getRoot() instanceof FunctionDeclaration
|| this.getRoot() instanceof MethodDeclaration || root instanceof LambdaFunctionDeclaration)
{
return false;
}
return true;
}
}
/**
* Class scope information.
*
* @author Denis Denisenko
*/
private static class ClassScopeInfo
{
/**
* Class entry.
*/
private IElementEntry classEntry;
/**
* Class fields.
*/
private Map<String, IElementEntry> fields = new HashMap<String, IElementEntry>();
/**
* ClassScopeInfo constructor.
*
* @param classEntry
* - class entry.
*/
private ClassScopeInfo(IElementEntry classEntry)
{
this.classEntry = classEntry;
}
/**
* Gets class entry.
*
* @return class entry.
*/
public IElementEntry getClassEntry()
{
return classEntry;
}
/**
* Gets class fields.
*
* @return class fields.
*/
public Collection<IElementEntry> getFields()
{
return fields.values();
}
/**
* Checks whether class has a field with a name specified.
*
* @param fieldName
* - field name to check.
* @return true if has field, false otherwise.
*/
public boolean hasField(String fieldName)
{
return fields.containsKey(fieldName);
}
/**
* Gets field by name.
*
* @param fieldName
* - field name to get.
* @return field entry or null.
*/
public IElementEntry getField(String fieldName)
{
return fields.get(fieldName);
}
/**
* Adds new field.
*
* @param fieldName
* - field name.
* @param field
* - field entry.
*/
public void setField(String fieldName, IElementEntry field)
{
fields.put(fieldName, field);
}
/**
* Adds field types.
*
* @param fieldName
* - field name.
* @param types
* - types to add.
* @return true if types are added, false otherwise.
*/
public boolean addFieldTypes(String fieldName, Set<Object> types)
{
IElementEntry fieldEntry = fields.get(fieldName);
if (fieldEntry == null)
{
return false;
}
Object entryValue = fieldEntry.getValue();
if (!(entryValue instanceof VariablePHPEntryValue))
{
return false;
}
VariablePHPEntryValue value = (VariablePHPEntryValue) entryValue;
for (Object type : types)
{
value.addType(type);
}
return true;
}
}
/**
* AST visitor.
*
* @author Denis Denisenko
*/
private class PHPASTVisitor extends AbstractVisitor
{
/**
* Reporter.
*/
private IIndexReporter reporter;
/**
* Module.
*/
private IModule module;
private String currentNamespace = EMPTY_STRING;
Map<String, String> aliases = new HashMap<String, String>();
/**
* Current class.
*/
private ClassScopeInfo currentClass;
/**
* Current function.
*/
private IElementEntry currentFunction; // FIXME: Shalom - Maintain a stack to handle nested functions?
/**
* Variable scopes.
*/
private Stack<Scope> scopes = new Stack<Scope>();
// /**
// * Backuped variable scopes.
// */
// private Stack<Scope> backupedScopes = new Stack<Scope>();
//
// /**
// * Scopes of the previous node.
// */
// private Stack<Scope> previousNodeScopes = new Stack<Scope>();
/**
* Whether the local stack was reported (required for local mode).
*/
boolean localStackReported = false;
/**
* PHPASTVisitor constructor.
*
* @param reporter
* - reporter to use.
* @param module
* - current module.
*/
private PHPASTVisitor(IIndexReporter reporter, IModule module)
{
this.reporter = reporter;
this.module = module;
}
@Override
public void endVisit(NamespaceDeclaration node)
{
this.endVisitScopeNode(node);
currentNamespace = EMPTY_STRING;
super.endVisit(node);
}
@Override
public boolean visit(NamespaceDeclaration node)
{
StringBuilder nameBuilder = new StringBuilder();
// TODO: Shalom - At the moment we place an empty string for the root namespace. We might want to consider
// using the namespace backslash '\' as the root.
if (node.getName() != null)
{
List<Identifier> segments = node.getName().segments();
int a = 0;
for (Identifier i : segments)
{
nameBuilder.append(i.getName());
a++;
if (a != segments.size())
{
nameBuilder.append('\\');
}
}
}
String name = nameBuilder.toString();
reporter.reportEntry(IPHPIndexConstants.NAMESPACE_CATEGORY, name, new NamespacePHPEntryValue(0, name),
module);
currentNamespace = name;
if (currentOffset == 0 || _namespace == null || currentOffset > node.getStart())
{
_namespace = currentNamespace;
}
this.startVisitScopeNode(node);
return super.visit(node);
}
@Override
public boolean visit(UseStatementPart node)
{
NamespaceName name = node.getName();
// String fullName = name.getFullName();
String fullName = name.getName();
Identifier alias = node.getAlias();
if (alias != null)
{
String aliasName = alias.getName();
// this is alias for class name
aliases.put(aliasName, fullName);
getCurrentScope().aliases.put(aliasName, fullName);
}
else
{
int lastIndexOf = fullName.lastIndexOf('\\');
String aliasName = fullName.substring(lastIndexOf + 1);
aliases.put(aliasName, fullName);
getCurrentScope().aliases.put(aliasName, fullName);
}
return super.visit(node);
}
/*
* (non-Javadoc)
* @see
* org2.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org2.eclipse.php.internal.core.ast.nodes
* .TraitDeclaration)
*/
@Override
public boolean visit(TraitDeclaration traitDeclaration)
{
List<Identifier> interfaces = traitDeclaration.interfaces();
List<String> interfaceNames = new ArrayList<String>(interfaces.size());
for (Identifier interfaceName : interfaces)
{
interfaceNames.add(interfaceName.getName());
}
Expression superClassIdentifier = traitDeclaration.getSuperClass();
String superClassName = null;
if (superClassIdentifier != null
&& (superClassIdentifier.getType() == ASTNode.NAMESPACE_NAME || superClassIdentifier.getType() == ASTNode.IDENTIFIER))
{
superClassName = ((Identifier) superClassIdentifier).getName();
}
TraitPHPEntryValue value = new TraitPHPEntryValue(traitDeclaration.getModifier(), superClassName,
interfaceNames, currentNamespace);
value.setStartOffset(traitDeclaration.getStart());
value.setEndOffset(traitDeclaration.getEnd());
String className = traitDeclaration.getName().getName();
// We keep this Trait as a CLASS_CATEGORY
IElementEntry currentClassEntry = reporter.reportEntry(IPHPIndexConstants.CLASS_CATEGORY, className, value,
module);
currentClass = new ClassScopeInfo(currentClassEntry);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(ClassDeclaration classDeclaration)
{
List<Identifier> interfaces = classDeclaration.interfaces();
List<String> interfaceNames = new ArrayList<String>(interfaces.size());
for (Identifier interfaceName : interfaces)
{
interfaceNames.add(interfaceName.getName());
}
Expression superClassIdentifier = classDeclaration.getSuperClass();
String superClassName = null;
if (superClassIdentifier != null
&& (superClassIdentifier.getType() == ASTNode.NAMESPACE_NAME || superClassIdentifier.getType() == ASTNode.IDENTIFIER))
{
superClassName = ((Identifier) superClassIdentifier).getName();
}
ClassPHPEntryValue value = new ClassPHPEntryValue(classDeclaration.getModifier(), superClassName,
interfaceNames, currentNamespace);
value.setStartOffset(classDeclaration.getStart());
value.setEndOffset(classDeclaration.getEnd());
String className = classDeclaration.getName().getName();
IElementEntry currentClassEntry = reporter.reportEntry(IPHPIndexConstants.CLASS_CATEGORY, className, value,
module);
currentClass = new ClassScopeInfo(currentClassEntry);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(InterfaceDeclaration interfaceDeclaration)
{
int category = IPHPIndexConstants.CLASS_CATEGORY;
List<Identifier> interfaces = interfaceDeclaration.interfaces();
List<String> interfaceNames = new ArrayList<String>(interfaces.size());
for (Identifier interfaceName : interfaces)
{
interfaceNames.add(interfaceName.getName());
}
ClassPHPEntryValue value = new ClassPHPEntryValue(PHPFlags.AccInterface, null, interfaceNames,
currentNamespace);
value.setStartOffset(interfaceDeclaration.getStart());
value.setEndOffset(interfaceDeclaration.getEnd());
IElementEntry currentClassEntry = reporter.reportEntry(category, interfaceDeclaration.getName().getName(),
value, module);
currentClass = new ClassScopeInfo(currentClassEntry);
return true;
}
/**
* Visit a Trait 'use' statement. We want to add those trait items just like we add interfaces to a class
* declaration.
*
* @see org2.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org2.eclipse.php.internal.core.ast.nodes.TraitUseStatement)
*/
@Override
public boolean visit(TraitUseStatement node)
{
List<NamespaceName> traitList = node.getTraitList();
if (!CollectionsUtil.isEmpty(traitList) && currentClass != null && currentClass.getClassEntry() != null
&& currentClass.getClassEntry().getValue() instanceof ClassPHPEntryValue)
{
ClassPHPEntryValue classValue = (ClassPHPEntryValue) currentClass.getClassEntry().getValue();
List<String> traits = new ArrayList<String>(traitList.size());
for (NamespaceName name : traitList)
{
traits.add(name.getName());
}
classValue.setTraits(traits);
}
return super.visit(node);
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(FunctionInvocation functionInvocation)
{
FunctionName funcName = functionInvocation.getFunctionName();
if (funcName == null)
{
return true;
}
Expression functionName = funcName.getName();
if (functionName instanceof Identifier)
{
if (!DEFINE.equals(((Identifier) functionName).getName()))
{
return true;
}
}
if (functionName instanceof Variable)
{
Variable vr = (Variable) functionName;
Expression name = vr.getName();
if (name instanceof Identifier)
{
if (!DEFINE.equals(((Identifier) name).getName()))
{
return true;
}
}
}
List<Expression> parameters = functionInvocation.parameters();
if (parameters.size() < 2)
{
return true;
}
if (parameters.get(0).getType() != ASTNode.SCALAR)
{
return true;
}
if (Scalar.TYPE_STRING != ((Scalar) parameters.get(0)).getScalarType())
{
return true;
}
// getting define name
String defineName = ((Scalar) parameters.get(0)).getStringValue();
if (defineName.startsWith("\"")) //$NON-NLS-1$
{
defineName = defineName.substring(1);
}
if (defineName.endsWith("\"")) //$NON-NLS-1$
{
defineName = defineName.substring(0, defineName.length() - 1);
}
if (defineName.startsWith("\'")) //$NON-NLS-1$;
{
defineName = defineName.substring(1);
}
if (defineName.endsWith("\'")) //$NON-NLS-1$
{
defineName = defineName.substring(0, defineName.length() - 1);
}
Set<Object> defineTypes = countExpressionTypes(parameters.get(1));
if (defineTypes == null)
{
return true;
}
VariableInfo info = new VariableInfo(defineName, defineTypes, getGlobalScope(),
functionInvocation.getStart(), PHPFlags.NAMED_CONSTANT); // TODO - Shalom - Test if Acc_constant is
// not enough here
// (we added the user-defined NAMED_CONSTANT into the PHPFlags)
getGlobalScope().addVariable(info);
VariablePHPEntryValue entryValue = new VariablePHPEntryValue(IPHPModifiers.NAMED_CONSTANT, false, false,
true, defineTypes, functionInvocation.getStart(), currentNamespace);
reporter.reportEntry(IPHPIndexConstants.CONST_CATEGORY, defineName, entryValue, module);
return true;
}
@Override
public boolean visit(FunctionDeclaration functionDeclaration)
{
// methods are handled in other type.
if (functionDeclaration.getParent() != null && functionDeclaration.getParent() instanceof MethodDeclaration)
{
return true;
}
PHPDocBlock comment = PHPDocUtils.findPHPDocComment(_comments, functionDeclaration.getStart(), _contents);
// getting function name
Identifier functionNameIdentifier = functionDeclaration.getFunctionName();
if (functionNameIdentifier == null)
{
return true;
}
String functionName = functionNameIdentifier.getName();
// getting function parameters
List<FormalParameter> parameters = functionDeclaration.formalParameters();
Map<String, Set<Object>> parametersMap = null;
int[] parameterPositions = (parameters == null || parameters.size() == 0) ? null : new int[parameters
.size()];
if (parameters.size() > 0)
{
parametersMap = new LinkedHashMap<String, Set<Object>>(parameters.size());
}
ArrayList<Boolean> mandatoryParams = new ArrayList<Boolean>();
if (parameters != null)
{
int parCount = 0;
for (FormalParameter parameter : parameters)
{
Identifier nameIdentifier = parameter.getParameterNameIdentifier();
if (nameIdentifier == null)
{
continue;
}
String parameterName = nameIdentifier.getName();
parameterPositions[parCount] = parameter.getStart();
String parameterType = null;
Expression parameterTypeIdentifier = parameter.getParameterType();
if (parameterTypeIdentifier != null
&& (parameterTypeIdentifier.getType() == ASTNode.IDENTIFIER || parameterTypeIdentifier
.getType() == ASTNode.NAMESPACE_NAME))
{
parameterType = ((Identifier) parameterTypeIdentifier).getName();
}
Set<Object> types = null;
if (parameterType != null)
{
types = new HashSet<Object>(1);
types.add(parameterType);
}
if (parameter.getDefaultValue() != null)
{
Expression rightPartExpr = parameter.getDefaultValue();
Set<Object> expressionTypes = countExpressionTypes(rightPartExpr);
if (expressionTypes != null && expressionTypes.size() != 0)
{
if (types == null)
{
types = new HashSet<Object>();
types.addAll(expressionTypes);
}
}
}
parametersMap.put(parameterName, types);
mandatoryParams.add(parameter.getDefaultValue() == null || parameter.isMandatory());
parCount++;
}
}
// parsing PHP doc and adding types from it to the parameters
String[] returnTypes = null;
if (comment != null)
{
returnTypes = applyComment(comment, parametersMap);
}
boolean[] mandatories = new boolean[mandatoryParams.size()];
for (int j = 0; j < mandatoryParams.size(); j++)
{
mandatories[j] = mandatoryParams.get(j);
}
FunctionPHPEntryValue entryValue = new FunctionPHPEntryValue(0, false, parametersMap, parameterPositions,
mandatories, functionDeclaration.getStart(), currentNamespace);
if (returnTypes != null)
{
Set<Object> returnTypesSet = new HashSet<Object>();
for (String returnType : returnTypes)
{
returnTypesSet.add(returnType);
}
entryValue.setReturnTypes(returnTypesSet);
}
String entryPath = EMPTY_STRING;
if (currentClass != null && currentClass.getClassEntry() != null)
{
entryPath = currentClass.getClassEntry().getEntryPath() + IElementsIndex.DELIMITER;
}
entryPath += functionName;
currentFunction = reporter.reportEntry(IPHPIndexConstants.FUNCTION_CATEGORY, entryPath, entryValue, module);
return true;
}
/*
* (non-Javadoc)
* @see
* org2.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org2.eclipse.php.internal.core.ast.nodes.
* LambdaFunctionDeclaration)
*/
@Override
public boolean visit(LambdaFunctionDeclaration lambdaFunctionDeclaration)
{
PHPDocBlock comment = PHPDocUtils.findPHPDocComment(_comments, lambdaFunctionDeclaration.getStart(),
_contents);
// Since this is a lambda function, we would like to give it the name of the variable assignment if possible
// getting function parameters
List<FormalParameter> parameters = lambdaFunctionDeclaration.formalParameters();
Map<String, Set<Object>> parametersMap = null;
int[] parameterPositions = (parameters == null || parameters.size() == 0) ? null : new int[parameters
.size()];
if (parameters.size() > 0)
{
parametersMap = new LinkedHashMap<String, Set<Object>>(parameters.size());
}
ArrayList<Boolean> mandatoryParams = new ArrayList<Boolean>();
if (parameters != null)
{
int parCount = 0;
for (FormalParameter parameter : parameters)
{
Identifier nameIdentifier = parameter.getParameterNameIdentifier();
if (nameIdentifier == null)
{
continue;
}
String parameterName = nameIdentifier.getName();
parameterPositions[parCount] = parameter.getStart();
String parameterType = null;
Expression parameterTypeIdentifier = parameter.getParameterType();
if (parameterTypeIdentifier != null
&& (parameterTypeIdentifier.getType() == ASTNode.IDENTIFIER || parameterTypeIdentifier
.getType() == ASTNode.NAMESPACE_NAME))
{
parameterType = ((Identifier) parameterTypeIdentifier).getName();
}
Set<Object> types = null;
if (parameterType != null)
{
types = new HashSet<Object>(1);
types.add(parameterType);
}
if (parameter.getDefaultValue() != null)
{
Expression rightPartExpr = parameter.getDefaultValue();
Set<Object> expressionTypes = countExpressionTypes(rightPartExpr);
if (expressionTypes != null && expressionTypes.size() != 0)
{
if (types == null)
{
types = new HashSet<Object>();
types.addAll(expressionTypes);
}
}
}
parametersMap.put(parameterName, types);
mandatoryParams.add(parameter.getDefaultValue() == null || parameter.isMandatory());
parCount++;
}
}
// parsing PHP doc and adding types from it to the parameters
String[] returnTypes = null;
if (comment != null)
{
returnTypes = applyComment(comment, parametersMap);
}
boolean[] mandatories = new boolean[mandatoryParams.size()];
for (int j = 0; j < mandatoryParams.size(); j++)
{
mandatories[j] = mandatoryParams.get(j);
}
LambdaFunctionPHPEntryValue entryValue = new LambdaFunctionPHPEntryValue(0, parametersMap,
parameterPositions, mandatories, lambdaFunctionDeclaration.getStart(), currentNamespace);
if (returnTypes != null)
{
Set<Object> returnTypesSet = new HashSet<Object>();
for (String returnType : returnTypes)
{
returnTypesSet.add(returnType);
}
entryValue.setReturnTypes(returnTypesSet);
}
String entryPath = EMPTY_STRING;
if (currentClass != null)
{
entryPath = currentClass.getClassEntry().getEntryPath() + IElementsIndex.DELIMITER;
}
// entryPath += functionName;
currentFunction = reporter.reportEntry(IPHPIndexConstants.LAMBDA_FUNCTION_CATEGORY, entryPath, entryValue,
module);
startVisitScopeNode(lambdaFunctionDeclaration);
return true;
}
/*
* (non-Javadoc)
* @see
* org2.eclipse.php.internal.core.ast.visitor.AbstractVisitor#endVisit(org2.eclipse.php.internal.core.ast.nodes
* .LambdaFunctionDeclaration)
*/
@Override
public void endVisit(LambdaFunctionDeclaration lambdaFunctionDeclaration)
{
currentFunction = null;
endVisitScopeNode(lambdaFunctionDeclaration);
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(MethodDeclaration methodDeclaration)
{
PHPDocBlock comment = PHPDocUtils.findPHPDocComment(_comments, methodDeclaration.getStart(), _contents);
FunctionDeclaration functionDeclaration = methodDeclaration.getFunction();
if (functionDeclaration == null)
{
return true;
}
// getting function name
Identifier functionNameIdentifier = functionDeclaration.getFunctionName();
if (functionNameIdentifier == null)
{
return true;
}
String functionName = functionNameIdentifier.getName();
// getting function parameters
List<FormalParameter> parameters = functionDeclaration.formalParameters();
int[] parameterPositions = (parameters == null || parameters.size() == 0) ? null : new int[parameters
.size()];
Map<String, Set<Object>> parametersMap = null;
if (parameters.size() > 0)
{
parametersMap = new LinkedHashMap<String, Set<Object>>(parameters.size());
}
ArrayList<Boolean> mandatoryParams = new ArrayList<Boolean>();
if (parameters != null)
{
int parCount = 0;
for (FormalParameter parameter : parameters)
{
Identifier nameIdentifier = parameter.getParameterNameIdentifier();
if (nameIdentifier == null)
{
continue;
}
String parameterName = nameIdentifier.getName();
parameterPositions[parCount] = parameter.getStart();
String parameterType = null;
Expression parameterTypeIdentifier = parameter.getParameterType();
if (parameterTypeIdentifier != null
&& (parameterTypeIdentifier.getType() == ASTNode.NAMESPACE_NAME || parameterTypeIdentifier
.getType() == ASTNode.IDENTIFIER))
{
parameterType = ((Identifier) parameterTypeIdentifier).getName();
}
Set<Object> types = null;
if (parameterType != null)
{
types = new HashSet<Object>(1);
types.add(parameterType);
}
parametersMap.put(parameterName, types);
mandatoryParams.add(parameter.getDefaultValue() == null || parameter.isMandatory());
parCount++;
}
}
// parsing PHP doc and adding types from it to the parameters
String[] returnTypes = null;
if (comment != null)
{
returnTypes = applyComment(comment, parametersMap);
}
int modifier = methodDeclaration.getModifier();
// if access modifier is unspecified, making it public.
if (!PHPFlags.isPublic(modifier) && !PHPFlags.isProtected(modifier) && !PHPFlags.isPrivate(modifier))
{
modifier |= PHPFlags.AccPublic;
}
boolean[] mandatories = new boolean[mandatoryParams.size()];
for (int j = 0; j < mandatoryParams.size(); j++)
{
mandatories[j] = mandatoryParams.get(j);
}
FunctionPHPEntryValue entryValue = new FunctionPHPEntryValue(modifier, true, parametersMap,
parameterPositions, mandatories, methodDeclaration.getStart(), currentNamespace);
if (returnTypes != null)
{
Set<Object> returnTypesSet = new HashSet<Object>();
for (String returnType : returnTypes)
{
returnTypesSet.add(returnType);
}
entryValue.setReturnTypes(returnTypesSet);
}
String entryPath = EMPTY_STRING;
if (currentClass != null && currentClass.getClassEntry() != null)
{
IElementEntry classEntry = currentClass.getClassEntry();
entryPath = classEntry.getEntryPath() + IElementsIndex.DELIMITER;
if (classEntry.getValue() instanceof TraitPHPEntryValue)
{
// Mark this method as a trait method.
entryValue.setIsTraitMethod(true);
}
}
entryPath += functionName;
currentFunction = reporter.reportEntry(IPHPIndexConstants.FUNCTION_CATEGORY, entryPath, entryValue, module);
// backuping old scopes
// backupedScopes = scopes;
// scopes = new Stack<Scope>();
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(Variable variable)
{
ASTNode parent = variable.getParent();
// handling variables assigned to some expression
if (parent instanceof Assignment)
{
Assignment assignment = (Assignment) parent;
if (variable.equals(assignment.getLeftHandSide()))
{
boolean staticDeclaration = parent.getParent() instanceof StaticStatement;
return handleAssigment(variable, assignment, staticDeclaration);
}
}
// handling simple variable definitions
else if (parent instanceof ExpressionStatement)
{
String variableName = getVariableName(variable);
if (variableName == null)
{
return true;
}
VariableInfo variableInfo = new VariableInfo(variableName, null, getCurrentScope(), variable.getStart());
getCurrentScope().addVariable(variableInfo);
}
// handling infix expressions, variable might take part in
else if (parent instanceof InfixExpression)
{
String variableName = getVariableName(variable);
if (variableName == null)
{
return true;
}
InfixExpression expr = (InfixExpression) parent;
Set<Object> types = countInfixExpressionTypes(expr);
VariableInfo variableInfo = new VariableInfo(variableName, types, getCurrentScope(),
variable.getStart());
getCurrentScope().addVariable(variableInfo);
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(StaticFieldAccess fieldAccess)
{
if (currentClass == null)
{
return true;
}
if (fieldAccess.getParent() == null || !(fieldAccess.getParent() instanceof Assignment))
{
return true;
}
Expression className = fieldAccess.getClassName();
if (className == null
|| (className.getType() == ASTNode.IDENTIFIER && !SELF.equals(((Identifier) className).getName())))
{
return true;
}
String fieldName = getVariableName(fieldAccess.getField());
if (fieldName == null)
{
return true;
}
Expression value = ((Assignment) fieldAccess.getParent()).getRightHandSide();
Set<Object> valueTypes = countExpressionTypes(value);
if (valueTypes != null && valueTypes.size() > 0)
{
if (currentClass.hasField(fieldName))
{
currentClass.addFieldTypes(fieldName, valueTypes);
}
else
{
reportField(PHPFlags.AccPublic | PHPFlags.AccStatic, fieldName, valueTypes, fieldAccess.getStart());
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(ConstantDeclaration constantDeclaration)
{
if (currentClass == null)
{
return true;
}
List<Identifier> variableNames = constantDeclaration.names();
List<Expression> values = constantDeclaration.initializers();
for (int i = 0; i < variableNames.size(); i++)
{
String variableName = variableNames.get(i).getName();
Expression value = values.get(i);
Set<Object> valueTypes = countExpressionTypes(value);
if (valueTypes != null && valueTypes.size() > 0)
{
// if (currentClass.hasField(variableName))
// {
// currentClass.addFieldTypes(variableName, valueTypes);
// }
// else
// {
reportClassConst(PHPFlags.AccPublic, variableName, valueTypes, constantDeclaration.getStart());
// }
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(FieldAccess fieldAccess)
{
if (fieldAccess == null)
{
return false;
}
if (currentClass == null)
{
return true;
}
if (fieldAccess.getParent() == null || !(fieldAccess.getParent() instanceof Assignment))
{
return true;
}
if (fieldAccess != ((Assignment) fieldAccess.getParent()).getLeftHandSide())
{
return true;
}
VariableBase leftSide = fieldAccess.getDispatcher();
if (!(leftSide instanceof Variable))
{
return true;
}
String variableName = getVariableName((Variable) leftSide);
if (variableName == null || !THIS.equals(variableName))
{
return true;
}
VariableBase rightSide = fieldAccess.getMember();
if (!(rightSide instanceof Variable))
{
return true;
}
String fieldName = getVariableName((Variable) rightSide);
if (fieldName == null)
{
return true;
}
Expression value = ((Assignment) fieldAccess.getParent()).getRightHandSide();
Set<Object> valueTypes = countExpressionTypes(value);
if (valueTypes != null && valueTypes.size() > 0)
{
if (currentClass.hasField(fieldName))
{
currentClass.addFieldTypes(fieldName, valueTypes);
}
else
{
reportField(PHPFlags.AccPublic, fieldName, valueTypes, fieldAccess.getStart());
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(FieldsDeclaration fieldsDeclaration)
{
Variable[] variables = fieldsDeclaration.getVariableNames();
Expression[] initialValues = fieldsDeclaration.getInitialValues();
int modifier = fieldsDeclaration.getModifier();
// if access modifier is unspecified, making it public.
if (!PHPFlags.isPublic(modifier) && !PHPFlags.isProtected(modifier) && !PHPFlags.isPrivate(modifier))
{
modifier |= PHPFlags.AccPublic;
}
for (int i = 0; i < variables.length; i++)
{
Variable fieldVariable = variables[i];
Expression initialValue = initialValues[i];
String fieldName = getVariableName(fieldVariable);
if (fieldName == null)
{
continue;
}
Set<Object> fieldTypes = null;
if (initialValue != null)
{
fieldTypes = countExpressionTypes(initialValue);
}
PHPDocBlock comment = PHPDocUtils.findPHPDocComment(_comments, fieldsDeclaration.getStart(), _contents);
if (comment != null)
{
FunctionDocumentation documentation = PHPDocUtils.getFunctionDocumentation(comment);
if (documentation != null)
{
List<TypedDescription> vars = documentation.getVars();
if (vars != null && vars.size() != 0)
{
if (fieldTypes == null)
{
fieldTypes = new HashSet<Object>();
}
for (TypedDescription descr : vars)
{
String[] types = descr.getTypes();
for (String type : types)
{
fieldTypes.add(type.trim());
}
}
}
}
}
reportField(modifier, fieldName, fieldTypes, fieldVariable.getStart());
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(GlobalStatement globalStatement)
{
List<Variable> variables = globalStatement.variables();
Set<String> imports = new HashSet<String>();
for (Variable variable : variables)
{
String varName = getVariableName(variable);
if (varName != null)
{
imports.add(varName);
getGlobalScope().addVariable(
new VariableInfo(varName, null, getGlobalScope(), globalStatement.getStart()));
}
}
getCurrentScope().addGlobalImports(imports);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(ReturnStatement returnStatement)
{
// ignoring out of function returns
if (currentFunction == null)
{
return true;
}
Expression expression = returnStatement.getExpression();
Set<Object> types = countExpressionTypes(expression);
if (!(currentFunction.getValue() instanceof FunctionPHPEntryValue))
{
return true;
}
FunctionPHPEntryValue value = (FunctionPHPEntryValue) currentFunction.getValue();
if (types != null)
{
Set<Object> currentTypes = value.getReturnTypes();
if (currentTypes == null || currentTypes.size() == 0)
{
currentTypes = new HashSet<Object>();
}
currentTypes.addAll(types);
value.setReturnTypes(currentTypes);
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(ClassDeclaration classDeclaration)
{
currentClass = null;
}
/*
* (non-Javadoc)
* @see
* org2.eclipse.php.internal.core.ast.visitor.AbstractVisitor#endVisit(org2.eclipse.php.internal.core.ast.nodes
* .InterfaceDeclaration)
*/
@Override
public void endVisit(InterfaceDeclaration interfaceDeclaration)
{
currentClass = null;
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(FunctionDeclaration functionDeclaration)
{
currentFunction = null;
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(MethodDeclaration methodDeclaration)
{
// restoring backuped scopes
// scopes = backupedScopes;
currentFunction = null;
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(Program program)
{
endVisitScopeNode(program);
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(Program program)
{
startVisitScopeNode(program);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(Block block)
{
if (block.getParent() instanceof NamespaceDeclaration)
{
return true;
}
startVisitScopeNode(block.getParent());
addBlockVariables(block);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(CatchClause catchClause)
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(DoStatement doStatement)
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(ForEachStatement forEachStatement)
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(ForStatement forStatement)
{
startVisitScopeNode(forStatement);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(IfStatement ifStatement)
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(SwitchStatement switchStatement)
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(TryStatement tryStatement)
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(WhileStatement whileStatement)
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean visit(Include include)
{
Expression expr = include.getExpression();
if (expr != null && (expr.getType() == ASTNode.PARENTHESIS_EXPRESSION || expr.getType() == ASTNode.SCALAR))
{
Expression subExpr = null;
if (expr instanceof Scalar)
{
subExpr = expr;
}
else
{
subExpr = ((ParenthesisExpression) expr).getExpression();
}
if (subExpr == null)
{
return true;
}
String includePath = null;
int type = subExpr.getType();
if (type == ASTNode.SCALAR)
{
includePath = ((Scalar) subExpr).getStringValue();
}
else if (type == ASTNode.INFIX_EXPRESSION)
{
// This expression may contain nested infix-expressions, so we just grab the text directly.
try
{
includePath = PDTPHPModuleIndexer.this._contents
.substring(subExpr.getStart(), subExpr.getEnd());
}
catch (Exception e)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"A problem while visiting an include statement", e); //$NON-NLS-1$
}
}
if (includePath != null)
{
if (includePath == null || includePath.length() == 0)
{
return true;
}
int pathStartOffset = subExpr.getStart();
if (includePath.startsWith("\"") || includePath.startsWith("'")) //$NON-NLS-1$ //$NON-NLS-2$
{
includePath = includePath.substring(1);
pathStartOffset++;
}
if (includePath.endsWith("\"") || includePath.endsWith("'")) //$NON-NLS-1$ //$NON-NLS-2$
{
includePath = includePath.substring(0, includePath.length() - 1);
}
int pdtIncludeType = include.getIncludeType();
int includeType = -1;
switch (pdtIncludeType)
{
case Include.IT_INCLUDE:
includeType = IncludePHPEntryValue.INCLUDE_TYPE;
break;
case Include.IT_INCLUDE_ONCE:
includeType = IncludePHPEntryValue.INCLUDE_ONCE_TYPE;
break;
case Include.IT_REQUIRE:
includeType = IncludePHPEntryValue.REQUIRE_TYPE;
break;
case Include.IT_REQUIRE_ONCE:
includeType = IncludePHPEntryValue.REQUIRE_ONCE_TYPE;
break;
}
IncludePHPEntryValue value = new IncludePHPEntryValue(includePath, include.getStart(),
include.getEnd(), pathStartOffset, includeType);
reporter.reportEntry(IPHPIndexConstants.IMPORT_CATEGORY, EMPTY_STRING, value, module);
}
}
return true;
}
// ///
/**
* {@inheritDoc}
*/
@Override
public void endVisit(Block block)
{
if (block.getParent() instanceof NamespaceDeclaration)
{
return;
}
endVisitScopeNode(block);
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(CatchClause catchClause)
{
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(DoStatement doStatement)
{
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(ForEachStatement forEachStatement)
{
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(ForStatement forStatement)
{
endVisitScopeNode(forStatement);
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(IfStatement ifStatement)
{
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(SwitchStatement switchStatement)
{
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(TryStatement tryStatement)
{
}
/**
* {@inheritDoc}
*/
@Override
public void endVisit(WhileStatement whileStatement)
{
}
/**
* Handles variable assignment.
*
* @param variable
* - variable.
* @param assigment
* - assignment node.
* @return
*/
private boolean handleAssigment(Variable variable, Assignment assigment, boolean staticDeclaration)
{
Expression value = assigment.getRightHandSide();
String variableName = getVariableName(variable);
if (variableName == null)
{
return true;
}
Set<Object> rightSideTypes = countExpressionTypes(value);
VariableInfo variableInfo = new VariableInfo(variableName, rightSideTypes, getCurrentScope(),
variable.getStart(), staticDeclaration ? PHPFlags.AccStatic : 0);
getCurrentScope().addVariable(variableInfo);
return true;
}
/**
* Gets variable entry path.
*
* @param variable
* - variable.
* @return entry path.
*/
String getVariableEntryPath(Variable variable)
{
String entryPath = EMPTY_STRING;
if (currentFunction != null)
{
entryPath = currentFunction.getEntryPath() + IElementsIndex.DELIMITER;
}
else if (currentClass != null)
{
entryPath = currentClass.getClassEntry().getEntryPath() + IElementsIndex.DELIMITER;
}
String varName = getVariableName(variable);
if (varName == null)
{
return null;
}
entryPath += varName;
return entryPath;
}
/**
* Gets variable name.
*
* @param variable
* - variable.
* @return variable name.
*/
private String getVariableName(Expression variable)
{
if (variable == null)
{
return null;
}
if (variable.getType() == ASTNode.VARIABLE)
{
variable = ((Variable) variable).getName();
}
if (variable.getType() == ASTNode.IDENTIFIER)
{
return ((Identifier) variable).getName();
}
return null;
}
/**
* Handles the start of visiting the node that provides variables scope.
*
* @param node
* - node.
*/
private void startVisitScopeNode(ASTNode node)
{
Scope parent = null;
if (!scopes.isEmpty())
{
parent = scopes.peek();
}
IElementEntry currentEntry = null;
if (node instanceof FunctionDeclaration || node instanceof LambdaFunctionDeclaration)
{
currentEntry = currentFunction;
}
else if (node instanceof ClassDeclaration)
{
currentEntry = currentClass.getClassEntry();
}
Scope scope = new Scope(node, parent, currentEntry);
scopes.push(scope);
// report any @var comment variables that exists under that node
if (_resolvedVarComments != null && _resolvedVarComments.get(node) != null)
{
for (VarComment comment : _resolvedVarComments.get(node))
{
String variableName = comment.getVariableReference().getName();
if (variableName.startsWith(DOLLAR_SIGN))
{
variableName = variableName.substring(1);
}
VariableInfo variableInfo = new VariableInfo(variableName, comment.getTypeReferencesNames(), scope,
comment.getStart(), 0);
getCurrentScope().addVariable(variableInfo);
}
}
}
/**
* Handles the end of visiting the node that provides variables scope.
*
* @param node
* - node.
*/
private void endVisitScopeNode(ASTNode node)
{
if (!scopes.isEmpty())
{
// if local mode is on and we did not report the local stack
// yet,
// backuping the stack.
if (!globalMode && !localStackReported)
{
if (node.getEnd() > currentOffset)
{
reportStack(scopes);
localStackReported = true;
}
}
Scope scope = scopes.pop();
reportGlobalScopeVariables(scope);
}
}
/**
* Gets current scope. Should never be null.
*
* @return current scope.
*/
private Scope getCurrentScope()
{
return scopes.peek();
}
/**
* Gets current scope. Should never be null.
*
* @return current scope.
*/
private Scope getGlobalScope()
{
return scopes.get(0);
}
/**
* Reports global scope variables.
*
* @param scope
* - scope, which variables to report.
*/
private void reportGlobalScopeVariables(Scope scope)
{
int rootType = scope.getRoot().getType();
if (globalMode || rootType == ASTNode.NAMESPACE)
{
if (rootType == ASTNode.PROGRAM || rootType == ASTNode.NAMESPACE)
{
for (VariableInfo info : scope.getVariables())
{
VariablePHPEntryValue entryValue = new VariablePHPEntryValue(0, false, false, false,
info.getVariableTypes(), info.getNodeStart(), currentNamespace);
String entryPath = info.getName();
int category = PHPFlags.isNamedConstant(info.getModifier()) ? IPHPIndexConstants.CONST_CATEGORY
: IPHPIndexConstants.VAR_CATEGORY;
reporter.reportEntry(category, entryPath, entryValue, module);
}
}
}
}
/**
* Count variables types by name and scope.
*
* @param variableName
* - variable name.
* @param currentScope
* - current scope.
* @return
*/
private Set<Object> countVariableTypes(String variableName, Scope currentScope)
{
Set<Object> result = new HashSet<Object>();
// checking for variable with this name.
VariableInfo variable = currentScope.getVariable(variableName);
if (variable != null)
{
result.addAll(variable.getVariableTypes());
}
// checking for function or method parameter with this name
IElementEntry entry = findFunctionOrMethodParent(currentScope);
if (entry != null)
{
FunctionPHPEntryValue entryValue = (FunctionPHPEntryValue) entry.getValue();
Map<String, Set<Object>> parameters = entryValue.getParameters();
if (parameters != null)
{
Set<Object> types = parameters.get(variableName);
if (types != null)
{
result.addAll(types);
}
}
}
return result;
}
/**
* Finds function or method parent scope and returns its element entry.
*
* @param scope
* - current scope.
* @return entry or null if not found.
*/
private IElementEntry findFunctionOrMethodParent(Scope scope)
{
Scope currentScope = scope;
while (currentScope != null)
{
IElementEntry entry = currentScope.getEntry();
if (entry != null)
{
if (entry.getValue() instanceof FunctionPHPEntryValue)
{
return entry;
}
}
currentScope = currentScope.getParent();
}
return null;
}
/**
* Counts infix expression types.
*
* @param expr
* - expression.
* @return expression type or null if undefined
*/
private Set<Object> countInfixExpressionTypes(InfixExpression expr)
{
int operator = expr.getOperator();
String type = null;
switch (operator)
{
case InfixExpression.OP_CONCAT:
type = IPHPIndexConstants.STRING_TYPE;
break;
case InfixExpression.OP_IS_IDENTICAL:
case InfixExpression.OP_IS_NOT_IDENTICAL:
case InfixExpression.OP_IS_EQUAL:
case InfixExpression.OP_IS_NOT_EQUAL:
case InfixExpression.OP_RGREATER:
case InfixExpression.OP_IS_SMALLER_OR_EQUAL:
case InfixExpression.OP_LGREATER:
case InfixExpression.OP_IS_GREATER_OR_EQUAL:
case InfixExpression.OP_BOOL_OR:
type = IPHPIndexConstants.BOOLEAN_TYPE;
break;
case InfixExpression.OP_STRING_OR:
case InfixExpression.OP_STRING_AND:
case InfixExpression.OP_STRING_XOR:
type = IPHPIndexConstants.STRING_TYPE;
break;
case InfixExpression.OP_PLUS:
case InfixExpression.OP_MINUS:
case InfixExpression.OP_MUL:
case InfixExpression.OP_DIV:
case InfixExpression.OP_MOD:
type = IPHPIndexConstants.REAL_TYPE;
break;
case InfixExpression.OP_SL:
case InfixExpression.OP_SR:
type = IPHPIndexConstants.INTEGER_TYPE;
break;
}
Set<Object> result = new HashSet<Object>(1);
result.add(type);
return result;
}
/**
* Converts static access to the plain path. In example ClassName::$b would be [ClassName,b] path.
*
* @param dispatch
* - dispatch.
* @return path or null indicating parsing failure
*/
private CallPath getPathByStaticDispatch(StaticDispatch dispatch)
{
CallPath result = new CallPath();
// counting first path entry
Expression classNameIdentifier = dispatch.getClassName();
if (classNameIdentifier == null
|| (classNameIdentifier.getType() != ASTNode.IDENTIFIER
&& classNameIdentifier.getType() != ASTNode.NAMESPACE_NAME && classNameIdentifier.getType() != ASTNode.VARIABLE))
{
IdeLog.logError(PHPEditorPlugin.getDefault(),
"Expected an identifier, variable or namespace-name", new Exception("Missing identifier")); //$NON-NLS-1$ //$NON-NLS-2$
return null;
}
String className = null;
if (classNameIdentifier.getType() == ASTNode.VARIABLE)
{
className = getVariableName(((Variable) classNameIdentifier));
}
else
{
className = ((Identifier) classNameIdentifier).getName();
}
result.setClassEntry(className);
// counting second entry
ASTNode member = dispatch.getMember();
// getting member name and type
String memberName = null;
boolean field = true;
if (member instanceof Variable)
{
Variable currentField = (Variable) member;
memberName = getVariableName(currentField);
if (memberName == null)
{
return null;
}
field = true;
}
else if (member instanceof FunctionInvocation)
{
FunctionInvocation funcInvocation = (FunctionInvocation) member;
memberName = getFunctionNameByInvocation(funcInvocation);
if (memberName == null)
{
return null;
}
field = false;
}
else
{
return null;
}
// inserting member to the path
if (field)
{
result.addVariableEntry(memberName);
}
else
{
result.addMethodEntry(memberName);
}
return result;
}
/**
* Converts field access to the plain path. In example $a->$b->$method() would be [a,b,method] path.
*
* @param dispatch
* - dispatch.
* @return path or null indicating parsing failure
*/
private CallPath getPathByDispatch(Dispatch dispatch)
{
CallPath result = new CallPath();
Dispatch currentDispatch = dispatch;
while (currentDispatch != null)
{
VariableBase currentDispatcher = currentDispatch.getDispatcher();
// getting member name and type
String memberName = null;
boolean field = true;
VariableBase member = currentDispatch.getMember();
if (member instanceof Variable)
{
Variable currentField = (Variable) member;
memberName = getVariableName(currentField);
if (memberName == null)
{
return null;
}
field = true;
}
else if (member instanceof FunctionInvocation)
{
FunctionInvocation funcInvocation = (FunctionInvocation) member;
memberName = getFunctionNameByInvocation(funcInvocation);
if (memberName == null)
{
return null;
}
field = false;
}
else
{
return null;
}
// inserting member to the path
if (field)
{
result.insertVariableEntry(memberName);
}
else
{
result.insertMethodEntry(memberName);
}
// if left side is still the dispatch, continue to parse it
if (currentDispatcher instanceof Dispatch)
{
currentDispatch = (Dispatch) currentDispatcher;
}
else if (currentDispatcher instanceof StaticDispatch)
{
// getting the path of the static dispatch
CallPath staticDispatchCallPath = getPathByStaticDispatch((StaticDispatch) currentDispatcher);
if (staticDispatchCallPath == null)
{
return null;
}
// adding current path to the static dispatch type
staticDispatchCallPath.addPath(result);
return staticDispatchCallPath;
}
else if (currentDispatcher instanceof Variable)
{
// if left side is variable, inserting it and stopping
// parsing
String dispatecherName = getVariableName((Variable) currentDispatcher);
if (dispatecherName == null)
{
return null;
}
result.insertVariableEntry(dispatecherName);
break;
}
else if (currentDispatcher instanceof FunctionInvocation)
{
// if left side is method, inserting it and stopping parsing
String dispatecherName = getFunctionNameByInvocation((FunctionInvocation) currentDispatcher);
if (dispatecherName == null)
{
return null;
}
result.insertMethodEntry(dispatecherName);
break;
}
else
{
// unrecognized construction
return null;
}
}
return result;
}
/**
* Counts the all possible types of expression.
*
* @param expression
* - expression to count.
* @return types set or null if expression types cannot be counted.
*/
private Set<Object> countExpressionTypes(Expression expression)
{
Set<Object> result = null;
// handling scalar values
if (expression instanceof Quote)
{
if (((Quote) expression).getQuoteType() == Quote.QT_HEREDOC)
{
result = new HashSet<Object>();
result.add(IPHPIndexConstants.STRING_TYPE);
}
}
if (expression instanceof LambdaFunctionDeclaration)
{
result = new HashSet<Object>(1);
StringBuilder type = new StringBuilder();
type.append(IPHPIndexConstants.LAMBDA_TYPE);
type.append('(');
LambdaFunctionDeclaration lf = (LambdaFunctionDeclaration) expression;
List<FormalParameter> formalParameters = lf.formalParameters();
int i = 0;
for (FormalParameter p : formalParameters)
{
Expression parameterName = p.getParameterName();
if (parameterName != null
&& (parameterName.getType() == ASTNode.IDENTIFIER || parameterName.getType() == ASTNode.NAMESPACE_NAME))
{
String name = ((Identifier) parameterName).getName();
if (name.startsWith(DOLLAR_SIGN))
{
type.append(name.substring(1));
i++;
if (i != formalParameters.size())
{
type.append(',');
}
}
}
}
type.append(')');
result.add(type.toString());
return result;
}
if (expression instanceof UnaryOperation)
{
UnaryOperation unaryOperation = (UnaryOperation) expression;
expression = unaryOperation.getExpression();
}
if (expression instanceof Scalar)
{
Scalar scalar = (Scalar) expression;
result = countScalarTypes(scalar);
}
// handling variable values
else if (expression instanceof Variable)
{
Variable rightSideVar = (Variable) expression;
String rightSideVarName = getVariableName(rightSideVar);
if (rightSideVarName == null)
{
return null;
}
result = countVariableTypes(rightSideVarName, getCurrentScope());
}
// handling instance creation
else if (expression instanceof ClassInstanceCreation)
{
ClassInstanceCreation creation = (ClassInstanceCreation) expression;
result = countInstanceCreationTypes(creation);
}
// handling call paths
else if (expression instanceof FieldAccess || expression instanceof MethodInvocation)
{
Dispatch dispatch = (Dispatch) expression;
result = countDispatchTypes(dispatch);
}
else if (expression instanceof StaticDispatch)
{
StaticDispatch staticDispatch = (StaticDispatch) expression;
result = countStaticDispatchTypes(staticDispatch);
}
// handling function invocation
else if (expression instanceof FunctionInvocation)
{
FunctionInvocation invocation = (FunctionInvocation) expression;
result = countFunctionInvocationTypes(invocation);
}
// handling infix expressions
else if (expression instanceof InfixExpression)
{
InfixExpression infix = (InfixExpression) expression;
result = countInfixExpressionTypes(infix);
}
return result;
}
/**
* Counts function invocation types.
*
* @param invocation
* - invocation.
* @return set of types or null if cannot count.
*/
private Set<Object> countFunctionInvocationTypes(FunctionInvocation invocation)
{
String functionName = getFunctionNameByInvocation(invocation);
if (functionName == null)
{
return null;
}
FunctionPathReference reference = new FunctionPathReference(functionName, null);
Set<Object> result = new HashSet<Object>(1);
result.add(reference);
return result;
}
/**
* Counts scalar expression types.
*
* @param scalar
* - scalar.
* @return set of types or null if cannot count.
*/
private Set<Object> countScalarTypes(Scalar scalar)
{
Set<Object> result;
int intType = scalar.getScalarType();
String type = typeToString(intType);
result = new HashSet<Object>(1);
result.add(type);
return result;
}
/**
* Counts class instance creation expression types.
*
* @param creation
* - instance creation.
* @return set of types or null if cannot count.
*/
private Set<Object> countInstanceCreationTypes(ClassInstanceCreation creation)
{
ClassName className = creation.getClassName();
if (className == null)
{
return null;
}
Expression classNameExpr = className.getName();
if (classNameExpr == null
|| !((classNameExpr instanceof Identifier) || (classNameExpr instanceof NamespaceName)))
{
return null;
}
String clName = null;
if (classNameExpr instanceof Identifier)
{
clName = ((Identifier) classNameExpr).getName();
String string = aliases.get(clName);
if (string != null)
{
clName = string;
}
if (currentNamespace != null && currentNamespace.length() > 0)
{
clName = currentNamespace + '\\' + clName;
}
}
else if (classNameExpr instanceof NamespaceName)
{
NamespaceName na = (NamespaceName) classNameExpr;
if (na.isGlobal())
{
clName = na.getName();
}
else if (na.isCurrent())
{
if (currentNamespace != null && currentNamespace.length() > 0)
{
clName = currentNamespace + '\\' + na.getName();
}
}
else
{
Identifier identifier = na.segments().get(0);
String name = identifier.getName();
String alias = aliases.get(name);
if (alias != null)
{
clName = na.getName();
clName = alias + clName.substring(name.length());
}
else
{
clName = currentNamespace + '\\' + na.getName();
}
}
}
if (clName == null)
{
return null;
}
Set<Object> result = new HashSet<Object>(1);
if (SELF.equals(clName))
{
if (currentClass != null && currentClass.getClassEntry() != null)
{
result.add(currentClass.getClassEntry().getEntryPath());
return result;
}
return null;
}
result.add(clName);
return result;
}
/**
* Counts dispatch expression types.
*
* @param dispatch
* - dispatch.
* @return types set or null if cannot count.
*/
private Set<Object> countStaticDispatchTypes(StaticDispatch dispatch)
{
Set<Object> result = null;
CallPath path = getPathByStaticDispatch(dispatch);
if (path == null || path.getSize() < 2)
{
return null;
}
CallPath remainingPath = path.subPath(1);
List<CallPath.Entry> pathEntries = path.getEntries();
CallPath.Entry dispatchEntry = pathEntries.get(0);
// handling "self::"
if (dispatchEntry instanceof CallPath.ClassEntry && SELF.equals(dispatchEntry.getName()))
{
if (currentClass != null)
{
Set<Object> dispatcherTypes = new HashSet<Object>(1);
IElementEntry classEntry = currentClass.getClassEntry();
if (classEntry != null)
{
dispatcherTypes.add(ElementsIndexingUtils.getFirstNameInPath(classEntry.getEntryPath()));
StaticPathReference reference = new StaticPathReference(dispatcherTypes, remainingPath);
result = new HashSet<Object>(1);
result.add(reference);
}
}
else
{
return null;
}
}
// handling "ClassName::"
else if (dispatchEntry instanceof CallPath.ClassEntry)
{
Set<Object> dispatcherTypes = new HashSet<Object>(1);
dispatcherTypes.add(dispatchEntry.getName());
StaticPathReference reference = new StaticPathReference(dispatcherTypes, remainingPath);
result = new HashSet<Object>(1);
result.add(reference);
}
else
{
return null;
}
return result;
}
/**
* Counts dispatch expression types.
*
* @param dispatch
* - dispatch.
* @return types set or null if cannot count.
*/
private Set<Object> countDispatchTypes(Dispatch dispatch)
{
Set<Object> result = null;
CallPath path = getPathByDispatch(dispatch);
if (path == null || path.getSize() < 2)
{
return null;
}
CallPath remainingPath = path.subPath(1);
List<CallPath.Entry> pathEntries = path.getEntries();
CallPath.Entry dispatchEntry = pathEntries.get(0);
// handling "this->"
if (dispatchEntry instanceof CallPath.VariableEntry && THIS.equals(dispatchEntry.getName()))
{
if (currentClass != null)
{
Set<Object> dispatcherTypes = new HashSet<Object>(1);
IElementEntry classEntry = currentClass.getClassEntry();
if (classEntry != null)
{
dispatcherTypes.add(ElementsIndexingUtils.getFirstNameInPath(classEntry.getEntryPath()));
VariablePathReference reference = new VariablePathReference(dispatcherTypes, remainingPath);
result = new HashSet<Object>(1);
result.add(reference);
}
}
else
{
return null;
}
}
// handling "self::"
else if (dispatchEntry instanceof CallPath.ClassEntry && SELF.equals(dispatchEntry.getName()))
{
if (currentClass != null && currentClass.getClassEntry() != null)
{
Set<Object> dispatcherTypes = new HashSet<Object>(1);
dispatcherTypes.add(ElementsIndexingUtils.getFirstNameInPath(currentClass.getClassEntry()
.getEntryPath()));
StaticPathReference reference = new StaticPathReference(dispatcherTypes, remainingPath);
result = new HashSet<Object>(1);
result.add(reference);
}
else
{
return null;
}
}
// handling "ClassName::"
else if (dispatchEntry instanceof CallPath.ClassEntry)
{
Set<Object> dispatcherTypes = new HashSet<Object>(1);
dispatcherTypes.add(dispatchEntry.getName());
StaticPathReference reference = new StaticPathReference(dispatcherTypes, remainingPath);
result = new HashSet<Object>(1);
result.add(reference);
}
// handling "$var->"
else if (dispatchEntry instanceof CallPath.VariableEntry)
{
Set<Object> dispatcherTypes = countVariableTypes(dispatchEntry.getName(), getCurrentScope());
if (dispatcherTypes == null)
{
return null;
}
VariablePathReference reference = new VariablePathReference(dispatcherTypes, remainingPath);
result = new HashSet<Object>(1);
result.add(reference);
}
// handling "method()->"
else if (dispatchEntry instanceof CallPath.MethodEntry)
{
String methodEntryPath = ((CallPath.MethodEntry) dispatchEntry).getName();
FunctionPathReference reference = new FunctionPathReference(methodEntryPath, remainingPath);
result = new HashSet<Object>(1);
result.add(reference);
}
else
{
return null;
}
return result;
}
/**
* Gets function name by function invocation.
*
* @param invocation
* - function invocation.
* @return function name or null if not recognized.
*/
private String getFunctionNameByInvocation(FunctionInvocation invocation)
{
FunctionName funcName = invocation.getFunctionName();
if (funcName == null)
{
return null;
}
Expression funcNameExpression = funcName.getName();
if (funcNameExpression == null)
{
return null;
}
if (funcNameExpression instanceof Variable)
{
return getVariableName((Variable) funcNameExpression);
}
else if (funcNameExpression instanceof Identifier)
{
return ((Identifier) funcNameExpression).getName();
}
return null;
}
/**
* Reports the stack. Needed for local mode.
*
* @param stack
* - stack to report.
*/
private void reportStack(List<Scope> stack)
{
if (stack.isEmpty())
{
return;
}
int currentScopeDepth = 0;
// collecting global imports
for (int i = 0; i < stack.size(); i++)
{
Scope currentScope = stack.get(i);
Set<String> currentGlobalImports = currentScope.getGlobalImports();
if (currentGlobalImports != null)
{
_overallGlobalImports.addAll(currentGlobalImports);
}
}
_overallAliases.putAll(aliases);
// _namespace=currentNamespace;
// searching for a first scope that start earlier then current
// offset
Scope currentScope = null;
for (int i = stack.size() - 1; i >= 0; i--)
{
currentScopeDepth = i;
currentScope = stack.get(i);
ASTNode root = currentScope.getRoot();
if (root == null)
{
continue;
}
if (root.getStart() < currentOffset)
{
break;
}
}
// nothing to report
if (currentScope == null)
{
return;
}
isReportedStackGlobal = currentScope.isGlobalScope();
isReportedScopeUnderClass = checkIfScopeIsUnderClass(stack, currentScopeDepth);
// String scopePath = getScopePath(stack, i);
Set<VariableInfo> variables = currentScope.getVariables();
boolean localVariables = !currentScope.isGlobalScope();
// reporting variables
for (VariableInfo varInfo : variables)
{
if (varInfo.getNodeStart() > currentOffset)
{
continue;
}
String entryPath = varInfo.getName();
VariablePHPEntryValue value = new VariablePHPEntryValue(varInfo.getModifier(), false, localVariables,
false, varInfo.getVariableTypes(), varInfo.getNodeStart(), currentNamespace);
int category = PHPFlags.isNamedConstant(varInfo.getModifier()) ? IPHPIndexConstants.CONST_CATEGORY
: IPHPIndexConstants.VAR_CATEGORY;
reporter.reportEntry(category, entryPath, value, module);
}
// reporting function/method parameters if needed, going up in the
// stack searching for the function
for (int i = stack.size() - 1; i >= 0; i--)
{
Scope scope = stack.get(i);
IElementEntry entry = scope.getEntry();
if (entry != null)
{
if (entry.getCategory() == IPHPIndexConstants.FUNCTION_CATEGORY
&& entry.getValue() instanceof FunctionPHPEntryValue
|| entry.getCategory() == IPHPIndexConstants.LAMBDA_FUNCTION_CATEGORY
&& entry.getValue() instanceof LambdaFunctionPHPEntryValue)
{
IPHPFunctionEntryValue val = (IPHPFunctionEntryValue) entry.getValue();
Map<String, Set<Object>> parameters = val.getParameters();
int[] parameterStartPositions = val.getParameterStartPositions();
if (parameters != null && !parameters.isEmpty())
{
int parCount = 0;
for (Map.Entry<String, Set<Object>> parEntry : parameters.entrySet())
{
String entryPath = parEntry.getKey();
VariablePHPEntryValue value = new VariablePHPEntryValue(0, true, false, false,
parEntry.getValue(),
(parameterStartPositions == null || parameterStartPositions.length == 0) ? val
.getStartOffset() : parameterStartPositions[parCount], currentNamespace);
reporter.reportEntry(IPHPIndexConstants.VAR_CATEGORY, entryPath, value, module);
parCount++;
}
}
}
}
}
}
/**
* Checks if the scope specified is under a class/interface scope.
*
* @param stack
* - scopes stack.
* @param currentScopeDepth
* - scope depth.
* @return true if the scope specified is under class or function/method scope, false otherwise.
*/
private boolean checkIfScopeIsUnderClass(List<Scope> stack, int currentScopeDepth)
{
for (int i = currentScopeDepth; i >= 0; i--)
{
Scope scope = scopes.get(i);
IElementEntry entry = scope.getEntry();
if (entry != null && entry.getCategory() == IPHPIndexConstants.CLASS_CATEGORY)
{
return true;
}
}
return false;
}
/**
* Gets scope entries path (including the ending delimiter).
*
* @param stack
* - scopes stack.
* @param pos
* - position of the scope in stack.
* @param clazz
* - class active for the scope.
* @return scope entries path
*/
String getScopePath(List<Scope> stack, int pos)
{
StringBuffer result = new StringBuffer();
for (int i = pos; i >= 0; i--)
{
Scope currentScope = stack.get(i);
ASTNode root = currentScope.getRoot();
if (root instanceof FunctionDeclaration)
{
Identifier funcNameIdentifier = ((FunctionDeclaration) root).getFunctionName();
if (funcNameIdentifier == null)
{
continue;
}
String functionName = funcNameIdentifier.getName();
if (functionName == null)
{
continue;
}
result.insert(0, functionName + IElementsIndex.DELIMITER);
}
else if (root instanceof MethodDeclaration)
{
Identifier funcNameIdentifier = ((MethodDeclaration) root).getFunction().getFunctionName();
if (funcNameIdentifier == null)
{
continue;
}
String functionName = funcNameIdentifier.getName();
if (functionName == null)
{
continue;
}
result.insert(0, functionName + IElementsIndex.DELIMITER);
}
else if (root instanceof ClassDeclaration)
{
Identifier classNameIdentifier = ((ClassDeclaration) root).getName();
if (classNameIdentifier == null)
{
continue;
}
String className = classNameIdentifier.getName();
if (className == null)
{
continue;
}
result.insert(0, className + IElementsIndex.DELIMITER);
}
}
return result.toString();
}
/**
* Parses comment and adds parameter types if availavle.
*
* @param comment
* @param parametersMap
* @return possible return types.
*/
private String[] applyComment(PHPDocBlock comment, Map<String, Set<Object>> parametersMap)
{
try
{
FunctionDocumentation doc = PHPDocUtils.getFunctionDocumentation(comment);
if (doc == null)
{
return null;
}
TypedDescription[] params = doc.getParams();
if (params != null && params.length != 0)
{
for (TypedDescription param : params)
{
String paramName = param.getName();
if (paramName == null || paramName.length() == 0)
{
continue;
}
if (paramName.startsWith(DOLLAR_SIGN))
{
paramName = paramName.substring(1);
}
String[] types = param.getTypes();
if (parametersMap != null)
{
Set<Object> toSetParams = parametersMap.get(paramName);
if (parametersMap.containsKey(paramName))
{
if (toSetParams == null && types != null)
{
toSetParams = new HashSet<Object>();
parametersMap.put(paramName, toSetParams);
}
if (types != null)
{
for (String type : types)
{
toSetParams.add(type);
}
}
}
}
}
}
TypedDescription returnDescr = doc.getReturn();
if (returnDescr == null)
{
return null;
}
return returnDescr.getTypes();
}
catch (Throwable th)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"PHP Module Indexer - Error while applying a comment (applyComment)", //$NON-NLS-1$
th, PHPEditorPlugin.INDEXER_SCOPE);
}
return null;
}
/**
* Reports field and adds it to the current class fields list.
*
* @param modifier
* - modifier.
* @param fieldName
* - field name.
* @param fieldTypes
* - field types.
* @param pos
* - position.
* @return reported entry or null.
*/
private IElementEntry reportField(int modifier, String fieldName, Set<Object> fieldTypes, int pos)
{
VariablePHPEntryValue entryValue = new VariablePHPEntryValue(modifier, false, false, true, fieldTypes, pos,
currentNamespace);
if (currentClass != null && currentClass.getClassEntry() != null)
{
String entryPath = currentClass.getClassEntry().getEntryPath() + IElementsIndex.DELIMITER;
entryPath += fieldName;
IElementEntry result = reporter.reportEntry(IPHPIndexConstants.VAR_CATEGORY, entryPath, entryValue,
module);
currentClass.setField(fieldName, result);
return result;
}
return null;
}
/**
* Reports field and adds it to the current class fields list.
*
* @param modifier
* - modifier.
* @param fieldName
* - field name.
* @param fieldTypes
* - field types.
* @param pos
* - position.
* @return reported entry or null.
*/
private IElementEntry reportClassConst(int modifier, String fieldName, Set<Object> fieldTypes, int pos)
{
modifier |= PHPFlags.AccStatic;
modifier |= PHPFlags.AccFinal;
VariablePHPEntryValue entryValue = new VariablePHPEntryValue(modifier, false, false, true, fieldTypes, pos,
currentNamespace);
if (currentClass != null && currentClass.getClassEntry() != null)
{
String entryPath = currentClass.getClassEntry().getEntryPath() + IElementsIndex.DELIMITER;
entryPath += fieldName;
IElementEntry result = reporter.reportEntry(IPHPIndexConstants.CONST_CATEGORY, entryPath, entryValue,
module);
// currentClass.setField(fieldName, result);
return result;
}
return null;
}
/**
* Adds block variables for try, for and other non-function expressions that can define local block variables.
*
* @param block
* - block.
*/
private void addBlockVariables(Block block)
{
ASTNode blockParent = block.getParent();
if (blockParent instanceof CatchClause)
{
addCatchClauseVariables((CatchClause) blockParent);
}
else if (blockParent instanceof ForStatement)
{
addForVariables((ForStatement) blockParent);
}
else if (blockParent instanceof ForEachStatement)
{
addForEachVariables((ForEachStatement) blockParent);
}
else if (blockParent instanceof LambdaFunctionDeclaration)
{
LambdaFunctionDeclaration lambdaFunctionDeclaration = (LambdaFunctionDeclaration) blockParent;
List<FormalParameter> formalParameters = lambdaFunctionDeclaration.formalParameters();
for (FormalParameter p : formalParameters)
{
Expression varName = p.getParameterName();
if (varName != null
&& (varName.getType() == ASTNode.IDENTIFIER || varName.getType() == ASTNode.NAMESPACE_NAME))
{
String name = ((Identifier) varName).getName();
if (name.startsWith(DOLLAR_SIGN))
{
VariableInfo info = new VariableInfo(name.substring(1), null, getCurrentScope(),
lambdaFunctionDeclaration.getStart());
getCurrentScope().addVariable(info);
}
}
}
List<Expression> lexicalVariables = lambdaFunctionDeclaration.lexicalVariables();
for (Expression p : lexicalVariables)
{
if (p.getType() == ASTNode.IDENTIFIER || p.getType() == ASTNode.NAMESPACE_NAME)
{
String varName = ((Identifier) p).getName();
if (varName != null && varName.startsWith(DOLLAR_SIGN))
{
VariableInfo info = new VariableInfo(varName.substring(1), null, getCurrentScope(),
lambdaFunctionDeclaration.getStart());
getCurrentScope().addVariable(info);
}
}
}
}
}
/**
* Adds "for each" local variables.
*
* @param foreachStatement
* - "for each" statement.
*/
private void addForEachVariables(ForEachStatement foreachStatement)
{
Expression key = foreachStatement.getKey();
Expression value = foreachStatement.getValue();
if (key != null && key instanceof Variable)
{
String varName = getVariableName((Variable) key);
if (varName != null)
{
VariableInfo info = new VariableInfo(varName, null, getCurrentScope(), key.getStart());
getCurrentScope().addVariable(info);
}
}
if (value != null && value instanceof Variable)
{
String varName = getVariableName((Variable) value);
if (varName != null)
{
VariableInfo info = new VariableInfo(varName, null, getCurrentScope(), value.getStart());
getCurrentScope().addVariable(info);
}
}
}
/**
* Adds "for" local variables.
*
* @param forStatement
* - "for" statement.
*/
private void addForVariables(ForStatement forStatement)
{
List<Expression> initializations = forStatement.initializers();
if (initializations == null || initializations.size() == 0)
{
return;
}
for (Expression initialization : initializations)
{
if (initialization instanceof Assignment)
{
Assignment assigment = (Assignment) initialization;
VariableBase var = assigment.getLeftHandSide();
if (var instanceof Variable)
{
String varName = getVariableName((Variable) var);
if (varName == null)
{
continue;
}
Set<Object> types = countExpressionTypes(assigment.getRightHandSide());
if (types != null && types.size() != 0)
{
VariableInfo info = new VariableInfo(varName, types, getCurrentScope(), var.getStart());
getCurrentScope().addVariable(info);
}
}
}
}
}
/**
* Adds catch clause local variables.
*
* @param clause
* - catch clause.
*/
private void addCatchClauseVariables(CatchClause clause)
{
Expression var = clause.getVariable();
String varName = getVariableName(var);
if (varName != null)
{
VariableInfo info = new VariableInfo(varName, "Exception", getCurrentScope(), var.getStart()); //$NON-NLS-1$
getCurrentScope().addVariable(info);
}
}
}
/**
* Mode.
*/
private boolean globalMode = true;
/**
* Current offset.
*/
private int currentOffset = 0;
/**
* Contents to index.
*/
private String _contents;
/**
* Comments.
*/
private List<Comment> _comments;
/**
* Overall global imports in the reported stack.
*/
private Set<String> _overallGlobalImports = new HashSet<String>();
/**
* Overall global imports in the reported stack.
*/
private Map<String, String> _overallAliases = new HashMap<String, String>();
/**
* Whether reported stack is global one.
*/
private boolean isReportedStackGlobal = true;
/**
* Whether reported stack is under class/interface
*/
private boolean isReportedScopeUnderClass = false;
private boolean updateTaskTags = true;
private String _namespace;
private Map<ASTNode, List<VarComment>> _resolvedVarComments;
/**
* @return is update task tags turned on
*/
public boolean isUpdateTaskTags()
{
return updateTaskTags;
}
/**
* @param updateTaskTags
*/
public void setUpdateTaskTags(boolean updateTaskTags)
{
this.updateTaskTags = updateTaskTags;
}
/**
* PDTPHPModuleIndexer constructor. Creates indexer in global mode.
*/
public PDTPHPModuleIndexer()
{
}
/**
* PDTPHPModuleIndexer constructor. Indexer might be created in one of two modes: global mode and local mode. In
* global mode indexer reports includes, classes, functions, methods, fields and only global variables. In local
* mode indexer reports includes, classes, functions, methods, fields, global variables and local variables that are
* visible from the offset specified.
*
* @param globalMode
* - true if global mode is on, false if local mode is on.
* @param currentOffset
* - offset used for local mode counting.
*/
public PDTPHPModuleIndexer(boolean globalMode, int currentOffset)
{
this.globalMode = globalMode;
this.currentOffset = currentOffset;
}
/**
* Indexes contents of the the module.
*
* @param contents
* - module contents.
* @param module
* - module.
* @param reporter
* - reporter to report to.
*/
public synchronized void indexModule(String contents, IModule module, IIndexReporter reporter)
{
_contents = contents;
try
{
Program program;
try
{
if (!globalMode)
{
StringBuffer cutContents = new StringBuffer();
String prevLine = ""; //$NON-NLS-1$
int lineStartPos = 0;
while (true)
{
String currentLine = readLine(contents, lineStartPos);
if (currentLine == null)
{
break;
}
int lineEndPos = lineStartPos + currentLine.length();
// if we are in local mode and current offset is in this
// line,
// replacing the line with the spaces, otherwise just
// adding contents
if (currentOffset > lineEndPos || currentOffset < lineStartPos)
{
cutContents.append(currentLine);
}
else
{
StringBuilder bld = new StringBuilder();
HashSet<String> variables = new HashSet<String>();
bld.append("<? "); //$NON-NLS-1$
if (currentLine.indexOf('{') != -1)
{
bld.append(prevLine);
}
bld.append(currentLine);
bld.append(" ?>"); //$NON-NLS-1$
Reader reader = new StringReader(bld.toString()); // $codepro.audit.disable
// closeWhereCreated
// TODO - Shalom: Get the right version from the module
AstLexer lexer = ASTFactory.getAstLexer(PHPVersion.getLatest(), reader);
// IsInCommentChecker isInCommentChecker = new
// IsInCommentChecker(offset);
// lexer.setCommentListener(isInCommentChecker);
// lexer.setTasksPatterns(new Pattern[0]);
Symbol prev = null;
try
{
while (true)
{
Symbol next_token = lexer.next_token();
// TODO: Shalom - Note that this is only relating to PHP 5.3!
if (next_token.sym == ParserConstants.T_EQUAL)
{
if (prev != null)
{
if (prev.sym == ParserConstants.T_VARIABLE)
{
String text = (String) prev.value;
variables.add(text);
}
}
}
// System.out.println(next_token);
if (next_token.sym == 0)
{
break;
}
prev = next_token;
}
}
catch (IOException e)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"PHP Module Indexer - I/O Error while indexing (indexModule)", //$NON-NLS-1$
e, PHPEditorPlugin.INDEXER_SCOPE);
}
int j = 0;
for (String s : variables)
{
j++;
BuildHelper.sleepLoop(BuildHelper.PHP_INDEX_TYPE, j);
VariablePHPEntryValue value = new VariablePHPEntryValue(0, false, false, false,
Collections.emptySet(), lineStartPos, this._namespace);
reporter.reportEntry(IPHPIndexConstants.VAR_CATEGORY, s.substring(1), value, module);
}
StringBuffer replaceBuffer = new StringBuffer();
for (int i = 0; i < currentLine.length(); i++)
{
char ch = currentLine.charAt(i);
if (Character.isWhitespace(ch))
{
replaceBuffer.append(ch);
}
else
{
if (ch == '{' || ch == '}')
{
replaceBuffer.append(ch);
}
else
{
replaceBuffer.append(' ');
}
}
}
cutContents.append(replaceBuffer);
}
prevLine = currentLine;
lineStartPos += currentLine.length();
}
cutContents.append("\r\n;"); //$NON-NLS-1$
program = parse(cutContents.toString(), module);
}
else
{
program = parse(contents, module);
if (program == null)
{
return;
}
}
}
catch (Throwable th)
{
return;
}
if (program == null)
{
return;
}
// collecting comments
CommentsVisitor commentsVisitor = new CommentsVisitor(true);
program.accept(commentsVisitor);
_comments = commentsVisitor.getComments();
_resolvedVarComments = commentsVisitor.getResolvedVarComments();
try
{
if (isUpdateTaskTags())
{
updater.updateTaskTags(_contents, program, _comments, module);
}
}
catch (Throwable th)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"Error while updating the task tags", th, PHPEditorPlugin.DEBUG_SCOPE); //$NON-NLS-1$
}
// indexing
PHPASTVisitor visitor = new PHPASTVisitor(reporter, module);
program.accept(visitor);
for (IIndexingASTVisitor v : ASTVisitorRegistry.getInstance().getVisitors())
{
v.process(program, reporter, module);
}
}
catch (Throwable th)
{
IdeLog.logError(PHPEditorPlugin.getDefault(), "Error while indexing module - " + module.toString(), th); //$NON-NLS-1$
}
}
/**
* {@inheritDoc}
*/
public synchronized void indexModule(IModule module, IIndexReporter reporter)
{
try
{
Program program;
try
{
setContents(module, null);
program = parse(_contents, module);
if (program == null)
{
return;
}
}
catch (Throwable th)
{
return;
}
if (program == null)
{
return;
}
// collecting comments
CommentsVisitor commentsVisitor = new CommentsVisitor();
program.accept(commentsVisitor);
_comments = commentsVisitor.getComments();
try
{
if (isUpdateTaskTags())
{
updater.updateTaskTags(_contents, program, _comments, module);
}
}
catch (Throwable th)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"Error while updating the task tags", th, PHPEditorPlugin.DEBUG_SCOPE); //$NON-NLS-1$
}
// indexing
PHPASTVisitor visitor = new PHPASTVisitor(reporter, module);
program.accept(visitor);
for (IIndexingASTVisitor v : ASTVisitorRegistry.getInstance().getVisitors())
{
v.process(program, reporter, module);
}
// Mark the errors in the project tree
program.getAST().flushErrors();
}
catch (Throwable th)
{
IdeLog.logError(PHPEditorPlugin.getDefault(), "Error while indexing module - " + module.toString(), th); //$NON-NLS-1$
}
}
private void setContents(IModule module, String source) throws IOException
{
BufferedReader reader;
if (source == null)
{
reader = new BufferedReader(new InputStreamReader(module.getContents(),
EncodingUtils.getModuleEncoding(module)));
}
else
{
reader = new BufferedReader(new InputStreamReader(new StringInputStream(source),
EncodingUtils.getModuleEncoding(module)));
}
StringBuffer moduleData = new StringBuffer();
try
{
char[] buf = new char[1024];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) // $codepro.audit.disable assignmentInCondition
{
String readData = String.valueOf(buf, 0, numRead);
moduleData.append(readData);
}
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException e)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"Error closing a BufferedReader in the PDTPHPModuleIndexer", e,//$NON-NLS-1$
PHPEditorPlugin.INDEXER_SCOPE);
}
}
}
String contents = moduleData.toString();
StringBuffer cutContents = new StringBuffer();
int lineStartPos = 0;
while (true)
{
String currentLine = readLine(contents, lineStartPos);
if (currentLine == null)
{
break;
}
int lineEndPos = lineStartPos + currentLine.length();
// if we are in local mode and current offset is in this line,
// replacing the line with the spaces, otherwise just adding
// contents
if (globalMode || currentOffset > lineEndPos || currentOffset < lineStartPos)
{
cutContents.append(currentLine);
}
else
{
StringBuffer replaceBuffer = new StringBuffer();
for (int i = 0; i < currentLine.length(); i++)
{
char ch = currentLine.charAt(i);
if (ch == '\r' || ch == '\n')
{
replaceBuffer.append(ch);
}
else
{
replaceBuffer.append(' ');
}
}
cutContents.append(replaceBuffer);
}
lineStartPos += currentLine.length();
}
_contents = cutContents.toString();
}
/**
* Gets global imports got while parsing in a local mode in the scopes stack.
*
* @return global imports.
*/
public Set<String> getGlobalImports()
{
return _overallGlobalImports;
}
/**
* Gets whether reported scope is global.
*
* @return whether reported scope is global.
*/
public boolean isReportedScopeGlobal()
{
return isReportedStackGlobal;
}
/**
* Gets whether reported scope is under a class
*
* @return true if whether reported scope is under a class
*/
public boolean isReportedScopeUnderClass()
{
return isReportedScopeUnderClass;
}
/**
* Reads line from contents starting with position specified.
*
* @param contents
* - contents.
* @param lineStartPos
* - line start position.
* @return line
*/
private String readLine(String contents, int lineStartPos)
{
StringBuffer result = new StringBuffer();
for (int i = lineStartPos; i < contents.length(); i++)
{
if (i == contents.length() - 1)
{
result.append(contents.substring(lineStartPos, contents.length()));
break;
}
char ch = contents.charAt(i);
switch (ch)
{
case '\r':
if (i < contents.length() - 1 && contents.charAt(i + 1) == '\n')
{
i++;
}
case '\n': // $codepro.audit.disable nonTerminatedCaseClause
result.append(contents.substring(lineStartPos, i + 1));
return result.toString();
}
}
if (result.length() == 0)
{
return null;
}
return result.toString();
}
/**
* Performs the parsing.
*
* @param string
* - contents.
* @param module
* @return parse results
* @throws Exception
* IF an exception occurs
*/
private Program parse(String contents, IModule module)
{
try
{
Reader reader = new StringReader(contents); // $codepro.audit.disable closeWhereCreated
IProject project = null;
if (module.getBuildPath() instanceof ProjectBuildPath)
{
project = ((ProjectBuildPath) module.getBuildPath()).getProject();
}
PHPVersion phpVersion = PHPVersionProvider.getPHPVersion(project);
PHPVersion version = (phpVersion == null) ? PHPVersionProvider.getDefaultPHPVersion() : phpVersion;
ASTParser parser = ASTParser.newParser(reader, version, true, ModelUtils.convertModule(module), BuildType.BUILD);
return parser.createAST(null);
}
catch (Throwable th)
{
// 99% of the parsing errors should be skipped
// String message = th.getMessage();
// if
// (message!=null&&message.contains("Can't recover from previous error(s)")){
// return null;
// }
// IdeLog.logError(PHPPlugin.getDefault(), "Unexpected exception while parsing module contents", //$NON-NLS-1$
// th);
return null;
}
}
/**
* Converts encoded type to its string representation.
*
* @param intType
* - integer-encoded type.
* @return string representation or null if not found.
*/
private static String typeToString(int intType)
{
switch (intType)
{
case Scalar.TYPE_INT:
return IPHPIndexConstants.INTEGER_TYPE;
case Scalar.TYPE_REAL:
return IPHPIndexConstants.REAL_TYPE;
case Scalar.TYPE_STRING:
return IPHPIndexConstants.STRING_TYPE;
case Scalar.TYPE_SYSTEM:
return IPHPIndexConstants.SYSTEM_TYPE;
case Scalar.TYPE_UNKNOWN:
return IPHPIndexConstants.UNKNOWN_TYPE;
}
return null;
}
public void indexModule(Program program, IModule module, IIndexReporter reporter)
{
indexModule(program, module, null, reporter);
}
/*
* (non-Javadoc)
* @see com.aptana.editor.php.indexer.IProgramIndexer#indexModule(org2.eclipse.php.internal.core.ast.nodes.Program,
* com.aptana.editor.php.internal.core.builder.IModule, java.lang.String,
* com.aptana.editor.php.indexer.IIndexReporter)
*/
public void indexModule(Program program, IModule module, String source, IIndexReporter reporter)
{
try
{
setContents(module, source);
}
catch (IOException e)
{
IdeLog.logError(PHPEditorPlugin.getDefault(), "Error while getting module contents", e); //$NON-NLS-1$
}
// collecting comments
CommentsVisitor commentsVisitor = new CommentsVisitor();
program.accept(commentsVisitor);
_comments = commentsVisitor.getComments();
// indexing
PHPASTVisitor visitor = new PHPASTVisitor(reporter, module);
program.accept(visitor);
for (IIndexingASTVisitor v : ASTVisitorRegistry.getInstance().getVisitors())
{
v.process(program, reporter, module);
}
}
public Map<String, String> getAliases()
{
return _overallAliases;
}
public String getNamespace()
{
return _namespace;
}
}