diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/TransformationErrorCode.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/TransformationErrorCode.java index 6b2d71af8..8a0970674 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/TransformationErrorCode.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/TransformationErrorCode.java @@ -23,6 +23,7 @@ public enum TransformationErrorCode { InvalidSupertype, InvalidFeature, InvalidFragmentOverride, + InvalidFragmentCall, InvalidRuleOverride; public String getFullyQualifiedCode() { diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java index ecabb93e8..a437c5d15 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java @@ -87,6 +87,7 @@ public class Xtext2EcoreInterpretationContext { if (terminal == null) { throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable, "Cannot derive type from incomplete assignment.", assignment); } + checkNoFragmentRuleCall(terminal); EClassifier type = getTerminalType(terminal); isContainment = isContainmentAssignment(assignment); featureTypeInfo = getEClassifierInfoOrThrowException(type, assignment); @@ -94,6 +95,17 @@ public class Xtext2EcoreInterpretationContext { addFeature(featureName, featureTypeInfo, isMultivalue, isContainment, assignment); } + private void checkNoFragmentRuleCall(AbstractElement terminal) throws TransformationException { + if (GrammarUtil.isEObjectFragmentRuleCall(terminal)) { + throw new TransformationException(TransformationErrorCode.InvalidFragmentCall, "Cannot call a fragment from an assignment", terminal); + } + if (terminal instanceof Alternatives) { + for(AbstractElement child: ((Alternatives) terminal).getElements()) { + checkNoFragmentRuleCall(child); + } + } + } + public boolean isContainmentAssignment(Assignment assignment) { // TODO throw TransformationException in case of unexpected terminal return new XtextSwitch() { diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformerTest.xtend b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformerTest.xtend index fd92a9b67..d1206eac0 100644 --- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformerTest.xtend +++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformerTest.xtend @@ -351,6 +351,32 @@ class Xtext2EcoreTransformerTest extends AbstractXtextTests { assertTrue(bottomType.superTypes.contains(middleType1)) assertTrue(bottomType.superTypes.contains(middleType2)) } + + @Test def void testParserRuleFragment_08() throws Exception { + val grammar = ''' + grammar test with org.eclipse.xtext.common.Terminals + generate test 'http://test' + RuleA: feature=Fragment; + fragment Fragment * Fragment: name=ID; + ''' + errorAcceptorMock.acceptError(TransformationErrorCode.InvalidFragmentCall, + TestErrorAcceptor.ANY_STRING, TestErrorAcceptor.ANY_EOBJECT) + var EPackage result = getEPackageFromGrammar(grammar, 2) + assertEquals(1, result.EClassifiers.size) + } + + @Test def void testParserRuleFragment_09() throws Exception { + val grammar = ''' + grammar test with org.eclipse.xtext.common.Terminals + generate test 'http://test' + RuleA: feature=(Fragment|Fragment); + fragment Fragment returns Fragment: name=ID; + ''' + errorAcceptorMock.acceptError(TransformationErrorCode.InvalidFragmentCall, + TestErrorAcceptor.ANY_STRING, TestErrorAcceptor.ANY_EOBJECT) + var EPackage result = getEPackageFromGrammar(grammar, 1) + assertEquals(2, result.EClassifiers.size) + } @Test def void testTypesOfImplicitSuperGrammar() throws Exception { val xtextGrammar = '''