Skip to content

Commit

Permalink
[Validation|Interpreter] Properly resolve methods declared in a paren…
Browse files Browse the repository at this point in the history
…t class (#173)

Same as #167 but also handles the case where the class is open with a fully qualified name.

And provides unit tests.
  • Loading branch information
echebbi committed Jul 3, 2020
1 parent d6e5429 commit 728195a
Show file tree
Hide file tree
Showing 15 changed files with 232 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<eStructuralFeatures xsi:type="ecore:EReference" name="body" lowerBound="1" eType="#//Block"
containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="tags" upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="overriding" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="ModelUnit" eSuperTypes="../../org.eclipse.emf.ecore/model/Ecore.ecore#//ENamedElement">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="services" upperBound="-1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Implementation.ecore#//Method/operationRef"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference Implementation.ecore#//Method/body"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Implementation.ecore#//Method/tags"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Implementation.ecore#//Method/overriding"/>
</genClasses>
<genClasses ecoreClass="Implementation.ecore#//ModelUnit">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Implementation.ecore#//ModelUnit/services"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,14 +431,23 @@ public interface ImplementationPackage extends EPackage {
*/
int METHOD__TAGS = 2;

/**
* The feature id for the '<em><b>Overriding</b></em>' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
* @ordered
*/
int METHOD__OVERRIDING = 3;

/**
* The number of structural features of the '<em>Method</em>' class.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
* @ordered
*/
int METHOD_FEATURE_COUNT = 3;
int METHOD_FEATURE_COUNT = 4;

/**
* The number of operations of the '<em>Method</em>' class.
Expand Down Expand Up @@ -1629,6 +1638,17 @@ public interface ImplementationPackage extends EPackage {
*/
EAttribute getMethod_Tags();

/**
* Returns the meta object for the attribute '{@link org.eclipse.emf.ecoretools.ale.implementation.Method#isOverriding <em>Overriding</em>}'.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @return the meta object for the attribute '<em>Overriding</em>'.
* @see org.eclipse.emf.ecoretools.ale.implementation.Method#isOverriding()
* @see #getMethod()
* @generated
*/
EAttribute getMethod_Overriding();

/**
* Returns the meta object for class '{@link org.eclipse.emf.ecoretools.ale.implementation.ModelUnit <em>Model Unit</em>}'.
* <!-- begin-user-doc -->
Expand Down Expand Up @@ -2449,6 +2469,14 @@ interface Literals {
*/
EAttribute METHOD__TAGS = eINSTANCE.getMethod_Tags();

/**
* The meta object literal for the '<em><b>Overriding</b></em>' attribute feature.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
EAttribute METHOD__OVERRIDING = eINSTANCE.getMethod_Overriding();

/**
* The meta object literal for the '{@link org.eclipse.emf.ecoretools.ale.implementation.impl.ModelUnitImpl <em>Model Unit</em>}' class.
* <!-- begin-user-doc -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.Method#getOperationRef <em>Operation Ref</em>}</li>
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.Method#getBody <em>Body</em>}</li>
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.Method#getTags <em>Tags</em>}</li>
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.Method#isOverriding <em>Overriding</em>}</li>
* </ul>
*
* @see org.eclipse.emf.ecoretools.ale.implementation.ImplementationPackage#getMethod()
Expand Down Expand Up @@ -110,4 +111,26 @@ public interface Method extends EObject {
*/
EList<String> getTags();

/**
* Returns the value of the '<em><b>Overriding</b></em>' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @return the value of the '<em>Overriding</em>' attribute.
* @see #setOverriding(boolean)
* @see org.eclipse.emf.ecoretools.ale.implementation.ImplementationPackage#getMethod_Overriding()
* @model
* @generated
*/
boolean isOverriding();

/**
* Sets the value of the '{@link org.eclipse.emf.ecoretools.ale.implementation.Method#isOverriding <em>Overriding</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @param value the new value of the '<em>Overriding</em>' attribute.
* @see #isOverriding()
* @generated
*/
void setOverriding(boolean value);

} // Method
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,16 @@ public EAttribute getMethod_Tags() {
return (EAttribute)methodEClass.getEStructuralFeatures().get(2);
}

/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public EAttribute getMethod_Overriding() {
return (EAttribute)methodEClass.getEStructuralFeatures().get(3);
}

/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
Expand Down Expand Up @@ -1133,6 +1143,7 @@ public void createPackageContents() {
createEReference(methodEClass, METHOD__OPERATION_REF);
createEReference(methodEClass, METHOD__BODY);
createEAttribute(methodEClass, METHOD__TAGS);
createEAttribute(methodEClass, METHOD__OVERRIDING);

modelUnitEClass = createEClass(MODEL_UNIT);
createEAttribute(modelUnitEClass, MODEL_UNIT__SERVICES);
Expand Down Expand Up @@ -1294,6 +1305,7 @@ public void initializePackageContents() {
initEReference(getMethod_OperationRef(), ecorePackage.getEOperation(), null, "operationRef", null, 1, 1, Method.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
initEReference(getMethod_Body(), this.getBlock(), null, "body", null, 1, 1, Method.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
initEAttribute(getMethod_Tags(), ecorePackage.getEString(), "tags", null, 0, -1, Method.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
initEAttribute(getMethod_Overriding(), ecorePackage.getEBoolean(), "overriding", null, 0, 1, Method.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);

initEClass(modelUnitEClass, ModelUnit.class, "ModelUnit", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
initEAttribute(getModelUnit_Services(), ecorePackage.getEString(), "services", null, 0, -1, ModelUnit.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.impl.MethodImpl#getOperationRef <em>Operation Ref</em>}</li>
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.impl.MethodImpl#getBody <em>Body</em>}</li>
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.impl.MethodImpl#getTags <em>Tags</em>}</li>
* <li>{@link org.eclipse.emf.ecoretools.ale.implementation.impl.MethodImpl#isOverriding <em>Overriding</em>}</li>
* </ul>
*
* @generated
Expand Down Expand Up @@ -84,6 +85,26 @@ public class MethodImpl extends MinimalEObjectImpl.Container implements Method {
*/
protected EList<String> tags;

/**
* The default value of the '{@link #isOverriding() <em>Overriding</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isOverriding()
* @generated
* @ordered
*/
protected static final boolean OVERRIDING_EDEFAULT = false;

/**
* The cached value of the '{@link #isOverriding() <em>Overriding</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isOverriding()
* @generated
* @ordered
*/
protected boolean overriding = OVERRIDING_EDEFAULT;

/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
Expand Down Expand Up @@ -201,6 +222,29 @@ public EList<String> getTags() {
return tags;
}

/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean isOverriding() {
return overriding;
}

/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setOverriding(boolean newOverriding) {
boolean oldOverriding = overriding;
overriding = newOverriding;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, ImplementationPackage.METHOD__OVERRIDING, oldOverriding, overriding));
}

/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
Expand Down Expand Up @@ -230,6 +274,8 @@ public Object eGet(int featureID, boolean resolve, boolean coreType) {
return getBody();
case ImplementationPackage.METHOD__TAGS:
return getTags();
case ImplementationPackage.METHOD__OVERRIDING:
return isOverriding();
}
return super.eGet(featureID, resolve, coreType);
}
Expand All @@ -253,6 +299,9 @@ public void eSet(int featureID, Object newValue) {
getTags().clear();
getTags().addAll((Collection<? extends String>)newValue);
return;
case ImplementationPackage.METHOD__OVERRIDING:
setOverriding((Boolean)newValue);
return;
}
super.eSet(featureID, newValue);
}
Expand All @@ -274,6 +323,9 @@ public void eUnset(int featureID) {
case ImplementationPackage.METHOD__TAGS:
getTags().clear();
return;
case ImplementationPackage.METHOD__OVERRIDING:
setOverriding(OVERRIDING_EDEFAULT);
return;
}
super.eUnset(featureID);
}
Expand All @@ -292,6 +344,8 @@ public boolean eIsSet(int featureID) {
return body != null;
case ImplementationPackage.METHOD__TAGS:
return tags != null && !tags.isEmpty();
case ImplementationPackage.METHOD__OVERRIDING:
return overriding != OVERRIDING_EDEFAULT;
}
return super.eIsSet(featureID);
}
Expand All @@ -308,6 +362,8 @@ public String toString() {
StringBuilder result = new StringBuilder(super.toString());
result.append(" (tags: ");
result.append(tags);
result.append(", overriding: ");
result.append(overriding);
result.append(')');
return result.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.eclipse.emf.ecoretools.ale.core.parser.ALEParser.TypeLiteralContext;
import org.eclipse.emf.ecoretools.ale.core.parser.ParsedFile;
import org.eclipse.emf.ecoretools.ale.core.validation.IConvertType;
import org.eclipse.emf.ecoretools.ale.core.validation.QualifiedNames;
import org.eclipse.emf.ecoretools.ale.core.validation.impl.ConvertType;
import org.eclipse.emf.ecoretools.ale.implementation.Attribute;
import org.eclipse.emf.ecoretools.ale.implementation.Block;
Expand Down Expand Up @@ -212,12 +213,9 @@ public Method buildMethod(EOperation operation, Block body, List<String> tags) {

public Method buildImplementation(String containingClass, String name, List<Parameter> params, RTypeContext returnType, Block body, List<String> tags) {
Optional<EOperation> existingOperation = resolve(containingClass, name, params.size(), returnType);

if(!existingOperation.isPresent()){
return buildMethod(null,body,tags);
}

return buildMethod(existingOperation.get(),body,tags);
Method method = buildMethod(existingOperation.orElse(null), body, tags);
method.setOverriding(true);
return method;
}


Expand Down Expand Up @@ -527,12 +525,21 @@ public void updateEClass(EClass cls, RuntimeClass clsDef) {
//Can return null
public Optional<EOperation> resolve(String className, String methodName, int nbArgs, RTypeContext returnType) {
EClassifier type = resolve(returnType).getEType();
// FIXME: manage qualified name
String packageName = null;

boolean isFullyQualifiedName = className.contains(".");
if (isFullyQualifiedName) {
packageName = className.substring(0, className.lastIndexOf('.')).replace(".", "::");
className = className.substring(className.lastIndexOf('.') + 1);
}
String finalPackageName = packageName;
String finalClassName = className;
return qryEnv.getEPackageProvider()
.getEClassifiers().stream()
.filter(cls -> cls instanceof EClass)
.map(EClass.class::cast)
.filter(cls -> cls.getName().equals(className))
.filter(cls -> cls.getName().equals(finalClassName))
.filter(cls -> finalPackageName == null ? true : (finalPackageName.equals(QualifiedNames.getQualifiedName(cls.getEPackage())) ? true : false))
.flatMap(cls -> cls.getEAllOperations().stream())
.filter(op -> op.getName().equals(methodName) && op.getEParameters().size() == nbArgs && op.getEType() == type)
.findFirst();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,20 +160,24 @@ public List<Message> validateExtendedClass(ExtendedClass xtdClass) {
*/
EList<EOperation> allEOperations = xtdClass.getBaseClass().getEAllOperations();
for (Method mtd : xtdClass.getMethods()) {
if (mtd.isOverriding()) {
continue;
}
EOperation opRef = mtd.getOperationRef();
if(opRef!= null && opRef.getEContainingClass() != xtdClass.getBaseClass()) {
if(allEOperations.stream().anyMatch(op -> areTheSame(opRef, op))){
CodeLocation location = DiagnosticsFactory.eINSTANCE.createCodeLocation();
location.setLine(base.getLines(mtd).get(0));
location.setStartPosition(base.getStartOffset(mtd));
location.setEndPosition(base.getEndOffset(mtd.getBody()));
location.setEndPosition(base.getStartOffset(mtd.getBody()));

Context context = DiagnosticsFactory.eINSTANCE.createContext();

MethodAlreadyDefinedInBaseClass alreadyDeclared = DiagnosticsFactory.eINSTANCE.createMethodAlreadyDefinedInBaseClass();
alreadyDeclared.setContext(context);
alreadyDeclared.setLocation(location);
alreadyDeclared.setNewDefinition(mtd);
alreadyDeclared.setSource(mtd);
msgs.add(alreadyDeclared);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ ASSIGN_ILLEGAL = Type mismatch: cannot assign {0} to {1}
ADD_ASSIGN_ILLEGAL = {0} cannot be added to {1} (expected {2})
SUB_ASSIGN_ILLEGAL = {0} cannot be removed from {1} (expected {2})

METHOD_ALREADY_DEFINED = The operation {0} must override
METHOD_ALREADY_DEFINED = Use the ''override'' keyword to override the {0} operation

NOT_ITERABLE = Expected Collection but was {0}
OVERRIDDEN_METHOD_NOT_FOUND = Can''t find matching EOperation in {0}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
behavior overrideMethod;

open class D {

@main
def void main() {
self.foo();
}

override void foo() {

}
}

// Same but with fully qualified name

open class doublemulti.C {

@main
def void main() {
self.foo();
}

override void foo() {

}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<?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="doublemulti" nsURI="http://doublemulti" nsPrefix="doublemulti">
<eClassifiers xsi:type="ecore:EClass" name="A"/>
<eClassifiers xsi:type="ecore:EClass" name="A">
<eOperations name="foo"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="B"/>
<eClassifiers xsi:type="ecore:EClass" name="C" eSuperTypes="#//A #//B"/>
<eClassifiers xsi:type="ecore:EClass" name="D" eSuperTypes="#//B #//A"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<doublemulti:C xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:doublemulti="http://doublemulti" xsi:schemaLocation="http://doublemulti doubleMulti.ecore"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<doublemulti:D xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:doublemulti="http://doublemulti" xsi:schemaLocation="http://doublemulti doubleMulti.ecore"/>
Loading

0 comments on commit 728195a

Please sign in to comment.