Referenced DSL-Files are not recognized on clean [message #1838543] |
Mon, 01 March 2021 04:45  |
Eclipse User |
|
|
|
We have a DSL where the parameters of calls are defined in separate Files. Those are normally read and parsed automatically. We also have a validator to check those parameters.
Now when we edit the dsl file containing the call, everything is normal. But if I do a clean, all parameters become red underlined. Debugging reveals that at this stage the definitions of the separate files have not been read yet, hence no validation is possible.
Also the stack trace of an edit validation is completely differend from a clean validation, when setting the halt point inside the validation.
How comes? And what is the solution to this problem?
Though the error goes away after insertion of a blank this behaviour is very confusing for the users. Even in some cases (this cannot always be reproduced) it is necessary to reopen the file, to get rid of thoses false errors.
|
|
|
|
|
|
|
|
|
|
|
Re: Referenced DSL-Files are not recognized on clean [message #1838556 is a reply to message #1838555] |
Mon, 01 March 2021 07:08   |
Eclipse User |
|
|
|
We used the following code:
package at.ama.swm.tabs.scoping
import com.google.inject.Inject
import org.eclipse.emf.ecore.EObject
import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider
import at.ama.swm.tabs.tabs.TabsPackage
class TabsIndex {
@Inject ResourceDescriptionsProvider rdp
def getResourceDescription(EObject eObj) {
val index = rdp.getResourceDescriptions(eObj.eResource)
index.getResourceDescription(eObj.eResource.URI)
}
def getExportedEObjectDescriptions(EObject eObj) {
eObj.getResourceDescription.getExportedObjects
}
def getExportedClassesEObjectDescriptions(EObject eObj) {
eObj.getResourceDescription.getExportedObjectsByType(TabsPackage.eINSTANCE.project)
}
}
and
/*
* generated by Xtext 2.16.0
*/
package at.ama.swm.tabs.scoping
import at.ama.swm.tabs.tabs.Process
import at.ama.swm.tabs.tabs.TabsPackage
import at.ama.swm.tabs.tabs.TabsProcess
import at.ama.swm.tabs.tabs.TabsProgram
import org.eclipse.emf.common.util.BasicEList
import org.eclipse.emf.common.util.EList
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.EReference
import org.eclipse.xtext.scoping.IScope
/**
* This class contains custom scoping description.
*
* See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping
* on how and when to use it.
*/
class TabsScopeProvider extends AbstractTabsScopeProvider {
val ePackage = TabsPackage.eINSTANCE
override getScope(EObject context, EReference reference) {
// Symbols - Variables & In/Out Parameters
if (reference == ePackage.symbolRef_Value || reference == ePackage.resultRef_Symbol) {
return scopeForSymbolRef(context)
}
// use - only valid in current process
else if (reference == ePackage.call_Ref) {
return scopeForUseRef(context)
}
else if (reference == ePackage.processCall_Ref) {
return scopeForUseRef(context)
}
else if (reference == ePackage.call_Fqn) {
}
// global var defs
else if (reference == ePackage.qualifiedVariable_Struct) {
return scopeForGlobalRef(context)
}
return super.getScope(context, reference)
}
def protected IScope scopeForGlobalRef(EObject context) {
val container = context.eContainer
return switch (container) {
TabsProgram: {
IgnoreCaseScopes.scopeFor(container.proc.using)
}
default: scopeForGlobalRef(container)
}
}
def protected IScope scopeForUseRef(EObject context) {
val container = context.eContainer
return switch (container) {
TabsProcess: {
IgnoreCaseScopes.scopeFor(container.using)
}
default: scopeForUseRef(container)
}
}
/*
* calculate the Scope for Symbol References
* Seite 249 im Buch!
*/
def protected IScope scopeForSymbolRef(EObject context) {
val container = context.eContainer
return switch (container) {
Process: {
var EList<EObject> symbolList = new BasicEList()
symbolList.addAll(container.variables)
symbolList.addAll(container.parameter)
IgnoreCaseScopes.scopeFor(symbolList)
}
default: scopeForSymbolRef(container)
}
}
}
and for ignore case:
/*******************************************************************************
* Cope of org.eclipse.xtext.scoping.Scopes
*
* THE ESSENTIAL DIFFERENCE:
* SimpleScope() is created with last param boolean ignoreCase set to true
*
*******************************************************************************/
package at.ama.swm.tabs.scoping;
import java.util.ArrayList;
import java.util.Map;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.EObjectDescription;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.SimpleScope;
import org.eclipse.xtext.util.SimpleAttributeResolver;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
/**
* This class contains static utility functions to create and work on {@link IScope} and {@link IEObjectDescription}
*
* @author Sven Efftinge - Initial contribution and API
* @author Jan Koehnlein - introduced QualifiedName
*/
public class IgnoreCaseScopes {
public static Iterable<IEObjectDescription> selectCompatible(Iterable<IEObjectDescription> exportedObjects, final EClass clazz) {
return Iterables.filter(exportedObjects, new Predicate<IEObjectDescription>() {
@Override
public boolean apply(IEObjectDescription input) {
return EcoreUtil2.isAssignableFrom(clazz,input.getEClass());
}
});
}
/**
* creates a scope using {@link SimpleAttributeResolver#NAME_RESOLVER} to compute the names and sets
* {@link IScope#NULLSCOPE} as parent scope
*/
public static IScope scopeFor(Iterable<? extends EObject> elements) {
return scopeFor(elements, IScope.NULLSCOPE);
}
/**
* creates a scope using {@link SimpleAttributeResolver#NAME_RESOLVER} to compute the names
*/
public static IScope scopeFor(Iterable<? extends EObject> elements, IScope outer) {
return scopeFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER), outer);
}
/**
* creates a scope using the passed function to compute the names and sets the passed scope as the parent scope
*/
public static <T extends EObject> IScope scopeFor(Iterable<? extends T> elements,
final Function<T, QualifiedName> nameComputation, IScope outer) {
return new SimpleScope(outer,scopedElementsFor(elements, nameComputation), true);
}
/**
* transforms an {@link Iterable} of {@link EObject}s into an {@link Iterable} of {@link IEObjectDescription}s computing
* the {@link EAttribute} 'name' to compute the {@link IEObjectDescription}'s name. If not existent the object is
* filtered out.
*/
public static Iterable<IEObjectDescription> scopedElementsFor(Iterable<? extends EObject> elements) {
return scopedElementsFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER));
}
/**
* transforms an {@link Iterable} of {@link EObject}s into an {@link Iterable} of {@link IEObjectDescription}s computing
* the name of the elements using the passed {@link Function} If the passed function returns null the object is
* filtered out.
*/
public static <T extends EObject> Iterable<IEObjectDescription> scopedElementsFor(Iterable<? extends T> elements,
final Function<T, QualifiedName> nameComputation) {
Iterable<IEObjectDescription> transformed = Iterables.transform(elements,
new Function<T, IEObjectDescription>() {
@Override
public IEObjectDescription apply(T from) {
final QualifiedName qualifiedName = nameComputation.apply(from);
if (qualifiedName != null)
return new EObjectDescription(qualifiedName, from, null);
return null;
}
});
return Iterables.filter(transformed, Predicates.notNull());
}
/**
* indexes the IEObject description using the given
*/
public static <T> Multimap<T,IEObjectDescription> index(Iterable<IEObjectDescription> descriptions, Function<IEObjectDescription,T> indexer) {
ArrayList<IEObjectDescription> list = Lists.newArrayList(descriptions);
LinkedHashMultimap<T, IEObjectDescription> multimap = LinkedHashMultimap.create(list.size(),1);
for (IEObjectDescription desc : list) {
multimap.put(indexer.apply(desc), desc);
}
return multimap;
}
/**
* indexes the IEObject description using the given
*/
public static Multimap<QualifiedName,IEObjectDescription> index(Iterable<IEObjectDescription> descriptions) {
return index(descriptions, new Function<IEObjectDescription, QualifiedName>() {
@Override
public QualifiedName apply(IEObjectDescription from) {
return from.getName().toLowerCase();
}
});
}
public static Iterable<IEObjectDescription> filterDuplicates(Iterable<IEObjectDescription> filtered) {
Map<QualifiedName, IEObjectDescription> result = Maps.newLinkedHashMap();
for (IEObjectDescription e : filtered) {
QualifiedName qualifiedName = e.getName();
if (result.containsKey(qualifiedName)) {
result.put(qualifiedName, null);
} else {
result.put(qualifiedName, e);
}
}
return Iterables.filter(result.values(), Predicates.notNull());
}
}
|
|
|
|
|
|
|
Re: Referenced DSL-Files are not recognized on clean [message #1838691 is a reply to message #1838569] |
Wed, 03 March 2021 11:37   |
Eclipse User |
|
|
|
After long debugging I found out, that Xtext/Eclipse did not resolve proxy-objects correctly. After resolving them by hand, everything worked.
Here is the altered code:
@Check
def checkNumberOfProcessArguments(Process p) {
var numberArgsGiven = 0
var numberArgsDefMin = 0
var numberArgsDefMax = 0
if (p.parameter !== null) {
numberArgsGiven = p.parameter.size;
}
if (p.process !== null) {
if (p.process.eIsProxy) { // resolve proxy
var XtextResourceSet rs = new XtextResourceSet();
rs.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, java.lang.Boolean.TRUE);
p.process = p.process.resolve(rs) as ProcessDefinition
}
numberArgsDefMax = p.process.parameter.size;
numberArgsDefMin = p.process.parameter.filter[defaultValue === null].size;
/* add all out-parameters also */
if (p.process.result !== null) {
numberArgsDefMax += p.process.result.results.size;
numberArgsDefMin += p.process.result.results.size;
}
}
if ((numberArgsGiven > numberArgsDefMax) || (numberArgsGiven < numberArgsDefMin)) {
if (numberArgsDefMax != numberArgsDefMin) {
error(
"Die Anzahl der Parameter muss zwischen " + numberArgsDefMin + " und " + numberArgsDefMax + " sein",
p, TabsPackage.eINSTANCE.process_Parameter, NUMBER_ARGS)
} else {
error("Die Anzahl der Parameter muss " + numberArgsDefMin + " sein",
p, TabsPackage.eINSTANCE.process_Parameter, NUMBER_ARGS)
}
}
}
|
|
|
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 1.24630 seconds