blob: 401baa81a766522dcdcfec8443e9cd46f74a478c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2010 BMW Car IT, Technische Universitaet Muenchen, and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* BMW Car IT - Initial API and implementation
* Technische Universitaet Muenchen - Major refactoring and extension
*******************************************************************************/
package org.eclipse.emf.edapt.internal.common;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
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.EcorePackage;
/**
* Helper methods for inheritance of Ecore classes
*
* @author herrmama
* @author $Author$
* @version $Rev$
* @levd.rating RED Rev:
*/
public final class TypeUtils {
/**
* Constructor
*/
private TypeUtils() {
// hidden, since this class only provides static helper methods
}
/**
* Get the wrapped least common ancestor of a collection of classes
*
* @param classes
* Collection of classes
* @return Wrapped least common ancestor
*/
public static EClass leastCommonAncestor(Collection<EClass> classes) {
return wrap(leastCommonAncestorHelper(classes));
}
/**
* Get the least common ancestor of a collection of classes
*
* @param classes Collection of classes
* @return Least common ancestor
*/
private static EClass leastCommonAncestorHelper(Collection<EClass> classes) {
if (classes.isEmpty()) {
return null;
} else if (classes.size() == 1) {
return classes.iterator().next();
} else {
final Iterator<EClass> i = classes.iterator();
EClass lca = i.next();
while (i.hasNext()) {
if (lca == null) {
break;
}
lca = leastCommonAncestorHelper(lca, i.next());
}
return lca;
}
}
/**
* Get the wrapped least common ancestor of two classes
*
* @param class1 First class
* @param class2 Second class
* @return Wrapped least common ancestor
*/
public static EClass leastCommonAncestor(EClass class1, EClass class2) {
return wrap(leastCommonAncestorHelper(class1, class2));
}
/**
* Helper method to wrap a null result by the EObject class (ancestor of all classes)
*
* @param c Class
* @return Replaced class
*/
static EClass wrap(EClass c) {
return c == null ? EcorePackage.eINSTANCE.getEObject() : c;
}
/**
* Get the least common ancestor of two classes
*
* @param class1 First class
* @param class2 Second class
* @return Least common ancestor
*/
static EClass leastCommonAncestorHelper(EClass class1, EClass class2) {
if (ancestor(class1, class2)) {
return class2;
} else if (ancestor(class2, class1)) {
return class1;
} else {
EClass ancestor1 = superClass(class1);
while (ancestor1 != null) {
if (ancestor(class2, ancestor1)) {
return ancestor1;
}
ancestor1 = superClass(ancestor1);
}
EClass ancestor2 = superClass(class2);
while (ancestor2 != null) {
if (ancestor(class1, ancestor2)) {
return ancestor2;
}
ancestor2 = superClass(ancestor2);
}
return null;
}
}
/**
* Decide whether the second class is an ancestor of the first class
*
* @param class1 First class
* @param class2 Second class
* @return true if the second class is an ancestor of the first class, false otherwise
*/
public static boolean ancestor(EClass class1, EClass class2) {
if (class1 == class2) {
return true;
} else if (class2 == EcorePackage.eINSTANCE.getEObject()) {
return true;
} else if (class2 == null) {
return true;
} else if (class1 == null) {
return false;
} else {
return ancestor(superClass(class1), class2);
}
}
/**
* Get superclass of a class (multiple inheritance is not used in the Ecore core model)
*
* @param c class
* @return Super class
*/
static EClass superClass(EClass c) {
if (c.getESuperTypes().isEmpty()) {
return null;
}
return c.getESuperTypes().get(0);
}
/**
* Calculate the common super class of a list of instances
*
* @param elements List of instances
* @return Common super class
*/
public static EClass commonSuperClass(List<EObject> elements) {
final Set<EClass> classes = new HashSet<EClass>();
for (final Iterator<EObject> i = elements.iterator(); i.hasNext();) {
classes.add(i.next().eClass());
}
return leastCommonAncestor(classes);
}
/**
* Check whether a type can be used in the context where another type is expected
*
* @param classifier Actual type
* @param withClassifier Expected type
* @return true if the actual type is compatible with the expected type, false otherwise
*/
public static boolean isCompatible(EClassifier classifier, EClassifier withClassifier) {
if (classifier instanceof EDataType) {
return classifier == withClassifier;
}
final EClass clazz = (EClass) classifier;
if (withClassifier instanceof EClass) {
final EClass withClazz = (EClass) withClassifier;
return ancestor(clazz, withClazz);
}
return false;
}
}