Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » EObjectDescription userData and information from other Resources
EObjectDescription userData and information from other Resources [message #1832605] Mon, 21 September 2020 16:51 Go to next message
Stefan Winkler is currently offline Stefan WinklerFriend
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 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
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
Re: EObjectDescription userData and information from other Resources [message #1832623 is a reply to message #1832607] Tue, 22 September 2020 08:29 Go to previous messageGo to next message
Stefan Winkler is currently offline Stefan WinklerFriend
Messages: 307
Registered: July 2009
Location: Germany
Senior Member
Hi Christian,

thanks. Yes that's what I meant with the solution using the ForwardingMap - in our codebase someone implemented it using

@Inject CompilerPhases compilerPhases;


and in delegate() then
if (this.compilerPhases.isIndexing(eObject)) {
  return Collections.emptyMap();
}
// else compute real map here


My problem with this solution is that the ForwardingMap instance references the EObject and, therefore, basically keeps the Resource in memory and prevents GC, so I need to make the ForwardingMap into a real class (instead of anonymous) and try to release the eObjectReference as soon as the userData is computed. Maybe it's worth it, now that I know that Xtext/Xbase does it more or less the same way...
(maybe we should factor the lazy user data computation out of .JvmTypesResourceDescriptionStrategy and create a common, more "official" API for this in Xtext - if that's the 'common' way to solve this?)

Thanks again!
Best,
Stefan
Re: EObjectDescription userData and information from other Resources [message #1832624 is a reply to message #1832623] Tue, 22 September 2020 08:34 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
this is a matter of special usecase vs general.
can you please create an issue to discuss if there should be done something in xtext or not


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: EObjectDescription userData and information from other Resources [message #1832625 is a reply to message #1832624] Tue, 22 September 2020 08:35 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
maybe also you can capture the uri instead of the resource
and reload the resource in doubt,
but that may cost some cpu time
(maybe more that you save in the end on query the index)


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Previous Topic:Post process transient attributes from comments
Next Topic:Open call hierarchy option
Goto Forum:
  


Current Time: Fri Apr 19 22:57:23 GMT 2024

Powered by FUDForum. Page generated in 0.03716 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top