Permalink
Browse files

Merge pull request #197 from zulus/ca_improvement

Improve code assist
  • Loading branch information...
2 parents c59f69a + c84aec4 commit 262a492e02464c36df012a26bff9ebbf468bfe1c @pulse00 committed Mar 3, 2014
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
@@ -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;
}
}
@@ -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,26 +20,28 @@
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;
import com.dubture.symfony.core.model.SymfonyModelAccess;
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()]);
+ }
}
@@ -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);
}
}
}
Oops, something went wrong.

0 comments on commit 262a492

Please sign in to comment.