Skip to content

Commit

Permalink
Merge 1c99100 into ce7884e
Browse files Browse the repository at this point in the history
  • Loading branch information
LorenzoBettini committed Jun 27, 2020
2 parents ce7884e + 1c99100 commit b342cf4
Show file tree
Hide file tree
Showing 24 changed files with 846 additions and 54 deletions.
@@ -0,0 +1,41 @@
package edelta;

import edelta.lib.AbstractEdelta;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;

@SuppressWarnings("all")
public class ExampleAccessNotYetExistingElements extends AbstractEdelta {
public ExampleAccessNotYetExistingElements() {

}

public ExampleAccessNotYetExistingElements(final AbstractEdelta other) {
super(other);
}

public void creation(final EPackage it) {
this.lib.addNewEClass(it, "NewClass");
EList<EClass> _eSuperTypes = getEClass("myecore", "NewClass").getESuperTypes();
_eSuperTypes.add(getEClass("myecore", "MyEClass"));
}

public void anotherCreation(final EPackage it) {
this.lib.addNewEClass(it, "AnotherNewClass");
EList<EClass> _eSuperTypes = getEClass("myecore", "AnotherNewClass").getESuperTypes();
_eSuperTypes.add(getEClass("myecore", "MyEClass"));
}

@Override
public void performSanityChecks() throws Exception {
ensureEPackageIsLoaded("ecore");
ensureEPackageIsLoaded("myecore");
}

@Override
protected void doExecute() throws Exception {
creation(getEPackage("myecore"));
anotherCreation(getEPackage("myecore"));
}
}
@@ -0,0 +1,22 @@


// IMPORTANT: ecores must be in source directories
// otherwise you can't refer to them
metamodel "ecore"
metamodel "myecore"

modifyEcore creation epackage myecore {
// uncomment to see the error: Element not yet available in this context: myecore.NewClass
// not that you can still navigate to the creation expression

// ecoreref(NewClass).abstract = true
// ecoreref(AnotherNewClass).abstract = true

addNewEClass("NewClass")
ecoreref(NewClass).ESuperTypes += ecoreref(MyEClass)
}

modifyEcore anotherCreation epackage myecore {
addNewEClass("AnotherNewClass")
ecoreref(AnotherNewClass).ESuperTypes += ecoreref(MyEClass)
}
Expand Up @@ -1458,6 +1458,39 @@ class EdeltaInterpreterTest extends EdeltaAbstractTest {
]
}
@Test
def void testAccessToNotYetExistingElement() {
val input =
'''
metamodel "foo"

modifyEcore aTest epackage foo {
ecoreref(ANewClass) // doesn't exist yet
ecoreref(NonExisting) // doesn't exist at all
addNewEClass("ANewClass")
ecoreref(ANewClass) // this is OK
}
'''
input
.parseWithTestEcore => [
interpretProgram
val ecoreref1 = allEcoreReferenceExpressions.get(0).reference
val ecoreref2 = allEcoreReferenceExpressions.get(1).reference
val unresolved = derivedStateHelper.getUnresolvedEcoreReferences(eResource)
assertThat(unresolved)
.containsOnly(ecoreref1, ecoreref2)
// also check what's resolved in the end
assertThat(ecoreref1.enamedelement.eIsProxy).isFalse
assertThat(ecoreref2.enamedelement.eIsProxy).isTrue
val map = derivedStateHelper.getEnamedElementXExpressionMap(eResource)
// we can access the expression that created the element
// that is not available in the current context
assertThat(map.get(ecoreref1.enamedelement))
.isNotNull
.isSameAs(lastModifyEcoreOperation.body.block.expressions.get(2))
]
}

def private assertAfterInterpretationOfEdeltaModifyEcoreOperation(
CharSequence input, (EPackage)=>void testExecutor
) {
Expand Down
Expand Up @@ -9,6 +9,7 @@ import org.junit.runner.RunWith
import static edelta.util.EdeltaModelUtil.*
import static org.assertj.core.api.Assertions.assertThat
import static org.junit.Assert.*
import org.eclipse.xtext.xbase.XIfExpression

@RunWith(XtextRunner)
@InjectWith(EdeltaInjectorProviderCustom)
Expand Down Expand Up @@ -138,4 +139,39 @@ class EdeltaModelUtilTest extends EdeltaAbstractTest {
assertThat(hasCycleInHierarchy(c2)).isTrue
assertThat(hasCycleInHierarchy(c1)).isTrue
}

@Test
def void testGetContainingBlockXExpression() {
val input = '''
metamodel "foo"
modifyEcore aTest epackage foo {
ecoreref(FooClass) // 0
ecoreref(FooClass).abstract = true // 1
ecoreref(FooClass).ESuperTypes += null // 2
if (true) {
ecoreref(FooClass).ESuperTypes += null // 3
}
}
'''
input.parseWithTestEcore => [
val mainBlock = lastModifyEcoreOperation.body.block
val ecoreRefs = allEcoreReferenceExpressions.map[reference]
var ecoreRef = ecoreRefs.get(0)
assertThat(getContainingBlockXExpression(ecoreRef))
.isSameAs(ecoreRef.eContainer)
ecoreRef = ecoreRefs.get(1)
assertThat(getContainingBlockXExpression(ecoreRef))
.isSameAs(mainBlock.expressions.get(1))
ecoreRef = ecoreRefs.get(2)
assertThat(getContainingBlockXExpression(ecoreRef))
.isSameAs(mainBlock.expressions.get(2))
ecoreRef = ecoreRefs.get(3)
assertThat(getContainingBlockXExpression(ecoreRef))
.isSameAs(
(mainBlock.expressions.get(3) as XIfExpression)
.then.block.expressions.head
)
]
}
}
115 changes: 114 additions & 1 deletion edelta.parent/edelta.tests/src/edelta/tests/EdeltaValidatorTest.xtend
Expand Up @@ -7,11 +7,11 @@ import edelta.validation.EdeltaValidator
import org.eclipse.xtext.diagnostics.Diagnostic
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.XtextRunner
import org.eclipse.xtext.xbase.validation.IssueCodes
import org.junit.Test
import org.junit.runner.RunWith

import static edelta.edelta.EdeltaPackage.Literals.*
import org.eclipse.xtext.xbase.validation.IssueCodes

@RunWith(XtextRunner)
@InjectWith(EdeltaInjectorProviderCustom)
Expand Down Expand Up @@ -440,4 +440,117 @@ class EdeltaValidatorTest extends EdeltaAbstractTest {
.assertNoErrors
}

@Test
def void testAccessToNotYetExistingElement() {
val input =
'''
metamodel "foo"
modifyEcore aTest epackage foo {
ecoreref(ANewClass) // doesn't exist yet
ecoreref(NonExisting) // doesn't exist at all
addNewEClass("ANewClass")
ecoreref(ANewClass) // this is OK
}
'''
input
.parseWithTestEcore => [
assertError(
EDELTA_ECORE_DIRECT_REFERENCE,
EdeltaValidator.INTERPRETER_ACCESS_NOT_YET_EXISTING_ELEMENT,
input.indexOf("ANewClass"),
"ANewClass".length,
"Element not yet available in this context: foo.ANewClass"
)
assertErrorsAsStrings(
'''
Element not yet available in this context: foo.ANewClass
NonExisting cannot be resolved.
'''
)
]
}
@Test
def void testAccessToNotYetExistingElementInComplexExpression() {
val input =
'''
metamodel "foo"

modifyEcore aTest epackage foo {
// doesn't exist yet
ecoreref(ANewClass).ESuperTypes =
ecoreref(ANewSuperClass) // doesn't exist yet
addNewEClass("ANewClass")
addNewEClass("ANewSuperClass")
ecoreref(ANewClass) // this is OK
ecoreref(ANewSuperClass) // this is OK
}
'''
input
.parseWithTestEcore => [
assertErrorsAsStrings(
'''
Element not yet available in this context: foo.ANewClass
Element not yet available in this context: foo.ANewSuperClass
The method ESuperTypes(EClass) is undefined for the type EClass
'''
)
assertError(
EDELTA_ECORE_DIRECT_REFERENCE,
EdeltaValidator.INTERPRETER_ACCESS_NOT_YET_EXISTING_ELEMENT,
input.indexOf("ANewClass"),
"ANewClass".length,
"Element not yet available in this context: foo.ANewClass"
)
assertError(
EDELTA_ECORE_DIRECT_REFERENCE,
EdeltaValidator.INTERPRETER_ACCESS_NOT_YET_EXISTING_ELEMENT,
input.indexOf("ANewSuperClass"),
"ANewSuperClass".length,
"Element not yet available in this context: foo.ANewSuperClass"
)
]
}
@Test
def void testAccessToNotYetExistingElementInComplexExpression2() {
val input =
'''
metamodel "foo"

modifyEcore aTest epackage foo {
// doesn't exist yet
ecoreref(ANewClass).ESuperTypes +=
ecoreref(ANewSuperClass) // doesn't exist yet
addNewEClass("ANewClass")
addNewEClass("ANewSuperClass")
ecoreref(ANewClass) // this is OK
ecoreref(ANewSuperClass) // this is OK
}
'''
input
.parseWithTestEcore => [
assertErrorsAsStrings(
'''
Element not yet available in this context: foo.ANewClass
Element not yet available in this context: foo.ANewSuperClass
'''
)
assertError(
EDELTA_ECORE_DIRECT_REFERENCE,
EdeltaValidator.INTERPRETER_ACCESS_NOT_YET_EXISTING_ELEMENT,
input.indexOf("ANewClass"),
"ANewClass".length,
"Element not yet available in this context: foo.ANewClass"
)
assertError(
EDELTA_ECORE_DIRECT_REFERENCE,
EdeltaValidator.INTERPRETER_ACCESS_NOT_YET_EXISTING_ELEMENT,
input.indexOf("ANewSuperClass"),
"ANewSuperClass".length,
"Element not yet available in this context: foo.ANewSuperClass"
)
]
}
}
Expand Up @@ -13,6 +13,8 @@
import edelta.interpreter.EdeltaInterpreterWrapperException;
import edelta.resource.derivedstate.EdeltaCopiedEPackagesMap;
import edelta.resource.derivedstate.EdeltaDerivedStateHelper;
import edelta.resource.derivedstate.EdeltaENamedElementXExpressionMap;
import edelta.resource.derivedstate.EdeltaUnresolvedEcoreReferences;
import edelta.tests.EdeltaAbstractTest;
import edelta.tests.EdeltaInjectorProviderDerivedStateComputerWithoutInterpreter;
import edelta.tests.additional.MyCustomEdeltaThatCannotBeLoadedAtRuntime;
Expand Down Expand Up @@ -2206,6 +2208,44 @@ public void testIntroducedCycles() {
ObjectExtensions.<EdeltaProgram>operator_doubleArrow(_parseWithTestEcore, _function);
}

@Test
public void testAccessToNotYetExistingElement() {
StringConcatenation _builder = new StringConcatenation();
_builder.append("metamodel \"foo\"");
_builder.newLine();
_builder.newLine();
_builder.append("modifyEcore aTest epackage foo {");
_builder.newLine();
_builder.append("\t");
_builder.append("ecoreref(ANewClass) // doesn\'t exist yet");
_builder.newLine();
_builder.append("\t");
_builder.append("ecoreref(NonExisting) // doesn\'t exist at all");
_builder.newLine();
_builder.append("\t");
_builder.append("addNewEClass(\"ANewClass\")");
_builder.newLine();
_builder.append("\t");
_builder.append("ecoreref(ANewClass) // this is OK");
_builder.newLine();
_builder.append("}");
_builder.newLine();
final String input = _builder.toString();
EdeltaProgram _parseWithTestEcore = this.parseWithTestEcore(input);
final Procedure1<EdeltaProgram> _function = (EdeltaProgram it) -> {
this.interpretProgram(it);
final EdeltaEcoreReference ecoreref1 = this.getAllEcoreReferenceExpressions(it).get(0).getReference();
final EdeltaEcoreReference ecoreref2 = this.getAllEcoreReferenceExpressions(it).get(1).getReference();
final EdeltaUnresolvedEcoreReferences unresolved = this.derivedStateHelper.getUnresolvedEcoreReferences(it.eResource());
Assertions.<EdeltaEcoreReference>assertThat(unresolved).containsOnly(ecoreref1, ecoreref2);
Assertions.assertThat(ecoreref1.getEnamedelement().eIsProxy()).isFalse();
Assertions.assertThat(ecoreref2.getEnamedelement().eIsProxy()).isTrue();
final EdeltaENamedElementXExpressionMap map = this.derivedStateHelper.getEnamedElementXExpressionMap(it.eResource());
Assertions.<XExpression>assertThat(map.get(ecoreref1.getEnamedelement())).isNotNull().isSameAs(this.getBlock(this.lastModifyEcoreOperation(it).getBody()).getExpressions().get(2));
};
ObjectExtensions.<EdeltaProgram>operator_doubleArrow(_parseWithTestEcore, _function);
}

private void assertAfterInterpretationOfEdeltaModifyEcoreOperation(final CharSequence input, final Procedure1<? super EPackage> testExecutor) {
this.assertAfterInterpretationOfEdeltaModifyEcoreOperation(input, true, testExecutor);
}
Expand Down

0 comments on commit b342cf4

Please sign in to comment.