Skip to content

Loading…

Improve code assist #197

Merged
merged 2 commits into from

2 participants

@zulus
Collaborator

CA and Goal evaluators require Controller class or ContainerAware interface in parent hierarchy.
This change require pulse00/Doctrine-Eclipse-Plugin#9

@zulus
Collaborator

This code:

$this->get('my_service')->| // works ok and always
$this->get('my_service')->serviceMethod()->chainCall()->|; // not work

Reason: getCompletion()->getLeftHandType() is using CodeAssistUtils.getTypesFor().
This method ignore method call arguments. I'll try fix it in PDT 3.3 ;)

@pulse00
Owner

@zulus great, thanks a lot!

@pulse00 pulse00 merged commit 262a492 into pulse00:master

1 check passed

Details default The Travis CI build passed
@zulus zulus deleted the unknown repository branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 3, 2014
  1. @zulus

    Improve code assist

    zulus committed
  2. @zulus

    Filter private methods

    zulus committed
    Service type goal
Showing with 475 additions and 201 deletions.
  1. +73 −22 ...bture.symfony.core/src/com/dubture/symfony/core/codeassist/contexts/ServiceReturnTypeContext.java
  2. +26 −25 ....core/src/com/dubture/symfony/core/codeassist/strategies/ServiceReturnTypeCompletionStrategy.java
  3. +25 −47 com.dubture.symfony.core/src/com/dubture/symfony/core/goals/ContainerAwareGoalEvaluatorFactory.java
  4. +47 −0 com.dubture.symfony.core/src/com/dubture/symfony/core/goals/ServiceTypeGoal.java
  5. +112 −20 com.dubture.symfony.core/src/com/dubture/symfony/core/goals/evaluator/ServiceGoalEvaluator.java
  6. +53 −0 com.dubture.symfony.core/src/com/dubture/symfony/core/goals/evaluator/ServiceTypeGoalEvaluator.java
  7. +5 −1 com.dubture.symfony.core/src/com/dubture/symfony/core/preferences/SymfonyCoreConstants.java
  8. +103 −79 com.dubture.symfony.core/src/com/dubture/symfony/core/util/text/SymfonyTextSequenceUtilities.java
  9. +4 −0 com.dubture.symfony.test/workspace/services/ContainerInterface.php
  10. +6 −0 com.dubture.symfony.test/workspace/services/Controller.php
  11. +1 −1 com.dubture.symfony.test/workspace/services/testChainedServiceCompletion.pdtt
  12. +1 −1 com.dubture.symfony.test/workspace/services/testParameterizedServiceMethodCompletion.pdtt
  13. +1 −1 com.dubture.symfony.test/workspace/services/testServiceIdCompletion.pdtt
  14. +3 −2 com.dubture.symfony.test/workspace/services/testServiceMethodCompletion.pdtt
  15. +14 −0 com.dubture.symfony.test/workspace/services/testServiceMethodCompletion2.pdtt
  16. +1 −2 ...bture.symfony.ui/src/com/dubture/symfony/ui/contentassist/SymfonyCompletionProposalCollector.java
View
95 ...mfony.core/src/com/dubture/symfony/core/codeassist/contexts/ServiceReturnTypeContext.java
@@ -1,8 +1,8 @@
/*******************************************************************************
* This file is part of the Symfony eclipse plugin.
- *
+ *
* (c) Robert Gruendler <r.gruendler@gmail.com>
- *
+ *
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
******************************************************************************/
@@ -12,27 +12,34 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.dltk.core.CompletionRequestor;
import org.eclipse.dltk.core.ISourceModule;
+import org.eclipse.dltk.core.IType;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.php.internal.core.codeassist.CodeAssistUtils;
import org.eclipse.php.internal.core.codeassist.contexts.ClassMemberContext;
+import org.eclipse.php.internal.core.format.PHPHeuristicScanner;
+import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
+import org.eclipse.php.internal.core.util.text.PHPTextSequenceUtilities;
+import org.eclipse.php.internal.core.util.text.TextSequence;
import com.dubture.symfony.core.builder.SymfonyNature;
import com.dubture.symfony.core.log.Logger;
+import com.dubture.symfony.core.preferences.SymfonyCoreConstants;
import com.dubture.symfony.core.util.text.SymfonyTextSequenceUtilities;
-
/**
- *
+ *
* A context which is valid when completing services directly from
* the DI container:
- *
- *
+ *
+ *
* <pre>
- *
+ *
* $em = $this->get('doctrine')-> |
- *
+ *
* </pre>
- *
- *
- *
+ *
+ *
+ *
* @author Robert Gruendler <r.gruendler@gmail.com>
*
*/
@@ -44,26 +51,70 @@
public boolean isValid(ISourceModule sourceModule, int offset,
CompletionRequestor requestor) {
- if (super.isValid(sourceModule, offset, requestor))
- {
-
+ if (super.isValid(sourceModule, offset, requestor))
+ {
+
try {
-
- IProjectNature nature;
+ IProjectNature nature;
nature = sourceModule.getScriptProject().getProject().getNature(SymfonyNature.NATURE_ID);
-
+
// wrong nature
if(!(nature instanceof SymfonyNature)) {
- return false;
+ return false;
+ }
+ // Check function name
+ if (SymfonyTextSequenceUtilities.isGetFunction(getStatementText()) == -1) {
+ return false;
+ }
+
+ TextSequence statementText = getStatementText();
+ int totalLength = statementText.length();
+ int elementStart = PHPTextSequenceUtilities.readBackwardSpaces(
+ statementText, totalLength);
+ elementStart = PHPTextSequenceUtilities.readIdentifierStartIndex(
+ statementText, elementStart, true);
+ elementStart = PHPTextSequenceUtilities.readBackwardSpaces(
+ statementText, elementStart);
+ elementStart-=3;
+ if (statementText.charAt(elementStart) != ')') { //
+ return false;
+ }
+
+ // find get()
+ PHPHeuristicScanner scanner = PHPHeuristicScanner.createHeuristicScanner(getDocument(), offset - statementText.length() + elementStart-1, true);
+ int open = scanner.findOpeningPeer(offset - statementText.length() + elementStart-1, PHPHeuristicScanner.UNBOUND, PHPHeuristicScanner.LPAREN, PHPHeuristicScanner.RPAREN);
+ statementText = getStatementText(open);
+ totalLength = statementText.length();
+ elementStart = PHPTextSequenceUtilities.readBackwardSpaces(
+ statementText, totalLength);
+ elementStart = PHPTextSequenceUtilities.readIdentifierStartIndex(
+ statementText, elementStart, true);
+
+
+ // read lhs types
+ IType[] lhsTypes = CodeAssistUtils.getTypesFor(getSourceModule(), statementText, elementStart, open);
+
+ for (IType type : lhsTypes) {
+ if (type.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTAINER_INTERFACE) || type.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTROLLER_PARENT)) {
+ return true;
+ }
+
+ IType[] superClasses = PHPModelUtils.getSuperClasses(type, getCompanion().getSuperTypeHierarchy(type, null));
+ for (IType sc : superClasses) {
+ if (sc.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTAINER_INTERFACE) || sc.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTROLLER_PARENT)) {
+ return true;
+ }
+ }
}
-
- return SymfonyTextSequenceUtilities.isInServiceContainerFunction(getStatementText()) > -1;
-
+
} catch (CoreException e) {
Logger.logException(e);
+ } catch (BadLocationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
}
}
-
+
return false;
}
}
View
51 ...c/com/dubture/symfony/core/codeassist/strategies/ServiceReturnTypeCompletionStrategy.java
@@ -1,8 +1,8 @@
/*******************************************************************************
* This file is part of the Symfony eclipse plugin.
- *
+ *
* (c) Robert Gruendler <r.gruendler@gmail.com>
- *
+ *
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
******************************************************************************/
@@ -20,11 +20,13 @@
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.internal.core.SourceRange;
import org.eclipse.php.core.codeassist.ICompletionContext;
+import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.internal.core.codeassist.CodeAssistUtils;
import org.eclipse.php.internal.core.codeassist.ICompletionReporter;
import org.eclipse.php.internal.core.codeassist.contexts.AbstractCompletionContext;
import org.eclipse.php.internal.core.codeassist.strategies.ClassMembersStrategy;
import org.eclipse.php.internal.core.model.PhpModelAccess;
+import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
import com.dubture.symfony.core.codeassist.contexts.ServiceReturnTypeContext;
import com.dubture.symfony.core.model.Service;
@@ -32,14 +34,14 @@
import com.dubture.symfony.core.util.text.SymfonyTextSequenceUtilities;
/**
- *
+ *
* A completionstrategy that reports methods from a service returned
* by the DI container.
- *
- *
+ *
+ *
* @see ServiceReturnTypeContext
- *
- *
+ *
+ *
* @author Robert Gruendler <r.gruendler@gmail.com>
*
*/
@@ -51,7 +53,6 @@
public ServiceReturnTypeCompletionStrategy(ICompletionContext context) {
super(context);
-
}
@Override
@@ -60,10 +61,10 @@ public void apply(ICompletionReporter reporter) throws Exception {
ServiceReturnTypeContext context = (ServiceReturnTypeContext) getContext();
IScriptProject project = context.getSourceModule().getScriptProject();
String source = SymfonyTextSequenceUtilities.getServiceFromMethodParam(context.getStatementText());
-
+
if (source == null)
return;
-
+
Service service = SymfonyModelAccess.getDefault().findService(source, project.getPath());
if (service == null) {
return;
@@ -74,33 +75,33 @@ public void apply(ICompletionReporter reporter) throws Exception {
// if that's possible.
//
// this way, we could avoid the SearchEngine call here
-
+
String namespace = service.getSimpleNamespace();
IType[] types = getTypes(context, service.getClassName(), namespace);
-
+
if (types.length != 1) {
return;
}
-
- IType type = types[0];
- SourceRange range = getReplacementRange(context);
+
+ IType type = types[0];
+ SourceRange range = getReplacementRange(context);
String prefix = context.getPrefix();
-
- for(IMethod method : type.getMethods()) {
- if (CodeAssistUtils.startsWithIgnoreCase(method.getElementName(), prefix)) {
- reporter.reportMethod(method, "", range);
- }
+
+ for(IMethod method : type.getMethods()) {
+ if (!PHPModelUtils.isConstructor(method) && PHPFlags.isPublic(method.getFlags()) && CodeAssistUtils.startsWithIgnoreCase(method.getElementName(), prefix)) {
+ reporter.reportMethod(method, "", range);
+ }
}
}
-
+
private IType[] getTypes(AbstractCompletionContext context, String prefix, String pkg) {
-
+
IDLTKSearchScope scope = createSearchScope();
List<IType> result = new LinkedList<IType>();
IType[] types = PhpModelAccess.getDefault().findTypes(pkg, prefix,
MatchRule.EXACT, trueFlag, falseFlag, scope, null);
result.addAll(Arrays.asList(types));
-
- return (IType[]) result.toArray(new IType[result.size()]);
- }
+
+ return (IType[]) result.toArray(new IType[result.size()]);
+ }
}
View
72 ...e.symfony.core/src/com/dubture/symfony/core/goals/ContainerAwareGoalEvaluatorFactory.java
@@ -10,20 +10,22 @@
import java.util.List;
+import org.eclipse.core.resources.IProjectNature;
import org.eclipse.dltk.ast.ASTNode;
-import org.eclipse.dltk.ast.references.VariableReference;
import org.eclipse.dltk.ti.IGoalEvaluatorFactory;
+import org.eclipse.dltk.ti.ISourceModuleContext;
import org.eclipse.dltk.ti.goals.ExpressionTypeGoal;
import org.eclipse.dltk.ti.goals.GoalEvaluator;
import org.eclipse.dltk.ti.goals.IGoal;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPCallExpression;
import org.eclipse.php.internal.core.compiler.ast.nodes.Scalar;
+import org.eclipse.php.internal.core.compiler.ast.parser.ASTUtils;
import org.eclipse.php.internal.core.typeinference.context.MethodContext;
import org.eclipse.php.internal.core.typeinference.goals.phpdoc.PHPDocMethodReturnTypeGoal;
+import com.dubture.symfony.core.builder.SymfonyNature;
import com.dubture.symfony.core.goals.evaluator.ServiceGoalEvaluator;
-import com.dubture.symfony.core.model.Service;
-import com.dubture.symfony.core.model.SymfonyModelAccess;
+import com.dubture.symfony.core.goals.evaluator.ServiceTypeGoalEvaluator;
/**
@@ -52,13 +54,17 @@ public GoalEvaluator createEvaluator(IGoal goal) {
try {
this.goal = goal;
- //TODO: find a way to check project nature
- // and return null if it's not a symfonyNature
- // goal.getContext().getLangNature() always returns the PHPNature...
- GoalEvaluator evaluator = evaluateServiceCalls(goal);
-
+ if (goal.getContext() instanceof ISourceModuleContext) {
+ ISourceModuleContext context = (ISourceModuleContext) goal.getContext();
+ IProjectNature nature = context.getSourceModule().getScriptProject().getProject().getNature(SymfonyNature.NATURE_ID);
+ if(!(nature instanceof SymfonyNature)) {
+ return null;
+ }
+ } else {
+ return null;
+ }
//TODO: add more evaluators...
- return evaluator;
+ return evaluateServiceCalls(goal);
} catch (Exception e) {
return null;
@@ -91,49 +97,24 @@ private GoalEvaluator evaluateServiceCalls(IGoal goal) {
// MethodContext context = (MethodContext) goal.getContext();
// PHPClassType classType = (PHPClassType) context.getInstanceType();
-
if (goalClass == ExpressionTypeGoal.class) {
-
-
ExpressionTypeGoal expGoal = (ExpressionTypeGoal) goal;
ASTNode expression = expGoal.getExpression();
// we're inside a call expression in the form $em->|
if (expression instanceof PHPCallExpression) {
-
-
-
PHPCallExpression exp = (PHPCallExpression) expression;
- ASTNode receiver = exp.getReceiver();
-
// are we calling a method named "get" ?
- if (exp.getName().equals("get") && receiver instanceof VariableReference) {
-
- VariableReference ref = (VariableReference) receiver;
-
- // is the receiver an object instance ?
- if (ref.getName().equals("$this")) {
- return getEvaluator(exp);
- }
- } else if (exp.getName().equals("get") && receiver instanceof PHPCallExpression) {
-
- PHPCallExpression call = (PHPCallExpression) receiver;
-
- if (call.getName().equals("getContainer")) {
- return getEvaluator(exp);
- }
+ if (exp.getName().equals("get")) {
+ return getEvaluator(exp);
}
}
// we're checking a PHPDocMethodReturnTypeGoal like $em = $this->get('doctrine')->|
// to support fluent interfaces.
- } else if (goalClass == PHPDocMethodReturnTypeGoal.class) {
-
-// PHPDocMethodReturnTypeGoal mGoal = (PHPDocMethodReturnTypeGoal) goal;
-// if (mGoal.getMethodName().equals("get")) {
-// return new ContainerMethodReturnTypeEvaluator(mGoal);
-// }
+ } else if (goalClass == ServiceTypeGoal.class) {
+ return new ServiceTypeGoalEvaluator((ServiceTypeGoal)goal);
}
// Give the control to the default PHP goal evaluator
@@ -146,21 +127,18 @@ private ServiceGoalEvaluator getEvaluator(PHPCallExpression exp) {
List args = exp.getArgs().getChilds();
- // does the get() method have exact one argument?
- if (args.size() == 1) {
+ // does the get() method have minimum one argument?
+ if (args.size() >= 1) {
Object first = args.get(0);
-
+ // TODO resolve quotes
if (first instanceof Scalar && ((Scalar)first).getScalarType() == Scalar.TYPE_STRING) {
- //TODO: check if there are PDT utils for stripping away quotes from
- // string literals.
- String className = ((Scalar)first).getValue().replace("'", "").replace("\"", "");
- Service service = SymfonyModelAccess.getDefault().findService(className,context.getSourceModule().getScriptProject().getPath());
+ String serviceName = ASTUtils.stripQuotes(((Scalar)first).getValue());
// we got a service match, return the goalevaluator.
- if (service != null) {
- return new ServiceGoalEvaluator(goal, service);
+ if (serviceName != null) {
+ return new ServiceGoalEvaluator(goal, serviceName);
}
}
}
View
47 com.dubture.symfony.core/src/com/dubture/symfony/core/goals/ServiceTypeGoal.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * This file is part of the Symfony eclipse plugin.
+ *
+ * (c) Dawid Pakuła <zulus@w3des.net>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ ******************************************************************************/
+package com.dubture.symfony.core.goals;
+
+import org.eclipse.dltk.ti.IContext;
+import org.eclipse.dltk.ti.goals.AbstractGoal;
+
+public class ServiceTypeGoal extends AbstractGoal{
+
+
+ private final String serviceId;
+
+ public ServiceTypeGoal(IContext context, String serviceId) {
+ super(context);
+ assert serviceId != null;
+ this.serviceId = serviceId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ } else if (!super.equals(obj)) {
+ return false;
+ } else if (this.getClass() != obj.getClass()) {
+ return false;
+ }
+
+ return serviceId.equals(((ServiceTypeGoal) obj).getServiceId());
+ }
+
+ @Override
+ public int hashCode() {
+ return 41 * super.hashCode() + serviceId.hashCode();
+ }
+
+ public String getServiceId() {
+ return serviceId;
+ }
+
+}
View
132 ...bture.symfony.core/src/com/dubture/symfony/core/goals/evaluator/ServiceGoalEvaluator.java
@@ -1,58 +1,150 @@
/*******************************************************************************
* This file is part of the Symfony eclipse plugin.
- *
+ *
* (c) Robert Gruendler <r.gruendler@gmail.com>
- *
+ *
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
******************************************************************************/
package com.dubture.symfony.core.goals.evaluator;
+import org.eclipse.dltk.ast.ASTNode;
+import org.eclipse.dltk.ast.expressions.CallExpression;
+import org.eclipse.dltk.core.ISourceModule;
+import org.eclipse.dltk.core.IType;
+import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.ti.GoalState;
+import org.eclipse.dltk.ti.ISourceModuleContext;
+import org.eclipse.dltk.ti.goals.ExpressionTypeGoal;
import org.eclipse.dltk.ti.goals.GoalEvaluator;
import org.eclipse.dltk.ti.goals.IGoal;
-import org.eclipse.php.internal.core.typeinference.PHPClassType;
+import org.eclipse.dltk.ti.types.IEvaluatedType;
+import org.eclipse.php.internal.core.typeinference.IModelAccessCache;
+import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
+import org.eclipse.php.internal.core.typeinference.context.IModelCacheContext;
-import com.dubture.symfony.core.model.Service;
+import com.dubture.symfony.core.goals.ServiceTypeGoal;
+import com.dubture.symfony.core.log.Logger;
+import com.dubture.symfony.core.preferences.SymfonyCoreConstants;
/**
- *
- *
- *
- * @author Robert Gruendler <r.gruendler@gmail.com>
*
+ * @author Robert Gruendler <r.gruendler@gmail.com>
*/
@SuppressWarnings("restriction")
public class ServiceGoalEvaluator extends GoalEvaluator {
- private Service service;
-
+ private ISourceModule sourceModule;
+
+ private final static int STATE_INIT = 0;
+ private final static int STATE_WAITING_RECEIVER = 1;
+ private final static int STATE_GOT_RECEIVER = 2;
+ private final static int STATE_WAITING_SERVICE_TYPE = 3;
+ private final static int STATE_GOT_SERVICE_TYPE = 4;
+
+ private IEvaluatedType receiverType;
+ private IEvaluatedType result;
- public ServiceGoalEvaluator(IGoal goal, Service service) {
+ private int state = STATE_INIT;
+
+ private String serviceName;
+
+ public ServiceGoalEvaluator(IGoal goal, String serviceName) {
super(goal);
- this.service = service;
+ this.serviceName = serviceName;
+ if (goal.getContext() instanceof ISourceModuleContext) {
+ sourceModule = ((ISourceModuleContext)goal.getContext()).getSourceModule();
+ }
}
@Override
public IGoal[] init() {
+ IGoal goal = produceNextSubgoal(null, null, null);
+ if (goal != null) {
+ return new IGoal[] { goal };
+ }
+ return IGoal.NO_GOALS;
+ }
+
+ private IGoal produceNextSubgoal(IGoal previousGoal,
+ IEvaluatedType previousResult, GoalState goalState) {
+ ExpressionTypeGoal typedGoal = (ExpressionTypeGoal) goal;
+ CallExpression expression = (CallExpression) typedGoal.getExpression();
+ if (sourceModule == null) {
+ return null;
+ }
+ // just starting to evaluate method, evaluate method receiver first:
+ if (state == STATE_INIT) {
+ ASTNode receiver = expression.getReceiver();
+ if (receiver == null) {
+ state = STATE_GOT_RECEIVER;
+ } else {
+ state = STATE_WAITING_RECEIVER;
+ return new ExpressionTypeGoal(goal.getContext(), receiver);
+ }
+ }
+
+ if (state == STATE_WAITING_RECEIVER) {
+ receiverType = previousResult;
+ previousResult = null;
+ if (receiverType == null) {
+ return null;
+ }
+ state = STATE_GOT_RECEIVER;
+ }
+
+ if (state == STATE_GOT_RECEIVER && receiverType != null) {
+ if (receiverType.getTypeName().equals(SymfonyCoreConstants.CONTAINER_INTERFACE) || receiverType.getTypeName().equals(SymfonyCoreConstants.CONTROLLER_PARENT)) {
+ return generateServiceTypeGoal();
+ } else {
+ IModelAccessCache accessCache = null;
+ if (goal.getContext() instanceof IModelCacheContext) {
+ accessCache = ((IModelCacheContext)goal.getContext()).getCache();
+ }
+ try {
+ IType[] types = PHPModelUtils.getTypes(receiverType.getTypeName(), sourceModule, 0, accessCache, null);
+ for (IType type : types) {
+ if (type.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTAINER_INTERFACE) || type.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTROLLER_PARENT)) {
+ return generateServiceTypeGoal();
+ }
+ IType[] superClasses = PHPModelUtils.getSuperClasses(type, accessCache != null ? accessCache.getSuperTypeHierarchy(type, null) : null);
+ for (IType sc : superClasses) {
+ if (sc.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTAINER_INTERFACE) || sc.getFullyQualifiedName("\\").equals(SymfonyCoreConstants.CONTROLLER_PARENT)) {
+ return generateServiceTypeGoal();
+ }
+ }
+
+ }
+ } catch (ModelException e) {
+ Logger.logException(e);
+ }
+ }
+ }
+ if (state == STATE_WAITING_SERVICE_TYPE) {
+ result = previousResult;
+ state = STATE_GOT_SERVICE_TYPE;
+ }
return null;
}
+ private IGoal generateServiceTypeGoal() {
+ state = STATE_WAITING_SERVICE_TYPE;
+ return new ServiceTypeGoal(goal.getContext(), serviceName);
+ }
+
@Override
public IGoal[] subGoalDone(IGoal subgoal, Object result, GoalState state) {
-
+ IGoal goal = produceNextSubgoal(subgoal, (IEvaluatedType) result, state);
+ if (goal != null) {
+ return new IGoal[] { goal };
+ }
return IGoal.NO_GOALS;
}
-
+
@Override
public Object produceResult() {
-
- if (service == null)
- return null;
-
- return new PHPClassType(service.getFullyQualifiedName());
-
+ return result;
}
}
View
53 ...e.symfony.core/src/com/dubture/symfony/core/goals/evaluator/ServiceTypeGoalEvaluator.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+
+ * This file is part of the Symfony eclipse plugin.
+ *
+ * (c) Dawid Pakuła <zulus@w3des.net>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ ******************************************************************************/
+package com.dubture.symfony.core.goals.evaluator;
+
+import org.eclipse.dltk.ti.GoalState;
+import org.eclipse.dltk.ti.ISourceModuleContext;
+import org.eclipse.dltk.ti.goals.IGoal;
+import org.eclipse.dltk.ti.types.IEvaluatedType;
+import org.eclipse.php.internal.core.typeinference.PHPClassType;
+import org.eclipse.php.internal.core.typeinference.evaluators.AbstractPHPGoalEvaluator;
+
+import com.dubture.symfony.core.goals.ServiceTypeGoal;
+import com.dubture.symfony.core.model.Service;
+import com.dubture.symfony.core.model.SymfonyModelAccess;
+
+@SuppressWarnings("restriction")
+public class ServiceTypeGoalEvaluator extends AbstractPHPGoalEvaluator {
+ protected ServiceTypeGoal goal;
+ private IEvaluatedType result = null;
+
+ public ServiceTypeGoalEvaluator(ServiceTypeGoal goal) {
+ super(goal);
+ this.goal = goal;
+
+ }
+
+ @Override
+ public IGoal[] init() {
+ if (goal.getContext() instanceof ISourceModuleContext) {
+ Service findService = SymfonyModelAccess.getDefault().findService(goal.getServiceId(),((ISourceModuleContext)goal.getContext()).getSourceModule().getScriptProject().getPath());
+ if (findService != null)
+ result = new PHPClassType(findService.getFullyQualifiedName());
+ }
+ return IGoal.NO_GOALS;
+ }
+
+ @Override
+ public Object produceResult() {
+ return result;
+ }
+
+ @Override
+ public IGoal[] subGoalDone(IGoal subgoal, Object result, GoalState state) {
+ return IGoal.NO_GOALS;
+ }
+}
View
6 com.dubture.symfony.core/src/com/dubture/symfony/core/preferences/SymfonyCoreConstants.java
@@ -64,7 +64,7 @@
public static final String VENDOR_PATH = "vendor";
public static final String CACHE_PATH = "app/cache";
public static final String LOG_PATH = "app/logs";
-
+
public static final String CACHE_PATTERN = "**/cache/";
public static final String LOG_PATTERN = "**/logs/";
public static final String SKELETON_PATTERN = "**/skeleton/";
@@ -85,6 +85,10 @@
public static final String SYMFONY_STANDARD_EDITION = "symfony/framework-standard-edition";
+ public static final String CONTROLLER_PARENT = "Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller";
+
+ public static final String CONTAINER_INTERFACE = "Symfony\\Component\\DependencyInjection\\ContainerInterface";
+
}
View
182 ...ure.symfony.core/src/com/dubture/symfony/core/util/text/SymfonyTextSequenceUtilities.java
@@ -1,8 +1,8 @@
/*******************************************************************************
* This file is part of the Symfony eclipse plugin.
- *
+ *
* (c) Robert Gruendler <r.gruendler@gmail.com>
- *
+ *
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
******************************************************************************/
@@ -19,24 +19,24 @@
/**
- *
+ *
* {@link SymfonyTextSequenceUtilities} is a utility class for {@link TextSequence}.
* Use it to check if you're inside a special pattern - ie. a servicecontainer
* getter function function like:
- *
+ *
* <pre>
- *
+ *
* $this->get(|
- *
- * or
- *
+ *
+ * or
+ *
* $this->container->get('
- *
+ *
* </pre>
- *
- *
+ *
+ *
* @see PHPTextSequenceUtilities
- *
+ *
* @author Robert Gruendler <r.gruendler@gmail.com>
*
*/
@@ -44,10 +44,12 @@
public class SymfonyTextSequenceUtilities {
private static final Pattern SERVICE_PATTERN = Pattern.compile("(\\$this->get\\(|\\$this->container->get\\(|->getContainer\\(\\)->get\\()");
-
- private static final Pattern REPOSITORY_PATTERN = Pattern.compile("\\->getRepository\\(");
-
- private static final Pattern TRANSLATION_PATTERN = Pattern.compile("(\\->transChoice\\(|\\->trans\\()");
+
+ private static final Pattern GET_PATTERN = Pattern.compile("(->get\\()");
+
+ private static final Pattern REPOSITORY_PATTERN = Pattern.compile("\\->getRepository\\(");
+
+ private static final Pattern TRANSLATION_PATTERN = Pattern.compile("(\\->transChoice\\(|\\->trans\\()");
private SymfonyTextSequenceUtilities() {
@@ -56,19 +58,19 @@ private SymfonyTextSequenceUtilities() {
/**
* Retrieve the startOffset of a ViewPath inside a textSeauence
- *
- *
+ *
+ *
* @param textSequence
* @return
*/
public static int readViewPathStartIndex(CharSequence textSequence) {
- int startPosition = textSequence.length() -1;
+ int startPosition = textSequence.length() -1;
return readLiteralStartIndex(textSequence, startPosition);
}
-
-
+
+
/**
* Checks for the existance of a service container function, ie. $this->get( or $this->container->get(
* @param sequence
@@ -78,7 +80,7 @@ public static int isInServiceContainerFunction(CharSequence sequence) {
Matcher matcher = SERVICE_PATTERN.matcher(sequence);
- while (matcher.find()) {
+ while (matcher.find()) {
int pos = matcher.end();
@@ -89,24 +91,46 @@ public static int isInServiceContainerFunction(CharSequence sequence) {
return pos;
}
- return -1;
+ return -1;
+ }
+ /**
+ * Checks for the existance of a get function, ie. ->get(
+ * @param sequence
+ * @return
+ */
+ public static int isGetFunction(CharSequence sequence) {
+
+ Matcher matcher = GET_PATTERN.matcher(sequence);
+
+ while (matcher.find()) {
+
+ int pos = matcher.end();
+
+ int lastMethodCall = sequence.toString().lastIndexOf("(");
+
+ if (lastMethodCall > pos)
+ return -1;
+
+ return pos;
+ }
+ return -1;
}
-
-
+
+
/**
* Check if the sequence is a method call for a doctrine repository ie
- *
+ *
* $this->getDoctrine()->getRepository(|
- *
+ *
* @param sequence
* @return
*/
public static int isInEntityFunctionParameter(CharSequence sequence) {
-
+
Matcher matcher = REPOSITORY_PATTERN.matcher(sequence);
- while (matcher.find()) {
+ while (matcher.find()) {
int pos = matcher.end();
@@ -117,18 +141,18 @@ public static int isInEntityFunctionParameter(CharSequence sequence) {
return pos;
}
- return -1;
-
-
-
+ return -1;
+
+
+
}
-
-
+
+
public static int isInTranslationFunctionParameter(CharSequence sequence) {
-
+
Matcher matcher = TRANSLATION_PATTERN.matcher(sequence);
- while (matcher.find()) {
+ while (matcher.find()) {
int pos = matcher.end();
@@ -139,8 +163,8 @@ public static int isInTranslationFunctionParameter(CharSequence sequence) {
return pos;
}
- return -1;
-
+ return -1;
+
}
public static String removeQuotes(String source) {
@@ -149,11 +173,11 @@ public static String removeQuotes(String source) {
}
-
+
/**
* Retrieve the service name from a PHP method call,
* ie: $this->get('session') will return the session literal.
- *
+ *
* @param sequence
* @return
*/
@@ -168,46 +192,46 @@ public static String getServiceFromMethodParam(TextSequence sequence) {
return null;
- return removeQuotes(source.substring(start, end));
+ return removeQuotes(source.substring(start, end));
}
-
-
+
+
/**
- *
+ *
* Extract the methodName of a TextSequence, ie,
- *
- * "$this->generate('" will return generate
- *
+ *
+ * "$this->generate('" will return generate
+ *
* @param statement
* @return
*/
public static String getMethodName(CharSequence statement) {
-
+
String text = statement.toString();
-
+
int start = text.indexOf("->");
int end = text.lastIndexOf("(");
-
+
int current = end;
-
+
while( current > 0 && current > start) {
- char c = text.charAt(current--);
+ char c = text.charAt(current--);
if (c == '>') {
- return text.substring(current+2, end);
+ return text.substring(current+2, end);
}
}
-
+
return null;
-
-
+
+
}
/**
* Check if the TextSequence is inside PHP method accepting
- * viewPath parameters.
- *
+ * viewPath parameters.
+ *
* @param statement
* @param project
* @return
@@ -215,10 +239,10 @@ public static String getMethodName(CharSequence statement) {
public static boolean isInViewPathFunctionParameter(TextSequence statement, IScriptProject project) {
String method = getMethodName(statement);
-
+
if (method == null)
return false;
-
+
return SymfonyModelAccess.getDefault().hasViewMethod(method, project);
}
@@ -226,36 +250,36 @@ public static boolean isInViewPathFunctionParameter(TextSequence statement, IScr
/**
* Check if the TextSequence is a function which accept route parameters.
- *
- *
+ *
+ *
* @param statement
* @param project
* @return
*/
public static boolean isInRouteFunctionParameter(TextSequence statement,
IScriptProject project) {
-
+
String method = getMethodName(statement);
if (method == null)
return false;
-
-
+
+
return SymfonyModelAccess.getDefault().hasRouteMethod(method, project);
}
-
-
+
+
/**
- *
+ *
* Read to the start index of a String literal.
- *
+ *
* @param textSequence
* @param startPosition
* @return
*/
public static int readLiteralStartIndex(CharSequence textSequence, int startPosition) {
-
+
while (startPosition > 0) {
char ch = textSequence.charAt(startPosition - 1);
@@ -270,25 +294,25 @@ public static int readLiteralStartIndex(CharSequence textSequence, int startPosi
}
- return startPosition;
-
+ return startPosition;
+
}
-
+
/**
- *
+ *
* Read to the end index of a String literal.
- *
+ *
* @param textSequence
* @param startPosition
* @return
*/
public static int readLiteralEndIndex(CharSequence textSequence, int startPosition) {
-
+
int max = textSequence.length() -1;
-
+
while (startPosition < max) {
char ch = textSequence.charAt(startPosition);
@@ -303,7 +327,7 @@ public static int readLiteralEndIndex(CharSequence textSequence, int startPositi
}
- return startPosition;
+ return startPosition;
}
}
View
4 com.dubture.symfony.test/workspace/services/ContainerInterface.php
@@ -0,0 +1,4 @@
+<?php
+namespace Symfony\Component\DependencyInjection;
+
+interface ContainerInterface {}
View
6 com.dubture.symfony.test/workspace/services/Controller.php
@@ -0,0 +1,6 @@
+<?php
+namespace Symfony\Bundle\FrameworkBundle\Controller;
+
+class Controller {
+
+}
View
2 com.dubture.symfony.test/workspace/services/testChainedServiceCompletion.pdtt
@@ -3,7 +3,7 @@ Should complete methods from the session service
--FILE--
<?
namespace NS;
-class A {
+class A implements \Symfony\Component\DependencyInjection\ContainerInterface {
function goo() {
$form = $this->get('form.factory');
$form->|
View
2 com.dubture.symfony.test/workspace/services/testParameterizedServiceMethodCompletion.pdtt
@@ -3,7 +3,7 @@ Should complete methods from the other service
--FILE--
<?
namespace NS;
-class B {
+class B extends \Symfony\Bundle\FrameworkBundle\Controller\Controller {
function roo() {
$this->get('other')->|
}
View
2 com.dubture.symfony.test/workspace/services/testServiceIdCompletion.pdtt
@@ -3,7 +3,7 @@ Should complete methods from the session service
--FILE--
<?
namespace NS;
-class A {
+class A implements \Symfony\Component\DependencyInjection\ContainerInterface {
function goo() {
$this->get('|');
}
View
5 com.dubture.symfony.test/workspace/services/testServiceMethodCompletion.pdtt
@@ -3,9 +3,10 @@ Should complete methods from the session service
--FILE--
<?
namespace NS;
-class A {
+class A implements \Symfony\Component\DependencyInjection\ContainerInterface {
function goo() {
- $this->get('session')->|
+ $variable = $this;
+ $variable->get('session')->|
}
}
?>
View
14 com.dubture.symfony.test/workspace/services/testServiceMethodCompletion2.pdtt
@@ -0,0 +1,14 @@
+--TEST--
+Should complete methods from the session service
+--FILE--
+<?
+namespace NS;
+class A extends \Symfony\Bundle\FrameworkBundle\Controller\Controller {
+ function goo() {
+ $this->get('session')->|
+ }
+}
+?>
+--EXPECT--
+method(sessionTest)
+method(someOtherMethod)
View
3 ...mfony.ui/src/com/dubture/symfony/ui/contentassist/SymfonyCompletionProposalCollector.java
@@ -80,8 +80,7 @@ protected IScriptCompletionProposal createScriptCompletionProposal(
return symfonyProposal;
}
- // don't complete anything else or we'll get duplicate entries
- return null;
+ return super.createScriptCompletionProposal(proposal);
}
private ScriptCompletionProposal generateSymfonyProposal(CompletionProposal typeProposal, ImageDescriptor descriptor) {
Something went wrong with that request. Please try again.