blob: 26bf9d2a48229fb6befd16c077afe8100c2cd293 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 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:
* Horacio Hoyos - initial migration from Epsilon prototype
* E.D.Willink - simplification
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvtb2qvts;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CallExp;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.CompleteClass;
import org.eclipse.ocl.pivot.CompleteModel;
import org.eclipse.ocl.pivot.CompletePackage;
import org.eclipse.ocl.pivot.DataType;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.LetExp;
import org.eclipse.ocl.pivot.NavigationCallExp;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.ShadowExp;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.utilities.EnvironmentFactory;
import org.eclipse.ocl.pivot.utilities.FeatureFilter;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.TreeIterable;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsageAnalysis;
import org.eclipse.qvtd.pivot.qvtcore.analysis.RootDomainUsageAnalysis;
import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.CollectionClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.PropertyDatum;
import org.eclipse.qvtd.pivot.qvtschedule.QVTscheduleFactory;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.DomainUsage;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import com.google.common.collect.Iterables;
/**
* DatumCaches maintains the caches of ClassDatum and PropertyDatum that establish the inter-Mapping connectivity.
*/
public class DatumCaches
{
protected final @NonNull ScheduleManager scheduleManager;
protected final @NonNull Property oclContainerProperty;
protected final @NonNull RootDomainUsageAnalysis domainUsageAnalysis;
protected final @NonNull ContainmentAnalysis containmentAnalysis;
protected final @NonNull CompleteModel completeModel;
// Caches
/**
* The per-TypedModel mappings from a CompleteClass to its corresponding ClassDatum in that TypedModel.
*/
private @NonNull Map<@NonNull TypedModel, @NonNull Map<@NonNull CompleteClass, @NonNull ClassDatum>> typedModel2completeClass2classDatum = new HashMap<>();
private @NonNull Map<@NonNull TypedModel, @NonNull Map<@NonNull Set<@NonNull CompleteClass>, @NonNull ClassDatum>> typedModel2completeClasses2classDatum = new HashMap<>();
/**
* The per-ClassDatum mapping from a Property to its corresponding PropertyDatum.
* FIXME to what extent are inherited properties entered?
*/
private @NonNull Map<@NonNull ClassDatum, @NonNull Map<@NonNull Property, @NonNull PropertyDatum>> classDatum2property2propertyDatum = new HashMap<>();
/**
* The per-ClassDatum mapping from the oclContainer Property to all possible containing PropertyDatums.
*/
private @NonNull Map<@NonNull ClassDatum, @NonNull List<@NonNull PropertyDatum>> classDatum2oclContainerPropertyDatums = new HashMap<>();
protected DatumCaches(@NonNull ScheduleManager scheduleManager) {
this.scheduleManager = scheduleManager;
this.oclContainerProperty = scheduleManager.getStandardLibraryHelper().getOclContainerProperty();
this.domainUsageAnalysis = scheduleManager.getDomainUsageAnalysis();
EnvironmentFactory environmentFactory = scheduleManager.getEnvironmentFactory();
this.containmentAnalysis = new ContainmentAnalysis(environmentFactory);
this.completeModel = environmentFactory.getCompleteModel();
}
private @NonNull Set<@NonNull PropertyDatum> analyseOclContainerCall(@NonNull TypedModel typedModel, @NonNull CompleteClass context) {
InheritanceAnalysis inheritanceAnalysis = containmentAnalysis.getInheritanceAnalysis();
Set<@NonNull PropertyDatum> result = new HashSet<>();
for (@NonNull CompleteClass parentClass : containmentAnalysis.getContainerClasses(context)) {
for (@NonNull Property prop : parentClass.getProperties(FeatureFilter.SELECT_NON_STATIC)) {
if (prop.isIsComposite()) {
Set<@NonNull CompleteClass> allSuperAndSubClasses = inheritanceAnalysis.getAllSuperAndSelfAndSubClasses(context);
CompleteClass elementClass = getElementClass(prop);
if (allSuperAndSubClasses.contains(elementClass)) {
result.add(getPropertyDatum(typedModel, parentClass, prop));
}
}
}
}
return result;
}
public void analyzeCompletePackage(@NonNull TypedModel typedModel, @NonNull CompletePackage completePackage) {
for (@NonNull CompleteClass completeClass : PivotUtil.getOwnedCompleteClasses(completePackage)) {
org.eclipse.ocl.pivot.Class asClass = completeClass.getPrimaryClass();
TypedModel containingTypedModel = asClass instanceof DataType ? domainUsageAnalysis.getPrimitiveTypeModel() : typedModel;
ClassDatum classDatum = getClassDatum(containingTypedModel, asClass);
for (@NonNull Property property : PivotUtil.getOwnedProperties(asClass)) {
if (property != oclContainerProperty) {
@SuppressWarnings("unused")
PropertyDatum propertyDatumDatum = getPropertyDatum(classDatum, property);
}
}
}
}
private boolean assertValidTypedModel(@NonNull TypedModel typedModel, @NonNull CompleteClass completeClass) {
org.eclipse.ocl.pivot.@NonNull Class aType = completeClass.getPrimaryClass();
Type elementType = QVTbaseUtil.getElementalType(aType);
if (elementType instanceof DataType) {
assert typedModel == domainUsageAnalysis.getPrimitiveTypeModel();
}
else {
assert typedModel != null;
/* FIXME waiting for BUG 485647
if (typedModel != domainUsageAnalysis.getPrimitiveTypeModel()) { // Un'used' packages are primitive
Set<org.eclipse.ocl.pivot.Package> allUsedPackages = QVTbaseUtil.getAllUsedPackages(typedModel);
org.eclipse.ocl.pivot.Package containingPackage = PivotUtil.getContainingPackage(elementType);
assert containingPackage != null;
if (!Iterables.contains(allUsedPackages, containingPackage)) {
StandardLibrary standardLibrary = classRelationships.getEnvironmentFactory().getStandardLibrary();
assert (elementType == standardLibrary.getOclAnyType())
|| (elementType == standardLibrary.getOclElementType())
|| (elementType == standardLibrary.getOclVoidType());
}
} */
}
return true;
}
// TODO cache
private @NonNull Set<@NonNull CompleteClass> computeContexts(@NonNull OCLExpression oclExp, @NonNull Map<@NonNull Variable, @NonNull Set<@NonNull CompleteClass>> variable2BoundContext) {
Set<@NonNull CompleteClass> result = new HashSet<>();
if (oclExp instanceof VariableExp) {
VariableExp varExp = (VariableExp) oclExp;
Set<@NonNull CompleteClass> context = variable2BoundContext.get(varExp.getReferredVariable());
if (context != null) { // FIXME is this check needed ?
result.addAll(context);
} else {
result.add(completeModel.getCompleteClass(QVTbaseUtil.getType(varExp)));
}
} else if (oclExp instanceof CallExp) {
CallExp callExp = (CallExp) oclExp;
if (callExp instanceof OperationCallExp &&
isOclContainerOp(QVTbaseUtil.getReferredOperation(callExp))) {
OCLExpression ownedSource = QVTbaseUtil.getOwnedSource(callExp);
for (@NonNull CompleteClass oclContainerOpContext : computeContexts(ownedSource, variable2BoundContext)) {
Iterables.addAll(result, containmentAnalysis.getContainerClasses(oclContainerOpContext));
}
} else {
result.add(completeModel.getCompleteClass(QVTbaseUtil.getType(callExp)));
}
} else if (oclExp instanceof ShadowExp) {
result.add(completeModel.getCompleteClass(QVTbaseUtil.getType(oclExp)));
} else {
throw new IllegalStateException("OCLExpression has not been considered yet");
}
return result;
}
public @NonNull Iterable<@NonNull PropertyDatum> getAllPropertyDatums(@NonNull ClassDatum classDatum) {
return getAllPropertyDatumsInternal(new HashSet<>(), new HashSet<>(), classDatum);
}
private @NonNull Iterable<@NonNull PropertyDatum> getAllPropertyDatumsInternal(@NonNull Set<@NonNull ClassDatum> classDatums, @NonNull Set<@NonNull PropertyDatum> propertyDatums, @NonNull ClassDatum cDatum) {
if (classDatums.add(cDatum)) {
Iterables.addAll(propertyDatums, QVTscheduleUtil.getOwnedPropertyDatums(cDatum));
}
for (@NonNull ClassDatum superClassDatum : scheduleManager.getSuperClassDatums(cDatum)) {
if (superClassDatum != cDatum) {
getAllPropertyDatumsInternal(classDatums, propertyDatums, superClassDatum);
}
}
return propertyDatums;
}
// Property datum analysis
public @NonNull ClassDatum getClassDatum(@NonNull TypedModel typedModel, org.eclipse.ocl.pivot.@NonNull Class asClass) {
CompleteClass completeClass = completeModel.getCompleteClass(asClass);
return getClassDatum(typedModel, completeClass);
}
public @NonNull ClassDatum getClassDatum(@NonNull TypedModel typedModel, @NonNull CompleteClass completeClass) {
assert assertValidTypedModel(typedModel, completeClass);
Map<@NonNull CompleteClass, @NonNull ClassDatum> completeClass2classDatums = typedModel2completeClass2classDatum.get(typedModel);
if (completeClass2classDatums == null) {
completeClass2classDatums = new HashMap<>();
typedModel2completeClass2classDatum.put(typedModel, completeClass2classDatums);
}
ClassDatum classDatum = completeClass2classDatums.get(completeClass);
if (classDatum == null) {
org.eclipse.ocl.pivot.@NonNull Class primaryClass = completeClass.getPrimaryClass();
if (primaryClass instanceof CollectionType) {
Type elementType = PivotUtil.getElementType((CollectionType)primaryClass);
org.eclipse.ocl.pivot.@NonNull Class primaryElementClass = PivotUtil.getClass(elementType, scheduleManager.getStandardLibrary());
CompleteClass completeElementClass = scheduleManager.getEnvironmentFactory().getCompleteModel().getCompleteClass(primaryElementClass);
ClassDatum elementClassDatum = getClassDatum(typedModel, completeElementClass);
CollectionClassDatum collectionClassDatum = QVTscheduleFactory.eINSTANCE.createCollectionClassDatum();
collectionClassDatum.setElementalClassDatum(elementClassDatum);
classDatum = collectionClassDatum;
}
else {
classDatum = QVTscheduleFactory.eINSTANCE.createClassDatum();
}
classDatum.setOwningScheduleModel(scheduleManager.getScheduleModel());
classDatum.getCompleteClasses().add(completeClass);
classDatum.setReferredClass(primaryClass);
classDatum.setName(primaryClass.getName());
classDatum.setReferredTypedModel(typedModel);
if (!(primaryClass instanceof DataType)) {
// scheduleManager.getSuperClassDatums(classDatum); -- lazily computed
/* List<ClassDatum> superClassDatums = classDatum.getSuperClassDatums();
for (@NonNull CompleteClass superCompleteClass : completeClass.getProperSuperCompleteClasses()) {
DomainUsage superUsage = getUsage(superCompleteClass.getPrimaryClass());
if (superUsage != null) { // Ignore superClassDatum with differet typedModels (OclAny)
Iterable<@NonNull TypedModel> superTypedModels = superUsage.getTypedModels();
if ((Iterables.size(superTypedModels) == 1) && Iterables.contains(superTypedModels, typedModel)) {
ClassDatum superClassDatum = getClassDatum(typedModel, superCompleteClass);
superClassDatums.add(superClassDatum);
}
}
} */
}
completeClass2classDatums.put(completeClass, classDatum);
}
/**
* Following check is useful for heterogeneous checking. assertValidTypedModel should be better once BUG 485647 is fixed.
*
TypedModel tmKey = null;
for (TypedModel tm : typedModel2class2datum.keySet()) {
Map<Type, ClassDatum> c2d = typedModel2class2datum.get(tm);
if (c2d.containsKey(aType)) {
if (tmKey == null) {
tmKey = tm;
}
else if (!aType.getName().startsWith("Ocl") && !aType.getName().equals("EObject")) {
System.out.println(aType + " is both " + tmKey + " and " + tm);
throw new IllegalStateException(aType + " is both " + tmKey + " and " + tm);
}
}
} */
return classDatum;
}
public @NonNull ClassDatum getClassDatum(@NonNull TypedModel typedModel, @NonNull Set<@NonNull CompleteClass> completeClasses) {
assert completeClasses.size() >= 2;
for (@NonNull CompleteClass completeClass : completeClasses) {
assert assertValidTypedModel(typedModel, completeClass);
}
Map<@NonNull Set<@NonNull CompleteClass>, @NonNull ClassDatum> completeClasses2classDatums = typedModel2completeClasses2classDatum.get(typedModel);
if (completeClasses2classDatums == null) {
completeClasses2classDatums = new HashMap<>();
typedModel2completeClasses2classDatum.put(typedModel, completeClasses2classDatums);
}
ClassDatum classDatum = completeClasses2classDatums.get(completeClasses);
if (classDatum == null) {
org.eclipse.ocl.pivot.@NonNull Class primaryClass = completeClasses.iterator().next().getPrimaryClass();
if (primaryClass instanceof CollectionType) {
Type elementType = PivotUtil.getElementType((CollectionType)primaryClass);
org.eclipse.ocl.pivot.@NonNull Class primaryElementClass = PivotUtil.getClass(elementType, scheduleManager.getStandardLibrary());
CompleteClass completeElementClass = scheduleManager.getEnvironmentFactory().getCompleteModel().getCompleteClass(primaryElementClass);
ClassDatum elementClassDatum = getClassDatum(typedModel, completeElementClass);
CollectionClassDatum collectionClassDatum = QVTscheduleFactory.eINSTANCE.createCollectionClassDatum();
collectionClassDatum.setElementalClassDatum(elementClassDatum);
classDatum = collectionClassDatum;
}
else {
classDatum = QVTscheduleFactory.eINSTANCE.createClassDatum();
}
classDatum.setOwningScheduleModel(scheduleManager.getScheduleModel());
classDatum.getCompleteClasses().addAll(completeClasses);
classDatum.setReferredClass(primaryClass);
classDatum.setName(primaryClass.getName());
classDatum.setReferredTypedModel(typedModel);
if (!(primaryClass instanceof DataType)) {
// scheduleManager.getSuperClassDatums(classDatum); -- lazily computed
/* List<ClassDatum> superClassDatums = classDatum.getSuperClassDatums();
for (@NonNull CompleteClass superCompleteClass : completeClass.getProperSuperCompleteClasses()) {
DomainUsage superUsage = getUsage(superCompleteClass.getPrimaryClass());
if (superUsage != null) { // Ignore superClassDatum with differet typedModels (OclAny)
Iterable<@NonNull TypedModel> superTypedModels = superUsage.getTypedModels();
if ((Iterables.size(superTypedModels) == 1) && Iterables.contains(superTypedModels, typedModel)) {
ClassDatum superClassDatum = getClassDatum(typedModel, superCompleteClass);
superClassDatums.add(superClassDatum);
}
}
} */
}
completeClasses2classDatums.put(completeClasses, classDatum);
}
/**
* Following check is useful for heterogeneous checking. assertValidTypedModel should be better once BUG 485647 is fixed.
*
TypedModel tmKey = null;
for (TypedModel tm : typedModel2class2datum.keySet()) {
Map<Type, ClassDatum> c2d = typedModel2class2datum.get(tm);
if (c2d.containsKey(aType)) {
if (tmKey == null) {
tmKey = tm;
}
else if (!aType.getName().startsWith("Ocl") && !aType.getName().equals("EObject")) {
System.out.println(aType + " is both " + tmKey + " and " + tm);
throw new IllegalStateException(aType + " is both " + tmKey + " and " + tm);
}
}
} */
return classDatum;
}
// Property datum analysis
// This is needed when analysing Property/Operation call exps so that they exploit the statically computed context
// carried on through the analysis.
// TODO cache
private @NonNull Set<@NonNull CompleteClass> getComputedContexts(@NonNull CallExp callExp, @NonNull Map<@NonNull Variable, @NonNull Set<@NonNull CompleteClass>> variable2BoundContext) {
OCLExpression source = QVTbaseUtil.getOwnedSource(callExp);
return computeContexts(source, variable2BoundContext);
}
public @NonNull ContainmentAnalysis getContainmentAnalysis() {
return containmentAnalysis;
}
protected @NonNull CompleteClass getElementClass(@NonNull TypedElement typedElement) {
Type type = QVTbaseUtil.getElementalType(QVTbaseUtil.getType(typedElement));
return completeModel.getCompleteClass(type);
}
public @NonNull Iterable<@NonNull PropertyDatum> getOclContainerPropertyDatums(@NonNull ClassDatum containedClassDatum) {
List<@NonNull PropertyDatum> oclContainerPropertyDatums = classDatum2oclContainerPropertyDatums.get(containedClassDatum);
if (oclContainerPropertyDatums == null) {
oclContainerPropertyDatums = new ArrayList<>();
classDatum2oclContainerPropertyDatums.put(containedClassDatum, oclContainerPropertyDatums);
for (@NonNull CompleteClass containedCompleteClass : QVTscheduleUtil.getCompleteClasses(containedClassDatum)) {
Iterable<@NonNull Property> containmentProperties = containmentAnalysis.getContainmentProperties(containedCompleteClass);
for (@NonNull Property containmentProperty : containmentProperties) {
// CompleteClass containingCompleteClass = scheduleManager.getEnvironmentFactory().getCompleteModel().getCompleteClass(PivotUtil.getOwningClass(containmentProperty));
ClassDatum containingClassDatum = getClassDatum(QVTscheduleUtil.getReferredTypedModel(containedClassDatum), PivotUtil.getOwningClass(containmentProperty));
oclContainerPropertyDatums.add(getPropertyDatum(containingClassDatum, containmentProperty));
}
}
}
return oclContainerPropertyDatums;
}
protected @NonNull Set<@NonNull PropertyDatum> getOperationPropertyDatums(@NonNull OperationCallExp opCall, @NonNull CompleteClass context,
@NonNull Map<@NonNull CompleteClass, @NonNull Set<@NonNull Operation>> type2VisitedOps,
@NonNull Map<@NonNull Variable, @NonNull Set<@NonNull CompleteClass>> variable2BoundContext) {
Set<@NonNull Operation> visitedOps = type2VisitedOps.get(context);
if (visitedOps == null) {
visitedOps = new HashSet<>();
type2VisitedOps.put(context, visitedOps);
}
Set<@NonNull PropertyDatum> result = new HashSet<>();
Operation op = QVTbaseUtil.getReferredOperation(opCall);
if (!visitedOps.contains(op)) {
visitedOps.add(op);
if (isOclContainerOp(op)) {
for (@NonNull TypedModel typedModel : getTypedModels(context.getPrimaryClass())) {
for (@NonNull CompleteClass newContext : getComputedContexts(opCall, variable2BoundContext)) {
result.addAll(analyseOclContainerCall(typedModel, newContext));
}
}
// for (@SuppressWarnings("null") @NonNull TypedModel typedModel : getTypedModels(opCall)) {
// for (@SuppressWarnings("null") org.eclipse.ocl.pivot.@NonNull Class newContext : getComputedContexts(opCall, variable2BoundContext)) {
// result.addAll(analyseOclContainerCall(typedModel, newContext));
// }
// }
} else {
result.addAll(getOperationPropertyDatums(op, context, type2VisitedOps));
}
}
return result;
}
// Property datum analysis
private @NonNull Set<@NonNull PropertyDatum> getOperationPropertyDatums(@NonNull Operation operation, @NonNull CompleteClass context, @NonNull Map<@NonNull CompleteClass, @NonNull Set<@NonNull Operation>> type2VisitedOps) {
Set<@NonNull PropertyDatum> result = new HashSet<>();
LanguageExpression langExp = operation.getBodyExpression();
if (langExp instanceof ExpressionInOCL) {
ExpressionInOCL expInOCL = (ExpressionInOCL) langExp;
if (expInOCL.getOwnedBody() != null) {
Map<@NonNull Variable, @NonNull Set<@NonNull CompleteClass>> variable2BoundContext = new HashMap<>();
Set<@NonNull CompleteClass> boundContexts = new HashSet<>();
boundContexts.add(context);
Variable ownedContext = expInOCL.getOwnedContext();
if (ownedContext != null) {
variable2BoundContext.put(ownedContext, boundContexts);
}
for (@NonNull EObject eObject : new TreeIterable(expInOCL, true)) {
if (eObject instanceof LetExp) {
updateVariableBindings((LetExp) eObject, variable2BoundContext);
} else if (eObject instanceof NavigationCallExp) {
NavigationCallExp navCallExp = (NavigationCallExp)eObject;
Property property = QVTbaseUtil.getReferredProperty(navCallExp);
OCLExpression ownedSource = QVTbaseUtil.getOwnedSource(navCallExp);
TypedModel typedModel = getTypedModel(ownedSource);
for (@NonNull CompleteClass newContext : getComputedContexts(navCallExp, variable2BoundContext)) {
PropertyDatum propertyDatum = getPropertyDatum(typedModel, newContext, property);
result.add(propertyDatum);
}
} else if (eObject instanceof OperationCallExp) {
OperationCallExp opCallExp = (OperationCallExp) eObject;
for (@NonNull CompleteClass newContext : getComputedContexts(opCallExp, variable2BoundContext)) {
result.addAll(getOperationPropertyDatums(opCallExp, newContext, type2VisitedOps, variable2BoundContext));
}
}
}
}
}
return result;
}
protected @NonNull PropertyDatum getPropertyDatum(@NonNull TypedModel typedModel, org.eclipse.ocl.pivot.@NonNull Class context, @NonNull Property property) {
CompleteClass completeClass = completeModel.getCompleteClass(context);
return getPropertyDatum(typedModel, completeClass, property);
}
protected @NonNull PropertyDatum getPropertyDatum(@NonNull TypedModel typedModel, @NonNull CompleteClass completeClass, @NonNull Property property) {
ClassDatum classDatum = getClassDatum(typedModel, completeClass);
return getPropertyDatum(classDatum, property);
}
public @NonNull PropertyDatum getPropertyDatum(@NonNull ClassDatum classDatum, @NonNull Property property) {
assert property != oclContainerProperty; // Use getOclContainerPropertyDatums() to return multiple candidates
Map<@NonNull Property, @NonNull PropertyDatum> property2propertyDatum = getProperty2propertyDatum(classDatum);
PropertyDatum cachedPropertyDatum = property2propertyDatum.get(property);
if (cachedPropertyDatum != null) {
return cachedPropertyDatum;
}
// If not found we create it
TypedModel typedModel = QVTscheduleUtil.getReferredTypedModel(classDatum);
// Iterable<@NonNull CompleteClass> targetCompleteClasses = QVTscheduleUtil.getCompleteClasses(classDatum);
// org.eclipse.ocl.pivot.Class owningClass = QVTbaseUtil.getOwningClass(property);
// Iterable<@NonNull CompleteClass> hostCompleteClasses = QVTscheduleUtil.getCompleteClasses(classDatum);// completeModel.getCompleteClass(owningClass);
PropertyDatum propertyDatum = QVTscheduleFactory.eINSTANCE.createPropertyDatum();
propertyDatum.setReferredTypedModel(typedModel);
propertyDatum.setReferredProperty(property);
propertyDatum.setName(property.getName());
propertyDatum.setOwningClassDatum(classDatum);
// assert targetClassDatum.conformsTo(hostClassDatum);
PropertyDatum oldPropertyDatum = property2propertyDatum.put(property, propertyDatum);
assert oldPropertyDatum == null;
/* for (@NonNull CompleteClass superCompleteClass : targetCompleteClass.getSuperCompleteClasses()) {
if (superCompleteClass.conformsTo(hostCompleteClass)) {
PropertyDatum superPropDatum = getPropertyDatum(typedModel, superCompleteClass, property);
propertyDatum.getSuperPropertyDatums().add(superPropDatum);
}
} */
// Lazily assign the opposite
Property oppositeProperty = property.getOpposite();
if (oppositeProperty != null) {
// assert oppositeProperty != oclContainerProperty;
ClassDatum oppositeClassDatum = getClassDatum(QVTscheduleUtil.getReferredTypedModel(classDatum), PivotUtil.getOwningClass(oppositeProperty));
Map<@NonNull Property, @NonNull PropertyDatum> oppositeProperty2propertyDatum = getProperty2propertyDatum(oppositeClassDatum);
PropertyDatum oppositePropertyDatum = oppositeProperty2propertyDatum.get(oppositeProperty);
if (oppositePropertyDatum != null) {
propertyDatum.setOpposite(oppositePropertyDatum);
oppositePropertyDatum.setOpposite(propertyDatum);
}
}
return propertyDatum;
}
private @NonNull Map<@NonNull Property, @NonNull PropertyDatum> getProperty2propertyDatum(@NonNull ClassDatum classDatum) {
Map<@NonNull Property, @NonNull PropertyDatum> property2propertyDatum = classDatum2property2propertyDatum.get(classDatum);
if (property2propertyDatum == null) {
property2propertyDatum = new HashMap<>();
classDatum2property2propertyDatum.put(classDatum, property2propertyDatum);
}
return property2propertyDatum;
}
public @NonNull PropertyDatum getSuccessPropertyDatum(@NonNull Property successProperty) { // FIXME Could this be more regular ?? <<success>> in the QVTm ??
org.eclipse.ocl.pivot.Class owningClass = QVTbaseUtil.getOwningClass(successProperty);
TypedModel typedModel = getTypedModel(owningClass);
return getPropertyDatum(typedModel, owningClass, successProperty);
}
protected @NonNull TypedModel getTypedModel(@NonNull Element element) {
DomainUsage domainUsage = getUsage(element);
if (domainUsage == null) {
getUsage(element);
throw new IllegalStateException("No DomainUsage for " + element);
}
Iterator<TypedModel> typedModels = getTypedModels(element).iterator();
if (!typedModels.hasNext()) {
throw new IllegalStateException("No TypedModel for " + element);
}
@SuppressWarnings("null") @NonNull TypedModel typedModel = typedModels.next();
if (typedModels.hasNext()) {
getUsage(element);
throw new IllegalStateException("Ambiguous TypedModel: " + domainUsage + " for " + element);
}
return typedModel;
}
private @NonNull Iterable<@NonNull TypedModel> getTypedModels(@NonNull Element element) {
DomainUsage domainUsage = getUsage(element);
if (domainUsage == null) {
getUsage(element);
throw new IllegalStateException("No DomainUsage for " + element);
}
return domainUsage.getTypedModels();
}
protected @Nullable DomainUsage getUsage(@NonNull Element element) {
Operation operation = QVTbaseUtil.getContainingOperation(element);
if (operation != null) {
DomainUsageAnalysis analysis = domainUsageAnalysis.getAnalysis(operation);
return analysis.getUsage(element);
}
else {
return domainUsageAnalysis.getUsage(element);
}
}
private boolean isOclContainerOp(@NonNull Operation operation) {
return operation.getOperationId() == domainUsageAnalysis.getOclContainerId();
// return "oclContainer".equals(op.getName()) && op.getOwnedParameters().isEmpty();
}
private void updateVariableBindings(@NonNull LetExp letExp, @NonNull Map<@NonNull Variable, @NonNull Set<@NonNull CompleteClass>> variable2BoundContext ) {
Variable variable = QVTbaseUtil.getOwnedVariable(letExp);
variable2BoundContext.put(variable, computeContexts(QVTbaseUtil.getOwnedInit(variable), variable2BoundContext));
}
}