mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 16:28:56 +00:00
Improved validation against imported ecore meta model (#1552)
closes #1551 Signed-off-by: Sebastian Zarnekow <sebastian.zarnekow@gmail.com>
This commit is contained in:
parent
6d7097ef24
commit
108ea555d7
10 changed files with 1832 additions and 98 deletions
|
@ -59,7 +59,7 @@ public class SerializationErrorTestLanguageSemanticSequencer extends AbstractDel
|
|||
* Indent returns Indent
|
||||
*
|
||||
* Constraint:
|
||||
* ((((req=TwoRequired opt=TwoOptions) | opt=TwoOptions)? indent+=Indent+) | indent+=Indent+)?
|
||||
* ((req=TwoRequired? opt=TwoOptions indent+=Indent+) | (req=TwoRequired? indent+=Indent+) | indent+=Indent+)?
|
||||
*/
|
||||
protected void sequence_Indent(ISerializationContext context, Indent semanticObject) {
|
||||
genericSequencer.createSequence(context, semanticObject);
|
||||
|
|
|
@ -2141,5 +2141,582 @@ class Xtext2EcoreTransformerTest extends AbstractXtextTests {
|
|||
"Cannot create datatype BAR. If this is supposed to return EString, make sure you have imported 'http://www.eclipse.org/emf/2002/Ecore'", TestErrorAcceptor.ANY_EOBJECT)
|
||||
getEPackageFromGrammar(grammar, 1)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_01() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA: ({ChildA} 'ChildA' | {ChildB} 'ChildB') aString=ID;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_02() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA: ({ChildA} 'ChildA' | {ChildB} 'ChildB' | {ChildC} 'ChildC') aString=ID;
|
||||
'''
|
||||
errorAcceptorMock.acceptError(TransformationErrorCode.CannotCreateTypeInSealedMetamodel,
|
||||
"Cannot find compatible feature aString in sealed EClass ChildC from imported package http://multiinheritancetest: The type 'ChildC' does not have a feature 'aString'.", TestErrorAcceptor.ANY_EOBJECT)
|
||||
getEPackagesFromGrammar(grammar, 1)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_03() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA: ({ChildA} 'ChildA' | {ChildB} 'ChildB')? aString=ID;
|
||||
'''
|
||||
errorAcceptorMock.acceptError(TransformationErrorCode.CannotCreateTypeInSealedMetamodel,
|
||||
"Cannot find compatible feature aString in sealed EClass ParentA from imported package http://multiinheritancetest: The type 'ParentA' does not have a feature 'aString'.", TestErrorAcceptor.ANY_EOBJECT)
|
||||
getEPackagesFromGrammar(grammar, 1)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_04() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' {ChildC.someContainment=current}
|
||||
| {ChildB} 'ChildB' {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_05() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
( {ChildA} 'ChildA' {ChildC.someContainment=current}
|
||||
| {ChildB} 'ChildB' {ChildC.someContainment=current}
|
||||
) {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_06() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
( {ChildA} 'ChildA' | {ChildB} 'ChildB' ) {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_07() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' {ChildC.someContainment=current} 'ChildC' {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_08() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' ({ChildC.someContainment=current} 'ChildC')+ {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_09() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' ({ChildC.someContainment=current} 'ChildC')? {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_10() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' {ChildB.someContainment=current} 'ChildB' aString=ID
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_11() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' ({ChildB.someContainment=current} 'ChildB')? aString=ID
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_12() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
( {ChildA} 'ChildA'
|
||||
| {ChildB} 'ChildB'
|
||||
| {ChildC} 'ChildC') parent=ChildA
|
||||
;
|
||||
ChildA: {ChildA} 'ChildA';
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_13() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildC} 'ChildC'
|
||||
( {ChildA.someContainment=current} 'ChildA'
|
||||
| {ChildB.someContainment=current} 'ChildB'
|
||||
) parent=ChildA
|
||||
;
|
||||
ChildA: {ChildA} 'ChildA';
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_14() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildC} 'ChildC'
|
||||
( {ChildA.someContainment=current} 'ChildA'
|
||||
| {ChildB.someContainment=current} 'ChildB'
|
||||
)* parent=ChildA
|
||||
;
|
||||
ChildA: {ChildA} 'ChildA';
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_15() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA: ({ChildA} 'ChildA' | {ChildB} 'ChildB') aString=ID;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_16() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA: ({ChildA} 'ChildA' | {ChildB} 'ChildB' | {ChildC} 'ChildC') aString=ID;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_17() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA: ({ChildA} 'ChildA' | {ChildB} 'ChildB')? aString=ID;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_18() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' {ChildC.someContainment=current}
|
||||
| {ChildB} 'ChildB' {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_19() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
( {ChildA} 'ChildA' {ChildC.someContainment=current}
|
||||
| {ChildB} 'ChildB' {ChildC.someContainment=current}
|
||||
) {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_20() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
( {ChildA} 'ChildA' | {ChildB} 'ChildB' ) {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_21() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' {ChildC.someContainment=current} 'ChildC' {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_22() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' ({ChildC.someContainment=current} 'ChildC')+ {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_23() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' ({ChildC.someContainment=current} 'ChildC')? {ChildC.someContainment=current}
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_24() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' {ChildB.someContainment=current} 'ChildB' aString=ID
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_25() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildA} 'ChildA' ({ChildB.someContainment=current} 'ChildB')? aString=ID
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_26() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
( {ChildA} 'ChildA'
|
||||
| {ChildB} 'ChildB'
|
||||
| {ChildC} 'ChildC') parent=ChildA
|
||||
;
|
||||
ChildA: {ChildA} 'ChildA';
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_27() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildC} 'ChildC'
|
||||
( {ChildA.someContainment=current} 'ChildA'
|
||||
| {ChildB.someContainment=current} 'ChildB'
|
||||
) parent=ChildA
|
||||
;
|
||||
ChildA: {ChildA} 'ChildA';
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testTypeAfterAction_28() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
SomeChild returns ParentA:
|
||||
{ChildC} 'ChildC'
|
||||
( {ChildA.someContainment=current} 'ChildA'
|
||||
| {ChildB.someContainment=current} 'ChildB'
|
||||
)* parent=ChildA
|
||||
;
|
||||
ChildA: {ChildA} 'ChildA';
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
|
||||
@Test def void testAssignObjectAlternative_01() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
import 'classpath:/org/eclipse/xtext/xtext/ecoreInference/multiinheritancetest.ecore'
|
||||
|
||||
ChildA_ returns ChildA:
|
||||
someContainment=(ChildA|ChildB)
|
||||
;
|
||||
ChildA: {ChildA} 'ChildA';
|
||||
ChildB: {ChildB} 'ChildB';
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
@Test def void testAssignObjectAlternative_02() throws Exception {
|
||||
var String grammar = '''
|
||||
grammar test with org.eclipse.xtext.common.Terminals
|
||||
generate multiinheritancetest 'multiinheritancetest'
|
||||
|
||||
DeclParentA returns ParentA:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentA} attributeInParentA=ID;
|
||||
DeclParentB returns ParentB:
|
||||
DeclChildA | DeclChildB | DeclChildC | {ParentB} someContainment=DeclParentA;
|
||||
DeclChildA returns ChildA:
|
||||
aString=ID parent=DeclParentA;
|
||||
DeclChildB returns ChildB:
|
||||
aString=ID parent=DeclParentB;
|
||||
DeclChildC returns ChildC:
|
||||
parent=DeclChildA;
|
||||
|
||||
|
||||
ChildA:
|
||||
someContainment=(DeclChildA|DeclChildB)
|
||||
;
|
||||
'''
|
||||
val resource = getResourceFromString(grammar)
|
||||
assertTrue(resource.errors.isEmpty)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="multiinheritancetest" nsURI="http://multiinheritancetest" nsPrefix="multiinheritancetest">
|
||||
<eClassifiers xsi:type="ecore:EClass" name="ParentA">
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="attributeInParentA" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="ParentB">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="someContainment" eType="#//ParentA"
|
||||
containment="true"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="ChildA" eSuperTypes="#//ParentA #//ParentB">
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="aString" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="parent" eType="#//ParentA"
|
||||
containment="true"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="ChildB" eSuperTypes="#//ParentA #//ParentB">
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="aString" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="parent" eType="#//ParentB"
|
||||
containment="true"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="ChildC" eSuperTypes="#//ParentA #//ParentB">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="parent" eType="#//ChildA"
|
||||
containment="true"/>
|
||||
</eClassifiers>
|
||||
</ecore:EPackage>
|
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,10 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.ecoreInference;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
|
@ -33,6 +36,9 @@ import org.eclipse.xtext.GrammarUtil;
|
|||
import org.eclipse.xtext.util.ReflectionUtil;
|
||||
import org.eclipse.xtext.util.Strings;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* @author Jan Köhnlein - Initial contribution and API
|
||||
* @author Heiko Behrens
|
||||
|
@ -70,7 +76,7 @@ public abstract class EClassifierInfo {
|
|||
|
||||
public abstract boolean addSupertype(EClassifierInfo superTypeInfo);
|
||||
|
||||
public abstract boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue,
|
||||
public abstract boolean addFeature(String featureName, EClassifierInfoAccess featureTypeInfo, boolean isMultivalue,
|
||||
boolean isContainment, AbstractElement parserElement) throws TransformationException;
|
||||
|
||||
public static class EClassInfo extends EClassifierInfo {
|
||||
|
@ -156,10 +162,11 @@ public abstract class EClassifierInfo {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue,
|
||||
public boolean addFeature(String featureName, EClassifierInfoAccess featureTypeInfo, boolean isMultivalue,
|
||||
boolean isContainment, AbstractElement parserElement) throws TransformationException {
|
||||
EClassifier featureClassifier = featureType.getEClassifier();
|
||||
return addFeature(featureName, featureClassifier, isMultivalue, isContainment, parserElement);
|
||||
ImmutableList<EClassifier> featureClassifiers = FluentIterable.from(featureTypeInfo.getCurrentTypes()).transform(EClassifierInfo::getEClassifier).toList();
|
||||
EClassifier compatibleType = featureTypeInfo.getCurrentCompatibleType().getEClassifier();
|
||||
return addFeature(featureName, featureClassifiers, compatibleType, isMultivalue, isContainment, parserElement);
|
||||
}
|
||||
|
||||
public boolean addFeature(EStructuralFeature prototype) {
|
||||
|
@ -169,7 +176,7 @@ public abstract class EClassifierInfo {
|
|||
EReference reference = (EReference) prototype;
|
||||
isContainment = reference.isContainment();
|
||||
}
|
||||
boolean result = addFeature(prototype.getName(), prototype.getEType(), prototype.isMany(), isContainment, null);
|
||||
boolean result = addFeature(prototype.getName(), Arrays.asList(prototype.getEType()), prototype.getEType(), prototype.isMany(), isContainment, null);
|
||||
if (result) {
|
||||
EStructuralFeature newFeature = getEClass().getEStructuralFeature(prototype.getName());
|
||||
SourceAdapter oldAdapter = SourceAdapter.find(prototype);
|
||||
|
@ -279,7 +286,7 @@ public abstract class EClassifierInfo {
|
|||
&& left.getEPackage().getNsURI().equals(right.getEPackage().getNsURI())) {
|
||||
return true;
|
||||
}
|
||||
// Check all supertypes of the right class
|
||||
// Check all super-types of the right class
|
||||
for (EClass superClass : right.getEAllSuperTypes()) {
|
||||
if (left.getClassifierID() == superClass.getClassifierID()
|
||||
&& superClass.getEPackage() != null
|
||||
|
@ -299,14 +306,26 @@ public abstract class EClassifierInfo {
|
|||
return result;
|
||||
}
|
||||
|
||||
public boolean isFeatureSemanticallyEqualTo(EStructuralFeature f1, EStructuralFeature f2) {
|
||||
private boolean isFeatureSemanticallyEqualTo(EStructuralFeature f1, EStructuralFeature f2, Set<EClassifier> f2Types) {
|
||||
if (f1 == f2) {
|
||||
return true;
|
||||
}
|
||||
boolean result = isFeatureSemanticallyEqualApartFromType(f1, f2);
|
||||
if (f1 instanceof EReference && f2 instanceof EReference) {
|
||||
EClass f1Type = (EClass) f1.getEType();
|
||||
EClass f2Type = (EClass) f2.getEType();
|
||||
result &= f1Type.isSuperTypeOf(f2Type);
|
||||
EClass f1Type = ((EReference)f1).getEReferenceType();
|
||||
result &= ((EReference) f1).isContainment() == ((EReference) f2).isContainment();
|
||||
result &= ((EReference) f1).isContainer() == ((EReference) f2).isContainer();
|
||||
if (result) {
|
||||
for(EClassifier f2Type: f2Types) {
|
||||
if (f2Type instanceof EClass) {
|
||||
if (!f1Type.isSuperTypeOf((EClass) f2Type)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result &= f1.getEType().equals(EcoreUtil2.getCompatibleType(f1.getEType(), f2.getEType()));
|
||||
}
|
||||
|
@ -327,32 +346,47 @@ public abstract class EClassifierInfo {
|
|||
}
|
||||
|
||||
public FindResult containsSemanticallyEqualFeature(EStructuralFeature feature) {
|
||||
return containsSemanticallyEqualFeature(getEClass().getEAllStructuralFeatures(), feature);
|
||||
return containsSemanticallyEqualFeature(feature, Collections.singleton(feature.getEType()));
|
||||
}
|
||||
|
||||
public FindResult containsSemanticallyEqualFeature(EStructuralFeature feature, Set<EClassifier> toBeAssignedTypes) {
|
||||
return containsSemanticallyEqualFeature(getEClass().getEAllStructuralFeatures(), feature, toBeAssignedTypes);
|
||||
}
|
||||
|
||||
public FindResult containsSemanticallyEqualFeature(Collection<EStructuralFeature> features,
|
||||
EStructuralFeature feature) {
|
||||
return containsSemanticallyEqualFeature(features, feature, Collections.singleton(feature.getEType()));
|
||||
}
|
||||
|
||||
public FindResult containsSemanticallyEqualFeature(Collection<EStructuralFeature> features,
|
||||
EStructuralFeature feature, Set<EClassifier> toBeAssignedTypes) {
|
||||
EStructuralFeature potentiallyEqualFeature = findFeatureByName(features, feature.getName());
|
||||
if (potentiallyEqualFeature == null)
|
||||
return FindResult.FeatureDoesNotExist;
|
||||
else if (isFeatureSemanticallyEqualTo(potentiallyEqualFeature, feature))
|
||||
else if (isFeatureSemanticallyEqualTo(potentiallyEqualFeature, feature, toBeAssignedTypes))
|
||||
return FindResult.FeatureExists;
|
||||
else
|
||||
return FindResult.DifferentFeatureWithSameNameExists;
|
||||
}
|
||||
|
||||
private boolean addFeature(String featureName, EClassifier featureClassifier, boolean isMultivalue,
|
||||
private boolean addFeature(
|
||||
String featureName,
|
||||
List<EClassifier> featureTypes,
|
||||
EClassifier compatibleSuperType,
|
||||
boolean isMultivalue,
|
||||
boolean isContainment, AbstractElement grammarElement) throws TransformationException {
|
||||
if (!isGenerated()) {
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
if (!containsCompatibleFeature(featureName, isMultivalue, isContainment, featureClassifier, errorMessage)) {
|
||||
throw new TransformationException(TransformationErrorCode.CannotCreateTypeInSealedMetamodel,
|
||||
"Cannot find compatible feature "+featureName+" in sealed EClass "+getEClass().getName()+" from imported package "+getEClass().getEPackage().getNsURI()+": " + errorMessage.toString(),
|
||||
grammarElement);
|
||||
for(EClassifier featureType: featureTypes) {
|
||||
if (!containsCompatibleFeature(featureName, isMultivalue, isContainment, featureType, errorMessage)) {
|
||||
throw new TransformationException(TransformationErrorCode.CannotCreateTypeInSealedMetamodel,
|
||||
"Cannot find compatible feature "+featureName+" in sealed EClass "+getEClass().getName()+" from imported package "+getEClass().getEPackage().getNsURI()+": " + errorMessage.toString(),
|
||||
grammarElement);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EStructuralFeature newFeature = createFeatureWith(featureName, featureClassifier, isMultivalue,
|
||||
EStructuralFeature newFeature = createFeatureWith(featureName, compatibleSuperType, isMultivalue,
|
||||
isContainment);
|
||||
|
||||
FindResult containsSemanticallyEqualFeature = containsSemanticallyEqualFeature(newFeature);
|
||||
|
@ -443,7 +477,7 @@ public abstract class EClassifierInfo {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue,
|
||||
public boolean addFeature(String featureName, EClassifierInfoAccess featureType, boolean isMultivalue,
|
||||
boolean isContainment, AbstractElement parserElement) throws TransformationException {
|
||||
throw new UnsupportedOperationException("Cannot add feature " + featureName + " to simple datatype "
|
||||
+ Strings.emptyIfNull(this.getEClassifier().getName()));
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2020 Sebastian Zarnekow and others.
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.ecoreInference;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Encapsulates the access to the type information during the static analysis of Xtext grammar rules.
|
||||
*
|
||||
* @since 2.23
|
||||
*/
|
||||
interface EClassifierInfoAccess {
|
||||
|
||||
/**
|
||||
* The most specific single super type of all known potential types.
|
||||
*/
|
||||
EClassifierInfo getCurrentCompatibleType();
|
||||
|
||||
/**
|
||||
* All types that have be used to instantiate the current object or all the types
|
||||
* that are the outcome of a grammar alternative.
|
||||
*/
|
||||
default Collection<EClassifierInfo> getCurrentTypes() {
|
||||
EClassifierInfo currentCompatibleType = getCurrentCompatibleType();
|
||||
if (currentCompatibleType == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.asList(currentCompatibleType);
|
||||
}
|
||||
|
||||
}
|
|
@ -34,7 +34,6 @@ import org.eclipse.xtext.xtext.ecoreInference.EClassifierInfo.EClassInfo;
|
|||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* A possible extension would be to normalize the type hierarchy and remove
|
||||
|
@ -165,22 +164,10 @@ public class EClassifierInfos {
|
|||
while (i.hasNext())
|
||||
result = getCompatibleType(result, i.next());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public EClassifier getCompatibleTypeNameOf(Collection<EClassifier> classifiers, boolean useParent) {
|
||||
final Collection<EClassifierInfo> types = Sets.newLinkedHashSet();
|
||||
for (EClassifier classifier : classifiers) {
|
||||
final EClassifierInfo info = getInfoOrNull(classifier);
|
||||
if (info == null)
|
||||
return null;
|
||||
types.add(info);
|
||||
if (result == null) {
|
||||
return getInfoOrNull(GrammarUtil.findEObject(grammar));
|
||||
}
|
||||
|
||||
final EClassifierInfo compatibleType = getCompatibleTypeOf(types);
|
||||
if (compatibleType != null)
|
||||
return compatibleType.getEClassifier();
|
||||
return GrammarUtil.findEObject(grammar);
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<EClassInfo> getAllEClassInfos() {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.ecoreInference;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EClassifier;
|
||||
|
@ -32,7 +33,7 @@ import com.google.common.collect.Sets;
|
|||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
*/
|
||||
final class ElementTypeCalculator extends XtextSwitch<EClassifier> implements Function<AbstractElement, EClassifier>{
|
||||
final class ElementTypeCalculator extends XtextSwitch<Set<EClassifier>> implements Function<AbstractElement, Set<EClassifier>>{
|
||||
|
||||
private final EClassifierInfos classifierInfos;
|
||||
|
||||
|
@ -41,16 +42,16 @@ final class ElementTypeCalculator extends XtextSwitch<EClassifier> implements Fu
|
|||
}
|
||||
|
||||
@Override
|
||||
public EClassifier caseKeyword(Keyword object) {
|
||||
public Set<EClassifier> caseKeyword(Keyword object) {
|
||||
EDataType eString = GrammarUtil.findEString(GrammarUtil.getGrammar(object));
|
||||
if (eString != null)
|
||||
return eString;
|
||||
return Collections.singleton(eString);
|
||||
// nowhere imported - use the instance from the registry
|
||||
return EcorePackage.Literals.ESTRING;
|
||||
return Collections.singleton(EcorePackage.Literals.ESTRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EClassifier caseTypeRef(TypeRef object) {
|
||||
public Set<EClassifier> caseTypeRef(TypeRef object) {
|
||||
if (object.getClassifier() == null) {
|
||||
if (object.getMetamodel() == null || object.getMetamodel().getEPackage() == null)
|
||||
return null;
|
||||
|
@ -61,18 +62,18 @@ final class ElementTypeCalculator extends XtextSwitch<EClassifier> implements Fu
|
|||
if (info != null)
|
||||
object.setClassifier(info.getEClassifier());
|
||||
}
|
||||
return object.getClassifier();
|
||||
return Collections.singleton(object.getClassifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EClassifier caseAbstractRule(AbstractRule object) {
|
||||
public Set<EClassifier> caseAbstractRule(AbstractRule object) {
|
||||
if (object.getType() != null)
|
||||
return doSwitch(object.getType());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EClassifier caseCompoundElement(CompoundElement object) {
|
||||
public Set<EClassifier> caseCompoundElement(CompoundElement object) {
|
||||
// since we do not allow unassigned rule calls and
|
||||
// actions, it is safe to use the same logic for
|
||||
// unordered groups as for groups
|
||||
|
@ -82,31 +83,27 @@ final class ElementTypeCalculator extends XtextSwitch<EClassifier> implements Fu
|
|||
}
|
||||
|
||||
@Override
|
||||
public EClassifier caseRuleCall(RuleCall ruleCall) {
|
||||
public Set<EClassifier> caseRuleCall(RuleCall ruleCall) {
|
||||
if (ruleCall.getRule() != null)
|
||||
return doSwitch(ruleCall.getRule());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EClassifier caseAlternatives(Alternatives object) {
|
||||
final Set<EClassifier> types = Sets.newLinkedHashSet();
|
||||
public Set<EClassifier> caseAlternatives(Alternatives object) {
|
||||
Set<EClassifier> types = Sets.newLinkedHashSet();
|
||||
for (AbstractElement group : object.getElements())
|
||||
types.add(doSwitch(group));
|
||||
try {
|
||||
return classifierInfos.getCompatibleTypeNameOf(types, true);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
types.addAll(doSwitch(group));
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EClassifier caseCrossReference(CrossReference object) {
|
||||
public Set<EClassifier> caseCrossReference(CrossReference object) {
|
||||
return doSwitch(object.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EClassifier apply(AbstractElement param) {
|
||||
public Set<EClassifier> apply(AbstractElement param) {
|
||||
return doSwitch(param);
|
||||
}
|
||||
}
|
|
@ -9,8 +9,10 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.ecoreInference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EClassifier;
|
||||
import org.eclipse.emf.ecore.EDataType;
|
||||
|
@ -32,14 +34,16 @@ import com.google.common.collect.Sets;
|
|||
* <a href="https://www.eclipse.org/Xtext/documentation/301_grammarlanguage.html#metamodel-inference">documentation</a>
|
||||
* for details.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @author Heiko Behrens - Initial contribution and API
|
||||
* @author Sebastian Zarnekow
|
||||
*/
|
||||
public class Xtext2EcoreInterpretationContext {
|
||||
public class Xtext2EcoreInterpretationContext implements EClassifierInfoAccess {
|
||||
|
||||
private final EClassifierInfos eClassifierInfos;
|
||||
|
||||
private final Function<AbstractElement, EClassifier> classifierCalculator;
|
||||
private final Function<AbstractElement, Set<EClassifier>> classifierCalculator;
|
||||
|
||||
private final Collection<EClassifierInfo> currentTypes = Sets.newLinkedHashSet();
|
||||
|
||||
|
@ -76,12 +80,13 @@ public class Xtext2EcoreInterpretationContext {
|
|||
final String featureName = assignment.getFeature();
|
||||
boolean isMultivalue = GrammarUtil.isMultipleAssignment(assignment);
|
||||
boolean isContainment = true;
|
||||
EClassifierInfo featureTypeInfo;
|
||||
EClassifierInfoAccess featureTypeInfo;
|
||||
|
||||
if (GrammarUtil.isBooleanAssignment(assignment)) {
|
||||
checkNoFragmentRuleCall(assignment.getTerminal());
|
||||
EDataType eBoolean = GrammarUtil.findEBoolean(GrammarUtil.getGrammar(assignment));
|
||||
featureTypeInfo = getEClassifierInfoOrThrowException(eBoolean, assignment);
|
||||
EClassifierInfo classifierInfo = getEClassifierInfoOrThrowException(eBoolean, assignment);
|
||||
featureTypeInfo = ()->classifierInfo;
|
||||
isMultivalue = false;
|
||||
}
|
||||
else {
|
||||
|
@ -90,13 +95,30 @@ public class Xtext2EcoreInterpretationContext {
|
|||
throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable, "Cannot derive type from incomplete assignment.", assignment);
|
||||
}
|
||||
checkNoFragmentRuleCall(terminal);
|
||||
EClassifier type = getTerminalType(terminal);
|
||||
List<EClassifierInfo> classifierInfos = new ArrayList<>();
|
||||
for(EClassifier type: getTerminalTypes(terminal)) {
|
||||
classifierInfos.add(getEClassifierInfoOrThrowException(type, assignment));
|
||||
}
|
||||
isContainment = isContainmentAssignment(assignment);
|
||||
featureTypeInfo = getEClassifierInfoOrThrowException(type, assignment);
|
||||
featureTypeInfo = new EClassifierInfoAccess() {
|
||||
|
||||
@Override
|
||||
public Collection<EClassifierInfo> getCurrentTypes() {
|
||||
return classifierInfos;
|
||||
}
|
||||
@Override
|
||||
public EClassifierInfo getCurrentCompatibleType() {
|
||||
try {
|
||||
return eClassifierInfos.getCompatibleTypeOf(classifierInfos);
|
||||
} catch(IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
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);
|
||||
|
@ -133,14 +155,14 @@ public class Xtext2EcoreInterpretationContext {
|
|||
}.doSwitch(assignment.getTerminal());
|
||||
}
|
||||
|
||||
public void addFeature(String featureName, EClassifierInfo featureTypeInfo, boolean isMultivalue,
|
||||
public void addFeature(String featureName, EClassifierInfoAccess featureTypeInfo, boolean isMultivalue,
|
||||
boolean isContainment, AbstractElement parserElement) throws TransformationException {
|
||||
for (EClassifierInfo type : currentTypes)
|
||||
type.addFeature(featureName, featureTypeInfo, isMultivalue, isContainment, parserElement);
|
||||
}
|
||||
|
||||
private EClassifier getTerminalType(AbstractElement terminal) throws TransformationException {
|
||||
final EClassifier result = classifierCalculator.apply(terminal);
|
||||
private Set<EClassifier> getTerminalTypes(AbstractElement terminal) throws TransformationException {
|
||||
Set<EClassifier> result = classifierCalculator.apply(terminal);
|
||||
if (result == null) {
|
||||
final ICompositeNode node = NodeModelUtils.getNode(terminal);
|
||||
if (node != null) {
|
||||
|
@ -190,8 +212,16 @@ public class Xtext2EcoreInterpretationContext {
|
|||
return result;
|
||||
}
|
||||
|
||||
public Collection<EClassifierInfo> getCurrentTypes() {
|
||||
return currentTypes;
|
||||
}
|
||||
|
||||
public EClassifierInfo getCurrentCompatibleType() {
|
||||
return eClassifierInfos.getCompatibleTypeOf(currentTypes);
|
||||
try {
|
||||
return eClassifierInfos.getCompatibleTypeOf(currentTypes);
|
||||
} catch(IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Xtext2EcoreInterpretationContext spawnContextWithReferencedType(EClassifierInfo referencedType, EObject parserElement) {
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.eclipse.xtext.xtext.GrammarResource;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
@ -117,27 +118,25 @@ public class Xtext2EcoreTransformer {
|
|||
}
|
||||
|
||||
public List<EPackage> getGeneratedPackages() {
|
||||
final List<EPackage> result = new ArrayList<EPackage>();
|
||||
final ResourceSet resourceSet = grammar.eResource().getResourceSet();
|
||||
ResourceSet resourceSet = grammar.eResource().getResourceSet();
|
||||
if (resourceSet == null)
|
||||
throw new NullPointerException("resourceSet may not be null");
|
||||
Iterables.addAll(result, Iterables.filter(Iterables.transform(
|
||||
Iterables.filter(grammar.getMetamodelDeclarations(), GeneratedMetamodel.class),
|
||||
new Function<AbstractMetamodelDeclaration, EPackage>() {
|
||||
@Override
|
||||
public EPackage apply(AbstractMetamodelDeclaration param) {
|
||||
EPackage pack = (EPackage) param.eGet(XtextPackage.Literals.ABSTRACT_METAMODEL_DECLARATION__EPACKAGE, false);
|
||||
if (pack != null && !pack.eIsProxy()) {
|
||||
return pack;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}), Predicates.notNull()));
|
||||
return getPackagesSortedByName(result);
|
||||
|
||||
return FluentIterable.from(grammar.getMetamodelDeclarations())
|
||||
.filter(GeneratedMetamodel.class)
|
||||
.transform(mm->{
|
||||
EPackage pack = (EPackage) mm.eGet(XtextPackage.Literals.ABSTRACT_METAMODEL_DECLARATION__EPACKAGE, false);
|
||||
if (pack != null && !pack.eIsProxy()) {
|
||||
return pack;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Predicates.notNull())
|
||||
.toSortedList(Comparator.comparing(EPackage::getName));
|
||||
}
|
||||
|
||||
/*
|
||||
* pre-conditions - ensure non-duplicate aliases - ensure all aliases have matching metamodel declarations
|
||||
* preconditions - ensure non-duplicate aliases - ensure all aliases have matching metamodel declarations
|
||||
*/
|
||||
public void transform() {
|
||||
eClassifierInfos = new EClassifierInfos(grammar);
|
||||
|
@ -187,17 +186,6 @@ public class Xtext2EcoreTransformer {
|
|||
}
|
||||
}
|
||||
|
||||
private static List<EPackage> getPackagesSortedByName(Collection<EPackage> packages) {
|
||||
final ArrayList<EPackage> result = new ArrayList<EPackage>(packages);
|
||||
Collections.sort(result, new Comparator<EPackage>() {
|
||||
@Override
|
||||
public int compare(EPackage o1, EPackage o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean deriveTypes() {
|
||||
return deriveTypesImpl() && checkDatatypeRules() && deriveTypeHierarchy();
|
||||
}
|
||||
|
@ -496,11 +484,9 @@ public class Xtext2EcoreTransformer {
|
|||
try {
|
||||
TypeRef actionTypeRef = object.getType();
|
||||
EClassifierInfo actionType = findOrCreateEClassifierInfo(actionTypeRef, null, true);
|
||||
EClassifierInfo currentCompatibleType = context.getCurrentCompatibleType();
|
||||
Xtext2EcoreInterpretationContext ctx = context.spawnContextWithReferencedType(actionType, object);
|
||||
if (object.getFeature() != null) {
|
||||
ctx.addFeature(object.getFeature(), currentCompatibleType,
|
||||
GrammarUtil.isMultipleAssignment(object), true, object);
|
||||
ctx.addFeature(object.getFeature(), context, GrammarUtil.isMultipleAssignment(object), true, object);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
@ -982,7 +968,7 @@ public class Xtext2EcoreTransformer {
|
|||
"Cannot find EPackage for type '" + typeRef.getClassifier().getName() + "'", typeRef);
|
||||
EClassifierInfo info = eClassifierInfos.getInfo(typeRef);
|
||||
if (info == null) {
|
||||
// we assumend EString for terminal rules and datatype rules, so
|
||||
// we assumed EString for terminal rules and data-type rules, so
|
||||
// we have to do a look up in super grammar
|
||||
EDataType dataType = GrammarUtil.findEString(GrammarUtil.getGrammar(typeRef));
|
||||
if (dataType != null && typeRef.getClassifier() == dataType) {
|
||||
|
@ -1039,7 +1025,7 @@ public class Xtext2EcoreTransformer {
|
|||
EClassifierInfo result;
|
||||
if (classifier instanceof EClass)
|
||||
result = EClassifierInfo.createEClassInfo((EClass) classifier, true, getGeneratedEPackageURIs(), GrammarUtil.getGrammar(typeRef));
|
||||
else // datatype or enum
|
||||
else // data-type or enum
|
||||
result = EClassifierInfo.createEDataTypeInfo((EDataType) classifier, true);
|
||||
|
||||
if (!eClassifierInfos.addInfo(typeRef, result))
|
||||
|
|
Loading…
Reference in a new issue