Skip to content

Commit

Permalink
perf: do not install proxy node models on the complete AST
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenporras committed Jan 16, 2025
1 parent acb87bd commit 153d596
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -56,7 +55,7 @@
class ProxyCompositeNode implements ICompositeNode, BidiTreeIterable<INode>, 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<EObject> idToEObjectMap;
private ArrayList<EObject> idToEObjectMap; // NOPMD LooseCoupling

private EObject semanticElement;

Expand All @@ -75,39 +74,42 @@ static void installProxyNodeModel(final Resource resource) {
return;
}

ArrayList<EObject> 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<EObject> 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<EObject> map) {
map.add(eObject);

FeatureIterator<EObject> iterator = (FeatureIterator<EObject>) eObject.eContents().iterator();
if (iterator instanceof Filterable filterable) {
filterable.filter(f -> !f.isTransient());
for (FeatureIterator<EObject> it = iterator; it.hasNext();) {
installProxyNodeModel(it.next(), map);
fillIdToEObjectMap(it.next(), map);
}
} else {
// post-filter the iterator, which is extra work
for (FeatureIterator<EObject> it = iterator; it.hasNext();) {
EObject child = it.next();
if (!it.feature().isTransient()) {
installProxyNodeModel(child, map);
fillIdToEObjectMap(child, map);
}
}
}
return result;
}

/**
Expand All @@ -124,9 +126,6 @@ static List<EObject> uninstallProxyNodeModel(final Resource resource) {
ProxyCompositeNode proxyNode = uninstallProxyNode(root);
if (proxyNode != null) {
result = proxyNode.idToEObjectMap;
for (TreeIterator<EObject> it = root.eAllContents(); it.hasNext();) {
uninstallProxyNode(it.next());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;


Expand Down Expand Up @@ -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.
Expand All @@ -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();
Expand Down

0 comments on commit 153d596

Please sign in to comment.