diff options
author | Ed Willink | 2016-11-01 12:46:04 +0000 |
---|---|---|
committer | Ed Willink | 2016-11-01 12:46:43 +0000 |
commit | b0e854c6947b26b1d46dd5eadc6d788f47b549b7 (patch) | |
tree | b9e0fb074cad76b8ecbe2b2d547c7330e520c6d4 | |
parent | 8e48a6ce0a97c44016f1abc9b54bf73d8c4e96a6 (diff) | |
download | org.eclipse.qvtd-b0e854c6947b26b1d46dd5eadc6d788f47b549b7.tar.gz org.eclipse.qvtd-b0e854c6947b26b1d46dd5eadc6d788f47b549b7.tar.xz org.eclipse.qvtd-b0e854c6947b26b1d46dd5eadc6d788f47b549b7.zip |
[474537] Ensure operation returns are specialized
3 files changed, 111 insertions, 2 deletions
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/ExpressionAnalyzer.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/ExpressionAnalyzer.java index 2101d4df9..736af6814 100644 --- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/ExpressionAnalyzer.java +++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/ExpressionAnalyzer.java @@ -64,6 +64,7 @@ import org.eclipse.qvtd.pivot.qvtcore.OppositePropertyAssignment; import org.eclipse.qvtd.pivot.qvtcore.PropertyAssignment; import org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsage; import org.eclipse.qvtd.pivot.qvtcore.util.AbstractExtendingQVTcoreVisitor; +import org.eclipse.qvtd.pivot.qvtcore.utilities.QVTcoreHelper; import org.eclipse.qvtd.pivot.qvtcore.utilities.QVTcoreUtil; import com.google.common.collect.Iterables; @@ -706,7 +707,8 @@ public class ExpressionAnalyzer extends AbstractExtendingQVTcoreVisitor<@NonNull assert property != null; OCLExpression value = asNavigationAssignment.getValue(); if (value != null) { - PivotUtil.rewriteSafeNavigations(environmentFactory, value); + QVTcoreHelper helper = new QVTcoreHelper(environmentFactory); // FIXME Re-use a helper + helper.rewriteSafeNavigations(value); } Node targetNode = analyze(value); NavigableEdge navigationEdge = getNavigationEdge(slotNode, property, targetNode, asNavigationAssignment); diff --git a/plugins/org.eclipse.qvtd.cs2as.compiler/src/org/eclipse/qvtd/cs2as/compiler/internal/OCL2QVTiCompilerChain.java b/plugins/org.eclipse.qvtd.cs2as.compiler/src/org/eclipse/qvtd/cs2as/compiler/internal/OCL2QVTiCompilerChain.java index 7efe60e8f..bd245a176 100644 --- a/plugins/org.eclipse.qvtd.cs2as.compiler/src/org/eclipse/qvtd/cs2as/compiler/internal/OCL2QVTiCompilerChain.java +++ b/plugins/org.eclipse.qvtd.cs2as.compiler/src/org/eclipse/qvtd/cs2as/compiler/internal/OCL2QVTiCompilerChain.java @@ -30,6 +30,7 @@ import org.eclipse.qvtd.compiler.AbstractCompilerChain; import org.eclipse.qvtd.compiler.AbstractCompilerStep; import org.eclipse.qvtd.compiler.CompilerChain; import org.eclipse.qvtd.compiler.CompilerChainException; +import org.eclipse.qvtd.pivot.qvtcore.utilities.QVTcoreHelper; import org.eclipse.qvtd.pivot.qvtimperative.ImperativeTransformation; import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperative; @@ -142,9 +143,10 @@ public class OCL2QVTiCompilerChain extends AbstractCompilerChain { // FIXME this workaround produces a new traversal of the resource private void rewriteSafeNavigations(@NonNull Resource resource) { + QVTcoreHelper helper = new QVTcoreHelper(environmentFactory); // FIXME Re-use a helper for (EObject rootObject : resource.getContents()) { if (rootObject instanceof Element) { - PivotUtil.rewriteSafeNavigations(environmentFactory, (Element) rootObject); + helper.rewriteSafeNavigations((Element) rootObject); } } } diff --git a/plugins/org.eclipse.qvtd.pivot.qvtcore/src/org/eclipse/qvtd/pivot/qvtcore/utilities/QVTcoreHelper.java b/plugins/org.eclipse.qvtd.pivot.qvtcore/src/org/eclipse/qvtd/pivot/qvtcore/utilities/QVTcoreHelper.java index e6930fbe4..777cb8965 100644 --- a/plugins/org.eclipse.qvtd.pivot.qvtcore/src/org/eclipse/qvtd/pivot/qvtcore/utilities/QVTcoreHelper.java +++ b/plugins/org.eclipse.qvtd.pivot.qvtcore/src/org/eclipse/qvtd/pivot/qvtcore/utilities/QVTcoreHelper.java @@ -10,13 +10,28 @@ *******************************************************************************/ package org.eclipse.qvtd.pivot.qvtcore.utilities; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.ocl.pivot.CallExp; +import org.eclipse.ocl.pivot.CollectionType; +import org.eclipse.ocl.pivot.Element; +import org.eclipse.ocl.pivot.LetExp; import org.eclipse.ocl.pivot.OCLExpression; +import org.eclipse.ocl.pivot.Operation; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.Variable; +import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager; +import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal; import org.eclipse.ocl.pivot.utilities.EnvironmentFactory; +import org.eclipse.ocl.pivot.utilities.NameUtil; import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseHelper; import org.eclipse.qvtd.pivot.qvtcore.BottomPattern; import org.eclipse.qvtd.pivot.qvtcore.GuardPattern; @@ -78,4 +93,94 @@ public class QVTcoreHelper extends QVTbaseHelper asVariableAssignment.setValue(asValueExpression); return asVariableAssignment; } + + /** + * Rewrite asTree and all its descendants to replace all "?." and "?->" navigations by their safe counterparts. + * @deprecated-promote to PivotHelper for M4. + */ + @Deprecated + public void rewriteSafeNavigations(@NonNull Element asTree) { + // + // Locate all unsafe calls first to avoid CME from concurrent locate/rewrite. + // + List<@NonNull CallExp> unsafeCallExps = null; + if (asTree instanceof CallExp) { + unsafeCallExps = rewriteUnsafeCallExp_Gather(unsafeCallExps, (CallExp)asTree); + } + for (TreeIterator<EObject> tit = asTree.eAllContents(); tit.hasNext(); ) { + EObject eObject = tit.next(); + if (eObject instanceof CallExp) { + unsafeCallExps = rewriteUnsafeCallExp_Gather(unsafeCallExps, (CallExp)eObject); + } + } + // + // Rewrite the unsafe calls + // + if (unsafeCallExps != null) { + PivotMetamodelManager metamodelManager = (PivotMetamodelManager) environmentFactory.getMetamodelManager(); + org.eclipse.ocl.pivot.Class oclAnyType = environmentFactory.getStandardLibrary().getOclAnyType(); + Operation oclEqualsOperation = NameUtil.getNameable(oclAnyType.getOwnedOperations(), "="); + assert oclEqualsOperation != null; + org.eclipse.ocl.pivot.Class collectionType = environmentFactory.getStandardLibrary().getCollectionType(); + Operation excludingOperation = NameUtil.getNameable(collectionType.getOwnedOperations(), "excluding"); + assert excludingOperation != null; + for (CallExp unsafeCallExp : unsafeCallExps) { + OCLExpression source = unsafeCallExp.getOwnedSource(); + assert source != null; + if (source.getType() instanceof CollectionType) { + rewriteUnsafeCollectionCallExp(metamodelManager, excludingOperation, unsafeCallExp); + } + else { + rewriteUnsafeObjectCallExp(metamodelManager, oclEqualsOperation, unsafeCallExp); + } + } + } + } + + private @Nullable List<@NonNull CallExp> rewriteUnsafeCallExp_Gather(@Nullable List<@NonNull CallExp> unsafeCallExps, @NonNull CallExp callExp) { + OCLExpression source = callExp.getOwnedSource(); + if ((source != null) && callExp.isIsSafe()) { + if (unsafeCallExps == null) { + unsafeCallExps = new ArrayList<@NonNull CallExp>(); + } + unsafeCallExps.add(callExp); + } + return unsafeCallExps; + } + + private void rewriteUnsafeCollectionCallExp(@NonNull PivotMetamodelManager metamodelManager, @NonNull Operation excludingOperation, @NonNull CallExp unsafeCollectionCallExp) { + unsafeCollectionCallExp.setIsSafe(false); + EObject eContainer = unsafeCollectionCallExp.eContainer(); + EReference eContainmentFeature = unsafeCollectionCallExp.eContainmentFeature(); + PivotUtilInternal.resetContainer(unsafeCollectionCallExp); + // + OCLExpression nullExpression = metamodelManager.createNullLiteralExp(); + OCLExpression safeCollectionCallExp = createOperationCallExp(unsafeCollectionCallExp, excludingOperation, Collections.singletonList(nullExpression)); + // + eContainer.eSet(eContainmentFeature, safeCollectionCallExp); + } + + private void rewriteUnsafeObjectCallExp(@NonNull PivotMetamodelManager metamodelManager, @NonNull Operation oclEqualsOperation, @NonNull CallExp unsafeObjectCallExp) { + unsafeObjectCallExp.setIsSafe(false); + EObject eContainer = unsafeObjectCallExp.eContainer(); + EReference eContainmentFeature = unsafeObjectCallExp.eContainmentFeature(); + PivotUtilInternal.resetContainer(unsafeObjectCallExp); + OCLExpression oldSourceExpression = unsafeObjectCallExp.getOwnedSource(); + assert oldSourceExpression != null; + // + Variable unsafeSourceVariable = createVariable("unsafe", oldSourceExpression); + OCLExpression unsafeSourceExpression1 = createVariableExp(unsafeSourceVariable); + unsafeObjectCallExp.setOwnedSource(unsafeSourceExpression1); + // + OCLExpression unsafeSourceExpression2 = createVariableExp(unsafeSourceVariable); + OCLExpression nullExpression = metamodelManager.createNullLiteralExp(); + OCLExpression isUnsafeExpression = createOperationCallExp(unsafeSourceExpression2, oclEqualsOperation, Collections.singletonList(nullExpression)); + // + OCLExpression thenExpression = metamodelManager.createNullLiteralExp(); + OCLExpression safeObjectCallExp = metamodelManager.createIfExp(isUnsafeExpression, thenExpression, unsafeObjectCallExp); + // + LetExp safeExp = createLetExp(unsafeSourceVariable, safeObjectCallExp); + // + eContainer.eSet(eContainmentFeature, safeExp); + } }
\ No newline at end of file |