/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.core.codeassist.strategies;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.compiler.env.IModuleSource;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.internal.core.ModelElement;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.php.core.codeassist.ICompletionContext;
import org.eclipse.php.core.codeassist.ICompletionReporter;
import org.eclipse.php.core.codeassist.IElementFilter;
import org.eclipse.php.core.compiler.ast.nodes.NamespaceReference;
import org.eclipse.php.core.compiler.ast.nodes.UsePart;
import org.eclipse.php.internal.core.PHPCoreConstants;
import org.eclipse.php.internal.core.PHPCorePlugin;
import org.eclipse.php.internal.core.codeassist.AliasField;
import org.eclipse.php.internal.core.codeassist.ProposalExtraInfo;
import org.eclipse.php.internal.core.codeassist.contexts.AbstractCompletionContext;
import org.eclipse.php.internal.core.codeassist.contexts.UseConstNameContext;
import org.eclipse.php.internal.core.model.PHPModelAccess;
import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
/**
* This strategy completes global constants
*
* @author michael
*/
public class GlobalConstantsStrategy extends GlobalElementStrategy {
public GlobalConstantsStrategy(ICompletionContext context, IElementFilter elementFilter) {
super(context, elementFilter);
}
public GlobalConstantsStrategy(ICompletionContext context) {
super(context);
}
public void apply(ICompletionReporter reporter) throws BadLocationException {
ICompletionContext context = getContext();
AbstractCompletionContext abstractContext = (AbstractCompletionContext) context;
CompletionRequestor requestor = abstractContext.getCompletionRequestor();
if (StringUtils.isBlank(abstractContext.getPrefixWithoutProcessing())) {
return;
}
String prefix = abstractContext.getPrefix();
if (prefix.startsWith("$")) { //$NON-NLS-1$
return;
}
boolean isUseConstContext = context instanceof UseConstNameContext;
int extraInfo = getExtraInfo();
if (isUseConstContext) {
extraInfo |= ProposalExtraInfo.NO_INSERT_USE;
extraInfo |= ProposalExtraInfo.FULL_NAME;
}
MatchRule matchRule = MatchRule.PREFIX;
if (requestor.isContextInformationMode()) {
matchRule = MatchRule.EXACT;
}
ISourceModule sourceModule = abstractContext.getSourceModule();
IType enclosingType = null;
try {
IModelElement enclosingElement = sourceModule.getElementAt(abstractContext.getOffset());
if (enclosingElement != null && enclosingElement instanceof IType) {
enclosingType = (IType) enclosingElement;
}
} catch (ModelException e) {
PHPCorePlugin.log(e);
}
IDLTKSearchScope scope = null;
IModelElement[] enclosingTypeConstants = null;
if (enclosingType != null && isStartOfStatement(prefix, abstractContext, abstractContext.getOffset())) {
// See the case of testClassStatement1.pdtt and
// testClassStatement2.pdtt
scope = SearchEngine.createSearchScope(enclosingType);
} else {
scope = getSearchScope(abstractContext);
}
enclosingTypeConstants = PHPModelAccess.getDefault().findFields(prefix, matchRule, Modifiers.AccConstant, 0,
scope, null);
if (isCaseSensitive()) {
enclosingTypeConstants = filterByCase(enclosingTypeConstants, prefix);
}
// workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=310383
enclosingTypeConstants = filterClassConstants(enclosingTypeConstants);
// workaround end
ISourceRange replaceRange = getReplacementRange(abstractContext);
for (IModelElement constant : enclosingTypeConstants) {
IField field = (IField) constant;
reporter.reportField(field, "", replaceRange, false, 0, extraInfo); //$NON-NLS-1$
}
addAlias(reporter);
}
protected void addAlias(ICompletionReporter reporter) throws BadLocationException {
ICompletionContext context = getContext();
AbstractCompletionContext abstractContext = (AbstractCompletionContext) context;
if (abstractContext.getCompletionRequestor().isContextInformationMode()) {
return;
}
String prefix = abstractContext.getPrefixWithoutProcessing();
if (prefix.indexOf(NamespaceReference.NAMESPACE_SEPARATOR) != -1) {
return;
}
IModuleSource module = reporter.getModule();
org.eclipse.dltk.core.ISourceModule sourceModule = (org.eclipse.dltk.core.ISourceModule) module
.getModelElement();
ModuleDeclaration moduleDeclaration = SourceParserUtil.getModuleDeclaration(sourceModule);
final int offset = abstractContext.getOffset();
IType namespace = PHPModelUtils.getCurrentNamespace(sourceModule, offset);
final Map<String, UsePart> result = PHPModelUtils.getAliasToNSMap(prefix, moduleDeclaration, offset, namespace,
false);
reportAlias(reporter, abstractContext, module, result);
}
protected void reportAlias(ICompletionReporter reporter, AbstractCompletionContext abstractContext,
IModuleSource module, final Map<String, UsePart> result) throws BadLocationException {
ISourceRange replacementRange = getReplacementRange(abstractContext);
IDLTKSearchScope scope = createSearchScope();
for (Entry<String, UsePart> entry : result.entrySet()) {
String name = entry.getKey();
String fullName = entry.getValue().getNamespace().getFullyQualifiedName();
if (fullName.startsWith(NamespaceReference.NAMESPACE_DELIMITER)) {
fullName = fullName.substring(1);
}
IField[] elements = PHPModelAccess.getDefault().findFields(null, fullName, MatchRule.PREFIX, 0, 0, scope,
null);
for (int i = 0; i < elements.length; i++) {
String elementName = elements[i].getElementName();
reportAlias(reporter, scope, module, replacementRange, elements[i], elementName,
elementName.replace(fullName, name));
}
elements = PHPModelAccess.getDefault().findFields(fullName, MatchRule.EXACT, 0, 0, scope, null);
for (int i = 0; i < elements.length; i++) {
String elementName = elements[i].getElementName();
reportAlias(reporter, scope, module, replacementRange, elements[i], elementName, name);
}
}
}
protected void reportAlias(ICompletionReporter reporter, IDLTKSearchScope scope, IModuleSource module,
ISourceRange replacementRange, IMember member, String fullName, String alias) {
reporter.reportField(new AliasField((ModelElement) member, fullName, alias), "", replacementRange, false, 0, //$NON-NLS-1$
getExtraInfo());
}
private boolean isStartOfStatement(String prefix, AbstractCompletionContext abstractContext, int offset) {
IDocument doc = abstractContext.getDocument();
try {
int pos = offset - prefix.length() - 1;
char previousChar = doc.getChar(pos);
while (Character.isWhitespace(previousChar)) {
pos--;
previousChar = doc.getChar(pos);
}
return previousChar == '{' || previousChar == ';';
} catch (BadLocationException e) {
}
return false;
}
private IModelElement[] filterClassConstants(IModelElement[] elements) {
List<IModelElement> result = new ArrayList<IModelElement>(elements.length);
for (IModelElement element : elements) {
try {
if ((((IField) element).getFlags() & PHPCoreConstants.AccClassField) == 0) {
result.add(element);
}
} catch (ModelException e) {
PHPCorePlugin.log(e);
}
}
return (IModelElement[]) result.toArray(new IModelElement[result.size()]);
}
protected int getExtraInfo() {
return ProposalExtraInfo.DEFAULT;
}
private IDLTKSearchScope getSearchScope(AbstractCompletionContext abstractContext) {
IDLTKSearchScope scope = createSearchScope();
return scope;
}
}