Skip to content

Commit 432b02f

Browse files
committed
fix: tolerate an unresolvable grammar in export model generation
The sibling-grammar lookup in ExportGeneratorX.getGrammar demand-loads <name>.xtext next to the export model; for models with no such sibling (every test .export file, models built via ParseHelper) the load throws and the builder participant logs "Error during compilation" and silently aborts generation for the file — dozens of ERROR entries in every full test run, and the generator's main path never executes over the test fixtures. Make grammar resolution defensive: guard a missing resource or resource set, reject unresolved targetGrammar proxies, and catch the demand-load failure, returning null. Downstream, GeneratorUtil.allInstantiatedTypes treats a null grammar as "no parser-instantiated subtypes" (covering typeMap and canContain), and the remaining generator call sites already tolerate a null grammar (grammar?.name in ExportedNamesProviderGenerator; an explicit null check in ResourceDescriptionManagerGenerator). Export model generation now degrades gracefully instead of aborting. Phase 0 of #1458.
1 parent f3f4e1a commit 432b02f

3 files changed

Lines changed: 42 additions & 5 deletions

File tree

com.avaloq.tools.ddk.xtext.export.test/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorXTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@
1111
package com.avaloq.tools.ddk.xtext.export.generator;
1212

1313
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertNull;
1415

1516
import org.eclipse.emf.common.util.URI;
17+
import org.eclipse.emf.ecore.InternalEObject;
1618
import org.eclipse.emf.ecore.resource.Resource;
1719
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
20+
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
21+
import org.eclipse.xtext.Grammar;
22+
import org.eclipse.xtext.XtextFactory;
1823
import org.junit.jupiter.api.Test;
1924

2025
import com.avaloq.tools.ddk.xtext.export.export.ExportFactory;
@@ -32,6 +37,7 @@ public class ExportGeneratorXTest extends AbstractXtextTest {
3237
private static final String DERIVED_PACKAGE_PROVIDER = "com.avaloq.naming.fooExportedNamesProvider";
3338
private static final String PROJECT_FALLBACK_PROVIDER = "MyProject.naming.fooExportedNamesProvider";
3439
private static final String DEFAULT_FALLBACK_PROVIDER = "generated.naming.fooExportedNamesProvider";
40+
private static final String NO_SIBLING_URI = "platform:/resource/TEST/NoSibling.export";
3541

3642
private final ExportGeneratorX exportGeneratorX = getXtextTestUtil().get(ExportGeneratorX.class);
3743

@@ -71,6 +77,26 @@ public void testSingleSegmentUriFallsBackToDefaultPackage() {
7177
assertEquals(DEFAULT_FALLBACK_PROVIDER, exportedNamesProviderFor("foo.export"));
7278
}
7379

80+
@Test
81+
public void testGetGrammarReturnsNullWithoutResolvableGrammar() {
82+
final ExportModel detached = ExportFactory.eINSTANCE.createExportModel();
83+
assertNull(exportGeneratorX.getGrammar(detached), "model without a resource");
84+
85+
final ExportModel withoutResourceSet = ExportFactory.eINSTANCE.createExportModel();
86+
new ResourceImpl(URI.createURI(NO_SIBLING_URI)).getContents().add(withoutResourceSet);
87+
assertNull(exportGeneratorX.getGrammar(withoutResourceSet), "resource without a resource set");
88+
89+
final ExportModel withoutSibling = ExportFactory.eINSTANCE.createExportModel();
90+
final Resource resource = new ResourceSetImpl().createResource(URI.createURI(NO_SIBLING_URI));
91+
resource.getContents().add(withoutSibling);
92+
assertNull(exportGeneratorX.getGrammar(withoutSibling), "missing sibling grammar must not throw");
93+
94+
final Grammar proxy = XtextFactory.eINSTANCE.createGrammar();
95+
((InternalEObject) proxy).eSetProxyURI(URI.createURI("platform:/resource/TEST/Unresolved.xtext#/"));
96+
withoutSibling.setTargetGrammar(proxy);
97+
assertNull(exportGeneratorX.getGrammar(withoutSibling), "unresolved targetGrammar proxy");
98+
}
99+
74100
private String exportedNamesProviderFor(final String uri) {
75101
final Resource resource = new ResourceImpl(URI.createURI(uri));
76102
final ExportModel model = ExportFactory.eINSTANCE.createExportModel();

com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.xtend

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,22 @@ class ExportGeneratorX {
4747
}
4848

4949
def Grammar getGrammar(ExportModel model) {
50-
val uri = model.eResource.URI
5150
// Grammar should be set correctly for export extensions, not yet for normal export sources
52-
if(model.targetGrammar !== null) {
51+
if (model.targetGrammar !== null && !model.targetGrammar.eIsProxy) {
5352
return model.targetGrammar;
5453
}
55-
val grammarResource = model.eResource.resourceSet.getResource(uri.trimSegments(1).appendSegment(uri.trimFileExtension.lastSegment + '.xtext'), true)
56-
return grammarResource?.contents.head as Grammar
54+
val resource = model.eResource
55+
if (resource?.resourceSet === null) {
56+
return null
57+
}
58+
val uri = resource.URI
59+
try {
60+
val grammarResource = resource.resourceSet.getResource(uri.trimSegments(1).appendSegment(uri.trimFileExtension.lastSegment + '.xtext'), true)
61+
return grammarResource?.contents.head as Grammar
62+
} catch (RuntimeException e) {
63+
// no resolvable sibling grammar; all generators tolerate a null grammar
64+
return null
65+
}
5766
}
5867

5968
def String getExportedNamesProvider(ExportModel model) {

com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtil.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ protected GeneratorUtil() {
5555
*/
5656
public static Set<EClass> allInstantiatedTypes(final Grammar grammar) {
5757
Set<EClass> result = Sets.newLinkedHashSet();
58-
collectInstantiatedTypes(grammar, result);
58+
if (grammar != null) { // no grammar -> no parser-instantiated subtypes
59+
collectInstantiatedTypes(grammar, result);
60+
}
5961
return result;
6062
}
6163

0 commit comments

Comments
 (0)