From 153d596e246d88fc33c10da12616dea5099d1238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Porras=20Campo?= Date: Mon, 13 Jan 2025 16:57:19 +0100 Subject: [PATCH] perf: do not install proxy node models on the complete AST --- .../persistence/ProxyCompositeNode.java | 25 +++++++++---------- .../tools/ddk/xtext/util/ParseTreeUtil.java | 22 ++++++++++++++++ 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java index e8911dc25..97831c496 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java @@ -18,7 +18,6 @@ import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.WrappedException; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; @@ -56,7 +55,7 @@ class ProxyCompositeNode implements ICompositeNode, BidiTreeIterable, Adapter { /** The root node proxy stores the original EObject ID map so that it can be used when installing the real node model. */ - private List idToEObjectMap; + private ArrayList idToEObjectMap; // NOPMD LooseCoupling private EObject semanticElement; @@ -75,39 +74,42 @@ static void installProxyNodeModel(final Resource resource) { return; } - ArrayList idToEObjectMap = Lists.newArrayList(); // NOPMD LooseCoupling EObject root = resource.getContents().get(0); - ProxyCompositeNode rootNode = installProxyNodeModel(root, idToEObjectMap); - idToEObjectMap.trimToSize(); - rootNode.idToEObjectMap = idToEObjectMap; + ProxyCompositeNode rootNode = installProxyNodeModel(root); + rootNode.idToEObjectMap = Lists.newArrayList(); + fillIdToEObjectMap(root, rootNode.idToEObjectMap); + rootNode.idToEObjectMap.trimToSize(); if (resource instanceof XtextResource) { ((XtextResource) resource).setParseResult(new ParseResult(root, rootNode, false)); } } - private static ProxyCompositeNode installProxyNodeModel(final EObject eObject, final List map) { + private static ProxyCompositeNode installProxyNodeModel(final EObject eObject) { ProxyCompositeNode result = new ProxyCompositeNode(); eObject.eAdapters().add(result); + return result; + } + + private static void fillIdToEObjectMap(final EObject eObject, final List map) { map.add(eObject); FeatureIterator iterator = (FeatureIterator) eObject.eContents().iterator(); if (iterator instanceof Filterable filterable) { filterable.filter(f -> !f.isTransient()); for (FeatureIterator it = iterator; it.hasNext();) { - installProxyNodeModel(it.next(), map); + fillIdToEObjectMap(it.next(), map); } } else { // post-filter the iterator, which is extra work for (FeatureIterator it = iterator; it.hasNext();) { EObject child = it.next(); if (!it.feature().isTransient()) { - installProxyNodeModel(child, map); + fillIdToEObjectMap(child, map); } } } - return result; } /** @@ -124,9 +126,6 @@ static List uninstallProxyNodeModel(final Resource resource) { ProxyCompositeNode proxyNode = uninstallProxyNode(root); if (proxyNode != null) { result = proxyNode.idToEObjectMap; - for (TreeIterator it = root.eAllContents(); it.hasNext();) { - uninstallProxyNode(it.next()); - } } } diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java index 15e4ce79a..fdc2f7a77 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java @@ -18,6 +18,7 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.CrossReference; import org.eclipse.xtext.Keyword; import org.eclipse.xtext.RuleCall; @@ -28,6 +29,7 @@ import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import com.avaloq.tools.ddk.xtext.linking.LazyLinkingResource2; import com.google.common.collect.Iterables; @@ -127,6 +129,21 @@ public static String getParsedString(final EObject object, final String featureN return getParsedStringUnchecked(object, feature, convert); } + /** + * Ensure the node model loaded. + * + * @param resource + * the resource + */ + public static void ensureNodeModelLoaded(final Resource resource) { + if (resource instanceof LazyLinkingResource2 lazyLinkinResource && lazyLinkinResource.isLoadedFromStorage()) { + EObject root = resource.getContents().get(0); + if (root != null && NodeModelUtils.getNode(root) instanceof ICompositeNode composite) { + composite.getText(); // side-effect on removing com.avaloq.tools.ddk.xtext.resource.persistence.ProxyCompositeNode + } + } + } + /** * Returns the source text assigned to the given feature of the given object. Does not work for multi-valued features. Optionally also converts the source * text using the corresponding value converter. Conversion is only performed for keywords, rule call or cross reference grammar rules. @@ -143,6 +160,11 @@ public static String getParsedString(final EObject object, final String featureN */ public static String getParsedStringUnchecked(final EObject object, final EStructuralFeature feature, final boolean convert) { INode node = Iterables.getFirst(NodeModelUtils.findNodesForFeature(object, feature), null); + + if (node == null) { // NOPMD CollapsibleIfStatements + ensureNodeModelLoaded(object.eResource()); + node = Iterables.getFirst(NodeModelUtils.findNodesForFeature(object, feature), null); + } if (node != null) { if (convert) { final LazyLinkingResource res = (LazyLinkingResource) object.eResource();