EObjectDescription userData and information from other Resources [message #1832605] |
Mon, 21 September 2020 16:51 |
Stefan Winkler Messages: 307 Registered: July 2009 Location: Germany |
Senior Member |
|
|
Hi,
TL;DR I want to know if there is an Xtext standard solution for having resource description user data refer to information from cross-references outside its own Resource.
To illustrate, let me take this example from the tutorial:
mydsl.xtext:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
Domainmodel:
(elements+=AbstractElement)*;
PackageDeclaration:
'package' name=QualifiedName '{'
(elements+=AbstractElement)*
'}';
AbstractElement:
PackageDeclaration | Type | Import;
QualifiedName:
ID ('.' ID)*;
Import:
'import' importedNamespace=QualifiedNameWithWildcard;
QualifiedNameWithWildcard:
QualifiedName '.*'?;
Type:
DataType | Entity;
DataType:
'datatype' name=ID;
Entity:
'entity' name=ID ('extends' superType=[Entity|QualifiedName])? '{'
(features+=Feature)*
'}';
Feature:
(many?='many')? name=ID ':' type=[Type|QualifiedName];
and two files in that language:
one.mydsl:
package one {
entity upper {
}
}
two.mydsl:
package two {
import one.*
entity lower extends upper {
}
}
I want to implement my own ResourceDescriptionStrategy which adds user data in a way so I can directly query for the superclass of a given entitie's IEObjectDescription without the need for proxy resolution (for performance reasons. Let's say I want a fast way to query the Xtext index for a type and without resolving it's proxy to navigate to the supertype and check something with that).
The trivial approach would be to implement the ResourceDescriptionStrategy like this:
package org.xtext.example.mydsl.resource;
import java.util.Collections;
import javax.inject.Inject;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.EObjectDescription;
import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionStrategy;
import org.eclipse.xtext.util.IAcceptor;
import org.xtext.example.mydsl.myDsl.Entity;
public class MyResourceDescriptionStrategy extends DefaultResourceDescriptionStrategy implements IDefaultResourceDescriptionStrategy
{
@Inject
IQualifiedNameProvider qnProvider;
@Override
public boolean createEObjectDescriptions(final EObject eObject, final IAcceptor<IEObjectDescription> acceptor)
{
if (eObject instanceof Entity)
{
Entity type = (Entity) eObject;
QualifiedName typeName = this.qnProvider.getFullyQualifiedName(type);
IEObjectDescription desc;
Entity superType = type.getSuperType();
if (superType != null)
{
QualifiedName superTypeName = this.qnProvider.getFullyQualifiedName(superType);
// PROBLEM: superType is (can be) a proxy, then superTypeName is null!
String superNameString = superTypeName != null ? superTypeName.toString() : "";
desc = EObjectDescription.create(typeName, type, Collections.singletonMap("superType", superNameString));
}
else
{
desc = EObjectDescription.create(typeName, type);
}
acceptor.accept(desc);
return true;
}
else
{
return super.createEObjectDescriptions(eObject, acceptor);
}
}
}
but this does not work (of course) because superType is imported from a different resource and therefore is a proxy here.
I could take the name of the superclass from the node model, but I still could not resolve it to its qualified name because it's imported (even via wildcard in this case).
I have seen a solution for this which uses a ForwardingMap as UserData which is evaluated lazily on access, later, after the indexing phase. But that seems a bit hacky for my taste and consumes memory because the ForwardingMap will hold on to the eObject, so it cannot be garbage collected...
I thought that problem (using data from cross-references in user data) might be a problem that is more common, but I have not found a common solution for that (or I am looking in the wrong places, or I am overlooking something obvious...?).
Any help would be appreciated! Thanks in advance!
Best,
Stefan
|
|
|
Re: EObjectDescription userData and information from other Resources [message #1832607 is a reply to message #1832605] |
Mon, 21 September 2020 17:30 |
|
you can try to hack something like
org.eclipse.xtext.common.types.descriptions.JvmTypesResourceDescriptionStrategy.createLazyUserData(EObject)
unfortunatly it is not that easy for non xbase langs
you can:
from ClusteringBuilder state set a flag in a custom resource class that indexing is done & references are resolved (e.g. after resolveLazyCrossReferences)
this might need a big c&p
then in indexing you can do something like
lazyUserData = new ForwardingMap<String, String>() {
private Map<String, String> delegate;
@Override
protected Map<String, String> delegate() {
if (delegate == null) {
Resource resource = eObject.eResource();
if (resource instanceof YourXtextResource && !((YourXtextResource) resource).flag()) {
return Collections.emptyMap();
}
Builder<String, String> userData = ImmutableMap.builder();
String xxxx = ....
userData.put("YYYYY", xxxx);
delegate = userData.build();
}
return delegate;
}
};
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.01460 seconds