/*
* generated by Xtext
*/
package it.xsemantics.dsl.scoping;
import static org.eclipse.xtext.xbase.lib.IterableExtensions.filter;
import static org.eclipse.xtext.xbase.lib.IterableExtensions.head;
import it.xsemantics.dsl.util.XsemanticsUtils;
import it.xsemantics.dsl.xsemantics.ExpressionInConclusion;
import it.xsemantics.dsl.xsemantics.Rule;
import it.xsemantics.dsl.xsemantics.RuleInvocation;
import it.xsemantics.dsl.xsemantics.RuleParameter;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.xbase.XBlockExpression;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.XVariableDeclaration;
import org.eclipse.xtext.xbase.annotations.scoping.XbaseWithAnnotationsScopeProvider;
import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations;
import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;
import org.eclipse.xtext.xbase.scoping.LocalVariableScopeContext;
import org.eclipse.xtext.xbase.scoping.XbaseScopeProvider;
import org.eclipse.xtext.xbase.scoping.XbaseScopeProvider.LocalVariableAcceptor;
import org.eclipse.xtext.xbase.scoping.featurecalls.IValidatedEObjectDescription;
import org.eclipse.xtext.xbase.scoping.featurecalls.JvmFeatureScope;
import org.eclipse.xtext.xbase.validation.IssueCodes;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
/**
* This class contains custom scoping description.
*
* see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping on
* how and when to use it
*
*/
public class XsemanticsScopeProvider extends XbaseWithAnnotationsScopeProvider {
@Inject
protected XsemanticsUtils utils;
@Inject
protected IJvmModelAssociations associations;
@Inject
private ILogicalContainerProvider logicalContainerProvider;
@Override
protected void createLocalVarScope(LocalVariableAcceptor acceptor, LocalVariableScopeContext scopeContext) {
if (scopeContext == null || scopeContext.getContext() == null) {
super.createLocalVarScope(acceptor, scopeContext);
return;
}
EObject context = scopeContext.getContext();
// The inferrer associates to a Rule both field(s) and methods
// and we need the method (i.e., the JvmOperation) to actually
// build a correct scope
JvmOperation jvmOperation = getJvmOperationAssociatedToSourceElement(context);
if (jvmOperation == null)
super.createLocalVarScope(acceptor, scopeContext);
else {
if (jvmOperation.getDeclaringType() != null) {
JvmDeclaredType declaredType = jvmOperation.getDeclaringType();
if (!jvmOperation.isStatic()) {
createLocalVarScopeForJvmDeclaredType(
declaredType, acceptor);
}
}
createLocalVarScopeForJvmOperation(jvmOperation, acceptor);
}
}
@Override
protected JvmDeclaredType getContextType(EObject obj) {
// the context type of an ExpressionInConclusion is the same
// as the inferred class of the containing Rule
// this way, visibility works correctly and
// an ExpressionInConclusion can access private injected fields
if (obj instanceof ExpressionInConclusion) {
return super.getContextType(logicalContainerProvider
.getLogicalContainer(utils.containingRule(obj)));
}
return super.getContextType(obj);
}
private JvmOperation getJvmOperationAssociatedToSourceElement(
EObject context) {
EObject sourceElement = associations.getPrimarySourceElement(context);
if (sourceElement == null)
return null;
Set<EObject> jvmElements = associations.getJvmElements(sourceElement);
JvmOperation jvmOperation = head(filter(jvmElements, JvmOperation.class));
return jvmOperation;
}
@Override
protected void createLocalVarScopeForBlock(XBlockExpression block, int indexOfContextExpressionInBlock,
boolean referredFromClosure, LocalVariableAcceptor acceptor) {
super.createLocalVarScopeForBlock(block,
indexOfContextExpressionInBlock, referredFromClosure,
acceptor);
List<IValidatedEObjectDescription> descriptions = Lists.newArrayList();
EObject container = block.eContainer();
// add the output parameters as variable declarations
if (container instanceof Rule) {
Rule rule = (Rule) container;
addRuleParamsInDescriptions(utils.outputParams(rule), descriptions,
referredFromClosure);
}
// add the variable declarations inside rule invocations
for (int i = 0; i < indexOfContextExpressionInBlock; i++) {
XExpression expression = block.getExpressions().get(i);
if (expression instanceof RuleInvocation) {
RuleInvocation ruleInvocation = (RuleInvocation) expression;
List<XVariableDeclaration> variableDeclarations = utils
.getVariableDeclarations(ruleInvocation);
for (XVariableDeclaration varDecl : variableDeclarations) {
addVariableDeclaration(descriptions, varDecl,
referredFromClosure);
}
}
}
if (descriptions.isEmpty())
return;
acceptor.accept("XBlockExpression", descriptions);
}
private void addRuleParamsInDescriptions(List<RuleParameter> params,
List<IValidatedEObjectDescription> descriptions,
boolean referredFromClosure) {
for (RuleParameter p : params) {
if (p.getParameter() != null && p.getParameter().getName() != null) {
IValidatedEObjectDescription desc = createLocalVarDescription(p
.getParameter());
if (referredFromClosure)
desc.setIssueCode(IssueCodes.INVALID_MUTABLE_VARIABLE_ACCESS);
descriptions.add(desc);
}
}
}
protected void addVariableDeclaration(
List<IValidatedEObjectDescription> descriptions,
XVariableDeclaration varDecl, boolean referredFromClosure) {
if (varDecl.getName() != null) {
IValidatedEObjectDescription desc = createLocalVarDescription(varDecl);
if (referredFromClosure && varDecl.isWriteable())
desc.setIssueCode(IssueCodes.INVALID_MUTABLE_VARIABLE_ACCESS);
descriptions.add(desc);
}
}
}