From 302fc99a1f54ceee7e10207d37595c235a48922c Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Wed, 19 Apr 2006 21:03:51 +0000 Subject: [PATCH] Put the Type Cache back and reactivate the code that uses it, i.e., Open Type and the New Class Wizard. The info still returns null but I'll you should be able to compile. --- .../browser/ChangeLog-browser | 108 + .../cdt/core/browser/AllTypesCache.java | 150 ++ .../cdt/core/browser/IQualifiedTypeName.java | 48 + .../eclipse/cdt/core/browser/ITypeInfo.java | 205 ++ .../cdt/core/browser/ITypeInfoVisitor.java | 18 + .../cdt/core/browser/ITypeReference.java | 91 + .../cdt/core/browser/ITypeSearchScope.java | 47 + .../core/browser/IWorkingCopyProvider.java | 22 + .../eclipse/cdt/core/browser/PathUtil.java | 164 ++ .../cdt/core/browser/QualifiedTypeName.java | 391 ++++ .../eclipse/cdt/core/browser/Signature.java | 1991 +++++++++++++++++ .../eclipse/cdt/core/browser/TypeInfo.java | 322 +++ .../cdt/core/browser/TypeReference.java | 244 ++ .../cdt/core/browser/TypeSearchScope.java | 370 +++ .../eclipse/cdt/core/browser/TypeUtil.java | 288 +++ .../cdt/core/browser/UnknownTypeInfo.java | 39 + .../internal/core/browser/util/ArrayUtil.java | 53 + .../util/DelegatedProgressMonitor.java | 249 +++ .../core/browser/util/SimpleStack.java | 84 + 19 files changed, 4884 insertions(+) create mode 100644 core/org.eclipse.cdt.core/browser/ChangeLog-browser create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfoVisitor.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeReference.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IWorkingCopyProvider.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/PathUtil.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/Signature.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeReference.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/UnknownTypeInfo.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/ArrayUtil.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/DelegatedProgressMonitor.java create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java 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$ + } +}