blob: ef597f4ca1d4f267f18c069e04d81745fc154fbf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 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:
* Adolfo Sanchez-Barbudo Herrera - initial API and implementation
* E.D.Willink - use Complete model
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvtb2qvts;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.RegionsAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.analysis.PartialRegionAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.analysis.PartialRegionClassAnalysis;
import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge;
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.RuleRegion;
import org.eclipse.qvtd.pivot.qvtschedule.SharedEdge;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import com.google.common.collect.Iterables;
/**
* An OriginalContentsAnalysis provides an original, prior to partitioning, analysis of many (all) regions to facilitate lookup of all producers consumers of particular types and properties.
*
* The analysis is not updated by subsequent partitioning.
*/
public class OriginalContentsAnalysis
{
protected final @NonNull ScheduleManager scheduleManager;
protected final @NonNull Property oclContainerProperty;
private final @NonNull AbstractTransformationAnalysis transformationAnalysis;
/**
* The Speculation or Realized Nodes that produce each ClassDatum.
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull List<@NonNull Node>> classDatum2newNodes = new HashMap<>();
/**
* The input model classes that may be used as independent inputs by mappings and the nodes at which they are consumed.
* In the worst case a flat schedule just permutes allInstances() to provide all mapping inputs.
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull List<@NonNull Node>> classDatum2oldNodes = new HashMap<>();
/**
* The Realized Edges that produce each base PropertyDatum (or its opposite).
*/
private final @NonNull Map<@NonNull PropertyDatum, @NonNull List<@NonNull NavigationEdge>> basePropertyDatum2newEdges = new HashMap<>();
/**
* The Shared Edge that produces each singleton ClassDatum.
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull SharedEdge> classDatum2newSharedEdge = new HashMap<>();
/**
* The Shared Edge that produces each singleton ClassDatum.
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull List<@NonNull SharedEdge>> classDatum2oldSharedEdges = new HashMap<>();
/**
* The regions that consume each ClassDatum, eagerly computed by addRegion().
* (Uses only the super-ClassDatum hierarchy; no sub-ClassDatums.)
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull Set<@NonNull RuleRegion>> classDatum2consumingRegions = new HashMap<>();
/**
* The regions that consume each ClassDatum, lazily computed from the ClassAnalysis.
* Should be identical to classDatum2consumingRegions, but historical accident leave two 'identical'
* algorithms with differences to smooth out.
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull Set<@NonNull RuleRegion>> classDatum2consumingRegions2 = new HashMap<>();
/**
* The regions that produce each ClassDatum, eagerly computed by addRegion().
* (Uses only the super-ClassDatum hierarchy; no sub-ClassDatums.)
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull Set<@NonNull RuleRegion>> classDatum2producingRegions = new HashMap<>();
/**
* The regions that produce each ClassDatum, lazily computed from the ClassAnalysis.
* Should be identical to classDatum2producingRegions, but historical accident leave two 'identical'
* algorithms with differences to smooth out.
*/
private final @NonNull Map<@NonNull ClassDatum, @NonNull Set<@NonNull RuleRegion>> classDatum2producingRegions2 = new HashMap<>();
public OriginalContentsAnalysis(@NonNull ScheduleManager scheduleManager) {
this.scheduleManager = scheduleManager;
this.oclContainerProperty = scheduleManager.getStandardLibraryHelper().getOclContainerProperty();
Iterable<@NonNull AbstractTransformationAnalysis> transformationAnalyses = scheduleManager.getTransformationAnalyses();
assert Iterables.size(transformationAnalyses) == 1;
this.transformationAnalysis = transformationAnalyses.iterator().next();
}
private void addNewEdge(@NonNull RuleRegion region, @NonNull NavigableEdge newEdge) {
if (newEdge instanceof NavigationEdge) {
PropertyDatum propertyDatum = getPropertyDatum((NavigationEdge)newEdge);
addNewEdge(region, (NavigationEdge)newEdge, propertyDatum);
}
else {
assert newEdge.isShared();
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(QVTscheduleUtil.getTargetNode(newEdge));
SharedEdge oldEdge = classDatum2newSharedEdge.put(classDatum, (SharedEdge)newEdge);
assert oldEdge == null : "Duplicate new SharedEdge for " + classDatum;
}
}
private void addNewEdge(@NonNull RuleRegion region, @NonNull NavigationEdge newEdge, @NonNull PropertyDatum propertyDatum) {
@SuppressWarnings("unused") String name = propertyDatum.getName();
PropertyDatum basePropertyDatum = scheduleManager.getBasePropertyDatum(propertyDatum);
List<@NonNull NavigationEdge> edges = basePropertyDatum2newEdges.get(basePropertyDatum);
if (edges == null) {
edges = new ArrayList<>();
basePropertyDatum2newEdges.put(basePropertyDatum, edges);
}
if (!edges.contains(newEdge)) {
edges.add(newEdge);
// for (@NonNull PropertyDatum superAbstractDatum : ClassUtil.nullFree(propertyDatum.getSuperPropertyDatums())) {
// addNewEdge(region, newEdge, superAbstractDatum);
// }
}
}
private void addNewNode(@NonNull RuleRegion region, @NonNull Node newNode) {
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(newNode);
ClassDatum elementalClassDatum = scheduleManager.getElementalClassDatum(classDatum);
for (@NonNull ClassDatum superClassDatum : scheduleManager.getSuperClassDatums(elementalClassDatum)) {
List<@NonNull Node> nodes = classDatum2newNodes.get(superClassDatum);
if (nodes == null) {
nodes = new ArrayList<>();
classDatum2newNodes.put(superClassDatum, nodes);
}
nodes.add(newNode);
Set<@NonNull RuleRegion> regions = classDatum2producingRegions2.get(superClassDatum);
if (regions == null) {
regions = new HashSet<>();
classDatum2producingRegions2.put(superClassDatum, regions);
}
regions.add(region);
}
}
private void addOldEdge(@NonNull RuleRegion region, @NonNull NavigableEdge oldEdge) {
if (oldEdge instanceof NavigationEdge) {
}
else {
assert oldEdge.isShared();
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(QVTscheduleUtil.getTargetNode(oldEdge));
List<@NonNull SharedEdge> edges = classDatum2oldSharedEdges.get(classDatum);
if (edges == null) {
edges = new ArrayList<>();
classDatum2oldSharedEdges.put(classDatum, edges);
}
edges.add((SharedEdge)oldEdge);
}
}
private void addOldNode(@NonNull RuleRegion region, @NonNull Node oldNode) {
// assert !"EObject".equals(headNode.getCompleteClass().getName());
// Region region = oldNode.getRegion();
// Region invokingRegion = region.getInvokingRegion();
// assert (invokingRegion == this) || (invokingRegion == null);
// ClassDatumAnalysis classDatumAnalysis = QVTscheduleUtil.getClassDatumAnalysis(oldNode);
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(oldNode);
// classDatum = scheduleManager.getElementalClassDatum(classDatum);
for (@NonNull ClassDatum superClassDatum : scheduleManager.getSuperClassDatums(classDatum)) {
List<@NonNull Node> nodes = classDatum2oldNodes.get(superClassDatum);
if (nodes == null) {
nodes = new ArrayList<>();
classDatum2oldNodes.put(superClassDatum, nodes);
}
if (!nodes.contains(oldNode)) {
nodes.add(oldNode);
}
Set<@NonNull RuleRegion> regions = classDatum2consumingRegions2.get(superClassDatum);
if (regions == null) {
regions = new HashSet<>();
classDatum2consumingRegions2.put(superClassDatum, regions);
}
regions.add(region);
}
}
public void addRegion(@NonNull RuleRegion region) {
// FIXME Eliminate duplication wrt the use of ClassAnalysis to determine regions.
for (@NonNull Node oldNode : QVTscheduleUtil.getOwnedNodes(region)) {
if (oldNode.isOld() && !oldNode.isDependency() && !oldNode.isConstant()) {
if (oldNode.isHead()) {
// if (oldNode.isLoaded()) {
addOldNode(region, oldNode);
// }
}
else {
// if (!oldNode.isLoaded()) {
if (!isOnlyCastOrRecursed(oldNode)) { // FIXME Eliminate cast nodes
addOldNode(region, oldNode);
}
// }
}
}
}
for (@NonNull Node newNode : QVTscheduleUtil.getOwnedNodes(region)) {
if (newNode.isNew() && newNode.isClass()) {
addNewNode(region, newNode);
}
}
for (@NonNull Edge newEdge : QVTscheduleUtil.getOwnedEdges(region)) {
if (newEdge.isNavigable()) {
if (newEdge.isRealized()) {
addNewEdge(region, (NavigableEdge)newEdge);
}
else {
addOldEdge(region, (NavigableEdge)newEdge);
}
}
}
}
/* private @Nullable PropertyDatum basicGetPropertyDatum(@NonNull NavigableEdge producedEdge) {
assert !producedEdge.isCast(); // Handled by caller
Property forwardProperty = QVTscheduleUtil.getProperty(producedEdge);
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(producedEdge.getEdgeSource());
ClassDatum forwardClassDatum = scheduleManager.getElementalClassDatum(classDatum);
return scheduleManager.getPropertyDatum(forwardClassDatum, forwardProperty);
} */
public @NonNull String dumpClass2newNode() {
StringBuilder s = new StringBuilder();
List<@NonNull ClassDatum> classDatums = new ArrayList<>(classDatum2newNodes.keySet());
Collections.sort(classDatums, NameUtil.NAMEABLE_COMPARATOR);
for (@NonNull ClassDatum classDatum : classDatums) {
s.append("\n\t" + classDatum + " : ");
List<@NonNull Node> newNodes = new ArrayList<>(classDatum2newNodes.get(classDatum));
Collections.sort(newNodes, NameUtil.NAMEABLE_COMPARATOR);
for (@NonNull Node newNode : newNodes) {
s.append("\n\t\t" + newNode.getDisplayName());
}
}
return s.toString();
}
public @NonNull String dumpClass2oldNode() {
StringBuilder s = new StringBuilder();
List<@NonNull ClassDatum> classDatums = new ArrayList<>(classDatum2oldNodes.keySet());
Collections.sort(classDatums, NameUtil.NAMEABLE_COMPARATOR);
for (@NonNull ClassDatum classDatum : classDatums) {
s.append("\n\t" + classDatum + " : ");
List<@NonNull Node> oldNodes = new ArrayList<>(classDatum2oldNodes.get(classDatum));
Collections.sort(oldNodes, NameUtil.NAMEABLE_COMPARATOR);
for (@NonNull Node oldNode : oldNodes) {
s.append("\n\t\t" + oldNode.getDisplayName());
}
}
return s.toString();
}
/**
* Return all Realized NavigationEdges corresponding to predicatedEdge that navigate an isComposite property in either direction.
* Returns null in the very unusual event that there are none.
*
* It is assumed that edge is an predicated oclContainer edge to which almost all containment edges are compatible for a pathological
* input model whose metamodel extends the transformed metamodel with derived classes that merge the containment relationship
* of predicated/realized candidates.
*
* FIXME In the event that the ends of the realized edges are realized variables, we do know the precise
* type and could filter accordingly; a not-yet-exploited optimisation.
*/
private @Nullable Iterable<@NonNull NavigationEdge> getCompositeNewEdges(@NonNull NavigableEdge predicatedEdge) {
Set<@NonNull NavigationEdge> realizedEdges = null;
for (Map.Entry<@NonNull PropertyDatum, @NonNull List<@NonNull NavigationEdge>> entry : basePropertyDatum2newEdges.entrySet()) {
Property property = entry.getKey().getReferredProperty();
if (property != null) {
@Nullable Property compositeProperty = null;
if (property.isIsComposite()) {
compositeProperty = property;
}
else {
Property oppositeProperty = property.getOpposite();
if ((oppositeProperty != null) && oppositeProperty.isIsComposite()) {
compositeProperty = oppositeProperty;
}
}
if (compositeProperty != null) {
if (realizedEdges == null) {
realizedEdges = new HashSet<>();
}
realizedEdges.addAll(entry.getValue());
}
}
}
return realizedEdges;
}
/**
* Return the regions that consume precisely classDatum.
*/
public @NonNull Iterable<@NonNull RuleRegion> getDirectlyConsumingRegions(@NonNull ClassDatum classDatum) {
Set<@NonNull RuleRegion> consumingRegions = classDatum2consumingRegions.get(classDatum);
if (consumingRegions == null) {
PartialRegionClassAnalysis<@NonNull RegionsAnalysis> classAnalysis = transformationAnalysis.basicGetClassAnalysis(classDatum);
consumingRegions = new HashSet<>();
if (classAnalysis != null) {
for (@NonNull PartialRegionClassAnalysis<@NonNull RegionsAnalysis> subClassAnalysis : classAnalysis.getSubClassAnalyses()) {
for (@NonNull PartialRegionAnalysis<@NonNull RegionsAnalysis> regionAnalysis : subClassAnalysis.getConsumers()) {
consumingRegions.add((RuleRegion) regionAnalysis.getRegion());
}
}
}
classDatum2consumingRegions.put(classDatum, consumingRegions);
}
Set<@NonNull RuleRegion> consumingRegions2 = classDatum2consumingRegions2.get(classDatum);
if (consumingRegions2 == null) {
consumingRegions2 = new HashSet<>();
}
/* if (!consumingRegions.equals(consumingRegions2)) {
PartialRegionClassAnalysis<@NonNull RegionsAnalysis> classAnalysis = transformationAnalysis.basicGetClassAnalysis(classDatum);
consumingRegions = new HashSet<>();
if (classAnalysis != null) {
for (@NonNull PartialRegionClassAnalysis<@NonNull RegionsAnalysis> subClassAnalysis : classAnalysis.getSubClassAnalyses()) {
for (@NonNull RegionAnalysis regionAnalysis : subClassAnalysis.getConsumers()) {
consumingRegions.add((RuleRegion) regionAnalysis.getRegion());
}
}
}
classDatum2consumingRegions.put(classDatum, consumingRegions);
} */
assert consumingRegions.equals(consumingRegions2);
return consumingRegions;
}
/**
* Return the regions that produce classDatum or one of its subClassDatums.
*/
public @NonNull Iterable<@NonNull RuleRegion> getIndirectlyProducingRegions(@NonNull ClassDatum classDatum) {
Set<@NonNull RuleRegion> producingRegions = classDatum2producingRegions.get(classDatum);
if (producingRegions == null) {
PartialRegionClassAnalysis<@NonNull RegionsAnalysis> classAnalysis = transformationAnalysis.basicGetClassAnalysis(classDatum);
producingRegions = new HashSet<>();
if (classAnalysis != null) {
for (@NonNull PartialRegionClassAnalysis<@NonNull RegionsAnalysis> subClassAnalysis : classAnalysis.getSubClassAnalyses()) {
for (@NonNull PartialRegionAnalysis<@NonNull RegionsAnalysis> regionAnalysis : subClassAnalysis.getExactProducers()) {
producingRegions.add((RuleRegion) regionAnalysis.getRegion());
}
}
}
classDatum2producingRegions.put(classDatum, producingRegions);
}
Set<@NonNull RuleRegion> producingRegions2 = classDatum2producingRegions2.get(classDatum);
if (producingRegions2 == null) {
producingRegions2 = new HashSet<>();
}
assert producingRegions.equals(producingRegions2);
return producingRegions;
}
public @Nullable Iterable<@NonNull Node> getNewNodes(@NonNull ClassDatum classDatum) {
Iterable<@NonNull Node> newNodes = classDatum2newNodes.get(classDatum);
/* PartialRegionClassAnalysis<@NonNull RegionsAnalysis> classAnalysis = transformationAnalysis.basicGetClassAnalysis(classDatum);
Set<@NonNull RuleRegion> producingRegions = new HashSet<>();
if (classAnalysis != null) {
for (@NonNull PartialRegionClassAnalysis<@NonNull RegionsAnalysis> subClassAnalysis : classAnalysis.getSubClassAnalyses()) {
for (@NonNull RegionAnalysis regionAnalysis : subClassAnalysis.getProducers()) {
producingRegions.add((RuleRegion) regionAnalysis.getRegion());
}
}
} */
return newNodes;
}
public @Nullable Iterable<@NonNull NavigationEdge> getNewEdges(@NonNull NavigableEdge edge, @NonNull ClassDatum requiredClassDatum) {
if (edge instanceof NavigationEdge) {
Property property = QVTscheduleUtil.getReferredProperty((NavigationEdge)edge);
if (property.eContainer() == null) { // Ignore pseudo-properties such as «iterate»
return null;
}
if (property == oclContainerProperty) {
return getCompositeNewEdges(edge);
}
Iterable<@NonNull NavigationEdge> realizedEdges = null;
PropertyDatum propertyDatum = getPropertyDatum((NavigationEdge) edge);
PropertyDatum basePropertyDatum = scheduleManager.getBasePropertyDatum(propertyDatum);
// if (propertyDatum == null) {
// propertyDatum = basicGetPropertyDatum(edge); // FIXME debugging
// }
// if (propertyDatum == null) { // May be null for edges only used by operation dependencies
// return null;
// }
realizedEdges = basePropertyDatum2newEdges.get(basePropertyDatum);
if (realizedEdges == null) {
return null;
}
List<@NonNull NavigationEdge> conformantRealizedEdges = null;
for (@NonNull NavigationEdge realizedEdge : realizedEdges) {
boolean matches = false;
Property realizedProperty = QVTscheduleUtil.getReferredProperty(realizedEdge);
if (realizedProperty != property) {
assert realizedProperty.getOpposite() == property;
matches = true;
}
else {
Node targetNode = realizedEdge.getEdgeTarget();
ClassDatum realizedClassDatum = QVTscheduleUtil.getClassDatum(targetNode);
if (QVTscheduleUtil.conformsToClassOrBehavioralClass(realizedClassDatum, requiredClassDatum)) {
matches = true;
}
}
if (matches) {
if (conformantRealizedEdges == null) {
conformantRealizedEdges = new ArrayList<>();
}
conformantRealizedEdges.add(realizedEdge);
}
}
return conformantRealizedEdges;
}
else {
// FIXME SharedEdge
return null;
}
}
/* public @Nullable Iterable<@NonNull NavigableEdge> getNewInverseEdges(@NonNull NavigableEdge edge, @NonNull ClassDatum requiredClassDatum) {
Property property = edge.getProperty();
assert property.isIsMany();
if (property.eContainer() == null) { // Ignore pseudo-properties such as «iterate»
return null;
}
assert property != oclContainerProperty;
// if (property == oclContainerProperty) {
// return getCompositeNewEdges(edge);
// }
PropertyDatum propertyDatum = getPropertyDatum(edge);
PropertyDatum basePropertyDatum = scheduleManager.getBasePropertyDatum(propertyDatum);
PropertyDatum inversePropertyDatum = propertyDatum.getOpposite();
// if (propertyDatum == null) {
// propertyDatum = basicGetPropertyDatum(edge); // FIXME debugging
// }
// if (propertyDatum == null) { // May be null for edges only used by operation dependencies
// return null;
// }
Iterable<@NonNull NavigableEdge> inverseRealizedEdges = propertyDatum2newEdges.get(inversePropertyDatum);
if (inverseRealizedEdges == null) {
return null;
}
CompleteClass requiredClass = QVTscheduleUtil.getCompleteClass(requiredClassDatum);
List<@NonNull NavigableEdge> conformantRealizedEdges = null;
for (@NonNull NavigableEdge inverseRealizedEdge : inverseRealizedEdges) {
CompleteClass requiredCollectionCompleteClass = QVTscheduleUtil.getCompleteClass(requiredClassDatum);
Type requiredElementType = QVTimperativeUtil.getElementType((CollectionType) requiredCollectionCompleteClass.getPrimaryClass());
ClassDatum requiredElementClassDatum = scheduleManager.getClassDatum(QVTscheduleUtil.getReferredTypedModel(requiredClassDatum), (org.eclipse.ocl.pivot.Class)requiredElementType);
CompleteClass requiredElementCompleteClass = QVTscheduleUtil.getCompleteClass(requiredElementClassDatum);
ClassDatum requiredSourceClassDatum = propertyDatum.getOwningClassDatum();
CompleteClass requiredSourceCompleteClass = QVTscheduleUtil.getCompleteClass(requiredSourceClassDatum);
Node sourceNode = inverseRealizedEdge.getEdgeSource();
Node targetNode = inverseRealizedEdge.getEdgeTarget();
CompleteClass realizedSourceClass = sourceNode.getCompleteClass();
CompleteClass realizedTargetClass = targetNode.getCompleteClass();
if (QVTscheduleUtil.conformsToClassOrBehavioralClass(realizedTargetClass, requiredSourceCompleteClass)
&& QVTscheduleUtil.conformsToClassOrBehavioralClass(realizedSourceClass, requiredElementCompleteClass)) {
if (conformantRealizedEdges == null) {
conformantRealizedEdges = new ArrayList<>();
}
conformantRealizedEdges.add(inverseRealizedEdge);
}
}
return conformantRealizedEdges;
} */
public @Nullable Iterable<@NonNull Node> getOldNodes(@NonNull ClassDatum classDatum) {
return classDatum2oldNodes.get(classDatum);
}
public @Nullable Iterable<@NonNull SharedEdge> getOldSharedEdges(@NonNull SharedEdge edge) {
Node traceNode = QVTscheduleUtil.getTargetNode(edge);
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(traceNode);
return classDatum2oldSharedEdges.get(classDatum);
}
private @NonNull PropertyDatum getPropertyDatum(@NonNull NavigationEdge producedEdge) {
assert !producedEdge.isCast(); // Handled by caller
Property forwardProperty = QVTscheduleUtil.getReferredProperty(producedEdge);
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(producedEdge.getEdgeSource());
ClassDatum forwardClassDatum = scheduleManager.getElementalClassDatum(classDatum);
return scheduleManager.getPropertyDatum(forwardClassDatum, forwardProperty);
}
public @Nullable SharedEdge getNewSharedEdge(@NonNull SharedEdge edge) {
Node traceNode = QVTscheduleUtil.getTargetNode(edge);
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(traceNode);
return classDatum2newSharedEdge.get(classDatum);
}
/**
* Return true if this node is consumed solely by casts (or recursions) and so need not be considered as a true consumer.
* The downstream usages will consume more accurately.
*/
private boolean isOnlyCastOrRecursed(@NonNull Node predicatedNode) {
boolean isCast = false;
for (Edge outgoingEdge : QVTscheduleUtil.getOutgoingEdges(predicatedNode)) {
assert !outgoingEdge.isCast();
if (!outgoingEdge.isRecursion()) {
return false;
}
isCast = true;
}
return isCast;
}
/* private void removeNewEdge(@NonNull NavigableEdge newEdge) {
PropertyDatum propertyDatum = getPropertyDatum(newEdge);
removeNewEdge(newEdge, propertyDatum);
}
private void removeNewEdge(@NonNull NavigableEdge newEdge, @NonNull PropertyDatum propertyDatum) {
List<@NonNull NavigableEdge> edges = propertyDatum2newEdges.get(propertyDatum);
if (edges != null) {
if (edges.remove(newEdge)) {
for (@NonNull PropertyDatum superAbstractDatum : ClassUtil.nullFree(propertyDatum.getSuperPropertyDatums())) {
removeNewEdge(newEdge, superAbstractDatum);
}
}
}
} */
/* private void removeNewNode(@NonNull Node newNode) {
List<@NonNull Node> nodes = classDatum2newNodes.get(newNode.getClassDatum());
if (nodes != null) {
nodes.remove(newNode);
}
} */
/* private void removeOldNode(@NonNull Node oldNode) {
List<@NonNull Node> nodes = classDatum2oldNodes.get(oldNode.getClassDatum());
if (nodes != null) {
nodes.remove(oldNode);
}
} */
/* public void removeRegion(@NonNull RuleRegion region) {
for (@NonNull Node oldNode : region.getOldNodes()) {
removeOldNode(oldNode);
}
for (@NonNull Node newNode : region.getNewNodes()) {
removeNewNode(newNode);
}
for (@NonNull NavigableEdge newEdge : region.getRealizedNavigationEdges()) {
removeNewEdge(newEdge);
}
} */
}