| /******************************************************************************* |
| * Copyright (c) 2015, 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 |
| *******************************************************************************/ |
| package org.eclipse.qvtd.compiler.internal.qvtr2qvts; |
| |
| import java.util.ArrayList; |
| 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.DataType; |
| 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.Type; |
| import org.eclipse.ocl.pivot.Variable; |
| import org.eclipse.ocl.pivot.VariableDeclaration; |
| import org.eclipse.ocl.pivot.VariableExp; |
| import org.eclipse.ocl.pivot.ids.OperationId; |
| import org.eclipse.ocl.pivot.utilities.ClassUtil; |
| import org.eclipse.ocl.pivot.utilities.PivotUtil; |
| import org.eclipse.ocl.pivot.utilities.TreeIterable; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.UtilityAnalysis; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.trace.Element2MiddleProperty; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.ExpressionSynthesizer; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.RegionHelper; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.RuleAnalysis; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.RuleHeadAnalysis; |
| import org.eclipse.qvtd.compiler.internal.qvtb2qvts.AbstractTransformationAnalysis; |
| import org.eclipse.qvtd.compiler.internal.qvtc2qvtu.QVTuConfiguration; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.RelationAnalysis2TraceGroup; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.RelationalTransformationAnalysis2TracePackage; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.VariableDeclaration2TraceProperty; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.DispatchClass2TraceProperty; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.Relation2ResultProperty; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.RelationAnalysis2DispatchClass; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.RelationAnalysis2MiddleType; |
| import org.eclipse.qvtd.compiler.internal.qvtr2qvts.trace.RelationAnalysis2TraceClass; |
| import org.eclipse.qvtd.pivot.qvtbase.Domain; |
| import org.eclipse.qvtd.pivot.qvtbase.Pattern; |
| import org.eclipse.qvtd.pivot.qvtbase.Predicate; |
| import org.eclipse.qvtd.pivot.qvtbase.TypedModel; |
| import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil; |
| import org.eclipse.qvtd.pivot.qvtrelation.DomainPattern; |
| import org.eclipse.qvtd.pivot.qvtrelation.Key; |
| import org.eclipse.qvtd.pivot.qvtrelation.QVTrelationPackage; |
| 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.RelationDomainAssignment; |
| import org.eclipse.qvtd.pivot.qvtrelation.SharedVariable; |
| import org.eclipse.qvtd.pivot.qvtrelation.TemplateVariable; |
| import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil; |
| import org.eclipse.qvtd.pivot.qvtschedule.RuleRegion; |
| import org.eclipse.qvtd.pivot.qvtschedule.VariableNode; |
| import org.eclipse.qvtd.pivot.qvtschedule.VerdictRegion; |
| import org.eclipse.qvtd.pivot.qvtschedule.Node.Utility; |
| import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum; |
| import org.eclipse.qvtd.pivot.qvtschedule.DispatchRegion; |
| import org.eclipse.qvtd.pivot.qvtschedule.Edge; |
| import org.eclipse.qvtd.pivot.qvtschedule.KeyedValueNode; |
| import org.eclipse.qvtd.pivot.qvtschedule.NavigationEdge; |
| import org.eclipse.qvtd.pivot.qvtschedule.Node; |
| 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 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; |
| |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| |
| /** |
| * A RelationAnalysis provides the analysis a QVTr mapping. |
| */ |
| public class RelationAnalysis extends RuleAnalysis |
| { |
| /** |
| * A Dispatch assists in the synthesis of the dispatch for an override hierarchy. |
| */ |
| protected class Dispatch extends RegionHelper<@NonNull RuleRegion> |
| { |
| public Dispatch(@NonNull RuleRegion ruleRegion) { |
| super(RelationAnalysis.this.getScheduleManager(), ruleRegion); |
| } |
| |
| public void gatherRuleRegions(@NonNull List<@NonNull RuleRegion> ruleRegions) { |
| ruleRegions.add(region); |
| } |
| |
| protected void synthesizeDispatchHierarchy(@NonNull Node traceNode, @NonNull RelationAnalysis2DispatchClass relationAnalysis2dispatchClass, @NonNull Relation relation) { |
| if (!relation.isIsAbstract()) { |
| QVTrelationScheduleManager scheduleManager =(QVTrelationScheduleManager)getScheduleManager(); |
| RelationAnalysis2TraceClass relationAnalysis2TraceClass = scheduleManager.getRuleAnalysis(relation).getRuleAnalysis2TraceGroup().getRuleAnalysis2TraceClass(); |
| ClassDatum dispatchedClassDatum = scheduleManager.getClassDatum(getTraceTypedModel(), relationAnalysis2TraceClass.getMiddleClass()); |
| Node dispatchedNode = createRealizedNode(getName(relation), dispatchedClassDatum, true); |
| DispatchClass2TraceProperty dispatchClass2traceProperty = relationAnalysis2dispatchClass.getDispatchClass2TraceProperty(relation); |
| createRealizedNavigationEdge(traceNode, dispatchClass2traceProperty.getTraceProperty(), dispatchedNode, false); |
| } |
| for (@NonNull Relation overridingRelation : QVTrelationUtil.getOverrides(relation)) { |
| synthesizeDispatchHierarchy(traceNode, relationAnalysis2dispatchClass, overridingRelation); |
| } |
| } |
| |
| /** |
| * Create a realized trace node, a predicated guard node per input root variable and a |
| * predicated property edge between them. |
| */ |
| public void synthesizeElements() { |
| RelationAnalysis2DispatchClass relationAnalysis2dispatchClass = getRuleAnalysis2TraceGroup().getRuleAnalysis2DispatchClass(); |
| // |
| // Create the trace node |
| // |
| Node traceNode = synthesizeTraceNode(relationAnalysis2dispatchClass); |
| // |
| // Create the trace node assignments to guard nodes |
| // |
| synthesizeTraceEdges(traceNode); |
| // |
| // Create the trace node assignments to pattern nodes |
| // |
| synthesizeDispatchHierarchy(traceNode, relationAnalysis2dispatchClass, getRule()); |
| // |
| // |
| // |
| // Iterable<@NonNull Node> headNodes = RuleHeadAnalysis.computeRuleHeadNodes(scheduleManager, region, null); |
| // List<@NonNull Node> headNodesList = QVTscheduleUtil.Internal.getHeadNodesList(region); |
| // headNodesList.clear(); |
| // Iterables.addAll(headNodesList, headNodes); |
| UtilityAnalysis.assignUtilities(scheduleManager, region); |
| } |
| |
| /** |
| * Create the trace node assignments to pattern nodes |
| */ |
| protected void synthesizeTraceEdges(@NonNull Node traceNode) { |
| // assert region.getHeadNodes().isEmpty(); |
| Relation relation = getRule(); |
| boolean isTopLevel = relation.isIsTopLevel(); |
| RelationAnalysis2TraceGroup ruleAnalysis2TraceGroup = getRuleAnalysis2TraceGroup(); |
| RelationAnalysis2DispatchClass ruleAnalysis2dispatchClass = ruleAnalysis2TraceGroup.getRuleAnalysis2DispatchClass(); |
| for (@NonNull RelationDomain relationDomain : QVTrelationUtil.getOwnedDomains(relation)) { |
| if (scheduleManager.isInput(relationDomain)) { |
| for (@NonNull VariableDeclaration variable : QVTrelationUtil.getRootVariables(relationDomain)) { |
| VariableDeclaration2TraceProperty variableDeclaration2traceClassProperty = ruleAnalysis2dispatchClass.getVariableDeclaration2TraceProperty(variable); |
| // VariableDeclaration2TraceProperty variableDeclaration2traceInterfaceProperty = ruleAnalysis2traceInterface.getVariableDeclaration2TraceProperty(variable); |
| Property traceClassProperty = variableDeclaration2traceClassProperty.getTraceProperty(); |
| // Property traceInterfaceProperty = variableDeclaration2traceInterfaceProperty.getTraceProperty(); |
| Node targetNode = createOldNode(variable); |
| boolean isPartial = scheduleManager.computeIsPartial(targetNode, traceClassProperty); |
| createNavigationEdge(traceNode, traceClassProperty, targetNode, isPartial); |
| if (isTopLevel) { |
| region.getHeadNodes().add(targetNode); |
| targetNode.setHead(); |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| /* Relation relation = getRule(); |
| RelationAnalysis relationAnalysis = RelationAnalysis.this.getScheduleManager().getRuleAnalysis(relation); |
| RelationAnalysis2TraceGroup relationAnalysis2TraceGroup = relationAnalysis.getRuleAnalysis2TraceGroup(); |
| RelationAnalysis2MiddleType relationAnalysis2TraceClass = relationAnalysis2TraceGroup.getRuleAnalysis2TraceClass(); |
| Property successProperty = relationAnalysis2TraceClass.getSuccessProperty(); |
| Node falseNode = createBooleanValueNode(true, false); |
| createNavigationEdge(traceNode, successProperty, falseNode, false); */ |
| } |
| |
| /** |
| * Create the trace node |
| */ |
| protected @NonNull Node synthesizeTraceNode(@NonNull RelationAnalysis2DispatchClass relationAnalysis2dispatchClass) { |
| Relation relation = getRule(); |
| TypedModel traceTypedModel = getTraceTypedModel(); |
| ClassDatum dispatchedClassDatum = scheduleManager.getClassDatum(traceTypedModel, relationAnalysis2dispatchClass.getMiddleClass()); |
| if (relation.isIsTopLevel()) { |
| VariableNode realizedDispatchNode = createRealizedNode(QVTrelationNameGenerator.DISPATCHCLASS_SELF_NAME, dispatchedClassDatum, true); |
| realizedDispatchNode.setUtility(Utility.TRACE); |
| return realizedDispatchNode; |
| } |
| else { |
| Node predicatedDispatchNode = createPredicatedNode(QVTrelationNameGenerator.DISPATCHCLASS_SELF_NAME, dispatchedClassDatum, true); |
| predicatedDispatchNode.setUtility(Utility.TRACE); |
| region.getHeadNodes().add(predicatedDispatchNode); |
| predicatedDispatchNode.setHead(); |
| return predicatedDispatchNode; |
| } |
| } |
| } |
| |
| /** |
| * A Verdict assists in the synthesis of the base region that assigns the false success once all overrides have failed. |
| */ |
| protected class Verdict extends RegionHelper<@NonNull RuleRegion> |
| { |
| public Verdict(@NonNull RuleRegion ruleRegion) { |
| super(RelationAnalysis.this.getScheduleManager(), ruleRegion); |
| } |
| |
| public void gatherRuleRegions(@NonNull List<@NonNull RuleRegion> ruleRegions) { |
| ruleRegions.add(getRegion()); |
| } |
| |
| protected void synthesizeDispatchHierarchy(@NonNull Node traceNode, @NonNull RelationAnalysis2DispatchClass relationAnalysis2dispatchClass, @NonNull Relation relation) { |
| if (!relation.isIsAbstract()) { // Cannot test abstract -must test all its overrides |
| // |
| // Create a predicated node for the overriding relation's trace |
| // |
| QVTrelationScheduleManager scheduleManager =(QVTrelationScheduleManager)getScheduleManager(); |
| RelationAnalysis2TraceClass relationAnalysis2TraceClass = scheduleManager.getRuleAnalysis(relation).getRuleAnalysis2TraceGroup().getRuleAnalysis2TraceClass(); |
| RelationAnalysis2MiddleType relationAnalysis2TraceInterface = getBaseRelationAnalysis().getRuleAnalysis2TraceGroup().getRuleAnalysis2TraceInterface(); |
| ClassDatum dispatchedClassDatum = scheduleManager.getClassDatum(getTraceTypedModel(), relationAnalysis2TraceClass.getMiddleClass()); |
| Node dispatchedNode = createPredicatedNode(getName(relation), dispatchedClassDatum, true); |
| // |
| // Reached by the appropriate dispatch navigation. |
| // |
| DispatchClass2TraceProperty dispatchClass2traceProperty = relationAnalysis2dispatchClass.getDispatchClass2TraceProperty(relation); |
| createNavigationEdge(traceNode, dispatchClass2traceProperty.getTraceProperty(), dispatchedNode, false); |
| // |
| // Require the overriding relation to have failed. |
| // |
| Property successProperty = relationAnalysis2TraceInterface.getGlobalSuccessProperty(); |
| createPredicatedSuccess(dispatchedNode, successProperty, false); |
| } |
| for (@NonNull Relation overridingRelation : QVTrelationUtil.getOverrides(relation)) { |
| synthesizeDispatchHierarchy(traceNode, relationAnalysis2dispatchClass, overridingRelation); |
| } |
| } |
| |
| /** |
| * Create a realized trace node, a predicatec guard node per input root variable and a |
| * predicated property edge between them. |
| */ |
| public void synthesizeElements() { |
| RelationAnalysis2DispatchClass relationAnalysis2dispatchClass = getRuleAnalysis2TraceGroup().getRuleAnalysis2DispatchClass(); |
| // |
| // Create the trace node |
| // |
| Node traceNode = synthesizeTraceNode(relationAnalysis2dispatchClass); |
| // |
| // Create the trace node assignments to pattern nodes |
| // |
| synthesizeDispatchHierarchy(traceNode, relationAnalysis2dispatchClass, getRule()); |
| // |
| UtilityAnalysis.assignUtilities(scheduleManager, region); |
| } |
| |
| /** |
| * Create the trace node |
| */ |
| protected @NonNull Node synthesizeTraceNode(@NonNull RelationAnalysis2DispatchClass relationAnalysis2dispatchClass) { |
| Relation relation = getRule(); |
| QVTrelationScheduleManager scheduleManager =(QVTrelationScheduleManager)getScheduleManager(); |
| TypedModel traceTypedModel = scheduleManager.getTraceTypedModel(); |
| ClassDatum dispatchedClassDatum = scheduleManager.getClassDatum(traceTypedModel, relationAnalysis2dispatchClass.getMiddleClass()); |
| Node traceNode = createPredicatedNode(getName(relation), dispatchedClassDatum, true); |
| region.getHeadNodes().add(traceNode); |
| traceNode.setHead(); |
| |
| Property successProperty = relationAnalysis2dispatchClass.getGlobalSuccessProperty(); |
| createRealizedSuccess(traceNode, successProperty, false); |
| |
| return traceNode; |
| } |
| } |
| |
| /** |
| * Synthesizer for the dispatch execution region of an override hierarchy. |
| */ |
| private final @Nullable Dispatch dispatch; |
| |
| /** |
| * Synthesizer for the override verdict region. |
| */ |
| private final @Nullable Verdict verdict; |
| |
| /** |
| * Predicates that are too complex to analyze. i.e. more than a comparison of a bound variable wrt |
| * a property call chain on another bound variable. |
| */ |
| // private final @NonNull Set<@NonNull Predicate> complexPredicates = new HashSet<>(); |
| |
| // private @Nullable Node traceNode = null; |
| |
| /** |
| * The variable initializers, simple predicate reference expression and variable assignment values that define a value for each variable. |
| * Variable initializers are populated lazily since not all LetVariables may even exist for an eager population. |
| */ |
| private @NonNull Map<@NonNull VariableDeclaration, @NonNull List<@NonNull OCLExpression>> variable2expressions = new HashMap<>(); |
| |
| /** |
| * The implicit/when expressions that call this relation. |
| */ |
| private @Nullable List<@NonNull RelationCallExp> incomingWhenInvocations = null; |
| |
| /** |
| * The where expressions that call this relation. |
| */ |
| private @Nullable List<@NonNull RelationCallExp> incomingWhereInvocations = null; |
| |
| /** |
| * The expressions that call this relation from a when clause. |
| */ |
| private @Nullable List<@NonNull InvocationAnalysis> incomingWhenInvocationAnalyses = null; |
| |
| /** |
| * The expressions that call this relation from a where clause. |
| */ |
| private @Nullable List<@NonNull InvocationAnalysis> incomingWhereInvocationAnalyses = null; |
| |
| /** |
| * The expressions that call relations with this relation. |
| */ |
| // private @Nullable List<@NonNull RelationCallExp> outgoingInvocations = null; |
| |
| /** |
| * The expressions that call relations with this relation's when clause. |
| */ |
| private @Nullable List<@NonNull InvocationAnalysis> outgoingWhenInvocationAnalyses = null; |
| |
| /** |
| * The expressions that call relations with this relation's where clause. |
| */ |
| private @Nullable List<@NonNull InvocationAnalysis> outgoingWhereInvocationAnalyses = null; |
| |
| /** |
| * Closure of all overriding relations or null if not overridden. |
| */ |
| // private @Nullable Set<@NonNull RelationAnalysis> overridingRelationAnalyses = null; |
| |
| /** |
| * The RelationAnalysis for the least overridden relationinvoing this relation. |
| * |
| * Populated by analyzeSourceModel. |
| */ |
| private @Nullable RelationAnalysis baseRelationAnalysis = null; |
| |
| /** |
| * The output variables that are realized. These variables are logically created as a single composite object. |
| * |
| * Populated by analyzeSourceModel. |
| */ |
| private @Nullable Set<@NonNull VariableDeclaration> realizedOutputVariables = null; |
| |
| /** |
| * The output variables that are created/shared by a key constructor. |
| * |
| * Populated by analyzeSourceModel. |
| */ |
| private @Nullable Set<@NonNull VariableDeclaration> keyedOutputVariables = null; |
| |
| /** |
| * The TemplateExp that binds each variable |
| * |
| * Populated by analyzeSourceModel. |
| */ |
| private @Nullable Map<@NonNull TemplateVariable, @NonNull TemplateExp> variable2templateExp = null; |
| |
| /** |
| * The output variables that are assigned by a top when invocation. |
| * |
| * Populated by analyzeSourceModel. |
| */ |
| private @Nullable Set<@NonNull VariableDeclaration> topWhenedOutputVariables = null; |
| |
| /** |
| * The output variables that are assigned by a non-top when invocation. |
| * |
| * Populated by analyzeSourceModel. |
| */ |
| private @Nullable Set<@NonNull VariableDeclaration> nonTopWhenedOutputVariables = null; |
| |
| public RelationAnalysis(@NonNull AbstractTransformationAnalysis transformationAnalysis, @NonNull QVTuConfiguration qvtuConfiguration, @NonNull RuleRegion ruleRegion) { |
| super(transformationAnalysis, ruleRegion); |
| dispatch = createDispatch(qvtuConfiguration); |
| verdict = createVerdict(qvtuConfiguration); |
| } |
| |
| protected void addExpression(@NonNull VariableDeclaration variable, @NonNull OCLExpression expression) { |
| List<@NonNull OCLExpression> initializers = variable2expressions.get(variable); |
| if (initializers == null) { |
| initializers = new ArrayList<>(); |
| variable2expressions.put(variable, initializers); |
| } |
| if (!initializers.contains(expression)) { // Shouldn't really happen but variable.ownedIInit is lazy |
| initializers.add(expression); |
| } |
| } |
| |
| private void addIncomingInvocationAnalysis(@NonNull InvocationAnalysis invocationAnalysis) { |
| boolean isWhen = invocationAnalysis.isWhen(); |
| if (isWhen) { |
| List<@NonNull InvocationAnalysis> incomingWhenInvocationAnalyses2 = incomingWhenInvocationAnalyses; |
| if (incomingWhenInvocationAnalyses2 == null) { |
| incomingWhenInvocationAnalyses = incomingWhenInvocationAnalyses2 = new ArrayList<>(); |
| } |
| incomingWhenInvocationAnalyses2.add(invocationAnalysis); |
| } |
| else { |
| List<@NonNull InvocationAnalysis> incomingWhereInvocationAnalyses2 = incomingWhereInvocationAnalyses; |
| if (incomingWhereInvocationAnalyses2 == null) { |
| incomingWhereInvocationAnalyses = incomingWhereInvocationAnalyses2 = new ArrayList<>(); |
| } |
| incomingWhereInvocationAnalyses2.add(invocationAnalysis); |
| } |
| } |
| |
| private void addOutgoingInvocationAnalysis(@NonNull InvocationAnalysis invocationAnalysis) { |
| boolean isWhen = invocationAnalysis.isWhen(); |
| if (isWhen) { |
| List<@NonNull InvocationAnalysis> outgoingWhenInvocationAnalyses2 = outgoingWhenInvocationAnalyses; |
| if (outgoingWhenInvocationAnalyses2 == null) { |
| outgoingWhenInvocationAnalyses = outgoingWhenInvocationAnalyses2 = new ArrayList<>(); |
| } |
| outgoingWhenInvocationAnalyses2.add(invocationAnalysis); |
| } |
| else { |
| List<@NonNull InvocationAnalysis> outgoingWhereInvocationAnalyses2 = outgoingWhereInvocationAnalyses; |
| if (outgoingWhereInvocationAnalyses2 == null) { |
| outgoingWhereInvocationAnalyses = outgoingWhereInvocationAnalyses2 = new ArrayList<>(); |
| } |
| outgoingWhereInvocationAnalyses2.add(invocationAnalysis); |
| } |
| } |
| |
| protected void analyzeContainments() { |
| for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) { |
| if (node.isNew()) { |
| boolean isContained = false; |
| for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(node)) { |
| if (edge.isNavigation()) { |
| NavigationEdge navigationEdge = (NavigationEdge)edge; |
| Property property = QVTscheduleUtil.getReferredProperty(navigationEdge); |
| Property opposite = property.getOpposite(); |
| if ((opposite != null) && opposite.isIsComposite() && !navigationEdge.getEdgeTarget().isNullLiteral()) { |
| isContained = true; |
| break; |
| } |
| } |
| else { |
| // SharedEdge |
| } |
| } |
| if (isContained) { |
| node.setContained(true); |
| } |
| } |
| } |
| } |
| |
| protected void analyzeInvocations() { |
| for (@NonNull EObject eObject : new TreeIterable(rule, false)) { |
| if (eObject instanceof RelationCallExp) { |
| RelationCallExp relationInvocation = (RelationCallExp) eObject; |
| RelationAnalysis invokedRelationAnalysis = (RelationAnalysis) transformationAnalysis.getRuleAnalysis(QVTrelationUtil.getReferredRelation(relationInvocation)); |
| // String name= invokedRelationAnalysis.getName(); |
| Pattern pattern = QVTrelationUtil.basicGetContainingPattern(eObject); |
| if ((pattern != null) && (pattern.eContainmentFeature() == QVTrelationPackage.Literals.RELATION__WHERE)) { |
| invokedRelationAnalysis.addIncomingWhereRelation(relationInvocation); |
| } |
| else { |
| invokedRelationAnalysis.addIncomingWhenRelation(relationInvocation); |
| } |
| } |
| } |
| } |
| |
| protected void analyzeKeyedOutputVariables(@NonNull RelationDomain relationDomain, @NonNull Set<@NonNull VariableDeclaration> keyedOutputVariables) { |
| RelationalTransformationAnalysis transformationAnalysis2 = getTransformationAnalysis(); |
| Set<@NonNull VariableDeclaration> whenedOutputVariables = getTopWhenedOutputVariables(); |
| for (@NonNull DomainPattern domainPattern : QVTrelationUtil.getOwnedPatterns(relationDomain)) { |
| TemplateExp templateExpression = QVTrelationUtil.getOwnedTemplateExpression(domainPattern); |
| for (@NonNull EObject eObject : new TreeIterable(templateExpression, true)) { |
| if (eObject instanceof TemplateExp) { |
| TemplateExp templateExp = (TemplateExp)eObject; |
| TemplateVariable templateVariable = (TemplateVariable) QVTrelationUtil.getBindsTo(templateExp); |
| if (!whenedOutputVariables.contains(templateVariable)) { |
| Key key = transformationAnalysis2.getKeyForType(QVTrelationUtil.getType(templateVariable)); |
| if (key != null) { |
| keyedOutputVariables.add(templateVariable); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private void addIncomingWhenRelation(@NonNull RelationCallExp relationInvocation) { |
| List<@NonNull RelationCallExp> incomingWhenInvocations2 = incomingWhenInvocations; |
| if (incomingWhenInvocations2 == null) { |
| incomingWhenInvocations = incomingWhenInvocations2 = new ArrayList<>(); |
| } |
| incomingWhenInvocations2.add(relationInvocation); |
| } |
| |
| private void addIncomingWhereRelation(@NonNull RelationCallExp relationInvocation) { |
| List<@NonNull RelationCallExp> incomingWhereInvocations2 = incomingWhereInvocations; |
| if (incomingWhereInvocations2 == null) { |
| incomingWhereInvocations = incomingWhereInvocations2 = new ArrayList<>(); |
| } |
| incomingWhereInvocations2.add(relationInvocation); |
| } |
| |
| /* private void addOutgoingRelation(@NonNull RelationCallExp relationInvocation) { |
| List<@NonNull RelationCallExp> outgoingInvocations2 = outgoingInvocations; |
| if (outgoingInvocations2 == null) { |
| outgoingInvocations = outgoingInvocations2 = new ArrayList<>(); |
| } |
| outgoingInvocations2.add(relationInvocation); |
| } */ |
| |
| /* private void addOutgoingWhenRelation(@NonNull RelationCallExp relationInvocation) { |
| List<@NonNull RelationCallExp> outgoingWhenInvocations2 = outgoingWhenInvocations; |
| if (outgoingWhenInvocations2 == null) { |
| outgoingWhenInvocations = outgoingWhenInvocations2 = new ArrayList<>(); |
| } |
| outgoingWhenInvocations2.add(relationInvocation); |
| } */ |
| |
| /* private void addOutgoingWhereRelation(@NonNull RelationCallExp relationInvocation) { |
| List<@NonNull RelationCallExp> outgoingWhereInvocations2 = outgoingWhereInvocations; |
| if (outgoingWhereInvocations2 == null) { |
| outgoingWhereInvocations = outgoingWhereInvocations2 = new ArrayList<>(); |
| } |
| outgoingWhereInvocations2.add(relationInvocation); |
| } */ |
| |
| @Override |
| public void analyzeMappingRegion() { |
| rewriteCastEdges(); |
| // |
| // Create the BLUE/CYAN guard nodes. |
| // |
| // analyzeGuardVariables(); |
| // |
| // Create the GREEN realized nodes. |
| // |
| // analyzeRealizedVariables(); // FIXME bottom variables too |
| // |
| // Create the predicate/computation nodes and edges |
| // |
| // analyzePredicates(guardPatterns); |
| // analyzePredicates(bottomPatterns); |
| // analyzeAssignmentValues(); |
| // analyzeComplexPredicates(); |
| // analyzeContainments(); |
| // |
| List<@NonNull Node> preferredHeadNodes = Lists.newArrayList(QVTscheduleUtil.getHeadNodes(region)); // FIXME Use domain roots as preferred heads |
| if (preferredHeadNodes.isEmpty()) { |
| for (@NonNull Variable rootVariable : QVTrelationUtil.getRootVariables(getRule())) { |
| Node rootNode = region.getNode(rootVariable); |
| if (rootNode != null) { |
| preferredHeadNodes.add(rootNode); |
| } |
| }; |
| } |
| Iterable<@NonNull Node> headNodes; |
| if (getBaseRelationAnalysis() != this) { |
| headNodes = preferredHeadNodes; |
| } |
| else { |
| headNodes = RuleHeadAnalysis.computeRuleHeadNodes(scheduleManager, region, preferredHeadNodes); |
| } |
| List<@NonNull Node> headNodesList = QVTscheduleUtil.Internal.getHeadNodesList(region); |
| headNodesList.clear(); |
| Iterables.addAll(headNodesList, headNodes); |
| UtilityAnalysis.assignUtilities(scheduleManager, region); |
| } |
| |
| protected void analyzeRealizedOutputVariables(@NonNull RelationDomain relationDomain, @NonNull Set<@NonNull VariableDeclaration> realizedOutputVariables) { |
| for (@NonNull DomainPattern domainPattern : QVTrelationUtil.getOwnedPatterns(relationDomain)) { |
| TemplateExp templateExpression = QVTrelationUtil.getOwnedTemplateExpression(domainPattern); |
| for (@NonNull EObject eObject : new TreeIterable(templateExpression, true)) { |
| if (eObject instanceof TemplateExp) { |
| TemplateExp templateExp = (TemplateExp)eObject; |
| TemplateVariable templateVariable = (TemplateVariable) QVTrelationUtil.getBindsTo(templateExp); |
| realizedOutputVariables.add(templateVariable); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void analyzeSourceModel() { |
| Relation relation = getRule(); |
| baseRelationAnalysis = getScheduleManager().getRuleAnalysis(QVTrelationUtil.getBaseRelation(relation)); |
| variable2templateExp = analyzeVariable2TemplateExp(); |
| analyzeInvocations(); |
| Set<@NonNull VariableDeclaration> topWhenedOutputVariables2 = topWhenedOutputVariables = new HashSet<>(); |
| Set<@NonNull VariableDeclaration> nonTopWhenedOutputVariables2 = nonTopWhenedOutputVariables = new HashSet<>(); |
| analyzeWhenedOutputVariables(topWhenedOutputVariables2, nonTopWhenedOutputVariables2); |
| Set<@NonNull VariableDeclaration> keyedOutputVariables = this.keyedOutputVariables = new HashSet<>(); |
| Set<@NonNull VariableDeclaration> realizedOutputVariables = this.realizedOutputVariables = new HashSet<>(); |
| for (@NonNull RelationDomain relationDomain : QVTrelationUtil.getOwnedDomains(relation)) { |
| DomainUsage domainUsage = scheduleManager.getDomainUsage(relationDomain); |
| if (domainUsage.isOutput()) { |
| // assert keyedOutputVariables == null; -- The assumption of a single output domain does not seem to be justified |
| analyzeKeyedOutputVariables(relationDomain, keyedOutputVariables); |
| // assert realizedOutputVariables == null; -- The assumption of a single output domain does not seem to be justified |
| analyzeRealizedOutputVariables(relationDomain, realizedOutputVariables); |
| } |
| } |
| } |
| |
| /** |
| * Return the boundExpression if conditionExpression is of the form |
| * <br>"variable = referenceExpression" => VariableExp(variable) |
| * <br>"referenceExpression = variable" => VariableExp(variable) |
| * <br>"null = referenceExpression" => NullLiteralExp(null) |
| * <br>"referenceExpression = null" => NullLiteralExp(null) |
| * <br>"constant-expression = referenceExpression" => OCLExpression(constant) |
| * <br>"referenceExpression = constant-expression" => OCLExpression(constant) |
| * |
| * <br>Returns null otherwise. |
| * |
| private @Nullable OCLExpression getPredicateComparisonBoundExpression(@NonNull OCLExpression conditionExpression) { |
| if (conditionExpression instanceof OperationCallExp) { |
| OperationCallExp callExp = (OperationCallExp)conditionExpression; |
| OperationId operationId = callExp.getReferredOperation().getOperationId(); |
| if (PivotUtil.isSameOperation(operationId, scheduleManager.getStandardLibraryHelper().getOclAnyEqualsId())) { |
| OCLExpression leftExp = callExp.getOwnedSource(); |
| if (leftExp instanceof VariableExp) { |
| return leftExp; |
| } |
| OCLExpression rightExp = callExp.getOwnedArguments().get(0); |
| if (rightExp instanceof VariableExp) { |
| return rightExp; |
| } |
| IsConstantExpressionVisitor isConstantExpressionVisitor = new IsConstantExpressionVisitor(null); |
| if (isConstantExpressionVisitor.isConstant(leftExp)) { |
| return leftExp; |
| } |
| if (isConstantExpressionVisitor.isConstant(rightExp)) { |
| return rightExp; |
| } |
| } |
| } |
| return null; |
| } */ |
| |
| protected @NonNull Map<@NonNull TemplateVariable, @NonNull TemplateExp> analyzeVariable2TemplateExp() { |
| Relation relation = getRule(); |
| Map<@NonNull TemplateVariable, @NonNull TemplateExp> variable2templateExp = new HashMap<>(); |
| for (@NonNull RelationDomain relationDomain : QVTrelationUtil.getOwnedDomains(relation)) { |
| for (@NonNull DomainPattern domainPattern : QVTrelationUtil.getOwnedPatterns(relationDomain)) { |
| for (@NonNull EObject eObject : new TreeIterable(domainPattern, true)) { |
| if (eObject instanceof TemplateExp) { |
| TemplateExp templateExp = (TemplateExp)eObject; |
| TemplateVariable templateVariable = (TemplateVariable) QVTrelationUtil.getBindsTo(templateExp); |
| TemplateExp oldTemplateExp = variable2templateExp.put(templateVariable, templateExp); |
| assert oldTemplateExp == null; |
| } |
| } |
| } |
| } |
| return variable2templateExp; |
| } |
| |
| protected void analyzeWhenedOutputVariables(@NonNull Set<@NonNull VariableDeclaration> topWhenedOutputVariables, @NonNull Set<@NonNull VariableDeclaration> nonTopWhenedOutputVariables) { |
| Relation relation = getRule(); |
| Pattern whenPattern = relation.getWhen(); |
| if (whenPattern != null) { |
| for (@NonNull Predicate whenPredicate : QVTrelationUtil.getOwnedPredicates(whenPattern)) { |
| for (@NonNull EObject eObject : new TreeIterable(QVTrelationUtil.getOwnedConditionExpression(whenPredicate), true)) { |
| if (eObject instanceof VariableExp) { |
| VariableExp variableExp = (VariableExp)eObject; |
| EObject eContainer = variableExp.eContainer(); |
| if (eContainer instanceof RelationCallExp) { |
| RelationCallExp invocation = (RelationCallExp)eContainer; |
| int argumentIndex = invocation.getArgument().indexOf(variableExp); |
| assert argumentIndex >= 0; |
| RelationDomain domain = QVTrelationUtil.getRelationCallExpArgumentDomain(invocation, argumentIndex); |
| DomainUsage domainUsage = scheduleManager.getDomainUsage(domain); |
| if (domainUsage.isOutput()) { |
| if (invocation.getReferredRelation().isIsTopLevel()) { |
| topWhenedOutputVariables.add(QVTrelationUtil.getReferredVariable(variableExp)); |
| } |
| else { |
| nonTopWhenedOutputVariables.add(QVTrelationUtil.getReferredVariable(variableExp)); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| public @Nullable Iterable<@NonNull InvocationAnalysis> basicGetIncomingWhenInvocationAnalyses() { |
| return incomingWhenInvocationAnalyses; |
| } |
| |
| public @Nullable Iterable<@NonNull InvocationAnalysis> basicGetIncomingWhereInvocationAnalyses() { |
| return incomingWhereInvocationAnalyses; |
| } |
| |
| public @Nullable Iterable<@NonNull InvocationAnalysis> basicGetOutgoingWhenInvocationAnalyses() { |
| return outgoingWhenInvocationAnalyses; |
| } |
| |
| public @Nullable Iterable<@NonNull InvocationAnalysis> basicGetOutgoingWhereInvocationAnalyses() { |
| return outgoingWhereInvocationAnalyses; |
| } |
| |
| protected @Nullable TemplateExp basicGetTemplateExp(@NonNull VariableDeclaration variable) { |
| return ClassUtil.nonNullState(variable2templateExp).get(variable); |
| } |
| |
| protected @Nullable Dispatch createDispatch(@NonNull QVTuConfiguration qvtuConfiguration) { |
| Relation relation = getRule(); |
| if (!QVTrelationUtil.hasOverrides(relation)) { |
| return null; |
| } |
| if (QVTrelationUtil.getBaseRelation(relation) != relation) { |
| return null; |
| } |
| DispatchRegion dispatchRegion = QVTscheduleFactory.eINSTANCE.createDispatchRegion(); |
| dispatchRegion.setOwningScheduleModel(scheduleManager.getScheduleModel()); |
| dispatchRegion.setReferredRule(relation); |
| dispatchRegion.setReferredRuleRegion(getRegion()); |
| dispatchRegion.setName(getNameGenerator().createMappingName(relation, "dispatch", qvtuConfiguration)); |
| return new Dispatch(dispatchRegion); |
| } |
| |
| public @NonNull InvocationAnalysis createInvocationAnalysis(@NonNull RelationAnalysis invokedRelationAnalysis, @NonNull RelationCallExp relationCallExp, boolean isWhen) { |
| RelationAnalysis invokedBaseRelationAnalysis = invokedRelationAnalysis.getBaseRelationAnalysis(); |
| InvocationAnalysis invocationAnalysis; |
| if (invokedBaseRelationAnalysis.getRule().isIsTopLevel()) { |
| if (isWhen) { |
| invocationAnalysis = new TopWhenInvocationAnalysis(this, invokedRelationAnalysis); |
| } |
| else { |
| invocationAnalysis = new TopWhereInvocationAnalysis(this, invokedRelationAnalysis); |
| } |
| } |
| else { |
| boolean hasWhenInvocations = (invokedRelationAnalysis.incomingWhenInvocations != null) && !invokedRelationAnalysis.incomingWhenInvocations.isEmpty(); |
| boolean hasWhereInvocations = (invokedRelationAnalysis.incomingWhereInvocations != null) && !invokedRelationAnalysis.incomingWhereInvocations.isEmpty(); |
| boolean hasWhenAndWhereInvocations = hasWhenInvocations && hasWhereInvocations; |
| if (isWhen) { |
| if (hasWhenAndWhereInvocations) { |
| invocationAnalysis = new NonTopWhenAfterWhereInvocationAnalysis(this, invokedRelationAnalysis); |
| } |
| else { |
| boolean hasClassInput = false; |
| Relation rule2 = invokedRelationAnalysis.getRule(); |
| for (@NonNull RelationDomain relationDomain : QVTrelationUtil.getOwnedDomains(rule2)) { |
| if (scheduleManager.isInput(relationDomain)) { |
| for (@NonNull VariableDeclaration rootVariable : QVTrelationUtil.getRootVariables(relationDomain)) { |
| Type type = QVTrelationUtil.getType(rootVariable); |
| if (!(type instanceof DataType)) { |
| hasClassInput = true; |
| } |
| } |
| } |
| } |
| if (hasClassInput) { |
| invocationAnalysis = new NonTopWhenOnlyClassInvocationAnalysis(this, invokedRelationAnalysis); |
| } |
| else { |
| invocationAnalysis = new NonTopWhenOnlyDataTypeInvocationAnalysis(this, invokedRelationAnalysis); |
| } |
| } |
| } |
| else { |
| if (hasWhenAndWhereInvocations) { |
| invocationAnalysis = new NonTopWhereBeforeWhenInvocationAnalysis(this, invokedRelationAnalysis); |
| } |
| else { |
| invocationAnalysis = new NonTopWhereOnlyInvocationAnalysis(this, invokedRelationAnalysis); |
| } |
| } |
| } |
| addOutgoingInvocationAnalysis(invocationAnalysis); |
| invokedRelationAnalysis.addIncomingInvocationAnalysis(invocationAnalysis); |
| invokedBaseRelationAnalysis.addIncomingInvocationAnalysis(invocationAnalysis); |
| return invocationAnalysis; |
| } |
| |
| /** |
| * Return the referenceExpression if conditionExpression is of the form "boundVariable = referenceExpression" or |
| * "referenceExpression = boundVariable". Returns null otherwise. |
| * |
| private @Nullable OCLExpression getPredicateComparisonReferenceExpression(@NonNull OCLExpression conditionExpression) { |
| if (conditionExpression instanceof OperationCallExp) { |
| OperationCallExp callExp = (OperationCallExp)conditionExpression; |
| OperationId operationId = callExp.getReferredOperation().getOperationId(); |
| if (PivotUtil.isSameOperation(operationId, scheduleManager.getStandardLibraryHelper().getOclAnyEqualsId())) { |
| OCLExpression leftExp = callExp.getOwnedSource(); |
| OCLExpression rightExp = callExp.getOwnedArguments().get(0); |
| if (leftExp instanceof VariableExp) { |
| return rightExp; |
| } |
| else if (rightExp instanceof VariableExp) { |
| return leftExp; |
| } |
| IsConstantExpressionVisitor isConstantExpressionVisitor = new IsConstantExpressionVisitor(null); |
| if (isConstantExpressionVisitor.isConstant(leftExp)) { |
| return rightExp; |
| } |
| if (isConstantExpressionVisitor.isConstant(rightExp)) { |
| return leftExp; |
| } |
| } |
| } |
| return null; |
| } |
| * @param invokedRuleAnalysis */ |
| |
| protected @Nullable Verdict createVerdict(@NonNull QVTuConfiguration qvtuConfiguration) { |
| Relation relation = getRule(); |
| if (!QVTrelationUtil.hasOverrides(relation)) { |
| return null; |
| } |
| if (QVTrelationUtil.getBaseRelation(relation) != relation) { |
| return null; |
| } |
| VerdictRegion verdictRegion = QVTscheduleFactory.eINSTANCE.createVerdictRegion(); |
| verdictRegion.setOwningScheduleModel(scheduleManager.getScheduleModel()); |
| verdictRegion.setReferredRule(relation); |
| verdictRegion.setReferredRuleRegion(getRegion()); |
| verdictRegion.setName(getNameGenerator().createMappingName(relation, "verdict", qvtuConfiguration)); |
| return new Verdict(verdictRegion); |
| } |
| |
| @Override |
| public void gatherRuleRegions(@NonNull List<@NonNull RuleRegion> ruleRegions) { |
| // if (!getRule().isIsAbstract()) { |
| super.gatherRuleRegions(ruleRegions); |
| //} |
| if (dispatch != null) { |
| dispatch.gatherRuleRegions(ruleRegions); |
| } |
| if (verdict != null) { |
| verdict.gatherRuleRegions(ruleRegions); |
| } |
| } |
| |
| public @NonNull RelationAnalysis getBaseRelationAnalysis() { |
| return ClassUtil.nonNullState(baseRelationAnalysis); |
| } |
| |
| protected @NonNull Set<@NonNull VariableDeclaration> getKeyedOutputVariables() { |
| return ClassUtil.nonNullState(keyedOutputVariables); |
| } |
| |
| @Override |
| public @NonNull QVTrelationNameGenerator getNameGenerator() { |
| return (QVTrelationNameGenerator) super.getNameGenerator(); |
| } |
| |
| protected @NonNull Set<@NonNull VariableDeclaration> getRealizedOutputVariables() { |
| return ClassUtil.nonNullState(realizedOutputVariables); |
| } |
| |
| @Override |
| public @NonNull Node getReferenceNode(@NonNull VariableDeclaration variableDeclaration) { |
| Node node = region.getNode(variableDeclaration); |
| if (node == null) { |
| if (variableDeclaration instanceof SharedVariable) { |
| node = getReferenceNodeForSharedVariable((SharedVariable)variableDeclaration, null); |
| } |
| if (node == null) { |
| node = createOldNode(variableDeclaration); |
| } |
| } |
| assert node != null : "No variable2simpleNode entry for " + variableDeclaration; |
| assert node == region.getNode(variableDeclaration); |
| return node; |
| } |
| private @Nullable Node getReferenceNodeForSharedVariable(@NonNull SharedVariable variable, @Nullable OCLExpression predicatedInit /*, @NonNull List<@NonNull OCLExpression> expressions*/) { |
| // |
| // Use something hard to compute as the initializer that creates an initNode in the hope that other |
| // initializers might be easier and optimized as simple navigation edges. |
| // |
| OCLExpression bestInitExpression = variable.getOwnedInit(); |
| /* for (@NonNull OCLExpression initExpression : expressions) { |
| if (initExpression instanceof OperationCallExp ) { |
| OperationCallExp operationCallExp = (OperationCallExp)initExpression; |
| OperationId operationId = operationCallExp.getReferredOperation().getOperationId(); |
| if (!PivotUtil.isSameOperation(operationId, OperationId.OCLANY_EQUALS) && !PivotUtil.isSameOperation(operationId, OperationId.OCLANY_NOT_EQUALS)) { |
| bestInitExpression = initExpression; |
| break; |
| } |
| } |
| } |
| if (bestInitExpression == null) { |
| bestInitExpression = (expressions.size() > 0) ? expressions.get(0) : null; |
| } */ |
| if (bestInitExpression == null) { |
| if (predicatedInit != null) { |
| bestInitExpression = predicatedInit; |
| } |
| else { |
| return null; |
| } |
| } |
| ExpressionSynthesizer expressionSynthesizer2 = expressionSynthesizer; |
| if (variable.isIsRequired()) { |
| expressionSynthesizer2 = expressionSynthesizer.getRequiredExpressionSynthesizer(); |
| } |
| Node bestInitNode = bestInitExpression.accept(expressionSynthesizer2); |
| assert bestInitNode != null; |
| if (variable.isIsRequired()) { |
| assert bestInitNode.isRequired(); |
| // assert bestInitNode.isMatched(); --not satisfied by a cast to-non-null ATL2QVTr local variable |
| } |
| /* if ((ownedInit instanceof OperationCallExp) && initNode.isOperation()) { |
| if (QVTbaseUtil.isIdentification(((OperationCallExp)ownedInit).getReferredOperation())) { |
| Node stepNode = QVTscheduleUtil.createRealizedStepNode(mappingRegion, variable); |
| QVTscheduleUtil.createEqualsEdge(initNode, stepNode); |
| initNode = stepNode; |
| } |
| // else if (variable.getType() instanceof CollectionType) { |
| // Node stepNode = QVTscheduleUtil.ATTRIBUTE.createNode(this, variable, (OperationCallExp)ownedInit); |
| // QVTscheduleUtil.RESULT.createEdge(this, initNode, null, stepNode); |
| // initNode = stepNode; |
| // } |
| else { |
| // Node stepNode = QVTscheduleUtil.STEP.createNode(this, variable.getName(), (OperationCallExp)ownedInit, initNode); |
| Node stepNode = QVTscheduleUtil.createLoadedStepNode(mappingRegion, variable); |
| QVTscheduleUtil.createEqualsEdge(initNode, stepNode); |
| initNode = stepNode; |
| } |
| } */ |
| ClassDatum initClassDatum = QVTscheduleUtil.getClassDatum(bestInitNode); |
| ClassDatum variableClassDatum = scheduleManager.getClassDatum(variable); |
| if (!QVTscheduleUtil.conformsTo(initClassDatum, variableClassDatum)) { |
| Node castNode = createOldNode(variable); |
| expressionSynthesizer2.createCastEdge(bestInitNode, variableClassDatum, castNode); |
| bestInitNode = castNode; |
| } |
| bestInitNode.setOriginatingVariable(variable); |
| region.addVariableNode(variable, bestInitNode); |
| /* for (@NonNull OCLExpression initExpression : expressions) { |
| if (initExpression != bestInitExpression) { |
| // FIXME if the extra init is a navigation we can add a navigation to the bestInitNode |
| Node initNode = bestInitExpression.accept(expressionAnalyzer); |
| assert initNode != null; |
| createEqualsEdge(bestInitNode, initNode); |
| } |
| } */ |
| return bestInitNode; |
| } |
| |
| @Override |
| public @NonNull Relation getRule() { |
| return (Relation) super.getRule(); |
| } |
| |
| @Override |
| public @NonNull RelationAnalysis2TraceGroup getRuleAnalysis2TraceGroup() { |
| return (RelationAnalysis2TraceGroup) super.getRuleAnalysis2TraceGroup(); |
| } |
| |
| @Override |
| public @NonNull QVTrelationScheduleManager getScheduleManager() { |
| return (QVTrelationScheduleManager)scheduleManager; |
| } |
| |
| // protected @NonNull TemplateExp getTemplateExp(@NonNull VariableDeclaration variable) { |
| // return ClassUtil.nonNullState(basicGetTemplateExp(variable)); |
| // } |
| |
| public @NonNull TypedModel getTraceTypedModel() { |
| return scheduleManager.getTraceTypedModel(); |
| } |
| |
| @Override |
| public @NonNull RelationalTransformationAnalysis getTransformationAnalysis() { |
| return (RelationalTransformationAnalysis) transformationAnalysis; |
| } |
| |
| @Override |
| public @NonNull RelationalTransformationAnalysis2TracePackage getTransformationAnalysis2TracePackage() { |
| return (RelationalTransformationAnalysis2TracePackage) super.getTransformationAnalysis2TracePackage(); |
| } |
| |
| // @Override |
| // public @NonNull String getUniqueVariableName(@NonNull Element2MiddleProperty element2traceProperty, @NonNull String name) { |
| // return QVTrelationNameGenerator.getUniqueName(name2element2traceProperty, name, element2traceProperty); |
| // } |
| |
| /* @Override |
| public void initializeHeadNodes() { |
| // Node traceNode2 = traceNode; |
| // assert traceNode2 != null; |
| // if (getRule().isIsTopLevel()) { |
| mappingRegionAnalysis.initHeadNodes(null); |
| // } |
| // else { |
| // region.getHeadNodes().add(traceNode); |
| // } |
| } */ |
| |
| protected @NonNull Set<@NonNull VariableDeclaration> getNonTopWhenedOutputVariables() { |
| return ClassUtil.nonNullState(nonTopWhenedOutputVariables); |
| } |
| |
| protected @NonNull Set<@NonNull VariableDeclaration> getTopWhenedOutputVariables() { |
| return ClassUtil.nonNullState(topWhenedOutputVariables); |
| } |
| |
| public boolean hasIncomingWhenInvocationAnalyses() { |
| return getBaseRelationAnalysis().basicGetIncomingWhenInvocationAnalyses() != null; |
| } |
| |
| public boolean hasIncomingWhereInvocationAnalyses() { |
| return getBaseRelationAnalysis().basicGetIncomingWhereInvocationAnalyses() != null; |
| } |
| |
| public boolean isKeyedRealization(@NonNull VariableDeclaration variableDeclaration) { |
| return getKeyedOutputVariables().contains(variableDeclaration); |
| } |
| |
| /** |
| * Return true if the navigation from sourceNode using source2targetProperty corresponds to a PropertyAssigmment, |
| */ |
| @Override |
| public boolean isPropertyAssignment(@NonNull Node sourceNode, @NonNull Property source2targetProperty) { |
| /* if (sourceNode.isRealized()) { |
| for (@NonNull NavigationAssignment navigationAssignment : navigationAssignments) { |
| Property navigationProperty = QVTrelationUtil.getTargetProperty(navigationAssignment); |
| if (source2targetProperty == navigationProperty) { // ??? opposites ??? do they even exist ??? |
| Node slotNode = expressionAnalyzer.analyze(navigationAssignment.getSlotExpression()); |
| if (slotNode == sourceNode) { |
| return true; |
| } |
| } |
| } |
| } */ |
| return false; |
| } |
| |
| public boolean isSharedAggregator() { |
| return false; |
| } |
| |
| /* public OCLExpression synthesizeKeyTemplate(@NonNull VariableDeclaration templateVariable, @NonNull Node @NonNull [] argNodes) { |
| Node keyNode = createOperationNode(true, QVTrelationUtil.getName(templateVariable), templateVariable, argNodes); |
| region.addVariableNode(templateVariable, keyNode); |
| for (int i = 0; i <= argNodes.length; i++) { |
| argNames[i+1] = "«" + referredOperation.getOwnedParameters().get(i).getName() + "»"; |
| createExpressionEdge(argNodes[i], argNames[i], keyNode); |
| } |
| return null; |
| } */ |
| |
| /** |
| * Create the BLUE/CYAN computations for the RHS of assignments. |
| * |
| protected void analyzeAssignmentValues() { |
| AssignmentSorter assignmentSorter = new AssignmentSorter(); |
| for (@NonNull BottomPattern bottomPattern : bottomPatterns) { |
| assignmentSorter.addAll(ClassUtil.nullFree(bottomPattern.getAssignment())); |
| } |
| for (@NonNull Assignment assignment : assignmentSorter.getSortedAssignments()) { |
| assignment.accept(expressionAnalyzer); |
| } |
| } */ |
| |
| /* protected void synthesizeComplexPredicates() { |
| /** |
| * Identify any assignments and hidden inputs. |
| * / |
| for (Predicate predicate : complexPredicates) { |
| OCLExpression conditionExpression = predicate.getConditionExpression(); |
| /* if (conditionExpression instanceof OperationCallExp) { |
| OperationCallExp callExp = (OperationCallExp)conditionExpression; |
| OperationId operationId = callExp.getReferredOperation().getOperationId(); |
| if (ScheduleModel.isSameOperation(operationId, getScheduleModel().getOclAnyEqualsId())) { |
| OCLExpression leftExpression = callExp.getOwnedSource(); |
| OCLExpression rightExpression = callExp.getOwnedArguments().get(0); |
| Node leftNode = expressionAnalyzer.analyze(leftExpression); |
| Node rightNode = expressionAnalyzer.analyze(rightExpression); |
| if (leftNode != rightNode) { |
| if (leftNode.isKnown() && !(leftExpression instanceof NavigationCallExp)) { |
| QVTscheduleUtil.ARGUMENT.createEdge(this, leftNode, "=", rightNode); |
| } |
| else if (rightNode.isKnown() && !(rightExpression instanceof NavigationCallExp)) { |
| QVTscheduleUtil.ARGUMENT.createEdge(this, rightNode, "=", leftNode); |
| } |
| else if (leftNode.isKnown()) { |
| QVTscheduleUtil.ARGUMENT.createEdge(this, leftNode, "=", rightNode); |
| } |
| else if (rightNode.isKnown()) { |
| QVTscheduleUtil.ARGUMENT.createEdge(this, rightNode, "=", leftNode); |
| } |
| else { |
| QVTscheduleUtil.BINDING.createEdge(this, leftNode, null, rightNode); // FIXME |
| QVTscheduleUtil.BINDING.createEdge(this, rightNode, null, leftNode); |
| } |
| } |
| } |
| } |
| else { * / |
| Node resultNode = conditionExpression.accept(expressionAnalyzer); |
| if ((resultNode != null) && !resultNode.isTrue()) { |
| Node trueNode = createTrueNode(); |
| createPredicateEdge(resultNode, null, trueNode); |
| } |
| // FIXME ?? do includes() here explicitly |
| } |
| } */ |
| |
| /** |
| * Create a BLUE/CYAN node for each guard variable. |
| * |
| protected void analyzeGuardVariables() { |
| for (@NonNull GuardPattern guardPattern : guardPatterns) { |
| for (@NonNull Variable guardVariable : ClassUtil.nullFree(guardPattern.getVariable())) { |
| Node guardNode = ruleRegion.getNode(guardVariable); |
| assert guardNode == null; |
| guardNode = createOldNode(guardVariable); |
| assert guardNode == ruleRegion.getNode(guardVariable); |
| } |
| } |
| } */ |
| |
| public void synthesizeCollectionTemplate(@NonNull CollectionTemplateExp collectionTemplateExp) { |
| boolean isOutput = scheduleManager.getDomainUsage(collectionTemplateExp).isOutput(); |
| if (isOutput) { |
| synthesizeOutputCollectionTemplate(collectionTemplateExp); |
| } |
| else if (!synthesizeEmptyInputCollectionTemplate(collectionTemplateExp)) { |
| if (!synthesizeSingleInputCollectionTemplate(collectionTemplateExp)) { |
| synthesizeMultipleInputCollectionTemplate(collectionTemplateExp); |
| } |
| } |
| } |
| |
| public void synthesizeDefaultValue(@NonNull RelationDomainAssignment relationDomainAssignment) { |
| Variable variable = QVTrelationUtil.getVariable(relationDomainAssignment); |
| OCLExpression valueExp = QVTrelationUtil.getValueExp(relationDomainAssignment); |
| Node variableNode = region.getNode(variable); |
| if (variableNode != null) { |
| scheduleManager.addRegionWarning(region, "Conflicting default assignment " + relationDomainAssignment); |
| } |
| else if (!(variable instanceof SharedVariable)) { |
| scheduleManager.addRegionError(region, "Non-SharedVariable for " + relationDomainAssignment); |
| } |
| else if (variable.getOwnedInit() != null) { |
| scheduleManager.addRegionError(region, "Default assignment for initialized variable: " + relationDomainAssignment); |
| } |
| else { |
| variableNode = getReferenceNodeForSharedVariable((SharedVariable)variable, valueExp); |
| } |
| } |
| |
| /** |
| * Create the dispatch node |
| */ |
| protected @NonNull Node synthesizeDispatchNode(@NonNull Node traceNode) { |
| Relation relation = getRule(); |
| // assert dispatch != null; |
| // |
| // Connect a dispatch node using its do Property. |
| // |
| RelationAnalysis2DispatchClass relationAnalysis2dispatchClass = getBaseRelationAnalysis().getRuleAnalysis2TraceGroup().getRuleAnalysis2DispatchClass(); |
| ClassDatum classDatum = scheduleManager.getClassDatum(getTraceTypedModel(), relationAnalysis2dispatchClass.getMiddleClass()); |
| Node dispatchNode = createPredicatedNode(QVTrelationNameGenerator.DISPATCHCLASS_SELF_NAME, classDatum, true); |
| dispatchNode.setUtility(Utility.DISPATCH); |
| Property doProperty = relationAnalysis2dispatchClass.getDispatchClass2TraceProperty(relation).getTraceProperty(); |
| createNavigationEdge(dispatchNode, doProperty, traceNode, false); |
| // |
| // Set the trace node as the dispatch's result. |
| // |
| Property resultProperty = relationAnalysis2dispatchClass.getResultProperty(); |
| createRealizedNavigationEdge(dispatchNode, resultProperty, traceNode, false); |
| // |
| // Set the dispatch node success as true. |
| // |
| Property globalSuccessProperty = relationAnalysis2dispatchClass.getGlobalSuccessProperty(); |
| createRealizedSuccess(dispatchNode, globalSuccessProperty, true); |
| // |
| // dispatch node is the head. |
| // |
| Node headNode = traceNode.isPredicated() ? traceNode : dispatchNode; |
| region.getHeadNodes().clear(); |
| region.getHeadNodes().add(headNode); |
| headNode.setHead(); |
| return dispatchNode; |
| } |
| |
| /** |
| * Synthesize the simple CollectionTemplateExp pattern only match comprising no members and no rest. |
| * |
| * Returns false if a more complex match is needed. |
| */ |
| protected boolean synthesizeEmptyInputCollectionTemplate(@NonNull CollectionTemplateExp collectionTemplateExp) { |
| Variable rest = collectionTemplateExp.getRest(); |
| if (rest != null) { |
| return false; |
| } |
| List<OCLExpression> members = collectionTemplateExp.getMember(); |
| if (members.size() > 0) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Attempt to synthesize an x=y predicateExpression, returning true if successful. |
| */ |
| protected boolean synthesizeEqualsPredicate(@NonNull OCLExpression predicateExpression) { |
| if (!(predicateExpression instanceof OperationCallExp)) { |
| return false; |
| } |
| OperationCallExp operationCallExp = (OperationCallExp)predicateExpression; |
| Operation operation = QVTrelationUtil.getReferredOperation(operationCallExp); |
| OperationId oclAnyEqualsId = scheduleManager.getStandardLibraryHelper().getOclAnyEqualsId(); |
| if (!PivotUtil.isSameOperation(operation.getOperationId(), oclAnyEqualsId)) { |
| return false; |
| } |
| OCLExpression leftExpression = QVTrelationUtil.getOwnedSource(operationCallExp); |
| OCLExpression rightExpression = QVTrelationUtil.getOwnedArgument(operationCallExp, 0); |
| if (leftExpression instanceof VariableExp) { |
| VariableDeclaration leftVariable = QVTrelationUtil.getReferredVariable((VariableExp)leftExpression); |
| return synthesizeVariableEqualsPredicate(leftVariable, rightExpression); |
| } |
| if (rightExpression instanceof VariableExp) { |
| VariableDeclaration rightVariable = QVTrelationUtil.getReferredVariable((VariableExp)rightExpression); |
| return synthesizeVariableEqualsPredicate(rightVariable, leftExpression); |
| } |
| if (leftExpression instanceof NavigationCallExp) { |
| return synthesizeNavigationCallEqualsPredicate((NavigationCallExp)leftExpression, rightExpression); |
| } |
| if (rightExpression instanceof NavigationCallExp) { |
| return synthesizeNavigationCallEqualsPredicate((NavigationCallExp)rightExpression, leftExpression); |
| } |
| // FIXME What about OperationCallExp ?? see Bug 547263 |
| return false; |
| } |
| |
| /** |
| * Create the invocation interface for a non-top relation. |
| */ |
| protected void synthesizeIncomingNonTopInvocation(@NonNull Node traceNode) { |
| Relation relation = getRule(); |
| if (!relation.isIsTopLevel()) { |
| if (QVTrelationUtil.hasOverrides(relation)) { |
| Relation baseRelation = QVTrelationUtil.getBaseRelation(relation); |
| RelationAnalysis baseRelationAnalysis = getBaseRelationAnalysis(); |
| RelationAnalysis2TraceGroup baseRelationAnalysis2traceGroup = baseRelationAnalysis.getRuleAnalysis2TraceGroup(); |
| RelationAnalysis2MiddleType baseRelationAnalysis2invocationInterface = baseRelationAnalysis2traceGroup.getRuleAnalysis2InvocationInterface(); |
| org.eclipse.ocl.pivot.Class baseInvocationClass = baseRelationAnalysis2invocationInterface.getMiddleClass(); |
| ClassDatum classDatum = scheduleManager.getClassDatum(scheduleManager.getTraceTypedModel(), baseInvocationClass); |
| Node invocationNode = createPredicatedNode(QVTrelationNameGenerator.DISPATCHCLASS_SELF_NAME, classDatum, true); |
| invocationNode.setUtility(Utility.DISPATCH); |
| region.getHeadNodes().add(invocationNode); |
| invocationNode.setHead(); |
| Relation2ResultProperty relation2resultProperty = baseRelationAnalysis2invocationInterface.basicGetRelation2ResultProperty(); |
| if (relation2resultProperty != null) { |
| Property resultProperty = relation2resultProperty.getTraceProperty(); |
| createRealizedNavigationEdge(invocationNode, resultProperty, traceNode, false); |
| } |
| for (@NonNull VariableDeclaration rootVariable : QVTrelationUtil.getRootVariables(relation)) { |
| Node rootNode = region.getNode(rootVariable); |
| assert rootNode != null; |
| VariableDeclaration baseRootVariable = QVTrelationUtil.getOverriddenVariable(baseRelation, rootVariable); |
| Property traceProperty = baseRelationAnalysis2invocationInterface.getTraceProperty(baseRootVariable); |
| createNavigationEdge(invocationNode, traceProperty, rootNode, false); |
| } |
| } |
| else { |
| region.getHeadNodes().add(traceNode); |
| } |
| } |
| } |
| |
| protected void synthesizeInterfaceAssignments(@NonNull RelationAnalysis2TraceGroup relationAnalysis2traceGroup, @NonNull Node traceNode) { |
| // Relation relation = getRule(); |
| // RelationAnalysis overriddenRelationAnalysis = getBaseRelationAnalysis(); |
| // Relation overriddenRelation = overriddenRelationAnalysis.getRule(); |
| // RelationAnalysis2TraceGroup overriddenRelationAnalysis2TraceGroup = overriddenRelationAnalysis.getRuleAnalysis2TraceGroup(); |
| // RelationAnalysis2MiddleType overriddenRelationAnalysis2TraceInterface = overriddenRelationAnalysis2TraceGroup.basicGetRuleAnalysis2TraceInterface(); |
| /* assert (dispatch != null) == (overriddenRelationAnalysis2TraceInterface != null); |
| if (overriddenRelationAnalysis2TraceInterface != null) { |
| for (@NonNull VariableDeclaration rootVariable : QVTrelationUtil.getRootVariables(relation)) { |
| Node rootVariableNode = getReferenceNode(rootVariable); |
| VariableDeclaration overriddenRootVariable = QVTrelationUtil.getOverriddenVariable(overriddenRelation, rootVariable); |
| Property interfaceProperty = overriddenRelationAnalysis2TraceInterface.getTraceProperty(overriddenRootVariable); |
| createRealizedNavigationEdge(traceNode, interfaceProperty, rootVariableNode, null); |
| } |
| } */ |
| } |
| |
| public OCLExpression synthesizeKeyTemplate(@NonNull VariableDeclaration templateVariable, @NonNull Map<@NonNull Property, @NonNull Node> property2node) { |
| // List<@NonNull Property> properties = new ArrayList<>(property2node.keySet()); |
| // Collections.sort(properties, NameUtil.NAMEABLE_COMPARATOR); |
| // @NonNull Node[] argNodes = new @NonNull Node[properties.size()]; |
| // int argIndex = 0; |
| // for (@NonNull Property property : properties) { |
| // Node node = property2node.get(property); |
| // assert node != null; |
| // argNodes[argIndex++] = node; |
| // } |
| // boolean isUnconditional = true; |
| Node keyNode = region.getNode(templateVariable); //createKeyedNode(isUnconditional, QVTrelationUtil.getName(templateVariable), templateVariable, argNodes); |
| assert keyNode != null; |
| ClassDatum classDatum = ((KeyedValueNode)keyNode).getClassDatumValue(); |
| assert classDatum != null; |
| for (@NonNull Property property : property2node.keySet()) { |
| Node node = property2node.get(property); |
| assert node != null; |
| PropertyDatum propertyDatum = scheduleManager.getPropertyDatum(classDatum, property); |
| createKeyPartEdge(node, propertyDatum, keyNode); |
| } |
| return null; |
| } |
| |
| public @NonNull Node synthesizeKeyTemplatePart(@NonNull PropertyTemplateItem propertyTemplateItem) { |
| OCLExpression targetExpression = QVTrelationUtil.getOwnedValue(propertyTemplateItem); |
| Node partNode = targetExpression.accept(expressionSynthesizer); |
| assert partNode != null; |
| return partNode; |
| } |
| |
| protected void synthesizeMultipleInputCollectionTemplate(@NonNull CollectionTemplateExp collectionTemplateExp) { |
| Node residueNode = collectionTemplateExp.accept(expressionSynthesizer); |
| assert residueNode != null; |
| |
| /* EObject eContainer = collectionTemplateExp.eContainer(); |
| if (eContainer instanceof PropertyTemplateItem) { |
| |
| } |
| ObjectTemplateExp objectTemplateExp = QVTrelationUtil.getOwningObjectTemplateExp(propertyTemplateItem); |
| Node sourceNode = objectTemplateExp.accept(expressionSynthesizer); |
| assert sourceNode != null; |
| Node memberNode = members.get(0).accept(expressionSynthesizer); |
| assert memberNode != null; |
| createNavigationEdge(sourceNode, source2target, memberNode, true); */ |
| |
| |
| |
| Operation collectionExcludingOperation = scheduleManager.getStandardLibraryHelper().getCollectionExcludingOperation(); |
| Node memberNode = null; |
| // int i = 1; |
| for (@NonNull OCLExpression member : QVTrelationUtil.getOwnedMembers(collectionTemplateExp)) { |
| if (memberNode != null) { |
| Node selfNode = residueNode; |
| assert selfNode != null; |
| residueNode = createOperationCallNode(isUnconditional(member), null, collectionExcludingOperation, collectionTemplateExp, residueNode, memberNode); |
| createOperationSelfEdge(selfNode, QVTrelationUtil.getType(collectionExcludingOperation), residueNode); |
| createOperationParameterEdge(memberNode, QVTrelationUtil.getOwnedParameter(collectionExcludingOperation, 0), -1, residueNode); |
| } |
| memberNode = member.accept(expressionSynthesizer); |
| assert memberNode != null; |
| // memberNodes.add(memberNode); |
| // createPredicateEdge(collectionNode, "head-" + i++, memberNode); |
| createPredicateEdge(residueNode, INCLUDES_NAME, memberNode); |
| } |
| Variable rest = collectionTemplateExp.getRest(); |
| if ((rest != null) && !rest.isIsImplicit()) { |
| if (memberNode != null) { |
| Node selfNode = residueNode; |
| assert selfNode != null; |
| residueNode = createOperationCallNode(isUnconditional(rest), null, collectionExcludingOperation, collectionTemplateExp, residueNode, memberNode); |
| createOperationSelfEdge(selfNode, QVTrelationUtil.getType(collectionExcludingOperation), residueNode); |
| createOperationParameterEdge(memberNode, QVTrelationUtil.getOwnedParameter(collectionExcludingOperation, 0), -1, residueNode); |
| } |
| Node restNode = rest.accept(expressionSynthesizer); |
| assert restNode != null; |
| createEqualsEdge(residueNode, restNode); |
| } |
| if (rest == null) { |
| Operation collectionIsEmptyOperation = scheduleManager.getStandardLibraryHelper().getCollectionIsEmptyOperation(); |
| Node isEmptyNode = createOperationCallNode(isUnconditional(collectionTemplateExp), null, collectionIsEmptyOperation, collectionTemplateExp, residueNode); |
| createPredicatedStepNode(isEmptyNode, false); |
| } |
| } |
| |
| protected boolean synthesizeNavigationCallEqualsPredicate(@NonNull NavigationCallExp navExpression, @NonNull OCLExpression valueExpression) { |
| Node valueNode = valueExpression.accept(expressionSynthesizer); |
| assert valueNode != null; |
| OCLExpression sourceExpression = QVTbaseUtil.getOwnedSource(navExpression); |
| Node sourceNode = sourceExpression.accept(expressionSynthesizer); |
| assert sourceNode != null; |
| Property source2targetProperty = QVTbaseUtil.getReferredProperty(navExpression); |
| createNavigationEdge(sourceNode, source2targetProperty, valueNode, false); |
| return true; |
| } |
| |
| public @NonNull OCLExpression synthesizeObjectTemplatePart(@NonNull PropertyTemplateItem propertyTemplateItem) { |
| ObjectTemplateExp sourceObjectTemplateExp = QVTrelationUtil.getOwningObjectTemplateExp(propertyTemplateItem); |
| Variable sourceVariable = QVTrelationUtil.getBindsTo(sourceObjectTemplateExp); |
| Node sourceNode = region.getNode(sourceVariable); |
| assert sourceNode != null; |
| Property source2targetProperty = QVTrelationUtil.getReferredProperty(propertyTemplateItem); |
| OCLExpression targetExpression = QVTrelationUtil.getOwnedValue(propertyTemplateItem); |
| if (targetExpression instanceof CollectionTemplateExp) { |
| // The bound variables of CollectionTemplateExp do not need tracing and can generally be bypassed |
| Variable targetVariable = QVTrelationUtil.getBindsTo((CollectionTemplateExp) targetExpression); |
| Node targetNode = region.getNode(targetVariable); |
| if (targetNode != null) { |
| boolean isPartial = scheduleManager.computeIsPartial(targetNode, source2targetProperty); |
| if (scheduleManager.getDomainUsage(sourceVariable).isOutput() /*&& !propertyTemplateItem.isCheckOnly()*/) { |
| createRealizedNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial); |
| } |
| else { |
| createNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial); |
| } |
| } |
| } |
| else { |
| Node targetNode = expressionSynthesizer.synthesize(targetExpression); |
| boolean isPartial = scheduleManager.computeIsPartial(targetNode, source2targetProperty); |
| if (scheduleManager.getDomainUsage(sourceVariable).isOutput() /*&& !propertyTemplateItem.isCheckOnly()*/) { |
| createRealizedNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial); |
| } |
| else { |
| createNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial); |
| } |
| } |
| return targetExpression; |
| } |
| |
| /** |
| * Create the nodes for when invocations |
| */ |
| protected void synthesizeOutgoingWhenInvocations(@NonNull Node traceNode) { |
| List<@NonNull InvocationAnalysis> outgoingWhenInvocationAnalyses2 = outgoingWhenInvocationAnalyses; |
| if (outgoingWhenInvocationAnalyses2 != null) { |
| for (@NonNull InvocationAnalysis invocationAnalysis : outgoingWhenInvocationAnalyses2) { |
| invocationAnalysis.synthesizeInvocationNodes(traceNode); |
| } |
| } |
| } |
| |
| /** |
| * Create the nodes for where invocations |
| */ |
| protected void synthesizeOutgoingWhereInvocations(@NonNull Node traceNode) { |
| List<@NonNull InvocationAnalysis> outgoingWhereInvocationAnalyses2 = outgoingWhereInvocationAnalyses; |
| if (outgoingWhereInvocationAnalyses2 != null) { |
| for (@NonNull InvocationAnalysis invocationAnalysis : outgoingWhereInvocationAnalyses2) { |
| invocationAnalysis.synthesizeInvocationNodes(traceNode); |
| } |
| } |
| } |
| |
| protected void synthesizeOutputCollectionTemplate(@NonNull CollectionTemplateExp collectionTemplateExp) { |
| // FIXME multiples |
| EObject eContainer = collectionTemplateExp.eContainer(); |
| if (eContainer instanceof PropertyTemplateItem) { |
| PropertyTemplateItem propertyTemplateItem = (PropertyTemplateItem)eContainer; |
| Property source2target = QVTrelationUtil.getReferredProperty(propertyTemplateItem); |
| ObjectTemplateExp objectTemplateExp = QVTrelationUtil.getOwningObjectTemplateExp(propertyTemplateItem); |
| Node sourceNode = objectTemplateExp.accept(expressionSynthesizer); |
| assert sourceNode != null; |
| for (@NonNull OCLExpression member : QVTrelationUtil.getOwnedMembers(collectionTemplateExp)) { |
| Node memberNode = member.accept(expressionSynthesizer); |
| assert memberNode != null; |
| createRealizedNavigationEdge(sourceNode, source2target, memberNode, true); |
| } |
| } |
| else { |
| // FIXME can this ever happen ? |
| Node collectionNode = collectionTemplateExp.accept(expressionSynthesizer); |
| assert collectionNode != null; |
| for (@NonNull OCLExpression member : QVTrelationUtil.getOwnedMembers(collectionTemplateExp)) { |
| Node memberNode = member.accept(expressionSynthesizer); |
| assert memberNode != null; |
| // memberNodes.add(memberNode); |
| // createPredicateEdge(collectionNode, "head-" + i++, memberNode); |
| createRealizedIncludesEdge(collectionNode, memberNode); |
| } |
| } |
| } |
| |
| /** |
| * Create the guards for overriding relations. |
| */ |
| protected void synthesizeOverridingGuards(@Nullable Node dispatchNode, @NonNull Node traceNode) { |
| Relation relation = getRule(); |
| QVTrelationScheduleManager scheduleManager2 = getScheduleManager(); |
| TypedModel traceTypedModel = scheduleManager2.getTraceTypedModel(); |
| Iterable<@NonNull Relation> overridingRelations = QVTrelationUtil.getOverrides(relation); |
| if (!Iterables.isEmpty(overridingRelations)) { |
| for (@NonNull Relation overridingRelation : overridingRelations) { |
| RelationAnalysis overridingRelationAnalysis = scheduleManager2.getRuleAnalysis(overridingRelation); |
| RelationAnalysis overriddenRelationAnalysis = overridingRelationAnalysis.getBaseRelationAnalysis(); |
| // Relation overriddenRelation = overriddenRelationAnalysis.getRule(); |
| boolean isWhere = overriddenRelationAnalysis.hasIncomingWhereInvocationAnalyses(); |
| // RelationAnalysis2TraceGroup overriddenRelationAnalysis2TraceGroup = overriddenRelationAnalysis.getRuleAnalysis2TraceGroup(); |
| RelationAnalysis2TraceGroup overridingRelationAnalysis2TraceGroup = overridingRelationAnalysis.getRuleAnalysis2TraceGroup(); |
| // RelationAnalysis2MiddleType overriddenRelationAnalysis2TraceInterface = overriddenRelationAnalysis2TraceGroup.getRuleAnalysis2TraceInterface(); |
| RelationAnalysis2MiddleType overridingRelationAnalysis2TraceInterface = overridingRelationAnalysis2TraceGroup.getRuleAnalysis2TraceInterface(); |
| RelationAnalysis2MiddleType overridingRelationAnalysis2TraceClass = overridingRelationAnalysis2TraceGroup.getRuleAnalysis2TraceClass(); |
| ClassDatum overridingClassDatum = scheduleManager2.getClassDatum(traceTypedModel, overridingRelationAnalysis2TraceInterface.getMiddleClass()); |
| Node guardNode = createPredicatedNode("not_" + overridingRelation.getName(), overridingClassDatum, true); |
| Property globalSuccessProperty = overridingRelationAnalysis2TraceClass.getGlobalSuccessProperty(); |
| createPredicatedSuccess(guardNode, globalSuccessProperty, false); |
| if (dispatchNode != null) { |
| RelationAnalysis2DispatchClass relationAnalysis2dispatchClass = overriddenRelationAnalysis.getRuleAnalysis2TraceGroup().getRuleAnalysis2DispatchClass(); |
| DispatchClass2TraceProperty dispatchClass2TraceProperty = relationAnalysis2dispatchClass.getDispatchClass2TraceProperty(overridingRelation); |
| Property guardProperty = dispatchClass2TraceProperty.getTraceProperty(); |
| createNavigationEdge(dispatchNode, guardProperty, guardNode, false); |
| } |
| if (isWhere /*|| scheduleManager2.getDomainUsage(rootVariable).isInput()*/) { |
| for (@NonNull VariableDeclaration rootVariable : QVTrelationUtil.getRootVariables(relation)) { |
| Node rootVariableNode = getReferenceNode(rootVariable); |
| VariableDeclaration overridingRootVariable = QVTrelationUtil.getOverriddenVariable(overridingRelation, rootVariable); |
| Property invocationProperty = overridingRelationAnalysis2TraceInterface.getTraceProperty(overridingRootVariable); |
| boolean isPartial = scheduleManager.computeIsPartial(rootVariableNode, invocationProperty); |
| createNavigationEdge(guardNode, invocationProperty, rootVariableNode, isPartial); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Analyze the predicates to partition the guard variables into the distinct inputs that are not mutually |
| * navigable as a consequence of predicate constraints. |
| * @param bottomPatterns |
| * |
| protected void analyzePredicates(@NonNull List<@NonNull ? extends CorePattern> corePatterns) { |
| // |
| // Populate the targetVariable2sourceVariable2paths from the simple "a.b = c" style predicates, |
| // and cache those that are too hard to analyze as complex predicates. |
| // |
| for (@NonNull CorePattern corePattern : corePatterns) { |
| for (@NonNull Predicate predicate : ClassUtil.nullFree(corePattern.getPredicate())) { |
| OCLExpression conditionExpression = predicate.getConditionExpression(); |
| if (conditionExpression != null) { |
| OCLExpression boundExpression = getPredicateComparisonBoundExpression(conditionExpression); |
| if (boundExpression instanceof VariableExp) { |
| OCLExpression referenceExpression = getPredicateComparisonReferenceExpression(conditionExpression); |
| assert referenceExpression != null; |
| VariableDeclaration referredVariable = QVTrelationUtil.getReferredVariable(((VariableExp)boundExpression)); |
| // if (referredVariable instanceof BottomVariable) { |
| // addExpression(referredVariable, referenceExpression); |
| // } |
| // else { |
| if (!analyzeSimplePredicate(referredVariable, referenceExpression)) { |
| complexPredicates.add(predicate); |
| } |
| // } |
| } |
| else if (boundExpression instanceof NullLiteralExp) { |
| OCLExpression referenceExpression = getPredicateComparisonReferenceExpression(conditionExpression); |
| assert referenceExpression != null; |
| if (!analyzeSimplePredicate(null, referenceExpression)) { |
| complexPredicates.add(predicate); |
| } |
| } |
| else { |
| complexPredicates.add(predicate); |
| } |
| } |
| } |
| } |
| return; |
| } |
| * @return */ |
| |
| /* protected void analyzeInvocations(@NonNull Pattern pattern, boolean isWhen) { |
| for (@NonNull Predicate predicate : QVTrelationUtil.getOwnedPredicates(pattern)) { |
| OCLExpression predicateExpression = predicate.getConditionExpression(); |
| if (predicateExpression instanceof RelationCallExp) { |
| RelationCallExp relationInvocation = (RelationCallExp) predicateExpression; |
| Relation invokedRelation = QVTrelationUtil.getReferredRelation(relationInvocation); |
| RelationAnalysis invokedRelationAnalysis = (RelationAnalysis) transformationAnalysis.getRuleAnalysis(invokedRelation); |
| RelationAnalysis invokingRelationAnalysis = this; |
| if (isWhen) { |
| invokedRelationAnalysis.addIncomingWhenRelation(relationInvocation); |
| invokingRelationAnalysis.addOutgoingWhenRelation(relationInvocation); |
| } |
| else { |
| invokedRelationAnalysis.addIncomingWhereRelation(relationInvocation); |
| invokingRelationAnalysis.addOutgoingWhereRelation(relationInvocation); |
| } |
| } |
| } |
| } */ |
| |
| protected void synthesizePredicate(@NonNull OCLExpression predicateExpression) { |
| Domain asDomain = QVTrelationUtil.basicGetContainingDomain(predicateExpression); |
| if ((asDomain != null) && scheduleManager.isOutput(asDomain)) { |
| return; |
| } |
| if (synthesizeEqualsPredicate(predicateExpression)) { |
| return; |
| } |
| Node resultNode = predicateExpression.accept(expressionSynthesizer); //.getConditionalExpressionSynthesizer()); // See Bug 547263 |
| if (resultNode != null) { |
| Node trueNode = createBooleanLiteralNode(true); |
| createPredicateEdge(resultNode, null, trueNode); |
| } |
| } |
| |
| /** |
| * Create a GREEN node for each realized variable. |
| * |
| protected void analyzeRealizedVariables() { |
| for (@NonNull BottomPattern bottomPattern : bottomPatterns) { |
| for (@NonNull RealizedVariable realizedVariable : ClassUtil.nullFree(bottomPattern.getRealizedVariable())) { |
| Node realizedNode = ruleRegion.getNode(realizedVariable); |
| assert realizedNode == null; |
| realizedNode = createRealizedStepNode(realizedVariable); |
| assert realizedNode == ruleRegion.getNode(realizedVariable); |
| } |
| } |
| } */ |
| |
| // |
| // Install the targetVariable2sourceVariable2paths entries for a "boundVariable = referenceExpression" predicate, |
| // where the referenceExpression involves zero or more PropertyCallExps of a VariableExp. boundVariable may be null |
| // for a negative application condition. |
| // |
| // A reverse entry is also created if no PropertyCallExp is not to-one. |
| /* |
| private boolean analyzeSimplePredicate(@Nullable VariableDeclaration boundVariable, @NonNull OCLExpression referenceExpression) { |
| boolean isValid = false; |
| for (@NonNull OCLExpression expression = referenceExpression; expression instanceof NavigationCallExp; ) { |
| NavigationCallExp navigationCallExp = (NavigationCallExp)expression; |
| expression = ClassUtil.nonNullState(navigationCallExp.getOwnedSource()); |
| if (expression instanceof VariableExp) { |
| isValid = true; |
| break; |
| } |
| } |
| if (!isValid) { |
| return false; |
| } |
| for (@NonNull OCLExpression expression = referenceExpression; expression instanceof NavigationCallExp; ) { |
| NavigationCallExp navigationCallExp = (NavigationCallExp)expression; |
| Property referredProperty = PivotUtil.getReferredProperty(navigationCallExp); |
| assert referredProperty != null; |
| expression = ClassUtil.nonNullState(navigationCallExp.getOwnedSource()); |
| if (expression instanceof VariableExp) { |
| VariableDeclaration sourceVariable = ((VariableExp)expression).getReferredVariable(); |
| assert sourceVariable != null; |
| // assert guardVariables.contains(targetVariable); |
| // assert guardVariables.contains(sourceVariable); |
| Node sourceNode = getReferenceNode(sourceVariable); |
| Node targetNode = boundVariable != null ? getReferenceNode(boundVariable) : createNullNode(true, null); |
| // assert sourceNode.isGuard(); |
| // assert (boundVariable == null) || targetNode.isGuard(); |
| assert sourceNode.isClass(); |
| if (!referredProperty.isIsMany()) { |
| Edge predicateEdge = sourceNode.getPredicateEdge(referredProperty); |
| if (predicateEdge == null) { |
| createNavigationEdge(sourceNode, referredProperty, targetNode, false); |
| } |
| else { |
| assert predicateEdge.getEdgeTarget() == targetNode; |
| } |
| } |
| } |
| } |
| return true; |
| } */ |
| |
| /** |
| * Synthesize the simple input CollectionTemplateExp pattern match comprising a single member and no rest. |
| * |
| * Returns false if a more complex multi-member match is needed. |
| */ |
| protected boolean synthesizeSingleInputCollectionTemplate(@NonNull CollectionTemplateExp collectionTemplateExp) { |
| Variable rest = collectionTemplateExp.getRest(); |
| if ((rest == null) || !rest.isIsImplicit()) { |
| return false; |
| } |
| List<OCLExpression> members = collectionTemplateExp.getMember(); |
| if (members.size() > 1) { |
| return false; |
| } |
| EObject eContainer = collectionTemplateExp.eContainer(); |
| if (!(eContainer instanceof PropertyTemplateItem)) { |
| return false; // Can this ever happen? |
| } |
| PropertyTemplateItem propertyTemplateItem = (PropertyTemplateItem)eContainer; |
| Property source2target = QVTrelationUtil.getReferredProperty(propertyTemplateItem); |
| ObjectTemplateExp objectTemplateExp = QVTrelationUtil.getOwningObjectTemplateExp(propertyTemplateItem); |
| Node sourceNode = objectTemplateExp.accept(expressionSynthesizer); |
| assert sourceNode != null; |
| Node memberNode = members.get(0).accept(expressionSynthesizer); |
| assert memberNode != null; |
| createNavigationEdge(sourceNode, source2target, memberNode, true); |
| return true; |
| } |
| |
| /** |
| * Create the trace node assignments to pattern nodes |
| */ |
| protected void synthesizeTraceEdges(@NonNull Node traceNode, @Nullable Node dispatchNode) { |
| Relation relation = getRule(); |
| if (dispatchNode != null) { |
| RelationAnalysis2DispatchClass ruleAnalysis2dispatchClass = getBaseRelationAnalysis().getRuleAnalysis2TraceGroup().getRuleAnalysis2DispatchClass(); |
| // RelationAnalysis2TraceClass ruleAnalysis2traceClass = getRuleAnalysis2TraceGroup().getRuleAnalysis2TraceClass(); |
| Relation baseRelation = getBaseRelationAnalysis().getRule(); |
| for (@NonNull RelationDomain relationDomain : QVTrelationUtil.getOwnedDomains(relation)) { |
| Boolean isInput = getScheduleManager().isInput(relationDomain) || !relation.isIsTopLevel(); |
| for (@NonNull VariableDeclaration rootVariable : QVTrelationUtil.getRootVariables(relationDomain)) { |
| VariableDeclaration baseRootVariable = QVTrelationUtil.getOverriddenVariable(baseRelation, rootVariable); |
| VariableDeclaration2TraceProperty overriddenVariableDeclaration2traceProperty = ruleAnalysis2dispatchClass.getVariableDeclaration2TraceProperty(baseRootVariable); |
| // VariableDeclaration2TraceProperty overridingVariableDeclaration2traceProperty = ruleAnalysis2traceClass.getVariableDeclaration2TraceProperty(rootVariable); |
| Property traceProperty = overriddenVariableDeclaration2traceProperty.getTraceProperty(); |
| // VariableDeclaration tracedVariable = overridingVariableDeclaration2traceProperty.getOverridingVariable(); |
| Node targetNode = region.getNode(rootVariable); |
| assert targetNode != null; |
| boolean isPartial = scheduleManager.computeIsPartial(dispatchNode, traceProperty); |
| if (isInput) { |
| createNavigationEdge(dispatchNode, traceProperty, targetNode, isPartial); |
| } |
| else { |
| createRealizedNavigationEdge(dispatchNode, traceProperty, targetNode, isPartial); |
| } |
| } |
| } |
| boolean hasPredicatedTrace = traceNode.isPredicated(); // || traceNode.isSpeculated(); |
| assert hasPredicatedTrace; |
| List<@NonNull ? extends VariableDeclaration> rootVariables = QVTrelationUtil.getRootVariables(relation); |
| RelationAnalysis2TraceClass ruleAnalysis2traceClass = getRuleAnalysis2TraceGroup().getRuleAnalysis2TraceClass(); |
| for (@NonNull VariableDeclaration2TraceProperty variableDeclaration2traceProperty : ruleAnalysis2traceClass.getVariableDeclaration2TraceProperties()) { |
| Property traceProperty = variableDeclaration2traceProperty.getTraceProperty(); |
| VariableDeclaration tracedVariable = variableDeclaration2traceProperty.getOverridingVariable(); |
| Node targetNode = region.getNode(tracedVariable); |
| assert targetNode != null; |
| if (!rootVariables.contains(tracedVariable)) { |
| boolean isPartial = scheduleManager.computeIsPartial(targetNode, traceProperty); |
| createRealizedNavigationEdge(traceNode, traceProperty, targetNode, isPartial); |
| } |
| } |
| } |
| else { |
| boolean hasPredicatedTrace = traceNode.isPredicated(); // || traceNode.isSpeculated(); |
| List<@NonNull ? extends VariableDeclaration> rootVariables = QVTrelationUtil.getRootVariables(relation); |
| RelationAnalysis2TraceClass ruleAnalysis2traceClass = getRuleAnalysis2TraceGroup().getRuleAnalysis2TraceClass(); |
| for (@NonNull VariableDeclaration2TraceProperty variableDeclaration2traceProperty : ruleAnalysis2traceClass.getVariableDeclaration2TraceProperties()) { |
| Property traceProperty = variableDeclaration2traceProperty.getTraceProperty(); |
| VariableDeclaration tracedVariable = variableDeclaration2traceProperty.getOverridingVariable(); |
| Node targetNode = region.getNode(tracedVariable); |
| assert targetNode != null; |
| boolean isPartial = scheduleManager.computeIsPartial(traceNode, traceProperty); |
| if (hasPredicatedTrace && rootVariables.contains(tracedVariable)) { |
| createNavigationEdge(traceNode, traceProperty, targetNode, isPartial); |
| } |
| else { |
| createRealizedNavigationEdge(traceNode, traceProperty, targetNode, isPartial); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Create trace and when/where invocation nodes and their edges. |
| */ |
| public void synthesizeTraceElements(@NonNull RelationAnalysis2TraceGroup relationAnalysis2traceGroup) { |
| // |
| // Create the dispatch region if needed by an override. |
| // |
| if (dispatch != null) { |
| dispatch.synthesizeElements(); |
| } |
| // |
| // Create the base region if needed by an override. |
| // |
| if (verdict != null) { |
| verdict.synthesizeElements(); |
| } |
| // |
| // Correct type of the trace variable |
| // |
| Relation relation = getRule(); |
| if (!relation.isIsAbstract()) { |
| RelationAnalysis2TraceClass ruleAnalysis2traceClass = relationAnalysis2traceGroup.getRuleAnalysis2TraceClass(); |
| VariableDeclaration traceVariable = QVTrelationUtil.getTraceVariable(relation); |
| traceVariable.setType(ruleAnalysis2traceClass.getMiddleClass()); |
| // |
| // Create the trace node |
| // |
| Node traceNode = synthesizeTraceNode(); |
| // |
| // Create the dispatch node |
| // |
| Node dispatchNode = QVTrelationUtil.hasOverrides(relation) ? synthesizeDispatchNode(traceNode) : null; |
| // |
| // Create the trace node assignments to pattern nodes |
| // |
| synthesizeTraceEdges(traceNode, dispatchNode); |
| // |
| // Create the nodes for when invocations |
| // |
| synthesizeOutgoingWhenInvocations(traceNode); |
| // |
| // Create the nodes for where invocations |
| // |
| synthesizeOutgoingWhereInvocations(traceNode); |
| // |
| // Create the invocation interface for a non-top relation. |
| // |
| // synthesizeIncomingNonTopInvocation(traceNode); |
| // |
| // Create the guards for overriding relations. |
| // |
| synthesizeOverridingGuards(dispatchNode, traceNode); |
| // |
| // Create the trace status. |
| // |
| synthesizeTraceGlobalSuccessAssignment(relationAnalysis2traceGroup, traceNode); |
| // |
| // Create the interface property and status assignments. |
| // |
| synthesizeInterfaceAssignments(relationAnalysis2traceGroup, traceNode); |
| } |
| } |
| |
| protected void synthesizeTraceGlobalSuccessAssignment(@NonNull RelationAnalysis2TraceGroup relationAnalysis2traceGroup, @NonNull Node traceNode) { |
| RelationAnalysis2TraceClass relationAnalysis2TraceClass = relationAnalysis2traceGroup.getRuleAnalysis2TraceClass(); |
| Element2MiddleProperty relation2globalSuccessProperty = relationAnalysis2TraceClass.basicGetRelation2GlobalSuccessProperty(); |
| if (relation2globalSuccessProperty != null) { |
| createRealizedSuccess(traceNode, relation2globalSuccessProperty.getTraceProperty(), null); |
| } |
| } |
| |
| /* public void synthesizeTraceLocalSuccessAssignment(@NonNull RelationAnalysis2TraceGroup relationAnalysis2traceGroup, @NonNull Node traceNode) { |
| RelationAnalysis2TraceClass relationAnalysis2TraceClass = relationAnalysis2traceGroup.getRuleAnalysis2TraceClass(); |
| Element2MiddleProperty relation2localSuccessProperty = relationAnalysis2TraceClass.basicGetRelation2LocalSuccessProperty(); |
| if (relation2localSuccessProperty != null) { |
| createRealizedSuccess(traceNode, relation2localSuccessProperty.getTraceProperty(), null); |
| } |
| } */ |
| |
| /** |
| * Create the trace node |
| */ |
| protected @NonNull Node synthesizeTraceNode() { |
| Relation relation = getRule(); |
| VariableDeclaration traceVariable = QVTrelationUtil.getTraceVariable(relation); |
| Node traceNode; |
| boolean hasOverrides = QVTrelationUtil.hasOverrides(relation); |
| if (hasOverrides) { |
| traceNode = createOldNode(traceVariable); |
| } |
| // else if (isSharedAggregator()) { |
| // traceNode = createRealizedStepNode(traceVariable); |
| // } |
| else if (!relation.isIsTopLevel()) { |
| // if (hasOverrides) { |
| traceNode = createOldNode(traceVariable); |
| // DomainUsage domainUsage = scheduleManager.getDomainUsage(traceVariable); |
| // boolean isEnforceable = domainUsage.isOutput() || domainUsage.isMiddle(); |
| // Role phase = isEnforceable ? Role.PREDICATED : Role.LOADED; |
| // Role nodeRole = phase; |
| // PatternVariableNode traceNode = QVTscheduleFactory.eINSTANCE.createPatternVariableNode(); |
| // traceNode.initialize(nodeRole, region, getName(traceVariable), scheduleManager.getClassDatum(traceVariable)); |
| // traceNode.initializeVariable(region, traceVariable); |
| // traceNode.setMatched(true); |
| // |
| region.getHeadNodes().clear(); |
| region.getHeadNodes().add(traceNode); |
| traceNode.setHead(); |
| // } |
| // else { |
| // traceNode = createRealizedStepNode(traceVariable); |
| // } |
| /**** |
| if (hasIncomingWhereInvocationAnalyses()) { |
| traceNode = createOldNode(traceVariable); |
| region.getHeadNodes().clear(); |
| region.getHeadNodes().add(traceNode); |
| traceNode.setHead(); |
| } |
| else { |
| traceNode = createRealizedStepNode(traceVariable); |
| } |
| >>>>>>> 5716624 bad wip success checks ***/ |
| } |
| else { |
| boolean hasPredicatedTrace = (incomingWhereInvocationAnalyses != null) && !hasOverrides; |
| traceNode = hasPredicatedTrace ? createOldNode(traceVariable) : createRealizedStepNode(traceVariable); |
| if (!getRule().isIsTopLevel()) { |
| region.getHeadNodes().clear(); |
| // region.getHeadNodes().add(traceNode); |
| } |
| } |
| traceNode.setUtility(Utility.TRACE); |
| return traceNode; |
| } |
| |
| // FIXME Introduce derived RelationAnalysis strategies |
| public void synthesizeVariableDeclaration(@NonNull VariableDeclaration variableDeclaration) { // FIXME move to derived visitVariableDeclaration |
| // boolean isEnforced = false; |
| // ClassDatum classDatum = scheduleManager.getClassDatum(variableDeclaration); |
| // TypedModel typedModel = QVTscheduleUtil.getReferredTypedModel(classDatum); |
| // Map<@NonNull TemplateVariable, @NonNull TemplateExp> variable2templateExp2 = variable2templateExp; |
| // assert variable2templateExp2 != null; |
| TemplateExp templateExp = basicGetTemplateExp(variableDeclaration); |
| if ((variableDeclaration instanceof Variable) && ((Variable)variableDeclaration).isIsImplicit() && (templateExp == null)) { |
| return; // implicit CollectionTemplateExp rest nodes are not needed |
| } |
| else if (QVTrelationUtil.isTraceClassVariable(variableDeclaration)) { |
| return; // traceNode created by synthesizeTraceNodes |
| } |
| else if (getKeyedOutputVariables().contains(variableDeclaration)) { |
| boolean isUnconditional = true; |
| createKeyedNode(isUnconditional, QVTrelationUtil.getName(variableDeclaration), variableDeclaration); |
| return; // keyed object created by synthesizeKeyedObject |
| } |
| else if (getTopWhenedOutputVariables().contains(variableDeclaration)) { |
| createOldNode(variableDeclaration); // when output is created by the invoked when |
| } |
| else if (getNonTopWhenedOutputVariables().contains(variableDeclaration)) { |
| createOldNode(variableDeclaration); // when output is created by the invoked when |
| // createRealizedStepNode(variableDeclaration); // when output is created by the invoker |
| } |
| else if (hasIncomingWhereInvocationAnalyses() && Iterables.contains(QVTrelationUtil.getRootVariables(getRule()), variableDeclaration)) { |
| createOldNode(variableDeclaration); // where 'output' is created by invoker |
| } |
| else if (getRealizedOutputVariables().contains(variableDeclaration)) { |
| createRealizedStepNode(variableDeclaration); |
| } |
| else if (hasIncomingWhenInvocationAnalyses() && Iterables.contains(QVTrelationUtil.getRootVariables(getRule()), variableDeclaration)) { |
| createOldNode(variableDeclaration); // where 'output' is created by invoker |
| } |
| else { |
| if (variableDeclaration instanceof TemplateVariable) { |
| assert templateExp != null; |
| if (templateExp instanceof CollectionTemplateExp) { |
| // if (scheduleManager.getDomainUsage(templateExp).isOutput()) { |
| return; // CollectionTemplateExp variables would be bloat |
| // } |
| } |
| createOldNode(variableDeclaration); |
| } |
| else if (variableDeclaration instanceof SharedVariable) { |
| SharedVariable sharedVariable = (SharedVariable)variableDeclaration; |
| if (sharedVariable.getOwnedInit() != null) { |
| // defer to re-use initializer node -- createOldNode(sharedVariable); |
| } |
| else { |
| // createOldNode(variableDeclaration); // FIXME defer to avoid unused variable nodes |
| } |
| } |
| else { |
| createOldNode(variableDeclaration); // Never happens |
| } |
| } |
| } |
| |
| protected boolean synthesizeVariableEqualsPredicate(@NonNull VariableDeclaration variable, @NonNull OCLExpression valueExp) { |
| Node variableNode = region.getNode(variable); |
| if (variableNode == null) { |
| if (variable instanceof SharedVariable) { |
| variableNode = getReferenceNodeForSharedVariable((SharedVariable)variable, valueExp); |
| } |
| if (variableNode != null) { |
| return true; |
| } |
| } |
| variableNode = variable.accept(expressionSynthesizer); |
| Node expressionNode = valueExp.accept(expressionSynthesizer); |
| assert (variableNode != null) && (expressionNode != null); |
| createEqualsEdge(expressionNode, variableNode); |
| return true; |
| } |
| } |