/*******************************************************************************
* Copyright (c) 2017 Alex Xu and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alex Xu - initial API and implementation
*******************************************************************************/
package org.eclipse.php.internal.ui.corext.codemanipulation;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.dltk.compiler.problem.DefaultProblem;
import org.eclipse.dltk.compiler.problem.IProblem;
import org.eclipse.dltk.compiler.problem.IProblemIdentifier;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule;
import org.eclipse.dltk.core.index2.search.ModelAccess;
import org.eclipse.dltk.core.manipulation.SourceModuleChange;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.core.search.TypeNameMatch;
import org.eclipse.dltk.ui.viewsupport.BasicElementLabels;
import org.eclipse.ltk.core.refactoring.*;
import org.eclipse.php.core.ast.nodes.*;
import org.eclipse.php.core.ast.visitor.ApplyAll;
import org.eclipse.php.core.compiler.ast.nodes.NamespaceReference;
import org.eclipse.php.internal.core.ast.locator.PHPElementConciliator;
import org.eclipse.php.internal.core.ast.rewrite.ImportRewrite;
import org.eclipse.php.internal.core.ast.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.php.internal.core.compiler.ast.parser.PHPProblemIdentifier;
import org.eclipse.php.internal.core.search.PHPSearchTypeNameMatch;
import org.eclipse.php.internal.core.typeinference.PHPSimpleTypes;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.corext.util.Messages;
import org.eclipse.php.internal.ui.corext.util.TypeNameMatchCollector;
import org.eclipse.php.internal.ui.text.correction.ASTResolving;
import org.eclipse.php.internal.ui.text.correction.ProblemLocation;
import org.eclipse.php.internal.ui.text.correction.SimilarElementsRequestor;
import org.eclipse.php.ui.editor.SharedASTProvider;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
public class OrganizeUseStatementsOperation implements IWorkspaceRunnable {
public static interface IChooseImportQuery {
/**
* Selects imports from a list of choices.
*
* @param openChoices
* From each array, a type reference has to be selected
* @param ranges
* For each choice the range of the corresponding type
* reference.
* @return Returns <code>null</code> to cancel the operation, or the
* selected imports.
*/
TypeNameMatch[] chooseImports(TypeNameMatch[][] openChoices, ISourceRange[] ranges);
}
private static class UnresolvableImportMatcher {
static UnresolvableImportMatcher forProgram(Program cu) {
Map<NamespaceDeclaration, Map<String, Set<String>>> typeImportsBySimpleName = new HashMap<>();
List<NamespaceDeclaration> namespaces = cu.getNamespaceDeclarations();
if (namespaces.size() > 0) {
for (NamespaceDeclaration namespace : namespaces) {
forProgram(cu, namespace, typeImportsBySimpleName);
}
} else {
forProgram(cu, null, typeImportsBySimpleName);
}
return new UnresolvableImportMatcher(typeImportsBySimpleName);
}
private static void forProgram(Program cu, NamespaceDeclaration namespace,
Map<NamespaceDeclaration, Map<String, Set<String>>> typeImportsBySimpleName) {
typeImportsBySimpleName.put(namespace, new HashMap<>());
Collection<UseStatement> unresolvableImports = determineUnresolvableImports(cu, namespace);
for (UseStatement importDeclaration : unresolvableImports) {
for (UseStatementPart part : importDeclaration.parts()) {
String qualifiedName = part.getName().getName();
String simpleName = qualifiedName
.substring(qualifiedName.lastIndexOf(NamespaceReference.NAMESPACE_SEPARATOR) + 1);
Map<String, Set<String>> importsBySimpleName = typeImportsBySimpleName.get(namespace);
Set<String> importsWithSimpleName = importsBySimpleName.get(simpleName);
if (importsWithSimpleName == null) {
importsWithSimpleName = new HashSet<>();
importsBySimpleName.put(simpleName, importsWithSimpleName);
}
importsWithSimpleName.add(qualifiedName);
}
}
}
private static Collection<UseStatement> determineUnresolvableImports(Program program,
NamespaceDeclaration namespaceDeclaration) {
Collection<UseStatement> unresolvableImports = new ArrayList<>(
program.getUseStatements(namespaceDeclaration).size());
IProblem[] problems = program.getProblems();
for (IProblem problem : problems) {
IProblemIdentifier id = ((DefaultProblem) problem).getID();
if (id == PHPProblemIdentifier.ImportNotFound) {
UseStatement problematicImport = getProblematicImport(problem, program);
if (problematicImport != null) {
unresolvableImports.add(problematicImport);
}
}
}
return unresolvableImports;
}
private static UseStatement getProblematicImport(IProblem problem, Program cu) {
ASTNode coveringNode = new ProblemLocation(problem).getCoveringNode(cu);
if (coveringNode != null && coveringNode instanceof UseStatement) {
return (UseStatement) coveringNode;
}
return null;
}
private final Map<NamespaceDeclaration, Map<String, Set<String>>> fTypeImportsBySimpleName;
private UnresolvableImportMatcher(Map<NamespaceDeclaration, Map<String, Set<String>>> typeImportsBySimpleName) {
fTypeImportsBySimpleName = typeImportsBySimpleName;
}
private Set<String> matchImports(NamespaceDeclaration namespace, String simpleName) {
Map<String, Set<String>> importsBySimpleName = fTypeImportsBySimpleName.get(namespace);
Set<String> matchingSingleImports = importsBySimpleName.get(simpleName);
if (matchingSingleImports != null) {
return Collections.unmodifiableSet(matchingSingleImports);
}
Set<String> matchingOnDemandImports = importsBySimpleName.get("*"); //$NON-NLS-1$
if (matchingOnDemandImports != null) {
return Collections.unmodifiableSet(matchingOnDemandImports);
}
return Collections.emptySet();
}
Set<String> matchTypeImports(NamespaceDeclaration namespace, String simpleName) {
return matchImports(namespace, simpleName);
}
}
private static class TypeReferenceProcessor {
private static class UnresolvedTypeData {
final Identifier ref;
final int typeKinds;
final List<TypeNameMatch> foundInfos;
public UnresolvedTypeData(Identifier ref) {
this.ref = ref;
this.typeKinds = ASTResolving.getPossibleTypeKinds(ref);
this.foundInfos = new ArrayList<>(3);
}
public void addInfo(TypeNameMatch info) {
for (int i = this.foundInfos.size() - 1; i >= 0; i--) {
TypeNameMatch curr = this.foundInfos.get(i);
if (curr.getTypeContainerName().equals(info.getTypeContainerName())) {
return; // not added. already contains type with same
// name
}
}
foundInfos.add(info);
}
}
private Map<NamespaceDeclaration, Set<String>> fOldSingleImports;
private ImportRewrite fImpStructure;
private final UnresolvableImportMatcher fUnresolvableImportMatcher;
// private IPackageFragment fCurrPackage;
//
// private ScopeAnalyzer fAnalyzer;
private boolean fAllowDefaultPackageImports;
private Map<NamespaceDeclaration, Map<String, UnresolvedTypeData>> fUnresolvedTypes = new HashMap<>();
private Map<NamespaceDeclaration, Set<String>> fImportsAdded = new HashMap<>();
private Map<NamespaceDeclaration, TypeNameMatch[][]> fOpenChoices = new HashMap<>();
private Map<NamespaceDeclaration, SourceRange[]> fSourceRanges = new HashMap<>();
private Program fRoot;
public TypeReferenceProcessor(Map<NamespaceDeclaration, Set<String>> oldSingleImports, Program root,
ImportRewrite impStructure, UnresolvableImportMatcher unresolvableImportMatcher) {
fRoot = root;
fOldSingleImports = oldSingleImports;
fImpStructure = impStructure;
fUnresolvableImportMatcher = unresolvableImportMatcher;
// fAnalyzer= new ScopeAnalyzer(root);
//
// fCurrPackage= (IPackageFragment) cu.getParent()
fAllowDefaultPackageImports = true;
List<NamespaceDeclaration> namespaces = root.getNamespaceDeclarations();
if (namespaces.size() > 0) {
for (NamespaceDeclaration namespace : namespaces) {
fImportsAdded.put(namespace, new HashSet<>());
fUnresolvedTypes.put(namespace, new HashMap<>());
}
} else {
fImportsAdded.put(null, new HashSet<>());
fUnresolvedTypes.put(null, new HashMap<>());
}
}
/**
* Tries to find the given type name and add it to the import structure.
*
* @param ref
* the name node
*/
public void add(Identifier ref) {
NamespaceDeclaration namespace = fRoot.getNamespaceDeclaration(ref.getStart());
String typeName = ref.getName();
int index = typeName.indexOf(NamespaceReference.NAMESPACE_DELIMITER);
if (index > 0) {
typeName = typeName.substring(0, index);
}
if (fImportsAdded.get(namespace) == null || fImportsAdded.get(namespace).contains(typeName)) {
return;
}
IBinding binding = ref.resolveBinding();
if (binding != null) {
if (binding.getKind() != IBinding.TYPE) {
return;
}
ITypeBinding typeBinding = ((ITypeBinding) binding).getTypeDeclaration();
if (typeBinding != null) {
String alias = null;
String typeBindingName = typeBinding.getName();
if (typeBindingName != null) {
if (typeBindingName.startsWith(NamespaceReference.NAMESPACE_DELIMITER)) {
typeBindingName = typeBindingName.substring(1);
}
if (!typeBindingName.endsWith(typeName)) {
alias = typeName;
}
}
fImpStructure.addImport(namespace, typeBindingName, alias);
fImportsAdded.get(namespace).add(typeName);
return;
}
}
fImportsAdded.get(namespace).add(typeName);
fUnresolvedTypes.get(namespace).put(typeName, new UnresolvedTypeData(ref));
}
public Map<NamespaceDeclaration, Boolean> process(IProgressMonitor monitor) throws ModelException {
try {
Map<NamespaceDeclaration, Boolean> hasOpenChoices = new HashMap<>();
final IScriptProject project = fImpStructure.getSourceModule().getScriptProject();
IDLTKSearchScope scope = SearchEngine.createSearchScope(project);
List<NamespaceDeclaration> namespaces = fRoot.getNamespaceDeclarations();
if (namespaces.size() > 0) {
for (NamespaceDeclaration namespace : namespaces) {
hasOpenChoices.put(namespace, internalProcess(namespace, scope, monitor));
}
} else {
hasOpenChoices.put(null, internalProcess(null, scope, monitor));
}
return hasOpenChoices;
} finally {
monitor.done();
}
}
private boolean internalProcess(NamespaceDeclaration namespace, IDLTKSearchScope scope,
IProgressMonitor monitor) throws ModelException {
int nUnresolved = fUnresolvedTypes.get(namespace).size();
if (nUnresolved == 0) {
return false;
}
final ArrayList<TypeNameMatch> typesFound = new ArrayList<>();
TypeNameMatchCollector collector = new TypeNameMatchCollector(typesFound);
for (Iterator<String> iter = fUnresolvedTypes.get(namespace).keySet().iterator(); iter.hasNext();) {
ModelAccess modelAccess = new ModelAccess();
IType[] types = modelAccess.findTypes(iter.next(), MatchRule.EXACT, 0, 0, scope, monitor);
for (IType type : types) {
TypeNameMatch match = new PHPSearchTypeNameMatch(type, type.getFlags());
collector.acceptTypeNameMatch(match);
}
}
for (int i = 0; i < typesFound.size(); i++) {
TypeNameMatch curr = typesFound.get(i);
UnresolvedTypeData data = fUnresolvedTypes.get(namespace).get(curr.getSimpleTypeName());
if (data != null && isOfKind(curr, data.typeKinds)) {
if (fAllowDefaultPackageImports || curr.getPackageName().length() > 0) {
data.addInfo(curr);
}
}
}
for (Entry<String, UnresolvedTypeData> entry : fUnresolvedTypes.get(namespace).entrySet()) {
if (entry.getValue().foundInfos.size() == 0) { // No
// result
// found
// in
// search
Set<String> matchingUnresolvableImports = fUnresolvableImportMatcher.matchTypeImports(namespace,
entry.getKey());
if (!matchingUnresolvableImports.isEmpty()) {
// If there are matching unresolvable import(s),
// rely on them to provide the type.
for (String string : matchingUnresolvableImports) {
fImpStructure.addImport(namespace, string, UNRESOLVABLE_IMPORT_CONTEXT);
}
}
}
}
ArrayList<TypeNameMatch[]> openChoices = new ArrayList<>(nUnresolved);
ArrayList<SourceRange> sourceRanges = new ArrayList<>(nUnresolved);
for (Iterator<UnresolvedTypeData> iter = fUnresolvedTypes.get(namespace).values().iterator(); iter
.hasNext();) {
UnresolvedTypeData data = iter.next();
TypeNameMatch[] openChoice = processTypeInfo(namespace, data.foundInfos);
if (openChoice != null) {
openChoices.add(openChoice);
sourceRanges.add(new SourceRange(data.ref.getStart(), data.ref.getLength()));
}
}
if (openChoices.isEmpty()) {
return false;
}
fOpenChoices.put(namespace, openChoices.toArray(new TypeNameMatch[openChoices.size()][]));
fSourceRanges.put(namespace, sourceRanges.toArray(new SourceRange[sourceRanges.size()]));
return true;
}
private TypeNameMatch[] processTypeInfo(NamespaceDeclaration namespace, List<TypeNameMatch> typeRefsFound) {
int nFound = typeRefsFound.size();
if (nFound == 0) {
// nothing found
return null;
} else if (nFound == 1) {
TypeNameMatch typeRef = typeRefsFound.get(0);
fImpStructure.addImport(namespace, typeRef.getFullyQualifiedName());
return null;
} else {
// multiple found, use old imports to find an entry
for (int i = 0; i < nFound; i++) {
TypeNameMatch typeRef = typeRefsFound.get(i);
String fullName = typeRef.getFullyQualifiedName();
if (fOldSingleImports.get(namespace).contains(fullName)) {
// was single-imported
fImpStructure.addImport(namespace, fullName);
return null;
}
}
// return the open choices
return typeRefsFound.toArray(new TypeNameMatch[nFound]);
}
}
private boolean isOfKind(TypeNameMatch curr, int typeKinds) {
int flags = curr.getModifiers();
if (Flags.isInterface(flags)) {
return (typeKinds & SimilarElementsRequestor.INTERFACES) != 0;
}
return (typeKinds & SimilarElementsRequestor.CLASSES) != 0;
}
public Map<NamespaceDeclaration, TypeNameMatch[][]> getChoices() {
return fOpenChoices;
}
public Map<NamespaceDeclaration, SourceRange[]> getChoicesSourceRanges() {
return fSourceRanges;
}
}
/**
* Used to ensure that unresolvable imports don't get reduced into on-demand
* imports.
*/
private static ImportRewriteContext UNRESOLVABLE_IMPORT_CONTEXT = new ImportRewriteContext() {
@Override
public int findInContext(NamespaceDeclaration namespace, String qualifier, String name, int kind) {
return RES_NAME_UNKNOWN;
}
};
private int fNumberOfImportsAdded;
private int fNumberOfImportsRemoved;
private IChooseImportQuery fChooseImportQuery;
private ISourceModule fSourceModule;
private Program fASTRoot;
public OrganizeUseStatementsOperation(ISourceModule sourceModule, Program astRoot,
IChooseImportQuery chooseImportQuery) {
fSourceModule = sourceModule;
fASTRoot = astRoot;
// fAllowSyntaxErrors= allowSyntaxErrors;
fChooseImportQuery = chooseImportQuery;
fNumberOfImportsAdded = 0;
fNumberOfImportsRemoved = 0;
// fParsingError= null;
}
public TextEdit createTextEdit(IProgressMonitor monitor)
throws CoreException, OperationCanceledException, IOException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
fNumberOfImportsAdded = 0;
fNumberOfImportsRemoved = 0;
monitor.beginTask(Messages.format(CodeGenerationMessages.OrganizeImportsOperation_description,
BasicElementLabels.getFileName(fSourceModule)), 9);
Program astRoot = fASTRoot;
if (astRoot == null) {
astRoot = SharedASTProvider.getAST(fSourceModule, SharedASTProvider.WAIT_YES,
SubMonitor.convert(monitor, 2));
if (monitor.isCanceled())
throw new OperationCanceledException();
} else {
monitor.worked(2);
}
ImportRewrite importsRewrite = ImportRewrite.create(astRoot, false);
Map<NamespaceDeclaration, Set<String>> oldSingleImports = new HashMap<>();
List<Identifier> typeReferences = new ArrayList<>();
if (!collectReferences(astRoot, typeReferences, oldSingleImports))
return null;
UnresolvableImportMatcher unresolvableImportMatcher = UnresolvableImportMatcher.forProgram(astRoot);
TypeReferenceProcessor processor = new TypeReferenceProcessor(oldSingleImports, astRoot, importsRewrite,
unresolvableImportMatcher);
Iterator<Identifier> refIterator = typeReferences.iterator();
while (refIterator.hasNext()) {
Identifier typeRef = refIterator.next();
processor.add(typeRef);
}
Map<NamespaceDeclaration, Boolean> hasOpenChoices = processor.process(SubMonitor.convert(monitor, 3));
if (fChooseImportQuery != null) {
Map<NamespaceDeclaration, TypeNameMatch[][]> choices = processor.getChoices();
Map<NamespaceDeclaration, SourceRange[]> ranges = processor.getChoicesSourceRanges();
for (Iterator<Entry<NamespaceDeclaration, Boolean>> iter = hasOpenChoices.entrySet().iterator(); iter
.hasNext();) {
Entry<NamespaceDeclaration, Boolean> entry = iter.next();
NamespaceDeclaration namespace = entry.getKey();
if (entry.getValue()) {
TypeNameMatch[] chosen = fChooseImportQuery.chooseImports(choices.get(namespace),
ranges.get(namespace));
if (chosen == null) {
// cancel pressed by the user
throw new OperationCanceledException();
}
for (int i = 0; i < chosen.length; i++) {
TypeNameMatch typeInfo = chosen[i];
if (typeInfo != null) {
importsRewrite.addImport(namespace, typeInfo.getFullyQualifiedName());
} else { // Skipped by user
String typeName = choices.get(namespace)[i][0].getSimpleTypeName();
Set<String> matchingUnresolvableImports = unresolvableImportMatcher
.matchTypeImports(namespace, typeName);
if (!matchingUnresolvableImports.isEmpty()) {
// If there are matching unresolvable
// import(s),
// rely on them to provide the type.
for (String string : matchingUnresolvableImports) {
importsRewrite.addImport(namespace, string, UNRESOLVABLE_IMPORT_CONTEXT);
}
}
}
}
}
}
}
TextEdit result = importsRewrite.rewriteImports(SubMonitor.convert(monitor, 3));
determineImportDifferences(importsRewrite, oldSingleImports.values());
return result;
} catch (Exception e) {
PHPUiPlugin.log(e);
} finally {
monitor.done();
}
return null;
}
private void determineImportDifferences(ImportRewrite importsStructure,
Collection<Set<String>> oldSingleImportsCollection) {
ArrayList<String> importsAdded = new ArrayList<>();
importsAdded.addAll(Arrays.asList(importsStructure.getCreatedImports()));
for (Set<String> oldSingleImports : oldSingleImportsCollection) {
Object[] content = oldSingleImports.toArray();
for (int i = 0; i < content.length; i++) {
String importName = (String) content[i];
if (importsAdded.remove(importName))
oldSingleImports.remove(importName);
}
fNumberOfImportsRemoved += oldSingleImports.size();
}
fNumberOfImportsAdded = importsAdded.size();
}
/**
* Runs the operation.
*
* @param monitor
* the progress monitor
* @throws CoreException
* thrown when the operation failed
* @throws OperationCanceledException
* Runtime error thrown when operation is canceled.
*/
@Override
public void run(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
monitor.beginTask(Messages.format(CodeGenerationMessages.OrganizeImportsOperation_description,
BasicElementLabels.getFileName(fSourceModule)), 10);
SourceModuleChange cuChange = new SourceModuleChange("OrganizeUseStatements", fSourceModule); //$NON-NLS-1$
cuChange.setSaveMode(TextFileChange.LEAVE_DIRTY);
TextChange change = cuChange;
TextEdit edit = createTextEdit(SubMonitor.convert(monitor));
if (edit != null) {
change.setEdit(edit);
}
change.initializeValidationData(new NullProgressMonitor());
RefactoringStatus valid = change.isValid(new NullProgressMonitor());
if (valid.hasFatalError()) {
IStatus status = new Status(IStatus.ERROR, PHPUiPlugin.ID, IStatus.ERROR,
valid.getMessageMatchingSeverity(RefactoringStatus.FATAL), null);
throw new CoreException(status);
} else {
IUndoManager manager = RefactoringCore.getUndoManager();
Change undoChange;
boolean successful = false;
try {
manager.aboutToPerformChange(change);
undoChange = change.perform(new NullProgressMonitor());
successful = true;
} finally {
manager.changePerformed(change, successful);
}
if (undoChange != null) {
undoChange.initializeValidationData(new NullProgressMonitor());
manager.addUndo("OrganizeUseStatements", undoChange); //$NON-NLS-1$
}
}
} catch (MalformedTreeException | IOException e) {
PHPUiPlugin.log(e);
} finally {
monitor.done();
}
}
private boolean collectReferences(Program astRoot, List<Identifier> typeReferences,
Map<NamespaceDeclaration, Set<String>> oldSingleImports) {
List<NamespaceDeclaration> namespaces = astRoot.getNamespaceDeclarations();
if (namespaces.size() > 0) {
for (NamespaceDeclaration namespace : namespaces) {
collectImports(astRoot, namespace, oldSingleImports);
}
} else {
collectImports(astRoot, null, oldSingleImports);
}
astRoot.accept(new ReferencesCollector(typeReferences));
return true;
}
private void collectImports(Program astRoot, NamespaceDeclaration namespace,
Map<NamespaceDeclaration, Set<String>> oldSingleImports) {
oldSingleImports.put(namespace, new HashSet<>());
List<UseStatement> imports = astRoot.getUseStatements(namespace);
for (int i = 0; i < imports.size(); i++) {
UseStatement curr = imports.get(i);
for (UseStatementPart part : curr.parts()) {
String importName = part.getName().getName();
if (part.getAlias() != null) {
importName += " as " + part.getAlias().getName(); //$NON-NLS-1$
}
oldSingleImports.get(namespace).add(importName);
}
}
}
public int getNumberOfImportsAdded() {
return fNumberOfImportsAdded;
}
public int getNumberOfImportsRemoved() {
return fNumberOfImportsRemoved;
}
/**
* @return Returns the scheduling rule for this operation
*/
public ISchedulingRule getScheduleRule() {
return fSourceModule.getResource();
}
static class ReferencesCollector extends ApplyAll {
private static final List<String> TYPE_SKIP = new ArrayList<>();
static {
TYPE_SKIP.add("parent"); //$NON-NLS-1$
TYPE_SKIP.add("self"); //$NON-NLS-1$
TYPE_SKIP.add("static"); //$NON-NLS-1$
TYPE_SKIP.add("class"); //$NON-NLS-1$
}
List<Identifier> fTypeReferences;
public ReferencesCollector(List<Identifier> typeReferences) {
fTypeReferences = typeReferences;
}
@Override
protected boolean apply(ASTNode node) {
return true;
}
@Override
public boolean visit(UseStatement statement) {
return false;
}
@Override
public boolean visit(NamespaceName name) {
if (!name.isGlobal() && !(name.getParent() instanceof NamespaceDeclaration)) {
if (PHPSimpleTypes.isHintable(name.getName(), name.getAST().apiLevel())
|| TYPE_SKIP.contains(name.getName())) {
return false;
}
List<Identifier> segs = name.segments();
if (segs.size() > 0) {
Identifier node = segs.get(segs.size() - 1);
if (PHPElementConciliator.concile(node) == PHPElementConciliator.CONCILIATOR_CLASSNAME
|| PHPElementConciliator.concile(node) == PHPElementConciliator.CONCILIATOR_TRAITNAME) {
fTypeReferences.add(name);
}
}
}
return false;
}
@Override
public boolean visit(FunctionName functionName) {
return false;
}
@Override
public boolean visit(Scalar scalar) {
return false;
}
}
}