| /******************************************************************************* |
| * Copyright (c) 2017, 2019 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 (inspired by Horacio Hoyos' prototype) |
| ******************************************************************************/ |
| package org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace; |
| |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| 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.utilities.ClassUtil; |
| import org.eclipse.ocl.pivot.utilities.PivotUtil; |
| import org.eclipse.qvtd.compiler.CompilerChainException; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.HeadNodeGroup; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.trace.Element2MiddleProperty; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.InvocationAnalysis; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.QVTrelationNameGenerator; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.RelationAnalysis; |
| import org.eclipse.qvtd.pivot.qvtbase.TypedModel; |
| import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil; |
| import org.eclipse.qvtd.pivot.qvtschedule.Edge; |
| import org.eclipse.qvtd.pivot.qvtschedule.Node; |
| import org.eclipse.qvtd.pivot.qvtschedule.RuleRegion; |
| import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil; |
| |
| import com.google.common.collect.Iterables; |
| |
| /** |
| * A RelationAnalysis2TraceClass supervises the creation of a trace class for a relation, which may be abstract. |
| * |
| * If the relation participates in an override hierarchy, the trace class specifies the trace intrerface |
| * of the base relation as its direct superclass regardless of the complexity of the override hierarchy. |
| * |
| * The trace class provides a trace property for all traceable properties, including those inherited from |
| * the root relation trace interface. This ensures that each of the concrete trace class is navigable via their |
| * concrete trace property, while the successful execution is navigabel via the trace interface. |
| * |
| * The trace class for a relation within an override hierarchy provides a status property to facilitate mediation |
| * of the overriding relation executions. |
| * |
| * The trace class of a relation whose successful execution is monitored by a when predicate also provides |
| * a success property. |
| */ |
| public class RelationAnalysis2TraceClass extends AbstractRelationAnalysis2MiddleType |
| { |
| private @Nullable Map<@NonNull InvocationAnalysis, @NonNull Invocation2TraceProperty> invocationAnalysis2relation2traceProperty = null; |
| |
| /** |
| * Name to corresponding future trace property |
| */ |
| private final @NonNull Map<@NonNull String, /*@NonNull*/ Element2MiddleProperty> name2element2traceProperty = new HashMap<>(); |
| |
| public RelationAnalysis2TraceClass(@NonNull RelationAnalysis2TraceGroup relationAnalysis2traceGroup, @NonNull String middleClassName) { |
| super(relationAnalysis2traceGroup, middleClassName); |
| // traceClass.setIsAbstract(relation.isIsAbstract()); |
| // if (relation.isIsAbstract()) { |
| // middleClass.getOwningPackage().getOwnedClasses().remove(middleClass); |
| // } |
| } |
| |
| /* @Override |
| public void analyzeInheritance() { |
| Relation overriddenRelation = QVTrelationUtil.basicGetOverrides(relation); |
| if (overriddenRelation != null) { |
| Relation2TraceClass.@NonNull Internal overriddenRelation2TraceClass = relationalTransformation2tracePackage.getRelation2TraceClass(overriddenRelation); |
| traceClass.getSuperClasses().add(overriddenRelation2TraceClass.getTraceInterface()); |
| } |
| } */ |
| |
| /* protected void analyzeNonRootTemplateVariables(boolean manyTraces) { |
| // |
| // Traverse the domain patterns to prepare a trace property for each bound variable. |
| // |
| // FIXME to handle the obscure case of a diamond traversal in which the second path discovers that |
| // unitOpposites apply, we should preferentially descend unit paths, deferring non-unit paths til later. |
| // |
| /* for (@NonNull Domain domain : QVTbaseUtil.getOwnedDomains(rule)) { |
| for (@NonNull DomainPattern rDomainPattern : QVTbaseUtil.getOwnedPatterns(domain)) { |
| TemplateExp rTemplateExp = QVTrelationUtil.getOwnedTemplateExpression(rDomainPattern); |
| TypedModel rTypedModel = QVTbaseUtil.getTypedModel(domain); |
| analyzeTemplateVariables(rTemplateExp, rTypedModel, !manyTraces); |
| } |
| } * / |
| } */ |
| |
| /** |
| * Traverse a Pattern hierarchy to prepare/refine a trace property for each invocation argument variable. |
| * |
| private void analyzePredicateVariables(@NonNull Pattern rPattern, boolean isWhen) { |
| for (@NonNull Predicate rPredicate : QVTrelationUtil.getOwnedPredicates(rPattern)) { |
| OCLExpression rConditionExpression = QVTrelationUtil.getConditionExpression(rPredicate); |
| if (rConditionExpression instanceof RelationCallExp) { |
| RelationCallExp rInvocation = (RelationCallExp)rConditionExpression; |
| Relation invokedRelation = QVTrelationUtil.getReferredRelation(rInvocation); |
| if (!invokedRelation.isIsTopLevel()) { |
| String invocationPropertyName = isWhen ? nameGenerator.createWhenInvocationPropertyName(invokedRelation) : nameGenerator.createWhereInvocationPropertyName(invokedRelation); |
| // getInvocation2TraceProperty(invocationPropertyName, rInvocation); |
| } |
| else { |
| List<@NonNull OCLExpression> rArguments = QVTrelationUtil.Internal.getOwnedArgumentsList(rInvocation); |
| for (int i = 0; i < rArguments.size(); i++) { |
| OCLExpression rArgument = rArguments.get(i); |
| if (rArgument instanceof VariableExp) { |
| VariableDeclaration rVariable = QVTrelationUtil.getReferredVariable((VariableExp)rArgument); |
| RelationDomain rDomain = QVTrelationUtil.getRelationCallExpArgumentDomain(rInvocation, i); |
| getVariableDeclaration2TraceProperty(rDomain.getTypedModel(), rVariable, false); |
| } |
| } |
| } |
| } |
| } |
| } */ |
| |
| protected void analyzePatternNodes(@NonNull List<@NonNull HeadNodeGroup> headNodeGroups) { |
| // String name = relation.getName(); |
| boolean manyTracesPerHead = headNodeGroups.size() > 2; |
| Set<@NonNull Node> allHeadGroupNodes = new HashSet<>(); |
| for (@NonNull HeadNodeGroup headNodeGroup : headNodeGroups) { |
| Iterables.addAll(allHeadGroupNodes, headNodeGroup.getHeadNodes()); |
| } |
| List<@NonNull Variable> rootVariables = QVTrelationUtil.getRootVariables(relation); |
| for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(relationAnalysis.getRegion())) { |
| if (node.isPattern() && node.isMatched()) { |
| createVariableDeclaration2TraceProperty(node, rootVariables, allHeadGroupNodes, manyTracesPerHead); |
| } |
| else if (/*node.isPattern() &&*/ node.isMatched() && !node.isConstant()) { |
| String name = node.getName(); |
| if ("atlHelper".equals(name)) { |
| getClass(); |
| } |
| createVariableDeclaration2TraceProperty(node, rootVariables, allHeadGroupNodes, manyTracesPerHead); |
| } |
| } |
| // |
| // Create a trace for all predicated ends of realized edges to ensure that no rediscovery |
| // of predicates is needed after a region is partitioned. |
| // |
| for (@NonNull Edge edge : QVTscheduleUtil.getOwnedEdges(relationAnalysis.getRegion())) { |
| if (edge.isRealized()) { |
| Node sourceNode = QVTscheduleUtil.getSourceNode(edge); |
| Node targetNode = QVTscheduleUtil.getTargetNode(edge); |
| if (sourceNode.isPredicated()) { |
| createVariableDeclaration2TraceProperty(sourceNode, rootVariables, allHeadGroupNodes, manyTracesPerHead); |
| } |
| if (targetNode.isPredicated()) { |
| createVariableDeclaration2TraceProperty(targetNode, rootVariables, allHeadGroupNodes, manyTracesPerHead); |
| } |
| } |
| } |
| // |
| // Implicit/iterator variables do not have unit trace opposites. |
| // |
| /* for (@NonNull Variable rVariable : QVTrelationUtil.getOwnedVariables(rule)) { |
| if (!(rVariable instanceof IteratorVariable) && !(rVariable instanceof TemplateVariable) && !rVariable.isIsImplicit()) { |
| assert rVariable instanceof SharedVariable; |
| getVariableDeclaration2TraceProperty(null, rVariable, false); |
| } |
| } */ |
| } |
| |
| /* @Override |
| public void analyzeInheritance() { |
| Relation overriddenRelation = QVTrelationUtil.basicGetOverrides(relation); |
| if (overriddenRelation != null) { |
| Relation2TraceClass.@NonNull Internal overriddenRelation2TraceClass = relationalTransformation2tracePackage.getRelation2TraceClass(overriddenRelation); |
| traceClass.getSuperClasses().add(overriddenRelation2TraceClass.getTraceInterface()); |
| } |
| } */ |
| |
| @Override |
| public void analyzeTraceElements(@NonNull List<@NonNull HeadNodeGroup> headNodeGroups) throws CompilerChainException { |
| // |
| // If there is a trace interface, then it is the superclass, otherwise the Execution class. |
| // |
| RelationAnalysis2TraceGroup baseRelationAnalysis2TraceGroup = relationAnalysis2traceGroup.getBaseRelationAnalysis2TraceGroup(); |
| RelationAnalysis2TraceInterface baseRelationAnalysis2traceInterface = baseRelationAnalysis2TraceGroup.basicGetRuleAnalysis2TraceInterface(); |
| if (baseRelationAnalysis2traceInterface != null) { |
| middleClass.getSuperClasses().add(baseRelationAnalysis2traceInterface.getMiddleClass()); |
| } |
| else { |
| middleClass.getSuperClasses().add(getTransformation2TracePackage().getExecutionClass()); |
| } |
| // |
| // If there is a trace interface or a when invocation then there is a trace class success. |
| // |
| // if ((baseRelationAnalysis2traceInterface != null) || getRuleAnalysis().hasIncomingWhenInvocationAnalyses()) { |
| // createRelation2StatusProperty(relationAnalysis2traceGroup.getNameGenerator().createInternalTraceStatusPropertyName()); |
| // } |
| // |
| // No result property. |
| // |
| // |
| // Create an incoming invocation property for each where invocation. |
| // |
| Iterable<@NonNull InvocationAnalysis> outgoingWhereInvocationAnalyses = getRuleAnalysis().basicGetOutgoingWhereInvocationAnalyses(); |
| if (outgoingWhereInvocationAnalyses != null) { |
| for (@NonNull InvocationAnalysis outgoingWhereInvocationAnalysis : outgoingWhereInvocationAnalyses) { |
| createInvocation2TraceProperty(outgoingWhereInvocationAnalysis); |
| } |
| } |
| // |
| // Create an outgoing invocation property for each when invocation. |
| // |
| if (relation.isIsTopLevel()) { |
| Iterable<@NonNull InvocationAnalysis> outgoingWhenInvocationAnalyses = getRuleAnalysis().basicGetOutgoingWhenInvocationAnalyses(); |
| if (outgoingWhenInvocationAnalyses != null) { |
| for (@NonNull InvocationAnalysis outgoingWhenInvocationAnalysis : outgoingWhenInvocationAnalyses) { |
| createInvocation2TraceProperty(outgoingWhenInvocationAnalysis); |
| } |
| } |
| } |
| // |
| // Create one trace property per root variable. |
| // |
| if (!QVTrelationUtil.hasOverrides(relation)) { |
| analyzeRootTemplateVariables(headNodeGroups); |
| } |
| // |
| // ?? |
| // |
| // if (relationAnalysis2traceGroup.basicGetRuleAnalysis2TraceInterface() == null) { |
| // } |
| // else { |
| // installRootVariableTraceProperties(); |
| // } |
| |
| // boolean manyTraces = analyzeTraceMultiplicity(headNode2headGroupNodes); |
| // for (@NonNull VariableDeclaration rootVariable : QVTrelationUtil.getRootVariables(relation)) { |
| // Node rootNode = relationAnalysis.getRegion().getNode(rootVariable); |
| // assert rootNode != null; |
| // allHeadGroupNodes.remove(rootNode); |
| // } |
| analyzePatternNodes(headNodeGroups); |
| // analyzeSharedVariables(); |
| // analyzeNonRootTemplateVariables(manyTraces); |
| // analyzeInvocationVariables(); |
| // |
| // If there is a trace interface or a when invocation then there is a trace class global success. |
| // |
| analyzeGlobalSuccessNode(baseRelationAnalysis2traceInterface); |
| } |
| |
| // |
| // If there is a trace interface or a when invocation then there is a trace class global success. |
| // |
| protected void analyzeGlobalSuccessNode(@Nullable RelationAnalysis2TraceInterface baseRelationAnalysis2traceInterface) { |
| boolean hasTraceInterface = baseRelationAnalysis2traceInterface != null; |
| boolean hasWhenInvocation = getRuleAnalysis().hasIncomingWhenInvocationAnalyses(); |
| if (hasTraceInterface) { // FIXME Bug 540797 - this is used by e.g. mapBooleanExp in ATL2QVTr |
| return; |
| } |
| if (!hasWhenInvocation) { // FIXME enforced guard needs globalSucess |
| return; |
| } |
| if (!QVTrelationUtil.hasOverrides(relation)) { |
| boolean hasPredicatedElement = false; |
| RuleRegion region = getRuleAnalysis().getRegion(); |
| for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) { |
| if (node.isPredicated()) { |
| hasPredicatedElement = true; |
| break; |
| } |
| } |
| if (!hasPredicatedElement) { |
| for (@NonNull Edge edge : QVTscheduleUtil.getOwnedEdges(region)) { |
| if (edge.isPredicated()) { |
| hasPredicatedElement = true; |
| break; |
| } |
| } |
| } |
| if (!hasPredicatedElement) { |
| return; // extStat is identical to trace class existence |
| } |
| } |
| QVTrelationNameGenerator nameGenerator = relationAnalysis2traceGroup.getNameGenerator(); |
| String globalSuccessPropertyName = nameGenerator.createTraceGlobalSuccessPropertyName(); |
| createRelation2GlobalSuccessProperty(globalSuccessPropertyName); |
| } |
| |
| /* @Override |
| public @Nullable RelationAnalysis2MiddleType getSuperRuleAnalysis2MiddleType() { |
| RelationAnalysis2TraceInterface ruleAnalysis2TraceInterface = relationAnalysis2traceGroup.basicGetRuleAnalysis2TraceInterface(); |
| if (ruleAnalysis2TraceInterface != null) { |
| return ruleAnalysis2TraceInterface; |
| } |
| else { |
| Rule overriddenRule = getRule().getOverridden(); |
| if (overriddenRule != null) { |
| return transformationAnalysis2tracePackage.getRuleAnalysis2TraceGroup(overriddenRule).getRuleAnalysis2TraceClass(); |
| } |
| else { |
| return null; |
| } |
| } |
| } */ |
| |
| @Override |
| public @Nullable Element2MiddleProperty basicGetRelation2GlobalSuccessProperty() { |
| Element2MiddleProperty relation2SuccessProperty = super.basicGetRelation2GlobalSuccessProperty(); |
| if (relation2SuccessProperty != null) { |
| return relation2SuccessProperty; |
| } |
| RelationAnalysis2TraceGroup baseRelationAnalysis2TraceGroup = relationAnalysis2traceGroup.getBaseRelationAnalysis2TraceGroup(); |
| RelationAnalysis2TraceInterface baseRelationAnalysis2traceInterface = baseRelationAnalysis2TraceGroup.basicGetRuleAnalysis2TraceInterface(); |
| if (baseRelationAnalysis2traceInterface != null) { |
| return baseRelationAnalysis2traceInterface.basicGetRelation2GlobalSuccessProperty(); |
| } |
| return null; |
| } |
| |
| /** |
| * Descend the templateExp hierarchy to prepare a trace property for each bound variable. |
| * |
| private void analyzeTemplateVariables(@NonNull TemplateExp templateExp, @NonNull TypedModel rTypedModel, boolean isOneToOne) { |
| Variable templateVariable = QVTrelationUtil.getBindsTo(templateExp); |
| VariableDeclaration2TraceProperty variableDeclaration2TraceProperty = basicGetVariableDeclaration2TraceProperty(templateVariable); |
| if (variableDeclaration2TraceProperty != null) { |
| if (templateExp instanceof ObjectTemplateExp) { |
| for (@NonNull PropertyTemplateItem rPropertyTemplateItem : QVTrelationUtil.getOwnedParts((ObjectTemplateExp)templateExp)) { |
| boolean isNestedOneToOne = false; |
| Property property = QVTrelationUtil.getReferredProperty(rPropertyTemplateItem); |
| if (!property.isIsMany()) { |
| Property oppositeProperty = property.getOpposite(); |
| if ((oppositeProperty != null) && !oppositeProperty.isIsMany()) { |
| isNestedOneToOne = isOneToOne; |
| } |
| } |
| OCLExpression valueExpression = QVTrelationUtil.getOwnedValue(rPropertyTemplateItem); |
| if (valueExpression instanceof TemplateExp) { |
| TemplateExp templateValueExpression = (TemplateExp)valueExpression; |
| Variable itemVariable = QVTrelationUtil.getBindsTo(templateValueExpression); |
| if (QVTrelationUtil.getElementalType(QVTrelationUtil.getType(itemVariable)) instanceof DataType) { |
| getVariableDeclaration2TraceProperty(null, itemVariable, false); |
| } |
| else { |
| assert itemVariable instanceof TemplateVariable; |
| getVariableDeclaration2TraceProperty(rTypedModel, itemVariable, isNestedOneToOne); |
| analyzeTemplateVariables(templateValueExpression, rTypedModel, isOneToOne); |
| } |
| } |
| else if (valueExpression instanceof VariableExp) { |
| VariableExp variableExpression = (VariableExp)valueExpression; |
| Variable itemVariable = QVTrelationUtil.getReferredVariable(variableExpression); |
| getVariableDeclaration2TraceProperty(null, itemVariable, isNestedOneToOne); |
| } |
| } |
| } |
| else if (templateExp instanceof CollectionTemplateExp) { |
| for (@NonNull OCLExpression memberExpression : QVTrelationUtil.getOwnedMembers((CollectionTemplateExp)templateExp)) { |
| if (memberExpression instanceof TemplateExp) { |
| TemplateExp templateValueExpression = (TemplateExp)memberExpression; |
| Variable itemVariable = QVTrelationUtil.getBindsTo(templateValueExpression); |
| assert itemVariable instanceof TemplateVariable; |
| getVariableDeclaration2TraceProperty(rTypedModel, itemVariable, false); |
| analyzeTemplateVariables(templateValueExpression, rTypedModel, false); |
| } |
| else if (memberExpression instanceof VariableExp) { |
| VariableExp variableExpression = (VariableExp)memberExpression; |
| Variable itemVariable = QVTrelationUtil.getReferredVariable(variableExpression); |
| getVariableDeclaration2TraceProperty(null, itemVariable, false); |
| } |
| } |
| } |
| } |
| } */ |
| |
| // |
| // Determine the trace variables and whether they have a to-one opposite |
| // |
| /* protected boolean analyzeTraceMultiplicity(@NonNull Map<@NonNull Node, @NonNull Set<@NonNull Node>> headNode2headGroupNodes) { |
| // |
| // Determine whether a navigation from the trace to an unambiguous left/right object can ever be possible. |
| // |
| /* boolean manyTraces = hasManyRootMatches() || hasCollectionMemberMatches() || hasMultiObjectMatches(); |
| if (!manyTraces) { |
| for (@NonNull Variable rVariable : QVTbaseUtil.getOwnedVariables(rule)) { |
| if (hasManyVariableMatches(rVariable)) { |
| manyTraces = true; |
| break; |
| } |
| } |
| } |
| return manyTraces; * / |
| int maxHeadCount = 0; |
| Map<@NonNull TypedModel, @NonNull Integer> typedModel2headCount = new HashMap<>(); |
| for (@NonNull Node headNode : headNode2headGroupNodes.keySet()) { |
| assert headNode.isPattern(); |
| TypedModel typedModel = QVTscheduleUtil.getTypedModel(headNode); |
| Integer headCount = typedModel2headCount.get(typedModel); |
| headCount = headCount != null ? headCount+1 : 1; |
| typedModel2headCount.put(typedModel, headCount); |
| if (headCount > maxHeadCount) { |
| maxHeadCount = headCount; |
| } |
| } |
| assert maxHeadCount > 0; |
| return maxHeadCount > 1; |
| } */ |
| |
| public @NonNull Invocation2TraceProperty createInvocation2TraceProperty(@NonNull InvocationAnalysis invocationAnalysis) { |
| Map<@NonNull InvocationAnalysis, @NonNull Invocation2TraceProperty> invocationAnalysis2relation2traceProperty2 = invocationAnalysis2relation2traceProperty; |
| if (invocationAnalysis2relation2traceProperty2 == null) { |
| invocationAnalysis2relation2traceProperty = invocationAnalysis2relation2traceProperty2 = new HashMap<>(); |
| } |
| RelationAnalysis invokedRelationAnalysis = invocationAnalysis.getInvokedRelationAnalysis().getBaseRelationAnalysis(); |
| RelationAnalysis2TraceGroup invokedRule2TraceGroup = invokedRelationAnalysis.getRuleAnalysis2TraceGroup(); |
| String nameHint = relationAnalysis2traceGroup.getNameGenerator().createInvocationTraceProperty(invokedRelationAnalysis.getRule()); |
| Invocation2TraceProperty relation2traceProperty = new Invocation2TraceProperty(this, nameHint, invokedRule2TraceGroup.getInvocationClass(), invocationAnalysis.isWhen() && !invocationAnalysis.isTop()); |
| Invocation2TraceProperty oldRelation2traceProperty = invocationAnalysis2relation2traceProperty2.put(invocationAnalysis, relation2traceProperty); |
| assert oldRelation2traceProperty == null; |
| return relation2traceProperty; |
| } |
| |
| public @NonNull Property createProperty(@NonNull String name, @NonNull Type type) { |
| String uniqueName = QVTrelationNameGenerator.getUniqueName(name2element2traceProperty.keySet(), name); |
| Property property = PivotUtil.createProperty(uniqueName, type); |
| //FIXME name2element2traceProperty.put(uniqueName, property); |
| return property; |
| } |
| |
| @Override |
| protected @NonNull String createTracePropertyName(@NonNull TypedModel typedModel, @NonNull VariableDeclaration variable) { |
| return getTransformation2TracePackage().getNameGenerator().createTraceClassPropertyName(typedModel, variable); |
| } |
| |
| protected void createVariableDeclaration2TraceProperty(@NonNull Node node, @NonNull List<@NonNull Variable> rootVariables, |
| @NonNull Set<@NonNull Node> allHeadGroupNodes, boolean manyTracesPerHead) { |
| boolean unitOpposite = allHeadGroupNodes.contains(node) && !manyTracesPerHead; |
| TypedModel typedModel = QVTscheduleUtil.getTypedModel(node); |
| VariableDeclaration variable = node.basicGetOriginatingVariable(); |
| if ((variable != null) && !rootVariables.contains(variable)) { |
| VariableDeclaration2TraceProperty variableDeclaration2traceProperty = basicGetVariableDeclaration2TraceProperty(variable); |
| if (variableDeclaration2traceProperty == null) { |
| createVariableDeclaration2TraceProperty(typedModel, variable, unitOpposite); |
| } |
| } |
| } |
| |
| public @NonNull Invocation2TraceProperty getInvocation2TraceProperty(@NonNull InvocationAnalysis invocationAnalysis) { |
| return ClassUtil.nonNullState(ClassUtil.nonNullState(invocationAnalysis2relation2traceProperty).get(invocationAnalysis)); |
| } |
| |
| /* @Override |
| public @Nullable RelationAnalysis2MiddleType getSuperRuleAnalysis2MiddleType() { |
| RelationAnalysis2TraceInterface ruleAnalysis2TraceInterface = relationAnalysis2traceGroup.basicGetRuleAnalysis2TraceInterface(); |
| if (ruleAnalysis2TraceInterface != null) { |
| return ruleAnalysis2TraceInterface; |
| } |
| else { |
| Rule overriddenRule = getRule().getOverridden(); |
| if (overriddenRule != null) { |
| return transformationAnalysis2tracePackage.getRuleAnalysis2TraceGroup(overriddenRule).getRuleAnalysis2TraceClass(); |
| } |
| else { |
| return null; |
| } |
| } |
| } */ |
| |
| @Override |
| public @NonNull String getUniquePropertyName(@NonNull Element2MiddleProperty element2traceProperty, @NonNull String name) { |
| return QVTrelationNameGenerator.getUniqueName(name2element2traceProperty, name, element2traceProperty); |
| } |
| |
| /* private boolean hasCollectionMemberMatches() { |
| for (EObject eObject : new TreeIterable(relation, true)) { |
| if (eObject instanceof CollectionTemplateExp) { |
| List<OCLExpression> members = ((CollectionTemplateExp)eObject).getMember(); |
| if (members.size() > 0) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } */ |
| |
| /** |
| * Return true if there may be more than one trace instance for a given root variable. |
| * |
| private boolean hasManyRootMatches() { |
| // |
| // Only a single root variable in each of just two domains gurantees just one trace per root variable. |
| // |
| List<@NonNull Domain> rDomains = QVTrelationUtil.Internal.getOwnedDomainsList(rule); |
| if (rDomains.size() > 2) { |
| return true; |
| } |
| else { |
| for (@NonNull Domain rDomain : rDomains) { |
| List<Variable> rootVariables = ((RelationDomain)rDomain).getRootVariable(); |
| if (rootVariables.size() > 1) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } */ |
| |
| /* private boolean hasManyVariableMatches(@NonNull Variable rVariable) { |
| for (@NonNull Domain rDomain : QVTrelationUtil.getOwnedDomains(relation)) { |
| Iterable<@NonNull Variable> bindsTo = QVTr2QVTcUtil.getRelationDomainBindsTo((RelationDomain) rDomain); |
| if (Iterables.contains(bindsTo, rVariable)) { |
| return false; |
| } |
| } |
| for (@NonNull EObject eObject : new TreeIterable(relation, true)) { |
| if (eObject instanceof VariableExp) { |
| VariableDeclaration referredVariable = ((VariableExp)eObject).getReferredVariable(); |
| if (referredVariable == rVariable) { |
| EObject eContainer = eObject.eContainer(); |
| if (eContainer instanceof OperationCallExp) { |
| OperationCallExp operationCallExp = (OperationCallExp)eContainer; |
| Operation referredOperation = operationCallExp.getReferredOperation(); |
| assert referredOperation != null; |
| if (operationCallExp.getOwnedArguments().equals(Collections.singletonList(eObject)) && "includes".equals(referredOperation.getName())) { // FIXME stronger test |
| return true; |
| } |
| } |
| // FIXME more cases |
| } |
| } |
| } |
| return false; |
| } */ |
| |
| /* private boolean hasMultiObjectMatches() { |
| for (RelationDomain relationDomain : QVTrelationUtil.getOwnedDomains(rule)) { |
| if (!relationDomain.isIsEnforceable()) { |
| for (EObject eObject : new TreeIterable(relationDomain, true)) { |
| if (eObject instanceof PropertyTemplateItem) { |
| Property referredProperty = QVTrelationUtil.getReferredProperty((PropertyTemplateItem)eObject); |
| if (referredProperty.isIsMany()) { |
| return true; |
| } |
| } |
| } |
| } |
| } |
| return false; |
| } */ |
| |
| protected void reservePropertyName(@NonNull String name) { |
| assert !name2element2traceProperty.containsKey(name); |
| name2element2traceProperty.put(name, null); |
| } |
| |
| @Override |
| public void synthesizeTraceModel() { |
| Map<@NonNull InvocationAnalysis, @NonNull Invocation2TraceProperty> incomingInvocationAnalysis2relation2traceProperty2 = invocationAnalysis2relation2traceProperty; |
| if (incomingInvocationAnalysis2relation2traceProperty2 != null) { |
| for (@NonNull Invocation2TraceProperty relation2traceProperty : incomingInvocationAnalysis2relation2traceProperty2.values()) { |
| relation2traceProperty.synthesizeTraceModel(); |
| } |
| } |
| super.synthesizeTraceModel(); |
| } |
| } |