Applied patch from Heiko:

Feature uplift
see https://bugs.eclipse.org/bugs/attachment.cgi?id=113868
This commit is contained in:
jkohnlein 2008-09-30 13:35:24 +00:00
parent af48e40b1a
commit a14dd5eb00
8 changed files with 362 additions and 161 deletions

View file

@ -9,6 +9,7 @@ package org.eclipse.xtext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -17,10 +18,14 @@ import org.apache.log4j.Logger;
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.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
@ -161,16 +166,82 @@ public class EcoreUtil2 extends EcoreUtil {
}
private static List<EClass> getSortedCommonCompatibleTypeCandidates(EClass classA, EClass classB) {
List<EClass> ca = new ArrayList<EClass>(classA.getEAllSuperTypes());
ca.add(classA);
List<EClass> cb = new ArrayList<EClass>(classB.getEAllSuperTypes());
cb.add(classB);
cb.retainAll(ca);
ca.retainAll(cb);
List<EClass> result = getCompatibleTypesOf(classA);
List<EClass> compatibleTypesOfB = getCompatibleTypesOf(classB);
result.retainAll(compatibleTypesOfB);
List<EClass> intersection = ca;
Collections.sort(intersection, new EClassTypeHierarchyComparator());
Collections.sort(result, new EClassTypeHierarchyComparator());
return intersection;
return result;
}
public static List<EClass> getCompatibleTypesOf(EClass eClass) {
List<EClass> ca = new ArrayList<EClass>(eClass.getEAllSuperTypes());
ca.add(eClass);
return ca;
}
public static boolean isFeatureSemanticallyEqualApartFromType(EStructuralFeature f1, EStructuralFeature f2) {
boolean result = f1.getName().equals(f1.getName());
result &= f1.getLowerBound() == f2.getLowerBound();
result &= f1.getUpperBound() == f2.getUpperBound();
if (f1 instanceof EReference && f2 instanceof EReference)
result &= ((EReference) f1).isContainment() == ((EReference) f2).isContainment();
return result;
}
public static boolean isFeatureSemanticallyEqualTo(EStructuralFeature f1, EStructuralFeature f2) {
boolean result = isFeatureSemanticallyEqualApartFromType(f1, f2);
result &= f1.getEType().equals(f2.getEType());
return result;
}
public enum FindResult {
FeatureDoesNotExist, FeatureExists, DifferentFeatureWithSameNameExists
}
public static EStructuralFeature findFeatureByName(Collection<EStructuralFeature> features, String name) {
for (EStructuralFeature feature : features)
if(feature.getName().equals(name))
return feature;
return null;
}
public static FindResult containsSemanticallyEqualFeature(EClass eClass, EStructuralFeature feature) {
return containsSemanticallyEqualFeature(eClass.getEAllStructuralFeatures(), feature);
}
public static FindResult containsSemanticallyEqualFeature(Collection<EStructuralFeature> features,
EStructuralFeature feature) {
EStructuralFeature potentiallyEqualFeature = findFeatureByName(features, feature.getName());
if (potentiallyEqualFeature == null)
return FindResult.FeatureDoesNotExist;
else if (isFeatureSemanticallyEqualTo(potentiallyEqualFeature, feature))
return FindResult.FeatureExists;
else
return FindResult.DifferentFeatureWithSameNameExists;
}
public static EStructuralFeature createFeatureAsCloneOf(EStructuralFeature prototype) {
EStructuralFeature result;
if (prototype instanceof EReference) {
EReference prototypeAsReference = (EReference) prototype;
EReference resultAsReference = EcoreFactory.eINSTANCE.createEReference();
resultAsReference.setContainment(prototypeAsReference.isContainment());
result = resultAsReference;
}
else if (prototype instanceof EAttribute)
result = EcoreFactory.eINSTANCE.createEAttribute();
else
throw new IllegalArgumentException("Unsupported feature type " + prototype);
result.setName(prototype.getName());
result.setEType(prototype.getEType());
result.setLowerBound(prototype.getLowerBound());
result.setUpperBound(prototype.getUpperBound());
return result;
}
}

View file

@ -68,11 +68,8 @@ public class XtextResource extends ResourceImpl {
return parseResult;
}
public void update(int offset, String change) {
public void update(int offset, int originalLength, String change) {
CompositeNode rootNode = parseResult.getRootNode();
int length = change.length();
int documentGrowth = length - rootNode.getLength();
int originalLength = length - documentGrowth;
// unloading is required to ensure that any EObjects hanging around
// (e.g. in the outline) get a proxied URI

View file

@ -8,7 +8,6 @@
*******************************************************************************/
package org.eclipse.xtext.resource.metamodel;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
@ -72,7 +71,7 @@ public abstract class EClassifierInfo {
}
EClass eClass = getEClass();
EClass superEClass = (EClass) superTypeInfo.getEClassifier();
if(eClass.equals(superEClass))
if (eClass.equals(superEClass))
// cannot add class as it's own superclass
// this usually happens due to a rule call
return false;
@ -80,13 +79,6 @@ public abstract class EClassifierInfo {
return eClass.getESuperTypes().add(superEClass);
}
private EStructuralFeature findFeatureInClassIgnoringSuperclasses(EClass eClass, String featureName) {
for (EStructuralFeature feature : eClass.getEStructuralFeatures())
if (feature.getName().equals(featureName))
return feature;
return null;
}
@Override
public boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue,
boolean isContainment, EObject parserElement) throws TransformationException {
@ -94,11 +86,11 @@ public abstract class EClassifierInfo {
EClassifier featureClassifier = featureType.getEClassifier();
return addFeature(featureName, featureClassifier, isMultivalue, isContainment, parserElement);
}
public boolean addFeature(EStructuralFeature prototype) {
// TODO implement
try {
return addFeature(prototype.getName(), prototype.getEType(), prototype.isMany(), false, null);
return addFeature(prototype.getName(), prototype.getEType(), prototype.isMany(), prototype
.getUpperBound() > 1, null);
}
catch (TransformationException e) {
throw new IllegalArgumentException(e.getMessage());
@ -107,6 +99,41 @@ public abstract class EClassifierInfo {
private boolean addFeature(String featureName, EClassifier featureClassifier, boolean isMultivalue,
boolean isContainment, EObject parserElement) throws TransformationException {
EStructuralFeature newFeature = createFeatureWith(featureName, featureClassifier, isMultivalue,
isContainment);
switch (EcoreUtil2.containsSemanticallyEqualFeature(getEClass(), newFeature)) {
case FeatureDoesNotExist:
return getEClass().getEStructuralFeatures().add(newFeature);
case FeatureExists:
// do nothing
return false;
}
// feature with same name exists, but have a different, potentially
// incompatible configuration
EStructuralFeature existingFeature = getEClass().getEStructuralFeature(featureName);
if (!EcoreUtil2.isFeatureSemanticallyEqualApartFromType(newFeature, existingFeature))
throw new TransformationException(ErrorCode.FeatureWithDifferentConfigurationAlreadyExists,
"feature with different cardinality or containment configuration already exists " + newFeature,
parserElement);
EClassifier compatibleType = EcoreUtil2
.getCompatibleType(existingFeature.getEType(), newFeature.getEType());
if (compatibleType == null)
throw new TransformationException(ErrorCode.NoCompatibleFeatureTypeAvailable,
"Cannot find compatible type for features", parserElement);
// TODO check, whether existing feature can be changed (feature's
// declaring type isGenerated==true)
// try to avoid coupling between this class and EClassifierInfos
existingFeature.setEType(compatibleType);
return true;
}
private EStructuralFeature createFeatureWith(String featureName, EClassifier featureClassifier,
boolean isMultivalue, boolean isContainment) {
EStructuralFeature newFeature;
if (featureClassifier instanceof EClass) {
@ -120,37 +147,7 @@ public abstract class EClassifierInfo {
newFeature.setEType(featureClassifier);
newFeature.setLowerBound(0);
newFeature.setUpperBound(isMultivalue ? -1 : 1);
EList<EStructuralFeature> features = getEClass().getEStructuralFeatures();
EStructuralFeature existentFeature = findFeatureInClassIgnoringSuperclasses(getEClass(), featureName);
if (existentFeature == null) {
// feature does not exist, yet
return features.add(newFeature);
}
else {
if (newFeature.getLowerBound() != existentFeature.getLowerBound()
|| newFeature.getUpperBound() != existentFeature.getUpperBound())
throw new TransformationException(ErrorCode.FeatureWithDifferentConfigurationAlreadyExists,
"feature with different cardinality already exists " + newFeature, parserElement);
else {
// TODO Extract into something more genreral that can be used for uplifting
// same name but different type => feature should have
// compatible type
// remove and add again to overcome problem with reference
// vs. attribute
EClassifier compatibleType = EcoreUtil2.getCompatibleType(existentFeature.getEType(), newFeature
.getEType());
if (compatibleType == null)
throw new TransformationException(ErrorCode.NoCompatibleFeatureTypeAvailable,
"Cannot find compatible type for features", parserElement);
int oldIndex = features.indexOf(existentFeature);
features.remove(existentFeature);
addFeature(featureName, compatibleType, isMultivalue, isContainment, parserElement);
existentFeature = findFeatureInClassIgnoringSuperclasses(getEClass(), featureName);
features.move(oldIndex, existentFeature);
return true;
}
}
return newFeature;
}
public EClass getEClass() {

View file

@ -16,7 +16,7 @@ import org.eclipse.emf.ecore.EObject;
*/
public interface ErrorAcceptor {
public enum ErrorCode {
NoSuchTypeAvailable, MoreThanOneTypeChangeInOneRule, CannotLoadMetamodel, CannotCreateTypeInSealedMetamodel, FeatureWithDifferentConfigurationAlreadyExists, NoCompatibleFeatureTypeAvailable, AliasForMetamodelAlreadyExists
NoSuchTypeAvailable, MoreThanOneTypeChangeInOneRule, CannotLoadMetamodel, CannotCreateTypeInSealedMetamodel, FeatureWithDifferentConfigurationAlreadyExists, NoCompatibleFeatureTypeAvailable, AliasForMetamodelAlreadyExists, NoSuchRuleAvailable
}
public void acceptError(ErrorCode errorCode, String message, EObject element);

View file

@ -15,9 +15,10 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.EcoreUtil2.FindResult;
import org.eclipse.xtext.resource.metamodel.EClassifierInfo.EClassInfo;
/**
@ -59,7 +60,8 @@ public class TypeHierarchyHelper {
return result;
}
public void liftUpFeaturesOf(Collection<EClassInfo> infos) {
public void liftUpFeaturesRecursively(Collection<EClassInfo> infos) {
traversedTypes.clear();
for (EClassInfo info : infos)
liftUpFeaturesInto(info);
}
@ -71,9 +73,9 @@ public class TypeHierarchyHelper {
traversedTypes.add(superType);
Collection<EClassInfo> subTypes = getSubTypesOf(superType);
if(subTypes.isEmpty())
if (subTypes.isEmpty())
return;
// lift up features recursively, deepest first
for (EClassInfo subType : subTypes) {
liftUpFeaturesInto(subType);
@ -86,7 +88,7 @@ public class TypeHierarchyHelper {
// only if all subtypes' compatible type is superType itself
// features can be lifted into superType
if (infos.getCompatibleTypeOf(subTypes).equals(superType)) {
Collection<EStructuralFeature> commonFeatures = getCommonFeatures(subTypes);
Collection<EStructuralFeature> commonFeatures = getCommonDirectFeatures(subTypes);
Collection<EStructuralFeature> liftedFeatures = joinFeaturesInto(commonFeatures, superType);
for (EClassInfo subClassInfo : subTypes)
removeFeatures(subClassInfo, liftedFeatures);
@ -94,31 +96,30 @@ public class TypeHierarchyHelper {
}
private void removeFeatures(EClassInfo info, Collection<EStructuralFeature> features) {
Collection<EStructuralFeature> featuresToBeRemoved = new HashSet<EStructuralFeature>();
for (EStructuralFeature feature : info.getEClass().getEStructuralFeatures())
if(containsEqualFeature(features, feature))
featuresToBeRemoved.add(feature);
Collection<EStructuralFeature> featuresToBeModified = info.getEClass().getEStructuralFeatures();
for (Iterator<EStructuralFeature> iterator = featuresToBeModified.iterator(); iterator.hasNext();)
if (EcoreUtil2.containsSemanticallyEqualFeature(features, iterator.next()) == FindResult.FeatureExists)
iterator.remove();
info.getEClass().getEStructuralFeatures().removeAll(featuresToBeRemoved);
}
private Collection<EStructuralFeature> joinFeaturesInto(Collection<EStructuralFeature> commonFeatures,
EClassInfo info) {
Collection<EStructuralFeature> result = new HashSet<EStructuralFeature>();
for (EStructuralFeature feature : commonFeatures) {
if (containsEqualFeature(info.getEClass().getEStructuralFeatures(), feature))
// feature already exists, feature can be lifted, nothing to do
result.add(feature);
else if (info.getEClass().getEStructuralFeature(feature.getName()) == null) {
info.addFeature(feature);
result.add(feature);
switch (EcoreUtil2.containsSemanticallyEqualFeature(info.getEClass(), feature)) {
case FeatureDoesNotExist:
info.addFeature(feature);
case FeatureExists:
result.add(feature);
default:
break;
}
}
return result;
}
private Collection<EStructuralFeature> getCommonFeatures(Collection<EClassInfo> infos) {
private Collection<EStructuralFeature> getCommonDirectFeatures(Collection<EClassInfo> infos) {
Collection<EStructuralFeature> result = new HashSet<EStructuralFeature>();
Iterator<EClassInfo> iterator = infos.iterator();
@ -127,42 +128,54 @@ public class TypeHierarchyHelper {
result.addAll(eClass.getEStructuralFeatures());
}
while (iterator.hasNext()) {
EList<EStructuralFeature> features = iterator.next().getEClass().getEStructuralFeatures();
result = getCommonFeatures(result, features);
}
while (iterator.hasNext())
result = getCommonFeatures(iterator.next(), result);
return result;
}
public Collection<EStructuralFeature> getCommonFeatures(Collection<EStructuralFeature> setA,
EList<EStructuralFeature> setB) {
public Collection<EStructuralFeature> getCommonFeatures(EClassInfo info, Collection<EStructuralFeature> features) {
Collection<EStructuralFeature> result = new HashSet<EStructuralFeature>();
for (EStructuralFeature f : setA)
if (containsEqualFeature(setB, f))
for (EStructuralFeature f : features)
if (EcoreUtil2.containsSemanticallyEqualFeature(info.getEClass(), f) == FindResult.FeatureExists)
result.add(f);
return result;
}
private boolean containsEqualFeature(Collection<EStructuralFeature> features, EStructuralFeature feature) {
for (EStructuralFeature otherFeature : features) {
if (isFeatureEqualTo(feature, otherFeature))
return true;
public void liftUpFeaturesRecursively() {
traversedTypes.clear();
liftUpFeaturesRecursively(rootInfos);
}
public void removeDuplicateDerivedFeatures() {
removeDuplicateDerivedFeaturesOf(infos.getAllEClassInfos());
}
private void removeDuplicateDerivedFeaturesOf(Collection<EClassInfo> classInfos) {
for (EClassInfo classInfo : classInfos) {
removeDuplicateDerivedFeaturesOf(classInfo);
}
return false;
}
private boolean isFeatureEqualTo(EStructuralFeature f1, EStructuralFeature f2) {
// TODO make comparison more precise
// TODO extract into a common place, e.g. EcoreUtil2
return f1.getName().equals(f2.getName()) && f1.getEType().equals(f2.getEType()) && f1.getLowerBound() == f2.getLowerBound()
&& f1.getUpperBound() == f2.getUpperBound();
private void removeDuplicateDerivedFeaturesOf(EClassInfo classInfo) {
// do not modify sealed types
if (!classInfo.isGenerated())
return;
Collection<EStructuralFeature> features = classInfo.getEClass().getEStructuralFeatures();
for (Iterator<EStructuralFeature> iterator = features.iterator(); iterator.hasNext();)
if(anySuperTypeContainsSemanticallyEqualFeature(classInfo.getEClass(), iterator.next()))
iterator.remove();
}
public void liftUpFeatures() {
liftUpFeaturesOf(rootInfos);
private boolean anySuperTypeContainsSemanticallyEqualFeature(EClass eClass, EStructuralFeature feature) {
Collection<EStructuralFeature> allSupertypesFeatures = new HashSet<EStructuralFeature>();
for (EClass superType : eClass.getEAllSuperTypes())
allSupertypesFeatures.addAll(superType.getEAllStructuralFeatures());
return EcoreUtil2.containsSemanticallyEqualFeature(allSupertypesFeatures, feature) == FindResult.FeatureExists;
}
}

View file

@ -170,7 +170,10 @@ public class Xtext2EcoreTransformer {
else if (element instanceof RuleCall && !GrammarUtil.isOptionalCardinality(element)) {
RuleCall ruleCall = (RuleCall) element;
AbstractRule calledRule = GrammarUtil.findRuleForName(grammar, ruleCall.getName());
return context.spawnContextWithCalledRule(findOrCreateEClass(calledRule), ruleCall);
// do not throw an exception for missing rules, these have been
// announced during the first iteration
if (calledRule != null)
return context.spawnContextWithCalledRule(findOrCreateEClass(calledRule), ruleCall);
}
else if (element instanceof Action) {
Action action = (Action) element;
@ -214,14 +217,9 @@ public class Xtext2EcoreTransformer {
}
private void normalizeGeneratedPackages() {
// TODO Implement
// feature normalization
// - uplift of common feature to supertype
// - removal in subtype if already in supertype
// - don't combine features with different EDatatypes
// NOTE: package dependencies
TypeHierarchyHelper helper = new TypeHierarchyHelper(this.eClassifierInfos);
helper.liftUpFeaturesRecursively();
helper.removeDuplicateDerivedFeatures();
}
private void deriveTypesAndHierarchy(EClassifierInfo ruleReturnType, AbstractElement element)
@ -229,6 +227,9 @@ public class Xtext2EcoreTransformer {
if (element instanceof RuleCall) {
RuleCall ruleCall = (RuleCall) element;
AbstractRule calledRule = GrammarUtil.calledRule(ruleCall);
if (calledRule == null)
throw new TransformationException(ErrorCode.NoSuchRuleAvailable, "Cannot find rule "
+ ruleCall.getName(), ruleCall);
TypeRef calledRuleReturnTypeRef = getOrFakeReturnType(calledRule);
addSuperType(calledRuleReturnTypeRef, ruleReturnType);
}

View file

@ -1,3 +1,11 @@
/*******************************************************************************
* Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.eclipse.xtext.resource.metamodel;
import junit.framework.TestCase;
@ -5,19 +13,24 @@ import junit.framework.TestCase;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.xtext.resource.metamodel.EClassifierInfo.EClassInfo;
/**
* @author Heiko Behrens - Initial contribution and API
*
*/
public class TypeHierarchyHelperTests extends TestCase {
private TypeHierarchyHelper helper;
private EClassifierInfos infos = new EClassifierInfos();
private EDataType INT = EcoreFactory.eINSTANCE.createEDataType();
// private EDataType STRING = EcoreFactory.eINSTANCE.createEDataType();
private EDataType STRING = EcoreFactory.eINSTANCE.createEDataType();
private void liftUpFeatures() throws Exception {
helper = new TypeHierarchyHelper(infos);
helper.liftUpFeatures();
helper.liftUpFeaturesRecursively();
}
private EClassInfo addClass(String name, boolean isGenerated) {
@ -31,7 +44,7 @@ public class TypeHierarchyHelperTests extends TestCase {
private EClassInfo addClass(String name) {
return addClass(name, true);
}
private void addAttribute(EClassInfo eClass, EDataType eType, String name) {
EAttribute feature = EcoreFactory.eINSTANCE.createEAttribute();
feature.setName(name);
@ -39,6 +52,13 @@ public class TypeHierarchyHelperTests extends TestCase {
eClass.getEClass().getEStructuralFeatures().add(feature);
}
private void addReference(EClassInfo eClass, EClassInfo ref, String name) {
EReference feature = EcoreFactory.eINSTANCE.createEReference();
feature.setName(name);
feature.setEType(ref.getEClassifier());
eClass.getEClass().getEStructuralFeatures().add(feature);
}
public void testSimpeCase01() throws Exception {
EClassInfo a = addClass("a");
EClassInfo b = addClass("b");
@ -51,9 +71,9 @@ public class TypeHierarchyHelperTests extends TestCase {
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
assertEquals(1, c.getEClass().getEStructuralFeatures().size());
liftUpFeatures();
assertEquals(1, a.getEClass().getEStructuralFeatures().size());
assertEquals(0, b.getEClass().getEStructuralFeatures().size());
assertEquals(0, c.getEClass().getEStructuralFeatures().size());
@ -68,13 +88,13 @@ public class TypeHierarchyHelperTests extends TestCase {
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
liftUpFeatures();
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
}
public void testRecursiveUplift01() throws Exception {
// no uplift for less than two children
EClassInfo a = addClass("a");
@ -86,26 +106,26 @@ public class TypeHierarchyHelperTests extends TestCase {
c.addSupertype(a);
d.addSupertype(c);
e.addSupertype(c);
addAttribute(b, INT, "f1");
addAttribute(d, INT, "f1");
addAttribute(e, INT, "f1");
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
assertEquals(0, c.getEClass().getEStructuralFeatures().size());
assertEquals(1, d.getEClass().getEStructuralFeatures().size());
assertEquals(1, e.getEClass().getEStructuralFeatures().size());
liftUpFeatures();
assertEquals(1, a.getEClass().getEStructuralFeatures().size());
assertEquals(0, b.getEClass().getEStructuralFeatures().size());
assertEquals(0, c.getEClass().getEStructuralFeatures().size());
assertEquals(0, d.getEClass().getEStructuralFeatures().size());
assertEquals(0, e.getEClass().getEStructuralFeatures().size());
}
public void testNikolaus() throws Exception {
// no uplift for less than two children
EClassInfo a = addClass("a");
@ -119,24 +139,87 @@ public class TypeHierarchyHelperTests extends TestCase {
d.addSupertype(c);
e.addSupertype(b);
e.addSupertype(c);
addAttribute(b, STRING, "f2");
addAttribute(c, STRING, "f2");
addAttribute(d, INT, "f1");
addAttribute(e, INT, "f1");
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(0, b.getEClass().getEStructuralFeatures().size());
assertEquals(0, c.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
assertEquals(1, c.getEClass().getEStructuralFeatures().size());
assertEquals(1, d.getEClass().getEStructuralFeatures().size());
assertEquals(1, e.getEClass().getEStructuralFeatures().size());
liftUpFeatures();
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, a.getEClass().getEStructuralFeatures().size());
assertEquals(0, b.getEClass().getEStructuralFeatures().size());
assertEquals(0, c.getEClass().getEStructuralFeatures().size());
assertEquals(1, d.getEClass().getEStructuralFeatures().size());
assertEquals(1, e.getEClass().getEStructuralFeatures().size());
}
public void testImcompatipleFeatures() throws Exception {
EClassInfo a = addClass("a");
EClassInfo b = addClass("b");
EClassInfo c = addClass("c");
b.addSupertype(a);
c.addSupertype(a);
addAttribute(b, INT, "f1");
addAttribute(c, STRING, "f1");
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
assertEquals(1, c.getEClass().getEStructuralFeatures().size());
liftUpFeatures();
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
assertEquals(1, c.getEClass().getEStructuralFeatures().size());
}
public void testReferences() throws Exception {
EClassInfo a = addClass("a");
EClassInfo b = addClass("b");
EClassInfo c = addClass("c");
EClassInfo d = addClass("d");
b.addSupertype(a);
c.addSupertype(a);
addReference(b, d, "r1");
addReference(c, d, "r1");
assertEquals(0, a.getEClass().getEStructuralFeatures().size());
assertEquals(1, b.getEClass().getEStructuralFeatures().size());
assertEquals(1, c.getEClass().getEStructuralFeatures().size());
liftUpFeatures();
assertEquals(1, a.getEClass().getEStructuralFeatures().size());
assertEquals(0, b.getEClass().getEStructuralFeatures().size());
assertEquals(0, c.getEClass().getEStructuralFeatures().size());
}
public void testDublicateDerivedFeature() throws Exception {
EClassInfo a = addClass("a");
EClassInfo b = addClass("b");
EClassInfo c = addClass("b");
b.addSupertype(a);
c.addSupertype(b);
addAttribute(a, INT, "f");
addAttribute(c, INT, "f");
assertEquals(1, a.getEClass().getEStructuralFeatures().size());
assertEquals(0, b.getEClass().getEStructuralFeatures().size());
assertEquals(1, c.getEClass().getEStructuralFeatures().size());
helper = new TypeHierarchyHelper(infos);
helper.removeDuplicateDerivedFeatures();
assertEquals(1, a.getEClass().getEStructuralFeatures().size());
assertEquals(0, b.getEClass().getEStructuralFeatures().size());
assertEquals(0, c.getEClass().getEStructuralFeatures().size());
}
}

View file

@ -234,14 +234,13 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertEquals(ruleA, ruleC.getESuperTypes().get(0));
// test all features are separated
assertEquals(0, ruleA.getEAttributes().size());
assertEquals(2, ruleB.getEAttributes().size());
assertAttributeConfiguration(ruleB, 0, "featureA", "EString");
assertAttributeConfiguration(ruleB, 1, "featureB", "EString");
assertEquals(3, ruleC.getEAttributes().size());
assertEquals(1, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "featureA", "EString");
assertEquals(1, ruleB.getEAttributes().size());
assertAttributeConfiguration(ruleB, 0, "featureB", "EString");
assertEquals(2, ruleC.getEAttributes().size());
assertAttributeConfiguration(ruleC, 0, "featureC1", "EString");
assertAttributeConfiguration(ruleC, 1, "featureA", "EString");
assertAttributeConfiguration(ruleC, 2, "featureC2", "EString");
assertAttributeConfiguration(ruleC, 1, "featureC2", "EString");
}
public void testFeaturesAndInheritanceOfOptionalOptionalRuleCalls() throws Exception {
@ -273,7 +272,11 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
}
public void testFeaturesAndInheritanceOfNestedRuleCalls() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: ((RuleB|RuleC featureC1=ID)? featureBC=ID | (RuleC|RuleD featureD1=ID) featureCD=ID) featureA=ID; RuleB: featureB2=ID; RuleC: featureC2=ID; RuleD: featureD2=ID;";
String grammar = "language test generate test 'http://test'";
grammar += " RuleA: ((RuleB|RuleC featureC1=ID)? featureBC=ID | (RuleC|RuleD featureD1=ID) featureCD=ID) featureA=ID;";
grammar += " RuleB: featureB2=ID;";
grammar += " RuleC: featureC2=ID;";
grammar += " RuleD: featureD2=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(4, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
@ -300,16 +303,14 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertAttributeConfiguration(ruleA, 1, "featureA", "EString");
assertEquals(1, ruleB.getEAttributes().size());
assertAttributeConfiguration(ruleB, 0, "featureB2", "EString");
assertEquals(4, ruleC.getEAttributes().size());
assertEquals(3, ruleC.getEAttributes().size());
assertAttributeConfiguration(ruleC, 0, "featureC1", "EString");
assertAttributeConfiguration(ruleC, 1, "featureCD", "EString");
assertAttributeConfiguration(ruleC, 2, "featureA", "EString");
assertAttributeConfiguration(ruleC, 3, "featureC2", "EString");
assertEquals(4, ruleD.getEAttributes().size());
assertAttributeConfiguration(ruleC, 2, "featureC2", "EString");
assertEquals(3, ruleD.getEAttributes().size());
assertAttributeConfiguration(ruleD, 0, "featureD1", "EString");
assertAttributeConfiguration(ruleD, 1, "featureCD", "EString");
assertAttributeConfiguration(ruleD, 2, "featureA", "EString");
assertAttributeConfiguration(ruleD, 3, "featureD2", "EString");
assertAttributeConfiguration(ruleD, 2, "featureD2", "EString");
}
public void testFeaturesAndInheritanceOfActions01() throws Exception {
@ -331,15 +332,16 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertEquals(ruleA, sub.getESuperTypes().get(0));
// test features
assertEquals(0, ruleA.getEAttributes().size());
assertEquals(1, add.getEAttributes().size());
assertAttributeConfiguration(add, 0, "featureAS", "EString");
assertEquals(1, add.getEReferences().size());
assertReferenceConfiguration(add, 0, "a", "RuleA", true, 0, 1);
assertEquals(1, sub.getEAttributes().size());
assertAttributeConfiguration(sub, 0, "featureAS", "EString");
assertEquals(1, sub.getEReferences().size());
assertReferenceConfiguration(sub, 0, "a", "RuleA", true, 0, 1);
assertEquals(1, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "featureAS", "EString");
assertEquals(1, ruleA.getEReferences().size());
assertReferenceConfiguration(ruleA, 0, "a", "RuleA", false, 0, 1);
assertEquals(0, add.getEAttributes().size());
assertEquals(0, add.getEReferences().size());
assertEquals(0, sub.getEAttributes().size());
assertEquals(0, sub.getEReferences().size());
}
public void testFeaturesAndInheritanceOfActions02() throws Exception {
@ -421,7 +423,7 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
grammar += " RuleC: featureC=ID;";
grammar += " RuleD returns TypeB: featureD=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
@ -495,14 +497,13 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
grammar += " generate t2 'http://t2' as target";
grammar += " RuleA: featureA=ID;"; // no alias => cannot be created
grammar += " RuleB returns target::TypeB: featureB=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.AliasForMetamodelAlreadyExists), (String) anyObject(),
(EObject) anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.CannotCreateTypeInSealedMetamodel), (String) anyObject(),
(EObject) anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.NoSuchTypeAvailable), (String) anyObject(),
(EObject) anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.NoSuchTypeAvailable), (String) anyObject(), (EObject) anyObject());
List<EPackage> ePackages = getEPackagesFromGrammar(grammar);
assertEquals(1, ePackages.size());
EPackage t1 = ePackages.get(0);
@ -557,12 +558,10 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
}
public void testAddingDifferentFeaturesWithSameName01() throws Exception {
// simple datatypes do not have a common compatible type
final String grammar = "" +
" language test generate test 'http://test'" +
" RuleA returns TypeA: featureA=ID;" +
" RuleB returns TypeA: featureA=INT;";
// simple datatypes do not have a common compatible type
final String grammar = "" + " language test generate test 'http://test'" + " RuleA returns TypeA: featureA=ID;"
+ " RuleB returns TypeA: featureA=INT;";
errorAcceptorMock.acceptError(same(ErrorCode.NoCompatibleFeatureTypeAvailable), (String) anyObject(),
(EObject) anyObject());
EPackage ePackage = getEPackageFromGrammar(grammar);
@ -581,7 +580,7 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
grammar += " RuleC: RuleD;";
grammar += " RuleD: featureD=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass typeA = (EClass) ePackage.getEClassifier("TypeA");
assertNotNull(typeA);
@ -602,7 +601,7 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
grammar += " RuleC: featureC=INT;";
grammar += " RuleD: featureD=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass typeA = (EClass) ePackage.getEClassifier("TypeA");
assertNotNull(typeA);
@ -614,9 +613,49 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertEquals(2, typeA.getEAllAttributes().size());
assertAttributeConfiguration(typeA, 0, "featureA1", "EString");
assertAttributeConfiguration(typeA, 1, "featureA4", "EInt");
assertEquals(2, typeA.getEReferences().size());
assertReferenceConfiguration(typeA, 0, "featureA2", "EObject", true, 0, 1);
assertReferenceConfiguration(typeA, 1, "featureA3", "RuleC", true, 0, 1);
}
public void testUplift01() throws Exception {
String grammar = "language test generate test 'http://test'";
grammar += " RuleA: (RuleB|RuleC) featureA=ID;";
grammar += " RuleB: featureB=INT;";
grammar += " RuleC: (featureA=ID)?;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
EClass ruleB = (EClass) ePackage.getEClassifier("RuleB");
assertNotNull(ruleB);
EClass ruleC = (EClass) ePackage.getEClassifier("RuleC");
assertNotNull(ruleC);
assertEquals(1, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "featureA", "EString");
assertEquals(1, ruleB.getEAttributes().size());
assertAttributeConfiguration(ruleB, 0, "featureB", "EInt");
assertEquals(0, ruleC.getEAttributes().size());
}
public void testCallOfUndeclaredRule() throws Exception {
String grammar = "language test generate test 'http://test'";
grammar += " RuleA: CallOfUndeclaredRule featureA=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.NoSuchRuleAvailable), (String) anyObject(),
(EObject) anyObject());
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(1, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
assertEquals(1, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "featureA", "EString");
}
}