From 302fc99a1f54ceee7e10207d37595c235a48922c Mon Sep 17 00:00:00 2001
From: Doug Schaefer
+ * AllTypesCache runs asynchronously using a background job to rebuild the cache
+ * as needed. If the cache becomes dirty again while the background job is
+ * running, the job is restarted.
+ *
+ * If
+ * 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:
+ * ICElement
the methods of this class returns a
+ * list of the lightweight objects TypeInfo
.
+ * getTypes
is called in response to a user action, a progress
+ * dialog is shown. If called before the background job has finished, getTypes
+ * waits for the completion of the background job.
+ */
+public class AllTypesCache {
+
+ /**
+ * Returns all types in the workspace.
+ */
+ public static ITypeInfo[] getAllTypes() {
+ final Collection fAllTypes = new ArrayList();
+ TypeSearchScope workspaceScope = new TypeSearchScope(true);
+ ICProject[] projects = workspaceScope.getEnclosingProjects();
+ ITypeInfoVisitor visitor = new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo info) {
+ fAllTypes.add(info);
+ return true;
+ }
+ public boolean shouldContinue() { return true; }
+ };
+ for (int i = 0; i < projects.length; ++i) {
+// TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
+ }
+ return (ITypeInfo[]) fAllTypes.toArray(new ITypeInfo[fAllTypes.size()]);
+ }
+
+ /**
+ * Returns all types in the given scope.
+ *
+ * @param scope The search scope
+ * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS,
+ * C_UNION, C_ENUMERATION, C_TYPEDEF
+ */
+ public static ITypeInfo[] getTypes(ITypeSearchScope scope, int[] kinds) {
+ final Collection fTypesFound = new ArrayList();
+ final ITypeSearchScope fScope = scope;
+ final int[] fKinds = kinds;
+ ICProject[] projects = scope.getEnclosingProjects();
+ ITypeInfoVisitor visitor = new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo info) {
+ if (ArrayUtil.contains(fKinds, info.getCElementType())
+ && (fScope != null && info.isEnclosed(fScope))) {
+ fTypesFound.add(info);
+ }
+ return true;
+ }
+ public boolean shouldContinue() { return true; }
+ };
+ for (int i = 0; i < projects.length; ++i) {
+// TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
+ }
+ return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
+ }
+
+ /**
+ * Returns all namespaces in the given scope.
+ *
+ * @param scope The search scope
+ * @param includeGlobalNamespace true
if the global (default) namespace should be returned
+ */
+ public static ITypeInfo[] getNamespaces(ITypeSearchScope scope, boolean includeGlobalNamespace) {
+ final Collection fTypesFound = new ArrayList();
+ final ITypeSearchScope fScope = scope;
+ ICProject[] projects = scope.getEnclosingProjects();
+ ITypeInfoVisitor visitor = new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo info) {
+ if (info.getCElementType() == ICElement.C_NAMESPACE
+ && (fScope != null && info.isEnclosed(fScope))) {
+ fTypesFound.add(info);
+ }
+ return true;
+ }
+ public boolean shouldContinue() { return true; }
+ };
+ for (int i = 0; i < projects.length; ++i) {
+// ITypeCache cache = TypeCacheManager.getInstance().getCache(projects[i]);
+// cache.accept(visitor);
+// if (includeGlobalNamespace) {
+// fTypesFound.add(cache.getGlobalNamespace());
+// }
+ }
+ return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
+ }
+
+ /** Returns first type in the cache which matches the given
+ * type and name. If no type is found, null
+ * is returned.
+ *
+ * @param project the enclosing project
+ * @param type the ICElement type
+ * @param qualifiedName the qualified type name to match
+ * @return the matching type
+ */
+ public static ITypeInfo getType(ICProject project, int type, IQualifiedTypeName qualifiedName) {
+// ITypeCache cache = TypeCacheManager.getInstance().getCache(project);
+// return cache.getType(type, qualifiedName);
+ return null;
+ }
+
+ /**
+ * Returns all types matching name in the given project.
+ *
+ * @param project the enclosing project
+ * @param qualifiedName The qualified type name
+ * @param matchEnclosed true
if enclosed types count as matches (foo::bar == bar)
+ * @param ignoreCase true
if case-insensitive
+ * @return Array of types
+ */
+ public static ITypeInfo[] getTypes(ICProject project, IQualifiedTypeName qualifiedName, boolean matchEnclosed, boolean ignoreCase) {
+// ITypeCache cache = TypeCacheManager.getInstance().getCache(project);
+// return cache.getTypes(qualifiedName, matchEnclosed, ignoreCase);
+ return new ITypeInfo[0];
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java
new file mode 100644
index 00000000000..2d7836201c9
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+public interface IQualifiedTypeName extends Comparable {
+
+ public final static String QUALIFIER = "::"; //$NON-NLS-1$
+
+ public String getName();
+
+ public String getFullyQualifiedName();
+ public IQualifiedTypeName getEnclosingTypeName();
+ public String[] getEnclosingNames();
+
+ public boolean isQualified();
+ public boolean isEmpty();
+ public boolean isGlobal();
+
+ public IQualifiedTypeName append(String qualifiedName);
+ public IQualifiedTypeName append(String[] names);
+ public IQualifiedTypeName append(IQualifiedTypeName typeName);
+
+ public String[] segments();
+ public String segment(int index);
+ public int segmentCount();
+ public String lastSegment();
+ public int matchingFirstSegments(IQualifiedTypeName typeName);
+ public IQualifiedTypeName removeFirstSegments(int count);
+ public IQualifiedTypeName removeLastSegments(int count);
+ public boolean isPrefixOf(IQualifiedTypeName typeName);
+
+ public boolean isLowLevel();
+ public boolean isValidSegment(String segment);
+ public boolean isValid();
+
+ public boolean equals(IQualifiedTypeName typeName);
+ public boolean equalsIgnoreCase(IQualifiedTypeName typeName);
+ public int compareTo(IQualifiedTypeName typeName);
+ public int compareToIgnoreCase(IQualifiedTypeName typeName);
+}
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
new file mode 100644
index 00000000000..5b10ac987a2
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+
+/**
+ * Type information.
+ */
+public interface ITypeInfo extends Comparable {
+
+ public static final int KNOWN_TYPES[] = {
+ ICElement.C_NAMESPACE,
+ ICElement.C_CLASS,
+ ICElement.C_STRUCT,
+ ICElement.C_UNION,
+ ICElement.C_ENUMERATION,
+ ICElement.C_TYPEDEF
+ };
+
+ /**
+ * Gets the CElement type.
+ * @return ICElement.C_NAMESPACE, C_CLASS, C_STRUCT, C_UNION, C_ENUMERATION, or C_TYPEDEF,
+ * or zero if unknown type.
+ */
+ public int getCElementType();
+
+ /**
+ * Sets the CElement type.
+ */
+ public void setCElementType(int type);
+
+ /**
+ * Gets the type name.
+ */
+ public String getName();
+
+ /**
+ * Gets the qualified type name.
+ */
+ public IQualifiedTypeName getQualifiedTypeName();
+
+ /**
+ * Returns true if the type exists.
+ */
+ public boolean exists();
+
+ /**
+ * Returns true if the element type is unknown.
+ */
+ public boolean isUndefinedType();
+
+ /**
+ * Returns true if this type is enclosed by other types,
+ * i.e. declared an inside another namespace or class.
+ */
+ public boolean isEnclosedType();
+
+ /** Gets the enclosing type, i.e. the outer class or namespace which contains this type.
+ * @return the enclosing type, or null
if not found.
+ */
+ public ITypeInfo getEnclosingType();
+
+ /** Gets the enclosing namespace for this type.
+ * @return the enclosing namespace, or null
if none exists.
+ */
+ public ITypeInfo getEnclosingNamespace(boolean includeGlobalNamespace);
+
+ /** Gets the first enclosing type which matches one of the given kinds.
+ * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS, C_STRUCT
+ * @return the enclosing type, or null
if not found.
+ */
+ public ITypeInfo getEnclosingType(int[] kinds);
+
+ /** Gets the root namespace, i.e. the outermost namespace
+ * which contains this type.
+ * @param includeGlobalNamespace true
if the global (default) namespace should be returned
+ * @return the namespace, or null
if not found.
+ */
+ public ITypeInfo getRootNamespace(boolean includeGlobalNamespace);
+
+ /**
+ * Returns true if this type is capable of enclosing other types,
+ * i.e. it is a namespace, class, or struct.
+ */
+ public boolean isEnclosingType();
+
+ /**
+ * Returns true if this type encloses other types, i.e. contains
+ * inner classes or namespaces.
+ */
+ public boolean hasEnclosedTypes();
+
+ /**
+ * Returns true if this type encloses the given type.
+ */
+ public boolean encloses(ITypeInfo info);
+
+ /**
+ * Returns true if this type is enclosed by the given type.
+ */
+ public boolean isEnclosed(ITypeInfo info);
+
+ /** Gets the enclosed types, i.e. inner classes or classes inside this namespace.
+ * @return array of inner types, or empty array if not found.
+ */
+ public ITypeInfo[] getEnclosedTypes();
+
+ /** Gets the enclosed types, i.e. inner classes or classes inside this namespace.
+ * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS, C_STRUCT,
+ * C_UNION, C_ENUMERATION, C_TYPEDEF
+ * @return array of inner types, or empty array if not found.
+ */
+ public ITypeInfo[] getEnclosedTypes(int kinds[]);
+
+ /**
+ * Gets the enclosing project.
+ */
+ public ICProject getEnclosingProject();
+
+ /**
+ * Returns true if type is enclosed in the given scope.
+ */
+ public boolean isEnclosed(ITypeSearchScope scope);
+
+ /**
+ * Adds a source reference.
+ */
+ public void addReference(ITypeReference location);
+
+ /** Gets the originating locations where this type was declared.
+ * @return all known source references, or an empty
+ * array if none found.
+ */
+ public ITypeReference[] getReferences();
+
+ /** Gets the real location where type was declared.
+ * @return the parsed source reference (with offset and length),
+ * or null
if not found.
+ */
+ public ITypeReference getResolvedReference();
+
+ /**
+ * Returns true if the type can be substituted.
+ */
+ public boolean canSubstituteFor(ITypeInfo info);
+
+ /**
+ * 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/ITypeInfoVisitor.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfoVisitor.java
new file mode 100644
index 00000000000..38dcbe93abe
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfoVisitor.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+public interface ITypeInfoVisitor {
+
+ public boolean visit(ITypeInfo info);
+
+ public boolean shouldContinue();
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeReference.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeReference.java
new file mode 100644
index 00000000000..90d29c4283f
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeReference.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.model.IWorkingCopy;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+
+public interface ITypeReference {
+
+ /**
+ * Returns the full, absolute path of this reference
+ * relative to the workspace, or null if no path can be
+ * determined.
+ */
+ public IPath getPath();
+
+ /**
+ * Returns the absolute path in the local file system
+ * to this reference, or null if no path can be
+ * determined.
+ */
+ public IPath getLocation();
+
+ /**
+ * Returns the resource.
+ */
+ public IResource getResource();
+
+ /**
+ * Returns the working copy.
+ */
+ public IWorkingCopy getWorkingCopy();
+
+ /**
+ * Returns the project.
+ */
+ public IProject getProject();
+
+ /**
+ * Returns the offset.
+ */
+ public int getOffset();
+
+ /**
+ * Returns the length.
+ */
+ public int getLength();
+
+ /**
+ * Returns the CElements located at the stored offset and length,
+ * or null
if not found.
+ */
+ public ICElement[] getCElements();
+
+ /**
+ * Returns a translation unit for this location.
+ */
+ public ITranslationUnit getTranslationUnit();
+
+ /** Gets the path for this location, relative to one of
+ * the given project's include paths.
+ *
+ * @param project the project to use as a reference.
+ * @return The path to this location, relative to the longest
+ * matching include path in the given project.
+ */
+ public IPath getRelativeIncludePath(IProject project);
+
+ /** Gets the path for this location, relative to the
+ * given path.
+ *
+ * @param relativeToPath the path to use as a reference.
+ * @return The path to this location, relative to the
+ * given path.
+ */
+ public IPath getRelativePath(IPath relativeToPath);
+
+ boolean isLineNumber();
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java
new file mode 100644
index 00000000000..657bad5467d
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import java.util.Collection;
+
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.IWorkingCopy;
+import org.eclipse.core.runtime.IPath;
+
+public interface ITypeSearchScope {
+
+ public boolean isPathScope();
+ public boolean isProjectScope();
+ public boolean isWorkspaceScope();
+ public boolean isEmpty();
+
+ public boolean encloses(ITypeSearchScope scope);
+ public boolean encloses(ICProject project);
+ public boolean encloses(IPath path);
+ public boolean encloses(String path);
+ public boolean encloses(ICElement element);
+ public boolean encloses(IWorkingCopy workingCopy);
+
+ public void add(IWorkingCopy workingCopy);
+ public void add(IPath path, boolean addSubfolders, ICProject enclosingProject);
+ public void add(ICProject project);
+ public void add(ICElement elem);
+ public void add(ITypeSearchScope scope);
+ public void addWorkspace();
+ public void clear();
+ public ICProject[] getEnclosingProjects();
+
+ public Collection pathSet();
+ public Collection containerSet();
+ public Collection projectSet();
+ public Collection enclosingProjectSet();
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IWorkingCopyProvider.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IWorkingCopyProvider.java
new file mode 100644
index 00000000000..a3c31b1ae1b
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IWorkingCopyProvider.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.core.model.IWorkingCopy;
+
+/**
+ * Defines a simple interface in order to provide
+ * a level of abstraction between the Core and UI
+ * code.
+ */
+public interface IWorkingCopyProvider {
+ public IWorkingCopy[] getWorkingCopies();
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/PathUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/PathUtil.java
new file mode 100644
index 00000000000..38cafa24771
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/PathUtil.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.parser.IScannerInfoProvider;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+public class PathUtil {
+
+ public static boolean isWindowsFileSystem() {
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+ return (os != null && os.startsWith("Win")); //$NON-NLS-1$
+ }
+
+ public static IWorkspaceRoot getWorkspaceRoot() {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ if (workspace != null) {
+ return workspace.getRoot();
+ }
+ return null;
+ }
+
+ public static IPath getCanonicalPath(IPath fullPath) {
+ File file = fullPath.toFile();
+ try {
+ String canonPath = file.getCanonicalPath();
+ return new Path(canonPath);
+ } catch (IOException ex) {
+ }
+ return null;
+ }
+
+ public static IPath getWorkspaceRelativePath(IPath fullPath) {
+ IWorkspaceRoot workspaceRoot = getWorkspaceRoot();
+ if (workspaceRoot != null) {
+ IPath workspaceLocation = workspaceRoot.getLocation();
+ if (workspaceLocation != null && workspaceLocation.isPrefixOf(fullPath)) {
+ int segments = fullPath.matchingFirstSegments(workspaceLocation);
+ IPath relPath = fullPath.setDevice(null).removeFirstSegments(segments);
+ return new Path("").addTrailingSeparator().append(relPath); //$NON-NLS-1$
+ }
+ }
+ return fullPath;
+ }
+
+ public static IPath getProjectRelativePath(IPath fullPath, IProject project) {
+ IPath projectPath = project.getFullPath();
+ if (projectPath.isPrefixOf(fullPath)) {
+ return fullPath.removeFirstSegments(projectPath.segmentCount());
+ }
+ projectPath = project.getLocation();
+ if (projectPath.isPrefixOf(fullPath)) {
+ return fullPath.removeFirstSegments(projectPath.segmentCount());
+ }
+ return getWorkspaceRelativePath(fullPath);
+ }
+
+ public static IPath getWorkspaceRelativePath(String fullPath) {
+ return getWorkspaceRelativePath(new Path(fullPath));
+ }
+
+ public static IPath getRawLocation(IPath wsRelativePath) {
+ IWorkspaceRoot workspaceRoot = getWorkspaceRoot();
+ if (workspaceRoot != null && wsRelativePath != null) {
+ IPath workspaceLocation = workspaceRoot.getLocation();
+ if (workspaceLocation != null && !workspaceLocation.isPrefixOf(wsRelativePath)) {
+ return workspaceLocation.append(wsRelativePath);
+ }
+ }
+ return wsRelativePath;
+ }
+
+ public static IPath makeRelativePath(IPath path, IPath relativeTo) {
+ int segments = relativeTo.matchingFirstSegments(path);
+ if (segments > 0) {
+ IPath prefix = relativeTo.removeFirstSegments(segments);
+ IPath suffix = path.removeFirstSegments(segments);
+ IPath relativePath = new Path(""); //$NON-NLS-1$
+ for (int i = 0; i < prefix.segmentCount(); ++i) {
+ relativePath = relativePath.append(".." + IPath.SEPARATOR); //$NON-NLS-1$
+ }
+ return relativePath.append(suffix);
+ }
+ return null;
+ }
+
+ public static IPath makeRelativePathToProjectIncludes(IPath fullPath, IProject project) {
+ IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project);
+ if (provider != null) {
+ IScannerInfo info = provider.getScannerInformation(project);
+ if (info != null) {
+ return makeRelativePathToIncludes(fullPath, info.getIncludePaths());
+ }
+ }
+ return null;
+ }
+
+ public static IPath makeRelativePathToIncludes(IPath fullPath, String[] includePaths) {
+ IPath relativePath = null;
+ int mostSegments = 0;
+ for (int i = 0; i < includePaths.length; ++i) {
+ IPath includePath = new Path(includePaths[i]);
+ if (includePath.isPrefixOf(fullPath)) {
+ int segments = includePath.matchingFirstSegments(fullPath);
+ if (segments > mostSegments) {
+ relativePath = fullPath.removeFirstSegments(segments).setDevice(null);
+ mostSegments = segments;
+ }
+ }
+ }
+ return relativePath;
+ }
+
+ public static ICProject getEnclosingProject(IPath fullPath) {
+ IWorkspaceRoot root = getWorkspaceRoot();
+ if (root != null) {
+ IPath path = getWorkspaceRelativePath(fullPath);
+ while (!path.isEmpty()) {
+ IResource res = root.findMember(path);
+ if (res != null)
+ return CoreModel.getDefault().create(res.getProject());
+
+ path = path.removeLastSegments(1);
+ }
+ }
+ return null;
+ }
+
+ public static IPath getValidEnclosingFolder(IPath fullPath) {
+ IWorkspaceRoot root = getWorkspaceRoot();
+ if (root != null) {
+ IPath path = getWorkspaceRelativePath(fullPath);
+ while (!path.isEmpty()) {
+ IResource res = root.findMember(path);
+ if (res != null && res.exists() && (res.getType() == IResource.PROJECT || res.getType() == IResource.FOLDER))
+ return path;
+
+ path = path.removeLastSegments(1);
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java
new file mode 100644
index 00000000000..fac1632764f
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java
@@ -0,0 +1,391 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2005 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.core.CConventions;
+import org.eclipse.core.runtime.IStatus;
+
+public class QualifiedTypeName implements IQualifiedTypeName {
+
+ private static final String[] NO_SEGMENTS = new String[0];
+ private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+ private static final int INITIAL_SEGMENT_LENGTH = 12;
+ private static final int HASH_INIT = 17;
+ private static final int HASH_MULTIPLIER = 37;
+
+ private String[] fSegments = NO_SEGMENTS;
+ private int fHashCode = 0;
+
+ public static final QualifiedTypeName EMPTY = new QualifiedTypeName();
+
+ public QualifiedTypeName(IQualifiedTypeName typeName) {
+ fSegments = typeName.segments();
+ }
+
+ public QualifiedTypeName(String qualifiedName) {
+ fSegments = createSegments(qualifiedName);
+ }
+
+ public QualifiedTypeName(String[] names) {
+ fSegments = createSegments(names);
+ }
+
+ public QualifiedTypeName(String name, String[] enclosingNames) {
+ if (enclosingNames == null)
+ fSegments = createSegments(name);
+ else
+ fSegments = createSegments(name, enclosingNames);
+ }
+
+ private QualifiedTypeName() {
+ }
+
+ private String[] createSegments(String qualifiedName) {
+ String[] segments;
+ int qualifierIndex = qualifiedName.indexOf(QUALIFIER, 0);
+ if (qualifierIndex == -1) {
+ segments = new String[] { qualifiedName };
+ } else {
+ int maxSegments = 1;
+ int lastIndex = 0;
+ while (qualifierIndex >= 0) {
+ lastIndex = qualifierIndex + QUALIFIER.length();
+ ++maxSegments;
+ qualifierIndex = qualifiedName.indexOf(QUALIFIER, lastIndex);
+ }
+ segments = new String[maxSegments];
+ int segmentCount = 0;
+ lastIndex = 0;
+ qualifierIndex = qualifiedName.indexOf(QUALIFIER, 0);
+ while (qualifierIndex >= 0) {
+ // note: we allocate a new string rather than use the returned substring,
+ // otherwise we're holding a reference to the entire original string
+ segments[segmentCount] = new String(qualifiedName.substring(lastIndex, qualifierIndex));
+ ++segmentCount;
+ lastIndex = qualifierIndex + QUALIFIER.length();
+ qualifierIndex = qualifiedName.indexOf(QUALIFIER, lastIndex);
+ }
+ // note: we allocate a new string rather than use the returned substring,
+ // otherwise we're holding a reference to the entire original string
+ segments[segmentCount] = new String(qualifiedName.substring(lastIndex));
+ }
+ return segments;
+ }
+
+ private String[] createSegments(String[] names) {
+ String[] segments = new String[names.length];
+ System.arraycopy(names, 0, segments, 0, names.length);
+ return segments;
+ }
+
+ private String[] createSegments(String name, String[] enclosingNames) {
+ String[] segments = new String[enclosingNames.length + 1];
+ System.arraycopy(enclosingNames, 0, segments, 0, enclosingNames.length);
+ segments[segments.length - 1] = name;
+ return segments;
+ }
+
+ public String getName() {
+ if (fSegments.length > 0) {
+ return fSegments[fSegments.length - 1];
+ }
+ return EMPTY_STRING;
+ }
+
+ public String[] getEnclosingNames() {
+ if (fSegments.length > 1) {
+ String[] enclosingNames = new String[fSegments.length - 1];
+ System.arraycopy(fSegments, 0, enclosingNames, 0, fSegments.length - 1);
+ return enclosingNames;
+ }
+ return NO_SEGMENTS;
+ }
+
+ public String getFullyQualifiedName() {
+ if (fSegments.length > 0) {
+ StringBuffer buf = new StringBuffer(fSegments.length * INITIAL_SEGMENT_LENGTH);
+ for (int i = 0; i < fSegments.length; ++i) {
+ if (i > 0) {
+ buf.append(QUALIFIER);
+ }
+ buf.append(fSegments[i]);
+ }
+ return buf.toString();
+ }
+ return EMPTY_STRING;
+ }
+
+ public IQualifiedTypeName getEnclosingTypeName() {
+ String[] enclosingNames = getEnclosingNames();
+ if (enclosingNames.length > 0) {
+ QualifiedTypeName enclosingTypeName = new QualifiedTypeName();
+ enclosingTypeName.fSegments = enclosingNames;
+ return enclosingTypeName;
+ }
+ return null;
+ }
+
+ public boolean isQualified() {
+ return (fSegments.length > 1);
+ }
+
+ public boolean isEmpty() {
+ return (fSegments.length == 0);
+ }
+
+ public boolean isGlobal() {
+ return (fSegments.length <= 1 || fSegments[0].length() == 0);
+ }
+
+ public int segmentCount() {
+ return fSegments.length;
+ }
+
+ public String[] segments() {
+ String[] segmentCopy = new String[fSegments.length];
+ System.arraycopy(fSegments, 0, segmentCopy, 0, fSegments.length);
+ return segmentCopy;
+ }
+
+ public String segment(int index) {
+ if (index >= fSegments.length) {
+ return null;
+ }
+ return fSegments[index];
+ }
+
+ public String lastSegment() {
+ if (fSegments.length > 0) {
+ return fSegments[fSegments.length - 1];
+ }
+ return null;
+ }
+
+ public int matchingFirstSegments(IQualifiedTypeName typeName) {
+ int max = Math.min(fSegments.length, typeName.segmentCount());
+ int count = 0;
+ for (int i = 0; i < max; ++i) {
+ if (!fSegments[i].equals(typeName.segment(i))) {
+ return count;
+ }
+ ++count;
+ }
+ return count;
+ }
+
+ public boolean isPrefixOf(IQualifiedTypeName typeName) {
+ if (fSegments.length == 0)
+ return true;
+
+ if (fSegments.length > typeName.segmentCount()) {
+ return false;
+ }
+
+ for (int i = 0; i < fSegments.length; ++i) {
+ if (!fSegments[i].equals(typeName.segment(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public IQualifiedTypeName append(String[] names) {
+ int length = fSegments.length;
+ int typeNameLength = names.length;
+ String[] newSegments = new String[length + typeNameLength];
+ System.arraycopy(fSegments, 0, newSegments, 0, length);
+ System.arraycopy(names, 0, newSegments, length, typeNameLength);
+ QualifiedTypeName newTypeName = new QualifiedTypeName();
+ newTypeName.fSegments = newSegments;
+ return newTypeName;
+ }
+
+ public IQualifiedTypeName append(IQualifiedTypeName typeName) {
+ int length = fSegments.length;
+ int typeNameLength = typeName.segmentCount();
+ String[] newSegments = new String[length + typeNameLength];
+ System.arraycopy(fSegments, 0, newSegments, 0, length);
+ for (int i = 0; i < typeNameLength; ++i) {
+ newSegments[i + length] = typeName.segment(i);
+ }
+ QualifiedTypeName newTypeName = new QualifiedTypeName();
+ newTypeName.fSegments = newSegments;
+ return newTypeName;
+ }
+
+ public IQualifiedTypeName append(String qualifiedName) {
+ return append(createSegments(qualifiedName));
+ }
+
+ public IQualifiedTypeName removeFirstSegments(int count) {
+ if (count == 0) {
+ return this;
+ } else if (count >= fSegments.length || count < 0) {
+ return EMPTY;
+ } else {
+ int newSize = fSegments.length - count;
+ String[] newSegments = new String[newSize];
+ System.arraycopy(fSegments, count, newSegments, 0, newSize);
+ QualifiedTypeName newTypeName = new QualifiedTypeName();
+ newTypeName.fSegments = newSegments;
+ return newTypeName;
+ }
+ }
+
+ public IQualifiedTypeName removeLastSegments(int count) {
+ if (count == 0) {
+ return this;
+ } else if (count >= fSegments.length || count < 0) {
+ return EMPTY;
+ } else {
+ int newSize = fSegments.length - count;
+ String[] newSegments = new String[newSize];
+ System.arraycopy(fSegments, 0, newSegments, 0, newSize);
+ QualifiedTypeName newTypeName = new QualifiedTypeName();
+ newTypeName.fSegments = newSegments;
+ return newTypeName;
+ }
+ }
+
+ public boolean isLowLevel() {
+ for (int i = 0; i < fSegments.length; ++i) {
+ if (fSegments[i].startsWith("_")) { //$NON-NLS-1$
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isValid() {
+ for (int i = 0; i < fSegments.length; ++i) {
+ String segment = fSegments[i];
+ // type name must follow C conventions
+ IStatus val = CConventions.validateIdentifier(segment);
+ if (val.getSeverity() == IStatus.ERROR)
+ return false;
+ }
+ return true;
+ }
+
+ public boolean isValidSegment(String segment) {
+ if (segment.indexOf(QUALIFIER) != -1)
+ return false;
+ // type name must follow C conventions
+ IStatus val = CConventions.validateIdentifier(segment);
+ return (val.getSeverity() != IStatus.ERROR);
+ }
+
+ public int hashCode() {
+ if (fHashCode == 0) {
+ fHashCode = HASH_INIT;
+ for (int i = 0; i < fSegments.length; ++i) {
+ fHashCode = fHashCode * HASH_MULTIPLIER + fSegments[i].hashCode();
+ }
+ }
+ return fHashCode;
+ }
+
+ public String toString() {
+ return getFullyQualifiedName();
+ }
+
+ public int compareTo(Object obj) {
+ if (obj == this) {
+ return 0;
+ }
+ if (!(obj instanceof IQualifiedTypeName)) {
+ throw new ClassCastException();
+ }
+ return compareTo((IQualifiedTypeName)obj);
+ }
+
+ public int compareTo(IQualifiedTypeName typeName) {
+ if (typeName == this)
+ return 0;
+ if (typeName == null)
+ return 1;
+
+ int length = fSegments.length;
+ int typeNameLength = typeName.segmentCount();
+ int len = Math.min(length, typeNameLength);
+ int result = 0;
+ for (int i = 0; result == 0 && i < len; ++i) {
+ result = fSegments[i].compareTo(typeName.segment(i));
+ }
+ if (result == 0 && length != typeNameLength) {
+ result = (length < typeNameLength) ? -1 : 1;
+ }
+ return result;
+ }
+
+ public int compareToIgnoreCase(IQualifiedTypeName typeName) {
+ if (typeName == this)
+ return 0;
+ if (typeName == null)
+ return 1;
+
+ int length = fSegments.length;
+ int typeNameLength = typeName.segmentCount();
+ int len = Math.min(length, typeNameLength);
+ int result = 0;
+ for (int i = 0; result == 0 && i < len; ++i) {
+ result = fSegments[i].compareToIgnoreCase(typeName.segment(i));
+ }
+ if (result == 0 && length != typeNameLength) {
+ result = (length < typeNameLength) ? -1 : 1;
+ }
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof IQualifiedTypeName)) {
+ return false;
+ }
+ return equals((IQualifiedTypeName)obj);
+ }
+
+ public boolean equals(IQualifiedTypeName typeName) {
+ if (typeName == this)
+ return true;
+ if (typeName == null)
+ return false;
+
+ int length = fSegments.length;
+ int typeNameLength = typeName.segmentCount();
+ if (length != typeNameLength)
+ return false;
+ for (int i = 0; i < length; ++i) {
+ if (!fSegments[i].equals(typeName.segment(i)))
+ return false;
+ }
+ return true;
+ }
+
+ public boolean equalsIgnoreCase(IQualifiedTypeName typeName) {
+ if (typeName == this)
+ return true;
+ if (typeName == null)
+ return false;
+
+ int length = fSegments.length;
+ int typeNameLength = typeName.segmentCount();
+ if (length != typeNameLength)
+ return false;
+ for (int i = 0; i < length; ++i) {
+ if (!fSegments[i].equalsIgnoreCase(typeName.segment(i)))
+ return false;
+ }
+ return true;
+ }
+}
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..9786f678247
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/Signature.java
@@ -0,0 +1,1991 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-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.
+ *
+ * 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();
+ }
+ i++;
+ for (;;) {
+ if (methodSignature[i] == C_PARAM_END) {
+ return count;
+ }
+ int e= scanTypeSignature(methodSignature, i);
+ if (e < 0) {
+ throw new IllegalArgumentException();
+ }
+ 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; + } + 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; + } + 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); + } + 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(); + } + 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
new file mode 100644
index 00000000000..5492c812bbd
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java
@@ -0,0 +1,322 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
+
+public class TypeInfo implements ITypeInfo
+{
+// protected ITypeCache fTypeCache;
+ protected int fElementType;
+ 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;
+ protected final static ITypeInfo[] EMPTY_TYPES = new ITypeInfo[0];
+
+ public TypeInfo(int elementType, IQualifiedTypeName typeName) {
+ fElementType = elementType;
+ fQualifiedName = typeName;
+ }
+
+ public void addReference(ITypeReference location) {
+ if (fSourceRefs == null) {
+ fSourceRefs = new ITypeReference[INITIAL_REFS_SIZE];
+ fSourceRefsCount = 0;
+ } else if (fSourceRefsCount == fSourceRefs.length) {
+ ITypeReference[] refs = new ITypeReference[fSourceRefs.length + REFS_GROW_BY];
+ System.arraycopy(fSourceRefs, 0, refs, 0, fSourceRefsCount);
+ fSourceRefs = refs;
+ }
+ fSourceRefs[fSourceRefsCount] = location;
+ ++fSourceRefsCount;
+ }
+
+ public ITypeReference[] getReferences() {
+ if (fSourceRefs != null) {
+ ITypeReference[] refs = new ITypeReference[fSourceRefsCount];
+ System.arraycopy(fSourceRefs, 0, refs, 0, fSourceRefsCount);
+ return refs;
+ }
+ return null;
+ }
+
+ public ITypeReference getResolvedReference() {
+ for (int i = 0; i < fSourceRefsCount; ++i) {
+ ITypeReference location = fSourceRefs[i];
+ if (location.isLineNumber() )
+ return location;
+ if( location.getLength() != 0) {
+ return location;
+ }
+ }
+ return null;
+ }
+
+ public boolean isReferenced() {
+ 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;
+ }
+
+ public boolean canSubstituteFor(ITypeInfo info) {
+ return isExactMatch(info);
+ }
+
+ protected boolean isExactMatch(ITypeInfo info) {
+ if (hashCode() != info.hashCode())
+ return false;
+ if (fElementType == info.getCElementType()
+ && fQualifiedName.equals(info.getQualifiedTypeName())) {
+ ICProject project1 = getEnclosingProject();
+ ICProject project2 = info.getEnclosingProject();
+ if (project1 == null && project2 == null)
+ return true;
+ if (project1 == null || project2 == null)
+ return false;
+ return project1.equals(project2);
+ }
+ return false;
+ }
+
+ public boolean exists() {
+// return fTypeCache != null;
+ return true;
+ }
+
+ public int getCElementType() {
+ return fElementType;
+ }
+
+ public void setCElementType(int type) {
+ fElementType = type;
+ }
+
+ public IQualifiedTypeName getQualifiedTypeName() {
+ return fQualifiedName;
+ }
+
+ public String getName() {
+ return fQualifiedName.getName();
+ }
+
+ public boolean isEnclosedType() {
+ return (fQualifiedName.isQualified());
+ }
+
+ public ITypeInfo getEnclosingType(int kinds[]) {
+// if (fTypeCache != null) {
+// return fTypeCache.getEnclosingType(this, kinds);
+// }
+ return null;
+ }
+
+ public ITypeInfo getEnclosingType() {
+ return getEnclosingType(KNOWN_TYPES);
+ }
+
+ public ITypeInfo getEnclosingNamespace(boolean includeGlobalNamespace) {
+// if (fTypeCache != null) {
+// return fTypeCache.getEnclosingNamespace(this, includeGlobalNamespace);
+// }
+ return null;
+ }
+
+ public ITypeInfo getRootNamespace(boolean includeGlobalNamespace) {
+// if (fTypeCache != null) {
+// return fTypeCache.getRootNamespace(this, includeGlobalNamespace);
+// }
+ return null;
+ }
+
+ public boolean isEnclosingType() {
+ return (fElementType == ICElement.C_NAMESPACE
+ || fElementType == ICElement.C_CLASS
+ || fElementType == ICElement.C_STRUCT);
+ }
+
+ public boolean encloses(ITypeInfo info) {
+// if (isEnclosingType() && fTypeCache == info.getCache()) {
+// return fQualifiedName.isPrefixOf(info.getQualifiedTypeName());
+// }
+ return false;
+ }
+
+ public boolean isEnclosed(ITypeInfo info) {
+ return info.encloses(this);
+ }
+
+ public boolean hasEnclosedTypes() {
+// if (isEnclosingType() && fTypeCache != null) {
+// return fTypeCache.hasEnclosedTypes(this);
+// }
+ return false;
+ }
+
+ public ITypeInfo[] getEnclosedTypes() {
+ return getEnclosedTypes(KNOWN_TYPES);
+ }
+
+ public ITypeInfo[] getEnclosedTypes(int kinds[]) {
+// if (fTypeCache != null) {
+// return fTypeCache.getEnclosedTypes(this, kinds);
+// }
+ return EMPTY_TYPES;
+ }
+
+ public ICProject getEnclosingProject() {
+// if (fTypeCache != null) {
+// return fTypeCache.getProject();
+// }
+ return null;
+ }
+
+ public String toString() {
+ return fQualifiedName.toString();
+ }
+
+ public boolean isEnclosed(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;
+ }
+
+ return false;
+ }
+
+ public int hashCode() {
+ int hashCode = fQualifiedName.hashCode() + fElementType;
+ ICProject project = getEnclosingProject();
+ if (project != null)
+ hashCode += project.hashCode();
+ return hashCode;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof TypeInfo)) {
+ return false;
+ }
+ return isExactMatch((TypeInfo)obj);
+ }
+
+ public int compareTo(Object obj) {
+ if (obj == this) {
+ return 0;
+ }
+ if( !(obj instanceof TypeInfo)) {
+ throw new ClassCastException();
+ }
+ TypeInfo info= (TypeInfo)obj;
+ if (fElementType != info.fElementType)
+ return (fElementType < info.fElementType) ? -1 : 1;
+ return fQualifiedName.compareTo(info.getQualifiedTypeName());
+ }
+
+ public static boolean isValidType(int type) {
+ return ArrayUtil.contains(KNOWN_TYPES, type);
+ }
+
+ 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/TypeReference.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeReference.java
new file mode 100644
index 00000000000..9ad4850b42f
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeReference.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.model.IWorkingCopy;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+
+
+public class TypeReference implements ITypeReference {
+ private IPath fPath;
+ private IProject fProject;
+ private IResource fResource;
+ private IWorkingCopy fWorkingCopy;
+ private int fOffset;
+ private int fLength;
+ public boolean offsetIsLineNumber = false;
+
+ public TypeReference(IPath path, IProject project, int offset, int length) {
+ fPath = path;
+ fProject = project;
+ fWorkingCopy = null;
+ fResource = null;
+ fOffset = offset;
+ fLength = length;
+ }
+
+ public TypeReference(IResource resource, IProject project, int offset, int length) {
+ fPath = null;
+ fProject = project;
+ fWorkingCopy = null;
+ fResource = resource;
+ fOffset = offset;
+ fLength = length;
+ }
+
+ public TypeReference(IWorkingCopy workingCopy, IProject project, int offset, int length) {
+ fPath = null;
+ fProject = project;
+ fWorkingCopy = workingCopy;
+ fResource = null;
+ fOffset = offset;
+ fLength = length;
+ }
+
+ public TypeReference(IPath path, IProject project) {
+ this(path, project, 0, 0);
+ }
+
+ public TypeReference(IResource resource, IProject project) {
+ this(resource, project, 0, 0);
+ }
+
+ public TypeReference(IWorkingCopy workingCopy, IProject project) {
+ this(workingCopy, project, 0, 0);
+ }
+
+ public IPath getPath() {
+ if (fWorkingCopy != null) {
+ return fWorkingCopy.getPath();
+ } else if (fResource != null) {
+ return fResource.getFullPath();
+ } else {
+ return fPath;
+ }
+ }
+
+ public IPath getLocation() {
+ if (fWorkingCopy != null) {
+ IResource resource = fWorkingCopy.getUnderlyingResource();
+ if (resource != null) {
+ return resource.getLocation();
+ }
+ return null;
+ } else if (fResource != null) {
+ return fResource.getLocation();
+ } else if (fPath != null) {
+ return fPath;
+ } else if (fProject != null) {
+ return fProject.getLocation();
+ } else {
+ return null;
+ }
+ }
+
+ public IResource getResource() {
+ return fResource;
+ }
+
+ public IWorkingCopy getWorkingCopy() {
+ return fWorkingCopy;
+ }
+
+ public IProject getProject() {
+ if (fProject != null) {
+ return fProject;
+ }
+ if (fWorkingCopy != null) {
+ ICProject cProject = fWorkingCopy.getCProject();
+ if (cProject != null) {
+ return cProject.getProject();
+ }
+ return null;
+ } else if (fResource != null) {
+ return fResource.getProject();
+ } else {
+ return null;
+ }
+ }
+
+ public ITranslationUnit getTranslationUnit() {
+ ITranslationUnit unit = null;
+ if (fWorkingCopy != null) {
+ unit = fWorkingCopy.getTranslationUnit();
+ } else if (fResource != null) {
+ ICElement elem = CoreModel.getDefault().create(fResource);
+ if (elem instanceof ITranslationUnit)
+ unit = (ITranslationUnit) elem;
+ } else {
+ IPath path = getLocation();
+ ICElement elem = CoreModel.getDefault().create(path);
+ if (elem instanceof ITranslationUnit)
+ unit = (ITranslationUnit) elem;
+ }
+
+ if (unit == null) {
+ IProject project = getProject();
+ if (project != null) {
+ ICProject cProject = findCProject(project);
+ if (cProject != null) {
+ IPath path = getLocation();
+ ICElement elem = CoreModel.getDefault().createTranslationUnitFrom(cProject, path);
+ if (elem instanceof ITranslationUnit)
+ unit = (ITranslationUnit) elem;
+ }
+ }
+ }
+ return unit;
+ }
+
+ 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;
+ }
+
+ public ICElement[] getCElements() {
+ ITranslationUnit unit = getTranslationUnit();
+ if (unit != null) {
+ try {
+ if( offsetIsLineNumber )
+ {
+ ICElement [] result = new ICElement[1];
+ result[0] = unit.getElementAtLine(fOffset);
+ return result;
+ }
+ return unit.getElementsAtOffset(fOffset);
+ } catch (CModelException e) {
+ }
+ }
+ return null;
+ }
+
+ public int getOffset() {
+ return fOffset;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public IPath getRelativeIncludePath(IProject project) {
+ IPath path = getLocation();
+ if (path != null) {
+ IPath relativePath = PathUtil.makeRelativePathToProjectIncludes(path, project);
+ if (relativePath != null)
+ return relativePath;
+ }
+ return path;
+ }
+
+ public IPath getRelativePath(IPath relativeToPath) {
+ IPath path = getPath();
+ if (path != null) {
+ IPath relativePath = PathUtil.makeRelativePath(path, relativeToPath);
+ if (relativePath != null)
+ return relativePath;
+ }
+ return path;
+ }
+
+ public String toString() {
+ IPath path = getLocation();
+ if (path != null) {
+ if (fLength == 0 && fOffset == 0) {
+ return path.toString();
+ }
+ return path.toString() + ":" + fOffset + "-" + (fOffset + fLength); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ITypeReference)) {
+ return false;
+ }
+ ITypeReference ref = (ITypeReference)obj;
+ return toString().equals(ref.toString());
+ }
+
+ public boolean isLineNumber() {
+ return offsetIsLineNumber;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java
new file mode 100644
index 00000000000..bc162199f10
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.IWorkingCopy;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.parser.IScannerInfoProvider;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+public class TypeSearchScope implements ITypeSearchScope {
+
+ private Set fPathSet = new HashSet();
+ private Set fContainerSet = new HashSet();
+ private Set fProjectSet = new HashSet();
+ private Set fEnclosingProjectSet = new HashSet();
+ private boolean fWorkspaceScope = false;
+
+ // cached arrays
+ private ICProject[] fAllProjects = null;
+ private ICProject[] fProjects = null;
+ private IPath[] fContainerPaths = null;
+
+ public TypeSearchScope() {
+ }
+
+ public TypeSearchScope(boolean workspaceScope) {
+ fWorkspaceScope = workspaceScope;
+ }
+
+ public TypeSearchScope(ITypeSearchScope scope) {
+ add(scope);
+ }
+
+ public TypeSearchScope(ICProject project) {
+ add(project);
+ }
+
+ public Collection pathSet() {
+ return fPathSet;
+ }
+ public Collection containerSet() {
+ return fContainerSet;
+ }
+ public Collection projectSet() {
+ return fProjectSet;
+ }
+ public Collection enclosingProjectSet() {
+ return fEnclosingProjectSet;
+ }
+
+ public boolean encloses(ITypeSearchScope scope) {
+ if (isWorkspaceScope())
+ return true;
+
+ if (!scope.pathSet().isEmpty()) {
+ // check if this scope encloses the other scope's paths
+ for (Iterator i = scope.pathSet().iterator(); i.hasNext(); ) {
+ IPath path = (IPath) i.next();
+ if (!encloses(path))
+ return false;
+ }
+ }
+
+ if (!scope.containerSet().isEmpty()) {
+ // check if this scope encloses the other scope's containers
+ for (Iterator i = scope.containerSet().iterator(); i.hasNext(); ) {
+ IPath path = (IPath) i.next();
+ if (!encloses(path))
+ return false;
+ }
+ }
+
+ if (!scope.projectSet().isEmpty()) {
+ // check if this scope encloses the other scope's projects
+ for (Iterator i = scope.projectSet().iterator(); i.hasNext(); ) {
+ ICProject project = (ICProject) i.next();
+ if (!encloses(project))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public boolean encloses(ICProject project) {
+ if (isWorkspaceScope())
+ return true;
+
+ // check projects that were explicity added to scope
+ if (fProjectSet.contains(project))
+ return true;
+
+ return false;
+ }
+
+ public boolean encloses(IPath path) {
+ if (isWorkspaceScope())
+ return true;
+
+ // check files that were explicity added to scope
+ if (fPathSet.contains(path))
+ return true;
+
+ // check containers that were explicity added to scope
+ // including subdirs
+ if (fContainerSet.contains(path))
+ return true;
+ if (fContainerPaths == null) {
+ fContainerPaths = (IPath[]) fContainerSet.toArray(new IPath[fContainerSet.size()]);
+// java.util.Arrays.sort(fContainerPaths);
+ }
+ for (int i = 0; i < fContainerPaths.length; ++i) {
+ if (fContainerPaths[i].isPrefixOf(path)) {
+ return true;
+ }
+ }
+
+ // check projects that were explicity added to scope
+ if (fProjectSet.contains(path))
+ return true;
+
+ // check projects that were explicity added to scope
+ if (fProjects == null) {
+ fProjects = (ICProject[]) fProjectSet.toArray(new ICProject[fProjectSet.size()]);
+ }
+ // check if one of the projects contains path
+ for (int i = 0; i < fProjects.length; ++i) {
+ if (projectContainsPath(fProjects[i], path, false)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean encloses(String path) {
+ return encloses(new Path(path));
+ }
+
+ public boolean encloses(ICElement element) {
+ return encloses(element.getPath());
+ }
+
+ public boolean encloses(IWorkingCopy workingCopy) {
+ return encloses(workingCopy.getOriginalElement().getPath());
+ }
+
+ public ICProject[] getEnclosingProjects() {
+ if (isWorkspaceScope()) {
+ return getAllProjects();
+ }
+ return (ICProject[]) fEnclosingProjectSet.toArray(new ICProject[fEnclosingProjectSet.size()]);
+ }
+
+ private static boolean projectContainsPath(ICProject project, IPath path, boolean checkIncludePaths) {
+ IPath projectPath = project.getProject().getFullPath();
+ if (projectPath.isPrefixOf(path)) {
+// ISourceRoot[] sourceRoots = null;
+// try {
+// sourceRoots = cProject.getSourceRoots();
+// } catch (CModelException ex) {
+// }
+// if (sourceRoots != null) {
+// for (int j = 0; j < sourceRoots.length; ++j) {
+// ISourceRoot root = sourceRoots[j];
+// if (root.isOnSourceEntry(path))
+// return true;
+// }
+// }
+ return true;
+ }
+
+ if (checkIncludePaths) {
+ //TODO this appears to be very slow -- cache this?
+ IPath[] includePaths = getIncludePaths(project);
+ if (includePaths != null) {
+ for (int i = 0; i < includePaths.length; ++i) {
+ IPath include = includePaths[i];
+ if (include.isPrefixOf(path) || include.equals(path))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static IPath[] getIncludePaths(ICProject project) {
+ IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project.getProject());
+ if (provider != null) {
+ IScannerInfo info = provider.getScannerInformation(project.getProject());
+ if (info != null) {
+ String[] includes = info.getIncludePaths();
+ if (includes != null && includes.length > 0) {
+ IPath[] includePaths = new IPath[includes.length];
+ for (int i = 0; i < includes.length; ++i) {
+ includePaths[i] = new Path(includes[i]);
+ }
+// java.util.Arrays.sort(includePaths);
+ return includePaths;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static ICProject[] getAllProjects() {
+ ICProject[] projects = getCProjects();
+ if (projects == null)
+ projects = new ICProject[0];
+ return projects;
+ }
+
+ private static ICProject[] getCProjects() {
+ try {
+ return CoreModel.getDefault().getCModel().getCProjects();
+ } catch (CModelException e) {
+ CCorePlugin.log(e);
+ return new ICProject[0];
+ }
+ }
+
+ public boolean isPathScope() {
+ return !fPathSet.isEmpty();
+ }
+
+ public boolean isProjectScope() {
+ return !fProjectSet.isEmpty();
+ }
+
+ public boolean isWorkspaceScope() {
+ return fWorkspaceScope;
+ }
+
+ public boolean isEmpty() {
+ return (!isWorkspaceScope() && fPathSet.isEmpty() && fContainerSet.isEmpty() && fProjectSet.isEmpty());
+ }
+
+ public void add(IWorkingCopy workingCopy) {
+ IPath path = workingCopy.getOriginalElement().getPath();
+ ICProject cProject = workingCopy.getCProject();
+ fPathSet.add(path);
+ addEnclosingProject(cProject);
+ }
+
+ public void add(IPath path, boolean addSubfolders, ICProject enclosingProject) {
+ if (addSubfolders) {
+ fContainerSet.add(path);
+ fContainerPaths = null;
+ } else {
+ fPathSet.add(path);
+ }
+ if (enclosingProject != null) {
+ addEnclosingProject(enclosingProject);
+ } else {
+ // check all projects in workspace
+ if (fAllProjects == null) {
+ fAllProjects = getAllProjects();
+ }
+ // check if one of the projects contains path
+ for (int i = 0; i < fAllProjects.length; ++i) {
+ if (projectContainsPath(fAllProjects[i], path, false)) {
+ addEnclosingProject(fAllProjects[i]);
+ break;
+ }
+ }
+ }
+ }
+
+ public void add(ICProject project) {
+ fProjectSet.add(project);
+ fProjects = null;
+ fAllProjects = null;
+ addEnclosingProject(project);
+ }
+
+ private void addEnclosingProject(ICProject project) {
+ fEnclosingProjectSet.add(project);
+ }
+
+ public void addWorkspace() {
+ fWorkspaceScope = true;
+ fProjects = null;
+ fAllProjects = null;
+ }
+
+ public void add(ICElement elem) {
+ if (elem == null)
+ return;
+
+ switch (elem.getElementType()) {
+ case ICElement.C_MODEL: {
+ addWorkspace();
+ break;
+ }
+
+ case ICElement.C_PROJECT: {
+ ICProject project = ((ICProject)elem);
+ add(project);
+ break;
+ }
+
+ case ICElement.C_CCONTAINER: {
+ ICProject project = elem.getCProject();
+ add(elem.getPath(), true, project);
+ break;
+ }
+
+ case ICElement.C_UNIT: {
+ ICProject project = elem.getCProject();
+ add(elem.getPath(), false, project);
+ break;
+ }
+
+ case ICElement.C_INCLUDE:
+ case ICElement.C_NAMESPACE:
+ case ICElement.C_TEMPLATE_CLASS:
+ case ICElement.C_CLASS:
+ case ICElement.C_STRUCT:
+ case ICElement.C_UNION:
+ case ICElement.C_ENUMERATION:
+ case ICElement.C_TYPEDEF: {
+ ICProject project = elem.getCProject();
+ add(elem.getPath(), false, project);
+ break;
+ }
+ }
+ }
+
+ public void add(ITypeSearchScope scope) {
+ fPathSet.addAll(scope.pathSet());
+ fContainerSet.addAll(scope.containerSet());
+ fProjectSet.addAll(scope.projectSet());
+ fEnclosingProjectSet.addAll(scope.enclosingProjectSet());
+ fProjects = null;
+ fAllProjects = null;
+ fContainerPaths = null;
+ fWorkspaceScope |= scope.isWorkspaceScope();
+ }
+
+ public void clear() {
+ fPathSet.clear();
+ fContainerSet.clear();
+ fProjectSet.clear();
+ fEnclosingProjectSet.clear();
+ fWorkspaceScope = false;
+ fProjects = null;
+ fAllProjects = null;
+ fContainerPaths = null;
+ }
+}
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..3c2e9ca898e
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java
@@ -0,0 +1,288 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.IMember;
+import org.eclipse.cdt.core.model.IMethodDeclaration;
+import org.eclipse.cdt.core.model.IParent;
+import org.eclipse.cdt.core.model.IStructure;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+
+public class TypeUtil {
+
+ public static boolean isDeclaringType(ICElement elem) {
+ int type = elem.getElementType();
+ return (type == ICElement.C_CLASS
+ || type == ICElement.C_STRUCT
+ || type == ICElement.C_ENUMERATION
+ || type == ICElement.C_UNION
+ || type == ICElement.C_TYPEDEF
+ || type == ICElement.C_NAMESPACE);
+ }
+
+ public static boolean isMemberType(ICElement elem) {
+ int type = elem.getElementType();
+ if (type == ICElement.C_CLASS
+ || type == ICElement.C_STRUCT
+ || type == ICElement.C_ENUMERATION
+ || type == ICElement.C_UNION
+ || type == ICElement.C_TYPEDEF
+ || type == ICElement.C_NAMESPACE)
+ return true;
+ return elem instanceof IMember;
+ }
+
+ /**
+ * Returns the type in which this member is declared, or null
+ * if this member is not declared in a type (for example, a top-level type).
+ * This is a handle-only method.
+ *
+ * @return the type in which this member is declared, or null
+ * if this member is not declared in a type (for example, a top-level type)
+ */
+ public static ICElement getDeclaringType(ICElement elem) {
+ if (!isMemberType(elem))
+ return null;
+ ICElement parent = elem.getParent();
+ while (parent != null && !(parent instanceof ITranslationUnit)) {
+ if (isDeclaringType(parent))
+ return parent;
+ parent = parent.getParent();
+ }
+ return null;
+ }
+
+ public static ICElement getDeclaringClass(ICElement type) {
+ ICElement parentElement = type.getParent();
+ if (parentElement != null && isClassOrStruct(parentElement)) {
+ return parentElement;
+ }
+
+ if (isClassOrStruct(type)) {
+ while (parentElement != null) {
+ if (isClassOrStruct(parentElement)) {
+ return parentElement;
+ } else if (parentElement instanceof IMember) {
+ parentElement = parentElement.getParent();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public static boolean isClassOrStruct(ICElement type) {
+ int kind = type.getElementType();
+ // case ICElement.C_TEMPLATE_CLASS:
+ // case ICElement.C_TEMPLATE_STRUCT:
+ return (kind == ICElement.C_CLASS || kind == ICElement.C_STRUCT);
+ }
+
+ public static boolean isClass(ICElement type) {
+ return (type.getElementType() == ICElement.C_CLASS);
+ }
+
+ public static boolean isNamespace(ICElement type) {
+ return (type.getElementType() == ICElement.C_NAMESPACE);
+ }
+
+ /**
+ * Returns the top-level types declared in the given translation unit
+ * in the order in which they appear in the source.
+ *
+ * @param tu the translation unit
+ * @return the top-level types declared in the given translation unit
+ * @throws CModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ public static ICElement[] getTypes(ITranslationUnit tu) throws CModelException {
+ List typeList = new ArrayList();
+ ICElement[] children = tu.getChildren();
+ for (int i = 0; i < children.length; ++i) {
+ if (isDeclaringType(children[i]))
+ typeList.add(children[i]);
+ }
+ return (ICElement[])typeList.toArray(new ICElement[typeList.size()]);
+ }
+
+ /**
+ * Returns all types declared in the given translation unit in the order
+ * in which they appear in the source.
+ * This includes all top-level types and nested member types.
+ * It does NOT include local types (types defined in methods).
+ *
+ * @return the array of top-level and member types defined in the given translation unit, in declaration order.
+ * @throws CModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ public static ICElement[] getAllTypes(ITranslationUnit tu) throws CModelException {
+ ICElement[] types = getTypes(tu);
+ ArrayList allTypes = new ArrayList(types.length);
+ ArrayList typesToTraverse = new ArrayList(types.length);
+ for (int i = 0; i < types.length; i++) {
+ typesToTraverse.add(types[i]);
+ }
+ while (!typesToTraverse.isEmpty()) {
+ ICElement type = (ICElement) typesToTraverse.get(0);
+ typesToTraverse.remove(type);
+ allTypes.add(type);
+ types = getTypes(type);
+ for (int i = 0; i < types.length; i++) {
+ typesToTraverse.add(types[i]);
+ }
+ }
+ return (ICElement[])allTypes.toArray(new ICElement[allTypes.size()]);
+ }
+
+
+ /**
+ * Returns the immediate member types declared by the given element.
+ * The results are listed in the order in which they appear in the source file.
+ *
+ * @param elem the element
+ * @exception CModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ * @return the immediate member types declared by this type
+ */
+ public static ICElement[] getTypes(ICElement elem) throws CModelException {
+ List typeList = new ArrayList();
+ if (isDeclaringType(elem) && elem instanceof IParent) {
+ ICElement[] children = ((IParent)elem).getChildren();
+ for (int i = 0; i < children.length; ++i) {
+ if (isDeclaringType(children[i]))
+ typeList.add(children[i]);
+ }
+ }
+ return (ICElement[])typeList.toArray(new ICElement[typeList.size()]);
+ }
+
+ public static ITranslationUnit getTranslationUnit(ICElement elem) {
+ while (elem != null) {
+ if (elem instanceof ITranslationUnit)
+ return (ITranslationUnit)elem;
+ elem = elem.getParent();
+ }
+ return null;
+ }
+
+// TODO move method to CModelUtil
+ public static IQualifiedTypeName getFullyQualifiedName(ICElement type) {
+ String name = type.getElementName();
+ IQualifiedTypeName qualifiedName = new QualifiedTypeName(name);
+ ICElement parent = type.getParent();
+ while (parent != null && (isNamespace(parent) || isClass(parent))) {
+ qualifiedName = new QualifiedTypeName(parent.getElementName()).append(qualifiedName);
+ parent = parent.getParent();
+ }
+ return qualifiedName;
+ }
+
+ public static IMethodDeclaration[] getMethods(ICElement elem) {
+ if (elem instanceof IStructure) {
+ try {
+ List list = ((IParent)elem).getChildrenOfType(ICElement.C_METHOD_DECLARATION);
+ if (list != null && !list.isEmpty()) {
+ return (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));
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/UnknownTypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/UnknownTypeInfo.java
new file mode 100644
index 00000000000..a36c390e6a4
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/UnknownTypeInfo.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.core.runtime.IPath;
+
+public class UnknownTypeInfo extends TypeInfo {
+
+ public UnknownTypeInfo(String name, IPath path) {
+ this(new QualifiedTypeName(name));
+ if (path != null) {
+ addReference(new TypeReference(path, null));
+ }
+ }
+
+ public UnknownTypeInfo(IQualifiedTypeName typeName) {
+ super(0, typeName);
+ }
+
+ public boolean isUndefinedType() {
+ return true;
+ }
+
+ public boolean canSubstituteFor(ITypeInfo info) {
+ int compareType = info.getCElementType();
+ if (fElementType == 0 || compareType == 0 || fElementType == compareType) {
+ return fQualifiedName.equals(info.getQualifiedTypeName());
+ }
+ return false;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/ArrayUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/ArrayUtil.java
new file mode 100644
index 00000000000..a7f62f29445
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/ArrayUtil.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.util;
+
+/**
+ * A helper class which allows you to perform some
+ * simple set operations on int arrays.
+ */
+public class ArrayUtil {
+ private ArrayUtil() {
+ }
+
+ // returns true if set contains elem
+ public static boolean contains(int[] set, int elem) {
+ if (set == null)
+ return false;
+ for (int i= 0; i < set.length; ++i) {
+ if (set[i] == elem)
+ return true;
+ }
+ return false;
+ }
+
+ // returns true if set contains all of subset
+ public static boolean containsAll(int[] set, int[] subset) {
+ if (set == null || subset == null)
+ return false;
+ for (int i= 0; i < subset.length; ++i) {
+ if (!contains(set, subset[i]))
+ return false;
+ }
+ return true;
+ }
+
+ // return a copy of fromSet
+ public static int[] clone(int[] fromSet) {
+ if (fromSet == null)
+ return null;
+ int[] newSet= new int[fromSet.length];
+ for (int i= 0; i < fromSet.length; ++i) {
+ newSet[i]= fromSet[i];
+ }
+ return newSet;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/DelegatedProgressMonitor.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/DelegatedProgressMonitor.java
new file mode 100644
index 00000000000..4c229af80ca
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/DelegatedProgressMonitor.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * A wrapper around one or more progress monitors. Forwards
+ * IProgressMonitor
and IProgressMonitorWithBlocking
+ * methods to the delegate monitors.
+ */
+public class DelegatedProgressMonitor implements IProgressMonitor, IProgressMonitorWithBlocking {
+
+ private static int INITIAL_DELEGATE_COUNT = 2;
+ private final ArrayList fDelegateList = new ArrayList(INITIAL_DELEGATE_COUNT);
+ String fTaskName;
+ String fSubTask;
+ int fTotalWork;
+ private double fWorked;
+ private boolean fIsBlocked;
+ boolean fIsCanceled;
+
+ /**
+ * Creates a new delegated monitor.
+ */
+ public DelegatedProgressMonitor() {
+ init();
+ }
+
+ /**
+ * Creates a new delegated monitor, and adds a delegate.
+ */
+ public DelegatedProgressMonitor(IProgressMonitor delegate) {
+ init();
+ addDelegate(delegate);
+ }
+
+ /**
+ * Resets delegated monitor to initial state.
+ */
+ public synchronized void init() {
+ fTaskName= null;
+ fSubTask= null;
+ fTotalWork= IProgressMonitor.UNKNOWN;
+ fWorked= 0.0f;
+ fIsBlocked= false;
+ fIsCanceled= false;
+ }
+
+ /*
+ * @see IProgressMonitor#beginTask
+ */
+ public synchronized void beginTask(String name, int totalWork) {
+ fTaskName = name;
+ fTotalWork = totalWork;
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ delegate.beginTask(fTaskName, fTotalWork);
+ }
+ });
+ }
+
+ /*
+ * @see IProgressMonitor#done
+ */
+ public synchronized void done() {
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ delegate.done();
+ }
+ });
+ }
+
+ /*
+ * @see IProgressMonitor#setTaskName
+ */
+ public synchronized void setTaskName(String name) {
+ fTaskName = name;
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ delegate.setTaskName(fTaskName);
+ }
+ });
+ }
+
+ /*
+ * @see IProgressMonitor#subTask
+ */
+ public synchronized void subTask(String name) {
+ fSubTask = name;
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ delegate.subTask(fSubTask);
+ }
+ });
+ }
+
+ /*
+ * @see IProgressMonitor#worked
+ */
+ public void worked(int work) {
+ internalWorked(work);
+ }
+
+ /*
+ * @see IProgressMonitor#internalWorked
+ */
+ public synchronized void internalWorked(double internalWork) {
+ fWorked += internalWork;
+ final double fInternalWork = internalWork;
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ delegate.internalWorked(fInternalWork);
+ }
+ });
+ }
+
+ /*
+ * @see IProgressMonitor#isCanceled
+ */
+ public synchronized boolean isCanceled() {
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ fIsCanceled |= delegate.isCanceled();
+ }
+ });
+ return fIsCanceled;
+ }
+
+ /*
+ * @see IProgressMonitor#setCanceled
+ */
+ public synchronized void setCanceled(boolean canceled) {
+ fIsCanceled = canceled;
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ delegate.setCanceled(fIsCanceled);
+ }
+ });
+ }
+
+ /*
+ * @see IProgressMonitor#setBlocked
+ */
+ public synchronized void setBlocked(IStatus reason) {
+ fIsBlocked = true;
+ final IStatus fReason = reason;
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ if (delegate instanceof IProgressMonitorWithBlocking)
+ ((IProgressMonitorWithBlocking) delegate).setBlocked(fReason);
+ }
+ });
+ }
+
+ /*
+ * @see IProgressMonitor#clearBlocked
+ */
+ public synchronized void clearBlocked() {
+ fIsBlocked = false;
+ visitDelegates(new IDelegateVisitor() {
+ public void visit(IProgressMonitor delegate) {
+ if (delegate instanceof IProgressMonitorWithBlocking)
+ ((IProgressMonitorWithBlocking) delegate).clearBlocked();
+ }
+ });
+ }
+
+ /**
+ * Adds a delegate.
+ */
+ public synchronized void addDelegate(IProgressMonitor delegate) {
+ if (fDelegateList.indexOf(delegate) == -1) {
+ if (fTaskName != null)
+ syncUp(delegate);
+ fDelegateList.add(delegate);
+ }
+ }
+
+ /**
+ * Brings delegate in sync with current progress.
+ */
+ private void syncUp(IProgressMonitor delegate) {
+ delegate.beginTask(fTaskName, fTotalWork);
+ delegate.internalWorked(fWorked);
+ if (fSubTask != null && fSubTask.length() > 0)
+ delegate.subTask(fSubTask);
+ if (fIsBlocked && delegate instanceof IProgressMonitorWithBlocking)
+ ((IProgressMonitorWithBlocking) delegate).setBlocked(null);
+ }
+
+ /**
+ * Removes a delegate.
+ */
+ public synchronized void removeDelegate(IProgressMonitor delegate) {
+ int index = fDelegateList.indexOf(delegate);
+ if (index != -1) {
+ fDelegateList.remove(index);
+ }
+ }
+
+ /**
+ * Removes all delegates.
+ */
+ public synchronized void removeAllDelegates() {
+ fDelegateList.clear();
+ }
+
+ /**
+ * Returns the delegate list.
+ *
+ * @return An array of progress monitors added using addDelegate()
.
+ */
+ public synchronized IProgressMonitor[] getDelegates() {
+ return (IProgressMonitor[]) fDelegateList.toArray();
+ }
+
+ /**
+ * Defines a delegate visitor.
+ */
+ private static interface IDelegateVisitor {
+ public void visit(IProgressMonitor delegate);
+ }
+
+ /**
+ * Visits each delegate in the delegates list.
+ */
+ private void visitDelegates(IDelegateVisitor visitor) {
+ // Clone the delegates since they could remove themselves when called
+ ArrayList delegatesList = (ArrayList) fDelegateList.clone();
+ for (Iterator i = delegatesList.iterator(); i.hasNext(); ) {
+ IProgressMonitor delegate = (IProgressMonitor) i.next();
+ visitor.visit(delegate);
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java
new file mode 100644
index 00000000000..433439af856
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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 Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.util;
+
+import java.util.ArrayList;
+
+/**
+ * A helper class which allows you to perform some simple
+ * stack operations. Avoids the extra overhead of
+ * synchronization in Java.Util.Stack.
+ */
+public class SimpleStack {
+
+ private static int INITIAL_STACK_SIZE = 10;
+ private ArrayList items;
+ private static boolean VERBOSE = false;
+
+ public SimpleStack() {
+ items = new ArrayList(INITIAL_STACK_SIZE);
+ }
+
+ public SimpleStack(int initialSize) {
+ items = new ArrayList(initialSize);
+ }
+
+ public void clear() {
+ items.clear();
+ }
+
+ public Object push(Object item) {
+ items.add(item);
+ if (VERBOSE)
+ trace("push on stack: " + item); //$NON-NLS-1$
+ return item;
+ }
+
+ public Object pop() {
+ int top = items.size()-1;
+ if (top < 0)
+ return null;
+ Object item = items.get(top);
+ items.remove(top);
+ if (VERBOSE)
+ trace("pop from stack: " + item); //$NON-NLS-1$
+ return item;
+ }
+
+ public Object top() {
+ int top = items.size()-1;
+ if (top < 0)
+ return null;
+ return items.get(top);
+ }
+
+ public Object bottom() {
+ if (items.size() == 0)
+ return null;
+ return items.get(0);
+ }
+
+ public boolean isEmpty() {
+ return (items.size() == 0);
+ }
+
+ public Object[] toArray() {
+ return items.toArray();
+ }
+
+ public Object[] toArray(Object a[]) {
+ return items.toArray(a);
+ }
+
+ private static void trace(String msg) {
+ System.out.println("(" + Thread.currentThread() + ") " + msg); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}