From 155f502999a1218eb3f49efb482017df0ab8c189 Mon Sep 17 00:00:00 2001 From: Andreas Bayha <bayha@fortiss.org> Date: Wed, 22 Nov 2023 14:13:33 +0100 Subject: [PATCH] Reuse: Remove only external references when adding to library When removing references before adding elements to a library, only references that leave the elements containment (sub-)tree are removed. Issue-ref: 4346 Issue-URL: https://git.fortiss.org/af3/af3/-/issues/4346 Signed-off-by: Andreas Bayha <bayha@fortiss.org> --- .../tooling/ext/reuse/service/.ratings | 2 +- .../ext/reuse/service/ReuseProviderBase.java | 44 +++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/.ratings b/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/.ratings index 7c56142f7..5705d7eb2 100644 --- a/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/.ratings +++ b/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/.ratings @@ -1,5 +1,5 @@ IReuseProvider.java 18d293f7f1f072883188f16fb6eeb52c8d6042cf GREEN IReuseProviderService.java bcc70de0bb8d39c330e3a25d884abc7092dc1b7e GREEN LayoutedReuseProviderBase.java b0e4ce3cda818b0723ec37b925a4c4c3d0c41909 GREEN -ReuseProviderBase.java c956ba13df1b7b5c8dbd7cd1a9205a06b5cebba1 YELLOW +ReuseProviderBase.java d7b615677c9b147f93943a8b87c631c26f6e5b4d YELLOW ReuseProviderService.java c4ef33283002d6dac6167f9c6c8f71d2c2ce39d1 GREEN diff --git a/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/ReuseProviderBase.java b/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/ReuseProviderBase.java index c956ba13d..d7b615677 100644 --- a/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/ReuseProviderBase.java +++ b/org.fortiss.tooling.ext.reuse/src/org/fortiss/tooling/ext/reuse/service/ReuseProviderBase.java @@ -17,11 +17,14 @@ package org.fortiss.tooling.ext.reuse.service; import static org.eclipse.emf.ecore.util.EcoreUtil.replace; import static org.fortiss.tooling.ext.variability.util.VariabilityUtils.getOptVarPointSpecification; +import static org.fortiss.tooling.kernel.utils.EcoreUtils.getChildrenWithType; import static org.fortiss.tooling.kernel.utils.EcoreUtils.replaceEObjectReferences; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; @@ -137,8 +140,19 @@ public class ReuseProviderBase<T extends EObject> implements IReuseProvider<T> { * @param eObj * The {@link EObject} for which all reference targets shall be removed. */ - @SuppressWarnings("unchecked") private void removeExternalReferences(EObject eObj) { + // whitelist all contained elements as reference targets. + Set<EObject> whitelist = new HashSet<EObject>(getChildrenWithType(eObj, EObject.class)); + + removeReferences(eObj, whitelist); + } + + /** + * Recursively removes all reference targets from this and all contained {@link EObject}s which + * are not contained in the given whitelist. + */ + @SuppressWarnings("unchecked") + private void removeReferences(EObject eObj, Set<EObject> whitelist) { for(EReference ref : eObj.eClass().getEReferences()) { Object refTarget = eObj.eGet(ref); @@ -146,17 +160,29 @@ public class ReuseProviderBase<T extends EObject> implements IReuseProvider<T> { continue; } - if(ref.isContainment()) { - // Containment relations must not be removed. Yet, references of childs need to be - // removed recursively. - if(refTarget instanceof Collection<?>) { - ((Collection<EObject>)refTarget).stream() - .forEach(t -> removeExternalReferences(t)); + if(refTarget instanceof Collection<?>) { + Collection<EObject> refTargetCollection = (Collection<EObject>)refTarget; + + if(ref.isContainment()) { + // Containment relations must not be removed. Yet, references of childs need to + // be removed recursively. + refTargetCollection.stream().forEach(t -> removeReferences(t, whitelist)); } else { - removeExternalReferences((EObject)refTarget); + for(EObject t : refTargetCollection) { + if(!whitelist.contains(t)) { + refTargetCollection.remove(t); + } + } } } else { - eObj.eSet(ref, null); + if(ref.isContainment()) { + // Keep reference target and make recursive call. + removeReferences((EObject)refTarget, whitelist); + } else { + if(!whitelist.contains(refTarget)) { + eObj.eSet(ref, null); + } + } } } } -- GitLab