Improved AqlDefinitionLocator with ValidationServices.call().

Change-Id: Ic60ba2cb0229163b536850cc5c76e277465576d3
diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/AcceleoAstCompletor.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/AcceleoAstCompletor.java
index 6ff0f34..ab3a342 100644
--- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/AcceleoAstCompletor.java
+++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/AcceleoAstCompletor.java
@@ -203,7 +203,7 @@
 
 		this.astCompletor = new AstCompletor(new CompletionServices(this.queryEnvironment));
 		this.aqlCompletionEngine = new QueryCompletionEngine(queryEnvironment);
-		this.acceleoCompletionProposalProvider = new AcceleoCompletionProposalsProvider(queryEnvironment);
+		this.acceleoCompletionProposalProvider = new AcceleoCompletionProposalsProvider();
 	}
 
 	/**
diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/AcceleoCompletionProposalsProvider.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/AcceleoCompletionProposalsProvider.java
index b2f7f3f..7ff669d 100644
--- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/AcceleoCompletionProposalsProvider.java
+++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/AcceleoCompletionProposalsProvider.java
@@ -37,7 +37,6 @@
 import org.eclipse.acceleo.aql.completion.proposals.templates.AcceleoCodeTemplateCompletionProposal;
 import org.eclipse.acceleo.aql.completion.proposals.templates.AcceleoCodeTemplateCompletionProposalsProvider;
 import org.eclipse.acceleo.aql.completion.proposals.templates.AcceleoCodeTemplates;
-import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.acceleo.util.AcceleoSwitch;
 import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.EObject;
@@ -54,18 +53,7 @@
 	 * The {@link AcceleoCodeTemplateCompletionProposalsProvider} that provides code template completion
 	 * proposals.
 	 */
-	private final AcceleoCodeTemplateCompletionProposalsProvider acceleoCodeTemplatesProvider;
-
-	/**
-	 * The constructor.
-	 * 
-	 * @param queryEnvironment
-	 *            the (non-{@code null}) contextual {@link IQualifiedNameQueryEnvironment}.
-	 */
-	public AcceleoCompletionProposalsProvider(IQualifiedNameQueryEnvironment queryEnvironment) {
-		this.acceleoCodeTemplatesProvider = new AcceleoCodeTemplateCompletionProposalsProvider(
-				queryEnvironment);
-	}
+	private final AcceleoCodeTemplateCompletionProposalsProvider acceleoCodeTemplatesProvider = new AcceleoCodeTemplateCompletionProposalsProvider();
 
 	/**
 	 * Provides the syntactic and code template completion proposals for a position where the given Acceleo
diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/templates/AcceleoCodeTemplateCompletionProposalsProvider.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/templates/AcceleoCodeTemplateCompletionProposalsProvider.java
index 7a1ac30..da00446 100644
--- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/templates/AcceleoCodeTemplateCompletionProposalsProvider.java
+++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/completion/proposals/templates/AcceleoCodeTemplateCompletionProposalsProvider.java
@@ -12,7 +12,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 
 import org.eclipse.acceleo.AcceleoPackage;
 import org.eclipse.acceleo.BlockComment;
@@ -29,7 +28,6 @@
 import org.eclipse.acceleo.aql.completion.AcceleoCompletor;
 import org.eclipse.acceleo.aql.completion.proposals.AcceleoCompletionProposal;
 import org.eclipse.acceleo.aql.completion.proposals.AcceleoCompletionProposalsProvider;
-import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.acceleo.util.AcceleoSwitch;
 import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.EObject;
@@ -135,21 +133,6 @@
 			AcceleoCodeTemplates.NEW_COMMENT_MAIN, AcceleoPackage.Literals.COMMENT);
 
 	/**
-	 * The {@link IQualifiedNameQueryEnvironment}.
-	 */
-	private final IQualifiedNameQueryEnvironment queryEnvironment;
-
-	/**
-	 * Constructor.
-	 * 
-	 * @param queryEnvironment
-	 *            the (non-{@code null}) contextual {@link IQualifiedNameQueryEnvironment}.
-	 */
-	public AcceleoCodeTemplateCompletionProposalsProvider(IQualifiedNameQueryEnvironment queryEnvironment) {
-		this.queryEnvironment = Objects.requireNonNull(queryEnvironment);
-	}
-
-	/**
 	 * Provides the code template completion proposals for a position where the given Acceleo type is
 	 * syntactically allowed.
 	 * 
diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoLocator.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoLocator.java
index 0ef7a94..bbccdc1 100644
--- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoLocator.java
+++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoLocator.java
@@ -21,6 +21,7 @@
 import org.eclipse.acceleo.aql.parser.AcceleoAstUtils;
 import org.eclipse.acceleo.aql.validation.IAcceleoValidationResult;
 import org.eclipse.acceleo.query.parser.AstResult;
+import org.eclipse.acceleo.query.runtime.IValidationResult;
 import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.emf.ecore.EObject;
 
@@ -120,8 +121,10 @@
 						acceleoOrAqlNodeUnderCursor);
 				AstResult astResultOfAqlNode = AcceleoAstUtils.getAqlAstResultOfAqlAstElement(
 						acceleoOrAqlNodeUnderCursor);
+				IValidationResult validationResult = acceleoValidationResult.getValidationResult(
+						astResultOfAqlNode);
 				definitionLocations.addAll(this.aqlLocator.getDefinitionLocations(acceleoOrAqlNodeUnderCursor,
-						astResultOfAqlNode, acceleoLocalVariablesContext));
+						validationResult, acceleoLocalVariablesContext));
 			}
 		}
 		return definitionLocations;
diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlDefinitionLocator.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlDefinitionLocator.java
index 540f556..93d7194 100644
--- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlDefinitionLocator.java
+++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlDefinitionLocator.java
@@ -32,14 +32,12 @@
 import org.eclipse.acceleo.query.ast.VariableDeclaration;
 import org.eclipse.acceleo.query.ast.util.AstSwitch;
 import org.eclipse.acceleo.query.parser.AstEvaluator;
-import org.eclipse.acceleo.query.parser.AstResult;
-import org.eclipse.acceleo.query.parser.AstValidator;
-import org.eclipse.acceleo.query.parser.CombineIterator;
 import org.eclipse.acceleo.query.runtime.EvaluationResult;
 import org.eclipse.acceleo.query.runtime.IService;
 import org.eclipse.acceleo.query.runtime.IValidationResult;
 import org.eclipse.acceleo.query.runtime.impl.EvaluationServices;
 import org.eclipse.acceleo.query.runtime.impl.Nothing;
+import org.eclipse.acceleo.query.runtime.impl.ServicesValidationResult;
 import org.eclipse.acceleo.query.runtime.impl.ValidationServices;
 import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.acceleo.query.validation.type.IType;
@@ -76,20 +74,14 @@
 	private final AstEvaluator aqlEvaluator;
 
 	/**
-	 * The {@link AstValidator}, which we need to retrieve the types of the expressions passed as arguments to
-	 * service calls.
-	 */
-	private final AstValidator aqlValidator;
-
-	/**
 	 * The {@link AqlVariablesLocalContext} that holds information about the variables.
 	 */
 	private final AqlVariablesLocalContext aqlVariablesContext;
 
 	/**
-	 * The contextual {@link AstResult}.
+	 * The contextual {@link IValidationResult}.
 	 */
-	private final AstResult aqlAstResult;
+	private final IValidationResult validationResult;
 
 	/**
 	 * The context qualified name.
@@ -101,25 +93,25 @@
 	 * 
 	 * @param queryEnvironment
 	 *            the (non-{@code null}) {@link IQualifiedNameQueryEnvironment}.
-	 * @param aqlAstResult
-	 *            the (non-{@code null}) {@link AstResult} containing the element(s) that will be passed as
-	 *            argument to this.
+	 * @param validationResult
+	 *            the (non-{@code null}) {@link IValidationResult} containing the element(s) that will be
+	 *            passed as argument to this.
 	 * @param aqlVariablesContext
 	 *            the (non-{@code null}) {@link AqlVariablesLocalContext.
 	 * @param qualifiedName
 	 *            the context qualified name
 	 */
-	public AqlDefinitionLocator(IQualifiedNameQueryEnvironment queryEnvironment, AstResult aqlAstResult,
-			AqlVariablesLocalContext aqlVariablesContext, String qualifiedName) {
+	public AqlDefinitionLocator(IQualifiedNameQueryEnvironment queryEnvironment,
+			IValidationResult validationResult, AqlVariablesLocalContext aqlVariablesContext,
+			String qualifiedName) {
 		this.queryEnvironment = Objects.requireNonNull(queryEnvironment);
-		this.aqlAstResult = Objects.requireNonNull(aqlAstResult);
+		this.validationResult = Objects.requireNonNull(validationResult);
 
 		this.aqlEvaluationServices = new EvaluationServices(this.queryEnvironment);
 		this.aqlEvaluator = new AstEvaluator(aqlEvaluationServices);
 
 		this.aqlVariablesContext = Objects.requireNonNull(aqlVariablesContext);
 
-		this.aqlValidator = new AstValidator(new ValidationServices(this.queryEnvironment));
 		this.qualifiedName = qualifiedName;
 	}
 
@@ -196,32 +188,18 @@
 		queryEnvironment.getLookupEngine().getResolver().register(contextQualifiedName, module);
 		queryEnvironment.getLookupEngine().pushContext(contextQualifiedName);
 		try {
-			this.aqlValidator.validate(this.aqlVariablesContext.getVariableTypes(), this.aqlAstResult);
-
-			// Retrieve all the IServices which fit the name and argument types.
-			List<IService<?>> candidateServices = new ArrayList<>();
-
-			// Name
-			String serviceName = call.getServiceName();
+			final ValidationServices validationServices = new ValidationServices(queryEnvironment);
 
 			// Argument Types - which are expressions whose type must first be evaluated.
-			List<Set<IType>> argumentTypes = call.getArguments().stream().map(argument -> {
-				AstResult aqlAstOfArgument = AcceleoAstUtils.getAqlAstResultOfAqlAstElement(argument);
-				IValidationResult aqlValidationResultOfArgument = this.aqlValidator.validate(
-						this.aqlVariablesContext.getVariableTypes(), aqlAstOfArgument);
-				Set<IType> argumentPossibleTypes = aqlValidationResultOfArgument.getPossibleTypes(argument);
+			final List<Set<IType>> argumentTypes = call.getArguments().stream().map(argument -> {
+				Set<IType> argumentPossibleTypes = validationResult.getPossibleTypes(argument);
 				return argumentPossibleTypes;
 			}).collect(Collectors.toList());
 
-			CombineIterator<IType> it = new CombineIterator<IType>(argumentTypes);
-			while (it.hasNext()) {
-				List<IType> currentArgTypes = it.next();
-				IService<?> service = this.queryEnvironment.getLookupEngine().lookup(serviceName,
-						currentArgTypes.toArray(new IType[currentArgTypes.size()]));
-				if (service != null) {
-					candidateServices.add(service);
-				}
-			}
+			final ServicesValidationResult servicesValidationResult = validationServices.call(call,
+					validationResult, argumentTypes);
+			// Retrieve all the IServices which fit the name and argument types.
+			final Set<IService<?>> candidateServices = servicesValidationResult.getResolvedServices();
 
 			// Return links to all the candidates.
 			return candidateServices.stream().map(service -> new AqlLocationLinkToAny(call, service
diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlLocator.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlLocator.java
index 0d5c717..94aef48 100644
--- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlLocator.java
+++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/aql/AqlLocator.java
@@ -15,7 +15,7 @@
 import java.util.Objects;
 
 import org.eclipse.acceleo.aql.location.common.AbstractLocationLink;
-import org.eclipse.acceleo.query.parser.AstResult;
+import org.eclipse.acceleo.query.runtime.IValidationResult;
 import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.emf.ecore.EObject;
 
@@ -55,18 +55,18 @@
 	 * 
 	 * @param aqlAstElement
 	 *            the (non-{@code null}) AQL {@link EObject AST element}.
-	 * @param aqlAstResult
-	 *            the (non-{@code null}) {@link AstResult} containing {@code aqlAstElement}.
+	 * @param validationResult
+	 *            the (non-{@code null}) {@link IValidationResult} containing {@code aqlAstElement}.
 	 * @param aqlVariablesContext
 	 *            the (non-{@code null}) {@link AqlVariablesLocalContext}.
 	 * @return the {@link List} of {@link AbstractAqlLocationLink} corresponding to the declaration
 	 *         location(s) of the element at the given position of the source.
 	 */
 	public List<AbstractLocationLink<?, ?>> getDeclarationLocations(EObject aqlAstElement,
-			AstResult aqlAstResult, AqlVariablesLocalContext aqlVariablesContext) {
+			IValidationResult validationResult, AqlVariablesLocalContext aqlVariablesContext) {
 		// FIXME: LSP4E does not support "go-to declaration" so we simply dispatch to "go-to definition".
 		// Also, not sure we have a clear difference in Acceleo between declaration and definition.
-		return this.getDefinitionLocations(aqlAstElement, aqlAstResult, aqlVariablesContext);
+		return this.getDefinitionLocations(aqlAstElement, validationResult, aqlVariablesContext);
 	}
 
 	/**
@@ -75,19 +75,19 @@
 	 * 
 	 * @param aqlAstElement
 	 *            the (non-{@code null}) AQL {@link EObject AST element}.
-	 * @param aqlAstResult
-	 *            the (non-{@code null}) {@link AstResult} containing {@code aqlAstElement}.
+	 * @param validationResult
+	 *            the (non-{@code null}) {@link IValidationResult} containing {@code aqlAstElement}.
 	 * @param aqlVariablesContext
 	 *            the (non-{@code null}) {@link AqlVariablesLocalContext}.
 	 * @return the {@link List} of {@link AbstractAqlLocationLink} corresponding to the definition location(s)
 	 *         of the element at the given position of the source.
 	 */
 	public List<AbstractLocationLink<?, ?>> getDefinitionLocations(EObject aqlAstElement,
-			AstResult aqlAstResult, AqlVariablesLocalContext aqlVariablesContext) {
+			IValidationResult validationResult, AqlVariablesLocalContext aqlVariablesContext) {
 		final List<AbstractLocationLink<?, ?>> definitionLocations = new ArrayList<>();
 
-		AqlDefinitionLocator definitionLocator = new AqlDefinitionLocator(this.queryEnvironment, aqlAstResult,
-				aqlVariablesContext, qualifiedName);
+		AqlDefinitionLocator definitionLocator = new AqlDefinitionLocator(this.queryEnvironment,
+				validationResult, aqlVariablesContext, qualifiedName);
 
 		List<AbstractLocationLink<?, ?>> definitionLocationsOfAqlElement = definitionLocator.doSwitch(
 				aqlAstElement);