blob: 4cac8224d23ce812948f27eeea63cefeeaae177a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.xtext.essentialocl.attributes;
import java.util.List;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.IterateExp;
import org.eclipse.ocl.pivot.LoopExp;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.PivotPackage;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.internal.scoping.AbstractAttribution;
import org.eclipse.ocl.pivot.internal.scoping.EnvironmentView;
import org.eclipse.ocl.pivot.internal.scoping.ScopeView;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.xtext.essentialoclcs.AbstractNameExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.ExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.InfixExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.NavigatingArgCS;
import org.eclipse.ocl.xtext.essentialoclcs.NavigationRole;
import org.eclipse.ocl.xtext.essentialoclcs.RoundBracketedClauseCS;
public class NavigatingArgCSAttribution extends AbstractAttribution
{
public static final @NonNull NavigatingArgCSAttribution INSTANCE = new NavigatingArgCSAttribution();
@Override
public ScopeView computeLookup(@NonNull EObject target, @NonNull EnvironmentView environmentView, @NonNull ScopeView scopeView) {
NavigatingArgCS fromArgument = (NavigatingArgCS)target;
NavigationRole role = fromArgument.getRole();
RoundBracketedClauseCS csRoundBracketedClause = fromArgument.getOwningRoundBracketedClause();
AbstractNameExpCS targetElement = csRoundBracketedClause.getOwningNameExp();
assert targetElement != null;
InfixExpCS csNavigationOperator = NavigationUtil.getNavigationInfixExp(targetElement);
OCLExpression pivot = PivotUtil.getPivot(OCLExpression.class, targetElement); // NB QVTr's RelationCallExp is not a CallExp
if (pivot instanceof LoopExp) { // FIXME This is null for nested iteration
if (role == NavigationRole.EXPRESSION) {
for (Variable iterator : ((LoopExp)pivot).getOwnedIterators()) {
if (iterator.isIsImplicit()) {
environmentView.addElementsOfScope(iterator.getType(), scopeView);
}
else {
environmentView.addNamedElement(iterator);
}
if (environmentView.hasFinalResult()) {
return null;
}
}
for (Variable iterator : ((LoopExp)pivot).getOwnedCoIterators()) {
if (iterator.isIsImplicit()) {
environmentView.addElementsOfScope(iterator.getType(), scopeView);
}
else {
environmentView.addNamedElement(iterator);
}
if (environmentView.hasFinalResult()) {
return null;
}
}
if (pivot instanceof IterateExp) {
Variable result = ((IterateExp)pivot).getOwnedResult();
if (result.isIsImplicit()) {
environmentView.addElementsOfScope(result.getType(), scopeView);
}
else {
environmentView.addNamedElement(result);
}
if (environmentView.hasFinalResult()) {
return null;
}
}
}
else if (role == NavigationRole.ITERATOR) { // Happens during save
List<Variable> iterators = ((LoopExp)pivot).getOwnedIterators();
assert iterators != null;
environmentView.addNamedElements(iterators);
}
else if (role == NavigationRole.ACCUMULATOR) {
Variable result = ((IterateExp)pivot).getOwnedResult();
if (result != null) {
environmentView.addNamedElement(result);
}
}
}
else if (pivot != null) { // OperationCallExp
}
else { // No pivot resolved yet
if (role == NavigationRole.EXPRESSION) {
//
// Challenges:
// for x->select(oclIsKindOf(T)) must accept both T as a type (and as a source property)
// for x->select(something(T)) must accept both T as a source property (and as a type)
//
if ((csNavigationOperator != null) && PivotUtil.isAggregateNavigationOperator(csNavigationOperator.getName())) {
ExpCS csSource = csNavigationOperator.getSource();
OCLExpression source = PivotUtil.getPivot(OCLExpression.class, csSource);
if (source != null) {
Type type = source.getType();
Type elementType;
CollectionType collectionType;
PivotMetamodelManager metamodelManager = environmentView.getEnvironmentFactory().getMetamodelManager();
if (type instanceof CollectionType) { // collection->collection-operation(name...
collectionType = (CollectionType)type;
elementType = collectionType.getElementType();
ExpCS csArgument = csNavigationOperator.getArgument();
assert csArgument == targetElement;
}
else {
elementType = type;
collectionType = metamodelManager.getStandardLibrary().getSetType();
}
if (NavigationUtil.isIteration(metamodelManager, csRoundBracketedClause, collectionType)) {
if (environmentView.accepts(PivotPackage.Literals.TYPE)) {
EClassifier requiredType = environmentView.getRequiredType();
try {
environmentView.setRequiredType(PivotPackage.Literals.TYPE);
environmentView.computeLookups(scopeView.getParent().getParent().getParent());
}
finally {
environmentView.setRequiredType(requiredType);
}
}
environmentView.addElementsOfScope(elementType, scopeView);
if (environmentView.hasFinalResult()) { // If we found a type
return null; // but look no further for variables
}
}
}
}
}
}
if (csNavigationOperator != null) {
return scopeView.getParent().getParent().getParent().getParent(); // Leapfrog over RoundBracketedClauseCS, InvocationExpCS and its source operator
}
else {
return scopeView.getParent().getParent().getParent(); // Leapfrog over RoundBracketedClauseCS, InvocationExpCS
}
}
}