/******************************************************************************* * Copyright (c) 2004, 2009 QNX Software Systems 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 * * Contributors: * QNX Software Systems - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.browser; import java.util.ArrayList; import java.util.List; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.IMember; import org.eclipse.cdt.core.model.IMethodDeclaration; import org.eclipse.cdt.core.model.IParent; import org.eclipse.cdt.core.model.IStructure; import org.eclipse.cdt.core.model.ITranslationUnit; /** * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ public class TypeUtil { public static boolean isDeclaringType(ICElement elem) { int type = elem.getElementType(); return (type == ICElement.C_CLASS || type == ICElement.C_STRUCT || type == ICElement.C_ENUMERATION || type == ICElement.C_UNION || type == ICElement.C_TYPEDEF || type == ICElement.C_NAMESPACE); } public static boolean isMemberType(ICElement elem) { int type = elem.getElementType(); if (type == ICElement.C_CLASS || type == ICElement.C_STRUCT || type == ICElement.C_ENUMERATION || type == ICElement.C_UNION || type == ICElement.C_TYPEDEF || type == ICElement.C_NAMESPACE) return true; return elem instanceof IMember; } /** * Returns the type in which this member is declared, or <code>null</code> * if this member is not declared in a type (for example, a top-level type). * This is a handle-only method. * * @return the type in which this member is declared, or <code>null</code> * if this member is not declared in a type (for example, a top-level type) */ public static ICElement getDeclaringType(ICElement elem) { if (!isMemberType(elem)) return null; ICElement parent = elem.getParent(); while (parent != null && !(parent instanceof ITranslationUnit)) { if (isDeclaringType(parent)) return parent; parent = parent.getParent(); } return null; } public static ICElement getDeclaringClass(ICElement type) { ICElement parentElement = type.getParent(); if (parentElement != null && isClassOrStruct(parentElement)) { return parentElement; } if (isClassOrStruct(type)) { while (parentElement != null) { if (isClassOrStruct(parentElement)) { return parentElement; } else if (parentElement instanceof IMember) { parentElement = parentElement.getParent(); } else { return null; } } } return null; } public static boolean isClassOrStruct(ICElement type) { int kind = type.getElementType(); // case ICElement.C_TEMPLATE_CLASS: // case ICElement.C_TEMPLATE_STRUCT: return (kind == ICElement.C_CLASS || kind == ICElement.C_STRUCT); } public static boolean isClass(ICElement type) { return (type.getElementType() == ICElement.C_CLASS); } public static boolean isNamespace(ICElement type) { return (type.getElementType() == ICElement.C_NAMESPACE); } /** * Returns the top-level types declared in the given translation unit * in the order in which they appear in the source. * * @param tu the translation unit * @return the top-level types declared in the given translation unit * @throws CModelException if this element does not exist or if an * exception occurs while accessing its corresponding resource */ public static ICElement[] getTypes(ITranslationUnit tu) throws CModelException { List<ICElement> typeList = new ArrayList<ICElement>(); ICElement[] children = tu.getChildren(); for (int i = 0; i < children.length; ++i) { if (isDeclaringType(children[i])) typeList.add(children[i]); } return typeList.toArray(new ICElement[typeList.size()]); } /** * Returns all types declared in the given translation unit in the order * in which they appear in the source. * This includes all top-level types and nested member types. * It does NOT include local types (types defined in methods). * * @return the array of top-level and member types defined in the given translation unit, in declaration order. * @throws CModelException if this element does not exist or if an * exception occurs while accessing its corresponding resource */ public static ICElement[] getAllTypes(ITranslationUnit tu) throws CModelException { ICElement[] types = getTypes(tu); ArrayList<ICElement> allTypes = new ArrayList<ICElement>(types.length); ArrayList<ICElement> typesToTraverse = new ArrayList<ICElement>(types.length); for (ICElement type : types) { typesToTraverse.add(type); } while (!typesToTraverse.isEmpty()) { ICElement type = typesToTraverse.get(0); typesToTraverse.remove(type); allTypes.add(type); types = getTypes(type); for (ICElement type2 : types) { typesToTraverse.add(type2); } } return allTypes.toArray(new ICElement[allTypes.size()]); } /** * Returns the immediate member types declared by the given element. * The results are listed in the order in which they appear in the source file. * * @param elem the element * @exception CModelException if this element does not exist or if an * exception occurs while accessing its corresponding resource. * @return the immediate member types declared by this type */ public static ICElement[] getTypes(ICElement elem) throws CModelException { List<ICElement> typeList = new ArrayList<ICElement>(); if (isDeclaringType(elem) && elem instanceof IParent) { ICElement[] children = ((IParent)elem).getChildren(); for (int i = 0; i < children.length; ++i) { if (isDeclaringType(children[i])) typeList.add(children[i]); } } return typeList.toArray(new ICElement[typeList.size()]); } public static ITranslationUnit getTranslationUnit(ICElement elem) { while (elem != null) { if (elem instanceof ITranslationUnit) return (ITranslationUnit)elem; elem = elem.getParent(); } return null; } // TODO move method to CModelUtil public static IQualifiedTypeName getFullyQualifiedName(ICElement type) { String name = type.getElementName(); IQualifiedTypeName qualifiedName = new QualifiedTypeName(name); ICElement parent = type.getParent(); while (parent != null && (isNamespace(parent) || isClass(parent))) { qualifiedName = new QualifiedTypeName(parent.getElementName()).append(qualifiedName); parent = parent.getParent(); } return qualifiedName; } public static IMethodDeclaration[] getMethods(ICElement elem) { if (elem instanceof IStructure) { try { List<?> list = ((IParent)elem).getChildrenOfType(ICElement.C_METHOD_DECLARATION); if (list != null && !list.isEmpty()) { return list.toArray(new IMethodDeclaration[list.size()]); } } catch (CModelException e) { } } return null; } public static ICElement[] getFields(ICElement elem) { if (elem instanceof IStructure) { try { List<?> list = ((IParent)elem).getChildrenOfType(ICElement.C_FIELD); if (list != null && !list.isEmpty()) { return list.toArray(new ICElement[list.size()]); } } catch (CModelException e) { } } return null; } /** * Finds a method by name. * This searches for a method with a name and signature. Parameter types are only * compared by the simple name, no resolving for the fully qualified type name is done. * Constructors are only compared by parameters, not the name. * @param name The name of the method to find * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code> * @param isConstructor If the method is a constructor * @param methods The methods to search in * @return The found method or <code>null</code>, if nothing found */ // TODO move methods to CModelUtil public static IMethodDeclaration findMethod(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, IMethodDeclaration[] methods) throws CModelException { for (int i= methods.length - 1; i >= 0; i--) { if (isSameMethodSignature(name, paramTypes, isConstructor, isDestructor, methods[i])) { return methods[i]; } } return null; } /** * Tests if a method equals to the given signature. * Parameter types are only compared by the simple name, no resolving for * the fully qualified type name is done. Constructors are only compared by * parameters, not the name. * @param name Name of the method * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code> * @param isConstructor Specifies if the method is a constructor * @return Returns <code>true</code> if the method has the given name and parameter types and constructor state. */ //TODO move methods to CModelUtil public static boolean isSameMethodSignature(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, IMethodDeclaration curr) throws CModelException { if (isConstructor || isDestructor || name.equals(curr.getElementName())) { if ((isConstructor == curr.isConstructor()) && (isDestructor == curr.isDestructor())) { String[] currParamTypes= curr.getParameterTypes(); if (paramTypes.length == currParamTypes.length) { for (int i= 0; i < paramTypes.length; i++) { // TODO should compare signatures String t1= paramTypes[i]; String t2= currParamTypes[i]; if (!t1.equals(t2)) { return false; } } return true; } } } return false; } /** * Finds a method in a type. * This searches for a method with the same name and signature. Parameter types are only * compared by the simple name, no resolving for the fully qualified type name is done. * Constructors are only compared by parameters, not the name. * @param name The name of the method to find * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code> * @param isConstructor If the method is a constructor * @return The first found method or <code>null</code>, if nothing found */ // TODO move methods to CModelUtil public static IMethodDeclaration findMethod(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, ICElement type) throws CModelException { return findMethod(name, paramTypes, isConstructor, isDestructor, getMethods(type)); } }