From d34390a6113248e3ccb8e4216d8b724f328af41b Mon Sep 17 00:00:00 2001 From: Sebastian Zarnekow Date: Thu, 10 Nov 2011 20:03:12 +0100 Subject: [PATCH] [xtext][ecoreInference] Fix: Wrong error on compatible features in grammar editor --- .../src/org/eclipse/xtext/EcoreUtil2.java | 30 ++++++---- .../xtext/ecoreInference/EClassifierInfo.java | 7 ++- .../src/org/eclipse/xtext/EcoreUtil2Test.java | 56 +++++++++++++++++++ 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/EcoreUtil2.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/EcoreUtil2.java index b9c0c6fee..0e68c334a 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/EcoreUtil2.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/EcoreUtil2.java @@ -32,6 +32,7 @@ import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; @@ -307,18 +308,12 @@ public class EcoreUtil2 extends EcoreUtil { } public static EClassifier getCompatibleType(EClassifier typeA, EClassifier typeB) { - if (typeA.equals(typeB)) - return typeA; - // no common type for simple datatypes available - if (!(typeA instanceof EClass && typeB instanceof EClass)) - return null; - - List sortedCandidates = getSortedCommonCompatibleTypeCandidates((EClass) typeA, (EClass) typeB); - for (EClass candidate : sortedCandidates) - if (isCommonCompatibleType(candidate, sortedCandidates)) - return candidate; - - return EcorePackage.Literals.EOBJECT; + EClassifier result = getCompatibleType(typeA, typeB, null); + if (result != null) + return result; + if (typeA instanceof EClass && typeB instanceof EClass) + return EcorePackage.Literals.EOBJECT; + return null; } /** @@ -327,6 +322,17 @@ public class EcoreUtil2 extends EcoreUtil { public static EClassifier getCompatibleType(EClassifier typeA, EClassifier typeB, EObject grammarContext) { if (typeA.equals(typeB)) return typeA; + if (typeA instanceof EDataType && typeB instanceof EDataType) { + Class instanceClassA = typeA.getInstanceClass(); + Class instanceClassB = typeB.getInstanceClass(); + if (instanceClassA != null && instanceClassB != null) { + if (instanceClassA.isAssignableFrom(instanceClassB)) + return typeA; + if (instanceClassB.isAssignableFrom(instanceClassA)) + return typeB; + } + } + // no common type for simple datatypes available if (!(typeA instanceof EClass && typeB instanceof EClass)) return null; diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfo.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfo.java index 20d03debd..46a3ca639 100755 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfo.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfo.java @@ -258,8 +258,9 @@ public abstract class EClassifierInfo { result &= f1Type.isSuperTypeOf(f2Type); result &= ((EReference) f1).isContainment() == ((EReference) f2).isContainment(); result &= ((EReference) f1).isContainer() == ((EReference) f2).isContainer(); - } else - result &= f1.getEType().equals(f2.getEType()); + } else { + result &= f1.getEType().equals(EcoreUtil2.getCompatibleType(f1.getEType(), f2.getEType())); + } return result; } @@ -337,7 +338,7 @@ public abstract class EClassifierInfo { EClassifier compatibleType = EcoreUtil2.getCompatibleType(existingFeature.getEType(), newFeature.getEType(), grammarElement); if (compatibleType == null) throw new TransformationException(TransformationErrorCode.NoCompatibleFeatureTypeAvailable, - "Cannot find compatible type for features", grammarElement); + "Cannot find compatible type for the feature '" + existingFeature.getName() + "'", grammarElement); if (isGenerated(existingFeature)) { existingFeature.setEType(compatibleType); diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/EcoreUtil2Test.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/EcoreUtil2Test.java index b816114ec..45924e61b 100644 --- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/EcoreUtil2Test.java +++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/EcoreUtil2Test.java @@ -14,6 +14,7 @@ import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EPackage.Registry; @@ -43,6 +44,13 @@ public class EcoreUtil2Test extends AbstractXtextTests { return result; } + private EDataType createEDataType(String name, Class instanceClass) { + EDataType result = EcoreFactory.eINSTANCE.createEDataType(); + result.setName(name); + result.setInstanceClass(instanceClass); + return result; + } + public void testSimple() throws Exception { ResourceSet rs = new ResourceSetImpl(); Resource foo = rs.createResource(URI.createURI("foo.xmi"), ContentHandler.UNSPECIFIED_CONTENT_TYPE); @@ -144,6 +152,54 @@ public class EcoreUtil2Test extends AbstractXtextTests { assertSame(a, EcoreUtil2.getCompatibleType(d, e)); } + public void testGetCompatibleType_01() { + EDataType aString = createEDataType("a", String.class); + EDataType anotherString = createEDataType("b", String.class); + + assertSame(aString, EcoreUtil2.getCompatibleType(aString, anotherString, null)); + assertSame(anotherString, EcoreUtil2.getCompatibleType(anotherString, aString, null)); + } + + public void testGetCompatibleType_02() { + EDataType aString = createEDataType("a", String.class); + EDataType anObject = createEDataType("b", Object.class); + + assertSame(anObject, EcoreUtil2.getCompatibleType(aString, anObject, null)); + assertSame(anObject, EcoreUtil2.getCompatibleType(anObject, aString, null)); + } + + public void testGetCompatibleType_03() { + EDataType aCharSequence = createEDataType("a", CharSequence.class); + EDataType anAppendable = createEDataType("b", Appendable.class); + + assertSame(null, EcoreUtil2.getCompatibleType(aCharSequence, anAppendable, null)); + assertSame(null, EcoreUtil2.getCompatibleType(anAppendable, aCharSequence, null)); + } + + public void testGetCompatibleType_04() { + EDataType aString = createEDataType("a", String.class); + EDataType anotherString = createEDataType("b", String.class); + + assertSame(aString, EcoreUtil2.getCompatibleType(aString, anotherString)); + assertSame(anotherString, EcoreUtil2.getCompatibleType(anotherString, aString)); + } + + public void testGetCompatibleType_05() { + EDataType aString = createEDataType("a", String.class); + EDataType anObject = createEDataType("b", Object.class); + + assertSame(anObject, EcoreUtil2.getCompatibleType(aString, anObject)); + assertSame(anObject, EcoreUtil2.getCompatibleType(anObject, aString)); + } + + public void testGetCompatibleType_06() { + EDataType aCharSequence = createEDataType("a", CharSequence.class); + EDataType anAppendable = createEDataType("b", Appendable.class); + + assertSame(null, EcoreUtil2.getCompatibleType(aCharSequence, anAppendable)); + assertSame(null, EcoreUtil2.getCompatibleType(anAppendable, aCharSequence)); + } + public void testGetAllSuperTypesWithCycle() { EClass a = createEClass("a"); EClass b = createEClass("b");