/******************************************************************************* * Copyright (c) 2006-2014 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * 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 * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ package org.emftext.language.java.extensions.types; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.emftext.language.java.arrays.ArrayTypeable; import org.emftext.language.java.classifiers.Annotation; import org.emftext.language.java.classifiers.AnonymousClass; import org.emftext.language.java.classifiers.Classifier; import org.emftext.language.java.classifiers.ConcreteClassifier; import org.emftext.language.java.classifiers.Interface; import org.emftext.language.java.generics.TypeParameter; import org.emftext.language.java.members.Member; import org.emftext.language.java.parameters.VariableLengthParameter; import org.emftext.language.java.types.PrimitiveType; import org.emftext.language.java.types.Type; import org.emftext.language.java.types.TypeReference; import org.emftext.language.java.types.TypedElement; import org.emftext.language.java.util.TemporalCompositeClassifier; import org.emftext.language.java.util.UniqueEList; public class TypeExtension { /** * @param arrayDimension * @param otherType * @param otherArrayDimension * * @return if both type are equal */ public static boolean equalsType(Type me, long arrayDimension, Type otherType, long otherArrayDimension) { Type lOtherType = otherType; Type _this = me; //comparison for type parameters if (_this instanceof TypeParameter) { TypeParameter typeParameter = (TypeParameter) _this; for (TypeReference referencedType : typeParameter.getExtendTypes()) { if (referencedType.getTarget() != null && !referencedType.getTarget().eIsProxy() && referencedType.getTarget().equalsType(arrayDimension, lOtherType, otherArrayDimension)) { return true; } } if (typeParameter.getExtendTypes().isEmpty()) { if (me.getObjectClass().equalsType(arrayDimension, lOtherType, otherArrayDimension)) { return true; } } } if (lOtherType instanceof TypeParameter) { TypeParameter typeParameter = (TypeParameter) lOtherType; for (TypeReference referencedType : typeParameter.getExtendTypes()) { if (referencedType.getTarget() != null && !referencedType.getTarget().eIsProxy() && me.equalsType(arrayDimension, referencedType.getTarget(), otherArrayDimension)) { return true; } } if (typeParameter.getExtendTypes().isEmpty()) { if (me.equalsType(arrayDimension, me.getObjectClass(), otherArrayDimension)) { return true; } } } //do comparison on the classifier level if (_this instanceof PrimitiveType) { _this = ((PrimitiveType)_this).wrapPrimitiveType(); } if (lOtherType instanceof PrimitiveType) { lOtherType = ((PrimitiveType) lOtherType).wrapPrimitiveType(); } if (arrayDimension == otherArrayDimension && lOtherType instanceof Classifier && _this instanceof Classifier && (lOtherType.equals(_this))) { return true; } return false; } /** * @param arrayDimension * @param otherType * @param otherArrayType * @param otherArrayType * @return if the other type is equal to me or a super type of me */ public static boolean isSuperType(Type me, long arrayDimension, Type otherType, ArrayTypeable otherArrayType) { Type lOtherType = otherType; if (lOtherType == null) { return false; } Type _this = me; if (_this instanceof TemporalCompositeClassifier || lOtherType instanceof TemporalCompositeClassifier) { EList<Type> _thisTypeList = new UniqueEList<Type>(); EList<Type> otherTypeList = new UniqueEList<Type>(); if (_this instanceof TemporalCompositeClassifier) { for(EObject aType : ((TemporalCompositeClassifier)_this).getSuperTypes()) { _thisTypeList.add((Type)aType); } } else { _thisTypeList.add(_this); } if (lOtherType instanceof TemporalCompositeClassifier) { for(EObject aType : ((TemporalCompositeClassifier)lOtherType).getSuperTypes()) { otherTypeList.add((Type)aType); } } else { otherTypeList.add(_this); } for(Type one_thisType : _thisTypeList) { for(Type oneOtherType : otherTypeList) { boolean result = one_thisType.isSuperType(arrayDimension, oneOtherType, otherArrayType); if (result) { return true; } } } return false; } //if I am a void, I am of every type if (_this.equals(me.getLibClass("Void"))) { return true; } //if the other is Object I am a subtype in any case (also array dimensions do not matter) if (lOtherType.equals(me.getObjectClass())) { return true; } //String, primitives, and arrays are serializable ConcreteClassifier serializableClass = (ConcreteClassifier) EcoreUtil.resolve( me.getConcreteClassifierProxy("java.io.Serializable"), _this); if (lOtherType.equals(serializableClass)) { if (_this.equals(serializableClass)) { return true; } else if (_this.equals(me.getStringClass())) { return true; } else if (_this instanceof PrimitiveType) { return true; } else if (arrayDimension > 0) { //all arrays are serializable return true; } } //if one of us is a parameter to the best of my knowledge, we might match if (_this instanceof TypeParameter) { return true; } if (lOtherType instanceof TypeParameter) { return true; } //if array dimensions do not match, I am no subtype boolean isTypeParameter = false; if (otherArrayType instanceof TypedElement) { Type type = ((TypedElement)otherArrayType).getTypeReference().getTarget(); isTypeParameter = type instanceof TypeParameter; } boolean isVariableLengthParameter = otherArrayType instanceof VariableLengthParameter; long otherArrayDim = 0; if(otherArrayType != null) { otherArrayDim = otherArrayType.getArrayDimension(); } if (isTypeParameter && isVariableLengthParameter) { if(arrayDimension != otherArrayDim && arrayDimension != otherArrayDim-1 && arrayDimension < otherArrayDim) { return false; } } else if (isTypeParameter) { if(arrayDimension < otherArrayDim) { return false; } } else if (isVariableLengthParameter) { if(arrayDimension != otherArrayDim && arrayDimension != otherArrayDim-1) { return false; } } else { if(arrayDimension != otherArrayDim) { return false; } } //annotations if(_this instanceof Annotation && (lOtherType.equals(me.getAnnotationInterface()) || ((ConcreteClassifier)_this).getAllSuperClassifiers( ).contains(me.getAnnotationInterface()))) { return true; } //do comparison on the classifier level if (_this instanceof PrimitiveType) { _this = ((PrimitiveType) _this).wrapPrimitiveType(); } if (lOtherType instanceof PrimitiveType) { lOtherType = ((PrimitiveType) lOtherType).wrapPrimitiveType(); } //compare in type hierarchy if (lOtherType instanceof ConcreteClassifier && _this instanceof ConcreteClassifier && (lOtherType.equals(_this) || ((ConcreteClassifier)_this).getAllSuperClassifiers( ).contains(lOtherType))) { return true; } if (lOtherType instanceof ConcreteClassifier && _this instanceof AnonymousClass && ((AnonymousClass)_this).getAllSuperClassifiers( ).contains(lOtherType)) { return true; } //everything can be implicitly casted to CharSequence, so I match when the other type is a CharSequence Interface charSequenceClass = me.getLibInterface("CharSequence"); if (lOtherType instanceof ConcreteClassifier) { if(lOtherType.equals(charSequenceClass) || ((ConcreteClassifier)lOtherType).getAllSuperClassifiers( ).contains(charSequenceClass)) { return true; } } //there are some specifics for primitive types not reflected in the type hierarchy if (lOtherType instanceof org.emftext.language.java.classifiers.Class) { PrimitiveType primitiveType = ((org.emftext.language.java.classifiers.Class) lOtherType).unWrapPrimitiveType(); if(primitiveType == null) { return false; } lOtherType = primitiveType; } // FIXME This is duplicate if (_this instanceof org.emftext.language.java.classifiers.Class) { PrimitiveType primitiveType = ((org.emftext.language.java.classifiers.Class) _this).unWrapPrimitiveType(); if(primitiveType == null) { return false; } _this = primitiveType; } if (_this instanceof org.emftext.language.java.types.Boolean) { if (lOtherType instanceof org.emftext.language.java.types.Boolean) { return true; } else { return false; } } if (_this instanceof org.emftext.language.java.types.Byte || _this instanceof org.emftext.language.java.types.Int || _this instanceof org.emftext.language.java.types.Short || _this instanceof org.emftext.language.java.types.Long || _this instanceof org.emftext.language.java.types.Char) { if (lOtherType instanceof org.emftext.language.java.types.Byte || lOtherType instanceof org.emftext.language.java.types.Int || lOtherType instanceof org.emftext.language.java.types.Short || lOtherType instanceof org.emftext.language.java.types.Long || lOtherType instanceof org.emftext.language.java.types.Char || lOtherType instanceof org.emftext.language.java.types.Float || lOtherType instanceof org.emftext.language.java.types.Double) { return true; } else { return false; } } if (_this instanceof org.emftext.language.java.types.Float || _this instanceof org.emftext.language.java.types.Double) { if (lOtherType instanceof org.emftext.language.java.types.Float || lOtherType instanceof org.emftext.language.java.types.Double) { return true; } else { return false; } } return false; } public static EList<Member> getAllMembers(Type me) { //method has to be specified in subclasses throw new UnsupportedOperationException(); } }