Improved open definition in for loop.

Change-Id: I5003b5acc09c5757f424ea2ec139e2ff6f9be63e
diff --git a/plugins/org.eclipse.acceleo.aql.ls/src/org/eclipse/acceleo/aql/ls/services/textdocument/AcceleoTextDocument.java b/plugins/org.eclipse.acceleo.aql.ls/src/org/eclipse/acceleo/aql/ls/services/textdocument/AcceleoTextDocument.java
index 5628070..f8b795f 100644
--- a/plugins/org.eclipse.acceleo.aql.ls/src/org/eclipse/acceleo/aql/ls/services/textdocument/AcceleoTextDocument.java
+++ b/plugins/org.eclipse.acceleo.aql.ls/src/org/eclipse/acceleo/aql/ls/services/textdocument/AcceleoTextDocument.java
@@ -13,12 +13,12 @@
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
 import org.eclipse.acceleo.Metamodel;
 import org.eclipse.acceleo.Module;
-import org.eclipse.acceleo.ModuleElement;
 import org.eclipse.acceleo.aql.location.AcceleoLocator;
 import org.eclipse.acceleo.aql.location.common.AbstractLocationLink;
 import org.eclipse.acceleo.aql.ls.AcceleoLanguageServer;
@@ -81,6 +81,11 @@
 	private IAcceleoValidationResult acceleoValidationResult;
 
 	/**
+	 * The module qualified name.
+	 */
+	private String qualifiedName;
+
+	/**
 	 * Creates a new {@link AcceleoTextDocument} corresponding to the given URI and with the given initial
 	 * contents.
 	 * 
@@ -96,6 +101,7 @@
 		Objects.requireNonNull(textDocumentContents);
 		this.ownerProject = project;
 		this.uri = textDocumentUri;
+		qualifiedName = getProject().getResolver().getQualifiedName(this.getUrl());
 
 		this.setContents(textDocumentContents);
 	}
@@ -134,6 +140,7 @@
 	public void setProject(AcceleoProject acceleoProject) {
 		AcceleoProject oldProject = ownerProject;
 		this.ownerProject = acceleoProject;
+		qualifiedName = getProject().getResolver().getQualifiedName(getUrl());
 		if ((acceleoProject == null && oldProject != null) || !acceleoProject.equals(oldProject)) {
 			// When the project changes, the environment changes.
 			this.resolverChanged();
@@ -208,7 +215,8 @@
 	public void validateContents() {
 		IAcceleoValidationResult validationResults = null;
 		if (this.acceleoAstResult != null && this.getQueryEnvironment() != null) {
-			validationResults = doValidation(this.acceleoAstResult, this.getQueryEnvironment());
+			validationResults = doValidation(this.acceleoAstResult, this.getQueryEnvironment(),
+					getModuleQualifiedName());
 		}
 		this.acceleoValidationResult = validationResults;
 	}
@@ -222,14 +230,16 @@
 	 * @param queryEnvironment
 	 *            the (non-{@code null}) {@link IQualifiedNameQueryEnvironment} of the document being
 	 *            validated.
+	 * @param qualifiedName
+	 *            the context qualified name
 	 * @return the {@link IAcceleoValidationResult}.
 	 */
 	private static IAcceleoValidationResult doValidation(AcceleoAstResult acceleoAstResult,
-			IQualifiedNameQueryEnvironment queryEnvironment) {
+			IQualifiedNameQueryEnvironment queryEnvironment, String qualifiedName) {
 		Objects.requireNonNull(acceleoAstResult);
 		Objects.requireNonNull(queryEnvironment);
 
-		return validate(queryEnvironment, acceleoAstResult);
+		return validate(queryEnvironment, acceleoAstResult, qualifiedName);
 	}
 
 	/**
@@ -285,11 +295,7 @@
 	 *         {@link IQualifiedNameResolver}.
 	 */
 	public String getModuleQualifiedName() {
-		if (getProject() == null) {
-			return null;
-		} else {
-			return getProject().getResolver().getQualifiedName(this.getUrl());
-		}
+		return qualifiedName;
 	}
 
 	/**
@@ -316,12 +322,11 @@
 	 *         the Acceleo element found at the given position in the source contents.
 	 */
 	public List<AbstractLocationLink<?, ?>> getDefinitionLocations(int position) {
-		// FIXME we need any module element
-		ModuleElement moduleElement = acceleoAstResult.getModule().getModuleElements().get(0);
 		final IQualifiedNameLookupEngine lookupEngine = getQueryEnvironment().getLookupEngine();
 		lookupEngine.pushImportsContext(getModuleQualifiedName(), getModuleQualifiedName());
-		List<AbstractLocationLink<?, ?>> definitionLocations = new AcceleoLocator(getQueryEnvironment())
-				.getDefinitionLocations(this.acceleoAstResult, position);
+		List<AbstractLocationLink<?, ?>> definitionLocations = new AcceleoLocator(getQueryEnvironment(),
+				getModuleQualifiedName(), acceleoValidationResult).getDefinitionLocations(
+						this.acceleoAstResult, position);
 		lookupEngine.popContext(getModuleQualifiedName());
 		return definitionLocations;
 	}
@@ -336,8 +341,8 @@
 	 *         of the Acceleo element found at the given position in the source contents.
 	 */
 	public List<AbstractLocationLink<?, ?>> getDeclarationLocations(int position) {
-		return new AcceleoLocator(getQueryEnvironment()).getDeclarationLocations(this.acceleoAstResult,
-				position);
+		return new AcceleoLocator(getQueryEnvironment(), getModuleQualifiedName(), acceleoValidationResult)
+				.getDeclarationLocations(this.acceleoAstResult, position);
 	}
 
 	/**
@@ -423,22 +428,28 @@
 	 *            the (non-{@code null}) {@link IQualifiedNameQueryEnvironment}.
 	 * @param acceleoAstResult
 	 *            the (non-{@code null}) {@link AcceleoAstResult}.
+	 * @param qualifiedName
+	 *            the context qualified name
 	 * @return the {@link IAcceleoValidationResult}.
 	 */
 	// FIXME the "synchronized" here is an ugly but convenient way to ensure that a validation finishes before
 	// any other is triggered. Otherwise a validation can push imports which invalidates the services lookup
 	// for another validation
 	private static synchronized IAcceleoValidationResult validate(
-			IQualifiedNameQueryEnvironment queryEnvironment, AcceleoAstResult acceleoAstResult) {
+			IQualifiedNameQueryEnvironment queryEnvironment, AcceleoAstResult acceleoAstResult,
+			String qualifiedName) {
 		String moduleQualifiedNameForValidation = VALIDATION_NAMESPACE + AcceleoParser.QUALIFIER_SEPARATOR
-				+ acceleoAstResult.getModule().getName();
+				+ qualifiedName;
 		final IQualifiedNameResolver resolver = queryEnvironment.getLookupEngine().getResolver();
 		resolver.register(moduleQualifiedNameForValidation, acceleoAstResult.getModule());
-
-		final AcceleoValidator acceleoValidator = new AcceleoValidator(queryEnvironment);
-		final IAcceleoValidationResult validationResults = acceleoValidator.validate(acceleoAstResult,
-				moduleQualifiedNameForValidation);
-		return validationResults;
+		try {
+			final AcceleoValidator acceleoValidator = new AcceleoValidator(queryEnvironment);
+			final IAcceleoValidationResult validationResults = acceleoValidator.validate(acceleoAstResult,
+					moduleQualifiedNameForValidation);
+			return validationResults;
+		} finally {
+			resolver.clear(Collections.singleton(moduleQualifiedNameForValidation));
+		}
 	}
 
 	/**
diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoExpressionVariablesContextProvider.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoExpressionVariablesContextProvider.java
index ce965fb..be8ee9b 100644
--- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoExpressionVariablesContextProvider.java
+++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/location/AcceleoExpressionVariablesContextProvider.java
@@ -10,9 +10,10 @@
  *******************************************************************************/
 package org.eclipse.acceleo.aql.location;
 
-import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.Set;
 
+import org.eclipse.acceleo.Binding;
 import org.eclipse.acceleo.Block;
 import org.eclipse.acceleo.Expression;
 import org.eclipse.acceleo.ForStatement;
@@ -22,11 +23,10 @@
 import org.eclipse.acceleo.Template;
 import org.eclipse.acceleo.TypedElement;
 import org.eclipse.acceleo.Variable;
-import org.eclipse.acceleo.aql.AcceleoUtil;
 import org.eclipse.acceleo.aql.location.aql.AqlVariablesLocalContext;
-import org.eclipse.acceleo.aql.validation.AcceleoValidationUtils;
-import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
-import org.eclipse.acceleo.query.validation.type.ClassType;
+import org.eclipse.acceleo.aql.validation.IAcceleoValidationResult;
+import org.eclipse.acceleo.query.parser.AstResult;
+import org.eclipse.acceleo.query.validation.type.ICollectionType;
 import org.eclipse.acceleo.query.validation.type.IType;
 import org.eclipse.acceleo.util.AcceleoSwitch;
 
@@ -40,18 +40,18 @@
 public class AcceleoExpressionVariablesContextProvider extends AcceleoSwitch<AqlVariablesLocalContext> {
 
 	/**
-	 * The {@link IQualifiedNameQueryEnvironment}.
+	 * The {@link IAcceleoValidationResult}.
 	 */
-	private final IQualifiedNameQueryEnvironment queryEnvironment;
+	private final IAcceleoValidationResult acceleoValidationResult;
 
 	/**
 	 * Constructor.
 	 * 
-	 * @param queryEnvironment
-	 *            the (non-{@code null}) {@link IQualifiedNameQueryEnvironment}.
+	 * @param acceleoValidationResult
+	 *            the (non-{@code null}) {@link IAcceleoValidationResult}.
 	 */
-	public AcceleoExpressionVariablesContextProvider(IQualifiedNameQueryEnvironment queryEnvironment) {
-		this.queryEnvironment = queryEnvironment;
+	public AcceleoExpressionVariablesContextProvider(IAcceleoValidationResult acceleoValidationResult) {
+		this.acceleoValidationResult = acceleoValidationResult;
 	}
 
 	// Expression and TypedElement are the two entry points into this because these are the only ASTNodes that
@@ -101,11 +101,6 @@
 	public AqlVariablesLocalContext caseTemplate(Template template) {
 		AqlVariablesLocalContext variablesContext = new AqlVariablesLocalContext();
 
-		// Deal with the implicit "self" variable.
-		Set<IType> selfPossibleTypes = Collections.singleton(new ClassType(queryEnvironment, String.class));
-		variablesContext.addVariable(AcceleoUtil.getTemplateImplicitVariableName(), template,
-				selfPossibleTypes);
-
 		for (Variable parameter : template.getParameters()) {
 			variablesContext.addAllVariables(this.getVariableStandaloneContext(parameter));
 		}
@@ -129,6 +124,18 @@
 		return variablesContext;
 	}
 
+	@Override
+	public AqlVariablesLocalContext caseBinding(Binding binding) {
+		AqlVariablesLocalContext variablesContext = new AqlVariablesLocalContext();
+
+		// Order matters probably.
+		variablesContext.addAllVariables(this.getBindingStandaloneContext(binding, binding
+				.eContainer() instanceof ForStatement));
+		variablesContext.addAllVariables(this.doSwitch(binding.eContainer()));
+
+		return variablesContext;
+	}
+
 	/**
 	 * Provides the {@link AqlVariablesLocalContext} corresponding to the given {@link Variable}. If the
 	 * {@link Variable} is supposed to be in the containment hierarchy of the initial argument, use
@@ -141,9 +148,45 @@
 	private AqlVariablesLocalContext getVariableStandaloneContext(Variable variable) {
 		AqlVariablesLocalContext variablesContext = new AqlVariablesLocalContext();
 
-		Set<IType> variablePossibleTypes = AcceleoValidationUtils.getPossibleTypes(variable,
-				queryEnvironment);
-		variablesContext.addVariable(variable.getName(), variable, variablePossibleTypes);
+		final AstResult type = variable.getType();
+		final Set<IType> possibleTypes = acceleoValidationResult.getValidationResult(type).getPossibleTypes(
+				type.getAst());
+		variablesContext.addVariable(variable.getName(), variable, possibleTypes);
+
+		return variablesContext;
+	}
+
+	/**
+	 * Provides the {@link AqlVariablesLocalContext} corresponding to the given {@link Binding}. If the
+	 * {@link Binding} is supposed to be in the containment hierarchy of the initial argument, use
+	 * {@link #caseBinding(Binding)} instead.
+	 * 
+	 * @param binding
+	 *            the (non-{@code null}) {@link Binding}.
+	 * @param extractCollectionTypes
+	 *            <code>true</code> if collection types should be extracted, <code>false</code> otherwise
+	 * @return the {@link AqlVariablesLocalContext} containing the variable defined by {@code variable}.
+	 */
+	private AqlVariablesLocalContext getBindingStandaloneContext(Binding binding,
+			boolean extractCollectionTypes) {
+		AqlVariablesLocalContext variablesContext = new AqlVariablesLocalContext();
+
+		final AstResult expression = binding.getInitExpression().getAst();
+		final Set<IType> possibleTypes = acceleoValidationResult.getValidationResult(expression)
+				.getPossibleTypes(expression.getAst());
+		if (extractCollectionTypes) {
+			final Set<IType> extractedPossibleTypes = new LinkedHashSet<IType>();
+			for (IType type : possibleTypes) {
+				if (type instanceof ICollectionType) {
+					extractedPossibleTypes.add(((ICollectionType)type).getCollectionType());
+				} else {
+					extractedPossibleTypes.add(type);
+				}
+			}
+			variablesContext.addVariable(binding.getName(), binding, extractedPossibleTypes);
+		} else {
+			variablesContext.addVariable(binding.getName(), binding, possibleTypes);
+		}
 
 		return variablesContext;
 	}
@@ -152,7 +195,7 @@
 	public AqlVariablesLocalContext caseForStatement(ForStatement forStatement) {
 		AqlVariablesLocalContext variablesContext = new AqlVariablesLocalContext();
 		variablesContext.addAllVariables(this.doSwitch(forStatement.eContainer()));
-		variablesContext.addAllVariables(this.getVariableStandaloneContext(forStatement.getBinding()));
+		variablesContext.addAllVariables(this.getBindingStandaloneContext(forStatement.getBinding(), true));
 		return variablesContext;
 	}
 
@@ -161,7 +204,7 @@
 		AqlVariablesLocalContext variablesContext = new AqlVariablesLocalContext();
 		variablesContext.addAllVariables(this.doSwitch(letStatement.eContainer()));
 		letStatement.getVariables().forEach(variableBinding -> variablesContext.addAllVariables(this
-				.getVariableStandaloneContext(variableBinding)));
+				.getBindingStandaloneContext(variableBinding, false)));
 		return variablesContext;
 	}
 	////
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 6e91c2f..0ef7a94 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
@@ -19,6 +19,7 @@
 import org.eclipse.acceleo.aql.location.common.AbstractLocationLink;
 import org.eclipse.acceleo.aql.parser.AcceleoAstResult;
 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.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.emf.ecore.EObject;
@@ -42,15 +43,26 @@
 	private final AqlLocator aqlLocator;
 
 	/**
+	 * The {@link IAcceleoValidationResult}.
+	 */
+	private IAcceleoValidationResult acceleoValidationResult;
+
+	/**
 	 * Creates a new {@link AcceleoLocator}.
 	 * 
 	 * @param queryEnvironment
 	 *            the (non-{@code null}) {@link IQualifiedNameQueryEnvironment} of the Acceleo contents.
+	 * @param qualifiedName
+	 *            the context qualified name
+	 * @param acceleoValidationResult
+	 *            the {@link IAcceleoValidationResult}
 	 */
-	public AcceleoLocator(IQualifiedNameQueryEnvironment queryEnvironment) {
+	public AcceleoLocator(IQualifiedNameQueryEnvironment queryEnvironment, String qualifiedName,
+			IAcceleoValidationResult acceleoValidationResult) {
 		this.queryEnvironment = queryEnvironment;
+		this.acceleoValidationResult = acceleoValidationResult;
 
-		this.aqlLocator = new AqlLocator(queryEnvironment);
+		this.aqlLocator = new AqlLocator(queryEnvironment, qualifiedName);
 	}
 
 	/**
@@ -125,8 +137,8 @@
 	 */
 	private AqlVariablesLocalContext getVariablesContext(EObject aqlAstElement) {
 		ASTNode acceleoContainerOfAqlElement = AcceleoAstUtils.getContainerOfAqlAstElement(aqlAstElement);
-		AqlVariablesLocalContext context = new AcceleoExpressionVariablesContextProvider(queryEnvironment)
-				.doSwitch(acceleoContainerOfAqlElement);
+		AqlVariablesLocalContext context = new AcceleoExpressionVariablesContextProvider(
+				acceleoValidationResult).doSwitch(acceleoContainerOfAqlElement);
 		return context;
 	}
 
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 33e4b09..540f556 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
@@ -18,8 +18,10 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.eclipse.acceleo.Module;
 import org.eclipse.acceleo.aql.location.common.AbstractLocationLink;
 import org.eclipse.acceleo.aql.parser.AcceleoAstUtils;
+import org.eclipse.acceleo.aql.parser.AcceleoParser;
 import org.eclipse.acceleo.query.ast.Call;
 import org.eclipse.acceleo.query.ast.ClassTypeLiteral;
 import org.eclipse.acceleo.query.ast.EClassifierTypeLiteral;
@@ -34,12 +36,12 @@
 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.IQueryEnvironment;
 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.ValidationServices;
+import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.acceleo.query.validation.type.IType;
 import org.eclipse.emf.ecore.EClassifier;
 import org.eclipse.emf.ecore.EEnumLiteral;
@@ -53,9 +55,14 @@
 public class AqlDefinitionLocator extends AstSwitch<List<AbstractLocationLink<?, ?>>> {
 
 	/**
-	 * The {@link IQueryEnvironment}.
+	 * FIXME: move somewhere else.
 	 */
-	private final IQueryEnvironment queryEnvironment;
+	private static final String LOCATION_NAMESPACE = "_reserved_::to::locate";
+
+	/**
+	 * The {@link IQualifiedNameQueryEnvironment}.
+	 */
+	private final IQualifiedNameQueryEnvironment queryEnvironment;
 
 	/**
 	 * The {@link EvaluationServices}. It is able to lookup services and variables.
@@ -85,18 +92,25 @@
 	private final AstResult aqlAstResult;
 
 	/**
+	 * The context qualified name.
+	 */
+	private String qualifiedName;
+
+	/**
 	 * Constructor.
 	 * 
 	 * @param queryEnvironment
-	 *            the (non-{@code null}) {@link IQueryEnvironment}.
+	 *            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 aqlVariablesContext
 	 *            the (non-{@code null}) {@link AqlVariablesLocalContext.
+	 * @param qualifiedName
+	 *            the context qualified name
 	 */
-	public AqlDefinitionLocator(IQueryEnvironment queryEnvironment, AstResult aqlAstResult,
-			AqlVariablesLocalContext aqlVariablesContext) {
+	public AqlDefinitionLocator(IQualifiedNameQueryEnvironment queryEnvironment, AstResult aqlAstResult,
+			AqlVariablesLocalContext aqlVariablesContext, String qualifiedName) {
 		this.queryEnvironment = Objects.requireNonNull(queryEnvironment);
 		this.aqlAstResult = Objects.requireNonNull(aqlAstResult);
 
@@ -106,6 +120,7 @@
 		this.aqlVariablesContext = Objects.requireNonNull(aqlVariablesContext);
 
 		this.aqlValidator = new AstValidator(new ValidationServices(this.queryEnvironment));
+		this.qualifiedName = qualifiedName;
 	}
 
 	/**
@@ -173,36 +188,50 @@
 
 	@Override
 	public List<AbstractLocationLink<?, ?>> caseCall(Call call) {
-		this.aqlValidator.validate(this.aqlVariablesContext.getVariableTypes(), this.aqlAstResult);
+		final String contextQualifiedName = LOCATION_NAMESPACE + AcceleoParser.QUALIFIER_SEPARATOR
+				+ qualifiedName;
 
-		// Retrieve all the IServices which fit the name and argument types.
-		List<IService<?>> candidateServices = new ArrayList<>();
+		final Module module = AcceleoAstUtils.getContainerModule(AcceleoAstUtils.getContainerOfAqlAstElement(
+				call));
+		queryEnvironment.getLookupEngine().getResolver().register(contextQualifiedName, module);
+		queryEnvironment.getLookupEngine().pushContext(contextQualifiedName);
+		try {
+			this.aqlValidator.validate(this.aqlVariablesContext.getVariableTypes(), this.aqlAstResult);
 
-		// Name
-		String serviceName = call.getServiceName();
+			// Retrieve all the IServices which fit the name and argument types.
+			List<IService<?>> candidateServices = new ArrayList<>();
 
-		// 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);
-			return argumentPossibleTypes;
-		}).collect(Collectors.toList());
+			// Name
+			String serviceName = call.getServiceName();
 
-		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);
+			// 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);
+				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);
+				}
 			}
-		}
 
-		// Return links to all the candidates.
-		return candidateServices.stream().map(service -> new AqlLocationLinkToAny(call, service.getOrigin()))
-				.collect(Collectors.toList());
+			// Return links to all the candidates.
+			return candidateServices.stream().map(service -> new AqlLocationLinkToAny(call, service
+					.getOrigin())).collect(Collectors.toList());
+		} finally {
+			queryEnvironment.getLookupEngine().popContext(contextQualifiedName);
+			queryEnvironment.getLookupEngine().getResolver().clear(Collections.singleton(
+					contextQualifiedName));
+			queryEnvironment.getLookupEngine().clearContext(contextQualifiedName);
+		}
 	}
 
 	@Override
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 a008280..0d5c717 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 Obeo.
+ * Copyright (c) 2020, 2021 Obeo.
  * 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
@@ -16,7 +16,7 @@
 
 import org.eclipse.acceleo.aql.location.common.AbstractLocationLink;
 import org.eclipse.acceleo.query.parser.AstResult;
-import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
+import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment;
 import org.eclipse.emf.ecore.EObject;
 
 /**
@@ -27,18 +27,26 @@
 public class AqlLocator {
 
 	/**
-	 * The {@link IQueryEnvironment}.
+	 * The {@link IQualifiedNameQueryEnvironment}.
 	 */
-	private final IQueryEnvironment queryEnvironment;
+	private final IQualifiedNameQueryEnvironment queryEnvironment;
+
+	/**
+	 * The context qualified name.
+	 */
+	private String qualifiedName;
 
 	/**
 	 * Constructor.
 	 * 
 	 * @param queryEnvironment
-	 *            the (non-{@code null}) {@link IQueryEnvironment}.
+	 *            the (non-{@code null}) {@link IQualifiedNameQueryEnvironment}.
+	 * @param qualifiedName
+	 *            the context qualified name
 	 */
-	public AqlLocator(IQueryEnvironment queryEnvironment) {
+	public AqlLocator(IQualifiedNameQueryEnvironment queryEnvironment, String qualifiedName) {
 		this.queryEnvironment = Objects.requireNonNull(queryEnvironment);
+		this.qualifiedName = qualifiedName;
 	}
 
 	/**
@@ -79,7 +87,7 @@
 		final List<AbstractLocationLink<?, ?>> definitionLocations = new ArrayList<>();
 
 		AqlDefinitionLocator definitionLocator = new AqlDefinitionLocator(this.queryEnvironment, aqlAstResult,
-				aqlVariablesContext);
+				aqlVariablesContext, qualifiedName);
 
 		List<AbstractLocationLink<?, ?>> definitionLocationsOfAqlElement = definitionLocator.doSwitch(
 				aqlAstElement);