blob: af385a2cc9addb90c87ca3a308f4e465c8aa2bb8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2017 Willink Transformations and others.
* 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* E.D.Willink - initial API and implementation
******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvtr2qvtc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
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.CollectionType;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.IteratorVariable;
import org.eclipse.ocl.pivot.LetVariable;
import org.eclipse.ocl.pivot.NavigationCallExp;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.Parameter;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.TreeIterable;
import org.eclipse.qvtd.compiler.CompilerChainException;
import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.analysis.RelationAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.analysis.TransformationAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.analysis.VariablesAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.trace.RelationalTransformation2TracePackage;
import org.eclipse.qvtd.pivot.qvtbase.Predicate;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtcore.Assignment;
import org.eclipse.qvtd.pivot.qvtcore.BottomPattern;
import org.eclipse.qvtd.pivot.qvtcore.CoreDomain;
import org.eclipse.qvtd.pivot.qvtcore.CorePattern;
import org.eclipse.qvtd.pivot.qvtcore.GuardPattern;
import org.eclipse.qvtd.pivot.qvtcore.Mapping;
import org.eclipse.qvtd.pivot.qvtcore.NavigationAssignment;
import org.eclipse.qvtd.pivot.qvtcore.RealizedVariable;
import org.eclipse.qvtd.pivot.qvtcore.utilities.QVTcoreUtil;
import org.eclipse.qvtd.pivot.qvtrelation.Relation;
import org.eclipse.qvtd.pivot.qvtrelation.RelationCallExp;
import org.eclipse.qvtd.pivot.qvtrelation.RelationDomain;
import org.eclipse.qvtd.pivot.qvtrelation.RelationalTransformation;
import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil;
import org.eclipse.qvtd.pivot.qvttemplate.CollectionTemplateExp;
import org.eclipse.qvtd.pivot.qvttemplate.ObjectTemplateExp;
import org.eclipse.qvtd.pivot.qvttemplate.PropertyTemplateItem;
import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp;
/**
* VariablesAnalysis manages all the variables in use by a Relation and its corresponding Mapping.
*/
/*public*/ class Variables2Variables extends VariablesAnalysis
{
// public static void gatherBoundVariables(@NonNull Map<@NonNull Variable, @Nullable TemplateExp> boundVariables, @NonNull Iterable<@NonNull ? extends Element> asRoots) {
// for (Element asRoot : asRoots) {
// gatherBoundVariables(boundVariables, asRoot);
// }
// }
/**
* Return a Map from each bound variable to the TemplateExp for which it is the TempateExp.getBindsTo().
*/
public static @NonNull Map<@NonNull Variable, @NonNull TemplateExp> gatherBoundVariables(@NonNull Element asRoot) {
Map<@NonNull Variable, @NonNull TemplateExp> boundVariables = new HashMap<>();
for (EObject eObject : new TreeIterable(asRoot, true)) {
if (eObject instanceof TemplateExp) {
Variable bindsTo = QVTrelationUtil.getBindsTo((TemplateExp)eObject);
TemplateExp oldTemplateExp = boundVariables.put(bindsTo, (TemplateExp)eObject);
assert oldTemplateExp == null;
}
}
return boundVariables;
}
/**
* Return a Map from each member variable to the CollectionTemplateExp's for which it is a CollectionTempateExp.member.referredVariable.
*/
public static @Nullable Map<@NonNull Variable, @NonNull List<@NonNull CollectionTemplateExp>> gatherMemberVariables(@NonNull Element asRoot) {
Map<@NonNull Variable, @NonNull List<@NonNull CollectionTemplateExp>> memberVariable2collectionTemplateExps = null;
for (EObject eObject : new TreeIterable(asRoot, true)) {
if (eObject instanceof CollectionTemplateExp) {
CollectionTemplateExp collectionTemplateExp = (CollectionTemplateExp)eObject;
for (@NonNull OCLExpression member : QVTrelationUtil.getOwnedMembers(collectionTemplateExp)) {
if (member instanceof VariableExp) {
Variable memberVariable = QVTrelationUtil.getReferredVariable((VariableExp)member);
if (memberVariable2collectionTemplateExps == null) {
memberVariable2collectionTemplateExps = new HashMap<>();
}
List<@NonNull CollectionTemplateExp> collectionTemplateExps = memberVariable2collectionTemplateExps.get(memberVariable);
if (collectionTemplateExps == null) {
collectionTemplateExps = new ArrayList<>();
memberVariable2collectionTemplateExps.put(memberVariable, collectionTemplateExps);
}
if (!collectionTemplateExps.contains(collectionTemplateExp)) {
collectionTemplateExps.add(collectionTemplateExp);
}
}
}
}
}
return memberVariable2collectionTemplateExps;
}
/**
* Return all variables referenced within the composition tree of each of asRoots.
*/
public static void gatherReferredVariables(@NonNull Set<@NonNull Variable> referredVariables, @NonNull Iterable<@NonNull ? extends Element> asRoots) {
for (@NonNull Element asRoot : asRoots) {
gatherReferredVariables(referredVariables, asRoot);
}
}
public static void gatherReferredVariables(@NonNull Set<@NonNull Variable> referredVariables, @NonNull Element asRoot) {
for (@NonNull EObject eObject : new TreeIterable(asRoot, true)) {
if (eObject instanceof VariableExp) {
VariableDeclaration referredVariable = ((VariableExp)eObject).getReferredVariable();
if (referredVariable instanceof Variable) {
referredVariables.add((Variable)referredVariable);
}
}
else if (eObject instanceof Variable) {
referredVariables.add((Variable)eObject);
}
else if (eObject instanceof TemplateExp) {
Variable bindsTo = ((TemplateExp)eObject).getBindsTo();
if (bindsTo != null) {
referredVariables.add(bindsTo);
}
if (eObject instanceof CollectionTemplateExp) { // Member variable are contained VariableExp's
Variable rest = ((CollectionTemplateExp)eObject).getRest();
if ((rest != null) && !rest.isIsImplicit()) {
referredVariables.add(rest);
}
}
}
}
}
public static void gatherReferredVariablesWithTypedModels(@NonNull Map<@NonNull Variable, @Nullable TypedModel> referredVariable2typedModel, @NonNull Element asRoot) {
for (EObject eObject : new TreeIterable(asRoot, true)) {
if (eObject instanceof VariableExp) {
VariableDeclaration referredVariable = ((VariableExp)eObject).getReferredVariable();
if (referredVariable instanceof Variable) {
EObject eContainer = eObject.eContainer();
if (eContainer instanceof RelationCallExp) {
RelationCallExp relationCallExp = (RelationCallExp)eContainer;
int argument = relationCallExp.getArgument().indexOf(eObject);
assert argument >= 0;
Relation referredRelation = ClassUtil.nonNullState(relationCallExp.getReferredRelation());
List<@NonNull Variable> rootVariables = QVTrelationUtil.getRootVariables(referredRelation);
assert argument < rootVariables.size();
Variable rootVariable = rootVariables.get(argument);
RelationDomain relationDomain = QVTrelationUtil.getRootVariableDomain(rootVariable);
gatherReferredVariablesWithTypedModelsAdd(referredVariable2typedModel, (Variable)referredVariable, relationDomain.getTypedModel());
}
else {
gatherReferredVariablesWithTypedModelsAdd(referredVariable2typedModel, (Variable)referredVariable, null);
}
}
}
else if (eObject instanceof Variable) {
gatherReferredVariablesWithTypedModelsAdd(referredVariable2typedModel, (Variable)eObject, null);
}
else if (eObject instanceof TemplateExp) {
Variable bindsTo = ((TemplateExp)eObject).getBindsTo();
if (bindsTo != null) {
gatherReferredVariablesWithTypedModelsAdd(referredVariable2typedModel, bindsTo, null);
}
if (eObject instanceof CollectionTemplateExp) {
Variable rest = ((CollectionTemplateExp)eObject).getRest();
if ((rest != null) && !rest.isIsImplicit()) {
gatherReferredVariablesWithTypedModelsAdd(referredVariable2typedModel, rest, null);
}
}
}
}
}
private static void gatherReferredVariablesWithTypedModelsAdd(@NonNull Map<@NonNull Variable, @Nullable TypedModel> referredVariable2typedModel,
@NonNull Variable variable, @Nullable TypedModel rTypedModel) {
if (rTypedModel != null) {
TypedModel oldTypedModel = referredVariable2typedModel.put(variable, rTypedModel);
assert (oldTypedModel == rTypedModel) || (oldTypedModel == null);
}
else if (!referredVariable2typedModel.containsKey(variable)) {
referredVariable2typedModel.put(variable, null);
}
}
/**
* Return a Map from each rest variable to the CollectionTemplateExp for which it is a CollectionTempateExp.rest.
*/
public static @Nullable Map<@NonNull Variable, @NonNull CollectionTemplateExp> gatherRestVariables(@NonNull Element asRoot) {
Map<@NonNull Variable, @NonNull CollectionTemplateExp> restVariable2collectionTemplateExp = null;
for (EObject eObject : new TreeIterable(asRoot, true)) {
if (eObject instanceof CollectionTemplateExp) {
CollectionTemplateExp collectionTemplateExp = (CollectionTemplateExp)eObject;
Variable rest = collectionTemplateExp.getRest();
if (rest != null) {
if (restVariable2collectionTemplateExp == null) {
restVariable2collectionTemplateExp = new HashMap<>();
}
CollectionTemplateExp oldCollectionTemplateExp = restVariable2collectionTemplateExp.put(rest, collectionTemplateExp);
assert oldCollectionTemplateExp == null;
}
}
}
return restVariable2collectionTemplateExp;
}
// TODO bug 453863 // ?? this is suspect for more than 2 domains. // FIXME What is 'shared'? a) any two domains b) output/any-input c) all domains
/**
* Return the variables that are used by more than one domain of the relation and so must be middle variables.
*/
public static @NonNull Set<@NonNull Variable> getMiddleDomainVariables(@NonNull Relation rRelation) {
Set<@NonNull Variable> rSomeDomainVariables = new HashSet<>();
Set<@NonNull Variable> rMiddleDomainVariables = new HashSet<>();
for (@NonNull RelationDomain rDomain : QVTrelationUtil.getOwnedDomains(rRelation)) {
Set<@NonNull Variable> rThisDomainVariables = new HashSet<>();
Variables2Variables.gatherReferredVariables(rThisDomainVariables, rDomain);
for (@NonNull Variable rVariable : rThisDomainVariables) {
if (!rSomeDomainVariables.add(rVariable)) {
rMiddleDomainVariables.add(rVariable); // Accumulate second (and higher) usages
}
}
}
return rMiddleDomainVariables;
}
// protected final @NonNull QVTr2QVTc qvtr2qvtc;
protected final @NonNull RelationalTransformation2TracePackage relationalTransformation2tracePackage;
protected final @NonNull CoreDomain cEnforcedDomain;
protected final @NonNull Mapping cMapping;
protected final @NonNull Transformation cTransformation;
protected final @NonNull BottomPattern cMiddleBottomPattern;
protected final @NonNull GuardPattern cMiddleGuardPattern;
protected final @Nullable VariableDeclaration cMiddleVariable; // tcv: The trace class variable (the middle variable identifying the middle object)
protected final @NonNull Variable rThisVariable;
protected final @NonNull Variable cThisVariable;
/**
* Map from the each core variable name in use to an originating object, typically the VariableAnalysis of a relation variable,
* but the RelationCallExp of a where, the invoking relation of a call-from invocation, or this for the middle variable.
*/
private @NonNull Map<@NonNull String, @NonNull Variable2Variable> name2originator = new HashMap<>();
/**
* The analysis of each relation variable.
*/
private final @NonNull Map<@NonNull VariableDeclaration, @NonNull Variable2Variable> rVariable2analysis = new HashMap<>();
/**
* The analysis of each core variable.
*/
private final @NonNull Map<@NonNull VariableDeclaration, @NonNull Variable2Variable> cVariable2analysis = new HashMap<>();
public Variables2Variables(@NonNull RelationAnalysis relationAnalysis, @NonNull RelationDomain rEnforcedDomain,
@NonNull CoreDomain cEnforcedDomain, @Nullable Type traceClass, boolean isWhened, boolean isWhered) throws CompilerChainException {
super(relationAnalysis, isWhened, isWhered);
TransformationAnalysis transformationAnalysis = relationAnalysis.getTransformationAnalysis();
QVTr2QVTc qvtr2qvtc = transformationAnalysis.getQVTr2QVTc();
this.relationalTransformation2tracePackage = qvtr2qvtc.getRelationalTransformation2TracePackage(transformationAnalysis);
this.cEnforcedDomain = cEnforcedDomain;
this.cMapping = ClassUtil.nonNullState(QVTcoreUtil.getContainingMapping(cEnforcedDomain));
this.cTransformation = ClassUtil.nonNullState(cMapping.getTransformation());
this.cMiddleBottomPattern = ClassUtil.nonNullState(cMapping.getBottomPattern());
this.cMiddleGuardPattern = ClassUtil.nonNullState(cMapping.getGuardPattern());
//
this.cMiddleVariable = (traceClass != null) ? relationAnalysis.traceIsRealized() ? addCoreRealizedVariable("trace", traceClass) : addCoreGuardVariable("trace", traceClass) : null;
this.rThisVariable = QVTbaseUtil.getContextVariable(environmentFactory.getStandardLibrary(), QVTbaseUtil.getContainingTransformation(rEnforcedDomain));
this.cThisVariable = QVTbaseUtil.getContextVariable(environmentFactory.getStandardLibrary(), cTransformation);
ThisVariable2Variable thisVariableAnalysis = new ThisVariable2Variable(this, rThisVariable, cThisVariable);
addVariableAnalysis(thisVariableAnalysis);
}
/**
* Add the predicate "cLeftExpression = cRightExpression" to cCorePattern.
* @throws CompilerChainException
*/
protected void addConditionPredicate(@NonNull CorePattern cCorePattern, @NonNull OCLExpression cLeftExpression, @NonNull OCLExpression cRightExpression) throws CompilerChainException {
OperationCallExp eTerm = createOperationCallExp(cLeftExpression, "=", cRightExpression);
addPredicate(cCorePattern, eTerm);
}
/**
* Create a core Variable with a name and type in the middle guard pattern. The variable has no corresponding relation variable.
* @throws CompilerChainException
*/
public @NonNull Variable addCoreGuardVariable(@NonNull String name, @NonNull Type type) throws CompilerChainException {
CoreVariable2Variable analysis = new CoreVariable2Variable(this, name, type, null);
Variable cVariable = analysis.getCoreVariable();
addVariableAnalysis(analysis);
cMiddleGuardPattern.getVariable().add(cVariable);
return cVariable;
}
/**
* Create a core RealizedVariable with a name and type in the middle bottom pattern. The variable has no corresponding relation variable.
* @throws CompilerChainException
*/
public @NonNull RealizedVariable addCoreRealizedVariable(@NonNull String name, @NonNull Type type) throws CompilerChainException {
CoreVariable2Variable analysis = new CoreVariable2Variable(this, name, type);
RealizedVariable cVariable = analysis.getCoreRealizedVariable();
addVariableAnalysis(analysis);
cMiddleBottomPattern.getRealizedVariable().add(cVariable);
return cVariable;
}
public @NonNull Variable addCoreVariable(@NonNull String name, @NonNull OCLExpression mMember) throws CompilerChainException {
CoreVariable2Variable analysis = new CoreVariable2Variable(this, name, ClassUtil.nonNullState(mMember.getType()), mMember);
Variable cVariable = analysis.getCoreVariable();
addVariableAnalysis(analysis);
cMiddleGuardPattern.getVariable().add(cVariable);
return cVariable;
}
public void addNavigationAssignment(@NonNull Variable rTargetVariable, @NonNull Property targetProperty, @NonNull OCLExpression cExpression, @Nullable Boolean isPartial) throws CompilerChainException {
getVariableAnalysis(rTargetVariable).addNavigationAssignment(targetProperty, cExpression, isPartial);
}
public void addNavigationPredicate(@NonNull CorePattern cCorePattern, @NonNull Variable rTargetVariable, @NonNull Property targetProperty, @NonNull OCLExpression cExpression) throws CompilerChainException {
Variable cTargetVariable = getCoreVariable(rTargetVariable);
NavigationCallExp cNavigationExp = createNavigationCallExp(createVariableExp(cTargetVariable), targetProperty);
if (cExpression instanceof VariableExp) {
addConditionPredicate(cCorePattern, cExpression, cNavigationExp);
}
else {
addConditionPredicate(cCorePattern, cNavigationExp, cExpression);
}
}
protected void addPredicate(@NonNull CorePattern cExpectedCorePattern, @NonNull OCLExpression cExpression) throws CompilerChainException {
assert cMapping == QVTcoreUtil.getContainingMapping(cExpectedCorePattern);
QVTr2QVTc.SYNTHESIS.println(" addPredicate " + cExpression);
Set<@NonNull Variable> cReferredVariables = new HashSet<>();
gatherReferredVariables(cReferredVariables, cExpression);
boolean isGuard = true;
boolean isMiddle = false;
CorePattern cReferredPattern = null;
for (@NonNull Variable cReferredVariable : cReferredVariables) {
Variable2Variable analysis = cVariable2analysis.get(cReferredVariable);
if (analysis == null) {
isGuard = false;
isMiddle = true;
break;
}
else {
CorePattern corePattern = analysis.getCorePattern();
if (corePattern == null) {
}
else if (!(corePattern instanceof GuardPattern)) {
isGuard = false;
}
if (cReferredPattern == null) {
cReferredPattern = corePattern;
}
else if (cReferredPattern != corePattern) {
isMiddle = true;
}
}
}
if (isMiddle) {
cReferredPattern = isGuard ? cMiddleGuardPattern : cMiddleBottomPattern;
}
else if (cReferredPattern != null) {
cReferredPattern = isGuard ? cReferredPattern.getArea().getGuardPattern() : cReferredPattern.getArea().getBottomPattern();
}
// assert cExpectedCorePattern == cReferredPattern;
if (cReferredPattern != null) {
Predicate cPredicate = createPredicate(cExpression);
/*cExpectedCorePattern*/cReferredPattern.getPredicate().add(cPredicate);
}
}
/**
* Add the assignment for rVariable to the middle BottomPattern. If isOptional, a missing trace property is ignored.
*
* Returns the core variant of the relation variable.
*/
public @NonNull Variable addTraceNavigationAssignment(@NonNull Variable rVariable, boolean isOptional) throws CompilerChainException {
@SuppressWarnings("unused")
boolean traceIsRealized = getRelationAnalysis().traceIsRealized();
// assert traceIsRealized;
VariableDeclaration cMiddleRealizedVariable2 = getMiddleVariable();
Variable cVariable = getCoreVariable(rVariable); //getCoreRealizedVariable(rTargetVariable);
Property cTargetProperty = relationalTransformation2tracePackage.basicGetTraceProperty(QVTrelationUtil.getType(cMiddleRealizedVariable2), rVariable);
if (!isOptional && (cTargetProperty == null)) { // FIXME debugging
cTargetProperty = relationalTransformation2tracePackage.basicGetTraceProperty(QVTrelationUtil.getType(cMiddleRealizedVariable2), rVariable);
}
assert isOptional || (cTargetProperty != null);
if (cTargetProperty != null) {
assert (!cTargetProperty.isIsMany() || (cVariable.getType() instanceof CollectionType));
VariableExp cSlotVariableExp = createVariableExp(cMiddleRealizedVariable2);
OCLExpression cExpression = createVariableExp(cVariable);
NavigationAssignment cAssignment = createNavigationAssignment(cSlotVariableExp, cTargetProperty, cExpression, false);
QVTr2QVTc.SYNTHESIS.println(" addPropertyAssignment " + cAssignment);
assertNewAssignment(QVTcoreUtil.getOwnedAssignments(cMiddleBottomPattern), cAssignment);
cMiddleBottomPattern.getAssignment().add(cAssignment);
}
return cVariable;
}
public @NonNull Variable addTraceNavigationAssignment(@NonNull Property cTargetProperty, @NonNull Variable cVariable) throws CompilerChainException {
@SuppressWarnings("unused")
boolean traceIsRealized = getRelationAnalysis().traceIsRealized();
// assert traceIsRealized;
assert (!cTargetProperty.isIsMany() || (cVariable.getType() instanceof CollectionType));
VariableDeclaration cMiddleRealizedVariable2 = getMiddleVariable();
VariableExp cSlotVariableExp = createVariableExp(cMiddleRealizedVariable2);
OCLExpression cExpression = createVariableExp(cVariable);
NavigationAssignment cAssignment = createNavigationAssignment(cSlotVariableExp, cTargetProperty, cExpression, false);
QVTr2QVTc.SYNTHESIS.println(" addPropertyAssignment " + cAssignment);
assertNewAssignment(QVTcoreUtil.getOwnedAssignments(cMiddleBottomPattern), cAssignment);
cMiddleBottomPattern.getAssignment().add(cAssignment);
return cVariable;
}
/**
* Add a predicate for rVariable wrt its trace in the middle GuardPattern.
*
* Returns the core variant of the relation variable.
*/
public @NonNull Variable addTraceNavigationPredicate(@NonNull Variable rVariable) throws CompilerChainException {
VariableDeclaration cMiddleRealizedVariable2 = getMiddleVariable();
Variable cVariable = getCoreVariable(rVariable); //getCoreRealizedVariable(rTargetVariable);
Property cTargetProperty = relationalTransformation2tracePackage.basicGetTraceProperty(QVTrelationUtil.getType(cMiddleRealizedVariable2), rVariable);
assert cTargetProperty != null;
assert (!cTargetProperty.isIsMany() || (cVariable.getType() instanceof CollectionType));
VariableExp cSlotVariableExp = createVariableExp(cMiddleRealizedVariable2);
OCLExpression cRightExp = createVariableExp(cVariable);
NavigationCallExp cLeftExp = createNavigationCallExp(cSlotVariableExp, cTargetProperty);
// QVTr2QVTc.SYNTHESIS.println(" addPropertyAssignment " + cAssignment);
addConditionPredicate(cMiddleGuardPattern, cLeftExp, cRightExp);
return cVariable;
}
public void addVariableAnalysis(@NonNull Variable2Variable analysis) {
Variable cVariable = analysis.getCoreVariable();
cVariable2analysis.put(cVariable, analysis);
VariableDeclaration rVariable = analysis.getRelationVariable();
if (rVariable != null) {
rVariable2analysis.put(rVariable, analysis);
}
}
public void assertNewAssignment(@NonNull Iterable<@NonNull Assignment> oldAssignments, @NonNull NavigationAssignment newAssignment) {
// if ("tr.action := sm".equals(newAssignment.toString())) {
// newAssignment.toString();
// }
OCLExpression newSlotExpression = newAssignment.getSlotExpression();
if (newSlotExpression instanceof VariableExp) {
VariableDeclaration newVariable = ((VariableExp)newSlotExpression).getReferredVariable();
Property targetProperty = QVTcoreUtil.getTargetProperty(newAssignment);
for (@NonNull Assignment oldAssignment : oldAssignments) {
if (oldAssignment instanceof NavigationAssignment) {
if (QVTcoreUtil.getTargetProperty((NavigationAssignment)oldAssignment) == targetProperty) {
OCLExpression oldSlotExpression = ((NavigationAssignment)oldAssignment).getSlotExpression();
if (oldSlotExpression instanceof VariableExp) {
VariableDeclaration oldVariable = ((VariableExp)oldSlotExpression).getReferredVariable();
assert oldVariable != newVariable : "Repeated assignment: \"" + oldAssignment + "\", \"" + newAssignment + "\"";
}
}
}
}
}
}
protected @Nullable Variable2Variable basicGetVariableAnalysis(@NonNull Variable relationVariable) {
return rVariable2analysis.get(relationVariable);
}
public void check() {
for (@NonNull Variable2Variable analysis : rVariable2analysis.values()) {
analysis.check();
}
}
public @NonNull Iterable<@NonNull Variable2Variable> getAnalyses() {
return rVariable2analysis.values();
}
public @NonNull CoreDomain getCoreDomain(@NonNull TypedModel rTypedModel) {
TypedModel cTypedModel = relationAnalysis.getTransformationAnalysis().getQVTr2QVTc().getCoreTypedModel(rTypedModel);
return QVTcoreUtil.getDomain(cMapping, cTypedModel);
}
public @NonNull Variable getCoreThisVariable() {
return cThisVariable;
}
public @NonNull Variable getCoreVariable(@NonNull Variable rVariable) { // doRVarToMVar
return getVariableAnalysis(rVariable).getCoreVariable();
}
protected @NonNull Variable2Variable getCoreVariableAnalysis(@NonNull VariableDeclaration coreVariable) {
return ClassUtil.nonNullState(cVariable2analysis.get(coreVariable));
}
public @NonNull BottomPattern getMiddleBottomPattern() {
return cMiddleBottomPattern;
}
public @NonNull GuardPattern getMiddleGuardPattern() {
return cMiddleGuardPattern;
}
public @NonNull VariableDeclaration getMiddleVariable() {
return ClassUtil.nonNullState(cMiddleVariable);
}
public @NonNull RelationAnalysis getRelationAnalysis() {
return relationAnalysis;
}
@Nullable OCLExpression getTemplateExp(@NonNull ObjectTemplateExp objectTemplateExp, @NonNull Parameter keyParameter) {
String keyParameterName = keyParameter.getName();
for (@NonNull PropertyTemplateItem propertyTemplateItem : ClassUtil.nullFree(objectTemplateExp.getPart())) {
Property property = propertyTemplateItem.getReferredProperty();
if (ClassUtil.safeEquals(property.getName(), keyParameterName)) {
return propertyTemplateItem.getValue();
}
}
EObject eContainer = objectTemplateExp.eContainer();
if (eContainer instanceof PropertyTemplateItem) {
PropertyTemplateItem containingPropertyTemplateItem = (PropertyTemplateItem)eContainer;
Property property = containingPropertyTemplateItem.getReferredProperty();
Property oppositeProperty = property != null ? property.getOpposite() : null;
if ((oppositeProperty != null) && ClassUtil.safeEquals(oppositeProperty.getName(), keyParameterName)) {
return containingPropertyTemplateItem.getObjContainer();
}
}
return null;
}
public @NonNull String getUniqueVariableName(@NonNull String name, @NonNull Variable2Variable originator) {
Object oldOriginator = name2originator.get(name);
if (oldOriginator != null) {
assert oldOriginator != originator; // Lazy re-creation should not occur.
for (int i = 0; true; i++) {
String newName = name + "_" + i;
if (!name2originator.containsKey(newName)) {
name = newName;
break;
}
}
}
name2originator.put(name, originator);
return name;
}
protected @NonNull Variable2Variable getVariableAnalysis(@NonNull Variable relationVariable) {
Variable2Variable analysis = rVariable2analysis.get(relationVariable);
if (analysis == null) {
assert QVTbaseUtil.basicGetContainingTransformation(relationVariable) instanceof RelationalTransformation;
if (relationVariable instanceof IteratorVariable) {
analysis = new IteratorVariable2Variable(this, (IteratorVariable)relationVariable);
}
else if (relationVariable instanceof LetVariable) {
analysis = new LetVariable2Variable(this, (LetVariable)relationVariable);
}
else {
analysis = new RelationVariable2Variable(this, relationVariable);
}
rVariable2analysis.put(relationVariable, analysis);
}
return analysis;
}
public boolean isAbstract() {
return relationAnalysis.getRelation().isIsAbstract();
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
List<@NonNull String> names = new ArrayList<>(name2originator.keySet());
Collections.sort(names);
for (@NonNull String name : names) {
if (s.length() > 0) {
s.append("\n");
}
s.append(name + " => " );
Object originator = name2originator.get(name);
if (originator != this) {
s.append(originator);
}
}
return s.toString();
}
}