diff --git a/core/org.eclipse.cdt.core/ChangeLog b/core/org.eclipse.cdt.core/ChangeLog
index 2026c6e5b89..6eb42969d5c 100644
--- a/core/org.eclipse.cdt.core/ChangeLog
+++ b/core/org.eclipse.cdt.core/ChangeLog
@@ -1,3 +1,8 @@
+2004-07-15 Chris Wiebe
+
+ Initial draft for the type hierarchy view.
+ * browser/*
+
2004-07-06 Bogdan Gheorghe
Handled the case of CContainer in both updateIndexAddResource and
updateIndexRemoveResource.
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
index 2ba97fc17ff..f0dbf6ee405 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
@@ -14,6 +14,8 @@ import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
+import org.eclipse.cdt.core.browser.typehierarchy.TypeHierarchyBuilder;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ElementChangedEvent;
@@ -48,7 +50,7 @@ public class AllTypesCache {
private static final int INITIAL_DELAY = 5000;
private static IWorkingCopyProvider fgWorkingCopyProvider;
- private static TypeCacheManager fgTypeCacheManager;
+ private static TypeHierarchyBuilder fgTypeHierarchyBuilder;
private static IElementChangedListener fgElementChangedListener;
private static IPropertyChangeListener fgPropertyChangeListener;
private static boolean fgEnableIndexing = true;
@@ -63,7 +65,8 @@ public class AllTypesCache {
*/
public static void initialize(IWorkingCopyProvider workingCopyProvider) {
fgWorkingCopyProvider = workingCopyProvider;
- fgTypeCacheManager = new TypeCacheManager(fgWorkingCopyProvider);
+ TypeCacheManager.getInstance().setWorkingCopyProvider(fgWorkingCopyProvider);
+ fgTypeHierarchyBuilder = new TypeHierarchyBuilder();
// load prefs
Preferences prefs = CCorePlugin.getDefault().getPluginPreferences();
@@ -77,13 +80,13 @@ public class AllTypesCache {
}
// start jobs in background after INITIAL_DELAY
- fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY);
+ TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY);
// add delta listener
fgElementChangedListener = new IElementChangedListener() {
public void elementChanged(ElementChangedEvent event) {
- fgTypeCacheManager.processDelta(event.getDelta());
- fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
+ TypeCacheManager.getInstance().processDelta(event.getDelta());
+ TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
}
};
CoreModel.getDefault().addElementChangedListener(fgElementChangedListener);
@@ -96,9 +99,9 @@ public class AllTypesCache {
String value = (String) event.getNewValue();
fgEnableIndexing = Boolean.valueOf(value).booleanValue();
if (!fgEnableIndexing) {
- fgTypeCacheManager.cancelJobs();
+ TypeCacheManager.getInstance().cancelJobs();
} else {
- fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
+ TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
}
}
}
@@ -119,8 +122,8 @@ public class AllTypesCache {
CCorePlugin.getDefault().getPluginPreferences().removePropertyChangeListener(fgPropertyChangeListener);
// terminate all running jobs
- if (fgTypeCacheManager != null) {
- fgTypeCacheManager.cancelJobs();
+ if (TypeCacheManager.getInstance() != null) {
+ TypeCacheManager.getInstance().cancelJobs();
}
}
@@ -139,7 +142,7 @@ public class AllTypesCache {
public boolean shouldContinue() { return true; }
};
for (int i = 0; i < projects.length; ++i) {
- fgTypeCacheManager.getCache(projects[i]).accept(visitor);
+ TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
}
return (ITypeInfo[]) fAllTypes.toArray(new ITypeInfo[fAllTypes.size()]);
}
@@ -167,7 +170,7 @@ public class AllTypesCache {
public boolean shouldContinue() { return true; }
};
for (int i = 0; i < projects.length; ++i) {
- fgTypeCacheManager.getCache(projects[i]).accept(visitor);
+ TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
}
return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
}
@@ -198,7 +201,7 @@ public class AllTypesCache {
public boolean shouldContinue() { return true; }
};
for (int i = 0; i < projects.length; ++i) {
- fgTypeCacheManager.getCache(projects[i]).accept(visitor);
+ TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
}
return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
}
@@ -224,7 +227,7 @@ public class AllTypesCache {
public boolean shouldContinue() { return true; }
};
for (int i = 0; i < projects.length; ++i) {
- ITypeCache cache = fgTypeCacheManager.getCache(projects[i]);
+ ITypeCache cache = TypeCacheManager.getInstance().getCache(projects[i]);
cache.accept(visitor);
if (includeGlobalNamespace) {
fTypesFound.add(cache.getGlobalNamespace());
@@ -243,7 +246,7 @@ public class AllTypesCache {
for (int i = 0; i < projects.length; ++i) {
IProject project = projects[i];
if (project.exists() && project.isOpen()) {
- if (!fgTypeCacheManager.getCache(project).isUpToDate())
+ if (!TypeCacheManager.getInstance().getCache(project).isUpToDate())
return false;
}
}
@@ -277,7 +280,7 @@ public class AllTypesCache {
for (int i = 0; i < projects.length; ++i) {
IProject project = projects[i];
// wait for any running jobs to finish
- fgTypeCacheManager.getCache(project).reconcileAndWait(true, Job.SHORT, monitor);
+ TypeCacheManager.getInstance().getCache(project).reconcileAndWait(true, Job.SHORT, monitor);
}
monitor.done();
}
@@ -293,17 +296,36 @@ public class AllTypesCache {
if (location == null) {
// cancel background jobs
IProject project = info.getEnclosingProject();
- fgTypeCacheManager.getCache(project).cancelJobs();
+ TypeCacheManager.getInstance().getCache(project).cancelJobs();
// start the search job
- fgTypeCacheManager.getCache(project).locateTypeAndWait(info, Job.SHORT, monitor);
+ TypeCacheManager.getInstance().getCache(project).locateTypeAndWait(info, Job.SHORT, monitor);
// get the newly parsed location
location = info.getResolvedReference();
// resume background jobs
- fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
+ TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
}
return location;
}
+
+ public static ITypeInfo getTypeForElement(ICElement elem) {
+ return TypeUtil.getTypeForElement(elem);
+ }
+
+ /**
+ * Creates and returns a type hierarchy for this type containing
+ * this type and all of its supertypes and subtypes in the workspace.
+ *
+ * @param info the given type
+ * @param monitor the given progress monitor
+ * @return a type hierarchy for the given type
+ */
+ public static ITypeHierarchy createTypeHierarchy(ICElement type, IProgressMonitor monitor) throws CModelException {
+ ITypeInfo info = TypeUtil.getTypeForElement(type);
+ if (info != null)
+ return fgTypeHierarchyBuilder.createTypeHierarchy(info, fgEnableIndexing, monitor);
+ return null;
+ }
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java
index 64e4159d68e..9c1eb6aad5a 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java
@@ -11,6 +11,7 @@
package org.eclipse.cdt.core.browser;
import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
import org.eclipse.core.resources.IProject;
@@ -145,11 +146,6 @@ public interface ITypeInfo extends Comparable {
*/
public ITypeReference getResolvedReference();
- /**
- * Returns the corresponding CElement or null
if not found.
- */
- public ICElement getCElement();
-
/**
* Returns true if the type can be substituted.
*/
@@ -157,4 +153,52 @@ public interface ITypeInfo extends Comparable {
public ITypeCache getCache();
public void setCache(ITypeCache typeCache);
+
+ /**
+ * Returns true if other types extend this type.
+ */
+ public boolean hasSubTypes();
+
+ /** Gets all types which extend this type.
+ * @return array of types, or null
if none found.
+ */
+ public ITypeInfo[] getSubTypes();
+
+ /**
+ * Returns true if this type has base classes.
+ */
+ public boolean hasSuperTypes();
+
+ /** Gets the base classes.
+ * @return array of types, or null
if none found.
+ */
+ public ITypeInfo[] getSuperTypes();
+
+ /**
+ * Gets the base class access visibility (PRIVATE, PROTECTED, PUBLIC)
+ */
+ public ASTAccessVisibility getSuperTypeAccess(ITypeInfo subType);
+
+ /**
+ * Adds a derived class reference, i.e. this type is used as
+ * a base class at the given location.
+ */
+ public void addDerivedReference(ITypeReference location);
+
+ /** Gets the originating locations where this type was
+ * used as a base class.
+ * @return all known source references, or an empty
+ * array if none found.
+ */
+ public ITypeReference[] getDerivedReferences();
+
+ /**
+ * Returns true if the type is a class or struct.
+ */
+ public boolean isClass();
+
+ /**
+ * Returns true if type is referenced in the given scope.
+ */
+ public boolean isReferenced(ITypeSearchScope scope);
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/Signature.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/Signature.java
new file mode 100644
index 00000000000..316d3934892
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/Signature.java
@@ -0,0 +1,1997 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * IBM Corporation - added J2SE 1.5 support
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.internal.core.CharOperation;
+
+//TODO move this class to CoreModel?
+
+/**
+ * Provides methods for encoding and decoding type and method signature strings.
+ *
+ * Signatures obtained from parsing source (".java") files differ subtly from + * ones obtained from pre-compiled binary (".class") files in class names are + * usually left unresolved in the former. For example, the normal resolved form + * of the type "String" embeds the class's package name ("Ljava.lang.String;" + * or "Ljava/lang/String;"), whereas the unresolved form contains only what is + * written "QString;". + *
+ *
+ * Generic types introduce to the Java language in J2SE 1.5 add three new
+ * facets to signatures: type variables, parameterized types with type arguments,
+ * and formal type parameters.
+ * The syntax for a type signature is: + *
+ * TypeSignature ::= + * "B" // byte + * | "C" // char + * | "D" // double + * | "F" // float + * | "I" // int + * | "J" // long + * | "S" // short + * | "V" // void + * | "Z" // boolean + * | "T" + Identifier + ";" // type variable + * | "[" + TypeSignature // array X[] + * | ResolvedClassTypeSignature + * | UnresolvedClassTypeSignature + * + * ResolvedClassTypeSignature ::= // resolved named type (in compiled code) + * "L" + Identifier + OptionalTypeArguments + * ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";" + * + * UnresolvedClassTypeSignature ::= // unresolved named type (in source code) + * "Q" + Identifier + OptionalTypeArguments + * ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";" + * + * OptionalTypeArguments ::= + * "<" + TypeArgument+ + ">" + * | + * + * TypeArgument ::= + * | TypeSignature + * | "*" // wildcard ? + * | "+" TypeSignature // wildcard ? extends X + * | "-" TypeSignature // wildcard ? super X + *+ * + *
+ * Examples: + *
"[[I"
denotes int[][]
"Ljava.lang.String;"
denotes java.lang.String
in compiled code"QString;"
denotes String
in source code"Qjava.lang.String;"
denotes java.lang.String
in source code"[QString;"
denotes String[]
in source code"QMap<QString;*>;"
denotes Map<String,?>
in source code"Qjava.util.List<TV;>;"
denotes java.util.List<V>
in source code+ * The syntax for a method signature is: + *
+ * MethodSignature ::= "(" + ParamTypeSignature* + ")" + ReturnTypeSignature + * ParamTypeSignature ::= TypeSignature + * ReturnTypeSignature ::= TypeSignature + *+ *
+ * Examples: + *
"()I"
denotes int foo()
"([Ljava.lang.String;)V"
denotes void foo(java.lang.String[])
in compiled code"(QString;)QObject;"
denotes Object foo(String)
in source code+ * The syntax for a formal type parameter signature is: + *
+ * FormalTypeParameterSignature ::= + * TypeVariableName + OptionalClassBound + InterfaceBound* + * TypeVariableName ::= Identifier + * OptionalClassBound ::= + * ":" + * | ":" + TypeSignature + * InterfaceBound ::= + * ":" + TypeSignature + *+ *
+ * Examples: + *
"X:"
denotes X
"X:QReader;"
denotes X extends Reader
in source code"X:QReader;:QSerializable;"
denotes X extends Reader & Serializable
in source code+ * This class provides static methods and constants only; it is not intended to be + * instantiated or subclassed by clients. + *
+ */ +public final class Signature { + + /** + * Character constant indicating the primitive type boolean in a signature. + * Value is'Z'
.
+ */
+ public static final char C_BOOLEAN = 'Z';
+
+ /**
+ * Character constant indicating the primitive type byte in a signature.
+ * Value is 'B'
.
+ */
+ public static final char C_BYTE = 'B';
+
+ /**
+ * Character constant indicating the primitive type char in a signature.
+ * Value is 'C'
.
+ */
+ public static final char C_CHAR = 'C';
+
+ /**
+ * Character constant indicating the primitive type double in a signature.
+ * Value is 'D'
.
+ */
+ public static final char C_DOUBLE = 'D';
+
+ /**
+ * Character constant indicating the primitive type float in a signature.
+ * Value is 'F'
.
+ */
+ public static final char C_FLOAT = 'F';
+
+ /**
+ * Character constant indicating the primitive type int in a signature.
+ * Value is 'I'
.
+ */
+ public static final char C_INT = 'I';
+
+ /**
+ * Character constant indicating the semicolon in a signature.
+ * Value is ';'
.
+ */
+ public static final char C_SEMICOLON = ';';
+
+ /**
+ * Character constant indicating the colon in a signature.
+ * Value is ':'
.
+ * @since 3.0
+ */
+ public static final char C_COLON = ':';
+
+ /**
+ * Character constant indicating the primitive type long in a signature.
+ * Value is 'J'
.
+ */
+ public static final char C_LONG = 'J';
+
+ /**
+ * Character constant indicating the primitive type short in a signature.
+ * Value is 'S'
.
+ */
+ public static final char C_SHORT = 'S';
+
+ /**
+ * Character constant indicating result type void in a signature.
+ * Value is 'V'
.
+ */
+ public static final char C_VOID = 'V';
+
+ /**
+ * Character constant indicating result const in a signature.
+ * Value is 'K'
.
+ */
+ public static final char C_CONST = 'K';
+
+ /**
+ * Character constant indicating the start of a resolved type variable in a
+ * signature. Value is 'T'
.
+ * @since 3.0
+ */
+ public static final char C_TYPE_VARIABLE = 'T';
+
+ /**
+ * Character constant indicating a wildcard type argument
+ * in a signature.
+ * Value is '*'
.
+ * @since 3.0
+ */
+ public static final char C_STAR = '*';
+
+ /**
+ * Character constant indicating the dot in a signature.
+ * Value is '.'
.
+ */
+ public static final char C_DOT = '.';
+
+ /**
+ * Character constant indicating the dollar in a signature.
+ * Value is '$'
.
+ */
+ public static final char C_DOLLAR = '$';
+
+ /**
+ * Character constant indicating an array type in a signature.
+ * Value is '['
.
+ */
+ public static final char C_ARRAY = '[';
+
+ /**
+ * Character constant indicating the start of a resolved, named type in a
+ * signature. Value is 'L'
.
+ */
+ public static final char C_RESOLVED = 'L';
+
+ /**
+ * Character constant indicating the start of an unresolved, named type in a
+ * signature. Value is 'Q'
.
+ */
+ public static final char C_UNRESOLVED = 'Q';
+
+ /**
+ * Character constant indicating the end of a named type in a signature.
+ * Value is ';'
.
+ */
+ public static final char C_NAME_END = ';';
+
+ /**
+ * Character constant indicating the start of a parameter type list in a
+ * signature. Value is '('
.
+ */
+ public static final char C_PARAM_START = '(';
+
+ /**
+ * Character constant indicating the end of a parameter type list in a
+ * signature. Value is ')'
.
+ */
+ public static final char C_PARAM_END = ')';
+
+ /**
+ * Character constant indicating the start of a formal type parameter
+ * (or type argument) list in a signature. Value is '<'
.
+ * @since 3.0
+ */
+ public static final char C_GENERIC_START = '<';
+
+ /**
+ * Character constant indicating the end of a generic type list in a
+ * signature. Value is '%gt;'
.
+ * @since 3.0
+ */
+ public static final char C_GENERIC_END = '>';
+
+ /**
+ * String constant for the signature of the primitive type boolean.
+ * Value is "Z"
.
+ */
+ public static final String SIG_BOOLEAN = "Z"; //$NON-NLS-1$
+
+ /**
+ * String constant for the signature of the primitive type byte.
+ * Value is "B"
.
+ */
+ public static final String SIG_BYTE = "B"; //$NON-NLS-1$
+
+ /**
+ * String constant for the signature of the primitive type char.
+ * Value is "C"
.
+ */
+ public static final String SIG_CHAR = "C"; //$NON-NLS-1$
+
+ /**
+ * String constant for the signature of the primitive type double.
+ * Value is "D"
.
+ */
+ public static final String SIG_DOUBLE = "D"; //$NON-NLS-1$
+
+ /**
+ * String constant for the signature of the primitive type float.
+ * Value is "F"
.
+ */
+ public static final String SIG_FLOAT = "F"; //$NON-NLS-1$
+
+ /**
+ * String constant for the signature of the primitive type int.
+ * Value is "I"
.
+ */
+ public static final String SIG_INT = "I"; //$NON-NLS-1$
+
+ /**
+ * String constant for the signature of the primitive type long.
+ * Value is "J"
.
+ */
+ public static final String SIG_LONG = "J"; //$NON-NLS-1$
+
+ /**
+ * String constant for the signature of the primitive type short.
+ * Value is "S"
.
+ */
+ public static final String SIG_SHORT = "S"; //$NON-NLS-1$
+
+ /** String constant for the signature of result type void.
+ * Value is "V"
.
+ */
+ public static final String SIG_VOID = "V"; //$NON-NLS-1$
+
+
+ /**
+ * Kind constant for a class type signature.
+ * @see #getTypeSignatureKind(String)
+ * @since 3.0
+ */
+ public static int CLASS_TYPE_SIGNATURE = 1;
+
+ /**
+ * Kind constant for a base (primitive or void) type signature.
+ * @see #getTypeSignatureKind(String)
+ * @since 3.0
+ */
+ public static int BASE_TYPE_SIGNATURE = 2;
+
+ /**
+ * Kind constant for a type variable signature.
+ * @see #getTypeSignatureKind(String)
+ * @since 3.0
+ */
+ public static int TYPE_VARIABLE_SIGNATURE = 3;
+
+ /**
+ * Kind constant for an array type signature.
+ * @see #getTypeSignatureKind(String)
+ * @since 3.0
+ */
+ public static int ARRAY_TYPE_SIGNATURE = 4;
+
+ private static final char[] BOOLEAN = {'b', 'o', 'o', 'l', 'e', 'a', 'n'};
+ private static final char[] BYTE = {'b', 'y', 't', 'e'};
+ private static final char[] CHAR = {'c', 'h', 'a', 'r'};
+ private static final char[] DOUBLE = {'d', 'o', 'u', 'b', 'l', 'e'};
+ private static final char[] FLOAT = {'f', 'l', 'o', 'a', 't'};
+ private static final char[] INT = {'i', 'n', 't'};
+ private static final char[] LONG = {'l', 'o', 'n', 'g'};
+ private static final char[] SHORT = {'s', 'h', 'o', 'r', 't'};
+ private static final char[] VOID = {'v', 'o', 'i', 'd'};
+ private static final char[] CONST = {'c', 'o', 'n', 's', 't'};
+
+ private static final String EMPTY = new String(CharOperation.NO_CHAR);
+
+private Signature() {
+ // Not instantiable
+}
+
+private static boolean checkPrimitiveType(char[] primitiveTypeName, char[] typeName) {
+ return CharOperation.fragmentEquals(primitiveTypeName, typeName, 0, true) &&
+ (typeName.length == primitiveTypeName.length
+ || Character.isWhitespace(typeName[primitiveTypeName.length])
+ || typeName[primitiveTypeName.length] == C_ARRAY
+ || typeName[primitiveTypeName.length] == C_DOT);
+}
+
+/**
+ * Creates a new type signature with the given amount of array nesting added
+ * to the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @param arrayCount the desired number of levels of array nesting
+ * @return the encoded array type signature
+ *
+ * @since 2.0
+ */
+public static char[] createArraySignature(char[] typeSignature, int arrayCount) {
+ if (arrayCount == 0) return typeSignature;
+ int sigLength = typeSignature.length;
+ char[] result = new char[arrayCount + sigLength];
+ for (int i = 0; i < arrayCount; i++) {
+ result[i] = C_ARRAY;
+ }
+ System.arraycopy(typeSignature, 0, result, arrayCount, sigLength);
+ return result;
+}
+/**
+ * Creates a new type signature with the given amount of array nesting added
+ * to the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @param arrayCount the desired number of levels of array nesting
+ * @return the encoded array type signature
+ */
+public static String createArraySignature(String typeSignature, int arrayCount) {
+ return new String(createArraySignature(typeSignature.toCharArray(), arrayCount));
+}
+
+/**
+ * Creates a method signature from the given parameter and return type
+ * signatures. The encoded method signature is dot-based.
+ *
+ * @param parameterTypes the list of parameter type signatures
+ * @param returnType the return type signature
+ * @return the encoded method signature
+ *
+ * @since 2.0
+ */
+public static char[] createMethodSignature(char[][] parameterTypes, char[] returnType) {
+ int parameterTypesLength = parameterTypes.length;
+ int parameterLength = 0;
+ for (int i = 0; i < parameterTypesLength; i++) {
+ parameterLength += parameterTypes[i].length;
+
+ }
+ int returnTypeLength = returnType.length;
+ char[] result = new char[1 + parameterLength + 1 + returnTypeLength];
+ result[0] = C_PARAM_START;
+ int index = 1;
+ for (int i = 0; i < parameterTypesLength; i++) {
+ char[] parameterType = parameterTypes[i];
+ int length = parameterType.length;
+ System.arraycopy(parameterType, 0, result, index, length);
+ index += length;
+ }
+ result[index] = C_PARAM_END;
+ System.arraycopy(returnType, 0, result, index+1, returnTypeLength);
+ return result;
+}
+
+/**
+ * Creates a method signature from the given parameter and return type
+ * signatures. The encoded method signature is dot-based. This method
+ * is equivalent to
+ * createMethodSignature(parameterTypes, returnType)
.
+ *
+ * @param parameterTypes the list of parameter type signatures
+ * @param returnType the return type signature
+ * @return the encoded method signature
+ * @see Signature#createMethodSignature(char[][], char[])
+ */
+public static String createMethodSignature(String[] parameterTypes, String returnType) {
+ int parameterTypesLenth = parameterTypes.length;
+ char[][] parameters = new char[parameterTypesLenth][];
+ for (int i = 0; i < parameterTypesLenth; i++) {
+ parameters[i] = parameterTypes[i].toCharArray();
+ }
+ return new String(createMethodSignature(parameters, returnType.toCharArray()));
+}
+
+/**
+ * Creates a new type signature from the given type name encoded as a character
+ * array. The type name may contain primitive types or array types. However,
+ * parameterized types are not supported.
+ * This method is equivalent to
+ * createTypeSignature(new String(typeName),isResolved)
, although
+ * more efficient for callers with character arrays rather than strings. If the
+ * type name is qualified, then it is expected to be dot-based.
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved true
if the type name is to be considered
+ * resolved (for example, a type name from a binary class file), and
+ * false
if the type name is to be considered unresolved
+ * (for example, a type name found in source code)
+ * @return the encoded type signature
+ * @see #createTypeSignature(java.lang.String,boolean)
+ */
+public static String createTypeSignature(char[] typeName, boolean isResolved) {
+ return new String(createCharArrayTypeSignature(typeName, isResolved));
+}
+/**
+ * Creates a new type signature from the given type name encoded as a character
+ * array. The type name may contain primitive types or array types. However,
+ * parameterized types are not supported.
+ * This method is equivalent to
+ * createTypeSignature(new String(typeName),isResolved).toCharArray()
,
+ * although more efficient for callers with character arrays rather than strings.
+ * If the type name is qualified, then it is expected to be dot-based.
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved true
if the type name is to be considered
+ * resolved (for example, a type name from a binary class file), and
+ * false
if the type name is to be considered unresolved
+ * (for example, a type name found in source code)
+ * @return the encoded type signature
+ * @see #createTypeSignature(java.lang.String,boolean)
+ *
+ * @since 2.0
+ */
+public static char[] createCharArrayTypeSignature(char[] typeName, boolean isResolved) {
+ if (typeName == null) throw new IllegalArgumentException("null"); //$NON-NLS-1$
+ int length = typeName.length;
+ if (length == 0) throw new IllegalArgumentException(new String(typeName));
+
+ int arrayCount = CharOperation.occurencesOf('[', typeName);
+ char[] sig;
+
+ switch (typeName[0]) {
+ // primitive type?
+ case 'b' :
+ if (checkPrimitiveType(BOOLEAN, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_BOOLEAN;
+ break;
+ } else if (checkPrimitiveType(BYTE, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_BYTE;
+ break;
+ }
+ case 'c':
+ if (checkPrimitiveType(CHAR, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_CHAR;
+ break;
+ }
+ case 'd':
+ if (checkPrimitiveType(DOUBLE, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_DOUBLE;
+ break;
+ }
+ case 'f':
+ if (checkPrimitiveType(FLOAT, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_FLOAT;
+ break;
+ }
+ case 'i':
+ if (checkPrimitiveType(INT, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_INT;
+ break;
+ }
+ case 'l':
+ if (checkPrimitiveType(LONG, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_LONG;
+ break;
+ }
+ case 's':
+ if (checkPrimitiveType(SHORT, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_SHORT;
+ break;
+ }
+ case 'v':
+ if (checkPrimitiveType(VOID, typeName)) {
+ sig = new char[arrayCount+1];
+ sig[arrayCount] = C_VOID;
+ break;
+ }
+ default:
+ // non primitive type
+ int sigLength = arrayCount + 1 + length + 1; // for example '[[[Ljava.lang.String;'
+ sig = new char[sigLength];
+ int sigIndex = arrayCount+1; // index in sig
+ int startID = 0; // start of current ID in typeName
+ int index = 0; // index in typeName
+ while (index < length) {
+ char currentChar = typeName[index];
+ switch (currentChar) {
+ case '.':
+ if (startID == -1) throw new IllegalArgumentException(new String(typeName));
+ if (startID < index) {
+ sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+ sigIndex += index-startID;
+ }
+ sig[sigIndex++] = C_DOT;
+ index++;
+ startID = index;
+ break;
+ case '[':
+ if (startID != -1) {
+ if (startID < index) {
+ sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+ sigIndex += index-startID;
+ }
+ startID = -1; // no more id after []
+ }
+ index++;
+ break;
+ default :
+ if (startID != -1 && CharOperation.isWhitespace(currentChar)) {
+ if (startID < index) {
+ sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+ sigIndex += index-startID;
+ }
+ startID = index+1;
+ }
+ index++;
+ break;
+ }
+ }
+ // last id
+ if (startID != -1 && startID < index) {
+ sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+ sigIndex += index-startID;
+ }
+
+ // add L (or Q) at the beigininig and ; at the end
+ sig[arrayCount] = isResolved ? C_RESOLVED : C_UNRESOLVED;
+ sig[sigIndex++] = C_NAME_END;
+
+ // resize if needed
+ if (sigLength > sigIndex) {
+ System.arraycopy(sig, 0, sig = new char[sigIndex], 0, sigIndex);
+ }
+ }
+
+ // add array info
+ for (int i = 0; i < arrayCount; i++) {
+ sig[i] = C_ARRAY;
+ }
+
+ return sig;
+}
+/**
+ * Creates a new type signature from the given type name. If the type name is qualified,
+ * then it is expected to be dot-based. The type name may contain primitive
+ * types or array types. However, parameterized types are not supported.
+ * + * For example: + *
+ *
+ * createTypeSignature("int", hucairz) -> "I"
+ * createTypeSignature("java.lang.String", true) -> "Ljava.lang.String;"
+ * createTypeSignature("String", false) -> "QString;"
+ * createTypeSignature("java.lang.String", false) -> "Qjava.lang.String;"
+ * createTypeSignature("int []", false) -> "[I"
+ *
+ *
+ *
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved true
if the type name is to be considered
+ * resolved (for example, a type name from a binary class file), and
+ * false
if the type name is to be considered unresolved
+ * (for example, a type name found in source code)
+ * @return the encoded type signature
+ */
+public static String createTypeSignature(String typeName, boolean isResolved) {
+ return createTypeSignature(typeName == null ? null : typeName.toCharArray(), isResolved);
+}
+
+/**
+ * Returns the array count (array nesting depth) of the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @return the array nesting depth, or 0 if not an array
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ *
+ * @since 2.0
+ */
+public static int getArrayCount(char[] typeSignature) throws IllegalArgumentException {
+ try {
+ int count = 0;
+ while (typeSignature[count] == C_ARRAY) {
+ ++count;
+ }
+ return count;
+ } catch (ArrayIndexOutOfBoundsException e) { // signature is syntactically incorrect if last character is C_ARRAY
+ throw new IllegalArgumentException();
+ }
+}
+/**
+ * Returns the array count (array nesting depth) of the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @return the array nesting depth, or 0 if not an array
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ */
+public static int getArrayCount(String typeSignature) throws IllegalArgumentException {
+ return getArrayCount(typeSignature.toCharArray());
+}
+/**
+ * Returns the type signature without any array nesting.
+ * + * For example: + *
+ *
+ * getElementType({'[', '[', 'I'}) --> {'I'}.
+ *
+ *
+ *
+ *
+ * @param typeSignature the type signature
+ * @return the type signature without arrays
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ *
+ * @since 2.0
+ */
+public static char[] getElementType(char[] typeSignature) throws IllegalArgumentException {
+ int count = getArrayCount(typeSignature);
+ if (count == 0) return typeSignature;
+ int length = typeSignature.length;
+ char[] result = new char[length-count];
+ System.arraycopy(typeSignature, count, result, 0, length-count);
+ return result;
+}
+/**
+ * Returns the type signature without any array nesting.
+ * + * For example: + *
+ *
+ * getElementType("[[I") --> "I".
+ *
+ *
+ *
+ *
+ * @param typeSignature the type signature
+ * @return the type signature without arrays
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ */
+public static String getElementType(String typeSignature) throws IllegalArgumentException {
+ return new String(getElementType(typeSignature.toCharArray()));
+}
+/**
+ * Returns the number of parameter types in the given method signature.
+ *
+ * @param methodSignature the method signature
+ * @return the number of parameters
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ * @since 2.0
+ */
+public static int getParameterCount(char[] methodSignature) throws IllegalArgumentException {
+ try {
+ int count = 0;
+ int i = CharOperation.indexOf(C_PARAM_START, methodSignature);
+ if (i < 0) {
+ throw new IllegalArgumentException();
+ } else {
+ i++;
+ }
+ for (;;) {
+ if (methodSignature[i] == C_PARAM_END) {
+ return count;
+ }
+ int e= scanTypeSignature(methodSignature, i);
+ if (e < 0) {
+ throw new IllegalArgumentException();
+ } else {
+ i = e + 1;
+ }
+ count++;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+}
+
+/**
+ * Returns the kind of type signature encoded by the given string.
+ *
+ * @param typeSignature the type signature string
+ * @return the kind of type signature; one of the kind constants:
+ * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
+ * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}
+ * @exception IllegalArgumentException if this is not a type signature
+ * @since 3.0
+ */
+public static int getTypeSignatureKind(char[] typeSignature) {
+ // need a minimum 1 char
+ if (typeSignature.length < 1) {
+ throw new IllegalArgumentException();
+ }
+ char c = typeSignature[0];
+ switch (c) {
+ case C_ARRAY :
+ return ARRAY_TYPE_SIGNATURE;
+ case C_RESOLVED :
+ case C_UNRESOLVED :
+ return CLASS_TYPE_SIGNATURE;
+ case C_TYPE_VARIABLE :
+ return TYPE_VARIABLE_SIGNATURE;
+ case C_BOOLEAN :
+ case C_BYTE :
+ case C_CHAR :
+ case C_DOUBLE :
+ case C_FLOAT :
+ case C_INT :
+ case C_LONG :
+ case C_SHORT :
+ case C_VOID :
+ return BASE_TYPE_SIGNATURE;
+ default :
+ throw new IllegalArgumentException();
+ }
+}
+
+/**
+ * Returns the kind of type signature encoded by the given string.
+ *
+ * @param typeSignature the type signature string
+ * @return the kind of type signature; one of the kind constants:
+ * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
+ * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}
+ * @exception IllegalArgumentException if this is not a type signature
+ * @since 3.0
+ */
+public static int getTypeSignatureKind(String typeSignature) {
+ // need a minimum 1 char
+ if (typeSignature.length() < 1) {
+ throw new IllegalArgumentException();
+ }
+ char c = typeSignature.charAt(0);
+ switch (c) {
+ case C_ARRAY :
+ return ARRAY_TYPE_SIGNATURE;
+ case C_RESOLVED :
+ case C_UNRESOLVED :
+ return CLASS_TYPE_SIGNATURE;
+ case C_TYPE_VARIABLE :
+ return TYPE_VARIABLE_SIGNATURE;
+ case C_BOOLEAN :
+ case C_BYTE :
+ case C_CHAR :
+ case C_DOUBLE :
+ case C_FLOAT :
+ case C_INT :
+ case C_LONG :
+ case C_SHORT :
+ case C_VOID :
+ return BASE_TYPE_SIGNATURE;
+ default :
+ throw new IllegalArgumentException();
+ }
+}
+
+/**
+ * Scans the given string for a type signature starting at the given index
+ * and returns the index of the last character.
+ * + * TypeSignature: + * | BaseTypeSignature + * | ArrayTypeSignature + * | ClassTypeSignature + * | TypeVariableSignature + *+ * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not a type signature + * @see #appendTypeSignature(char[], int, boolean, StringBuffer) + */ +private static int scanTypeSignature(char[] string, int start) { + // need a minimum 1 char + if (start >= string.length) { + throw new IllegalArgumentException(); + } + char c = string[start]; + switch (c) { + case C_ARRAY : + return scanArrayTypeSignature(string, start); + case C_RESOLVED : + case C_UNRESOLVED : + return scanClassTypeSignature(string, start); + case C_TYPE_VARIABLE : + return scanTypeVariableSignature(string, start); + case C_BOOLEAN : + case C_BYTE : + case C_CHAR : + case C_DOUBLE : + case C_FLOAT : + case C_INT : + case C_LONG : + case C_SHORT : + case C_VOID : + return scanBaseTypeSignature(string, start); + default : + throw new IllegalArgumentException(); + } +} + +/** + * Scans the given string for a base type signature starting at the given index + * and returns the index of the last character. + *
+ * BaseTypeSignature: + * B | C | D | F | I + * | J | S | V | Z + *+ * Note that although the base type "V" is only allowed in method return types, + * there is no syntactic ambiguity. This method will accept them anywhere + * without complaint. + * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not a base type signature + */ +private static int scanBaseTypeSignature(char[] string, int start) { + // need a minimum 1 char + if (start >= string.length) { + throw new IllegalArgumentException(); + } + char c = string[start]; + if ("BCDFIJSVZ".indexOf(c) >= 0) { //$NON-NLS-1$ + return start; + } else { + throw new IllegalArgumentException(); + } +} + +/** + * Scans the given string for an array type signature starting at the given + * index and returns the index of the last character. + *
+ * ArrayTypeSignature: + * [ TypeSignature + *+ * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not an array type signature + * @see #appendArrayTypeSignature(char[], int, boolean, StringBuffer) + */ +private static int scanArrayTypeSignature(char[] string, int start) { + // need a minimum 2 char + if (start >= string.length - 1) { + throw new IllegalArgumentException(); + } + char c = string[start]; + if (c != C_ARRAY) { //$NON-NLS-1$ + throw new IllegalArgumentException(); + } + return scanTypeSignature(string, start + 1); +} + +/** + * Scans the given string for a type variable signature starting at the given + * index and returns the index of the last character. + *
+ * TypeVariableSignature: + * T Identifier ; + *+ * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not a type variable signature + */ +private static int scanTypeVariableSignature(char[] string, int start) { + // need a minimum 3 chars "Tx;" + if (start >= string.length - 2) { + throw new IllegalArgumentException(); + } + // must start in "T" + char c = string[start]; + if (c != C_TYPE_VARIABLE) { + throw new IllegalArgumentException(); + } + int id = scanIdentifier(string, start + 1); + c = string[id + 1]; + if (c == C_SEMICOLON) { + return id + 1; + } else { + throw new IllegalArgumentException(); + } +} + +/** + * Scans the given string for an identifier starting at the given + * index and returns the index of the last character. + * Stop characters are: ";", ":", "<", ">", "/", ".". + * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not an identifier + */ +private static int scanIdentifier(char[] string, int start) { + // need a minimum 1 char + if (start >= string.length) { + throw new IllegalArgumentException(); + } + int p = start; + while (true) { + char c = string[p]; + if (c == '<' || c == '>' || c == ':' || c == ';' || c == '.' || c == '/') { + return p - 1; + } + p++; + if (p == string.length) { + return p - 1; + } + } +} + +/** + * Scans the given string for a class type signature starting at the given + * index and returns the index of the last character. + *
+ * ClassTypeSignature: + * { L | Q } Identifier + * { { / | . Identifier [ < TypeArgumentSignature* > ] } + * ; + *+ * Note that although all "/"-identifiers most come before "."-identifiers, + * there is no syntactic ambiguity. This method will accept them without + * complaint. + * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not a class type signature + * @see #appendClassTypeSignature(char[], int, boolean, StringBuffer) + */ +private static int scanClassTypeSignature(char[] string, int start) { + // need a minimum 3 chars "Lx;" + if (start >= string.length - 2) { + throw new IllegalArgumentException(); + } + // must start in "L" or "Q" + char c = string[start]; + if (c != C_RESOLVED && c != C_UNRESOLVED) { + return -1; + } + int p = start + 1; + while (true) { + if (p >= string.length) { + throw new IllegalArgumentException(); + } + c = string[p]; + if (c == C_SEMICOLON) { + // all done + return p; + } else if (c == C_GENERIC_START) { + int e = scanTypeArgumentSignatures(string, p); + p = e; + } else if (c == C_DOT || c == '/') { + int id = scanIdentifier(string, p + 1); + p = id; + } + p++; + } +} + +/** + * Scans the given string for a list of type argument signatures starting at + * the given index and returns the index of the last character. + *
+ * TypeArgumentSignatures: + * < TypeArgumentSignature* > + *+ * Note that although there is supposed to be at least one type argument, there + * is no syntactic ambiguity if there are none. This method will accept zero + * type argument signatures without complaint. + * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not a list of type arguments + * signatures + * @see #appendTypeArgumentSignatures(char[], int, boolean, StringBuffer) + */ +private static int scanTypeArgumentSignatures(char[] string, int start) { + // need a minimum 2 char "<>" + if (start >= string.length - 1) { + throw new IllegalArgumentException(); + } + char c = string[start]; + if (c != C_GENERIC_START) { + throw new IllegalArgumentException(); + } + int p = start + 1; + while (true) { + if (p >= string.length) { + throw new IllegalArgumentException(); + } + c = string[p]; + if (c == C_GENERIC_END) { + return p; + } + int e = scanTypeArgumentSignature(string, p); + p = e + 1; + } +} + +/** + * Scans the given string for a type argument signature starting at the given + * index and returns the index of the last character. + *
+ * TypeArgumentSignature: + * * + * | + TypeSignature + * | - TypeSignature + * | TypeSignature + *+ * Note that although base types are not allowed in type arguments, there is + * no syntactic ambiguity. This method will accept them without complaint. + * + * @param string the signature string + * @param start the 0-based character index of the first character + * @return the 0-based character index of the last character + * @exception IllegalArgumentException if this is not a type argument signature + * @see #appendTypeArgumentSignature(char[], int, boolean, StringBuffer) + */ +private static int scanTypeArgumentSignature(char[] string, int start) { + // need a minimum 1 char + if (start >= string.length) { + throw new IllegalArgumentException(); + } + char c = string[start]; + if (c == C_STAR) { + return start; + } + if (c == '+' || c == '-') { + return scanTypeSignature(string, start + 1); + } else { + return scanTypeSignature(string, start); + } +} + +/** + * Returns the number of parameter types in the given method signature. + * + * @param methodSignature the method signature + * @return the number of parameters + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ +public static int getParameterCount(String methodSignature) throws IllegalArgumentException { + return getParameterCount(methodSignature.toCharArray()); +} +/** + * Extracts the parameter type signatures from the given method signature. + * The method signature is expected to be dot-based. + * + * @param methodSignature the method signature + * @return the list of parameter type signatures + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * + * @since 2.0 + */ +public static char[][] getParameterTypes(char[] methodSignature) throws IllegalArgumentException { + try { + int count = getParameterCount(methodSignature); + char[][] result = new char[count][]; + if (count == 0) { + return result; + } + int i = CharOperation.indexOf(C_PARAM_START, methodSignature); + if (i < 0) { + throw new IllegalArgumentException(); + } else { + i++; + } + int t = 0; + for (;;) { + if (methodSignature[i] == C_PARAM_END) { + return result; + } + int e = scanTypeSignature(methodSignature, i); + if (e < 0) { + throw new IllegalArgumentException(); + } + result[t] = CharOperation.subarray(methodSignature, i, e + 1); + t++; + i = e + 1; + } + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } +} +/** + * Extracts the parameter type signatures from the given method signature. + * The method signature is expected to be dot-based. + * + * @param methodSignature the method signature + * @return the list of parameter type signatures + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + */ +public static String[] getParameterTypes(String methodSignature) throws IllegalArgumentException { + char[][] parameterTypes = getParameterTypes(methodSignature.toCharArray()); + int length = parameterTypes.length; + String[] result = new String[length]; + for (int i = 0; i < length; i++) { + result[i] = new String(parameterTypes[i]); + } + return result; +} + +/** + * Extracts the type variable name from the given formal type parameter + * signature. The signature is expected to be dot-based. + * + * @param formalTypeParameterSignature the formal type parameter signature + * @return the name of the type variable + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * @since 3.0 + */ +public static String getTypeVariable(String formalTypeParameterSignature) throws IllegalArgumentException { + return new String(getTypeVariable(formalTypeParameterSignature.toCharArray())); +} + +/** + * Extracts the type variable name from the given formal type parameter + * signature. The signature is expected to be dot-based. + * + * @param formalTypeParameterSignature the formal type parameter signature + * @return the name of the type variable + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * @since 3.0 + */ +public static char[] getTypeVariable(char[] formalTypeParameterSignature) throws IllegalArgumentException { + int p = CharOperation.indexOf(C_COLON, formalTypeParameterSignature); + if (p < 0) { + // no ":" means can't be a formal type parameter signature + throw new IllegalArgumentException(); + } + return CharOperation.subarray(formalTypeParameterSignature, 0, p); +} + +/** + * Extracts the class and interface bounds from the given formal type + * parameter signature. The class bound, if present, is listed before + * the interface bounds. The signature is expected to be dot-based. + * + * @param formalTypeParameterSignature the formal type parameter signature + * @return the (possibly empty) list of type signatures for the bounds + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * @since 3.0 + */ +public static char[][] getTypeParameterBounds(char[] formalTypeParameterSignature) throws IllegalArgumentException { + int p1 = CharOperation.indexOf(C_COLON, formalTypeParameterSignature); + if (p1 < 0) { + // no ":" means can't be a formal type parameter signature + throw new IllegalArgumentException(); + } + if (p1 == formalTypeParameterSignature.length - 1) { + // no class or interface bounds + return CharOperation.NO_CHAR_CHAR; + } + int p2 = CharOperation.indexOf(C_COLON, formalTypeParameterSignature, p1 + 1); + char[] classBound; + if (p2 < 0) { + // no interface bounds + classBound = CharOperation.subarray(formalTypeParameterSignature, p1 + 1, formalTypeParameterSignature.length); + return new char[][] {classBound}; + } + if (p2 == p1 + 1) { + // no class bound, but 1 or more interface bounds + classBound = null; + } else { + classBound = CharOperation.subarray(formalTypeParameterSignature, p1 + 1, p2); + } + char[][] interfaceBounds = CharOperation.splitOn(C_COLON, formalTypeParameterSignature, p2 + 1, formalTypeParameterSignature.length); + if (classBound == null) { + return interfaceBounds; + } + int resultLength = interfaceBounds.length + 1; + char[][] result = new char[resultLength][]; + result[0] = classBound; + System.arraycopy(interfaceBounds, 0, result, 1, interfaceBounds.length); + return result; +} + +/** + * Extracts the class and interface bounds from the given formal type + * parameter signature. The class bound, if present, is listed before + * the interface bounds. The signature is expected to be dot-based. + * + * @param formalTypeParameterSignature the formal type parameter signature + * @return the (possibly empty) list of type signatures for the bounds + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * @since 3.0 + */ +public static String[] getTypeParameterBounds(String formalTypeParameterSignature) throws IllegalArgumentException { + char[][] bounds = getTypeParameterBounds(formalTypeParameterSignature.toCharArray()); + int length = bounds.length; + String[] result = new String[length]; + for (int i = 0; i < length; i++) { + result[i] = new String(bounds[i]); + } + return result; +} + +/** + * Returns a char array containing all but the last segment of the given + * dot-separated qualified name. Returns the empty char array if it is not qualified. + *
+ * For example: + *
+ *
+ * getQualifier({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g'}
+ * getQualifier({'O', 'u', 't', 'e', 'r', '.', 'I', 'n', 'n', 'e', 'r'}) -> {'O', 'u', 't', 'e', 'r'}
+ *
+ *
+ *
+ *
+ * @param name the name
+ * @return the qualifier prefix, or the empty char array if the name contains no
+ * dots
+ * @exception NullPointerException if name is null
+ * @since 2.0
+ */
+public static char[] getQualifier(char[] name) {
+ int lastDot = CharOperation.lastIndexOf(C_DOT, name);
+ if (lastDot == -1) {
+ return CharOperation.NO_CHAR;
+ }
+ return CharOperation.subarray(name, 0, lastDot);
+}
+/**
+ * Returns a string containing all but the last segment of the given
+ * dot-separated qualified name. Returns the empty string if it is not qualified.
+ * + * For example: + *
+ *
+ * getQualifier("java.lang.Object") -> "java.lang"
+ * getQualifier("Outer.Inner") -> "Outer"
+ *
+ *
+ *
+ *
+ * @param name the name
+ * @return the qualifier prefix, or the empty string if the name contains no
+ * dots
+ * @exception NullPointerException if name is null
+ */
+public static String getQualifier(String name) {
+ int lastDot = name.lastIndexOf(C_DOT);
+ if (lastDot == -1) {
+ return EMPTY;
+ }
+ return name.substring(0, lastDot);
+}
+/**
+ * Extracts the return type from the given method signature. The method signature is
+ * expected to be dot-based.
+ *
+ * @param methodSignature the method signature
+ * @return the type signature of the return type
+ * @exception IllegalArgumentException if the signature is syntactically
+ * incorrect
+ *
+ * @since 2.0
+ */
+public static char[] getReturnType(char[] methodSignature) throws IllegalArgumentException {
+ // skip type parameters
+ int i = CharOperation.lastIndexOf(C_PARAM_END, methodSignature);
+ if (i == -1) {
+ throw new IllegalArgumentException();
+ }
+ // ignore any thrown exceptions
+ int j = CharOperation.indexOf('^', methodSignature);
+ int last = (j == -1 ? methodSignature.length : j);
+ return CharOperation.subarray(methodSignature, i + 1, last);
+}
+/**
+ * Extracts the return type from the given method signature. The method signature is
+ * expected to be dot-based.
+ *
+ * @param methodSignature the method signature
+ * @return the type signature of the return type
+ * @exception IllegalArgumentException if the signature is syntactically
+ * incorrect
+ */
+public static String getReturnType(String methodSignature) throws IllegalArgumentException {
+ return new String(getReturnType(methodSignature.toCharArray()));
+}
+/**
+ * Returns the last segment of the given dot-separated qualified name.
+ * Returns the given name if it is not qualified.
+ * + * For example: + *
+ *
+ * getSimpleName({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'O', 'b', 'j', 'e', 'c', 't'}
+ *
+ *
+ *
+ *
+ * @param name the name
+ * @return the last segment of the qualified name
+ * @exception NullPointerException if name is null
+ * @since 2.0
+ */
+public static char[] getSimpleName(char[] name) {
+ int lastDot = CharOperation.lastIndexOf(C_DOT, name);
+ if (lastDot == -1) {
+ return name;
+ }
+ return CharOperation.subarray(name, lastDot + 1, name.length);
+}
+/**
+ * Returns the last segment of the given dot-separated qualified name.
+ * Returns the given name if it is not qualified.
+ * + * For example: + *
+ *
+ * getSimpleName("java.lang.Object") -> "Object"
+ *
+ *
+ *
+ *
+ * @param name the name
+ * @return the last segment of the qualified name
+ * @exception NullPointerException if name is null
+ */
+public static String getSimpleName(String name) {
+ int lastDot = name.lastIndexOf(C_DOT);
+ if (lastDot == -1) {
+ return name;
+ }
+ return name.substring(lastDot + 1, name.length());
+}
+/**
+ * Returns all segments of the given dot-separated qualified name.
+ * Returns an array with only the given name if it is not qualified.
+ * Returns an empty array if the name is empty.
+ * + * For example: + *
+ *
+ * getSimpleNames({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}
+ * getSimpleNames({'O', 'b', 'j', 'e', 'c', 't'}) -> {{'O', 'b', 'j', 'e', 'c', 't'}}
+ * getSimpleNames("") -> {}
+ *
+ *
+ *
+ * @param name the name
+ * @return the list of simple names, possibly empty
+ * @exception NullPointerException if name is null
+ * @since 2.0
+ */
+public static char[][] getSimpleNames(char[] name) {
+ if (name.length == 0) {
+ return CharOperation.NO_CHAR_CHAR;
+ }
+ int dot = CharOperation.indexOf(C_DOT, name);
+ if (dot == -1) {
+ return new char[][] {name};
+ }
+ int n = 1;
+ while ((dot = CharOperation.indexOf(C_DOT, name, dot + 1)) != -1) {
+ ++n;
+ }
+ char[][] result = new char[n + 1][];
+ int segStart = 0;
+ for (int i = 0; i < n; ++i) {
+ dot = CharOperation.indexOf(C_DOT, name, segStart);
+ result[i] = CharOperation.subarray(name, segStart, dot);
+ segStart = dot + 1;
+ }
+ result[n] = CharOperation.subarray(name, segStart, name.length);
+ return result;
+}
+/**
+ * Returns all segments of the given dot-separated qualified name.
+ * Returns an array with only the given name if it is not qualified.
+ * Returns an empty array if the name is empty.
+ * + * For example: + *
+ *
+ * getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
+ * getSimpleNames("Object") -> {"Object"}
+ * getSimpleNames("") -> {}
+ *
+ *
+ *
+ * @param name the name
+ * @return the list of simple names, possibly empty
+ * @exception NullPointerException if name is null
+ */
+public static String[] getSimpleNames(String name) {
+ char[][] simpleNames = getSimpleNames(name.toCharArray());
+ int length = simpleNames.length;
+ String[] result = new String[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = new String(simpleNames[i]);
+ }
+ return result;
+}
+/**
+ * Converts the given method signature to a readable form. The method signature is expected to
+ * be dot-based.
+ * + * For example: + *
+ *
+ * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
+ *
+ *
+ *
+ *
+ * @param methodSignature the method signature to convert
+ * @param methodName the name of the method to insert in the result, or
+ * null
if no method name is to be included
+ * @param parameterNames the parameter names to insert in the result, or
+ * null
if no parameter names are to be included; if supplied,
+ * the number of parameter names must match that of the method signature
+ * @param fullyQualifyTypeNames true
if type names should be fully
+ * qualified, and false
to use only simple names
+ * @param includeReturnType true
if the return type is to be
+ * included
+ * @return the char array representation of the method signature
+ *
+ * @since 2.0
+ */
+public static char[] toCharArray(char[] methodSignature, char[] methodName, char[][] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
+ int firstParen = CharOperation.indexOf(C_PARAM_START, methodSignature);
+ if (firstParen == -1) {
+ throw new IllegalArgumentException();
+ }
+
+ StringBuffer buffer = new StringBuffer(methodSignature.length + 10);
+
+ // return type
+ if (includeReturnType) {
+ char[] rts = getReturnType(methodSignature);
+ appendTypeSignature(rts, 0 , fullyQualifyTypeNames, buffer);
+ buffer.append(' ');
+ }
+
+ // selector
+ if (methodName != null) {
+ buffer.append(methodName);
+ }
+
+ // parameters
+ buffer.append('(');
+ char[][] pts = getParameterTypes(methodSignature);
+ for (int i = 0; i < pts.length; i++) {
+ appendTypeSignature(pts[i], 0 , fullyQualifyTypeNames, buffer);
+ if (parameterNames != null) {
+ buffer.append(' ');
+ buffer.append(parameterNames[i]);
+ }
+ if (i != pts.length - 1) {
+ buffer.append(',');
+ buffer.append(' ');
+ }
+ }
+ buffer.append(')');
+ char[] result = new char[buffer.length()];
+ buffer.getChars(0, buffer.length(), result, 0);
+ return result;
+}
+
+/**
+ * Converts the given type signature to a readable string. The signature is expected to
+ * be dot-based.
+ *
+ * + * For example: + *
+ *
+ * toString({'[', 'L', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', ';'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', '[', ']'}
+ * toString({'I'}) -> {'i', 'n', 't'}
+ *
+ *
+ *
+ *
+ * Note: This method assumes that a type signature containing a '$'
+ * is an inner type signature. While this is correct in most cases, someone could
+ * define a non-inner type name containing a '$'
. Handling this
+ * correctly in all cases would have required resolving the signature, which
+ * generally not feasible.
+ *
true
if type names should be fully
+ * qualified, and false
to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a type signature
+ * @see #scanTypeSignature(char[], int)
+ */
+private static int appendTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+ // need a minimum 1 char
+ if (start >= string.length) {
+ throw new IllegalArgumentException();
+ }
+ char c = string[start];
+ switch (c) {
+ case C_ARRAY :
+ return appendArrayTypeSignature(string, start, fullyQualifyTypeNames, buffer);
+ case C_RESOLVED :
+ case C_UNRESOLVED :
+ return appendClassTypeSignature(string, start, fullyQualifyTypeNames, buffer);
+ case C_TYPE_VARIABLE :
+ int e = scanTypeVariableSignature(string, start);
+ buffer.append(CharOperation.subarray(string, start + 1, e));
+ return e;
+ case C_BOOLEAN :
+ buffer.append(BOOLEAN);
+ return start;
+ case C_BYTE :
+ buffer.append(BYTE);
+ return start;
+ case C_CHAR :
+ buffer.append(CHAR);
+ return start;
+ case C_DOUBLE :
+ buffer.append(DOUBLE);
+ return start;
+ case C_FLOAT :
+ buffer.append(FLOAT);
+ return start;
+ case C_INT :
+ buffer.append(INT);
+ return start;
+ case C_LONG :
+ buffer.append(LONG);
+ return start;
+ case C_SHORT :
+ buffer.append(SHORT);
+ return start;
+ case C_VOID :
+ buffer.append(VOID);
+ return start;
+ case C_CONST :
+ buffer.append(CONST);
+ return start;
+ default :
+ throw new IllegalArgumentException();
+ }
+}
+
+/**
+ * Scans the given string for an array type signature starting at the given
+ * index and appends it to the given buffer, and returns the index of the last
+ * character.
+ *
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames true
if type names should be fully
+ * qualified, and false
to use only simple names
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not an array type signature
+ * @see #scanArrayTypeSignature(char[], int)
+ */
+private static int appendArrayTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+ // need a minimum 2 char
+ if (start >= string.length - 1) {
+ throw new IllegalArgumentException();
+ }
+ char c = string[start];
+ if (c != C_ARRAY) { //$NON-NLS-1$
+ throw new IllegalArgumentException();
+ }
+ int e = appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
+ buffer.append('[');
+ buffer.append(']');
+ return e;
+}
+
+/**
+ * Scans the given string for a class type signature starting at the given
+ * index and appends it to the given buffer, and returns the index of the last
+ * character.
+ *
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames true
if type names should be fully
+ * qualified, and false
to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a class type signature
+ * @see #scanClassTypeSignature(char[], int)
+ */
+private static int appendClassTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+ // need a minimum 3 chars "Lx;"
+ if (start >= string.length - 2) {
+ throw new IllegalArgumentException();
+ }
+ // must start in "L" or "Q"
+ char c = string[start];
+ if (c != C_RESOLVED && c != C_UNRESOLVED) {
+ throw new IllegalArgumentException();
+ }
+ boolean resolved = (c == C_RESOLVED);
+ boolean removePackageQualifiers = !fullyQualifyTypeNames;
+ if (!resolved) {
+ // keep everything in an unresolved name
+ removePackageQualifiers = false;
+ }
+ int p = start + 1;
+ int checkpoint = buffer.length();
+ while (true) {
+ if (p >= string.length) {
+ throw new IllegalArgumentException();
+ }
+ c = string[p];
+ switch(c) {
+ case C_SEMICOLON :
+ // all done
+ return p;
+ case C_GENERIC_START :
+ int e = appendTypeArgumentSignatures(string, p, fullyQualifyTypeNames, buffer);
+ // once we hit type arguments there are no more package prefixes
+ removePackageQualifiers = false;
+ p = e;
+ break;
+ case C_DOT :
+ if (removePackageQualifiers) {
+ // erase package prefix
+ buffer.setLength(checkpoint);
+ } else {
+ buffer.append('.');
+ }
+ break;
+ case '/' :
+ if (removePackageQualifiers) {
+ // erase package prefix
+ buffer.setLength(checkpoint);
+ } else {
+ buffer.append('/');
+ }
+ break;
+ case C_DOLLAR :
+ if (resolved) {
+ // once we hit "$" there are no more package prefixes
+ removePackageQualifiers = false;
+ /**
+ * Convert '$' in resolved type signatures into '.'.
+ * NOTE: This assumes that the type signature is an inner type
+ * signature. This is true in most cases, but someone can define a
+ * non-inner type name containing a '$'.
+ */
+ buffer.append('.');
+ }
+ break;
+ default :
+ buffer.append(c);
+ }
+ p++;
+ }
+}
+
+/**
+ * Scans the given string for a list of type arguments signature starting at the
+ * given index and appends it to the given buffer, and returns the index of the
+ * last character.
+ *
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames true
if type names should be fully
+ * qualified, and false
to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a list of type argument
+ * signatures
+ * @see #scanTypeArgumentSignatures(char[], int)
+ */
+private static int appendTypeArgumentSignatures(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+ // need a minimum 2 char "<>"
+ if (start >= string.length - 1) {
+ throw new IllegalArgumentException();
+ }
+ char c = string[start];
+ if (c != C_GENERIC_START) {
+ throw new IllegalArgumentException();
+ }
+ buffer.append('<');
+ int p = start + 1;
+ int count = 0;
+ while (true) {
+ if (p >= string.length) {
+ throw new IllegalArgumentException();
+ }
+ c = string[p];
+ if (c == C_GENERIC_END) {
+ buffer.append('>');
+ return p;
+ }
+ if (count != 0) {
+ buffer.append(',');
+ }
+ int e = appendTypeArgumentSignature(string, p, fullyQualifyTypeNames, buffer);
+ count++;
+ p = e + 1;
+ }
+}
+
+/**
+ * Scans the given string for a type argument signature starting at the given
+ * index and appends it to the given buffer, and returns the index of the last
+ * character.
+ *
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames true
if type names should be fully
+ * qualified, and false
to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a type argument signature
+ * @see #scanTypeArgumentSignature(char[], int)
+ */
+private static int appendTypeArgumentSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+ // need a minimum 1 char
+ if (start >= string.length) {
+ throw new IllegalArgumentException();
+ }
+ char c = string[start];
+ switch(c) {
+ case C_STAR :
+ buffer.append('?');
+ return start;
+ case '+' :
+ buffer.append("? extends "); //$NON-NLS-1$
+ return appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
+ case '-' :
+ buffer.append("? super "); //$NON-NLS-1$
+ return appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
+ default :
+ return appendTypeSignature(string, start, fullyQualifyTypeNames, buffer);
+ }
+}
+
+/**
+ * Converts the given array of qualified name segments to a qualified name.
+ * + * For example: + *
+ *
+ * toQualifiedName({{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}
+ * toQualifiedName({{'O', 'b', 'j', 'e', 'c', 't'}}) -> {'O', 'b', 'j', 'e', 'c', 't'}
+ * toQualifiedName({{}}) -> {}
+ *
+ *
+ *
+ *
+ * @param segments the list of name segments, possibly empty
+ * @return the dot-separated qualified name, or the empty string
+ *
+ * @since 2.0
+ */
+public static char[] toQualifiedName(char[][] segments) {
+ int length = segments.length;
+ if (length == 0) return CharOperation.NO_CHAR;
+ if (length == 1) return segments[0];
+
+ int resultLength = 0;
+ for (int i = 0; i < length; i++) {
+ resultLength += segments[i].length+1;
+ }
+ resultLength--;
+ char[] result = new char[resultLength];
+ int index = 0;
+ for (int i = 0; i < length; i++) {
+ char[] segment = segments[i];
+ int segmentLength = segment.length;
+ System.arraycopy(segment, 0, result, index, segmentLength);
+ index += segmentLength;
+ if (i != length-1) {
+ result[index++] = C_DOT;
+ }
+ }
+ return result;
+}
+/**
+ * Converts the given array of qualified name segments to a qualified name.
+ * + * For example: + *
+ *
+ * toQualifiedName(new String[] {"java", "lang", "Object"}) -> "java.lang.Object"
+ * toQualifiedName(new String[] {"Object"}) -> "Object"
+ * toQualifiedName(new String[0]) -> ""
+ *
+ *
+ *
+ *
+ * @param segments the list of name segments, possibly empty
+ * @return the dot-separated qualified name, or the empty string
+ */
+public static String toQualifiedName(String[] segments) {
+ int length = segments.length;
+ char[][] charArrays = new char[length][];
+ for (int i = 0; i < length; i++) {
+ charArrays[i] = segments[i].toCharArray();
+ }
+ return new String(toQualifiedName(charArrays));
+}
+/**
+ * Converts the given type signature to a readable string. The signature is expected to
+ * be dot-based.
+ *
+ * + * For example: + *
+ *
+ * toString("[Ljava.lang.String;") -> "java.lang.String[]"
+ * toString("I") -> "int"
+ *
+ *
+ *
+ *
+ * Note: This method assumes that a type signature containing a '$'
+ * is an inner type signature. While this is correct in most cases, someone could
+ * define a non-inner type name containing a '$'
. Handling this
+ * correctly in all cases would have required resolving the signature, which
+ * generally not feasible.
+ *
null
if no method name is to be included
+ * @param parameterNames the parameter names to insert in the result, or
+ * null
if no parameter names are to be included; if supplied,
+ * the number of parameter names must match that of the method signature
+ * @param fullyQualifyTypeNames true
if type names should be fully
+ * qualified, and false
to use only simple names
+ * @param includeReturnType true
if the return type is to be
+ * included
+ * @see #toCharArray(char[], char[], char[][], boolean, boolean)
+ * @return the string representation of the method signature
+ */
+public static String toString(String methodSignature, String methodName, String[] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
+ char[][] params;
+ if (parameterNames == null) {
+ params = null;
+ } else {
+ int paramLength = parameterNames.length;
+ params = new char[paramLength][];
+ for (int i = 0; i < paramLength; i++) {
+ params[i] = parameterNames[i].toCharArray();
+ }
+ }
+ return new String(toCharArray(methodSignature.toCharArray(), methodName == null ? null : methodName.toCharArray(), params, fullyQualifyTypeNames, includeReturnType));
+}
+
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java
index ae233c3dcf7..7d9c412a32c 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java
@@ -10,7 +10,10 @@
*******************************************************************************/
package org.eclipse.cdt.core.browser;
+import java.util.Iterator;
+
import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
import org.eclipse.core.resources.IProject;
@@ -22,6 +25,8 @@ public class TypeInfo implements ITypeInfo
protected IQualifiedTypeName fQualifiedName;
protected ITypeReference[] fSourceRefs = null;
protected int fSourceRefsCount = 0;
+ protected ITypeReference[] fDerivedSourceRefs = null;
+ protected int fDerivedSourceRefsCount = 0;
protected final static int INITIAL_REFS_SIZE = 1;
protected final static int REFS_GROW_BY = 2;
@@ -54,26 +59,6 @@ public class TypeInfo implements ITypeInfo
return null;
}
- public ICElement getCElement() {
- ITypeReference ref = getResolvedReference();
- if (ref != null) {
- ICElement[] elems = ref.getCElements();
- if (elems != null && elems.length > 0) {
- if (elems.length == 1)
- return elems[0];
-
- for (int i = 0; i < elems.length; ++i) {
- ICElement elem = elems[i];
- if (elem.getElementType() == fElementType && elem.getElementName().equals(getName())) {
- //TODO should check fully qualified name
- return elem;
- }
- }
- }
- }
- return null;
- }
-
public ITypeReference getResolvedReference() {
for (int i = 0; i < fSourceRefsCount; ++i) {
ITypeReference location = fSourceRefs[i];
@@ -85,9 +70,28 @@ public class TypeInfo implements ITypeInfo
}
public boolean isReferenced() {
- return (fSourceRefs != null);
+ return (fSourceRefs != null || fDerivedSourceRefs != null);
}
+ public boolean isReferenced(ITypeSearchScope scope) {
+ if (scope == null || scope.isWorkspaceScope())
+ return true;
+
+ // check if path is in scope
+ for (int i = 0; i < fSourceRefsCount; ++i) {
+ ITypeReference location = fSourceRefs[i];
+ if (scope.encloses(location.getPath()))
+ return true;
+ }
+ for (int i = 0; i < fDerivedSourceRefsCount; ++i) {
+ ITypeReference location = fDerivedSourceRefs[i];
+ if (scope.encloses(location.getPath()))
+ return true;
+ }
+
+ return false;
+ }
+
public boolean isUndefinedType() {
return fElementType == 0;
}
@@ -256,4 +260,64 @@ public class TypeInfo implements ITypeInfo
public void setCache(ITypeCache typeCache) {
fTypeCache = typeCache;
}
+
+ public void addDerivedReference(ITypeReference location) {
+ if (fDerivedSourceRefs == null) {
+ fDerivedSourceRefs = new ITypeReference[INITIAL_REFS_SIZE];
+ fDerivedSourceRefsCount = 0;
+ } else if (fDerivedSourceRefsCount == fDerivedSourceRefs.length) {
+ ITypeReference[] refs = new ITypeReference[fDerivedSourceRefs.length + REFS_GROW_BY];
+ System.arraycopy(fDerivedSourceRefs, 0, refs, 0, fDerivedSourceRefsCount);
+ fDerivedSourceRefs = refs;
+ }
+ fDerivedSourceRefs[fDerivedSourceRefsCount] = location;
+ ++fDerivedSourceRefsCount;
+ }
+
+ public ITypeReference[] getDerivedReferences() {
+ if (fDerivedSourceRefs != null) {
+ ITypeReference[] refs = new ITypeReference[fDerivedSourceRefsCount];
+ System.arraycopy(fDerivedSourceRefs, 0, refs, 0, fDerivedSourceRefsCount);
+ return refs;
+ }
+ return null;
+ }
+
+ public boolean hasSubTypes() {
+ return (fDerivedSourceRefs != null);
+ }
+
+ public ITypeInfo[] getSubTypes() {
+ if (fTypeCache != null) {
+ return fTypeCache.getSubtypes(this);
+ }
+ return null;
+ }
+
+ public boolean hasSuperTypes() {
+ if (fTypeCache != null) {
+ return (fTypeCache.getSupertypes(this) != null);
+ }
+ return false;
+// return true; //TODO can't know this until we parse
+ }
+
+ public ITypeInfo[] getSuperTypes() {
+ if (fTypeCache != null) {
+ return fTypeCache.getSupertypes(this);
+ }
+ return null;
+ }
+
+ public ASTAccessVisibility getSuperTypeAccess(ITypeInfo superType) {
+ if (fTypeCache != null) {
+ return fTypeCache.getSupertypeAccess(this, superType);
+ }
+ return null;
+ }
+
+ public boolean isClass() {
+ return (fElementType == ICElement.C_CLASS
+ || fElementType == ICElement.C_STRUCT);
+ }
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java
new file mode 100644
index 00000000000..9168ff6a686
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java
@@ -0,0 +1,282 @@
+/*
+ * Created on Jul 5, 2004
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+package org.eclipse.cdt.core.browser;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.Flags;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementVisitor;
+import org.eclipse.cdt.core.model.ICProject;
+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;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+/**
+ * @author CWiebe
+ *
+ * TODO To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+public class TypeUtil {
+
+ public static ICElement getDeclaringType(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);
+ }
+
+ public static ICElement[] getTypes(ICElement elem) {
+ final List typeList = new ArrayList(3);
+ try {
+ elem.accept(new ICElementVisitor() {
+ public boolean visit(ICElement element) throws CoreException {
+ // TODO Auto-generated method stub
+ if (element instanceof IStructure) {
+ typeList.add(element);
+ }
+ return false;
+ }});
+ } catch (CoreException e) {
+ }
+ return (ICElement[])typeList.toArray(new ICElement[typeList.size()]);
+ }
+
+ 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 ITypeInfo getTypeForElement(ICElement elem, IProgressMonitor monitor) {
+ if (elem != null) {
+ ICProject cProject = elem.getCProject();
+ IQualifiedTypeName qualifiedName = getFullyQualifiedName(elem);
+ if (qualifiedName != null) {
+ final ITypeSearchScope fScope = new TypeSearchScope(true);
+ if (!AllTypesCache.isCacheUpToDate(fScope)) {
+ AllTypesCache.updateCache(fScope, monitor);
+ }
+
+ ITypeCache cache = TypeCacheManager.getInstance().getCache(cProject.getProject());
+ ITypeInfo info = cache.getType(elem.getElementType(), qualifiedName);
+ if (info != null) {
+ ITypeReference ref = info.getResolvedReference();
+ if (ref == null) {
+ ref = AllTypesCache.resolveTypeLocation(info, monitor);
+ }
+ return info;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static ITypeInfo getTypeForElement(ICElement elem) {
+ return getTypeForElement(elem, new NullProgressMonitor());
+ }
+
+ public static ICElement getElementForType(ITypeInfo type, IProgressMonitor monitor) {
+ final ITypeSearchScope fScope = new TypeSearchScope(true);
+ if (!AllTypesCache.isCacheUpToDate(fScope)) {
+ AllTypesCache.updateCache(fScope, monitor);
+ }
+ ITypeReference ref = type.getResolvedReference();
+ if (ref == null) {
+ ref = AllTypesCache.resolveTypeLocation(type, monitor);
+ }
+ if (ref != null) {
+ ICElement[] elems = ref.getCElements();
+ if (elems != null && elems.length > 0) {
+ if (elems.length == 1)
+ return elems[0];
+
+ for (int i = 0; i < elems.length; ++i) {
+ ICElement elem = elems[i];
+ if (elem.getElementType() == type.getCElementType() && elem.getElementName().equals(type.getName())) {
+ //TODO should check fully qualified name
+ return elem;
+ }
+ }
+ }
+ }
+ return null;
+ }
+ public static ICElement getElementForType(ITypeInfo type) {
+ return getElementForType(type, new NullProgressMonitor());
+ }
+
+ 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 (IMethodDeclaration[]) 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 (ICElement[]) 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. {"QString;","I"}
+ * @param isConstructor If the method is a constructor
+ * @param methods The methods to search in
+ * @return The found method or null
, 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. {"QString;","I"}
+ * @param isConstructor Specifies if the method is a constructor
+ * @return Returns true
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++) {
+ String t1= Signature.getSimpleName(Signature.toString(paramTypes[i]));
+ String t2= Signature.getSimpleName(Signature.toString(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. {"QString;","I"}
+ * @param isConstructor If the method is a constructor
+ * @return The first found method or null
, 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));
+ }
+
+ /**
+ * Finds a method declararion in a type's hierarchy. The search is top down, so this
+ * returns the first declaration of the method in the hierarchy.
+ * 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 type Searches in this type's supertypes.
+ * @param name The name of the method to find
+ * @param paramTypes The type signatures of the parameters e.g. {"QString;","I"}
+ * @param isConstructor If the method is a constructor
+ * @return The first method found or null, if nothing found
+ */
+// TODO move methods to CModelUtil
+ public static IMethodDeclaration findMethodDeclarationInHierarchy(ITypeHierarchy hierarchy, ICElement type, String name, String[] paramTypes, boolean isConstructor, boolean isDestructor) throws CModelException {
+ ICElement[] superTypes= hierarchy.getAllSupertypes(type);
+ for (int i= superTypes.length - 1; i >= 0; i--) {
+ IMethodDeclaration first= findMethod(name, paramTypes, isConstructor, isDestructor, superTypes[i]);
+ if (first != null && first.getVisibility() != ASTAccessVisibility.PRIVATE) {
+ // the order getAllSupertypes does make assumptions of the order of inner elements -> search recursivly
+ IMethodDeclaration res= findMethodDeclarationInHierarchy(hierarchy, TypeUtil.getDeclaringType(first), name, paramTypes, isConstructor, isDestructor);
+ if (res != null) {
+ return res;
+ }
+ return first;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java
new file mode 100644
index 00000000000..8dd7b729af0
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.cdt.core.browser.TypeUtil;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.model.IMember;
+import org.eclipse.cdt.core.model.IParent;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.internal.core.model.CElement;
+
+/*
+ * Collects changes (reported through fine-grained deltas) that can affect a type hierarchy.
+ */
+public class ChangeCollector {
+
+ /*
+ * A table from ICElements to TypeDeltas
+ */
+ HashMap changes = new HashMap();
+
+ TypeHierarchy hierarchy;
+
+ public ChangeCollector(TypeHierarchy hierarchy) {
+ this.hierarchy = hierarchy;
+ }
+
+ /*
+ * Adds the children of the given delta to the list of changes.
+ */
+ private void addAffectedChildren(ICElementDelta delta) throws CModelException {
+// ICElementDelta[] children = delta.getAffectedChildren();
+// for (int i = 0, length = children.length; i < length; i++) {
+// ICElementDelta child = children[i];
+// ICElement childElement = child.getElement();
+// switch (childElement.getElementType()) {
+// case ICElement.IMPORT_CONTAINER:
+// addChange((IImportContainer)childElement, child);
+// break;
+// case ICElement.IMPORT_DECLARATION:
+// addChange((IImportDeclaration)childElement, child);
+// break;
+// case ICElement.TYPE:
+// addChange((ICElement)childElement, child);
+// break;
+// case ICElement.INITIALIZER:
+// case ICElement.FIELD:
+// case ICElement.METHOD:
+// addChange((IMember)childElement, child);
+// break;
+// }
+// }
+ }
+
+ /*
+ * Adds the given delta on a compilation unit to the list of changes.
+ */
+ public void addChange(ITranslationUnit cu, ICElementDelta newDelta) throws CModelException {
+// int newKind = newDelta.getKind();
+// switch (newKind) {
+// case ICElementDelta.ADDED:
+// ArrayList allTypes = new ArrayList();
+// getAllTypesFromElement(cu, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement type = (ICElement)allTypes.get(i);
+// addTypeAddition(type, (SimpleDelta)this.changes.get(type));
+// }
+// break;
+// case ICElementDelta.REMOVED:
+// allTypes = new ArrayList();
+// getAllTypesFromHierarchy((JavaElement)cu, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement type = (ICElement)allTypes.get(i);
+// addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
+// }
+// break;
+// case ICElementDelta.CHANGED:
+// addAffectedChildren(newDelta);
+// break;
+// }
+ }
+
+/* private void addChange(IImportContainer importContainer, ICElementDelta newDelta) throws CModelException {
+ int newKind = newDelta.getKind();
+ if (newKind == ICElementDelta.CHANGED) {
+ addAffectedChildren(newDelta);
+ return;
+ }
+ SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importContainer);
+ if (existingDelta != null) {
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ if (existingDelta.getKind() == ICElementDelta.REMOVED) {
+ // REMOVED then ADDED
+ this.changes.remove(importContainer);
+ }
+ break;
+ case ICElementDelta.REMOVED:
+ if (existingDelta.getKind() == ICElementDelta.ADDED) {
+ // ADDED then REMOVED
+ this.changes.remove(importContainer);
+ }
+ break;
+ // CHANGED handled above
+ }
+ } else {
+ SimpleDelta delta = new SimpleDelta();
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ delta.added();
+ break;
+ case ICElementDelta.REMOVED:
+ delta.removed();
+ break;
+ }
+ this.changes.put(importContainer, delta);
+ }
+ }
+
+ private void addChange(IImportDeclaration importDecl, ICElementDelta newDelta) {
+ SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importDecl);
+ int newKind = newDelta.getKind();
+ if (existingDelta != null) {
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ if (existingDelta.getKind() == ICElementDelta.REMOVED) {
+ // REMOVED then ADDED
+ this.changes.remove(importDecl);
+ }
+ break;
+ case ICElementDelta.REMOVED:
+ if (existingDelta.getKind() == ICElementDelta.ADDED) {
+ // ADDED then REMOVED
+ this.changes.remove(importDecl);
+ }
+ break;
+ // CHANGED cannot happen for import declaration
+ }
+ } else {
+ SimpleDelta delta = new SimpleDelta();
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ delta.added();
+ break;
+ case ICElementDelta.REMOVED:
+ delta.removed();
+ break;
+ }
+ this.changes.put(importDecl, delta);
+ }
+ }
+*/
+
+ /*
+ * Adds a change for the given member (a method, a field or an initializer) and the types it defines.
+ */
+ private void addChange(IMember member, ICElementDelta newDelta) throws CModelException {
+// int newKind = newDelta.getKind();
+// switch (newKind) {
+// case ICElementDelta.ADDED:
+// ArrayList allTypes = new ArrayList();
+// getAllTypesFromElement(member, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement innerType = (ICElement)allTypes.get(i);
+// addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
+// }
+// break;
+// case ICElementDelta.REMOVED:
+// allTypes = new ArrayList();
+// getAllTypesFromHierarchy((JavaElement)member, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement type = (ICElement)allTypes.get(i);
+// addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
+// }
+// break;
+// case ICElementDelta.CHANGED:
+// addAffectedChildren(newDelta);
+// break;
+// }
+ }
+
+ /*
+ * Adds a change for the given type and the types it defines.
+ */
+ private void addChange(ICElement type, ICElementDelta newDelta) throws CModelException {
+// int newKind = newDelta.getKind();
+// SimpleDelta existingDelta = (SimpleDelta)this.changes.get(type);
+// switch (newKind) {
+// case ICElementDelta.ADDED:
+// addTypeAddition(type, existingDelta);
+// ArrayList allTypes = new ArrayList();
+// getAllTypesFromElement(type, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement innerType = (ICElement)allTypes.get(i);
+// addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
+// }
+// break;
+// case ICElementDelta.REMOVED:
+// addTypeRemoval(type, existingDelta);
+// allTypes = new ArrayList();
+// getAllTypesFromHierarchy((JavaElement)type, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement innerType = (ICElement)allTypes.get(i);
+// addTypeRemoval(innerType, (SimpleDelta)this.changes.get(innerType));
+// }
+// break;
+// case ICElementDelta.CHANGED:
+// addTypeChange(type, newDelta.getFlags(), existingDelta);
+// addAffectedChildren(newDelta);
+// break;
+// }
+ }
+
+/* private void addTypeAddition(ICElement type, SimpleDelta existingDelta) throws CModelException {
+ if (existingDelta != null) {
+ switch (existingDelta.getKind()) {
+ case ICElementDelta.REMOVED:
+ // REMOVED then ADDED
+ boolean hasChange = false;
+ if (hasSuperTypeChange(type)) {
+ existingDelta.superTypes();
+ hasChange = true;
+ }
+ if (hasVisibilityChange(type)) {
+ existingDelta.modifiers();
+ hasChange = true;
+ }
+ if (!hasChange) {
+ this.changes.remove(type);
+ }
+ break;
+ // CHANGED then ADDED
+ // or ADDED then ADDED: should not happen
+ }
+ } else {
+ // check whether the type addition affects the hierarchy
+ String typeName = type.getElementName();
+ if (this.hierarchy.hasSupertype(typeName)
+ || this.hierarchy.subtypesIncludeSupertypeOf(type)
+ || this.hierarchy.missingTypes.contains(typeName)) {
+ SimpleDelta delta = new SimpleDelta();
+ delta.added();
+ this.changes.put(type, delta);
+ }
+ }
+ }
+*/
+/* private void addTypeChange(ICElement type, int newFlags, SimpleDelta existingDelta) throws CModelException {
+ if (existingDelta != null) {
+ switch (existingDelta.getKind()) {
+ case ICElementDelta.CHANGED:
+ // CHANGED then CHANGED
+ int existingFlags = existingDelta.getFlags();
+ boolean hasChange = false;
+ if ((existingFlags & ICElementDelta.F_SUPER_TYPES) != 0
+ && hasSuperTypeChange(type)) {
+ existingDelta.superTypes();
+ hasChange = true;
+ }
+ if ((existingFlags & ICElementDelta.F_MODIFIERS) != 0
+ && hasVisibilityChange(type)) {
+ existingDelta.modifiers();
+ hasChange = true;
+ }
+ if (!hasChange) {
+ // super types and visibility are back to the ones in the existing hierarchy
+ this.changes.remove(type);
+ }
+ break;
+ // ADDED then CHANGED: leave it as ADDED
+ // REMOVED then CHANGED: should not happen
+ }
+ } else {
+ // check whether the type change affects the hierarchy
+ SimpleDelta typeDelta = null;
+ if ((newFlags & ICElementDelta.F_SUPER_TYPES) != 0
+ && this.hierarchy.includesTypeOrSupertype(type)) {
+ typeDelta = new SimpleDelta();
+ typeDelta.superTypes();
+ }
+ if ((newFlags & ICElementDelta.F_MODIFIERS) != 0
+ && this.hierarchy.hasSupertype(type.getElementName())) {
+ if (typeDelta == null) {
+ typeDelta = new SimpleDelta();
+ }
+ typeDelta.modifiers();
+ }
+ if (typeDelta != null) {
+ this.changes.put(type, typeDelta);
+ }
+ }
+ }
+*/
+/* private void addTypeRemoval(ICElement type, SimpleDelta existingDelta) {
+ if (existingDelta != null) {
+ switch (existingDelta.getKind()) {
+ case ICElementDelta.ADDED:
+ // ADDED then REMOVED
+ this.changes.remove(type);
+ break;
+ case ICElementDelta.CHANGED:
+ // CHANGED then REMOVED
+ existingDelta.removed();
+ break;
+ // REMOVED then REMOVED: should not happen
+ }
+ } else {
+ // check whether the type removal affects the hierarchy
+ if (this.hierarchy.contains(type)) {
+ SimpleDelta typeDelta = new SimpleDelta();
+ typeDelta.removed();
+ this.changes.put(type, typeDelta);
+ }
+ }
+ }
+*/
+ /*
+ * Returns all types defined in the given element excluding the given element.
+ */
+ private void getAllTypesFromElement(ICElement element, ArrayList allTypes) throws CModelException {
+ switch (element.getElementType()) {
+ case ICElement.C_UNIT:
+ ICElement[] types = TypeUtil.getTypes((ITranslationUnit)element);
+ for (int i = 0, length = types.length; i < length; i++) {
+ ICElement type = types[i];
+ allTypes.add(type);
+ getAllTypesFromElement(type, allTypes);
+ }
+ break;
+ case ICElement.C_CLASS:
+ case ICElement.C_STRUCT:
+// types = ((ICElement)element).getTypes();
+ types = TypeUtil.getTypes((ICElement)element);
+ for (int i = 0, length = types.length; i < length; i++) {
+ ICElement type = types[i];
+ allTypes.add(type);
+ getAllTypesFromElement(type, allTypes);
+ }
+ break;
+// case ICElement.INITIALIZER:
+// case ICElement.FIELD:
+ case ICElement.C_METHOD:
+ if (element instanceof IParent) {
+ ICElement[] children = ((IParent)element).getChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ ICElement type = (ICElement)children[i];
+ allTypes.add(type);
+ getAllTypesFromElement(type, allTypes);
+ }
+ }
+ break;
+ }
+ }
+
+ /*
+ * Returns all types in the existing hierarchy that have the given element as a parent.
+ */
+ private void getAllTypesFromHierarchy(CElement element, ArrayList allTypes) {
+ switch (element.getElementType()) {
+ case ICElement.C_UNIT:
+ ArrayList types = (ArrayList)this.hierarchy.files.get(element);
+ if (types != null) {
+ allTypes.addAll(types);
+ }
+ break;
+ case ICElement.C_CLASS:
+ case ICElement.C_STRUCT:
+// case ICElement.INITIALIZER:
+// case ICElement.FIELD:
+ case ICElement.C_METHOD:
+ types = (ArrayList)this.hierarchy.files.get(((IMember)element).getTranslationUnit());
+ if (types != null) {
+ for (int i = 0, length = types.size(); i < length; i++) {
+ ICElement type = (ICElement)types.get(i);
+ if (element.isAncestorOf(type)) {
+ allTypes.add(type);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ private boolean hasSuperTypeChange(ICElement type) throws CModelException {
+// // check super class
+// ICElement superclass = this.hierarchy.getSuperclass(type);
+// String existingSuperclassName = superclass == null ? null : superclass.getElementName();
+// String newSuperclassName = type.getSuperclassName();
+// if (existingSuperclassName != null && !existingSuperclassName.equals(newSuperclassName)) {
+// return true;
+// }
+//
+// // check super interfaces
+// ICElement[] existingSuperInterfaces = this.hierarchy.getSuperInterfaces(type);
+// String[] newSuperInterfaces = type.getSuperInterfaceNames();
+// if (existingSuperInterfaces.length != newSuperInterfaces.length) {
+// return true;
+// }
+// for (int i = 0, length = newSuperInterfaces.length; i < length; i++) {
+// String superInterfaceName = newSuperInterfaces[i];
+// if (!superInterfaceName.equals(newSuperInterfaces[i])) {
+// return true;
+// }
+// }
+
+ return false;
+ }
+
+ private boolean hasVisibilityChange(ICElement type) throws CModelException {
+// int existingFlags = this.hierarchy.getCachedFlags(type);
+// int newFlags = type.getFlags();
+// return existingFlags != newFlags;
+ return false;
+ }
+
+ /*
+ * Whether the hierarchy needs refresh according to the changes collected so far.
+ */
+ public boolean needsRefresh() {
+ return changes.size() != 0;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ Iterator iterator = this.changes.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Map.Entry)iterator.next();
+ buffer.append(((CElement)entry.getKey()).toDebugString());
+ buffer.append(entry.getValue());
+ if (iterator.hasNext()) {
+ buffer.append('\n');
+ }
+ }
+ return buffer.toString();
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java
new file mode 100644
index 00000000000..d6838a269d6
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.io.OutputStream;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A type hierarchy provides navigations between a type and its resolved
+ * supertypes and subtypes for a specific type or for all types within a region.
+ * Supertypes may extend outside of the type hierarchy's region in which it was
+ * created such that the root of the hierarchy is always included. For example, if a type
+ * hierarchy is created for a java.io.File
, and the region the hierarchy was
+ * created in is the package fragment java.io
, the supertype
+ * java.lang.Object
will still be included.
+ *
+ * A type hierarchy is static and can become stale. Although consistent when
+ * created, it does not automatically track changes in the model.
+ * As changes in the model potentially invalidate the hierarchy, change notifications
+ * are sent to registered ICElementHierarchyChangedListener
s. Listeners should
+ * use the exists
method to determine if the hierarchy has become completely
+ * invalid (for example, when the type or project the hierarchy was created on
+ * has been removed). To refresh a hierarchy, use the refresh
method.
+ *
+ * The type hierarchy may contain cycles due to malformed supertype declarations.
+ * Most type hierarchy queries are oblivious to cycles; the getAll*
+ * methods are implemented such that they are unaffected by cycles.
+ *
+ * This interface is not intended to be implemented by clients. + *
+ */ +public interface ITypeHierarchy { +/** + * Adds the given listener for changes to this type hierarchy. Listeners are + * notified when this type hierarchy changes and needs to be refreshed. + * Has no effect if an identical listener is already registered. + * + * @param listener the listener + */ +void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener); +/** + * Returns whether the given type is part of this hierarchy. + * + * @param type the given type + * @return true if the given type is part of this hierarchy, false otherwise + */ +boolean contains(ICElement type); +/** + * Returns whether the type and project this hierarchy was created on exist. + * @return true if the type and project this hierarchy was created on exist, false otherwise + */ +boolean exists(); + +/** + * Returns all resolved subtypes (direct and indirect) of the + * given type, in no particular order, limited to the + * types in this type hierarchy's graph. An empty array + * is returned if there are no resolved subtypes for the + * given type. + * + * @param type the given type + * @return all resolved subtypes (direct and indirect) of the given type + */ +ICElement[] getAllSubtypes(ICElement type); +/** + * Returns all resolved superclasses of the + * given class, in bottom-up order. An empty array + * is returned if there are no resolved superclasses for the + * given class. + * + *NOTE: once a type hierarchy has been created, it is more efficient to
+ * query the hierarchy for superclasses than to query a class recursively up
+ * the superclass chain. Querying an element performs a dynamic resolution,
+ * whereas the hierarchy returns a pre-computed result.
+ *
+ * @param type the given type
+ * @return all resolved superclasses of the given class, in bottom-up order, an empty
+ * array if none.
+ */
+ICElement[] getAllSupertypes(ICElement type);
+
+/**
+ * Returns all classes in the graph which have no resolved superclass,
+ * in no particular order.
+ *
+ * @return all classes in the graph which have no resolved superclass
+ */
+ICElement[] getRootClasses();
+
+/**
+ * Returns the direct resolved subtypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * If the type is a class, this returns the resolved subclasses.
+ * If the type is an interface, this returns both the classes which implement
+ * the interface and the interfaces which extend it.
+ *
+ * @param type the given type
+ * @return the direct resolved subtypes of the given type limited to the types in this
+ * type hierarchy's graph
+ */
+ICElement[] getSubtypes(ICElement type);
+
+/**
+ * Returns the resolved supertypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * For classes, this returns its superclass and the interfaces that the class implements.
+ * For interfaces, this returns the interfaces that the interface extends. As a consequence
+ * java.lang.Object
is NOT considered to be a supertype of any interface
+ * type.
+ *
+ * @param type the given type
+ * @return the resolved supertypes of the given type limited to the types in this
+ * type hierarchy's graph
+ */
+ICElement[] getSupertypes(ICElement type);
+/**
+ * Returns the type this hierarchy was computed for.
+ * Returns null
if this hierarchy was computed for a region.
+ *
+ * @return the type this hierarchy was computed for
+ */
+ICElement getType();
+/**
+ * Re-computes the type hierarchy reporting progress.
+ *
+ * @param monitor the given progress monitor
+ * @exception JavaModelException if unable to refresh the hierarchy
+ */
+void refresh(IProgressMonitor monitor) throws CModelException;
+/**
+ * Removes the given listener from this type hierarchy.
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ */
+void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
+/**
+ * Stores the type hierarchy in an output stream. This stored hierarchy can be load by
+ * ICElement#loadTypeHierachy(IJavaProject, InputStream, IProgressMonitor).
+ * Listeners of this hierarchy are not stored.
+ *
+ * Only hierarchies created by the following methods can be store:
+ *
+ * This interface may be implemented by clients. + *
+ */ +public interface ITypeHierarchyChangedListener { + /** + * Notifies that the given type hierarchy has changed in some way and should + * be refreshed at some point to make it consistent with the current state of + * the Java model. + * + * @param typeHierarchy the given type hierarchy + */ + void typeHierarchyChanged(ITypeHierarchy typeHierarchy); +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java new file mode 100644 index 00000000000..5978c9dcdde --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java @@ -0,0 +1,591 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.browser.typehierarchy; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.ICLogConstants; +import org.eclipse.cdt.core.browser.AllTypesCache; +import org.eclipse.cdt.core.browser.ITypeInfo; +import org.eclipse.cdt.core.browser.TypeUtil; +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ElementChangedEvent; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICElementDelta; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.IElementChangedListener; +import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; +import org.eclipse.cdt.core.search.ICSearchScope; +import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager; +import org.eclipse.cdt.internal.core.model.CElement; +import org.eclipse.cdt.internal.core.model.Util; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.Platform; + +public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { + + public static boolean DEBUG = false; + + private static final class TypeEntry { + ITypeInfo type; + ASTAccessVisibility access; + TypeEntry(ITypeInfo type, ASTAccessVisibility access) { + this.type = type; + this.access = access; + } + } + private static final int INITIAL_SUPER_TYPES = 1; + private static final int INITIAL_SUB_TYPES = 1; + private static final ITypeInfo[] NO_TYPES = new ITypeInfo[0]; + private ArrayList fAllTypes = new ArrayList(); + private ArrayList fRootTypes = new ArrayList(); + private Map fTypeToSuperTypes = new HashMap(); + private Map fTypeToSubTypes = new HashMap(); + + private ITypeInfo fFocusType; + + /** + * The progress monitor to report work completed too. + */ + protected IProgressMonitor fProgressMonitor = null; + /** + * Change listeners - null if no one is listening. + */ + protected ArrayList fChangeListeners = null; + + /* + * A map from Openables to ArrayLists of ITypes + */ + public Map files = null; + + /** + * Whether this hierarchy should contains subtypes. + */ + protected boolean fComputeSubtypes; + + /** + * The scope this hierarchy should restrain itsef in. + */ + ICSearchScope fScope; + + /* + * Whether this hierarchy needs refresh + */ + public boolean fNeedsRefresh = true; + /* + * Collects changes to types + */ + protected ChangeCollector fChangeCollector; + + + + /** + * Creates a TypeHierarchy on the given type. + */ + public TypeHierarchy(ITypeInfo type) { + fFocusType = type; + } + + /** + * Adds the type to the collection of root classes + * if the classes is not already present in the collection. + */ + public void addRootType(ITypeInfo type) { + if (!fRootTypes.contains(type)) { + fRootTypes.add(type); + } + } + + /** + * Adds the given supertype to the type. + */ + public void addSuperType(ITypeInfo type, ITypeInfo superType, ASTAccessVisibility access) { + Collection superEntries = (Collection) fTypeToSuperTypes.get(type); + if (superEntries == null) { + superEntries = new ArrayList(INITIAL_SUPER_TYPES); + fTypeToSuperTypes.put(type, superEntries); + } + Collection subTypes = (Collection) fTypeToSubTypes.get(superType); + if (subTypes == null) { + subTypes = new ArrayList(INITIAL_SUB_TYPES); + fTypeToSubTypes.put(superType, subTypes); + } + if (!subTypes.contains(type)) { + subTypes.add(type); + } + for (Iterator i = superEntries.iterator(); i.hasNext(); ) { + TypeEntry entry = (TypeEntry)i.next(); + if (entry.type.equals(superType)) { + // update the access + entry.access = access; + return; // don't add if already exists + } + } + TypeEntry typeEntry = new TypeEntry(superType, access); + superEntries.add(typeEntry); + } + + /** + * Adds the given subtype to the type. + */ + protected void addSubType(ITypeInfo type, ITypeInfo subType) { + Collection subTypes = (Collection) fTypeToSubTypes.get(type); + if (subTypes == null) { + subTypes = new ArrayList(INITIAL_SUB_TYPES); + fTypeToSubTypes.put(type, subTypes); + } + if (!subTypes.contains(subType)) { + subTypes.add(subType); + } + + Collection superEntries = (Collection) fTypeToSuperTypes.get(subType); + if (superEntries == null) { + superEntries = new ArrayList(INITIAL_SUPER_TYPES); + fTypeToSuperTypes.put(subType, superEntries); + } + for (Iterator i = superEntries.iterator(); i.hasNext(); ) { + TypeEntry entry = (TypeEntry)i.next(); + if (entry.type.equals(type)) + return; // don't add if already exists + } + // default to private access + TypeEntry typeEntry = new TypeEntry(type, ASTAccessVisibility.PRIVATE); + superEntries.add(typeEntry); + } + + /** + * Returns true if type already has the given supertype. + */ + public boolean hasSuperType(ITypeInfo type, ITypeInfo superType) { + Collection entries = (Collection) fTypeToSuperTypes.get(type); + if (entries != null) { + for (Iterator i = entries.iterator(); i.hasNext(); ) { + TypeEntry entry = (TypeEntry)i.next(); + if (entry.type.equals(superType)) + return true; + } + } + return false; + } + + /** + * Returns an array of supertypes for the given type - will never return null. + */ + public ITypeInfo[] getSuperTypes(ITypeInfo type) { + Collection entries = (Collection) fTypeToSuperTypes.get(type); + if (entries != null) { + ArrayList superTypes = new ArrayList(INITIAL_SUPER_TYPES); + for (Iterator i = entries.iterator(); i.hasNext(); ) { + TypeEntry entry = (TypeEntry)i.next(); + superTypes.add(entry.type); + } + return (ITypeInfo[])superTypes.toArray(new ITypeInfo[superTypes.size()]); + } + return NO_TYPES; + } + + /** + * Returns an array of subtypes for the given type - will never return null. + */ + public ITypeInfo[] getSubTypes(ITypeInfo type) { + Collection subTypes = (Collection) fTypeToSubTypes.get(type); + if (subTypes != null) { + return (ITypeInfo[])subTypes.toArray(new ITypeInfo[subTypes.size()]); + } + return NO_TYPES; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#addTypeHierarchyChangedListener(org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchyChangedListener) + */ + public void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) { + ArrayList listeners = fChangeListeners; + if (listeners == null) { + fChangeListeners = listeners = new ArrayList(); + } + + // register with JavaCore to get Java element delta on first listener added + if (listeners.size() == 0) { + CoreModel.getDefault().addElementChangedListener(this); + } + + // add listener only if it is not already present + if (listeners.indexOf(listener) == -1) { + listeners.add(listener); + } + } + + + /** + * @see ITypeHierarchy + */ + public synchronized void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) { + ArrayList listeners = fChangeListeners; + if (listeners == null) { + return; + } + listeners.remove(listener); + + // deregister from JavaCore on last listener removed + if (listeners.isEmpty()) { + CoreModel.getDefault().removeElementChangedListener(this); + } + } + + /** + * Determines if the change effects this hierarchy, and fires + * change notification if required. + */ + public void elementChanged(ElementChangedEvent event) { + // type hierarchy change has already been fired + if (fNeedsRefresh) return; + + if (isAffected(event.getDelta())) { + fNeedsRefresh = true; + fireChange(); + } + } + + /** + * Returns true if the given delta could change this type hierarchy + */ + public synchronized boolean isAffected(ICElementDelta delta) { + ICElement element= delta.getElement(); +// switch (element.getElementType()) { +// case ICElement.C_MODEL: +// return isAffectedByCModel(delta, element); +// case ICElement.C_PROJECT: +// return isAffectedByCProject(delta, element); +// case ICElement.C_UNIT: +// return isAffectedByOpenable(delta, element); +// } +// return false; + return true; + } + + /** + * Notifies listeners that this hierarchy has changed and needs + * refreshing. Note that listeners can be removed as we iterate + * through the list. + */ + public void fireChange() { + ArrayList listeners = fChangeListeners; + if (listeners == null) { + return; + } + if (DEBUG) { + System.out.println("FIRING hierarchy change ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ + if (fFocusType != null) { + System.out.println(" for hierarchy focused on " + fFocusType.toString()); //$NON-NLS-1$ + } + } + // clone so that a listener cannot have a side-effect on this list when being notified + listeners = (ArrayList)listeners.clone(); + for (int i= 0; i < listeners.size(); i++) { + final ITypeHierarchyChangedListener listener= (ITypeHierarchyChangedListener)listeners.get(i); + Platform.run(new ISafeRunnable() { + public void handleException(Throwable exception) { + Util.log(exception, "Exception occurred in listener of Type hierarchy change notification", ICLogConstants.CDT); //$NON-NLS-1$ + } + public void run() throws Exception { + listener.typeHierarchyChanged(TypeHierarchy.this); + } + }); + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#contains(org.eclipse.cdt.core.model.ICElement) + */ + public boolean contains(ICElement type) { + // classes + ITypeInfo info = AllTypesCache.getTypeForElement(type); + + if (info == null) + return false; + + if (fTypeToSuperTypes.get(info) != null) { + return true; + } + + // root classes + if (fRootTypes.contains(type)) return true; + + return false; + } + + /** + * @see ITypeHierarchy + */ + public boolean exists() { + if (!fNeedsRefresh) return true; + + return (fFocusType == null || fFocusType.exists()) && cProject().exists(); + } + + /** + * Returns the C project this hierarchy was created in. + */ + public ICProject cProject() { + IProject project = fFocusType.getCache().getProject(); + return findCProject(project); + } + private ICProject findCProject(IProject project) { + try { + ICProject[] cProjects = CoreModel.getDefault().getCModel().getCProjects(); + if (cProjects != null) { + for (int i = 0; i < cProjects.length; ++i) { + ICProject cProject = cProjects[i]; + if (project.equals(cProjects[i].getProject())) + return cProject; + } + } + } catch (CModelException e) { + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllClasses() + */ + public ICElement[] getAllClasses() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getRootClasses() + */ + public ICElement[] getRootClasses() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSubtypes(org.eclipse.cdt.core.model.ICElement) + */ + public ICElement[] getSubtypes(ICElement type) { + List list = new ArrayList(); + ITypeInfo info = TypeUtil.getTypeForElement(type); + Collection entries = (Collection) fTypeToSubTypes.get(info); + if (entries != null) { + for (Iterator i = entries.iterator(); i.hasNext(); ) { + ITypeInfo subType = (ITypeInfo)i.next(); + ICElement elem = TypeUtil.getElementForType(subType); + if (elem != null) { + list.add(elem); + } + } + } + return (ICElement[])list.toArray(new ICElement[list.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement) + */ + public ICElement[] getAllSubtypes(ICElement type) { + List list = new ArrayList(); + ITypeInfo info = TypeUtil.getTypeForElement(type); + addSubs(info, list); + //convert list to ICElements + ICElement[] elems = new ICElement[list.size()]; + int count = 0; + for (Iterator i = list.iterator(); i.hasNext(); ) { + ITypeInfo subType = (ITypeInfo) i.next(); + elems[count++] = TypeUtil.getElementForType(subType); + } + return elems; + } + + private void addSubs(ITypeInfo type, List list) { + Collection entries = (Collection) fTypeToSubTypes.get(type); + if (entries != null) { + for (Iterator i = entries.iterator(); i.hasNext(); ) { + ITypeInfo subType = (ITypeInfo)i.next(); + if (!list.contains(subType)) { + list.add(subType); + } + addSubs(subType, list); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSupertypes(org.eclipse.cdt.core.model.ICElement) + */ + public ICElement[] getSupertypes(ICElement type) { + List list = new ArrayList(); + ITypeInfo info = TypeUtil.getTypeForElement(type); + Collection entries = (Collection) fTypeToSuperTypes.get(info); + if (entries != null) { + for (Iterator i = entries.iterator(); i.hasNext(); ) { + TypeEntry entry = (TypeEntry)i.next(); + ITypeInfo superType = entry.type; + ICElement elem = TypeUtil.getElementForType(superType); + if (elem != null) { + list.add(elem); + } + } + } + return (ICElement[])list.toArray(new ICElement[list.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement) + */ + public ICElement[] getAllSupertypes(ICElement type) { + List list = new ArrayList(); + ITypeInfo info = TypeUtil.getTypeForElement(type); + addSupers(info, list); + //convert list to ICElements + ICElement[] elems = new ICElement[list.size()]; + int count = 0; + for (Iterator i = list.iterator(); i.hasNext(); ) { + ITypeInfo superType = (ITypeInfo) i.next(); + elems[count++] = TypeUtil.getElementForType(superType); + } + return elems; + } + + private void addSupers(ITypeInfo type, List list) { + Collection entries = (Collection) fTypeToSuperTypes.get(type); + if (entries != null) { + for (Iterator i = entries.iterator(); i.hasNext(); ) { + TypeEntry entry = (TypeEntry)i.next(); + ITypeInfo superType = entry.type; + if (!list.contains(superType)) { + list.add(superType); + } + addSupers(superType, list); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getType() + */ + public ICElement getType() { + if (fFocusType != null) + return TypeUtil.getElementForType(fFocusType); + return null; + } + + /** + * @see ITypeHierarchy + * TODO (jerome) should use a PerThreadObject to build the hierarchy instead of synchronizing + * (see also isAffected(IJavaElementDelta)) + */ + public synchronized void refresh(IProgressMonitor monitor) throws CModelException { + try { + fProgressMonitor = monitor; + if (monitor != null) { + if (fFocusType != null) { + monitor.beginTask(TypeHierarchyMessages.getFormattedString("hierarchy.creatingOnType", fFocusType.getQualifiedTypeName().getFullyQualifiedName()), 100); //$NON-NLS-1$ + } else { + monitor.beginTask(TypeHierarchyMessages.getString("hierarchy.creating"), 100); //$NON-NLS-1$ + } + } + long start = -1; + if (DEBUG) { + start = System.currentTimeMillis(); + if (fComputeSubtypes) { + System.out.println("CREATING TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + System.out.println("CREATING SUPER TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (fFocusType != null) { + System.out.println(" on type " + fFocusType.toString()); //$NON-NLS-1$ + } + } + + compute(); +// initializeRegions(); + fNeedsRefresh = false; + fChangeCollector = null; + + if (DEBUG) { + if (fComputeSubtypes) { + System.out.println("CREATED TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + System.out.println("CREATED SUPER TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ + } + System.out.println(this.toString()); + } + } catch (CModelException e) { + throw e; + } catch (CoreException e) { + throw new CModelException(e); + } finally { + if (monitor != null) { + monitor.done(); + } + fProgressMonitor = null; + } + } + + /** + * Compute this type hierarchy. + */ + protected void compute() throws CModelException, CoreException { + if (fFocusType != null) { +// HierarchyBuilder builder = +// new IndexBasedHierarchyBuilder( +// this, +// this.scope); +// builder.build(this.computeSubtypes); + +// initialize(1); +// buildSupertypes(); + + } // else a RegionBasedTypeHierarchy should be used + } + + /** + * Initializes this hierarchy's internal tables with the given size. + */ + /* protected void initialize(int size) { + if (size < 10) { + size = 10; + } + int smallSize = (size / 2); + this.classToSuperclass = new HashMap(size); + this.interfaces = new ArrayList(smallSize); + this.missingTypes = new ArrayList(smallSize); + this.rootClasses = new TypeVector(); + this.typeToSubtypes = new HashMap(smallSize); + this.typeToSuperInterfaces = new HashMap(smallSize); + this.typeFlags = new HashMap(smallSize); + + this.projectRegion = new Region(); + this.packageRegion = new Region(); + this.files = new HashMap(5); + } +*/ + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#store(java.io.OutputStream, org.eclipse.core.runtime.IProgressMonitor) + */ + public void store(OutputStream outputStream, IProgressMonitor monitor) throws CModelException { + // TODO Auto-generated method stub + + } + +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java new file mode 100644 index 00000000000..1e0f08bb812 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.browser.typehierarchy; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.cdt.core.browser.ITypeInfo; +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.ICModelStatusConstants; +import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; +import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager; +import org.eclipse.cdt.internal.core.model.CModelStatus; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.jobs.Job; + +public class TypeHierarchyBuilder { + + public TypeHierarchyBuilder() { + } + + public ITypeHierarchy createTypeHierarchy(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException { + TypeHierarchy typeHierarchy = new TypeHierarchy(info); + Set processedTypes = new HashSet(); + addSuperClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor); + + typeHierarchy.addRootType(info); + processedTypes.clear(); + addSubClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor); + + return typeHierarchy; + } + + private void addSuperClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException { + if (type.hasSuperTypes()) { + ITypeInfo[] superTypes = TypeCacheManager.getInstance().locateSuperTypesAndWait(type, enableIndexing, Job.SHORT, monitor); + if (superTypes == null) + throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST)); + + for (int i = 0; i < superTypes.length; ++i) { + ITypeInfo superType = superTypes[i]; + + // recursively process sub sub classes + if (!processedTypes.contains(superType)) { + processedTypes.add(superType); + addSuperClasses(typeHierarchy, superType, processedTypes, enableIndexing, monitor); + } + + ASTAccessVisibility access = type.getSuperTypeAccess(superType); + + typeHierarchy.addSuperType(type, superType, access); + } + } else { + typeHierarchy.addRootType(type); + } + } + + private void addSubClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException { + if (type.hasSubTypes()) { + ITypeInfo[] subTypes = TypeCacheManager.getInstance().locateSubTypesAndWait(type, enableIndexing, Job.SHORT, monitor); + if (subTypes == null) + throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST)); + + for (int i = 0; i < subTypes.length; ++i) { + ITypeInfo subType = subTypes[i]; + + // recursively process sub sub classes + if (!processedTypes.contains(subType)) { + processedTypes.add(subType); + addSubClasses(typeHierarchy, subType, processedTypes, enableIndexing, monitor); + } + + typeHierarchy.addSubType(type, subType); + } + } + } + +/* + private IStructure findCElementForType(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException { + if (!info.exists()) + throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST)); + + if (!info.isClass()) + throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES)); + + // first we need to resolve the type location + ITypeReference location = TypeCacheManager.getInstance().locateTypeAndWait(info, enableIndexing, Job.SHORT, monitor); + if (location == null) + throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST)); + + ICElement cElem = location.getCElement(); + if (cElem == null) + throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST)); + + if (!(cElem instanceof IStructure)) + throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES)); + + IStructure cClass = (IStructure)cElem; + + // check if type exists in cache + ITypeInfo type = TypeCacheManager.getInstance().getTypeForElement(cElem); + if (type == null || !type.equals(info)) + throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST)); + + return cClass; + } + + private ITypeInfo findTypeInCache(ITypeCache cache, String name) { + IQualifiedTypeName qualName = new QualifiedTypeName(name); + ITypeInfo[] superTypes = cache.getTypes(qualName); + for (int i = 0; i < superTypes.length; ++i) { + ITypeInfo superType = superTypes[i]; + if (superType.isClass()) { + return superType; + } + } + return null; + } +*/ + +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java new file mode 100644 index 00000000000..1b0c37c2111 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.browser.typehierarchy; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class TypeHierarchyMessages { + + private static final String RESOURCE_BUNDLE= TypeHierarchyMessages.class.getName(); + + private static ResourceBundle fgResourceBundle; + static { + try { + fgResourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE); + } catch (MissingResourceException x) { + fgResourceBundle = null; + } + } + + private TypeHierarchyMessages() { + } + + public static String getString(String key) { + try { + return fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } catch (NullPointerException e) { + return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + public static String getFormattedString(String key, String arg) { + return getFormattedString(key, new String[] { arg }); + } + + public static String getFormattedString(String key, String[] args) { + return MessageFormat.format(getString(key), args); + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties new file mode 100644 index 00000000000..ce0159de55c --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties @@ -0,0 +1,17 @@ +############################################################################### +# Copyright (c) 2000, 2004 QNX Software Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Common Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/cpl-v10.html +# +# Contributors: +# QNX Software Systems - Initial API and implementation +############################################################################### + +### hierarchy +hierarchy.nullProject = Project argument cannot be null +hierarchy.nullRegion = Region cannot be null +hierarchy.nullFocusType = Type focus cannot be null +hierarchy.creating = Creating type hierarchy... +hierarchy.creatingOnType = Creating type hierarchy on {0}... diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java index 2f632033c6a..3e229984c4f 100644 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java @@ -15,6 +15,7 @@ import org.eclipse.cdt.core.browser.ITypeInfo; import org.eclipse.cdt.core.browser.ITypeInfoVisitor; import org.eclipse.cdt.core.browser.ITypeReference; import org.eclipse.cdt.core.browser.ITypeSearchScope; +import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; @@ -40,6 +41,22 @@ public interface ITypeCache extends ISchedulingRule { */ public void insert(ITypeInfo info); + /** Adds subtype to type. + * + * @param type + * @param subtype + */ + public void addSubtype(ITypeInfo type, ITypeInfo subtype); + + /** Adds supertype to type. + * + * @param type the type + * @param supertype the supertype + * @param the access visibility (PUBLIC, PROTECTED, PRIVATE) + * @param isVirtualtrue
if virtual base class
+ */
+ public void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual);
+
/** Removes type from cache.
*
* @param info
@@ -134,6 +151,29 @@ public interface ITypeCache extends ISchedulingRule {
*/
public ITypeInfo[] getEnclosedTypes(ITypeInfo info, int kinds[]);
+ /** Returns all types in the cache are supertypes of the given type.
+ *
+ * @param info the given type
+ * @return Array of supertypes, or null
if none found.
+ */
+ public ITypeInfo[] getSupertypes(ITypeInfo info);
+
+ /** Returns the supertype access visiblity.
+ *
+ * @param type the given type
+ * @param supertype the supertype
+ * @return the visibility (PRIVATE, PROTECTED, PUBLIC) or null
if none found.
+ */
+ public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType);
+
+
+ /** Returns all types in the cache which extend the given type.
+ *
+ * @param info the given type
+ * @return Array of subtypes, or null
if none found.
+ */
+ public ITypeInfo[] getSubtypes(ITypeInfo info);
+
/** Returns the project associated with this cache.
*
* @return the project
@@ -154,5 +194,11 @@ public interface ITypeCache extends ISchedulingRule {
public void locateType(ITypeInfo info, int priority, int delay);
public ITypeReference locateTypeAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+ public void locateSupertypes(ITypeInfo info, int priority, int delay);
+ public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+
+ public void locateSubtypes(ITypeInfo info, int priority, int delay);
+ public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+
public ITypeInfo getGlobalNamespace();
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java
index bb4e1432e6b..6de268386cd 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java
@@ -30,6 +30,7 @@ import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
public class IndexerTypesJob extends IndexerJob {
@@ -108,6 +109,14 @@ public class IndexerTypesJob extends IndexerJob {
String[] enclosingNames = getEnclosingNames(word, slash);
addType(input, project, entry, type, name, enclosingNames, monitor);
}
+ } else if (decodedType == IIndexConstants.DERIVED_SUFFIX) {
+ firstSlash += 2;
+ int slash = CharOperation.indexOf(IIndexConstants.SEPARATOR, word, firstSlash + 1);
+ String name = String.valueOf(CharOperation.subarray(word, firstSlash + 1, slash));
+ if (name.length() != 0) { // skip anonymous structs
+ String[] enclosingNames = getEnclosingNames(word, slash);
+ addSuperTypeReference(input, project, entry, name, enclosingNames, monitor);
+ }
}
}
}
@@ -175,4 +184,37 @@ public class IndexerTypesJob extends IndexerJob {
}
}
}
+
+ private void addSuperTypeReference(IndexInput input, IProject project, IEntryResult entry, String name, String[] enclosingNames, IProgressMonitor monitor) throws InterruptedException, IOException {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ ITypeInfo info = fTypeCache.getType(ICElement.C_CLASS, qualifiedName);
+ if (info == null)
+ info = fTypeCache.getType(ICElement.C_STRUCT, qualifiedName);
+ if (info == null) {
+ // add dummy type to cache
+ info = new TypeInfo(0, qualifiedName);
+ fTypeCache.insert(info);
+ }
+ int[] references = entry.getFileReferences();
+ if (references != null && references.length > 0) {
+ for (int i = 0; i < references.length; ++i) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IndexedFile file = input.getIndexedFile(references[i]);
+ if (file != null && file.getPath() != null) {
+ IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+ info.addDerivedReference(new TypeReference(path, project));
+//
+// // get absolute path
+// IPath path = new Path(file.getPath());
+// IPath projectPath = project.getFullPath();
+// if (projectPath.isPrefixOf(path)) {
+// path = project.getLocation().append(path.removeFirstSegments(projectPath.segmentCount()));
+// }
+// info.addDerivedReference(new TypeReference(path, project));
+ }
+ }
+ }
+ }
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java
new file mode 100644
index 00000000000..2634059e4d5
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.cache;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+public class SubTypeLocatorJob extends BasicJob {
+
+ public static final Object FAMILY = new Object();
+ private ITypeInfo fLocateType;
+ private ITypeCache fTypeCache;
+ private IWorkingCopyProvider fWorkingCopyProvider;
+
+ public SubTypeLocatorJob(ITypeInfo info, ITypeCache typeCache, IWorkingCopyProvider workingCopyProvider) {
+ super(TypeCacheMessages.getString("SubTypeLocatorJob.jobName"), FAMILY); //$NON-NLS-1$
+ fLocateType = info;
+ fTypeCache = typeCache;
+ fWorkingCopyProvider= workingCopyProvider;
+ }
+
+ public ITypeInfo getType() {
+ return fLocateType;
+ }
+
+ protected IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException {
+ boolean success = false;
+ long startTime = System.currentTimeMillis();
+ trace("SubTypeLocatorJob: started"); //$NON-NLS-1$
+
+ try {
+ monitor.beginTask(TypeCacheMessages.getString("SubTypeLocatorJob.taskName"), 100); //$NON-NLS-1$
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ TypeParser parser = new TypeParser(fTypeCache, fWorkingCopyProvider);
+ success = parser.findSubTypes(fLocateType, new SubProgressMonitor(monitor, 100));
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ } finally {
+ long executionTime = System.currentTimeMillis() - startTime;
+ if (success)
+ trace("SubTypeLocatorJob: completed ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+ else
+ trace("SubTypeLocatorJob: aborted ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ monitor.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java
index 2925e854dd8..e0122dd2a22 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java
@@ -28,6 +28,7 @@ import org.eclipse.cdt.core.browser.QualifiedTypeName;
import org.eclipse.cdt.core.browser.TypeInfo;
import org.eclipse.cdt.core.browser.TypeSearchScope;
import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
@@ -49,6 +50,29 @@ public class TypeCache implements ITypeCache {
private final IWorkingCopyProvider fWorkingCopyProvider;
private final Collection fDeltas = new ArrayList();
private final ITypeInfo fGlobalNamespace;
+ private final Map fTypeToSubTypes = new HashMap();
+ private final Map fTypeToSuperTypes = new HashMap();
+
+ private static final class SuperTypeEntry {
+ ITypeInfo superType;
+ ASTAccessVisibility access;
+ boolean isVirtual;
+ SuperTypeEntry(ITypeInfo superType, ASTAccessVisibility access, boolean isVirtual) {
+ this.superType = superType;
+ this.access = access;
+ this.isVirtual = isVirtual;
+ }
+ }
+
+ private SuperTypeEntry findSuperTypeEntry(Collection entryCollection, ITypeInfo superType) {
+ for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
+ SuperTypeEntry e = (SuperTypeEntry) i.next();
+ if (e.superType.equals(superType)) {
+ return e;
+ }
+ }
+ return null;
+ }
private static final int[] ENCLOSING_TYPES = {ICElement.C_NAMESPACE, ICElement.C_CLASS, ICElement.C_STRUCT, 0};
@@ -330,6 +354,62 @@ public class TypeCache implements ITypeCache {
fTypeKeyMap.clear();
}
+ public synchronized void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual) {
+ Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+ if (entryCollection == null) {
+ entryCollection = new ArrayList();
+ fTypeToSuperTypes.put(type, entryCollection);
+ }
+ if (findSuperTypeEntry(entryCollection, supertype) == null) {
+ entryCollection.add(new SuperTypeEntry(supertype, access, isVirtual));
+ supertype.setCache(this);
+ }
+ }
+
+ public synchronized ITypeInfo[] getSupertypes(ITypeInfo type) {
+ Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+ if (entryCollection != null && !entryCollection.isEmpty()) {
+ ITypeInfo[] superTypes = new ITypeInfo[entryCollection.size()];
+ int count = 0;
+ for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
+ SuperTypeEntry e = (SuperTypeEntry) i.next();
+ superTypes[count++] = e.superType;
+ }
+ return superTypes;
+ }
+ return null;
+ }
+
+ public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType) {
+ Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+ if (entryCollection != null && !entryCollection.isEmpty()) {
+ SuperTypeEntry e = findSuperTypeEntry(entryCollection, superType);
+ if (e != null)
+ return e.access;
+ }
+ return null;
+ }
+
+ public synchronized void addSubtype(ITypeInfo type, ITypeInfo subtype) {
+ Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
+ if (typeCollection == null) {
+ typeCollection = new ArrayList();
+ fTypeToSubTypes.put(type, typeCollection);
+ }
+ if (!typeCollection.contains(subtype)) {
+ typeCollection.add(subtype);
+ subtype.setCache(this);
+ }
+ }
+
+ public synchronized ITypeInfo[] getSubtypes(ITypeInfo type) {
+ Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
+ if (typeCollection != null && !typeCollection.isEmpty()) {
+ return (ITypeInfo[]) typeCollection.toArray(new ITypeInfo[typeCollection.size()]);
+ }
+ return null;
+ }
+
public synchronized void accept(ITypeInfoVisitor visitor) {
for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry entry = (Map.Entry) mapIter.next();
@@ -579,6 +659,13 @@ public class TypeCache implements ITypeCache {
locatorJob.cancel();
}
}
+ jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().getEnclosingProject().equals(fProject)) {
+ locatorJob.cancel();
+ }
+ }
}
public void locateType(ITypeInfo info, int priority, int delay) {
@@ -626,4 +713,77 @@ public class TypeCache implements ITypeCache {
return info.getResolvedReference();
}
+
+ public void locateSupertypes(ITypeInfo info, int priority, int delay) {
+ ITypeInfo[] superTypes = getSupertypes(info);
+ if (superTypes != null)
+ return; // nothing to do
+
+ locateType(info, priority, delay);
+ }
+
+ public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
+ locateSupertypes(info, priority, 0);
+
+ // wait for jobs to complete
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ try {
+ locatorJob.join(monitor);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ return getSupertypes(info);
+ }
+
+ public void locateSubtypes(ITypeInfo info, int priority, int delay) {
+ ITypeInfo[] subTypes = getSubtypes(info);
+ if (subTypes != null)
+ return; // nothing to do
+
+ // cancel any scheduled or running jobs for this type
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ locatorJob.cancel();
+ }
+ }
+
+ // check again, in case some jobs finished in the meantime
+ subTypes = getSubtypes(info);
+ if (subTypes != null)
+ return; // nothing to do
+
+ // create a new job
+ SubTypeLocatorJob locatorJob = new SubTypeLocatorJob(info, this, fWorkingCopyProvider);
+ // schedule the new job
+ locatorJob.setPriority(priority);
+ locatorJob.schedule(delay);
+ }
+
+ public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
+ locateSubtypes(info, priority, 0);
+
+ // wait for jobs to complete
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ try {
+ locatorJob.join(monitor);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ return getSubtypes(info);
+ }
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java
index 6f4c802aaa1..cd6f77dcc6c 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java
@@ -13,7 +13,10 @@ package org.eclipse.cdt.internal.core.browser.cache;
import java.util.HashMap;
import java.util.Map;
+import org.eclipse.cdt.core.browser.IQualifiedTypeName;
+import org.eclipse.cdt.core.browser.ITypeInfo;
import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.cdt.core.browser.QualifiedTypeName;
import org.eclipse.cdt.core.browser.TypeSearchScope;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICElementDelta;
@@ -23,16 +26,26 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.Job;
public class TypeCacheManager {
- private Map fCacheMap = new HashMap();
+ private static final TypeCacheManager fgInstance = new TypeCacheManager();
+ private Map fCacheMap;
private IWorkingCopyProvider fWorkingCopyProvider;
- public TypeCacheManager(IWorkingCopyProvider workingCopyProvider) {
- fWorkingCopyProvider = workingCopyProvider;
+ private TypeCacheManager() {
+ fCacheMap = new HashMap();
}
+ public static TypeCacheManager getInstance() {
+ return fgInstance;
+ }
+
+ public void setWorkingCopyProvider(IWorkingCopyProvider workingCopyProvider) {
+ fWorkingCopyProvider = workingCopyProvider;
+ }
+
public synchronized void updateProject(IProject project) {
TypeCacheDelta cacheDelta = new TypeCacheDelta(project);
getCache(project).addDelta(cacheDelta);
@@ -194,4 +207,40 @@ public class TypeCacheManager {
jobManager.cancel(TypeCacherJob.FAMILY);
jobManager.cancel(TypeLocatorJob.FAMILY);
}
+
+ public ITypeInfo[] locateSuperTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
+ ITypeInfo[] superTypes = info.getSuperTypes();
+ if (superTypes == null) {
+ // cancel background jobs
+ IProject project = info.getEnclosingProject();
+ getCache(project).cancelJobs();
+
+ // start the search job
+ getCache(project).locateSupertypesAndWait(info, priority, monitor);
+
+ superTypes = info.getSuperTypes();
+
+ // resume background jobs
+ reconcile(enableIndexing, Job.BUILD, 0);
+ }
+ return superTypes;
+ }
+
+ public ITypeInfo[] locateSubTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
+ ITypeInfo[] subTypes = info.getSubTypes();
+ if (subTypes == null) {
+ // cancel background jobs
+ IProject project = info.getEnclosingProject();
+ getCache(project).cancelJobs();
+
+ // start the search job
+ getCache(project).locateSubtypesAndWait(info, priority, monitor);
+
+ subTypes = info.getSubTypes();
+
+ // resume background jobs
+ reconcile(enableIndexing, Job.BUILD, 0);
+ }
+ return subTypes;
+ }
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties
index 8b83fc7d1b0..2d406cdfe53 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties
@@ -17,5 +17,7 @@ TypeCacherJob.taskName=Updating Type Cache...
TypeLocatorJob.jobName=Type Locator
TypeLocatorJob.taskName=Searching for Type Declaration...
+SubTypeLocatorJob.jobName=Subtype Locator
+SubTypeLocatorJob.taskName=Searching for Subtypes...
TypeCache.globalNamespace=(global)
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java
index 809c3092369..f7493af6aea 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java
@@ -18,6 +18,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.browser.ITypeInfo;
@@ -49,7 +50,12 @@ import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.ParserUtil;
import org.eclipse.cdt.core.parser.ScannerInfo;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.core.parser.ast.ASTClassKind;
+import org.eclipse.cdt.core.parser.ast.ASTNotImplementedException;
+import org.eclipse.cdt.core.parser.ast.IASTBaseSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTTypeSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTTypedefDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTASMDefinition;
import org.eclipse.cdt.core.parser.ast.IASTAbstractTypeSpecifierDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTClassReference;
@@ -113,6 +119,8 @@ public class TypeParser implements ISourceElementRequestor {
private final SimpleStack fScopeStack = new SimpleStack();
private final SimpleStack fResourceStack = new SimpleStack();
private ITypeInfo fTypeToFind;
+ private ITypeInfo fSuperTypeToFind;
+ private Set fProcessedTypes = new HashSet();
private boolean fFoundType;
public TypeParser(ITypeCache typeCache, IWorkingCopyProvider provider) {
@@ -247,6 +255,75 @@ public class TypeParser implements ISourceElementRequestor {
return false;
}
+ public boolean findSubTypes(ITypeInfo info, IProgressMonitor monitor) throws InterruptedException {
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ fScope = new TypeSearchScope();
+ ITypeReference[] refs = info.getDerivedReferences();
+ if (refs == null || refs.length == 0)
+ return false; // no source references
+
+ for (int i = 0; i < refs.length; ++i) {
+ ITypeReference location = refs[i];
+ IPath path = location.getPath();
+ fScope.add(path, false, null);
+ }
+
+ Map workingCopyMap = null;
+ if (fWorkingCopyProvider != null) {
+ IWorkingCopy[] workingCopies = fWorkingCopyProvider.getWorkingCopies();
+ if (workingCopies != null && workingCopies.length > 0) {
+ workingCopyMap = new HashMap(workingCopies.length);
+ for (int i = 0; i < workingCopies.length; ++i) {
+ IWorkingCopy workingCopy = workingCopies[i];
+ IPath wcPath = workingCopy.getOriginalElement().getPath();
+ if (fScope.encloses(wcPath)) {
+// // always flush working copies from cache?
+// fTypeCache.flush(wcPath);
+ fScope.add(wcPath, false, null);
+ workingCopyMap.put(wcPath, workingCopy);
+ }
+ }
+ }
+ }
+
+ fProject = fTypeCache.getProject();
+ IPath[] searchPaths = fTypeCache.getPaths(fScope);
+ Collection workingCopyPaths = new HashSet();
+ if (workingCopyMap != null) {
+ collectWorkingCopiesInProject(workingCopyMap, fProject, workingCopyPaths);
+ //TODO what about working copies outside the workspace?
+ }
+
+ monitor.beginTask("", searchPaths.length + workingCopyPaths.size()); //$NON-NLS-1$
+ try {
+ fTypeToFind = null;
+ fSuperTypeToFind = info;
+ fFoundType = false;
+ for (Iterator pathIter = workingCopyPaths.iterator(); pathIter.hasNext(); ) {
+ IPath path = (IPath) pathIter.next();
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ }
+ for (int i = 0; i < searchPaths.length; ++i) {
+ IPath path = searchPaths[i];
+ if (!workingCopyPaths.contains(path)) {
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ } else {
+ monitor.worked(1);
+ }
+ }
+ } finally {
+ fTypeToFind = null;
+ fFoundType = false;
+ monitor.done();
+ }
+ return false;
+ }
+
private void collectWorkingCopiesInProject(Map workingCopyMap, IProject project, Collection workingCopyPaths) {
for (Iterator mapIter = workingCopyMap.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry entry = (Map.Entry) mapIter.next();
@@ -582,76 +659,6 @@ public class TypeParser implements ISourceElementRequestor {
throw new OperationCanceledException();
fResourceStack.pop();
}
-
- private void acceptType(ISourceElementCallbackDelegate node) {
- if (fProgressMonitor.isCanceled())
- throw new OperationCanceledException();
-
- // skip local declarations
- IASTScope currentScope = (IASTScope) fScopeStack.top();
- if (currentScope instanceof IASTFunction || currentScope instanceof IASTMethod) {
- return;
- }
-
- int offset = 0;
- int end = 0;
- IASTOffsetableNamedElement offsetable = null;
- String name = null;
- int type = 0;
-
- if (node instanceof IASTReference) {
- IASTReference reference = (IASTReference) node;
- offset = reference.getOffset();
- end = offset + reference.getName().length();
- } else if (node instanceof IASTOffsetableNamedElement) {
- offsetable = (IASTOffsetableNamedElement) node;
- offset = offsetable.getNameOffset() != 0 ? offsetable.getNameOffset() : offsetable.getStartingOffset();
- end = offsetable.getNameEndOffset();
- if (end == 0) {
- end = offset + offsetable.getName().length();
- }
- }
-
- if (node instanceof IASTReference)
- node = fLastDeclaration;
- if (node instanceof IASTReference) {
- offsetable = (IASTOffsetableNamedElement) ((IASTReference) node).getReferencedElement();
- name = ((IASTReference) node).getName();
- } else if (node instanceof IASTOffsetableNamedElement) {
- offsetable = (IASTOffsetableNamedElement) node;
- name = offsetable.getName();
- } else {
- return;
- }
-
- // skip unnamed structs
- if (name == null || name.length() == 0)
- return;
-
- // skip unused types
- type = getElementType(offsetable);
- if (type == 0) {
- return;
- }
-
- if (fTypeToFind != null) {
- if ((fTypeToFind.getCElementType() == type || fTypeToFind.isUndefinedType()) && name.equals(fTypeToFind.getName())) {
- String[] enclosingNames = getEnclosingNames(offsetable);
- QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
- if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
- fFoundType = true;
-
- // add types to cache
- addType(type, name, enclosingNames, fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
- fProgressMonitor.worked(1);
- }
- }
- } else {
- // add types to cache
- addType(type, name, getEnclosingNames(offsetable), fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
- fProgressMonitor.worked(1);
- }
- }
private String[] getEnclosingNames(IASTOffsetableNamedElement elem) {
String[] enclosingNames = null;
@@ -665,6 +672,140 @@ public class TypeParser implements ISourceElementRequestor {
return enclosingNames;
}
+
+ private class NodeTypeInfo {
+ int type;
+ String name;
+ String[] enclosingNames;
+ int offset;
+ int end;
+ IASTOffsetableNamedElement offsetable;
+
+ void init() {
+ type = 0;
+ name = null;
+ enclosingNames = null;
+ offset = 0;
+ end = 0;
+ offsetable = null;
+ }
+
+ boolean parseNodeForTypeInfo(ISourceElementCallbackDelegate node) {
+ init();
+
+ if (node instanceof IASTReference) {
+ IASTReference reference = (IASTReference) node;
+ offset = reference.getOffset();
+ end = offset + reference.getName().length();
+ } else if (node instanceof IASTOffsetableNamedElement) {
+ offsetable = (IASTOffsetableNamedElement) node;
+ offset = offsetable.getNameOffset() != 0 ? offsetable.getNameOffset() : offsetable.getStartingOffset();
+ end = offsetable.getNameEndOffset();
+ if (end == 0) {
+ end = offset + offsetable.getName().length();
+ }
+ }
+
+ if (node instanceof IASTReference)
+ node = fLastDeclaration;
+ if (node instanceof IASTReference) {
+ offsetable = (IASTOffsetableNamedElement) ((IASTReference) node).getReferencedElement();
+ name = ((IASTReference) node).getName();
+ } else if (node instanceof IASTOffsetableNamedElement) {
+ offsetable = (IASTOffsetableNamedElement) node;
+ name = offsetable.getName();
+ } else {
+ return false;
+ }
+
+ // skip unnamed structs
+ if (name == null || name.length() == 0)
+ return false;
+
+ // skip unused types
+ type = getElementType(offsetable);
+ if (type == 0) {
+ return false;
+ }
+
+ // collect enclosing names
+ if (offsetable instanceof IASTQualifiedNameElement) {
+ String[] names = ((IASTQualifiedNameElement) offsetable).getFullyQualifiedName();
+ if (names != null && names.length > 1) {
+ enclosingNames = new String[names.length - 1];
+ System.arraycopy(names, 0, enclosingNames, 0, names.length - 1);
+ }
+ }
+
+ return true;
+ }
+
+ }
+
+ private void acceptType(ISourceElementCallbackDelegate node) {
+ if (fProgressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ // skip local declarations
+ IASTScope currentScope = (IASTScope) fScopeStack.top();
+ if (currentScope instanceof IASTFunction || currentScope instanceof IASTMethod) {
+ return;
+ }
+
+ NodeTypeInfo nodeInfo = new NodeTypeInfo();
+ if (nodeInfo.parseNodeForTypeInfo(node)) {
+ TypeReference originalLocation = null;
+ Object originalRef = fResourceStack.bottom();
+ if (originalRef instanceof IWorkingCopy) {
+ IWorkingCopy workingCopy = (IWorkingCopy) originalRef;
+ originalLocation = new TypeReference(workingCopy, fProject);
+ } else if (originalRef instanceof IResource) {
+ IResource resource = (IResource) originalRef;
+ originalLocation = new TypeReference(resource, fProject);
+ } else if (originalRef instanceof IPath) {
+ IPath path = PathUtil.getProjectRelativePath((IPath)originalRef, fProject);
+ originalLocation = new TypeReference(path, fProject);
+ }
+
+ TypeReference resolvedLocation = null;
+ Object resolvedRef = fResourceStack.top();
+ if (resolvedRef instanceof IWorkingCopy) {
+ IWorkingCopy workingCopy = (IWorkingCopy) resolvedRef;
+ resolvedLocation = new TypeReference(workingCopy, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+ } else if (resolvedRef instanceof IResource) {
+ IResource resource = (IResource) resolvedRef;
+ resolvedLocation = new TypeReference(resource, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+ } else if (resolvedRef instanceof IPath) {
+ IPath path = PathUtil.getProjectRelativePath((IPath)resolvedRef, fProject);
+ resolvedLocation = new TypeReference(path, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+ }
+
+ if (fTypeToFind != null) {
+ if ((fTypeToFind.getCElementType() == nodeInfo.type || fTypeToFind.isUndefinedType()) && nodeInfo.name.equals(fTypeToFind.getName())) {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
+ if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
+ fFoundType = true;
+
+ // add types to cache
+ ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
+ if (newType != null && node instanceof IASTClassSpecifier) {
+ addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
+ }
+ fProgressMonitor.worked(1);
+ }
+ }
+ } else {
+ // add types to cache
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
+ ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
+ if (newType != null && node instanceof IASTClassSpecifier) {
+ addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
+ }
+ fProgressMonitor.worked(1);
+ }
+ }
+ }
+
private int getElementType(IASTOffsetableNamedElement offsetable) {
if (offsetable instanceof IASTClassSpecifier || offsetable instanceof IASTElaboratedTypeSpecifier) {
ASTClassKind kind = null;
@@ -690,8 +831,40 @@ public class TypeParser implements ISourceElementRequestor {
return 0;
}
- private void addType(int type, String name, String[] enclosingNames, Object originalRef, Object resolvedRef, int offset, int length) {
- QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ private void addSuperClasses(ITypeInfo type, IASTClassSpecifier classSpec, TypeReference location, Set processedClasses) {
+ Iterator baseIter = classSpec.getBaseClauses();
+ if (baseIter != null) {
+ while (baseIter.hasNext()) {
+ IASTBaseSpecifier baseSpec = (IASTBaseSpecifier) baseIter.next();
+ try {
+ String baseName = baseSpec.getParentClassName();
+ ASTAccessVisibility baseAccess = baseSpec.getAccess();
+
+ IASTClassSpecifier parentClass = null;
+ IASTTypeSpecifier parentSpec = baseSpec.getParentClassSpecifier();
+ if (parentSpec instanceof IASTClassSpecifier)
+ parentClass = (IASTClassSpecifier) parentSpec;
+
+ if (parentClass != null) {
+ NodeTypeInfo nodeInfo = new NodeTypeInfo();
+ if (nodeInfo.parseNodeForTypeInfo(parentClass)) {
+ // add type to cache
+ ITypeInfo superType = addSuperType(type, nodeInfo.type, nodeInfo.name, nodeInfo.enclosingNames, location, baseAccess, baseSpec.isVirtual());
+
+ // recursively process super super classes
+ if (!processedClasses.contains(parentClass)) {
+ processedClasses.add(parentClass);
+ addSuperClasses(superType, parentClass, location, processedClasses);
+ }
+ }
+ }
+ } catch (ASTNotImplementedException e) {
+ }
+ }
+ }
+ }
+
+ private ITypeInfo addType(int type, QualifiedTypeName qualifiedName, TypeReference originalLocation, TypeReference resolvedLocation) {
ITypeInfo info = fTypeCache.getType(type, qualifiedName);
if (info == null || info.isUndefinedType()) {
// add new type to cache
@@ -702,32 +875,35 @@ public class TypeParser implements ISourceElementRequestor {
fTypeCache.insert(info);
}
- TypeReference location;
- if (originalRef instanceof IWorkingCopy) {
- IWorkingCopy workingCopy = (IWorkingCopy) originalRef;
- location = new TypeReference(workingCopy, fProject);
- } else if (originalRef instanceof IResource) {
- IResource resource = (IResource) originalRef;
- location = new TypeReference(resource, fProject);
- } else {
- IPath path = (IPath) originalRef;
- location = new TypeReference(path, fProject);
- }
- info.addReference(location);
+ info.addReference(originalLocation);
}
- TypeReference location;
- if (resolvedRef instanceof IWorkingCopy) {
- IWorkingCopy workingCopy = (IWorkingCopy) resolvedRef;
- location = new TypeReference(workingCopy, fProject, offset, length);
- } else if (resolvedRef instanceof IResource) {
- IResource resource = (IResource) resolvedRef;
- location = new TypeReference(resource, fProject, offset, length);
- } else {
- IPath path = (IPath) resolvedRef;
- location = new TypeReference(path, fProject, offset, length);
+ info.addReference(resolvedLocation);
+
+ return info;
+ }
+
+ private ITypeInfo addSuperType(ITypeInfo addToType, int type, String name, String[] enclosingNames, TypeReference location, ASTAccessVisibility access, boolean isVirtual) {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ ITypeInfo superType = fTypeCache.getType(type, qualifiedName);
+ if (superType == null || superType.isUndefinedType()) {
+ if (superType != null) {
+ // merge with existing type
+ superType.setCElementType(type);
+ } else {
+ // add new type to cache
+ superType = new TypeInfo(type, qualifiedName);
+ fTypeCache.insert(superType);
+ }
}
- info.addReference(location);
+ superType.addDerivedReference(location);
+
+ if (fSuperTypeToFind != null && fSuperTypeToFind.equals(superType)) {
+ //TODO don't need to do anything here?
+ }
+ fTypeCache.addSupertype(addToType, superType, access, isVirtual);
+ fTypeCache.addSubtype(superType, addToType);
+ return superType;
}
/* (non-Javadoc)
diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java
index 1366f6fdf22..a6db20a0936 100644
--- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java
@@ -441,7 +441,7 @@ public abstract class CElement extends PlatformObject implements ICElement {
* Returns true if this element is an ancestor of the given element,
* otherwise false.
*/
- protected boolean isAncestorOf(ICElement e) {
+ public boolean isAncestorOf(ICElement e) {
ICElement parent= e.getParent();
while (parent != null && !parent.equals(this)) {
parent= parent.getParent();