/******************************************************************************* * 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.*; import org.eclipse.core.runtime.CoreException; import org.eclipse.dltk.core.*; 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.internal.core.PHPCorePlugin; import org.eclipse.php.core.PHPVersion; 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.ClassMemberContext; import org.eclipse.php.internal.core.codeassist.contexts.ClassMemberContext.Trigger; import org.eclipse.php.internal.core.language.PHPMagicMethods; import org.eclipse.php.internal.core.typeinference.PHPModelUtils; /** * This strategy completes class methods * * @author michael */ public class ClassMethodsStrategy extends ClassMembersStrategy { public ClassMethodsStrategy(ICompletionContext context, IElementFilter elementFilter) { super(context, elementFilter); } public ClassMethodsStrategy(ICompletionContext context) { super(context); } public void apply(ICompletionReporter reporter) throws BadLocationException { ICompletionContext context = getContext(); if (!(context instanceof ClassMemberContext)) { return; } ClassMemberContext concreteContext = (ClassMemberContext) context; CompletionRequestor requestor = concreteContext.getCompletionRequestor(); String prefix = concreteContext.getPrefix().isEmpty() ? concreteContext.getPreviousWord() : concreteContext.getPrefix(); boolean isParentCall = isParentCall(concreteContext); String suffix = getSuffix(concreteContext); ISourceRange replaceRange = null; if (suffix.equals("")) { //$NON-NLS-1$ replaceRange = getReplacementRange(concreteContext); } else { replaceRange = getReplacementRangeWithBraces(concreteContext); } PHPVersion phpVersion = concreteContext.getPHPVersion(); Set<String> magicMethods = new HashSet<String>(); magicMethods.addAll(Arrays.asList(PHPMagicMethods.getMethods(phpVersion))); boolean exactName = requestor.isContextInformationMode(); // for methodName(|),we need set exactName to true if (!exactName && concreteContext.getOffset() - 1 >= 0 && concreteContext.getDocument().getChar(concreteContext.getOffset() - 1) == '(') { exactName = true; } List<IMethod> result = new LinkedList<IMethod>(); for (IType type : concreteContext.getLhsTypes()) { try { ITypeHierarchy hierarchy = getCompanion().getSuperTypeHierarchy(type, null); IMethod[] methods = isParentCall ? PHPModelUtils.getSuperTypeHierarchyMethod(type, hierarchy, prefix, exactName, null) : PHPModelUtils.getTypeHierarchyMethod(type, hierarchy, prefix, exactName, null); boolean inConstructor = isInConstructor(type, type.getMethods(), concreteContext); for (IMethod method : removeOverriddenElements(Arrays.asList(methods))) { if (concreteContext.isInUseTraitStatement()) { // result.add(method); reporter.reportMethod((IMethod) method, "", //$NON-NLS-1$ replaceRange, ProposalExtraInfo.METHOD_ONLY); } else if ((!PHPModelUtils.isConstructor(method) || inConstructor && isSuperConstructor(method, type, concreteContext)) && !isFiltered(method, type, concreteContext)) { if (magicMethods.contains(method.getElementName())) { reporter.reportMethod(method, suffix, replaceRange, ProposalExtraInfo.MAGIC_METHOD); } else { result.add(method); } } } } catch (CoreException e) { PHPCorePlugin.log(e); } } for (IMethod method : result) { reporter.reportMethod((IMethod) method, suffix, replaceRange); } } private boolean isInConstructor(IType type, IMethod[] methods, ClassMemberContext concreteContext) { try { for (int i = 0; i < methods.length; i++) { IMethod method = methods[i]; if (PHPModelUtils.isConstructor(method) && method.getDeclaringType().equals(type)) { ISourceRange constructorRange = method.getSourceRange(); if (concreteContext.getOffset() > constructorRange.getOffset() && concreteContext .getOffset() < constructorRange.getOffset() + constructorRange.getLength()) { return true; } } } } catch (ModelException e) { } return false; } private boolean isSuperConstructor(IMethod method, IType type, ClassMemberContext context) { if (PHPModelUtils.isConstructor(method) && context.getTriggerType() == Trigger.CLASS && isParent(context) && !method.getDeclaringType().equals(type)) { return true; } return false; } /** * is 'parent' keyword * * @param context * @return */ private boolean isParent(ClassMemberContext context) { return !isThisCall(context) && isParentCall(context) && isDirectParentCall(context); } // private IMethod getConstructor(IType type, IMethod[] methods) { // for (int i = 0; i < methods.length; i++) { // IMethod method = methods[i]; // if (PHPModelUtils.isConstructor(method)) { // return method; // } // } // // return null; // } protected boolean showNonStaticMembers(ClassMemberContext context) { return super.showNonStaticMembers(context) || context.getTriggerType() == Trigger.CLASS; } public String getSuffix(AbstractCompletionContext abstractContext) throws BadLocationException { // look for method bracket or end of line IDocument document = abstractContext.getDocument(); int offset = abstractContext.getOffset(); while (document.getLength() > offset) { char ch = document.getChar(offset); if (ch == '(') { break; } else if (ch == '\n') { return "()"; //$NON-NLS-1$ } offset++; } return ""; //$NON-NLS-1$ } }