/*******************************************************************************
* 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.emftext.language.java.arrays.ArrayTypeable;
import org.emftext.language.java.classifiers.Classifier;
import org.emftext.language.java.generics.TypeParameter;
import org.emftext.language.java.references.ElementReference;
import org.emftext.language.java.references.MethodCall;
import org.emftext.language.java.references.Reference;
import org.emftext.language.java.references.ReferenceableElement;
import org.emftext.language.java.types.ClassifierReference;
import org.emftext.language.java.types.NamespaceClassifierReference;
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.TypesFactory;
public class TypeReferenceExtension {
/**
* Returns the type referenced by this <code>TypeReference</code>
* considering all concrete subclasses of <code>TypeReference</code> used
* by the Java metamodel.
*
* @return the referenced type
*/
public static Type getTarget(TypeReference me) {
return me.getBoundTarget(null);
}
/**
* Sets the type targeted by this type reference
*
* @param type the new type to set as target
*/
public static void setTarget(TypeReference me, Classifier type) {
if (type == null) {
return;
}
if (type.eIsProxy()) {
return;
}
if (me instanceof NamespaceClassifierReference) {
NamespaceClassifierReference nsClassifierReference = (NamespaceClassifierReference) me;
nsClassifierReference.getClassifierReferences().clear();
nsClassifierReference.getNamespaces().clear();
nsClassifierReference.getNamespaces().addAll(type.getContainingContainerName());
ClassifierReference classifierRef = TypesFactory.eINSTANCE.createClassifierReference();
classifierRef.setTarget(type);
nsClassifierReference.getClassifierReferences().add(classifierRef);
}
}
/**
* Returns the type referenced by this <code>TypeReference</code>
* considering all concrete subclasses of <code>TypeReference</code> used by
* the Java metamodel. If type parameters are bound in the given reference,
* the bound type will be returned instead of the parameter.
*
* @param reference
*
* @return the referenced type
*/
public static Type getBoundTarget(TypeReference me, Reference reference) {
Type type = null;
if (me instanceof ClassifierReference ||
me instanceof NamespaceClassifierReference) {
ClassifierReference classifierRef = me.getPureClassifierReference();
if (classifierRef != null) {
type = classifierRef.getTarget();
}
if (reference instanceof MethodCall) {
MethodCall potentialCloneCall = (MethodCall) reference;
//clone returns the type of the cloned in the case of arrays
ReferenceableElement potentialCloneCallTarget = potentialCloneCall.getTarget();
if (potentialCloneCallTarget != null &&
!potentialCloneCallTarget.eIsProxy() &&
"clone".equals(potentialCloneCallTarget.getName())) {
if (potentialCloneCall.getPrevious() instanceof ElementReference) {
ElementReference prevRef = (ElementReference) potentialCloneCall.getPrevious();
if (prevRef.getTarget() instanceof ArrayTypeable &&
((ArrayTypeable)prevRef.getTarget()).getArrayDimension() > 0) {
type = prevRef.getReferencedType();
}
}
}
}
}
else if (me instanceof PrimitiveType) {
return (PrimitiveType) me;
}
//resolve parameter to real type
if (type instanceof TypeParameter) {
type = ((TypeParameter) type).getBoundType(me, reference);
}
if (type != null && type.eIsProxy()) {
//this may happen, when e.g. a super type is resolved. It is ok.
return null;
}
return type;
}
/**
* Extracts the (possibly nested) classifier reference (if any) from this
* type references.
*
* @return
*/
public static ClassifierReference getPureClassifierReference(TypeReference me) {
ClassifierReference classifierReference = null;
if (me instanceof ClassifierReference) {
classifierReference = (ClassifierReference) me;
}
if (me instanceof NamespaceClassifierReference) {
NamespaceClassifierReference nsClassifierReference = (NamespaceClassifierReference) me;
if (!nsClassifierReference.getClassifierReferences().isEmpty()) {
int lastIndex = nsClassifierReference.getClassifierReferences().size() - 1;
classifierReference = nsClassifierReference.getClassifierReferences().get(lastIndex);
}
}
return classifierReference;
}
}