diff --git a/core/org.eclipse.cdt.core/browser/ChangeLog-browser b/core/org.eclipse.cdt.core/browser/ChangeLog-browser new file mode 100644 index 00000000000..076461df5df --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/ChangeLog-browser @@ -0,0 +1,108 @@ +2005-03-29 Chris Wiebe + small change for potential reduction in memory usage + * browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java + +2005-03-29 Chris Wiebe + temporary fix for type parser timeout + * browser/org/eclipse/cdt/core/browser/cache/TypeParser.java + +2005-03-13 Bogdan Gheorghe + Updated references to IndexManager to reflect new multi-indexer framework. + * browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependencies.java + * browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob.java + * browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java + * browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java + * browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java + + Added temporary flag to TypeCacheManager to prevent deadlocks during JUnit runs, pending + changes to Index Storage framework. + * browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java + +2005-01-06 Chris Wiebe + added parser timeout to TypeParser + * browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java + +2004-11-08 Chris Wiebe + + fix for 68883 + * browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java + +2004-09-15 Chris Wiebe + + add getTypes and getAllTypes methods + * browser/org/eclipse/cdt/core/browser/TypeUtil.java + +2004-09-02 Chris Wiebe + + add method to get global namespace + * browser/org/eclipse/cdt/internal/core/browser/AllTypesCache.java + +2004-09-01 Chris Wiebe + + avoid unnecessary deltas + * browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java + +2004-08-31 Chris Wiebe + + Fix for 68883 + * browser/org/eclipse/cdt/core/browser/AllTypesCache.java + * browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java + * browser/org/eclipse/cdt/core/browser/ITypeInfo.java + * browser/org/eclipse/cdt/core/browser/TypeInfo.java + * browser/org/eclipse/cdt/core/browser/TypeUtil.java + * browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java + * browser/org/eclipse/cdt/core/browser/cache/ITypeCache.java + * browser/org/eclipse/cdt/core/browser/cache/TypeCache.java + * browser/org/eclipse/cdt/core/browser/cache/TypeCacheManager.java + +2004-08-26 Chris Wiebe + + make QualifiedTypeName immutable class + get rid of unnecessary memory allocations + * browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java + * browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java + * browser/org/eclipse/cdt/core/browser/TypeInfo.java + * browser/org/eclipse/cdt/internal/core/browser/TypeCache.java + +2004-07-16 Chris Wiebe + + Fixing numerous warnings. + +2004-07-06 Chris Wiebe + + This patch prevents some NPEs from happening in the class browser. I + suggest this should be applied to both HEAD and CDT_2_0 branch. + + * browser/org/eclipse/cdt/core/browser/TypeInfo.java + +2004-06-22 Alain Magloire + Part of PR 68246. + Close the inputstream to release resource handle + when we done with it, we can not rely on the GC to do it for us. + + * browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java + +2004-06-21 Chris Wiebe + + - fix for bug #66108 (C++ browser cannot show members of class) + - TypeParser now uses resource to get scanner info + +2004-06-17 Alain Magloire + + Changes from Chris Wiebe to deal + with the memory consumption. + +2004-05-12 Chris Wiebe + Heavy refactoring of type cache to address scalability + concerns. + +2004-05-06 Chris Wiebe + Creating a new Job to handle the changes, instead + of reusing the same job. + +2004-04-20 Chris Wiebe + refactored TypeCacheDeltaListener into standalone class + added option in Work In Progress prefs page to disable background cache + +2004-04-06 Chris Wiebe + initial placement of non-ui code into org.eclipse.cdt.core.browser \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java new file mode 100644 index 00000000000..8be21ebedbd --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * 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.Collection; + +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.IElementChangedListener; +import org.eclipse.cdt.core.model.IWorkingCopy; +import org.eclipse.cdt.internal.core.browser.util.ArrayUtil; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Preferences.IPropertyChangeListener; + +/** + * Manages a search cache for types in the workspace. Instead of returning + * objects of type ICElement the methods of this class returns a + * list of the lightweight objects TypeInfo. + *

+ * 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 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. + *

+ * 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. Rich signatures containing these facets + * only occur when dealing with code that makes overt use of the new language + * features. All other code, and certainly all Java code written or compiled + * with J2SE 1.4 or earlier, involved only simple signatures. + *

+ *

+ * The syntax for a type signature is: + *

+ * TypeSignature ::=
+ *     "B"  // byte
+ *   | "C"  // char
+ *   | "D"  // double
+ *   | "F"  // float
+ *   | "I"  // int
+ *   | "J"  // long
+ *   | "S"  // short
+ *   | "V"  // void
+ *   | "Z"  // boolean
+ *   | "T" + Identifier + ";" // type variable
+ *   | "[" + TypeSignature  // array X[]
+ *   | ResolvedClassTypeSignature
+ *   | UnresolvedClassTypeSignature
+ * 
+ * ResolvedClassTypeSignature ::= // resolved named type (in compiled code)
+ *     "L" + Identifier + OptionalTypeArguments
+ *           ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
+ * 
+ * UnresolvedClassTypeSignature ::= // unresolved named type (in source code)
+ *     "Q" + Identifier + OptionalTypeArguments
+ *           ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
+ * 
+ * OptionalTypeArguments ::=
+ *     "<" + TypeArgument+ + ">" 
+ *   |
+ * 
+ * TypeArgument ::=
+ *   | TypeSignature
+ *   | "*" // wildcard ?
+ *   | "+" TypeSignature // wildcard ? extends X
+ *   | "-" TypeSignature // wildcard ? super X
+ * 
+ *

+ *

+ * Examples: + *

+ *

+ *

+ * The syntax for a method signature is: + *

+ * MethodSignature ::= "(" + ParamTypeSignature* + ")" + ReturnTypeSignature
+ * ParamTypeSignature ::= TypeSignature
+ * ReturnTypeSignature ::= TypeSignature
+ * 
+ *

+ * Examples: + *

+ *

+ *

+ * The syntax for a formal type parameter signature is: + *

+ * FormalTypeParameterSignature ::=
+ *     TypeVariableName + OptionalClassBound + InterfaceBound*
+ * TypeVariableName ::= Identifier
+ * OptionalClassBound ::=
+ *     ":"
+ *   | ":" + TypeSignature
+ * InterfaceBound ::= 
+ *     ":" + TypeSignature
+ * 
+ *

+ * Examples: + *

+ *

+ *

+ * 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. + *

+ * + * @param signature the type signature + * @return the string representation of the type + * @exception IllegalArgumentException if the signature is not syntactically + * correct + * + * @since 2.0 + */ +public static char[] toCharArray(char[] signature) throws IllegalArgumentException { + int sigLength = signature.length; + if (sigLength == 0 || signature[0] == C_PARAM_START || signature[0] == C_GENERIC_START) { + return toCharArray(signature, CharOperation.NO_CHAR, null, true, true); + } + + StringBuffer buffer = new StringBuffer(signature.length + 10); + appendTypeSignature(signature, 0, true, buffer); + char[] result = new char[buffer.length()]; + buffer.getChars(0, buffer.length(), result, 0); + return result; +} + +/** + * Scans the given string for a 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 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. + *

+ * + * @param signature the type signature + * @return the string representation of the type + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ +public static String toString(String signature) throws IllegalArgumentException { + return new String(toCharArray(signature.toCharArray())); +} +/** + * Converts the given method signature to a readable string. The method signature is expected to + * be dot-based. + * + * @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 + * @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$ + } +}