Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java253
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java32
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java8
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java10
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/PathUtil.java6
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java90
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java113
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java31
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/UnknownTypeInfo.java8
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java451
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java171
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java29
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java582
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java129
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java50
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties17
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/BasicJob.java116
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java214
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob.java93
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob2.java92
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob.java157
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob2.java166
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java186
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob2.java229
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java67
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java896
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheDelta.java60
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java471
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.java50
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties23
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java275
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeLocatorJob.java67
-rw-r--r--core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java955
33 files changed, 5991 insertions, 106 deletions
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
index 8be21ebedbd..89c047ae7d2 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java
@@ -14,15 +14,23 @@ import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
+import org.eclipse.cdt.core.browser.typehierarchy.TypeHierarchyBuilder;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ElementChangedEvent;
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.cache.ITypeCache;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
+import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
+import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
/**
* Manages a search cache for types in the workspace. Instead of returning
@@ -39,13 +47,92 @@ import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
*/
public class AllTypesCache {
+ private static final int INITIAL_DELAY = 5000;
+ private static IWorkingCopyProvider fgWorkingCopyProvider;
+ private static TypeHierarchyBuilder fgTypeHierarchyBuilder;
+ private static IElementChangedListener fgElementChangedListener;
+ private static IPropertyChangeListener fgPropertyChangeListener;
+ static boolean fgEnableIndexing = true;
+
+ /** Preference key for enabling background cache */
+ public final static String ENABLE_BACKGROUND_TYPE_CACHE = "enableBackgroundTypeCache"; //$NON-NLS-1$
+
+ /**
+ * Initializes the AllTypesCache service.
+ *
+ * @param provider A working copy provider.
+ */
+ public static void initialize(IWorkingCopyProvider workingCopyProvider) {
+ fgWorkingCopyProvider = workingCopyProvider;
+ TypeCacheManager.getInstance().setWorkingCopyProvider(fgWorkingCopyProvider);
+ fgTypeHierarchyBuilder = new TypeHierarchyBuilder();
+
+ // load prefs
+// Preferences prefs = CCorePlugin.getDefault().getPluginPreferences();
+// if (prefs.contains(ENABLE_BACKGROUND_TYPE_CACHE)) {
+// fgEnableIndexing = prefs.getBoolean(ENABLE_BACKGROUND_TYPE_CACHE);
+// } else {
+// prefs.setDefault(ENABLE_BACKGROUND_TYPE_CACHE, false);
+// prefs.setValue(ENABLE_BACKGROUND_TYPE_CACHE, false);
+// CCorePlugin.getDefault().savePluginPreferences();
+// fgEnableIndexing = true;
+// }
+ fgEnableIndexing = false;
+
+ // start jobs in background after INITIAL_DELAY
+ TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY);
+
+ // add delta listener
+ fgElementChangedListener = new IElementChangedListener() {
+ public void elementChanged(ElementChangedEvent event) {
+ TypeCacheManager.getInstance().processElementChanged(event, fgEnableIndexing);
+ }
+ };
+ CoreModel.getDefault().addElementChangedListener(fgElementChangedListener);
+
+// // add property change listener
+// fgPropertyChangeListener = new IPropertyChangeListener() {
+// public void propertyChange(PropertyChangeEvent event) {
+// String property = event.getProperty();
+// if (property.equals(ENABLE_BACKGROUND_TYPE_CACHE)) {
+// String value = (String) event.getNewValue();
+// fgEnableIndexing = Boolean.valueOf(value).booleanValue();
+// if (!fgEnableIndexing) {
+// TypeCacheManager.getInstance().cancelJobs();
+// } else {
+// TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
+// }
+// }
+// }
+// };
+// prefs.addPropertyChangeListener(fgPropertyChangeListener);
+ }
+
+ /**
+ * Terminates the service provided by AllTypesCache.
+ */
+ public static void terminate() {
+ // remove delta listener
+ if (fgElementChangedListener != null)
+ CoreModel.getDefault().removeElementChangedListener(fgElementChangedListener);
+
+ // remove property change listener
+ if (fgPropertyChangeListener != null)
+ CCorePlugin.getDefault().getPluginPreferences().removePropertyChangeListener(fgPropertyChangeListener);
+
+ // terminate all running jobs
+ if (TypeCacheManager.getInstance() != null) {
+ TypeCacheManager.getInstance().cancelJobs();
+ }
+ }
+
/**
* Returns all types in the workspace.
*/
public static ITypeInfo[] getAllTypes() {
final Collection fAllTypes = new ArrayList();
TypeSearchScope workspaceScope = new TypeSearchScope(true);
- ICProject[] projects = workspaceScope.getEnclosingProjects();
+ IProject[] projects = workspaceScope.getEnclosingProjects();
ITypeInfoVisitor visitor = new ITypeInfoVisitor() {
public boolean visit(ITypeInfo info) {
fAllTypes.add(info);
@@ -54,7 +141,7 @@ public class AllTypesCache {
public boolean shouldContinue() { return true; }
};
for (int i = 0; i < projects.length; ++i) {
-// TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
+ TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
}
return (ITypeInfo[]) fAllTypes.toArray(new ITypeInfo[fAllTypes.size()]);
}
@@ -70,7 +157,7 @@ public class AllTypesCache {
final Collection fTypesFound = new ArrayList();
final ITypeSearchScope fScope = scope;
final int[] fKinds = kinds;
- ICProject[] projects = scope.getEnclosingProjects();
+ IProject[] projects = scope.getEnclosingProjects();
ITypeInfoVisitor visitor = new ITypeInfoVisitor() {
public boolean visit(ITypeInfo info) {
if (ArrayUtil.contains(fKinds, info.getCElementType())
@@ -82,12 +169,51 @@ public class AllTypesCache {
public boolean shouldContinue() { return true; }
};
for (int i = 0; i < projects.length; ++i) {
-// TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
+ TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
}
return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
}
/**
+ * Returns all types matching name in the given scope.
+ *
+ * @param scope The search scope
+ * @param qualifiedName The qualified type name
+ * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS,
+ * C_UNION, C_ENUMERATION, C_TYPEDEF
+ * @param matchEnclosed <code>true</code> if enclosed types count as matches (foo::bar == bar)
+ */
+ public static ITypeInfo[] getTypes(ITypeSearchScope scope, IQualifiedTypeName qualifiedName, int[] kinds, boolean matchEnclosed) {
+ final Collection fTypesFound = new ArrayList();
+ final ITypeSearchScope fScope = scope;
+ final int[] fKinds = kinds;
+ final IQualifiedTypeName fQualifiedName = qualifiedName;
+ final boolean fMatchEnclosed = matchEnclosed;
+ IProject[] projects = scope.getEnclosingProjects();
+ ITypeInfoVisitor visitor = new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo info) {
+ if (ArrayUtil.contains(fKinds, info.getCElementType())
+ && (fScope != null && info.isEnclosed(fScope))) {
+ IQualifiedTypeName currName = info.getQualifiedTypeName();
+ if (fMatchEnclosed && currName.segmentCount() > fQualifiedName.segmentCount()
+ && currName.lastSegment().equals(fQualifiedName.lastSegment())) {
+ currName = currName.removeFirstSegments(currName.segmentCount() - fQualifiedName.segmentCount());
+ }
+ if (currName.equals(fQualifiedName)) {
+ 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
@@ -96,7 +222,7 @@ public class AllTypesCache {
public static ITypeInfo[] getNamespaces(ITypeSearchScope scope, boolean includeGlobalNamespace) {
final Collection fTypesFound = new ArrayList();
final ITypeSearchScope fScope = scope;
- ICProject[] projects = scope.getEnclosingProjects();
+ IProject[] projects = scope.getEnclosingProjects();
ITypeInfoVisitor visitor = new ITypeInfoVisitor() {
public boolean visit(ITypeInfo info) {
if (info.getCElementType() == ICElement.C_NAMESPACE
@@ -108,15 +234,76 @@ public class AllTypesCache {
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());
-// }
+ 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 the global (default) namespace for the given project.
+ *
+ * @param project the project
+ */
+ public static ITypeInfo getGlobalNamespace(IProject project) {
+ ITypeCache cache = TypeCacheManager.getInstance().getCache(project);
+ return cache.getGlobalNamespace();
+ }
+
+ /**
+ * Returns true if the type cache is up to date.
+ */
+ public static boolean isCacheUpToDate(ITypeSearchScope scope) {
+ forceDeltaComplete();
+
+ IProject[] projects = scope.getEnclosingProjects();
+ for (int i = 0; i < projects.length; ++i) {
+ IProject project = projects[i];
+ if (project.exists() && project.isOpen()) {
+ if (!TypeCacheManager.getInstance().getCache(project).isUpToDate())
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static void forceDeltaComplete() {
+ if (fgWorkingCopyProvider != null) {
+ IWorkingCopy[] workingCopies = fgWorkingCopyProvider.getWorkingCopies();
+ for (int i = 0; i < workingCopies.length; ++i) {
+ IWorkingCopy wc = workingCopies[i];
+ try {
+ synchronized (wc) {
+ wc.reconcile();
+ }
+ } catch (CModelException ex) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Updates the type cache.
+ *
+ * @param monitor the progress monitor
+ */
+ public static void updateCache(ITypeSearchScope scope, IProgressMonitor monitor) {
+ TypeCacheManager.getInstance().updateCache(scope, monitor);
+ }
+
+ /**
+ * Resolves a type location.
+ *
+ * @param info the type to search for
+ * @param monitor the progress monitor
+ */
+ public static ITypeReference resolveTypeLocation(ITypeInfo info, IProgressMonitor monitor) {
+ return TypeCacheManager.getInstance().resolveTypeLocation(info, monitor, fgEnableIndexing);
+ }
+
/** Returns first type in the cache which matches the given
* type and name. If no type is found, <code>null</code>
* is returned.
@@ -126,10 +313,9 @@ public class AllTypesCache {
* @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;
+ public static ITypeInfo getType(IProject project, int type, IQualifiedTypeName qualifiedName) {
+ ITypeCache cache = TypeCacheManager.getInstance().getCache(project);
+ return cache.getType(type, qualifiedName);
}
/**
@@ -141,10 +327,39 @@ public class AllTypesCache {
* @param ignoreCase <code>true</code> 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];
+ public static ITypeInfo[] getTypes(IProject project, IQualifiedTypeName qualifiedName, boolean matchEnclosed, boolean ignoreCase) {
+ ITypeCache cache = TypeCacheManager.getInstance().getCache(project);
+ return cache.getTypes(qualifiedName, matchEnclosed, ignoreCase);
}
+ /**
+ * Creates and returns a type hierarchy for this type containing
+ * this type and all of its supertypes and subtypes in the workspace.
+ *
+ * @param info the given type
+ * @param monitor the given progress monitor
+ * @return a type hierarchy for the given type
+ */
+ public static ITypeHierarchy createTypeHierarchy(ICElement type, IProgressMonitor monitor) throws CModelException {
+ ITypeInfo info = TypeCacheManager.getInstance().getTypeForElement(type, true, true, fgEnableIndexing, monitor);
+ if (info != null)
+ return fgTypeHierarchyBuilder.createTypeHierarchy(info, fgEnableIndexing, monitor);
+ return null;
+ }
+
+ public static void addTypeCacheChangedListener(ITypeCacheChangedListener listener) {
+ TypeCacheManager.getInstance().addTypeCacheChangedListener(listener);
+ }
+
+ public static void removeTypeCacheChangedListener(ITypeCacheChangedListener listener) {
+ TypeCacheManager.getInstance().removeTypeCacheChangedListener(listener);
+ }
+
+ public static ITypeInfo getTypeForElement(ICElement element, boolean forceUpdate, boolean forceResolve, IProgressMonitor monitor) {
+ return TypeCacheManager.getInstance().getTypeForElement(element, forceUpdate, forceResolve, fgEnableIndexing, monitor);
+ }
+
+ public static ICElement getElementForType(ITypeInfo type, boolean forceUpdate, boolean forceResolve, IProgressMonitor monitor) {
+ return TypeCacheManager.getInstance().getElementForType(type, forceUpdate, forceResolve, fgEnableIndexing, monitor);
+ }
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java
new file mode 100644
index 00000000000..a7e7bce5d19
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.resources.IProject;
+
+
+/**
+ * A listener which gets notified when the type cache changes.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface ITypeCacheChangedListener {
+
+ /**
+ * Notifies that the type cache for the given project has changed in some way
+ * and should be refreshed at some point to make it consistent with the current
+ * state of the C model.
+ *
+ * @param project the given project
+ */
+ void typeCacheChanged(IProject project);
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java
index 5b10ac987a2..b985dbf27f6 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java
@@ -11,8 +11,9 @@
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.cache.ITypeCache;
+import org.eclipse.core.resources.IProject;
/**
* Type information.
@@ -126,7 +127,7 @@ public interface ITypeInfo extends Comparable {
/**
* Gets the enclosing project.
*/
- public ICProject getEnclosingProject();
+ public IProject getEnclosingProject();
/**
* Returns true if type is enclosed in the given scope.
@@ -155,6 +156,9 @@ public interface ITypeInfo extends Comparable {
*/
public boolean canSubstituteFor(ITypeInfo info);
+ public ITypeCache getCache();
+ public void setCache(ITypeCache typeCache);
+
/**
* Returns true if other types extend this type.
*/
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
index 657bad5467d..269d3c9a8f5 100644
--- 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
@@ -13,8 +13,8 @@ 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.resources.IProject;
import org.eclipse.core.runtime.IPath;
public interface ITypeSearchScope {
@@ -25,20 +25,20 @@ public interface ITypeSearchScope {
public boolean isEmpty();
public boolean encloses(ITypeSearchScope scope);
- public boolean encloses(ICProject project);
+ public boolean encloses(IProject 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(IPath path, boolean addSubfolders, IProject enclosingProject);
+ public void add(IProject project);
public void add(ICElement elem);
public void add(ITypeSearchScope scope);
public void addWorkspace();
public void clear();
- public ICProject[] getEnclosingProjects();
+ public IProject[] getEnclosingProjects();
public Collection pathSet();
public Collection containerSet();
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
index 38cafa24771..99750e02091 100644
--- 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
@@ -14,8 +14,6 @@ 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;
@@ -132,14 +130,14 @@ public class PathUtil {
return relativePath;
}
- public static ICProject getEnclosingProject(IPath fullPath) {
+ public static IProject 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());
+ return res.getProject();
path = path.removeLastSegments(1);
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java
index 5492c812bbd..9a10b78da9d 100644
--- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java
@@ -11,13 +11,14 @@
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.cache.ITypeCache;
import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
+import org.eclipse.core.resources.IProject;
public class TypeInfo implements ITypeInfo
{
-// protected ITypeCache fTypeCache;
+ protected ITypeCache fTypeCache;
protected int fElementType;
protected IQualifiedTypeName fQualifiedName;
protected ITypeReference[] fSourceRefs = null;
@@ -104,8 +105,8 @@ public class TypeInfo implements ITypeInfo
return false;
if (fElementType == info.getCElementType()
&& fQualifiedName.equals(info.getQualifiedTypeName())) {
- ICProject project1 = getEnclosingProject();
- ICProject project2 = info.getEnclosingProject();
+ IProject project1 = getEnclosingProject();
+ IProject project2 = info.getEnclosingProject();
if (project1 == null && project2 == null)
return true;
if (project1 == null || project2 == null)
@@ -116,8 +117,7 @@ public class TypeInfo implements ITypeInfo
}
public boolean exists() {
-// return fTypeCache != null;
- return true;
+ return fTypeCache != null;
}
public int getCElementType() {
@@ -141,9 +141,9 @@ public class TypeInfo implements ITypeInfo
}
public ITypeInfo getEnclosingType(int kinds[]) {
-// if (fTypeCache != null) {
-// return fTypeCache.getEnclosingType(this, kinds);
-// }
+ if (fTypeCache != null) {
+ return fTypeCache.getEnclosingType(this, kinds);
+ }
return null;
}
@@ -152,16 +152,16 @@ public class TypeInfo implements ITypeInfo
}
public ITypeInfo getEnclosingNamespace(boolean includeGlobalNamespace) {
-// if (fTypeCache != null) {
-// return fTypeCache.getEnclosingNamespace(this, includeGlobalNamespace);
-// }
+ if (fTypeCache != null) {
+ return fTypeCache.getEnclosingNamespace(this, includeGlobalNamespace);
+ }
return null;
}
public ITypeInfo getRootNamespace(boolean includeGlobalNamespace) {
-// if (fTypeCache != null) {
-// return fTypeCache.getRootNamespace(this, includeGlobalNamespace);
-// }
+ if (fTypeCache != null) {
+ return fTypeCache.getRootNamespace(this, includeGlobalNamespace);
+ }
return null;
}
@@ -172,9 +172,9 @@ public class TypeInfo implements ITypeInfo
}
public boolean encloses(ITypeInfo info) {
-// if (isEnclosingType() && fTypeCache == info.getCache()) {
-// return fQualifiedName.isPrefixOf(info.getQualifiedTypeName());
-// }
+ if (isEnclosingType() && fTypeCache == info.getCache()) {
+ return fQualifiedName.isPrefixOf(info.getQualifiedTypeName());
+ }
return false;
}
@@ -183,9 +183,9 @@ public class TypeInfo implements ITypeInfo
}
public boolean hasEnclosedTypes() {
-// if (isEnclosingType() && fTypeCache != null) {
-// return fTypeCache.hasEnclosedTypes(this);
-// }
+ if (isEnclosingType() && fTypeCache != null) {
+ return fTypeCache.hasEnclosedTypes(this);
+ }
return false;
}
@@ -194,16 +194,16 @@ public class TypeInfo implements ITypeInfo
}
public ITypeInfo[] getEnclosedTypes(int kinds[]) {
-// if (fTypeCache != null) {
-// return fTypeCache.getEnclosedTypes(this, kinds);
-// }
+ if (fTypeCache != null) {
+ return fTypeCache.getEnclosedTypes(this, kinds);
+ }
return EMPTY_TYPES;
}
- public ICProject getEnclosingProject() {
-// if (fTypeCache != null) {
-// return fTypeCache.getProject();
-// }
+ public IProject getEnclosingProject() {
+ if (fTypeCache != null) {
+ return fTypeCache.getProject();
+ }
return null;
}
@@ -227,7 +227,7 @@ public class TypeInfo implements ITypeInfo
public int hashCode() {
int hashCode = fQualifiedName.hashCode() + fElementType;
- ICProject project = getEnclosingProject();
+ IProject project = getEnclosingProject();
if (project != null)
hashCode += project.hashCode();
return hashCode;
@@ -260,6 +260,14 @@ public class TypeInfo implements ITypeInfo
return ArrayUtil.contains(KNOWN_TYPES, type);
}
+ public ITypeCache getCache() {
+ return fTypeCache;
+ }
+
+ public void setCache(ITypeCache typeCache) {
+ fTypeCache = typeCache;
+ }
+
public void addDerivedReference(ITypeReference location) {
if (fDerivedSourceRefs == null) {
fDerivedSourceRefs = new ITypeReference[INITIAL_REFS_SIZE];
@@ -287,31 +295,31 @@ public class TypeInfo implements ITypeInfo
}
public ITypeInfo[] getSubTypes() {
-// if (fTypeCache != null) {
-// return fTypeCache.getSubtypes(this);
-// }
+ if (fTypeCache != null) {
+ return fTypeCache.getSubtypes(this);
+ }
return null;
}
public boolean hasSuperTypes() {
-// if (fTypeCache != null) {
-// return (fTypeCache.getSupertypes(this) != null);
-// }
+ 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);
-// }
+ if (fTypeCache != null) {
+ return fTypeCache.getSupertypes(this);
+ }
return null;
}
public ASTAccessVisibility getSuperTypeAccess(ITypeInfo superType) {
-// if (fTypeCache != null) {
-// return fTypeCache.getSupertypeAccess(this, superType);
-// }
+ if (fTypeCache != null) {
+ return fTypeCache.getSupertypeAccess(this, superType);
+ }
return null;
}
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
index bc162199f10..c29ea790f9a 100644
--- 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
@@ -16,13 +16,15 @@ 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.CProjectNature;
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.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
@@ -35,8 +37,8 @@ public class TypeSearchScope implements ITypeSearchScope {
private boolean fWorkspaceScope = false;
// cached arrays
- private ICProject[] fAllProjects = null;
- private ICProject[] fProjects = null;
+ private IProject[] fAllProjects = null;
+ private IProject[] fProjects = null;
private IPath[] fContainerPaths = null;
public TypeSearchScope() {
@@ -50,7 +52,7 @@ public class TypeSearchScope implements ITypeSearchScope {
add(scope);
}
- public TypeSearchScope(ICProject project) {
+ public TypeSearchScope(IProject project) {
add(project);
}
@@ -92,7 +94,7 @@ public class TypeSearchScope implements ITypeSearchScope {
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();
+ IProject project = (IProject) i.next();
if (!encloses(project))
return false;
}
@@ -101,7 +103,7 @@ public class TypeSearchScope implements ITypeSearchScope {
return true;
}
- public boolean encloses(ICProject project) {
+ public boolean encloses(IProject project) {
if (isWorkspaceScope())
return true;
@@ -140,7 +142,7 @@ public class TypeSearchScope implements ITypeSearchScope {
// check projects that were explicity added to scope
if (fProjects == null) {
- fProjects = (ICProject[]) fProjectSet.toArray(new ICProject[fProjectSet.size()]);
+ fProjects = (IProject[]) fProjectSet.toArray(new IProject[fProjectSet.size()]);
}
// check if one of the projects contains path
for (int i = 0; i < fProjects.length; ++i) {
@@ -164,15 +166,15 @@ public class TypeSearchScope implements ITypeSearchScope {
return encloses(workingCopy.getOriginalElement().getPath());
}
- public ICProject[] getEnclosingProjects() {
+ public IProject[] getEnclosingProjects() {
if (isWorkspaceScope()) {
return getAllProjects();
}
- return (ICProject[]) fEnclosingProjectSet.toArray(new ICProject[fEnclosingProjectSet.size()]);
+ return (IProject[]) fEnclosingProjectSet.toArray(new IProject[fEnclosingProjectSet.size()]);
}
- private static boolean projectContainsPath(ICProject project, IPath path, boolean checkIncludePaths) {
- IPath projectPath = project.getProject().getFullPath();
+ private static boolean projectContainsPath(IProject project, IPath path, boolean checkIncludePaths) {
+ IPath projectPath = project.getFullPath();
if (projectPath.isPrefixOf(path)) {
// ISourceRoot[] sourceRoots = null;
// try {
@@ -204,10 +206,10 @@ public class TypeSearchScope implements ITypeSearchScope {
return false;
}
- private static IPath[] getIncludePaths(ICProject project) {
- IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project.getProject());
+ private static IPath[] getIncludePaths(IProject project) {
+ IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project);
if (provider != null) {
- IScannerInfo info = provider.getScannerInformation(project.getProject());
+ IScannerInfo info = provider.getScannerInformation(project);
if (info != null) {
String[] includes = info.getIncludePaths();
if (includes != null && includes.length > 0) {
@@ -223,22 +225,56 @@ public class TypeSearchScope implements ITypeSearchScope {
return null;
}
- private static ICProject[] getAllProjects() {
- ICProject[] projects = getCProjects();
+ private static IProject[] getAllProjects() {
+ IProject[] projects = getCProjects();
if (projects == null)
- projects = new ICProject[0];
+ projects = new IProject[0];
return projects;
}
- private static ICProject[] getCProjects() {
- try {
- return CoreModel.getDefault().getCModel().getCProjects();
- } catch (CModelException e) {
- CCorePlugin.log(e);
- return new ICProject[0];
+ private static IProject[] getCProjects() {
+ IProject[] allProjects = CCorePlugin.getWorkspace().getRoot().getProjects();
+ if (allProjects != null) {
+ IProject[] cProjects = new IProject[allProjects.length];
+ int count = 0;
+ for (int i = 0; i < allProjects.length; ++i) {
+ IProject project = allProjects[i];
+ if (isCProject(project)) {
+ cProjects[count++] = project;
+ }
+ }
+ if (count > 0) {
+ if (count == allProjects.length) {
+ return cProjects;
+ }
+ IProject[] newProjects = new IProject[count];
+ System.arraycopy(cProjects, 0, newProjects, 0, count);
+ return newProjects;
+ }
}
+ return null;
}
+ private static boolean isCProject(IProject project) {
+ IProjectDescription projDesc = null;
+ try {
+ projDesc = project.getDescription();
+ if (projDesc == null)
+ return false;
+ } catch (CoreException e) {
+ return false;
+ }
+ String[] natures = projDesc.getNatureIds();
+ if (natures != null) {
+ for (int i = 0; i < natures.length; ++i) {
+ if (natures[i].equals(CProjectNature.C_NATURE_ID)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public boolean isPathScope() {
return !fPathSet.isEmpty();
}
@@ -257,12 +293,16 @@ public class TypeSearchScope implements ITypeSearchScope {
public void add(IWorkingCopy workingCopy) {
IPath path = workingCopy.getOriginalElement().getPath();
+ IProject enclosingProject = null;
ICProject cProject = workingCopy.getCProject();
+ if (cProject != null)
+ enclosingProject = cProject.getProject();
fPathSet.add(path);
- addEnclosingProject(cProject);
+ if (enclosingProject != null)
+ addEnclosingProject(enclosingProject);
}
- public void add(IPath path, boolean addSubfolders, ICProject enclosingProject) {
+ public void add(IPath path, boolean addSubfolders, IProject enclosingProject) {
if (addSubfolders) {
fContainerSet.add(path);
fContainerPaths = null;
@@ -286,14 +326,14 @@ public class TypeSearchScope implements ITypeSearchScope {
}
}
- public void add(ICProject project) {
+ public void add(IProject project) {
fProjectSet.add(project);
fProjects = null;
fAllProjects = null;
addEnclosingProject(project);
}
- private void addEnclosingProject(ICProject project) {
+ private void addEnclosingProject(IProject project) {
fEnclosingProjectSet.add(project);
}
@@ -314,19 +354,25 @@ public class TypeSearchScope implements ITypeSearchScope {
}
case ICElement.C_PROJECT: {
- ICProject project = ((ICProject)elem);
+ IProject project = ((ICProject)elem).getProject();
add(project);
break;
}
case ICElement.C_CCONTAINER: {
- ICProject project = elem.getCProject();
+ IProject project = null;
+ ICProject cProject = elem.getCProject();
+ if (cProject != null)
+ project = cProject.getProject();
add(elem.getPath(), true, project);
break;
}
case ICElement.C_UNIT: {
- ICProject project = elem.getCProject();
+ IProject project = null;
+ ICProject cProject = elem.getCProject();
+ if (cProject != null)
+ project = cProject.getProject();
add(elem.getPath(), false, project);
break;
}
@@ -339,7 +385,10 @@ public class TypeSearchScope implements ITypeSearchScope {
case ICElement.C_UNION:
case ICElement.C_ENUMERATION:
case ICElement.C_TYPEDEF: {
- ICProject project = elem.getCProject();
+ IProject project = null;
+ ICProject cProject = elem.getCProject();
+ if (cProject != null)
+ project = cProject.getProject();
add(elem.getPath(), false, project);
break;
}
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
index 3c2e9ca898e..9c86849c845 100644
--- 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
@@ -13,6 +13,7 @@ package org.eclipse.cdt.core.browser;
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IMember;
@@ -20,6 +21,7 @@ import org.eclipse.cdt.core.model.IMethodDeclaration;
import org.eclipse.cdt.core.model.IParent;
import org.eclipse.cdt.core.model.IStructure;
import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
public class TypeUtil {
@@ -285,4 +287,33 @@ public class TypeUtil {
return findMethod(name, paramTypes, isConstructor, isDestructor, getMethods(type));
}
+ /**
+ * Finds a method declararion in a type's hierarchy. The search is top down, so this
+ * returns the first declaration of the method in the hierarchy.
+ * This searches for a method with a name and signature. Parameter types are only
+ * compared by the simple name, no resolving for the fully qualified type name is done.
+ * Constructors are only compared by parameters, not the name.
+ * @param type Searches in this type's supertypes.
+ * @param name The name of the method to find
+ * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
+ * @param isConstructor If the method is a constructor
+ * @return The first method found or null, if nothing found
+ */
+// TODO move methods to CModelUtil
+ public static IMethodDeclaration findMethodDeclarationInHierarchy(ITypeHierarchy hierarchy, ICElement type, String name, String[] paramTypes, boolean isConstructor, boolean isDestructor) throws CModelException {
+ ICElement[] superTypes= hierarchy.getAllSupertypes(type);
+ for (int i= superTypes.length - 1; i >= 0; i--) {
+ IMethodDeclaration first= findMethod(name, paramTypes, isConstructor, isDestructor, superTypes[i]);
+ if (first != null && first.getVisibility() != ASTAccessVisibility.PRIVATE) {
+ // the order getAllSupertypes does make assumptions of the order of inner elements -> search recursivly
+ IMethodDeclaration res= findMethodDeclarationInHierarchy(hierarchy, TypeUtil.getDeclaringClass(first), name, paramTypes, isConstructor, isDestructor);
+ if (res != null) {
+ return res;
+ }
+ return first;
+ }
+ }
+ return null;
+ }
+
}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/UnknownTypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/UnknownTypeInfo.java
index a36c390e6a4..c31921f596c 100644
--- 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
@@ -30,9 +30,11 @@ public class UnknownTypeInfo extends TypeInfo {
}
public boolean canSubstituteFor(ITypeInfo info) {
- int compareType = info.getCElementType();
- if (fElementType == 0 || compareType == 0 || fElementType == compareType) {
- return fQualifiedName.equals(info.getQualifiedTypeName());
+ if (fTypeCache == info.getCache()) {
+ 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/core/browser/typehierarchy/ChangeCollector.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java
new file mode 100644
index 00000000000..71f9fe0f775
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the 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
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.cdt.core.browser.TypeUtil;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.model.IMember;
+import org.eclipse.cdt.core.model.IParent;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.internal.core.model.CElement;
+
+/*
+ * Collects changes (reported through fine-grained deltas) that can affect a type hierarchy.
+ */
+public class ChangeCollector {
+
+ /*
+ * A table from ICElements to TypeDeltas
+ */
+ HashMap changes = new HashMap();
+
+ TypeHierarchy hierarchy;
+
+ public ChangeCollector(TypeHierarchy hierarchy) {
+ this.hierarchy = hierarchy;
+ }
+
+ /*
+ * Adds the children of the given delta to the list of changes.
+ */
+ private void addAffectedChildren(ICElementDelta delta) throws CModelException {
+// ICElementDelta[] children = delta.getAffectedChildren();
+// for (int i = 0, length = children.length; i < length; i++) {
+// ICElementDelta child = children[i];
+// ICElement childElement = child.getElement();
+// switch (childElement.getElementType()) {
+// case ICElement.IMPORT_CONTAINER:
+// addChange((IImportContainer)childElement, child);
+// break;
+// case ICElement.IMPORT_DECLARATION:
+// addChange((IImportDeclaration)childElement, child);
+// break;
+// case ICElement.TYPE:
+// addChange((ICElement)childElement, child);
+// break;
+// case ICElement.INITIALIZER:
+// case ICElement.FIELD:
+// case ICElement.METHOD:
+// addChange((IMember)childElement, child);
+// break;
+// }
+// }
+ }
+
+ /*
+ * Adds the given delta on a compilation unit to the list of changes.
+ */
+ public void addChange(ITranslationUnit cu, ICElementDelta newDelta) throws CModelException {
+// int newKind = newDelta.getKind();
+// switch (newKind) {
+// case ICElementDelta.ADDED:
+// ArrayList allTypes = new ArrayList();
+// getAllTypesFromElement(cu, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement type = (ICElement)allTypes.get(i);
+// addTypeAddition(type, (SimpleDelta)this.changes.get(type));
+// }
+// break;
+// case ICElementDelta.REMOVED:
+// allTypes = new ArrayList();
+// getAllTypesFromHierarchy((JavaElement)cu, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement type = (ICElement)allTypes.get(i);
+// addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
+// }
+// break;
+// case ICElementDelta.CHANGED:
+// addAffectedChildren(newDelta);
+// break;
+// }
+ }
+
+/* private void addChange(IImportContainer importContainer, ICElementDelta newDelta) throws CModelException {
+ int newKind = newDelta.getKind();
+ if (newKind == ICElementDelta.CHANGED) {
+ addAffectedChildren(newDelta);
+ return;
+ }
+ SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importContainer);
+ if (existingDelta != null) {
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ if (existingDelta.getKind() == ICElementDelta.REMOVED) {
+ // REMOVED then ADDED
+ this.changes.remove(importContainer);
+ }
+ break;
+ case ICElementDelta.REMOVED:
+ if (existingDelta.getKind() == ICElementDelta.ADDED) {
+ // ADDED then REMOVED
+ this.changes.remove(importContainer);
+ }
+ break;
+ // CHANGED handled above
+ }
+ } else {
+ SimpleDelta delta = new SimpleDelta();
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ delta.added();
+ break;
+ case ICElementDelta.REMOVED:
+ delta.removed();
+ break;
+ }
+ this.changes.put(importContainer, delta);
+ }
+ }
+
+ private void addChange(IImportDeclaration importDecl, ICElementDelta newDelta) {
+ SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importDecl);
+ int newKind = newDelta.getKind();
+ if (existingDelta != null) {
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ if (existingDelta.getKind() == ICElementDelta.REMOVED) {
+ // REMOVED then ADDED
+ this.changes.remove(importDecl);
+ }
+ break;
+ case ICElementDelta.REMOVED:
+ if (existingDelta.getKind() == ICElementDelta.ADDED) {
+ // ADDED then REMOVED
+ this.changes.remove(importDecl);
+ }
+ break;
+ // CHANGED cannot happen for import declaration
+ }
+ } else {
+ SimpleDelta delta = new SimpleDelta();
+ switch (newKind) {
+ case ICElementDelta.ADDED:
+ delta.added();
+ break;
+ case ICElementDelta.REMOVED:
+ delta.removed();
+ break;
+ }
+ this.changes.put(importDecl, delta);
+ }
+ }
+*/
+
+ /*
+ * Adds a change for the given member (a method, a field or an initializer) and the types it defines.
+ */
+ private void addChange(IMember member, ICElementDelta newDelta) throws CModelException {
+// int newKind = newDelta.getKind();
+// switch (newKind) {
+// case ICElementDelta.ADDED:
+// ArrayList allTypes = new ArrayList();
+// getAllTypesFromElement(member, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement innerType = (ICElement)allTypes.get(i);
+// addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
+// }
+// break;
+// case ICElementDelta.REMOVED:
+// allTypes = new ArrayList();
+// getAllTypesFromHierarchy((JavaElement)member, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement type = (ICElement)allTypes.get(i);
+// addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
+// }
+// break;
+// case ICElementDelta.CHANGED:
+// addAffectedChildren(newDelta);
+// break;
+// }
+ }
+
+ /*
+ * Adds a change for the given type and the types it defines.
+ */
+ private void addChange(ICElement type, ICElementDelta newDelta) throws CModelException {
+// int newKind = newDelta.getKind();
+// SimpleDelta existingDelta = (SimpleDelta)this.changes.get(type);
+// switch (newKind) {
+// case ICElementDelta.ADDED:
+// addTypeAddition(type, existingDelta);
+// ArrayList allTypes = new ArrayList();
+// getAllTypesFromElement(type, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement innerType = (ICElement)allTypes.get(i);
+// addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
+// }
+// break;
+// case ICElementDelta.REMOVED:
+// addTypeRemoval(type, existingDelta);
+// allTypes = new ArrayList();
+// getAllTypesFromHierarchy((JavaElement)type, allTypes);
+// for (int i = 0, length = allTypes.size(); i < length; i++) {
+// ICElement innerType = (ICElement)allTypes.get(i);
+// addTypeRemoval(innerType, (SimpleDelta)this.changes.get(innerType));
+// }
+// break;
+// case ICElementDelta.CHANGED:
+// addTypeChange(type, newDelta.getFlags(), existingDelta);
+// addAffectedChildren(newDelta);
+// break;
+// }
+ }
+
+/* private void addTypeAddition(ICElement type, SimpleDelta existingDelta) throws CModelException {
+ if (existingDelta != null) {
+ switch (existingDelta.getKind()) {
+ case ICElementDelta.REMOVED:
+ // REMOVED then ADDED
+ boolean hasChange = false;
+ if (hasSuperTypeChange(type)) {
+ existingDelta.superTypes();
+ hasChange = true;
+ }
+ if (hasVisibilityChange(type)) {
+ existingDelta.modifiers();
+ hasChange = true;
+ }
+ if (!hasChange) {
+ this.changes.remove(type);
+ }
+ break;
+ // CHANGED then ADDED
+ // or ADDED then ADDED: should not happen
+ }
+ } else {
+ // check whether the type addition affects the hierarchy
+ String typeName = type.getElementName();
+ if (this.hierarchy.hasSupertype(typeName)
+ || this.hierarchy.subtypesIncludeSupertypeOf(type)
+ || this.hierarchy.missingTypes.contains(typeName)) {
+ SimpleDelta delta = new SimpleDelta();
+ delta.added();
+ this.changes.put(type, delta);
+ }
+ }
+ }
+*/
+/* private void addTypeChange(ICElement type, int newFlags, SimpleDelta existingDelta) throws CModelException {
+ if (existingDelta != null) {
+ switch (existingDelta.getKind()) {
+ case ICElementDelta.CHANGED:
+ // CHANGED then CHANGED
+ int existingFlags = existingDelta.getFlags();
+ boolean hasChange = false;
+ if ((existingFlags & ICElementDelta.F_SUPER_TYPES) != 0
+ && hasSuperTypeChange(type)) {
+ existingDelta.superTypes();
+ hasChange = true;
+ }
+ if ((existingFlags & ICElementDelta.F_MODIFIERS) != 0
+ && hasVisibilityChange(type)) {
+ existingDelta.modifiers();
+ hasChange = true;
+ }
+ if (!hasChange) {
+ // super types and visibility are back to the ones in the existing hierarchy
+ this.changes.remove(type);
+ }
+ break;
+ // ADDED then CHANGED: leave it as ADDED
+ // REMOVED then CHANGED: should not happen
+ }
+ } else {
+ // check whether the type change affects the hierarchy
+ SimpleDelta typeDelta = null;
+ if ((newFlags & ICElementDelta.F_SUPER_TYPES) != 0
+ && this.hierarchy.includesTypeOrSupertype(type)) {
+ typeDelta = new SimpleDelta();
+ typeDelta.superTypes();
+ }
+ if ((newFlags & ICElementDelta.F_MODIFIERS) != 0
+ && this.hierarchy.hasSupertype(type.getElementName())) {
+ if (typeDelta == null) {
+ typeDelta = new SimpleDelta();
+ }
+ typeDelta.modifiers();
+ }
+ if (typeDelta != null) {
+ this.changes.put(type, typeDelta);
+ }
+ }
+ }
+*/
+/* private void addTypeRemoval(ICElement type, SimpleDelta existingDelta) {
+ if (existingDelta != null) {
+ switch (existingDelta.getKind()) {
+ case ICElementDelta.ADDED:
+ // ADDED then REMOVED
+ this.changes.remove(type);
+ break;
+ case ICElementDelta.CHANGED:
+ // CHANGED then REMOVED
+ existingDelta.removed();
+ break;
+ // REMOVED then REMOVED: should not happen
+ }
+ } else {
+ // check whether the type removal affects the hierarchy
+ if (this.hierarchy.contains(type)) {
+ SimpleDelta typeDelta = new SimpleDelta();
+ typeDelta.removed();
+ this.changes.put(type, typeDelta);
+ }
+ }
+ }
+*/
+ /*
+ * Returns all types defined in the given element excluding the given element.
+ */
+ private void getAllTypesFromElement(ICElement element, ArrayList allTypes) throws CModelException {
+ switch (element.getElementType()) {
+ case ICElement.C_UNIT:
+ ICElement[] types = TypeUtil.getTypes((ITranslationUnit)element);
+ for (int i = 0, length = types.length; i < length; i++) {
+ ICElement type = types[i];
+ allTypes.add(type);
+ getAllTypesFromElement(type, allTypes);
+ }
+ break;
+ case ICElement.C_CLASS:
+ case ICElement.C_STRUCT:
+// types = ((ICElement)element).getTypes();
+ types = TypeUtil.getTypes(element);
+ for (int i = 0, length = types.length; i < length; i++) {
+ ICElement type = types[i];
+ allTypes.add(type);
+ getAllTypesFromElement(type, allTypes);
+ }
+ break;
+// case ICElement.INITIALIZER:
+// case ICElement.FIELD:
+ case ICElement.C_METHOD:
+ if (element instanceof IParent) {
+ ICElement[] children = ((IParent)element).getChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ ICElement type = (ICElement)children[i];
+ allTypes.add(type);
+ getAllTypesFromElement(type, allTypes);
+ }
+ }
+ break;
+ }
+ }
+
+ /*
+ * Returns all types in the existing hierarchy that have the given element as a parent.
+ */
+ private void getAllTypesFromHierarchy(CElement element, ArrayList allTypes) {
+ switch (element.getElementType()) {
+ case ICElement.C_UNIT:
+ ArrayList types = (ArrayList)this.hierarchy.files.get(element);
+ if (types != null) {
+ allTypes.addAll(types);
+ }
+ break;
+ case ICElement.C_CLASS:
+ case ICElement.C_STRUCT:
+// case ICElement.INITIALIZER:
+// case ICElement.FIELD:
+ case ICElement.C_METHOD:
+ types = (ArrayList)this.hierarchy.files.get(((IMember)element).getTranslationUnit());
+ if (types != null) {
+ for (int i = 0, length = types.size(); i < length; i++) {
+ ICElement type = (ICElement)types.get(i);
+ if (element.isAncestorOf(type)) {
+ allTypes.add(type);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ private boolean hasSuperTypeChange(ICElement type) throws CModelException {
+// // check super class
+// ICElement superclass = this.hierarchy.getSuperclass(type);
+// String existingSuperclassName = superclass == null ? null : superclass.getElementName();
+// String newSuperclassName = type.getSuperclassName();
+// if (existingSuperclassName != null && !existingSuperclassName.equals(newSuperclassName)) {
+// return true;
+// }
+//
+// // check super interfaces
+// ICElement[] existingSuperInterfaces = this.hierarchy.getSuperInterfaces(type);
+// String[] newSuperInterfaces = type.getSuperInterfaceNames();
+// if (existingSuperInterfaces.length != newSuperInterfaces.length) {
+// return true;
+// }
+// for (int i = 0, length = newSuperInterfaces.length; i < length; i++) {
+// String superInterfaceName = newSuperInterfaces[i];
+// if (!superInterfaceName.equals(newSuperInterfaces[i])) {
+// return true;
+// }
+// }
+
+ return false;
+ }
+
+ private boolean hasVisibilityChange(ICElement type) throws CModelException {
+// int existingFlags = this.hierarchy.getCachedFlags(type);
+// int newFlags = type.getFlags();
+// return existingFlags != newFlags;
+ return false;
+ }
+
+ /*
+ * Whether the hierarchy needs refresh according to the changes collected so far.
+ */
+ public boolean needsRefresh() {
+ return changes.size() != 0;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ Iterator iterator = this.changes.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Map.Entry)iterator.next();
+ buffer.append(((CElement)entry.getKey()).toDebugString());
+ buffer.append(entry.getValue());
+ if (iterator.hasNext()) {
+ buffer.append('\n');
+ }
+ }
+ return buffer.toString();
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java
new file mode 100644
index 00000000000..befed906b67
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the 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
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.io.OutputStream;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A type hierarchy provides navigations between a type and its resolved
+ * supertypes and subtypes for a specific type or for all types within a region.
+ * Supertypes may extend outside of the type hierarchy's region in which it was
+ * created such that the root of the hierarchy is always included. For example, if a type
+ * hierarchy is created for a <code>java.io.File</code>, and the region the hierarchy was
+ * created in is the package fragment <code>java.io</code>, the supertype
+ * <code>java.lang.Object</code> will still be included.
+ * <p>
+ * A type hierarchy is static and can become stale. Although consistent when
+ * created, it does not automatically track changes in the model.
+ * As changes in the model potentially invalidate the hierarchy, change notifications
+ * are sent to registered <code>ICElementHierarchyChangedListener</code>s. Listeners should
+ * use the <code>exists</code> method to determine if the hierarchy has become completely
+ * invalid (for example, when the type or project the hierarchy was created on
+ * has been removed). To refresh a hierarchy, use the <code>refresh</code> method.
+ * </p>
+ * <p>
+ * The type hierarchy may contain cycles due to malformed supertype declarations.
+ * Most type hierarchy queries are oblivious to cycles; the <code>getAll* </code>
+ * methods are implemented such that they are unaffected by cycles.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface ITypeHierarchy {
+/**
+ * Adds the given listener for changes to this type hierarchy. Listeners are
+ * notified when this type hierarchy changes and needs to be refreshed.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener
+ */
+void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
+/**
+ * Returns whether the given type is part of this hierarchy.
+ *
+ * @param type the given type
+ * @return true if the given type is part of this hierarchy, false otherwise
+ */
+boolean contains(ICElement type);
+/**
+ * Returns whether the type and project this hierarchy was created on exist.
+ * @return true if the type and project this hierarchy was created on exist, false otherwise
+ */
+boolean exists();
+
+/**
+ * Returns all resolved subtypes (direct and indirect) of the
+ * given type, in no particular order, limited to the
+ * types in this type hierarchy's graph. An empty array
+ * is returned if there are no resolved subtypes for the
+ * given type.
+ *
+ * @param type the given type
+ * @return all resolved subtypes (direct and indirect) of the given type
+ */
+ICElement[] getAllSubtypes(ICElement type);
+/**
+ * Returns all resolved superclasses of the
+ * given class, in bottom-up order. An empty array
+ * is returned if there are no resolved superclasses for the
+ * given class.
+ *
+ * <p>NOTE: once a type hierarchy has been created, it is more efficient to
+ * query the hierarchy for superclasses than to query a class recursively up
+ * the superclass chain. Querying an element performs a dynamic resolution,
+ * whereas the hierarchy returns a pre-computed result.
+ *
+ * @param type the given type
+ * @return all resolved superclasses of the given class, in bottom-up order, an empty
+ * array if none.
+ */
+ICElement[] getAllSupertypes(ICElement type);
+
+/**
+ * Returns all classes in the graph which have no resolved superclass,
+ * in no particular order.
+ *
+ * @return all classes in the graph which have no resolved superclass
+ */
+ICElement[] getRootClasses();
+
+/**
+ * Returns the direct resolved subtypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * If the type is a class, this returns the resolved subclasses.
+ * If the type is an interface, this returns both the classes which implement
+ * the interface and the interfaces which extend it.
+ *
+ * @param type the given type
+ * @return the direct resolved subtypes of the given type limited to the types in this
+ * type hierarchy's graph
+ */
+ICElement[] getSubtypes(ICElement type);
+
+/**
+ * Returns the resolved supertypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * For classes, this returns its superclass and the interfaces that the class implements.
+ * For interfaces, this returns the interfaces that the interface extends. As a consequence
+ * <code>java.lang.Object</code> is NOT considered to be a supertype of any interface
+ * type.
+ *
+ * @param type the given type
+ * @return the resolved supertypes of the given type limited to the types in this
+ * type hierarchy's graph
+ */
+ICElement[] getSupertypes(ICElement type);
+/**
+ * Returns the type this hierarchy was computed for.
+ * Returns <code>null</code> if this hierarchy was computed for a region.
+ *
+ * @return the type this hierarchy was computed for
+ */
+ICElement getType();
+/**
+ * Re-computes the type hierarchy reporting progress.
+ *
+ * @param monitor the given progress monitor
+ * @exception JavaModelException if unable to refresh the hierarchy
+ */
+void refresh(IProgressMonitor monitor) throws CModelException;
+/**
+ * Removes the given listener from this type hierarchy.
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ */
+void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
+/**
+ * Stores the type hierarchy in an output stream. This stored hierarchy can be load by
+ * ICElement#loadTypeHierachy(IJavaProject, InputStream, IProgressMonitor).
+ * Listeners of this hierarchy are not stored.
+ *
+ * Only hierarchies created by the following methods can be store:
+ * <ul>
+ * <li>ICElement#newSupertypeHierarchy(IProgressMonitor)</li>
+ * <li>ICElement#newTypeHierarchy(IJavaProject, IProgressMonitor)</li>
+ * <li>ICElement#newTypeHierarchy(IProgressMonitor)</li>
+ * </u>
+ *
+ * @param outputStream output stream where the hierarchy will be stored
+ * @param monitor the given progress monitor
+ * @exception JavaModelException if unable to store the hierarchy in the ouput stream
+ * @see ICElement#loadTypeHierachy(java.io.InputStream, IProgressMonitor)
+ * @since 2.1
+ */
+void store(OutputStream outputStream, IProgressMonitor monitor) throws CModelException;
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java
new file mode 100644
index 00000000000..cc985600ab8
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+/**
+ * A listener which gets notified when a particular type hierarchy object
+ * changes.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface ITypeHierarchyChangedListener {
+ /**
+ * Notifies that the given type hierarchy has changed in some way and should
+ * be refreshed at some point to make it consistent with the current state of
+ * the Java model.
+ *
+ * @param typeHierarchy the given type hierarchy
+ */
+ void typeHierarchyChanged(ITypeHierarchy typeHierarchy);
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java
new file mode 100644
index 00000000000..5288ff7e649
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java
@@ -0,0 +1,582 @@
+/*******************************************************************************
+ * 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.typehierarchy;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.ICLogConstants;
+import org.eclipse.cdt.core.browser.AllTypesCache;
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ElementChangedEvent;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.IElementChangedListener;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.core.search.ICSearchScope;
+import org.eclipse.cdt.internal.core.model.Util;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+
+public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener {
+
+ public static boolean DEBUG = false;
+
+ private static final class TypeEntry {
+ ITypeInfo type;
+ ASTAccessVisibility access;
+ TypeEntry(ITypeInfo type, ASTAccessVisibility access) {
+ this.type = type;
+ this.access = access;
+ }
+ }
+ private static final int INITIAL_SUPER_TYPES = 1;
+ private static final int INITIAL_SUB_TYPES = 1;
+ private static final ITypeInfo[] NO_TYPES = new ITypeInfo[0];
+ private ArrayList fRootTypes = new ArrayList();
+ private Map fTypeToSuperTypes = new HashMap();
+ private Map fTypeToSubTypes = new HashMap();
+
+ private ITypeInfo fFocusType;
+
+ /**
+ * The progress monitor to report work completed too.
+ */
+ protected IProgressMonitor fProgressMonitor = null;
+ /**
+ * Change listeners - null if no one is listening.
+ */
+ protected ArrayList fChangeListeners = null;
+
+ /*
+ * A map from Openables to ArrayLists of ITypes
+ */
+ public Map files = null;
+
+ /**
+ * Whether this hierarchy should contains subtypes.
+ */
+ protected boolean fComputeSubtypes;
+
+ /**
+ * The scope this hierarchy should restrain itsef in.
+ */
+ ICSearchScope fScope;
+
+ /*
+ * Whether this hierarchy needs refresh
+ */
+ public boolean fNeedsRefresh = true;
+// /*
+// * Collects changes to types
+// */
+// protected ChangeCollector fChangeCollector;
+
+
+
+ /**
+ * Creates a TypeHierarchy on the given type.
+ */
+ public TypeHierarchy(ITypeInfo type) {
+ fFocusType = type;
+ }
+
+ /**
+ * Adds the type to the collection of root classes
+ * if the classes is not already present in the collection.
+ */
+ public void addRootType(ITypeInfo type) {
+ if (!fRootTypes.contains(type)) {
+ fRootTypes.add(type);
+ }
+ }
+
+ /**
+ * Adds the given supertype to the type.
+ */
+ public void addSuperType(ITypeInfo type, ITypeInfo superType, ASTAccessVisibility access) {
+ Collection superEntries = (Collection) fTypeToSuperTypes.get(type);
+ if (superEntries == null) {
+ superEntries = new ArrayList(INITIAL_SUPER_TYPES);
+ fTypeToSuperTypes.put(type, superEntries);
+ }
+ Collection subTypes = (Collection) fTypeToSubTypes.get(superType);
+ if (subTypes == null) {
+ subTypes = new ArrayList(INITIAL_SUB_TYPES);
+ fTypeToSubTypes.put(superType, subTypes);
+ }
+ if (!subTypes.contains(type)) {
+ subTypes.add(type);
+ }
+ for (Iterator i = superEntries.iterator(); i.hasNext(); ) {
+ TypeEntry entry = (TypeEntry)i.next();
+ if (entry.type.equals(superType)) {
+ // update the access
+ entry.access = access;
+ return; // don't add if already exists
+ }
+ }
+ TypeEntry typeEntry = new TypeEntry(superType, access);
+ superEntries.add(typeEntry);
+ }
+
+ /**
+ * Adds the given subtype to the type.
+ */
+ protected void addSubType(ITypeInfo type, ITypeInfo subType) {
+ Collection subTypes = (Collection) fTypeToSubTypes.get(type);
+ if (subTypes == null) {
+ subTypes = new ArrayList(INITIAL_SUB_TYPES);
+ fTypeToSubTypes.put(type, subTypes);
+ }
+ if (!subTypes.contains(subType)) {
+ subTypes.add(subType);
+ }
+
+ Collection superEntries = (Collection) fTypeToSuperTypes.get(subType);
+ if (superEntries == null) {
+ superEntries = new ArrayList(INITIAL_SUPER_TYPES);
+ fTypeToSuperTypes.put(subType, superEntries);
+ }
+ for (Iterator i = superEntries.iterator(); i.hasNext(); ) {
+ TypeEntry entry = (TypeEntry)i.next();
+ if (entry.type.equals(type))
+ return; // don't add if already exists
+ }
+ // default to private access
+ TypeEntry typeEntry = new TypeEntry(type, ASTAccessVisibility.PRIVATE);
+ superEntries.add(typeEntry);
+ }
+
+ /**
+ * Returns true if type already has the given supertype.
+ */
+ public boolean hasSuperType(ITypeInfo type, ITypeInfo superType) {
+ Collection entries = (Collection) fTypeToSuperTypes.get(type);
+ if (entries != null) {
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ TypeEntry entry = (TypeEntry)i.next();
+ if (entry.type.equals(superType))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an array of supertypes for the given type - will never return null.
+ */
+ public ITypeInfo[] getSuperTypes(ITypeInfo type) {
+ Collection entries = (Collection) fTypeToSuperTypes.get(type);
+ if (entries != null) {
+ ArrayList superTypes = new ArrayList(INITIAL_SUPER_TYPES);
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ TypeEntry entry = (TypeEntry)i.next();
+ superTypes.add(entry.type);
+ }
+ return (ITypeInfo[])superTypes.toArray(new ITypeInfo[superTypes.size()]);
+ }
+ return NO_TYPES;
+ }
+
+ /**
+ * Returns an array of subtypes for the given type - will never return null.
+ */
+ public ITypeInfo[] getSubTypes(ITypeInfo type) {
+ Collection subTypes = (Collection) fTypeToSubTypes.get(type);
+ if (subTypes != null) {
+ return (ITypeInfo[])subTypes.toArray(new ITypeInfo[subTypes.size()]);
+ }
+ return NO_TYPES;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#addTypeHierarchyChangedListener(org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchyChangedListener)
+ */
+ public void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
+ ArrayList listeners = fChangeListeners;
+ if (listeners == null) {
+ fChangeListeners = listeners = new ArrayList();
+ }
+
+ // register with JavaCore to get Java element delta on first listener added
+ if (listeners.size() == 0) {
+ CoreModel.getDefault().addElementChangedListener(this);
+ }
+
+ // add listener only if it is not already present
+ if (listeners.indexOf(listener) == -1) {
+ listeners.add(listener);
+ }
+ }
+
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public synchronized void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
+ ArrayList listeners = fChangeListeners;
+ if (listeners == null) {
+ return;
+ }
+ listeners.remove(listener);
+
+ // deregister from JavaCore on last listener removed
+ if (listeners.isEmpty()) {
+ CoreModel.getDefault().removeElementChangedListener(this);
+ }
+ }
+
+ /**
+ * Determines if the change effects this hierarchy, and fires
+ * change notification if required.
+ */
+ public void elementChanged(ElementChangedEvent event) {
+ // type hierarchy change has already been fired
+ if (fNeedsRefresh) return;
+
+ if (isAffected(event.getDelta())) {
+ fNeedsRefresh = true;
+ fireChange();
+ }
+ }
+
+ /**
+ * Returns true if the given delta could change this type hierarchy
+ */
+ public synchronized boolean isAffected(ICElementDelta delta) {
+// ICElement element= delta.getElement();
+// switch (element.getElementType()) {
+// case ICElement.C_MODEL:
+// return isAffectedByCModel(delta, element);
+// case ICElement.C_PROJECT:
+// return isAffectedByCProject(delta, element);
+// case ICElement.C_UNIT:
+// return isAffectedByOpenable(delta, element);
+// }
+// return false;
+ return true;
+ }
+
+ /**
+ * Notifies listeners that this hierarchy has changed and needs
+ * refreshing. Note that listeners can be removed as we iterate
+ * through the list.
+ */
+ public void fireChange() {
+ ArrayList listeners = fChangeListeners;
+ if (listeners == null) {
+ return;
+ }
+ if (DEBUG) {
+ System.out.println("FIRING hierarchy change ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (fFocusType != null) {
+ System.out.println(" for hierarchy focused on " + fFocusType.toString()); //$NON-NLS-1$
+ }
+ }
+ // clone so that a listener cannot have a side-effect on this list when being notified
+ listeners = (ArrayList)listeners.clone();
+ for (int i= 0; i < listeners.size(); i++) {
+ final ITypeHierarchyChangedListener listener= (ITypeHierarchyChangedListener)listeners.get(i);
+ Platform.run(new ISafeRunnable() {
+ public void handleException(Throwable exception) {
+ Util.log(exception, "Exception occurred in listener of Type hierarchy change notification", ICLogConstants.CDT); //$NON-NLS-1$
+ }
+ public void run() throws Exception {
+ listener.typeHierarchyChanged(TypeHierarchy.this);
+ }
+ });
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#contains(org.eclipse.cdt.core.model.ICElement)
+ */
+ public boolean contains(ICElement type) {
+ // classes
+ ITypeInfo info = AllTypesCache.getTypeForElement(type, true, true, null);
+
+ if (info == null)
+ return false;
+
+ if (fTypeToSuperTypes.get(info) != null) {
+ return true;
+ }
+
+ // root classes
+ if (fRootTypes.contains(type)) return true;
+
+ return false;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public boolean exists() {
+ if (!fNeedsRefresh) return true;
+
+ return (fFocusType == null || fFocusType.exists()) && cProject().exists();
+ }
+
+ /**
+ * Returns the C project this hierarchy was created in.
+ */
+ public ICProject cProject() {
+ IProject project = fFocusType.getCache().getProject();
+ return findCProject(project);
+ }
+ private ICProject findCProject(IProject project) {
+ try {
+ ICProject[] cProjects = CoreModel.getDefault().getCModel().getCProjects();
+ if (cProjects != null) {
+ for (int i = 0; i < cProjects.length; ++i) {
+ ICProject cProject = cProjects[i];
+ if (project.equals(cProjects[i].getProject()))
+ return cProject;
+ }
+ }
+ } catch (CModelException e) {
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllClasses()
+ */
+ public ICElement[] getAllClasses() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getRootClasses()
+ */
+ public ICElement[] getRootClasses() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSubtypes(org.eclipse.cdt.core.model.ICElement)
+ */
+ public ICElement[] getSubtypes(ICElement type) {
+ List list = new ArrayList();
+ ITypeInfo info = AllTypesCache.getTypeForElement(type, true, true, null);
+ Collection entries = (Collection) fTypeToSubTypes.get(info);
+ if (entries != null) {
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ ITypeInfo subType = (ITypeInfo)i.next();
+ ICElement elem = AllTypesCache.getElementForType(subType, true, true, null);
+ if (elem != null) {
+ list.add(elem);
+ }
+ }
+ }
+ return (ICElement[])list.toArray(new ICElement[list.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement)
+ */
+ public ICElement[] getAllSubtypes(ICElement type) {
+ List list = new ArrayList();
+ ITypeInfo info = AllTypesCache.getTypeForElement(type, true, true, null);
+ addSubs(info, list);
+ //convert list to ICElements
+ ICElement[] elems = new ICElement[list.size()];
+ int count = 0;
+ for (Iterator i = list.iterator(); i.hasNext(); ) {
+ ITypeInfo subType = (ITypeInfo) i.next();
+ elems[count++] = AllTypesCache.getElementForType(subType, true, true, null);
+ }
+ return elems;
+ }
+
+ private void addSubs(ITypeInfo type, List list) {
+ Collection entries = (Collection) fTypeToSubTypes.get(type);
+ if (entries != null) {
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ ITypeInfo subType = (ITypeInfo)i.next();
+ if (!list.contains(subType)) {
+ list.add(subType);
+ }
+ addSubs(subType, list);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSupertypes(org.eclipse.cdt.core.model.ICElement)
+ */
+ public ICElement[] getSupertypes(ICElement type) {
+ List list = new ArrayList();
+ ITypeInfo info = AllTypesCache.getTypeForElement(type, true, true, null);
+ Collection entries = (Collection) fTypeToSuperTypes.get(info);
+ if (entries != null) {
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ TypeEntry entry = (TypeEntry)i.next();
+ ITypeInfo superType = entry.type;
+ ICElement elem = AllTypesCache.getElementForType(superType, true, true, null);
+ if (elem != null) {
+ list.add(elem);
+ }
+ }
+ }
+ return (ICElement[])list.toArray(new ICElement[list.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement)
+ */
+ public ICElement[] getAllSupertypes(ICElement type) {
+ List list = new ArrayList();
+ ITypeInfo info = AllTypesCache.getTypeForElement(type, true, true, null);
+ addSupers(info, list);
+ //convert list to ICElements
+ ICElement[] elems = new ICElement[list.size()];
+ int count = 0;
+ for (Iterator i = list.iterator(); i.hasNext(); ) {
+ ITypeInfo superType = (ITypeInfo) i.next();
+ elems[count++] = AllTypesCache.getElementForType(superType, true, true, null);
+ }
+ return elems;
+ }
+
+ private void addSupers(ITypeInfo type, List list) {
+ Collection entries = (Collection) fTypeToSuperTypes.get(type);
+ if (entries != null) {
+ for (Iterator i = entries.iterator(); i.hasNext(); ) {
+ TypeEntry entry = (TypeEntry)i.next();
+ ITypeInfo superType = entry.type;
+ if (!list.contains(superType)) {
+ list.add(superType);
+ }
+ addSupers(superType, list);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getType()
+ */
+ public ICElement getType() {
+ if (fFocusType != null)
+ return AllTypesCache.getElementForType(fFocusType, true, true, null);
+ return null;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ * TODO (jerome) should use a PerThreadObject to build the hierarchy instead of synchronizing
+ * (see also isAffected(IJavaElementDelta))
+ */
+ public synchronized void refresh(IProgressMonitor monitor) throws CModelException {
+ try {
+ fProgressMonitor = monitor;
+ if (monitor != null) {
+ if (fFocusType != null) {
+ monitor.beginTask(TypeHierarchyMessages.getFormattedString("hierarchy.creatingOnType", fFocusType.getQualifiedTypeName().getFullyQualifiedName()), 100); //$NON-NLS-1$
+ } else {
+ monitor.beginTask(TypeHierarchyMessages.getString("hierarchy.creating"), 100); //$NON-NLS-1$
+ }
+ }
+ long start = -1;
+ if (DEBUG) {
+ start = System.currentTimeMillis();
+ if (fComputeSubtypes) {
+ System.out.println("CREATING TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ System.out.println("CREATING SUPER TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (fFocusType != null) {
+ System.out.println(" on type " + fFocusType.toString()); //$NON-NLS-1$
+ }
+ }
+
+ compute();
+// initializeRegions();
+ fNeedsRefresh = false;
+// fChangeCollector = null;
+
+ if (DEBUG) {
+ if (fComputeSubtypes) {
+ System.out.println("CREATED TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ System.out.println("CREATED SUPER TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ System.out.println(this.toString());
+ }
+ } finally {
+ if (monitor != null) {
+ monitor.done();
+ }
+ fProgressMonitor = null;
+ }
+ }
+
+ /**
+ * Compute this type hierarchy.
+ */
+ protected void compute() {
+ if (fFocusType != null) {
+// HierarchyBuilder builder =
+// new IndexBasedHierarchyBuilder(
+// this,
+// this.scope);
+// builder.build(this.computeSubtypes);
+
+// initialize(1);
+// buildSupertypes();
+
+ } // else a RegionBasedTypeHierarchy should be used
+ }
+
+ /**
+ * Initializes this hierarchy's internal tables with the given size.
+ */
+ /* protected void initialize(int size) {
+ if (size < 10) {
+ size = 10;
+ }
+ int smallSize = (size / 2);
+ this.classToSuperclass = new HashMap(size);
+ this.interfaces = new ArrayList(smallSize);
+ this.missingTypes = new ArrayList(smallSize);
+ this.rootClasses = new TypeVector();
+ this.typeToSubtypes = new HashMap(smallSize);
+ this.typeToSuperInterfaces = new HashMap(smallSize);
+ this.typeFlags = new HashMap(smallSize);
+
+ this.projectRegion = new Region();
+ this.packageRegion = new Region();
+ this.files = new HashMap(5);
+ }
+*/
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#store(java.io.OutputStream, org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void store(OutputStream outputStream, IProgressMonitor monitor) throws CModelException {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java
new file mode 100644
index 00000000000..cded12e9745
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the 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.typehierarchy;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICModelStatusConstants;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
+import org.eclipse.cdt.internal.core.model.CModelStatus;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+public class TypeHierarchyBuilder {
+
+ public TypeHierarchyBuilder() {
+ }
+
+ public ITypeHierarchy createTypeHierarchy(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+ TypeHierarchy typeHierarchy = new TypeHierarchy(info);
+ Set processedTypes = new HashSet();
+ addSuperClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor);
+
+ typeHierarchy.addRootType(info);
+ processedTypes.clear();
+ addSubClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor);
+
+ return typeHierarchy;
+ }
+
+ private void addSuperClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+ if (type.hasSuperTypes()) {
+ ITypeInfo[] superTypes = TypeCacheManager.getInstance().locateSuperTypesAndWait(type, enableIndexing, Job.SHORT, monitor);
+ if (superTypes == null)
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+
+ for (int i = 0; i < superTypes.length; ++i) {
+ ITypeInfo superType = superTypes[i];
+
+ // recursively process sub sub classes
+ if (!processedTypes.contains(superType)) {
+ processedTypes.add(superType);
+ addSuperClasses(typeHierarchy, superType, processedTypes, enableIndexing, monitor);
+ }
+
+ ASTAccessVisibility access = type.getSuperTypeAccess(superType);
+
+ typeHierarchy.addSuperType(type, superType, access);
+ }
+ } else {
+ typeHierarchy.addRootType(type);
+ }
+ }
+
+ private void addSubClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+ if (type.hasSubTypes()) {
+ ITypeInfo[] subTypes = TypeCacheManager.getInstance().locateSubTypesAndWait(type, enableIndexing, Job.SHORT, monitor);
+ if (subTypes == null)
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+
+ for (int i = 0; i < subTypes.length; ++i) {
+ ITypeInfo subType = subTypes[i];
+
+ // recursively process sub sub classes
+ if (!processedTypes.contains(subType)) {
+ processedTypes.add(subType);
+ addSubClasses(typeHierarchy, subType, processedTypes, enableIndexing, monitor);
+ }
+
+ typeHierarchy.addSubType(type, subType);
+ }
+ }
+ }
+
+/*
+ private IStructure findCElementForType(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+ if (!info.exists())
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+
+ if (!info.isClass())
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES));
+
+ // first we need to resolve the type location
+ ITypeReference location = TypeCacheManager.getInstance().locateTypeAndWait(info, enableIndexing, Job.SHORT, monitor);
+ if (location == null)
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+
+ ICElement cElem = location.getCElement();
+ if (cElem == null)
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+
+ if (!(cElem instanceof IStructure))
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES));
+
+ IStructure cClass = (IStructure)cElem;
+
+ // check if type exists in cache
+ ITypeInfo type = TypeCacheManager.getInstance().getTypeForElement(cElem);
+ if (type == null || !type.equals(info))
+ throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+
+ return cClass;
+ }
+
+ private ITypeInfo findTypeInCache(ITypeCache cache, String name) {
+ IQualifiedTypeName qualName = new QualifiedTypeName(name);
+ ITypeInfo[] superTypes = cache.getTypes(qualName);
+ for (int i = 0; i < superTypes.length; ++i) {
+ ITypeInfo superType = superTypes[i];
+ if (superType.isClass()) {
+ return superType;
+ }
+ }
+ return null;
+ }
+*/
+
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java
new file mode 100644
index 00000000000..467841057cf
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the 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.typehierarchy;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class TypeHierarchyMessages {
+
+ private static final String RESOURCE_BUNDLE= TypeHierarchyMessages.class.getName();
+
+ private static ResourceBundle fgResourceBundle;
+ static {
+ try {
+ fgResourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE);
+ } catch (MissingResourceException x) {
+ fgResourceBundle = null;
+ }
+ }
+
+ private TypeHierarchyMessages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return fgResourceBundle.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ } catch (NullPointerException e) {
+ return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ public static String getFormattedString(String key, String arg) {
+ return getFormattedString(key, new String[] { arg });
+ }
+
+ public static String getFormattedString(String key, String[] args) {
+ return MessageFormat.format(getString(key), args);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties
new file mode 100644
index 00000000000..760292b333c
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2000, 2004 QNX Software Systems and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the 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
+###############################################################################
+
+### hierarchy
+hierarchy.nullProject = Project argument cannot be null
+hierarchy.nullRegion = Region cannot be null
+hierarchy.nullFocusType = Type focus cannot be null
+hierarchy.creating = Creating type hierarchy...
+hierarchy.creatingOnType = Creating type hierarchy on {0}...
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/BasicJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/BasicJob.java
new file mode 100644
index 00000000000..7bf631918b1
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/BasicJob.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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.cache;
+
+import org.eclipse.cdt.internal.core.browser.util.DelegatedProgressMonitor;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+public abstract class BasicJob extends Job {
+
+ private Object fFamily;
+ private DelegatedProgressMonitor fProgressMonitor= new DelegatedProgressMonitor();
+ private Object fRunLock = new Object();
+ private boolean fIsRunning = false;
+ private static boolean VERBOSE = false;
+
+ public BasicJob(String name, Object family) {
+ super(name);
+ fFamily = family;
+ setPriority(BUILD);
+ setSystem(true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor)
+ */
+ protected abstract IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.internal.jobs.InternalJob#belongsTo(java.lang.Object)
+ */
+ public boolean belongsTo(Object family) {
+ if (fFamily != null) {
+ return fFamily.equals(family);
+ }
+ return false;
+ }
+
+ public boolean isRunning() {
+ synchronized(fRunLock) {
+ return fIsRunning;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor)
+ */
+ public IStatus run(IProgressMonitor monitor) {
+ synchronized(fRunLock) {
+ fIsRunning = true;
+ }
+
+ fProgressMonitor.init();
+ fProgressMonitor.addDelegate(monitor);
+
+ IStatus result = Status.CANCEL_STATUS;
+ try {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ result = runWithDelegatedProgress(fProgressMonitor);
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+ } catch(InterruptedException ex) {
+ return Status.CANCEL_STATUS;
+ } catch (OperationCanceledException ex) {
+ return Status.CANCEL_STATUS;
+ } finally {
+ fProgressMonitor.done();
+ fProgressMonitor.removeAllDelegates();
+ fProgressMonitor.init();
+
+ synchronized(fRunLock) {
+ fIsRunning = false;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Forwards progress info to the progress monitor and
+ * blocks until the job is finished.
+ *
+ * @param monitor the progress monitor.
+ * @throws InterruptedException
+ *
+ * @see Job#join
+ */
+ public void join(IProgressMonitor monitor) throws InterruptedException {
+ if (monitor != null) {
+ fProgressMonitor.addDelegate(monitor);
+ }
+ super.join();
+ }
+
+ /**
+ * Outputs message to console.
+ */
+ protected static void trace(String msg) {
+ if (VERBOSE) {
+ System.out.println("(" + Thread.currentThread() + ") " + msg); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java
new file mode 100644
index 00000000000..d4e73fbdaef
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * 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.cache;
+
+import org.eclipse.cdt.core.browser.IQualifiedTypeName;
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.ITypeInfoVisitor;
+import org.eclipse.cdt.core.browser.ITypeReference;
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+
+public interface ITypeCache extends ISchedulingRule {
+
+ /** Returns whether cache contains any types.
+ *
+ * @return <code>true</code> if cache is empty
+ */
+ public boolean isEmpty();
+
+ /** Returns whether cache is complete.
+ *
+ * @return <code>true</code> if cache is up to date.
+ */
+ public boolean isUpToDate();
+
+ /** Inserts type into cache.
+ *
+ * @param info
+ */
+ public void insert(ITypeInfo info);
+
+ /** Adds subtype to type.
+ *
+ * @param type
+ * @param subtype
+ */
+ public void addSubtype(ITypeInfo type, ITypeInfo subtype);
+
+ /** Adds supertype to type.
+ *
+ * @param type the type
+ * @param supertype the supertype
+ * @param the access visibility (PUBLIC, PROTECTED, PRIVATE)
+ * @param isVirtual <code>true</code> if virtual base class
+ */
+ public void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual);
+
+ /** Removes type from cache.
+ *
+ * @param info
+ */
+ public void remove(ITypeInfo info);
+
+ /** Removes all types in the given scope.
+ *
+ * @param scope
+ */
+ public void flush(ITypeSearchScope scope);
+
+ /** Removes all types referenced by the given path.
+ *
+ * @param path
+ */
+ public void flush(IPath path);
+
+ /** Removes all types from the cache.
+ */
+ public void flushAll();
+
+ /** Returns all paths in the cache which are enclosed by
+ * the given scope. If no paths are found, an empty
+ * array is returned.
+ *
+ * @param scope the scope to search, or <code>null</code> to
+ * search the entire cache.
+ * @return A collection of paths in the given scope.
+ */
+ public IPath[] getPaths(ITypeSearchScope scope);
+
+ /** Returns all types in the cache which are enclosed by
+ * the given scope. If no types are found, an empty array
+ * is returned.
+ *
+ * @param scope the scope to search, or <code>null</code> to
+ * search the entire cache.
+ * @return Array of types in the given scope
+ */
+ public ITypeInfo[] getTypes(ITypeSearchScope scope);
+
+ /** Returns all types in the cache which match the given
+ * name. If no types are found, an empty array is returned.
+ *
+ * @param qualifiedName the qualified type name to match
+ * @param matchEnclosed <code>true</code> if enclosed types count as matches (foo::bar == bar)
+ * @param ignoreCase <code>true</code> if case-insensitive
+ * @return Array of types
+ */
+ public ITypeInfo[] getTypes(IQualifiedTypeName qualifiedName, boolean matchEnclosed, boolean ignoreCase);
+
+ /** Returns first type in the cache which matches the given
+ * type and name. If no type is found, <code>null</code>
+ * is returned.
+ *
+ * @param type the ICElement type
+ * @param qualifiedName the qualified type name to match
+ * @return the matching type
+ */
+ public ITypeInfo getType(int type, IQualifiedTypeName qualifiedName);
+
+ /** Gets the first enclosing type which matches one of the given kinds.
+ *
+ * @param info the given type
+ * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS, C_STRUCT
+ *
+ * @return the enclosing type, or <code>null</code> if not found.
+ */
+ public ITypeInfo getEnclosingType(ITypeInfo info, int[] kinds);
+
+ /** Returns the enclosing namespace for the given type, or
+ * <code>null</code> if none exists.
+ *
+ * @param type the ICElement type
+ * @param includeGlobalNamespace <code>true</code> if the global (default) namespace should be returned
+ * @return the enclosing namespace, or <code>null</code> if not found.
+ */
+ public ITypeInfo getEnclosingNamespace(ITypeInfo info, boolean includeGlobalNamespace);
+
+ /** Gets the root namespace of which encloses the given type.
+ *
+ * @param info the given type
+ * @param includeGlobalNamespace <code>true</code> if the global (default) namespace should be returned
+ * @return the enclosing namespace, or <code>null</code> if not found.
+ */
+ public ITypeInfo getRootNamespace(ITypeInfo info, boolean includeGlobalNamespace);
+
+ /** Returns whether any types are enclosed by the given type.
+ *
+ * @param info the given type
+ * @return <code>true</code> if the given type encloses other types.
+ */
+ public boolean hasEnclosedTypes(ITypeInfo info);
+
+ /** Gets the types which are enclosed by the given type.
+ *
+ * @param info the given type
+ * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS,
+ * C_UNION, C_ENUMERATION, C_TYPEDEF
+ * @return the enclosed types, or an empty array if not found.
+ */
+ public ITypeInfo[] getEnclosedTypes(ITypeInfo info, int kinds[]);
+
+ /** Returns all types in the cache are supertypes of the given type.
+ *
+ * @param info the given type
+ * @return Array of supertypes, or <code>null</code> if none found.
+ */
+ public ITypeInfo[] getSupertypes(ITypeInfo info);
+
+ /** Returns the supertype access visiblity.
+ *
+ * @param type the given type
+ * @param supertype the supertype
+ * @return the visibility (PRIVATE, PROTECTED, PUBLIC) or <code>null</code> if none found.
+ */
+ public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType);
+
+
+ /** Returns all types in the cache which extend the given type.
+ *
+ * @param info the given type
+ * @return Array of subtypes, or <code>null</code> if none found.
+ */
+ public ITypeInfo[] getSubtypes(ITypeInfo info);
+
+ /** Returns the project associated with this cache.
+ *
+ * @return the project
+ */
+ public IProject getProject();
+
+ /** Accepts a visitor and iterates over all types in the cache.
+ *
+ * @param visitor
+ */
+ public void accept(ITypeInfoVisitor visitor);
+
+ public void addDelta(TypeCacheDelta delta);
+ public void reconcile(boolean enableIndexing, int priority, int delay);
+ public void reconcileAndWait(boolean enableIndexing, int priority, IProgressMonitor monitor);
+ public void cancelJobs();
+
+ public void locateType(ITypeInfo info, int priority, int delay);
+ public ITypeReference locateTypeAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+
+ public void locateSupertypes(ITypeInfo info, int priority, int delay);
+ public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+
+ public void locateSubtypes(ITypeInfo info, int priority, int delay);
+ public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+
+ public ITypeInfo getGlobalNamespace();
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob.java
new file mode 100644
index 00000000000..e46b6711efe
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.internal.core.browser.cache;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.PathUtil;
+import org.eclipse.cdt.internal.core.index.IEntryResult;
+import org.eclipse.cdt.internal.core.index.IIndex;
+import org.eclipse.cdt.internal.core.index.cindexstorage.Index;
+import org.eclipse.cdt.internal.core.index.cindexstorage.IndexedFileEntry;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.BlocksIndexInput;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.IndexInput;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class IndexerDependenciesJob extends IndexerJob {
+
+ private ITypeCache fTypeCache;
+ private ITypeSearchScope fScope;
+
+ public IndexerDependenciesJob(IndexManager indexManager, ITypeCache typeCache, ITypeSearchScope scope) {
+ super(indexManager, typeCache.getProject());
+ fTypeCache = typeCache;
+ fScope = scope;
+ }
+
+ protected boolean processIndex(IIndex index, IProject project, IProgressMonitor progressMonitor) throws InterruptedException {
+ IndexInput input = new BlocksIndexInput(index.getIndexFile());
+ try {
+ input.open();
+ flushDependencies(input, progressMonitor);
+ return true;
+ } catch (IOException e) {
+ return false;
+ } finally {
+ try {
+ input.close();
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+
+ private void flushDependencies(IndexInput input, IProgressMonitor progressMonitor)
+ throws InterruptedException, IOException {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult[] includeEntries = input.queryEntriesPrefixedBy(Index.encodeEntry(IIndex.INCLUDE, IIndex.ANY, IIndex.REFERENCE));
+ if (includeEntries != null) {
+ //TODO subprogress monitor
+ for (int i = 0; i < includeEntries.length; ++i) {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult entry = includeEntries[i];
+ IPath includePath = getIncludePath(entry);
+
+ if (fScope != null && fScope.encloses(includePath)) {
+ int[] references = entry.getFileReferences();
+ if (references != null) {
+ for (int j = 0; j < references.length; ++j) {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ IndexedFileEntry file = input.getIndexedFile(references[j]);
+ if (file != null && file.getPath() != null) {
+ IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+ fTypeCache.flush(path);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private IPath getIncludePath(IEntryResult entry) {
+ return PathUtil.getWorkspaceRelativePath(entry.getName());
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob2.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob2.java
new file mode 100644
index 00000000000..2567bf32c6a
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob2.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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.internal.core.browser.cache;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.PathUtil;
+import org.eclipse.cdt.internal.core.index.IEntryResult;
+import org.eclipse.cdt.internal.core.index.IIndex;
+import org.eclipse.cdt.internal.core.index.cindexstorage.Index;
+import org.eclipse.cdt.internal.core.index.cindexstorage.IndexedFileEntry;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.BlocksIndexInput;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.IndexInput;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class IndexerDependenciesJob2 extends IndexerJob2 {
+
+ private ITypeCache fTypeCache;
+ private ITypeSearchScope fScope;
+
+ public IndexerDependenciesJob2(IndexManager indexManager, ITypeCache typeCache, ITypeSearchScope scope) {
+ super(indexManager, typeCache.getProject());
+ fTypeCache = typeCache;
+ fScope = scope;
+ }
+
+ protected boolean processIndex(IProgressMonitor progressMonitor) throws InterruptedException {
+ IndexInput input = new BlocksIndexInput(fProjectIndex.getIndexFile());
+ try {
+ input.open();
+ flushDependencies(input, progressMonitor);
+ return true;
+ } catch (IOException e) {
+ return false;
+ } finally {
+ try {
+ input.close();
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+
+ private void flushDependencies(IndexInput input, IProgressMonitor progressMonitor)
+ throws InterruptedException, IOException {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult[] includeEntries = input.queryEntriesPrefixedBy(Index.encodeEntry(IIndex.INCLUDE, IIndex.ANY, IIndex.REFERENCE));
+ if (includeEntries != null) {
+ //TODO subprogress monitor
+ for (int i = 0; i < includeEntries.length; ++i) {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult entry = includeEntries[i];
+ IPath includePath = getIncludePath(entry);
+
+ if (fScope != null && fScope.encloses(includePath)) {
+ int[] references = entry.getFileReferences();
+ if (references != null) {
+ for (int j = 0; j < references.length; ++j) {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ IndexedFileEntry file = input.getIndexedFile(references[j]);
+ if (file != null && file.getPath() != null) {
+ IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+ fTypeCache.flush(path);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private IPath getIncludePath(IEntryResult entry) {
+ return PathUtil.getWorkspaceRelativePath(entry.getName());
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob.java
new file mode 100644
index 00000000000..4de9fba649a
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2005 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 implementation
+ * QNX Software Systems - adapted for type cache
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.cache;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.core.index.ICDTIndexer;
+import org.eclipse.cdt.internal.core.index.IIndex;
+import org.eclipse.cdt.internal.core.index.domsourceindexer.DOMSourceIndexer;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.cdt.internal.core.search.indexing.ReadWriteMonitor;
+import org.eclipse.cdt.internal.core.search.processing.IIndexJob;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+public abstract class IndexerJob implements IIndexJob {
+
+ private IndexManager fIndexManager;
+ private IProject fProject;
+ private IIndex fProjectIndex = null;
+ private DOMSourceIndexer fSourceIndexer = null;
+
+ public static final String FAMILY= "BasicTypeIndexerJob"; //$NON-NLS-1$
+
+ public IndexerJob(IndexManager indexManager, IProject project) {
+ fIndexManager = indexManager;
+ fProject = project;
+ //Get the indexer assigned to this project; check to see if it's
+ //a Source Indexder
+ ICDTIndexer indexer = indexManager.getIndexerForProject(project);
+ if (indexer instanceof DOMSourceIndexer)
+ fSourceIndexer = (DOMSourceIndexer) indexer;
+ }
+
+ public boolean belongsTo(String family) {
+ return family == FAMILY;
+ }
+
+ public void cancel() {
+ }
+
+ public boolean isReadyToRun() {
+ if (fProjectIndex == null) { // only check once. As long as this job is used, it will keep the same index picture
+ getIndexForProject(fProject); // will only cache answer if all indexes were available originally
+ }
+ return true;
+ }
+
+ public String toString() {
+ return FAMILY;
+ }
+
+ protected abstract boolean processIndex(IIndex index, IProject project, IProgressMonitor progressMonitor) throws InterruptedException;
+
+ public boolean execute(IProgressMonitor progressMonitor) {
+ boolean success = false;
+ try {
+ fProjectIndex = getIndexForProject(fProject);
+ if (fProjectIndex == null)
+ return false;
+
+ if (progressMonitor == null) {
+ progressMonitor = new NullProgressMonitor();
+ }
+ if (progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ progressMonitor.beginTask("", 1); //$NON-NLS-1$
+
+ success = prepareIndex(fProjectIndex, fProject, progressMonitor);
+
+ if (progressMonitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ progressMonitor.worked(1);
+
+ return success;
+ } catch (InterruptedException e) {
+ throw new OperationCanceledException();
+ } finally {
+ progressMonitor.done();
+ }
+ }
+
+ private boolean prepareIndex(IIndex index, IProject project, IProgressMonitor progressMonitor) throws InterruptedException {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ if (index == null)
+ return COMPLETE;
+
+ if (fSourceIndexer == null)
+ return FAILED;
+
+ ReadWriteMonitor monitor = fSourceIndexer.getMonitorFor(index);
+
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+
+ try {
+ monitor.enterRead(); // ask permission to read
+ /* if index has changed, commit these before querying */
+ if (index.hasChanged()) {
+ try {
+ monitor.exitRead(); // free read lock
+ monitor.enterWrite(); // ask permission to write
+ fSourceIndexer.saveIndex(index);
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
+ }
+ }
+
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ return processIndex(index, project, progressMonitor);
+ } finally {
+ monitor.exitRead(); // finished reading
+ }
+ }
+
+ private IIndex getIndexForProject(IProject project) {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath path = project.getFullPath();
+ IPath location;
+ if ((!root.getProject(path.lastSegment()).exists()) // if project does not exist
+ && path.segmentCount() > 1
+ && ((location = root.getFile(path).getLocation()) == null
+ || !new java.io.File(location.toOSString()).exists()) // and internal jar file does not exist
+ && !new java.io.File(path.toOSString()).exists()) { // and external jar file does not exist
+ return null;
+ }
+
+ // may trigger some index recreation work
+ if (fSourceIndexer != null)
+ return fSourceIndexer.getIndex(path, true /*reuse index file*/, false /*do not create if none*/);
+
+ return null;
+ }
+}
+
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob2.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob2.java
new file mode 100644
index 00000000000..51be068de3e
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob2.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2004,2005 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
+ * QNX Software Systems - adapted for type cache
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.cache;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.core.index.ICDTIndexer;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.internal.core.index.IIndex;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.cdt.internal.core.search.indexing.ReadWriteMonitor;
+import org.eclipse.cdt.internal.core.search.processing.IIndexJob;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+public abstract class IndexerJob2 implements IIndexJob {
+
+ protected IProject fProject;
+ protected IIndex fProjectIndex = null;
+ protected ICDTIndexer fSourceIndexer = null;
+
+ public static final String FAMILY= "IndexerJob2"; //$NON-NLS-1$
+
+ public IndexerJob2(IndexManager indexManager, IProject project) {
+ fProject = project;
+ fSourceIndexer = indexManager.getIndexerForProject(project);
+ fProjectIndex = getIndexForProject();
+ }
+
+ public boolean belongsTo(String family) {
+ return family == FAMILY;
+ }
+
+ public void cancel() {
+ }
+
+ public boolean isReadyToRun() {
+ return true;
+ }
+
+ public String toString() {
+ return FAMILY;
+ }
+
+ protected abstract boolean processIndex(IProgressMonitor progressMonitor) throws InterruptedException;
+
+ public boolean execute(IProgressMonitor progressMonitor) {
+ boolean success = false;
+ try {
+ if (fProjectIndex == null)
+ return false;
+
+ if (progressMonitor == null) {
+ progressMonitor = new NullProgressMonitor();
+ }
+ if (progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ progressMonitor.beginTask("", 1); //$NON-NLS-1$
+
+ success = prepareIndex(progressMonitor);
+
+ if (progressMonitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ progressMonitor.worked(1);
+
+ return success;
+ } catch (InterruptedException e) {
+ throw new OperationCanceledException();
+ } finally {
+ progressMonitor.done();
+ }
+ }
+
+ private boolean prepareIndex(IProgressMonitor progressMonitor) throws InterruptedException {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ if (fProjectIndex == null)
+ return COMPLETE;
+
+ if (fSourceIndexer == null)
+ return FAILED;
+
+ ReadWriteMonitor monitor = fSourceIndexer.getMonitorFor(fProjectIndex);
+
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+
+ try {
+ monitor.enterRead(); // ask permission to read
+ /* if index has changed, commit these before querying */
+ if (fProjectIndex.hasChanged()) {
+ try {
+ monitor.exitRead(); // free read lock
+ monitor.enterWrite(); // ask permission to write
+ fSourceIndexer.saveIndex(fProjectIndex);
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
+ }
+ }
+
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ return processIndex(progressMonitor);
+ } finally {
+ monitor.exitRead(); // finished reading
+ }
+ }
+
+ private IIndex getIndexForProject() {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath path = fProject.getFullPath();
+ IPath location;
+ if ((!root.getProject(path.lastSegment()).exists()) // if project does not exist
+ && path.segmentCount() > 1
+ && ((location = root.getFile(path).getLocation()) == null
+ || !new java.io.File(location.toOSString()).exists()) // and internal jar file does not exist
+ && !new java.io.File(path.toOSString()).exists()) { // and external jar file does not exist
+ return null;
+ }
+
+ // may trigger some index recreation work
+ if (fSourceIndexer != null)
+ return fSourceIndexer.getIndex(path, true /*reuse index file*/, false /*do not create if none*/);
+
+ return null;
+ }
+
+ protected int index2ICElement( int kind )
+ {
+ switch(kind) {
+ case IIndex.TYPE_CLASS:
+ return ICElement.C_CLASS;
+ case IIndex.TYPE_STRUCT:
+ return ICElement.C_STRUCT;
+ case IIndex.TYPE_ENUM:
+ return ICElement.C_ENUMERATION;
+ case IIndex.TYPE_UNION:
+ return ICElement.C_UNION;
+ case IIndex.TYPE_TYPEDEF:
+ return ICElement.C_TYPEDEF;
+ default:
+ return 0;
+ }
+ }
+}
+
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java
new file mode 100644
index 00000000000..78c7cee5cc8
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * 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.internal.core.browser.cache;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.PathUtil;
+import org.eclipse.cdt.core.browser.QualifiedTypeName;
+import org.eclipse.cdt.core.browser.TypeInfo;
+import org.eclipse.cdt.core.browser.TypeReference;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.internal.core.index.IEntryResult;
+import org.eclipse.cdt.internal.core.index.IIndex;
+import org.eclipse.cdt.internal.core.index.cindexstorage.Index;
+import org.eclipse.cdt.internal.core.index.cindexstorage.IndexedFileEntry;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.BlocksIndexInput;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.IndexInput;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class IndexerTypesJob extends IndexerJob {
+
+ private ITypeCache fTypeCache;
+
+ public IndexerTypesJob(IndexManager indexManager, ITypeCache typeCache, ITypeSearchScope scope) {
+ super(indexManager, typeCache.getProject());
+ fTypeCache = typeCache;
+ }
+
+ protected boolean processIndex(IIndex index, IProject project, IProgressMonitor progressMonitor) throws InterruptedException {
+ IndexInput input = new BlocksIndexInput(index.getIndexFile());
+ try {
+ input.open();
+ updateNamespaces(input, project, progressMonitor);
+ updateTypes(input, project, progressMonitor);
+ return true;
+ } catch (IOException e) {
+ return false;
+ } finally {
+ try {
+ input.close();
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+
+ private void updateNamespaces(IndexInput input, IProject project, IProgressMonitor monitor)
+ throws InterruptedException, IOException {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult[] namespaceEntries = input.queryEntriesPrefixedBy(Index.encodeEntry(IIndex.NAMESPACE, IIndex.ANY, IIndex.DECLARATION));
+ if (namespaceEntries != null) {
+ //TODO subprogress monitor
+ for (int i = 0; i < namespaceEntries.length; ++i) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult entry = namespaceEntries[i];
+ String name = entry.getName();
+ if (name.length() != 0) {
+ String[] enclosingNames = entry.getEnclosingNames();
+ addType(input, project, entry, ICElement.C_NAMESPACE, name, enclosingNames, monitor);
+ }
+ }
+ }
+ }
+
+ private void updateTypes(IndexInput input, IProject project, IProgressMonitor monitor)
+ throws InterruptedException, IOException {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult[] typeEntries = input.queryEntriesPrefixedBy(Index.encodeEntry(IIndex.TYPE, IIndex.ANY, IIndex.DECLARATION));
+ if (typeEntries != null) {
+ //TODO subprogress monitor
+ for (int i = 0; i < typeEntries.length; ++i) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult entry = typeEntries[i];
+
+ String name = entry.getName();
+ switch (entry.getKind() ) {
+ case IIndex.TYPE_CLASS :
+ case IIndex.TYPE_STRUCT :
+ case IIndex.TYPE_TYPEDEF :
+ case IIndex.TYPE_ENUM :
+ case IIndex.TYPE_UNION :
+ if (name.length() != 0) { // skip anonymous structs
+ addType(input, project, entry, entry.getKind(), name, entry.getEnclosingNames(), monitor);
+ }
+ break;
+ case IIndex.TYPE_DERIVED :
+ if (name.length() != 0) { // skip anonymous structs
+ addSuperTypeReference(input, project, entry, name, entry.getEnclosingNames(), monitor);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ private void addType(IndexInput input, IProject project, IEntryResult entry, int type, String name, String[] enclosingNames, IProgressMonitor monitor)
+ throws InterruptedException, IOException {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ ITypeInfo info = fTypeCache.getType(type, qualifiedName);
+ if (info == null || info.isUndefinedType()) {
+ int[] references = entry.getFileReferences();
+ if (references != null && references.length > 0) {
+ // add new type to cache
+ if (info != null) {
+ info.setCElementType(type);
+ } else {
+ info = new TypeInfo(type, qualifiedName);
+ fTypeCache.insert(info);
+ }
+
+// for (int i = 0; i < references.length; ++i) {
+// if (monitor.isCanceled())
+// throw new InterruptedException();
+//
+// IndexedFile file = input.getIndexedFile(references[i]);
+// if (file != null && file.getPath() != null) {
+// IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+// info.addReference(new TypeReference(path, project));
+// }
+// }
+ // just grab the first reference
+ IndexedFileEntry file = input.getIndexedFile(references[0]);
+ if (file != null && file.getPath() != null) {
+ IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+ info.addReference(new TypeReference(path, project));
+ }
+ }
+ }
+ }
+
+ private void addSuperTypeReference(IndexInput input, IProject project, IEntryResult entry, String name, String[] enclosingNames, IProgressMonitor monitor) throws InterruptedException, IOException {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ ITypeInfo info = fTypeCache.getType(ICElement.C_CLASS, qualifiedName);
+ if (info == null)
+ info = fTypeCache.getType(ICElement.C_STRUCT, qualifiedName);
+ if (info == null) {
+ // add dummy type to cache
+ info = new TypeInfo(0, qualifiedName);
+ fTypeCache.insert(info);
+ }
+ int[] references = entry.getFileReferences();
+ if (references != null && references.length > 0) {
+ for (int i = 0; i < references.length; ++i) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IndexedFileEntry file = input.getIndexedFile(references[i]);
+ if (file != null && file.getPath() != null) {
+ IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+ info.addDerivedReference(new TypeReference(path, project));
+//
+// // get absolute path
+// IPath path = new Path(file.getPath());
+// IPath projectPath = project.getFullPath();
+// if (projectPath.isPrefixOf(path)) {
+// path = project.getLocation().append(path.removeFirstSegments(projectPath.segmentCount()));
+// }
+// info.addDerivedReference(new TypeReference(path, project));
+ }
+ }
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob2.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob2.java
new file mode 100644
index 00000000000..206db83a5c3
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob2.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * 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.internal.core.browser.cache;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.PathUtil;
+import org.eclipse.cdt.core.browser.QualifiedTypeName;
+import org.eclipse.cdt.core.browser.TypeInfo;
+import org.eclipse.cdt.core.browser.TypeReference;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.internal.core.index.IEntryResult;
+import org.eclipse.cdt.internal.core.index.IIndex;
+import org.eclipse.cdt.internal.core.index.IQueryResult;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.BlocksIndexInput;
+import org.eclipse.cdt.internal.core.index.cindexstorage.io.IndexInput;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class IndexerTypesJob2 extends IndexerJob2 {
+
+ private ITypeCache fTypeCache;
+
+ public IndexerTypesJob2(IndexManager indexManager, ITypeCache typeCache, ITypeSearchScope scope) {
+ super(indexManager, typeCache.getProject());
+ fTypeCache = typeCache;
+ }
+
+ protected boolean processIndex(IProgressMonitor progressMonitor) throws InterruptedException {
+ IndexInput input = null;
+ try {
+ input = new BlocksIndexInput( fProjectIndex.getIndexFile() );
+ input.open();
+ updateNamespaces(input, progressMonitor);
+ updateTypes(input, progressMonitor);
+ return true;
+ } catch (IOException e) {
+ return false;
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+ }
+ }
+
+ private void updateNamespaces(IndexInput input, IProgressMonitor monitor)
+ throws InterruptedException, IOException {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult[] namespaceEntries = fProjectIndex.getEntries( IIndex.NAMESPACE, IIndex.ANY, IIndex.DEFINITION );
+ IQueryResult[] namespacePaths = fProjectIndex.getPrefix(IIndex.NAMESPACE, IIndex.ANY, IIndex.DEFINITION );
+// input.queryEntriesPrefixedBy(Index.encodeEntry(IIndex.NAMESPACE, IIndex.ANY, IIndex.DECLARATION));
+ if (namespaceEntries != null) {
+ //TODO subprogress monitor
+ for (int i = 0; i < namespaceEntries.length; ++i) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult entry = namespaceEntries[i];
+ String name = entry.getName();
+ if (name.length() != 0) {
+ String[] enclosingNames = entry.getEnclosingNames();
+ addType(input, entry, namespacePaths[i].getPath(), ICElement.C_NAMESPACE, name, enclosingNames, monitor);
+ }
+ }
+ }
+ }
+
+ private void updateTypes(IndexInput input, IProgressMonitor monitor)
+ throws InterruptedException, IOException {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ for( int counter = 0; counter < 2; ++counter )
+ {
+ IEntryResult[] typeEntries = fProjectIndex.getEntries( IIndex.TYPE, IIndex.ANY, ( counter == 0 ) ? IIndex.DECLARATION : IIndex.DEFINITION );
+
+ if (typeEntries != null) {
+ //TODO subprogress monitor
+ for (int i = 0; i < typeEntries.length; ++i) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult entry = typeEntries[i];
+
+ String name = entry.extractSimpleName();
+ switch (entry.getKind() ) {
+ case IIndex.TYPE_CLASS :
+ case IIndex.TYPE_STRUCT :
+ case IIndex.TYPE_TYPEDEF :
+ case IIndex.TYPE_ENUM :
+ case IIndex.TYPE_UNION :
+ if (counter != 0 && name.length() != 0) { // skip anonymous structs
+ addType(input, entry, null, index2ICElement( entry.getKind() ), name, entry.getEnclosingNames(), monitor);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ IEntryResult[] typeEntries = fProjectIndex.getEntries( IIndex.TYPE, IIndex.TYPE_DERIVED, IIndex.ANY );
+ if (typeEntries != null){
+ for( int j = 0; j < typeEntries.length; ++j )
+ {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ IEntryResult entry = typeEntries[j];
+ String name = entry.extractSimpleName();
+ switch( entry.getKind() )
+ {
+ case IIndex.TYPE_DERIVED :
+ if (name.length() != 0) { // skip anonymous structs
+ addSuperTypeReference(input, entry, name, entry.getEnclosingNames(), monitor);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ private void addType(IndexInput input, IEntryResult entry, String pth, int type, String name, String[] enclosingNames, IProgressMonitor monitor)
+ throws InterruptedException, IOException {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ ITypeInfo info = fTypeCache.getType(type, qualifiedName);
+ if (info == null || info.isUndefinedType()) {
+ int[] references = entry.getFileReferences();
+ if (references != null && references.length > 0) {
+ // add new type to cache
+ if (info != null) {
+ info.setCElementType(type);
+ } else {
+ info = new TypeInfo(type, qualifiedName);
+ fTypeCache.insert(info);
+ }
+
+// for (int i = 0; i < references.length; ++i) {
+// if (monitor.isCanceled())
+// throw new InterruptedException();
+//
+// IndexedFile file = input.getIndexedFile(references[i]);
+// if (file != null && file.getPath() != null) {
+// IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+// info.addReference(new TypeReference(path, project));
+// }
+// }
+ if (pth == null) {
+ pth = input.getIndexedFile( references[0] ).getPath();
+ }
+
+ final IPath workspaceRelativePath = PathUtil.getWorkspaceRelativePath(pth);
+ int offset = entry.getOffsets()[0][0];
+// int offsetType = Integer.valueOf(String.valueOf(offsets[i][j]).substring(0,1)).intValue();
+ int offsetType = offset;
+ int m = 1;
+ while (offsetType >= 10) {
+ offsetType = offsetType / 10;
+ m *= 10;
+ }
+ int value = offset - ( offsetType * m );
+// int value = Integer.valueOf(String.valueOf(offset).substring(1)).intValue();
+
+ TypeReference typeReference = null;
+ if (offsetType==IIndex.LINE){
+ typeReference = new TypeReference(workspaceRelativePath, fProject, value, 0 );
+ typeReference.offsetIsLineNumber = true;
+ }else if (offsetType==IIndex.OFFSET){
+ typeReference = new TypeReference(workspaceRelativePath, fProject, value, entry.getOffsetLengths()[0][0] );
+ }
+ if( typeReference != null )
+ info.addReference(typeReference);
+ }
+ }
+ }
+
+ private void addSuperTypeReference(IndexInput input, IEntryResult entry, String name, String[] enclosingNames, IProgressMonitor monitor) throws InterruptedException, IOException {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ ITypeInfo info = fTypeCache.getType(ICElement.C_CLASS, qualifiedName);
+ if (info == null)
+ info = fTypeCache.getType(ICElement.C_STRUCT, qualifiedName);
+ if (info == null) {
+ // add dummy type to cache
+ info = new TypeInfo(0, qualifiedName);
+ fTypeCache.insert(info);
+ }
+ int[] references = entry.getFileReferences();
+ if (references != null && references.length > 0) {
+ for (int i = 0; i < references.length; ++i) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ String pth = input.getIndexedFile( references[i] ).getPath();
+ IPath path = PathUtil.getWorkspaceRelativePath(pth);
+
+ info.addDerivedReference(new TypeReference(path, fProject));
+//
+// // get absolute path
+// IPath path = new Path(file.getPath());
+// IPath projectPath = project.getFullPath();
+// if (projectPath.isPrefixOf(path)) {
+// path = project.getLocation().append(path.removeFirstSegments(projectPath.segmentCount()));
+// }
+// info.addDerivedReference(new TypeReference(path, project));
+
+ }
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java
new file mode 100644
index 00000000000..5fe508c83f7
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the 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.cache;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+public class SubTypeLocatorJob extends BasicJob {
+
+ public static final Object FAMILY = new Object();
+ private ITypeInfo fLocateType;
+ private ITypeCache fTypeCache;
+ private IWorkingCopyProvider fWorkingCopyProvider;
+
+ public SubTypeLocatorJob(ITypeInfo info, ITypeCache typeCache, IWorkingCopyProvider workingCopyProvider) {
+ super(TypeCacheMessages.getString("SubTypeLocatorJob.jobName"), FAMILY); //$NON-NLS-1$
+ fLocateType = info;
+ fTypeCache = typeCache;
+ fWorkingCopyProvider= workingCopyProvider;
+ }
+
+ public ITypeInfo getType() {
+ return fLocateType;
+ }
+
+ protected IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException {
+ boolean success = false;
+ long startTime = System.currentTimeMillis();
+ trace("SubTypeLocatorJob: started"); //$NON-NLS-1$
+
+ try {
+ monitor.beginTask(TypeCacheMessages.getString("SubTypeLocatorJob.taskName"), 100); //$NON-NLS-1$
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ TypeParser parser = new TypeParser(fTypeCache, fWorkingCopyProvider);
+ success = parser.findSubTypes(fLocateType, new SubProgressMonitor(monitor, 100));
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ } finally {
+ long executionTime = System.currentTimeMillis() - startTime;
+ if (success)
+ trace("SubTypeLocatorJob: completed ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+ else
+ trace("SubTypeLocatorJob: aborted ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ monitor.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java
new file mode 100644
index 00000000000..07f4fbc25a1
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java
@@ -0,0 +1,896 @@
+/*******************************************************************************
+ * 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.cache;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.core.browser.IQualifiedTypeName;
+import org.eclipse.cdt.core.browser.ITypeCacheChangedListener;
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.ITypeInfoVisitor;
+import org.eclipse.cdt.core.browser.ITypeReference;
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.cdt.core.browser.QualifiedTypeName;
+import org.eclipse.cdt.core.browser.TypeInfo;
+import org.eclipse.cdt.core.browser.TypeSearchScope;
+import org.eclipse.cdt.core.index.ICDTIndexer;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
+import org.eclipse.cdt.internal.core.model.CModelManager;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+
+public class TypeCache implements ITypeCache {
+
+ private static final int INITIAL_TYPE_COUNT = 100;
+ private final Map fTypeKeyMap = new HashMap(INITIAL_TYPE_COUNT);
+ final IProject fProject;
+ private final IWorkingCopyProvider fWorkingCopyProvider;
+ final Collection fDeltas = new ArrayList();
+ final ITypeInfo fGlobalNamespace;
+ private final Map fTypeToSubTypes = new HashMap();
+ private final Map fTypeToSuperTypes = new HashMap();
+ ITypeCacheChangedListener fChangeListener = null;
+
+ private static final class SuperTypeEntry {
+ ITypeInfo superType;
+ ASTAccessVisibility access;
+ boolean isVirtual;
+ SuperTypeEntry(ITypeInfo superType, ASTAccessVisibility access, boolean isVirtual) {
+ this.superType = superType;
+ this.access = access;
+ this.isVirtual = isVirtual;
+ }
+ }
+
+ private SuperTypeEntry findSuperTypeEntry(Collection entryCollection, ITypeInfo superType) {
+ for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
+ SuperTypeEntry e = (SuperTypeEntry) i.next();
+ if (e.superType.equals(superType)) {
+ return e;
+ }
+ }
+ return null;
+ }
+
+ private static final int[] ENCLOSING_TYPES = {ICElement.C_NAMESPACE, ICElement.C_CLASS, ICElement.C_STRUCT, 0};
+
+ private IJobChangeListener fJobChangeListener = new IJobChangeListener() {
+ public void aboutToRun(IJobChangeEvent event) {
+ }
+
+ public void awake(IJobChangeEvent event) {
+ }
+
+ public void done(IJobChangeEvent event) {
+ Job job = event.getJob();
+ if (job instanceof TypeCacherJob) {
+ TypeCacherJob deltaJob = (TypeCacherJob)job;
+ IStatus status = event.getResult();
+ if (status != null) {
+ boolean jobFinished = (status.equals(Status.OK_STATUS)
+ && !deltaJob.isIndexerBusy());
+ // remove the completed deltas
+ synchronized(fDeltas) {
+ for (Iterator i = fDeltas.iterator(); i.hasNext(); ) {
+ TypeCacheDelta delta = (TypeCacheDelta) i.next();
+ if (delta.getJob() != null && delta.getJob().equals(deltaJob)) {
+ if (jobFinished) {
+ i.remove();
+ } else {
+ delta.assignToJob(null);
+ }
+ }
+ }
+ }
+ }
+ // TODO finer-grained change deltas
+ if (fChangeListener != null)
+ fChangeListener.typeCacheChanged(fProject);
+ }
+ }
+
+ public void running(IJobChangeEvent event) {
+ }
+
+ public void scheduled(IJobChangeEvent event) {
+ }
+
+ public void sleeping(IJobChangeEvent event) {
+ }
+ };
+
+ private static class GlobalNamespace implements IQualifiedTypeName {
+
+ private static final String GLOBAL_NAMESPACE = TypeCacheMessages.getString("TypeCache.globalNamespace"); //$NON-NLS-1$
+ private static final String[] segments = new String[] { GLOBAL_NAMESPACE };
+
+ public GlobalNamespace() {
+ }
+
+ public String getName() {
+ return GLOBAL_NAMESPACE;
+ }
+
+ public String[] getEnclosingNames() {
+ return null;
+ }
+
+ public String getFullyQualifiedName() {
+ return GLOBAL_NAMESPACE;
+ }
+
+ public IQualifiedTypeName getEnclosingTypeName() {
+ return null;
+ }
+
+ public boolean isEmpty() {
+ return false;
+ }
+
+ public boolean isGlobal() {
+ return true;
+ }
+
+ public boolean isQualified() {
+ return false;
+ }
+
+ public boolean isValidSegment(String segment) {
+ return false;
+ }
+
+ public int segmentCount() {
+ return 1;
+ }
+
+ public String[] segments() {
+ return segments;
+ }
+
+ public String segment(int index) {
+ if (index > 0)
+ return null;
+ return GLOBAL_NAMESPACE;
+ }
+
+ public String lastSegment() {
+ return GLOBAL_NAMESPACE;
+ }
+
+ public int matchingFirstSegments(IQualifiedTypeName typeName) {
+ return 1;
+ }
+
+ public boolean isPrefixOf(IQualifiedTypeName typeName) {
+ return true;
+ }
+
+ public IQualifiedTypeName append(String[] names) {
+ return new QualifiedTypeName(names);
+ }
+
+ public IQualifiedTypeName append(IQualifiedTypeName typeName) {
+ return new QualifiedTypeName(typeName);
+ }
+
+ public IQualifiedTypeName append(String qualifiedName) {
+ return new QualifiedTypeName(qualifiedName);
+ }
+
+ public IQualifiedTypeName removeFirstSegments(int count) {
+ return this;
+ }
+
+ public IQualifiedTypeName removeLastSegments(int count) {
+ return this;
+ }
+
+ public boolean isLowLevel() {
+ return false;
+ }
+
+ public boolean isValid() {
+ return true;
+ }
+
+ public int hashCode() {
+ return GLOBAL_NAMESPACE.hashCode();
+ }
+
+ public String toString() {
+ return getFullyQualifiedName();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof IQualifiedTypeName)) {
+ return false;
+ }
+ return equals((IQualifiedTypeName)obj);
+ }
+
+ public int compareTo(Object obj) {
+ if (obj == this) {
+ return 0;
+ }
+ if (!(obj instanceof IQualifiedTypeName)) {
+ throw new ClassCastException();
+ }
+ return compareTo((IQualifiedTypeName)obj);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.IQualifiedTypeName#equals(org.eclipse.cdt.core.browser.IQualifiedTypeName)
+ */
+ public boolean equals(IQualifiedTypeName typeName) {
+ return (typeName instanceof GlobalNamespace);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.IQualifiedTypeName#equalsIgnoreCase(org.eclipse.cdt.core.browser.IQualifiedTypeName)
+ */
+ public boolean equalsIgnoreCase(IQualifiedTypeName typeName) {
+ return (typeName instanceof GlobalNamespace);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.IQualifiedTypeName#compareTo(org.eclipse.cdt.core.browser.IQualifiedTypeName)
+ */
+ public int compareTo(IQualifiedTypeName typeName) {
+ return getFullyQualifiedName().compareTo(typeName.getFullyQualifiedName());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.IQualifiedTypeName#compareToIgnoreCase(org.eclipse.cdt.core.browser.IQualifiedTypeName)
+ */
+ public int compareToIgnoreCase(IQualifiedTypeName typeName) {
+ return getFullyQualifiedName().compareToIgnoreCase(typeName.getFullyQualifiedName());
+ }
+ }
+
+ private static class HashKey {
+ private IQualifiedTypeName name;
+ private int type;
+ public HashKey(IQualifiedTypeName name, int type) {
+ this.name = name;
+ this.type = type;
+ }
+ public int hashCode() {
+ return (this.name.hashCode() + this.type);
+ }
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof HashKey)) {
+ return false;
+ }
+ HashKey otherKey = (HashKey)obj;
+ return (this.type == otherKey.type && this.name.equals(otherKey.name));
+ }
+ }
+
+ public TypeCache(IProject project, IWorkingCopyProvider workingCopyProvider) {
+ fProject = project;
+ fWorkingCopyProvider = workingCopyProvider;
+ fDeltas.add(new TypeCacheDelta(fProject));
+ fGlobalNamespace = new TypeInfo(ICElement.C_NAMESPACE, new GlobalNamespace());
+ fGlobalNamespace.setCache(this);
+ }
+
+ public TypeCache(IProject project, IWorkingCopyProvider workingCopyProvider, ITypeCacheChangedListener listener) {
+ this(project, workingCopyProvider);
+ fChangeListener = listener;
+ }
+
+ public boolean contains(ISchedulingRule rule) {
+ if (this == rule)
+ return true;
+ if (rule instanceof ITypeCache) {
+ ITypeCache typeCache = (ITypeCache) rule;
+ if (fProject.equals(typeCache.getProject()))
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isConflicting(ISchedulingRule rule) {
+ if (rule instanceof ITypeCache) {
+ ITypeCache typeCache = (ITypeCache) rule;
+ if (fProject.equals(typeCache.getProject()))
+ return true;
+ }
+ return false;
+ }
+
+ public IProject getProject() {
+ return fProject;
+ }
+
+ public synchronized boolean isEmpty() {
+ return fTypeKeyMap.isEmpty();
+ }
+
+ public synchronized void insert(ITypeInfo newType) {
+ // check if enclosing types are already in cache
+ IQualifiedTypeName enclosingName = newType.getQualifiedTypeName().getEnclosingTypeName();
+ if (enclosingName != null) {
+ while (!enclosingName.isEmpty()) {
+ // try namespace, class, struct, then undefined
+ ITypeInfo enclosingType = null;
+ for (int i = 0; enclosingType == null && i < ENCLOSING_TYPES.length; ++i) {
+ enclosingType = (ITypeInfo) fTypeKeyMap.get(new HashKey(enclosingName, ENCLOSING_TYPES[i]));
+ }
+ if (enclosingType == null) {
+ // create a dummy type to take this place (type 0 == unknown)
+ ITypeInfo dummyType = new TypeInfo(0, enclosingName);
+ dummyType.setCache(this);
+ fTypeKeyMap.put(new HashKey(enclosingName, 0), dummyType);
+ }
+ enclosingName = enclosingName.removeLastSegments(1);
+ }
+ }
+
+ fTypeKeyMap.put(new HashKey(newType.getQualifiedTypeName(), newType.getCElementType()), newType);
+ newType.setCache(this);
+ }
+
+ public synchronized void remove(ITypeInfo info) {
+ fTypeKeyMap.remove(new HashKey(info.getQualifiedTypeName(), info.getCElementType()));
+ info.setCache(null);
+ }
+
+ public synchronized void flush(ITypeSearchScope scope) {
+ if (scope.encloses(fProject)) {
+ flushAll();
+ } else {
+ for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) mapIter.next();
+ ITypeInfo info = (ITypeInfo) entry.getValue();
+ if (info.isEnclosed(scope)) {
+ mapIter.remove();
+ }
+ }
+ }
+ }
+
+ public synchronized void flush(IPath path) {
+ ITypeSearchScope scope = new TypeSearchScope();
+ scope.add(path, false, null);
+ flush(scope);
+ }
+
+ public synchronized void flushAll() {
+ // flush the entire cache
+ accept(new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo info) {
+ info.setCache(null);
+ return true;
+ }
+ public boolean shouldContinue() { return true; }
+ });
+ fTypeKeyMap.clear();
+ }
+
+ public synchronized void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual) {
+ Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+ if (entryCollection == null) {
+ entryCollection = new ArrayList();
+ fTypeToSuperTypes.put(type, entryCollection);
+ }
+ if (findSuperTypeEntry(entryCollection, supertype) == null) {
+ entryCollection.add(new SuperTypeEntry(supertype, access, isVirtual));
+ supertype.setCache(this);
+ }
+ }
+
+ public synchronized ITypeInfo[] getSupertypes(ITypeInfo type) {
+ Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+ if (entryCollection != null && !entryCollection.isEmpty()) {
+ ITypeInfo[] superTypes = new ITypeInfo[entryCollection.size()];
+ int count = 0;
+ for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
+ SuperTypeEntry e = (SuperTypeEntry) i.next();
+ superTypes[count++] = e.superType;
+ }
+ return superTypes;
+ }
+ return null;
+ }
+
+ public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType) {
+ Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+ if (entryCollection != null && !entryCollection.isEmpty()) {
+ SuperTypeEntry e = findSuperTypeEntry(entryCollection, superType);
+ if (e != null)
+ return e.access;
+ }
+ return null;
+ }
+
+ public synchronized void addSubtype(ITypeInfo type, ITypeInfo subtype) {
+ Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
+ if (typeCollection == null) {
+ typeCollection = new ArrayList();
+ fTypeToSubTypes.put(type, typeCollection);
+ }
+ if (!typeCollection.contains(subtype)) {
+ typeCollection.add(subtype);
+ subtype.setCache(this);
+ }
+ }
+
+ public synchronized ITypeInfo[] getSubtypes(ITypeInfo type) {
+ Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
+ if (typeCollection != null && !typeCollection.isEmpty()) {
+ return (ITypeInfo[]) typeCollection.toArray(new ITypeInfo[typeCollection.size()]);
+ }
+ return null;
+ }
+
+ public synchronized void accept(ITypeInfoVisitor visitor) {
+ for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) mapIter.next();
+ ITypeInfo info = (ITypeInfo) entry.getValue();
+ if (!visitor.shouldContinue())
+ return; // stop visiting
+ visitor.visit(info);
+ }
+ }
+
+ public synchronized IPath[] getPaths(final ITypeSearchScope scope) {
+ final Set pathSet = new HashSet();
+ accept(new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo info) {
+ if (scope == null || info.isEnclosed(scope)) {
+ ITypeReference[] refs = info.getReferences();
+ if (refs != null) {
+ for (int i = 0; i < refs.length; ++i) {
+ IPath path = refs[i].getPath();
+ if (scope == null || scope.encloses(path))
+ pathSet.add(path);
+ }
+ }
+ }
+ return true;
+ }
+ public boolean shouldContinue() { return true; }
+ });
+ return (IPath[]) pathSet.toArray(new IPath[pathSet.size()]);
+ }
+
+ public synchronized ITypeInfo[] getTypes(final ITypeSearchScope scope) {
+ final Collection results = new ArrayList();
+ accept(new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo info) {
+ if (scope == null || info.isEnclosed(scope)) {
+ results.add(info);
+ }
+ return true;
+ }
+ public boolean shouldContinue() { return true; }
+ });
+ return (ITypeInfo[]) results.toArray(new ITypeInfo[results.size()]);
+ }
+
+ public synchronized ITypeInfo[] getTypes(IQualifiedTypeName qualifiedName, boolean matchEnclosed, boolean ignoreCase) {
+ Collection results = new ArrayList();
+ if (!ignoreCase && !matchEnclosed) {
+ for (int i = 0; i < ITypeInfo.KNOWN_TYPES.length; ++i) {
+ ITypeInfo info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, ITypeInfo.KNOWN_TYPES[i]));
+ if (info != null) {
+ results.add(info);
+ }
+ }
+ ITypeInfo info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, 0));
+ if (info != null) {
+ results.add(info);
+ }
+ } else {
+ // TODO this should probably use a more efficient search algorithm
+ for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) mapIter.next();
+ ITypeInfo info = (ITypeInfo) entry.getValue();
+ IQualifiedTypeName currName = info.getQualifiedTypeName();
+
+ if (ignoreCase) {
+ if (matchEnclosed && currName.segmentCount() > qualifiedName.segmentCount()
+ && currName.lastSegment().equalsIgnoreCase(qualifiedName.lastSegment())) {
+ currName = currName.removeFirstSegments(currName.segmentCount() - qualifiedName.segmentCount());
+ }
+ if (currName.equalsIgnoreCase(qualifiedName)) {
+ results.add(info);
+ }
+ } else {
+ if (matchEnclosed && currName.segmentCount() > qualifiedName.segmentCount()
+ && currName.lastSegment().equals(qualifiedName.lastSegment())) {
+ currName = currName.removeFirstSegments(currName.segmentCount() - qualifiedName.segmentCount());
+ }
+ if (currName.equals(qualifiedName)) {
+ results.add(info);
+ }
+ }
+ }
+ }
+ return (ITypeInfo[]) results.toArray(new ITypeInfo[results.size()]);
+ }
+
+ public synchronized ITypeInfo getType(int type, IQualifiedTypeName qualifiedName) {
+ ITypeInfo info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, type));
+ if (info == null && type != 0) {
+ info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, 0));
+ }
+ return info;
+ }
+
+ public synchronized ITypeInfo getEnclosingType(ITypeInfo info, final int[] kinds) {
+ IQualifiedTypeName enclosingName = info.getQualifiedTypeName().getEnclosingTypeName();
+ if (enclosingName != null) {
+ // try namespace, class, struct, then undefined
+ ITypeInfo enclosingType = null;
+ for (int i = 0; enclosingType == null && i < ENCLOSING_TYPES.length; ++i) {
+ if (ArrayUtil.contains(kinds, ENCLOSING_TYPES[i])) {
+ enclosingType = (ITypeInfo) fTypeKeyMap.get(new HashKey(enclosingName, ENCLOSING_TYPES[i]));
+ }
+ }
+ return enclosingType;
+ }
+ return null;
+ }
+
+ public synchronized ITypeInfo getEnclosingNamespace(ITypeInfo info, boolean includeGlobalNamespace) {
+ IQualifiedTypeName enclosingName = info.getQualifiedTypeName().getEnclosingTypeName();
+ if (enclosingName != null) {
+ // look for namespace
+ ITypeInfo enclosingType = (ITypeInfo) fTypeKeyMap.get(new HashKey(enclosingName, ICElement.C_NAMESPACE));
+ if (enclosingType != null) {
+ return enclosingType;
+ }
+ // try class, struct, then undefined
+ final int[] kinds = {ICElement.C_CLASS, ICElement.C_STRUCT, 0};
+ for (int i = 0; enclosingType == null && i < kinds.length; ++i) {
+ enclosingType = (ITypeInfo) fTypeKeyMap.get(new HashKey(enclosingName, kinds[i]));
+ }
+ if (enclosingType != null) {
+ return getEnclosingNamespace(enclosingType, includeGlobalNamespace);
+ }
+ }
+ if (includeGlobalNamespace)
+ return fGlobalNamespace;
+ return null;
+ }
+
+ public synchronized ITypeInfo getRootNamespace(ITypeInfo info, boolean includeGlobalNamespace) {
+ IQualifiedTypeName qualifiedName = info.getQualifiedTypeName();
+ if (qualifiedName.isGlobal()) {
+ if (info.getCElementType() == ICElement.C_NAMESPACE)
+ return info;
+ if (includeGlobalNamespace)
+ return fGlobalNamespace;
+ return null;
+ }
+ IQualifiedTypeName namespace = qualifiedName.removeLastSegments(qualifiedName.segmentCount()-1);
+ // try namespace, then undefined
+ ITypeInfo namespaceType = (ITypeInfo) fTypeKeyMap.get(new HashKey(namespace, ICElement.C_NAMESPACE));
+ if (namespaceType == null)
+ namespaceType = (ITypeInfo) fTypeKeyMap.get(new HashKey(namespace, 0));
+ return namespaceType;
+ }
+
+ public synchronized boolean hasEnclosedTypes(final ITypeInfo info) {
+ final IQualifiedTypeName parentName = info.getQualifiedTypeName();
+ final boolean[] foundTypes = { false };
+ accept(new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo type) {
+ if (type != info && parentName.isPrefixOf(type.getQualifiedTypeName())) {
+ foundTypes[0] = true;
+ }
+ return true;
+ }
+ public boolean shouldContinue() {
+ return !foundTypes[0];
+ }
+ });
+ return foundTypes[0];
+ }
+
+ public synchronized ITypeInfo[] getEnclosedTypes(final ITypeInfo enclosedBy, final int kinds[]) {
+ final IQualifiedTypeName parentName = enclosedBy.getQualifiedTypeName();
+ final Collection results = new ArrayList();
+ accept(new ITypeInfoVisitor() {
+ public boolean visit(ITypeInfo type) {
+ if (ArrayUtil.contains(kinds, type.getCElementType())) {
+ IQualifiedTypeName enclosingName = type.getQualifiedTypeName().getEnclosingTypeName();
+ if (enclosedBy == fGlobalNamespace) {
+ if (enclosingName == null) {
+ results.add(type);
+ } else {
+// // check if enclosing parent is namespace
+// getRootNamespace(type);
+ }
+ } else if (parentName.equals(enclosingName)) {
+ results.add(type);
+ }
+ }
+ return true;
+ }
+ public boolean shouldContinue() { return true; }
+ });
+
+ return (ITypeInfo[]) results.toArray(new ITypeInfo[results.size()]);
+ }
+
+ public ITypeInfo getGlobalNamespace() {
+ return fGlobalNamespace;
+ }
+
+ public boolean isUpToDate() {
+ synchronized(fDeltas) {
+ return fDeltas.isEmpty();
+ }
+ }
+
+ public void addDelta(TypeCacheDelta delta) {
+ synchronized(fDeltas) {
+ fDeltas.add(delta);
+ }
+ }
+
+ public void reconcile(boolean enableIndexing, int priority, int delay) {
+ // check if anything needs to be done
+ if (deltasRemaining() == 0)
+ return; // nothing to do
+
+ // cancel any scheduled or running jobs for this project
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(TypeCacherJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ TypeCacherJob deltaJob = (TypeCacherJob) jobs[i];
+ if (deltaJob.getCache().equals(this)) {
+ deltaJob.cancel();
+ }
+ }
+
+ // check again, in case some jobs finished in the meantime
+ if (deltasRemaining() == 0)
+ return; // nothing to do
+
+ TypeCacherJob deltaJob = null;
+ IndexManager indexManager = CModelManager.getDefault().getIndexManager();
+ ICDTIndexer indexer = indexManager.getIndexerForProject( fProject );
+ boolean haveIndexer = (indexer != null && indexer.isIndexEnabled( fProject ));
+ synchronized(fDeltas) {
+ if( haveIndexer ){
+ // grab all the remaining deltas
+ TypeCacheDelta[] jobDeltas = (TypeCacheDelta[]) fDeltas.toArray(new TypeCacheDelta[fDeltas.size()]);
+
+ // assign deltas to job
+ if (jobDeltas != null) {
+ // create a new job
+ deltaJob = new TypeCacherJob(this, jobDeltas, enableIndexing);
+ for (int i = 0; i < jobDeltas.length; ++i) {
+ jobDeltas[i].assignToJob(deltaJob);
+ fDeltas.remove(jobDeltas[i]);
+ }
+ }
+ } else {
+ //we don't have an indexer, don't create a job to do these deltas, throw them away
+ fDeltas.clear();
+ }
+ }
+
+ if( deltaJob != null ){
+ // schedule the new job
+ deltaJob.addJobChangeListener(fJobChangeListener);
+ deltaJob.setPriority(priority);
+ deltaJob.schedule(delay);
+ }
+ }
+
+ public void reconcileAndWait(boolean enableIndexing, int priority, IProgressMonitor monitor) {
+ reconcile(enableIndexing, priority, 0);
+
+ // wait for jobs to complete
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(TypeCacherJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ TypeCacherJob deltaJob = (TypeCacherJob) jobs[i];
+ if (deltaJob.getCache().equals(this)) {
+ try {
+ deltaJob.join(monitor);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ // returns the number of deltas either not assigned to a job,
+ // or assigned to a job which is not yet running
+ private int deltasRemaining() {
+ // count the left-over deltas
+ synchronized(fDeltas) {
+ int count = 0;
+ for (Iterator i = fDeltas.iterator(); i.hasNext(); ) {
+ TypeCacheDelta delta = (TypeCacheDelta) i.next();
+ TypeCacherJob job = delta.getJob();
+ if (job == null || !job.isRunning()) {
+ ++count;
+ }
+ }
+ return count;
+ }
+ }
+
+ public void cancelJobs() {
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(TypeCacherJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ TypeCacherJob deltaJob = (TypeCacherJob) jobs[i];
+ if (deltaJob.getCache().equals(this)) {
+ deltaJob.cancel();
+ }
+ }
+ jobs = jobManager.find(TypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ TypeLocatorJob locatorJob = (TypeLocatorJob) jobs[i];
+ if (locatorJob.getType().getEnclosingProject().equals(fProject)) {
+ locatorJob.cancel();
+ }
+ }
+ jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().getEnclosingProject().equals(fProject)) {
+ locatorJob.cancel();
+ }
+ }
+ }
+
+ public void locateType(ITypeInfo info, int priority, int delay) {
+ ITypeReference location = info.getResolvedReference();
+ if (location != null)
+ return; // nothing to do
+
+ // cancel any scheduled or running jobs for this type
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(TypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ TypeLocatorJob locatorJob = (TypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ locatorJob.cancel();
+ }
+ }
+
+ // check again, in case some jobs finished in the meantime
+ location = info.getResolvedReference();
+ if (location != null)
+ return; // nothing to do
+
+ // create a new job
+ TypeLocatorJob locatorJob = new TypeLocatorJob(info, this, fWorkingCopyProvider);
+ // schedule the new job
+ locatorJob.setPriority(priority);
+ locatorJob.schedule(delay);
+ }
+
+ public ITypeReference locateTypeAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
+ locateType(info, priority, 0);
+
+ // wait for jobs to complete
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(TypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ TypeLocatorJob locatorJob = (TypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ try {
+ locatorJob.join(monitor);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ return info.getResolvedReference();
+ }
+
+ public void locateSupertypes(ITypeInfo info, int priority, int delay) {
+ ITypeInfo[] superTypes = getSupertypes(info);
+ if (superTypes != null)
+ return; // nothing to do
+
+ locateType(info, priority, delay);
+ }
+
+ public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
+ locateSupertypes(info, priority, 0);
+
+ // wait for jobs to complete
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ try {
+ locatorJob.join(monitor);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ return getSupertypes(info);
+ }
+
+ public void locateSubtypes(ITypeInfo info, int priority, int delay) {
+ ITypeInfo[] subTypes = getSubtypes(info);
+ if (subTypes != null)
+ return; // nothing to do
+
+ // cancel any scheduled or running jobs for this type
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ locatorJob.cancel();
+ }
+ }
+
+ // check again, in case some jobs finished in the meantime
+ subTypes = getSubtypes(info);
+ if (subTypes != null)
+ return; // nothing to do
+
+ // create a new job
+ SubTypeLocatorJob locatorJob = new SubTypeLocatorJob(info, this, fWorkingCopyProvider);
+ // schedule the new job
+ locatorJob.setPriority(priority);
+ locatorJob.schedule(delay);
+ }
+
+ public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
+ locateSubtypes(info, priority, 0);
+
+ // wait for jobs to complete
+ IJobManager jobManager = Platform.getJobManager();
+ Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+ for (int i = 0; i < jobs.length; ++i) {
+ SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+ if (locatorJob.getType().equals(info)) {
+ try {
+ locatorJob.join(monitor);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ return getSubtypes(info);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheDelta.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheDelta.java
new file mode 100644
index 00000000000..6b897bdb3ec
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheDelta.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * 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.cache;
+
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.TypeSearchScope;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.core.resources.IProject;
+
+
+public class TypeCacheDelta {
+ private IProject fProject = null;
+ private ICElementDelta fCElementDelta = null;
+ private ITypeSearchScope fScope = null;
+ private TypeCacherJob fJob = null;
+
+ public TypeCacheDelta(IProject project, ICElementDelta delta) {
+ fProject = project;
+ fCElementDelta = delta;
+ }
+
+ public TypeCacheDelta(IProject project, ITypeSearchScope scope) {
+ fProject = project;
+ fScope = scope;
+ }
+
+ public TypeCacheDelta(IProject project) {
+ fProject = project;
+ fScope = new TypeSearchScope();
+ fScope.add(project);
+ }
+
+ public IProject getProject() {
+ return fProject;
+ }
+
+ public ITypeSearchScope getScope() {
+ return fScope;
+ }
+
+ public ICElementDelta getCElementDelta() {
+ return fCElementDelta;
+ }
+
+ public void assignToJob(TypeCacherJob job) {
+ fJob = job;
+ }
+
+ public TypeCacherJob getJob() {
+ return fJob;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java
new file mode 100644
index 00000000000..623488a179a
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java
@@ -0,0 +1,471 @@
+/*******************************************************************************
+ * 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.internal.core.browser.cache;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.browser.IQualifiedTypeName;
+import org.eclipse.cdt.core.browser.ITypeCacheChangedListener;
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.ITypeReference;
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.cdt.core.browser.TypeSearchScope;
+import org.eclipse.cdt.core.browser.TypeUtil;
+import org.eclipse.cdt.core.model.ElementChangedEvent;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.internal.core.model.CModelManager;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.Job;
+
+public class TypeCacheManager implements ITypeCacheChangedListener, IndexManager.IIndexerSelectionListener {
+ private static final TypeCacheManager fgInstance = new TypeCacheManager();
+ private Map fCacheMap;
+ private IWorkingCopyProvider fWorkingCopyProvider;
+ private ArrayList fChangeListeners = new ArrayList();
+
+ private static final int INITIAL_TYPE_MAP_SIZE = 50;
+ //TODO make this a WeakHashMap or LRUCache
+ private Map fTypeToElementMap = new HashMap(INITIAL_TYPE_MAP_SIZE);
+ private Map fElementToTypeMap = new HashMap(INITIAL_TYPE_MAP_SIZE);
+ private boolean processTypeCacheEvents = true;
+
+ private TypeCacheManager() {
+ fCacheMap = new HashMap();
+ CModelManager.getDefault().getIndexManager().subscribeForIndexerChangeNotifications( this );
+ }
+
+ public static TypeCacheManager getInstance() {
+ return fgInstance;
+ }
+
+ protected void finalize() throws Throwable {
+ CModelManager.getDefault().getIndexManager().unSubscribeForIndexerChangeNotifications( this );
+ super.finalize();
+ }
+
+ public void setWorkingCopyProvider(IWorkingCopyProvider workingCopyProvider) {
+ fWorkingCopyProvider = workingCopyProvider;
+ }
+
+ public synchronized void updateProject(IProject project) {
+ // TODO finer-grained flush needed, for now just flush the whole map
+ fTypeToElementMap.clear();
+ fElementToTypeMap.clear();
+ addCacheDelta(project, null);
+ }
+
+ public synchronized void processElementChanged(ElementChangedEvent event, boolean enableIndexing) {
+ int deltaCount = processDelta(event.getDelta());
+ if (deltaCount > 0) {
+ // TODO finer-grained flush needed, for now just flush the whole map
+ fTypeToElementMap.clear();
+ fElementToTypeMap.clear();
+ reconcile(enableIndexing, Job.BUILD, 0);
+ }
+ }
+
+ private static final int PATH_ENTRY_FLAGS = ICElementDelta.F_ADDED_PATHENTRY_SOURCE
+ | ICElementDelta.F_REMOVED_PATHENTRY_SOURCE
+ | ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE
+ | ICElementDelta.F_CHANGED_PATHENTRY_MACRO
+ | ICElementDelta.F_PATHENTRY_REORDER;
+
+ private int processDelta(ICElementDelta delta) {
+ ICElement elem = delta.getElement();
+ boolean added = (delta.getKind() == ICElementDelta.ADDED);
+ boolean removed = (delta.getKind() == ICElementDelta.REMOVED);
+ boolean contentChanged = ((delta.getFlags() & ICElementDelta.F_CONTENT) != 0);
+ boolean pathEntryChanged = ((delta.getFlags() & PATH_ENTRY_FLAGS) != 0);
+ boolean openedOrClosed = (((delta.getFlags() & ICElementDelta.F_CLOSED) != 0) || ((delta.getFlags() & ICElementDelta.F_OPENED) != 0));
+ boolean hasChildren = ((delta.getFlags() & ICElementDelta.F_CHILDREN) != 0);
+ int deltaCount = 0;
+
+
+ switch (elem.getElementType()) {
+ case ICElement.C_PROJECT:
+ case ICElement.C_CCONTAINER: {
+ ICProject cProject = elem.getCProject();
+ IProject project = cProject.getProject();
+ if (added || removed || pathEntryChanged || openedOrClosed) {
+ addCacheDelta(project, delta);
+ ++deltaCount;
+ }
+ }
+ break;
+
+ case ICElement.C_UNIT: {
+ ICProject cProject = elem.getCProject();
+ IProject project = cProject.getProject();
+ ITranslationUnit unit = (ITranslationUnit) elem;
+ if (unit.isWorkingCopy()) {
+ deltaCount += processWorkingCopyDelta(delta);
+ return deltaCount;
+ }
+ if (added || removed || pathEntryChanged || contentChanged) {
+ addCacheDelta(project, delta);
+ ++deltaCount;
+ }
+ }
+ 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 cProject = elem.getCProject();
+ IProject project = cProject.getProject();
+ if (added || removed) {
+ addCacheDelta(project, delta);
+ ++deltaCount;
+ }
+ }
+ break;
+ }
+
+ if (hasChildren) {
+ ICElementDelta[] children = delta.getAffectedChildren();
+ if (children != null) {
+ for (int i = 0; i < children.length; ++i) {
+ deltaCount += processDelta(children[i]);
+ }
+ }
+ }
+
+ return deltaCount;
+ }
+
+ private void addCacheDelta(IProject project, ICElementDelta delta) {
+ if (delta == null) {
+ getCache(project).addDelta(new TypeCacheDelta(project));
+ } else {
+ getCache(project).addDelta(new TypeCacheDelta(project, delta));
+ }
+ }
+
+ private int processWorkingCopyDelta(ICElementDelta delta) {
+ // ignore workies copies for now
+ return 0;
+/* ICElement elem = delta.getElement();
+ boolean added = (delta.getKind() == ICElementDelta.ADDED);
+ boolean removed = (delta.getKind() == ICElementDelta.REMOVED);
+ boolean contentChanged = ((delta.getFlags() & ICElementDelta.F_CONTENT) != 0);
+ boolean pathEntryChanged = ((delta.getFlags() & PATH_ENTRY_FLAGS) != 0);
+ boolean hasChildren = ((delta.getFlags() & ICElementDelta.F_CHILDREN) != 0);
+
+ switch (elem.getElementType()) {
+ case ICElement.C_UNIT: {
+ ICProject cProject = elem.getCProject();
+ IProject project = cProject.getProject();
+ if (added || removed || pathEntryChanged || contentChanged) {
+ TypeCacheDelta cacheDelta = new TypeCacheDelta(project, delta);
+ getCache(project).addDelta(cacheDelta);
+ }
+ }
+ 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 cProject = elem.getCProject();
+ IProject project = cProject.getProject();
+ if (added || removed) {
+ TypeCacheDelta cacheDelta = new TypeCacheDelta(project, delta);
+ getCache(project).addDelta(cacheDelta);
+ }
+ }
+ break;
+ }
+
+ if (hasChildren) {
+ ICElementDelta[] children = delta.getAffectedChildren();
+ if (children != null) {
+ for (int i = 0; i < children.length; ++i) {
+ processWorkingCopyDelta(children[i]);
+ }
+ }
+ }
+*/
+ }
+
+ public synchronized ITypeCache getCache(IProject project) {
+ synchronized(fCacheMap) {
+ ITypeCache cache = (ITypeCache) fCacheMap.get(project);
+ if (cache == null) {
+ cache = new TypeCache(project, fWorkingCopyProvider, this);
+ fCacheMap.put(project, cache);
+ }
+ return cache;
+ }
+ }
+
+ public synchronized void reconcile(boolean enableIndexing, int priority, int delay) {
+ if (!(processTypeCacheEvents))
+ return;
+
+ TypeSearchScope workspaceScope = new TypeSearchScope(true);
+ IProject[] projects = workspaceScope.getEnclosingProjects();
+ for (int i = 0; i < projects.length; ++i) {
+ ITypeCache cache = getCache(projects[i]);
+ cache.reconcile(enableIndexing, priority, delay);
+ }
+ }
+
+ public synchronized void reconcileAndWait(boolean enableIndexing, int priority, IProgressMonitor monitor) {
+ if (!(processTypeCacheEvents))
+ return;
+
+ TypeSearchScope workspaceScope = new TypeSearchScope(true);
+ IProject[] projects = workspaceScope.getEnclosingProjects();
+ for (int i = 0; i < projects.length; ++i) {
+ ITypeCache cache = getCache(projects[i]);
+ cache.reconcileAndWait(enableIndexing, priority, monitor);
+ }
+ }
+
+ public void cancelJobs() {
+ IJobManager jobManager = Platform.getJobManager();
+ jobManager.cancel(TypeCacherJob.FAMILY);
+ jobManager.cancel(TypeLocatorJob.FAMILY);
+ }
+
+ public ITypeInfo[] locateSuperTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
+ ITypeInfo[] superTypes = info.getSuperTypes();
+ if (superTypes == null) {
+ // cancel background jobs
+ IProject project = info.getEnclosingProject();
+ getCache(project).cancelJobs();
+
+ // start the search job
+ getCache(project).locateSupertypesAndWait(info, priority, monitor);
+
+ superTypes = info.getSuperTypes();
+
+ // resume background jobs
+ reconcile(enableIndexing, Job.BUILD, 0);
+ }
+ return superTypes;
+ }
+
+ public ITypeInfo[] locateSubTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
+ ITypeInfo[] subTypes = info.getSubTypes();
+ if (subTypes == null) {
+ // cancel background jobs
+ IProject project = info.getEnclosingProject();
+ getCache(project).cancelJobs();
+
+ // start the search job
+ getCache(project).locateSubtypesAndWait(info, priority, monitor);
+
+ subTypes = info.getSubTypes();
+
+ // resume background jobs
+ reconcile(enableIndexing, Job.BUILD, 0);
+ }
+ return subTypes;
+ }
+
+ public void updateCache(ITypeSearchScope scope, IProgressMonitor monitor) {
+ // schedule jobs to update cache
+ IProject[] projects = scope.getEnclosingProjects();
+ monitor.beginTask(TypeCacheMessages.getString("AllTypesCache.updateCache.taskName"), projects.length); //$NON-NLS-1$
+ for (int i = 0; i < projects.length; ++i) {
+ IProject project = projects[i];
+ // wait for any running jobs to finish
+ getCache(project).reconcileAndWait(true, Job.SHORT, new SubProgressMonitor(monitor, 1));
+ }
+ monitor.done();
+ }
+
+ /**
+ * Resolves a type location.
+ *
+ * @param info the type to search for
+ * @param monitor the progress monitor
+ */
+ public ITypeReference resolveTypeLocation(ITypeInfo info, IProgressMonitor monitor, boolean enableIndexing) {
+ ITypeReference location = info.getResolvedReference();
+ if (location == null) {
+ // cancel background jobs
+ IProject project = info.getEnclosingProject();
+ ITypeCache cache = getCache(project);
+ cache.cancelJobs();
+
+ // start the search job
+ cache.locateTypeAndWait(info, Job.SHORT, monitor);
+
+ // get the newly parsed location
+ location = info.getResolvedReference();
+
+ // resume background jobs
+ reconcile(enableIndexing, Job.BUILD, 0);
+ }
+ return location;
+ }
+
+ public void addTypeCacheChangedListener(ITypeCacheChangedListener listener) {
+ // add listener only if it is not already present
+ synchronized(fChangeListeners) {
+ if (!fChangeListeners.contains(listener)) {
+ fChangeListeners.add(listener);
+ }
+ }
+ }
+
+ public void removeTypeCacheChangedListener(ITypeCacheChangedListener listener) {
+ synchronized(fChangeListeners) {
+ fChangeListeners.remove(listener);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.browser.ITypeCacheChangedListener#typeCacheChanged(org.eclipse.core.resources.IProject)
+ */
+ public synchronized void typeCacheChanged(final IProject project) {
+ // clone so that a listener cannot have a side-effect on this list when being notified
+ ArrayList listeners;
+ synchronized(fChangeListeners) {
+ listeners = (ArrayList) fChangeListeners.clone();
+ }
+ for (Iterator i = listeners.iterator(); i.hasNext(); ) {
+ final ITypeCacheChangedListener listener = (ITypeCacheChangedListener) i.next();
+ Platform.run(new ISafeRunnable() {
+ public void handleException(Throwable e) {
+ IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, IStatus.ERROR, "Exception occurred in listener of type cache change notification", e); //$NON-NLS-1$
+ CCorePlugin.log(status);
+ }
+ public void run() throws Exception {
+ listener.typeCacheChanged(project);
+ }
+ });
+ }
+ }
+
+ public ITypeInfo getTypeForElement(ICElement element, boolean forceUpdate, boolean forceResolve, boolean enableIndexing, IProgressMonitor monitor) {
+ if (element.exists()) {
+ ITypeInfo cachedInfo = (ITypeInfo) fElementToTypeMap.get(element);
+ if (cachedInfo != null && cachedInfo.exists())
+ return cachedInfo;
+ }
+
+ IQualifiedTypeName qualifiedName = TypeUtil.getFullyQualifiedName(element);
+ if (qualifiedName != null) {
+ ICProject cProject = element.getCProject();
+ IProject project = cProject.getProject();
+ ITypeCache cache = getCache(project);
+ if (!cache.isUpToDate() && forceUpdate) {
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+ // wait for any running jobs to finish
+ cache.reconcileAndWait(true, Job.SHORT, monitor);
+ }
+
+ ITypeInfo info = cache.getType(element.getElementType(), qualifiedName);
+ if (info != null) {
+ ITypeReference ref = info.getResolvedReference();
+ if (ref == null && forceResolve) {
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+ ref = resolveTypeLocation(info, monitor, enableIndexing);
+ }
+
+ // cache for later use
+ fElementToTypeMap.put(element, info);
+ return info;
+ }
+ }
+ return null;
+ }
+
+ public ICElement getElementForType(ITypeInfo type, boolean forceUpdate, boolean forceResolve, boolean enableIndexing, IProgressMonitor monitor) {
+ if (type.exists()) {
+ ICElement cachedElem = (ICElement) fTypeToElementMap.get(type);
+ if (cachedElem != null && cachedElem.exists())
+ return cachedElem;
+ }
+
+ IProject project = type.getEnclosingProject();
+ ITypeCache cache = getCache(project);
+ if (!cache.isUpToDate() && forceUpdate) {
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+ // wait for any running jobs to finish
+ cache.reconcileAndWait(true, Job.SHORT, monitor);
+
+ //TODO replace type with new type from cache???
+ }
+
+ ITypeReference ref = type.getResolvedReference();
+ if (ref == null && forceResolve) {
+ ref = resolveTypeLocation(type, monitor, enableIndexing);
+ }
+ if (ref != null) {
+ ICElement[] elems = ref.getCElements();
+ if (elems != null && elems.length > 0) {
+ ICElement foundElem = elems[0];
+ if (elems.length > 1) {
+ for (int i = 0; i < elems.length; ++i) {
+ ICElement elem = elems[i];
+ if (elem.getElementType() == type.getCElementType() && elem.getElementName().equals(type.getName())) {
+ //TODO should check fully qualified name
+ foundElem = elem;
+ break;
+ }
+ }
+ }
+
+ if (foundElem != null) {
+ // cache for later use
+ fTypeToElementMap.put(type, foundElem);
+ return foundElem;
+ }
+ }
+ }
+ return null;
+ }
+ public boolean getProcessTypeCacheEvents() {
+ return processTypeCacheEvents;
+ }
+ public void setProcessTypeCacheEvents(boolean processTypeCacheEvents) {
+ this.processTypeCacheEvents = processTypeCacheEvents;
+ }
+
+ public void indexerSelectionChanged(IProject project) {
+ addCacheDelta(project, null );
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.java
new file mode 100644
index 00000000000..30e20e62572
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the 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.cache;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class TypeCacheMessages {
+
+ private static final String RESOURCE_BUNDLE= TypeCacheMessages.class.getName();
+
+ private static ResourceBundle fgResourceBundle;
+ static {
+ try {
+ fgResourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE);
+ } catch (MissingResourceException x) {
+ fgResourceBundle = null;
+ }
+ }
+
+ private TypeCacheMessages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return fgResourceBundle.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ } catch (NullPointerException e) {
+ return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ public static String getFormattedString(String key, String arg) {
+ return getFormattedString(key, new String[] { arg });
+ }
+
+ public static String getFormattedString(String key, String[] args) {
+ return MessageFormat.format(getString(key), args);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties
new file mode 100644
index 00000000000..c4d26740d29
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties
@@ -0,0 +1,23 @@
+###############################################################################
+# Copyright (c) 2000, 2004 QNX Software Systems and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the 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
+###############################################################################
+
+AllTypesCache.updateCache.taskName=Updating Type Cache...
+
+TypeCacherJob.defaultJobName=Type Cache
+TypeCacherJob.jobName=Type Cache [{0}]
+TypeCacherJob.taskName=Updating Type Cache...
+
+TypeLocatorJob.jobName=Type Locator
+TypeLocatorJob.taskName=Searching for Type Declaration...
+SubTypeLocatorJob.jobName=Subtype Locator
+SubTypeLocatorJob.taskName=Searching for Subtypes...
+
+TypeCache.globalNamespace=(global)
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java
new file mode 100644
index 00000000000..3cb779f2e13
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * 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.internal.core.browser.cache;
+
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.TypeSearchScope;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.search.ICSearchConstants;
+import org.eclipse.cdt.internal.core.index.IIndex;
+import org.eclipse.cdt.internal.core.model.CModelManager;
+import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+
+/**
+ * Background job for filling the type cache.
+ * @see org.eclipse.core.runtime.jobs.Job
+ * @since 3.0
+ */
+public class TypeCacherJob extends BasicJob {
+
+ public static final Object FAMILY = new Object();
+ private IndexManager fIndexManager;
+ private ITypeCache fTypeCache;
+ private TypeCacheDelta[] fDeltas;
+ private boolean fEnableIndexing;
+ private boolean fIndexerIsBusy;
+
+ public TypeCacherJob(ITypeCache typeCache, TypeCacheDelta[] deltas, boolean enableIndexing) {
+ super(TypeCacheMessages.getString("TypeCacherJob.defaultJobName"), FAMILY); //$NON-NLS-1$
+ fTypeCache = typeCache;
+ fDeltas = deltas;
+ fEnableIndexing = enableIndexing;
+ fIndexerIsBusy = false;
+ fIndexManager = CModelManager.getDefault().getIndexManager();
+ setPriority(BUILD);
+ setSystem(true);
+ setRule(typeCache);
+ setName(TypeCacheMessages.getFormattedString("TypeCacherJob.jobName", fTypeCache.getProject().getName())); //$NON-NLS-1$
+ }
+
+ public ITypeCache getCache() {
+ return fTypeCache;
+ }
+
+ public TypeCacheDelta[] getDeltas() {
+ return fDeltas;
+ }
+
+ public boolean isIndexerBusy() {
+ return fIndexerIsBusy;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor)
+ */
+ protected IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException {
+ boolean success = false;
+ long startTime = System.currentTimeMillis();
+ trace("TypeCacherJob: started"); //$NON-NLS-1$
+
+ try {
+ int totalWork = 100;
+ monitor.beginTask(TypeCacheMessages.getString("TypeCacherJob.taskName"), totalWork); //$NON-NLS-1$
+
+ // figure out what needs to be flushed
+ TypeSearchScope flushScope = new TypeSearchScope();
+ if (fDeltas != null) {
+ for (int i = 0; i < fDeltas.length; ++i) {
+ TypeCacheDelta delta = fDeltas[i];
+ prepareToFlush(delta, flushScope);
+ }
+ }
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ // flush the cache
+ int flushWork = 0;
+ if (!flushScope.isEmpty()) {
+ flushWork = totalWork / 4;
+ IProgressMonitor subMonitor = new SubProgressMonitor(monitor, flushWork);
+ flush(flushScope, subMonitor);
+ }
+
+ // update the cache
+ IProgressMonitor subMonitor = new SubProgressMonitor(monitor, totalWork - flushWork);
+ update(flushScope, subMonitor);
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+ } finally {
+ long executionTime = System.currentTimeMillis() - startTime;
+ if (success)
+ trace("TypeCacherJob: completed ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+ else
+ trace("TypeCacherJob: aborted ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ monitor.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ private void flush(ITypeSearchScope scope, IProgressMonitor monitor) throws InterruptedException {
+ // flush the cache
+ boolean success = true;
+ IProject project = fTypeCache.getProject();
+
+ monitor.beginTask("", 100); //$NON-NLS-1$
+
+ fTypeCache.flush(scope);
+ if (!scope.encloses(project)) {
+ if (project.exists() && project.isOpen()) {
+ success = doIndexerJob(new IndexerDependenciesJob(fIndexManager, fTypeCache, scope), monitor);
+ }
+ }
+
+ if (!success || monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ monitor.done();
+ }
+
+ private void update(ITypeSearchScope scope, IProgressMonitor monitor) throws InterruptedException {
+ boolean success = true;
+ IProject project = fTypeCache.getProject();
+
+ monitor.beginTask("", 100); //$NON-NLS-1$
+ if (project.exists() && project.isOpen()) {
+ success = doIndexerJob(new IndexerTypesJob2(fIndexManager, fTypeCache, scope), monitor);
+ }
+
+ if (!success || monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ monitor.done();
+ }
+
+ private boolean doIndexerJob(IndexerJob job, IProgressMonitor monitor) {
+ if (!fEnableIndexing) {
+ return false;
+ }
+
+ // check if indexer is busy
+ fIndexerIsBusy = false;
+ try {
+ fIndexManager.performConcurrentJob(new DummyIndexerJob(fIndexManager, fTypeCache.getProject()),
+ ICSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH, new NullProgressMonitor(), null);
+ } catch (OperationCanceledException e) {
+ fIndexerIsBusy = true;
+ }
+
+ // do an immediate (but possibly incomplete) search
+ // if fIndexerIsBusy the cache will stay dirty and we'll hit the indexer again next time
+ return fIndexManager.performConcurrentJob(job,
+ ICSearchConstants.FORCE_IMMEDIATE_SEARCH, monitor, null);
+ }
+
+ private boolean doIndexerJob(IndexerJob2 job, IProgressMonitor monitor) {
+ if (!fEnableIndexing) {
+ return false;
+ }
+
+ // check if indexer is busy
+ fIndexerIsBusy = false;
+ try {
+ fIndexManager.performConcurrentJob(new DummyIndexerJob(fIndexManager, fTypeCache.getProject()),
+ ICSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH, new NullProgressMonitor(), null);
+ } catch (OperationCanceledException e) {
+ fIndexerIsBusy = true;
+ }
+
+ // do an immediate (but possibly incomplete) search
+ // if fIndexerIsBusy the cache will stay dirty and we'll hit the indexer again next time
+ return fIndexManager.performConcurrentJob(job,
+ ICSearchConstants.FORCE_IMMEDIATE_SEARCH, monitor, null);
+ }
+
+
+ private static final int PATH_ENTRY_FLAGS = ICElementDelta.F_ADDED_PATHENTRY_SOURCE
+ | ICElementDelta.F_REMOVED_PATHENTRY_SOURCE
+ | ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE
+ | ICElementDelta.F_CHANGED_PATHENTRY_MACRO
+ | ICElementDelta.F_PATHENTRY_REORDER;
+
+ private void prepareToFlush(TypeCacheDelta cacheDelta, ITypeSearchScope scope) {
+ ITypeSearchScope deltaScope = cacheDelta.getScope();
+ if (deltaScope != null)
+ scope.add(deltaScope);
+
+ ICElementDelta delta = cacheDelta.getCElementDelta();
+ if (delta != null) {
+ ICElement elem = delta.getElement();
+ boolean added = (delta.getKind() == ICElementDelta.ADDED);
+ boolean removed = (delta.getKind() == ICElementDelta.REMOVED);
+ boolean contentChanged = ((delta.getFlags() & ICElementDelta.F_CONTENT) != 0);
+ boolean pathEntryChanged = ((delta.getFlags() & PATH_ENTRY_FLAGS) != 0);
+
+ switch (elem.getElementType()) {
+ case ICElement.C_MODEL: {
+ if (added || removed) {
+ scope.add(elem);
+ }
+ }
+ break;
+
+ case ICElement.C_PROJECT: {
+ if (added || removed || pathEntryChanged) {
+ scope.add(elem);
+ }
+ }
+ break;
+
+ case ICElement.C_CCONTAINER: {
+ if (added || removed || pathEntryChanged) {
+ scope.add(elem);
+ }
+ }
+ break;
+
+ case ICElement.C_UNIT: {
+ if (added || removed || pathEntryChanged || contentChanged) {
+ scope.add(elem);
+ }
+ }
+ 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:
+ {
+ //TODO handle working copies
+ if (added || removed) {
+ scope.add(elem);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ private static final class DummyIndexerJob extends IndexerJob {
+ public DummyIndexerJob(IndexManager indexManager, IProject project) {
+ super(indexManager, project);
+ }
+ protected boolean processIndex(IIndex index, IProject project, IProgressMonitor progressMonitor) {
+ return false;
+ }
+ }
+
+}
+
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeLocatorJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeLocatorJob.java
new file mode 100644
index 00000000000..4bc931f10d3
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeLocatorJob.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the 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.cache;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+public class TypeLocatorJob extends BasicJob {
+
+ public static final Object FAMILY = new Object();
+ private ITypeInfo fLocateType;
+ private ITypeCache fTypeCache;
+ private IWorkingCopyProvider fWorkingCopyProvider;
+
+ public TypeLocatorJob(ITypeInfo info, ITypeCache typeCache, IWorkingCopyProvider workingCopyProvider) {
+ super(TypeCacheMessages.getString("TypeLocatorJob.jobName"), FAMILY); //$NON-NLS-1$
+ fLocateType = info;
+ fTypeCache = typeCache;
+ fWorkingCopyProvider= workingCopyProvider;
+ }
+
+ public ITypeInfo getType() {
+ return fLocateType;
+ }
+
+ protected IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException {
+ boolean success = false;
+ long startTime = System.currentTimeMillis();
+ trace("TypeLocatorJob: started"); //$NON-NLS-1$
+
+ try {
+ monitor.beginTask(TypeCacheMessages.getString("TypeLocatorJob.taskName"), 100); //$NON-NLS-1$
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ TypeParser parser = new TypeParser(fTypeCache, fWorkingCopyProvider);
+ success = parser.findType(fLocateType, new SubProgressMonitor(monitor, 100));
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ } finally {
+ long executionTime = System.currentTimeMillis() - startTime;
+ if (success)
+ trace("TypeLocatorJob: completed ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+ else
+ trace("TypeLocatorJob: aborted ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ monitor.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java
new file mode 100644
index 00000000000..f40b8daca49
--- /dev/null
+++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java
@@ -0,0 +1,955 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2005 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 implementation
+ * QNX Software Systems - adapted for type search
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.cache;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.ITypeReference;
+import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.cdt.core.browser.PathUtil;
+import org.eclipse.cdt.core.browser.QualifiedTypeName;
+import org.eclipse.cdt.core.browser.TypeInfo;
+import org.eclipse.cdt.core.browser.TypeReference;
+import org.eclipse.cdt.core.browser.TypeSearchScope;
+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.cdt.core.parser.CodeReader;
+import org.eclipse.cdt.core.parser.DefaultProblemHandler;
+import org.eclipse.cdt.core.parser.IParser;
+import org.eclipse.cdt.core.parser.IProblem;
+import org.eclipse.cdt.core.parser.IScanner;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.parser.IScannerInfoProvider;
+import org.eclipse.cdt.core.parser.ISourceElementCallbackDelegate;
+import org.eclipse.cdt.core.parser.ISourceElementRequestor;
+import org.eclipse.cdt.core.parser.ParseError;
+import org.eclipse.cdt.core.parser.ParserFactory;
+import org.eclipse.cdt.core.parser.ParserFactoryError;
+import org.eclipse.cdt.core.parser.ParserLanguage;
+import org.eclipse.cdt.core.parser.ParserMode;
+import org.eclipse.cdt.core.parser.ParserTimeOut;
+import org.eclipse.cdt.core.parser.ParserUtil;
+import org.eclipse.cdt.core.parser.ScannerInfo;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.core.parser.ast.ASTClassKind;
+import org.eclipse.cdt.core.parser.ast.ASTNotImplementedException;
+import org.eclipse.cdt.core.parser.ast.IASTASMDefinition;
+import org.eclipse.cdt.core.parser.ast.IASTAbstractTypeSpecifierDeclaration;
+import org.eclipse.cdt.core.parser.ast.IASTBaseSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTClassReference;
+import org.eclipse.cdt.core.parser.ast.IASTClassSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTCodeScope;
+import org.eclipse.cdt.core.parser.ast.IASTCompilationUnit;
+import org.eclipse.cdt.core.parser.ast.IASTDeclaration;
+import org.eclipse.cdt.core.parser.ast.IASTElaboratedTypeSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTEnumerationReference;
+import org.eclipse.cdt.core.parser.ast.IASTEnumerationSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTEnumeratorReference;
+import org.eclipse.cdt.core.parser.ast.IASTField;
+import org.eclipse.cdt.core.parser.ast.IASTFieldReference;
+import org.eclipse.cdt.core.parser.ast.IASTFunction;
+import org.eclipse.cdt.core.parser.ast.IASTFunctionReference;
+import org.eclipse.cdt.core.parser.ast.IASTInclusion;
+import org.eclipse.cdt.core.parser.ast.IASTLinkageSpecification;
+import org.eclipse.cdt.core.parser.ast.IASTMacro;
+import org.eclipse.cdt.core.parser.ast.IASTMethod;
+import org.eclipse.cdt.core.parser.ast.IASTMethodReference;
+import org.eclipse.cdt.core.parser.ast.IASTNamespaceDefinition;
+import org.eclipse.cdt.core.parser.ast.IASTNamespaceReference;
+import org.eclipse.cdt.core.parser.ast.IASTOffsetableNamedElement;
+import org.eclipse.cdt.core.parser.ast.IASTParameterReference;
+import org.eclipse.cdt.core.parser.ast.IASTQualifiedNameElement;
+import org.eclipse.cdt.core.parser.ast.IASTReference;
+import org.eclipse.cdt.core.parser.ast.IASTScope;
+import org.eclipse.cdt.core.parser.ast.IASTTemplateDeclaration;
+import org.eclipse.cdt.core.parser.ast.IASTTemplateInstantiation;
+import org.eclipse.cdt.core.parser.ast.IASTTemplateParameterReference;
+import org.eclipse.cdt.core.parser.ast.IASTTemplateSpecialization;
+import org.eclipse.cdt.core.parser.ast.IASTTypeSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTTypedefDeclaration;
+import org.eclipse.cdt.core.parser.ast.IASTTypedefReference;
+import org.eclipse.cdt.core.parser.ast.IASTUsingDeclaration;
+import org.eclipse.cdt.core.parser.ast.IASTUsingDirective;
+import org.eclipse.cdt.core.parser.ast.IASTVariable;
+import org.eclipse.cdt.core.parser.ast.IASTVariableReference;
+import org.eclipse.cdt.internal.core.browser.util.SimpleStack;
+import org.eclipse.core.resources.IFile;
+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.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+public class TypeParser implements ISourceElementRequestor {
+
+ private ITypeCache fTypeCache;
+ private ITypeSearchScope fScope;
+ private IProject fProject;
+ private IWorkingCopyProvider fWorkingCopyProvider;
+ private IProgressMonitor fProgressMonitor;
+ ISourceElementCallbackDelegate fLastDeclaration;
+ private final SimpleStack fScopeStack = new SimpleStack();
+ private final SimpleStack fResourceStack = new SimpleStack();
+ private ITypeInfo fTypeToFind;
+ private ITypeInfo fSuperTypeToFind;
+ private Set fProcessedTypes = new HashSet();
+ private boolean fFoundType;
+ IParser fParser = null;
+ ParserTimeOut fTimeoutThread = null;
+
+ public TypeParser(ITypeCache typeCache, IWorkingCopyProvider provider) {
+ fTypeCache = typeCache;
+ fWorkingCopyProvider = provider;
+
+ fTimeoutThread = new ParserTimeOut("TypeParser TimeOut Thread"); //$NON-NLS-1$
+ fTimeoutThread.setThreadPriority(Thread.MAX_PRIORITY);
+ }
+
+ public void parseTypes(TypeSearchScope scope, IProgressMonitor monitor) throws InterruptedException {
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ fScope = new TypeSearchScope(scope);
+ Map workingCopyMap = null;
+ if (fWorkingCopyProvider != null) {
+ IWorkingCopy[] workingCopies = fWorkingCopyProvider.getWorkingCopies();
+ if (workingCopies != null && workingCopies.length > 0) {
+ workingCopyMap = new HashMap(workingCopies.length);
+ for (int i = 0; i < workingCopies.length; ++i) {
+ IWorkingCopy workingCopy = workingCopies[i];
+ IPath wcPath = workingCopy.getOriginalElement().getPath();
+ if (fScope.encloses(wcPath)) {
+// // always flush working copies from cache?
+// fTypeCache.flush(wcPath);
+ fScope.add(wcPath, false, null);
+ workingCopyMap.put(wcPath, workingCopy);
+ }
+ }
+ }
+ }
+
+ fProject = fTypeCache.getProject();
+ IPath[] searchPaths = fTypeCache.getPaths(fScope);
+ Collection workingCopyPaths = new HashSet();
+ if (workingCopyMap != null) {
+ collectWorkingCopiesInProject(workingCopyMap, fProject, workingCopyPaths);
+ //TODO what about working copies outside the workspace?
+ }
+
+ monitor.beginTask("", searchPaths.length + workingCopyPaths.size()); //$NON-NLS-1$
+ try {
+ for (Iterator pathIter = workingCopyPaths.iterator(); pathIter.hasNext(); ) {
+ IPath path = (IPath) pathIter.next();
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ }
+ for (int i = 0; i < searchPaths.length; ++i) {
+ IPath path = searchPaths[i];
+ if (!workingCopyPaths.contains(path)) {
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ } else {
+ monitor.worked(1);
+ }
+ }
+ } finally {
+ monitor.done();
+ }
+ }
+
+ public boolean findType(ITypeInfo info, IProgressMonitor monitor) throws InterruptedException {
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ fScope = new TypeSearchScope();
+ ITypeReference[] refs = info.getReferences();
+ if (refs == null || refs.length == 0)
+ return false; // no source references
+
+ fScope.add(refs[0].getPath(), false, null);
+// for (int i = 0; i < refs.length; ++i) {
+// ITypeReference location = refs[i];
+// IPath path = location.getPath();
+// fScope.add(path, false, null);
+// }
+
+ Map workingCopyMap = null;
+ if (fWorkingCopyProvider != null) {
+ IWorkingCopy[] workingCopies = fWorkingCopyProvider.getWorkingCopies();
+ if (workingCopies != null && workingCopies.length > 0) {
+ workingCopyMap = new HashMap(workingCopies.length);
+ for (int i = 0; i < workingCopies.length; ++i) {
+ IWorkingCopy workingCopy = workingCopies[i];
+ IPath wcPath = workingCopy.getOriginalElement().getPath();
+ if (fScope.encloses(wcPath)) {
+// // always flush working copies from cache?
+// fTypeCache.flush(wcPath);
+ fScope.add(wcPath, false, null);
+ workingCopyMap.put(wcPath, workingCopy);
+ }
+ }
+ }
+ }
+
+ fProject = fTypeCache.getProject();
+ IPath[] searchPaths = fTypeCache.getPaths(fScope);
+ Collection workingCopyPaths = new HashSet();
+ if (workingCopyMap != null) {
+ collectWorkingCopiesInProject(workingCopyMap, fProject, workingCopyPaths);
+ //TODO what about working copies outside the workspace?
+ }
+
+ monitor.beginTask("", searchPaths.length + workingCopyPaths.size()); //$NON-NLS-1$
+ try {
+ fTypeToFind = info;
+ fFoundType = false;
+ for (Iterator pathIter = workingCopyPaths.iterator(); pathIter.hasNext(); ) {
+ IPath path = (IPath) pathIter.next();
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ if (fFoundType)
+ return true;
+ }
+ for (int i = 0; i < searchPaths.length; ++i) {
+ IPath path = searchPaths[i];
+ if (!workingCopyPaths.contains(path)) {
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ } else {
+ monitor.worked(1);
+ }
+
+ if (fFoundType)
+ return true;
+ }
+ } finally {
+ fTypeToFind = null;
+ fFoundType = false;
+ monitor.done();
+ }
+ return false;
+ }
+
+ public boolean findSubTypes(ITypeInfo info, IProgressMonitor monitor) throws InterruptedException {
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ fScope = new TypeSearchScope();
+ ITypeReference[] refs = info.getDerivedReferences();
+ if (refs == null || refs.length == 0)
+ return false; // no source references
+
+ for (int i = 0; i < refs.length; ++i) {
+ ITypeReference location = refs[i];
+ IPath path = location.getPath();
+ fScope.add(path, false, null);
+ }
+
+ Map workingCopyMap = null;
+ if (fWorkingCopyProvider != null) {
+ IWorkingCopy[] workingCopies = fWorkingCopyProvider.getWorkingCopies();
+ if (workingCopies != null && workingCopies.length > 0) {
+ workingCopyMap = new HashMap(workingCopies.length);
+ for (int i = 0; i < workingCopies.length; ++i) {
+ IWorkingCopy workingCopy = workingCopies[i];
+ IPath wcPath = workingCopy.getOriginalElement().getPath();
+ if (fScope.encloses(wcPath)) {
+// // always flush working copies from cache?
+// fTypeCache.flush(wcPath);
+ fScope.add(wcPath, false, null);
+ workingCopyMap.put(wcPath, workingCopy);
+ }
+ }
+ }
+ }
+
+ fProject = fTypeCache.getProject();
+ IPath[] searchPaths = fTypeCache.getPaths(fScope);
+ Collection workingCopyPaths = new HashSet();
+ if (workingCopyMap != null) {
+ collectWorkingCopiesInProject(workingCopyMap, fProject, workingCopyPaths);
+ //TODO what about working copies outside the workspace?
+ }
+
+ monitor.beginTask("", searchPaths.length + workingCopyPaths.size()); //$NON-NLS-1$
+ try {
+ fTypeToFind = null;
+ fSuperTypeToFind = info;
+ fFoundType = false;
+ for (Iterator pathIter = workingCopyPaths.iterator(); pathIter.hasNext(); ) {
+ IPath path = (IPath) pathIter.next();
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ }
+ for (int i = 0; i < searchPaths.length; ++i) {
+ IPath path = searchPaths[i];
+ if (!workingCopyPaths.contains(path)) {
+ parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+ } else {
+ monitor.worked(1);
+ }
+ }
+ } finally {
+ fTypeToFind = null;
+ fFoundType = false;
+ monitor.done();
+ }
+ return false;
+ }
+
+ private void collectWorkingCopiesInProject(Map workingCopyMap, IProject project, Collection workingCopyPaths) {
+ for (Iterator mapIter = workingCopyMap.entrySet().iterator(); mapIter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) mapIter.next();
+ IPath path = (IPath) entry.getKey();
+ IWorkingCopy copy = (IWorkingCopy) entry.getValue();
+
+ ICProject cProject = copy.getCProject();
+ if (cProject != null && cProject.getProject().equals(project)) {
+ workingCopyPaths.add(path);
+ }
+ }
+ }
+
+ private void parseSource(IPath path, IProject project, Map workingCopyMap, IProgressMonitor progressMonitor) throws InterruptedException {
+ if (progressMonitor.isCanceled())
+ throw new InterruptedException();
+
+ // count how many types were indexed for this path
+ TypeSearchScope pathScope = new TypeSearchScope();
+ pathScope.add(path, false, project);
+ int typeCount = fTypeCache.getTypes(pathScope).length;
+
+ progressMonitor.beginTask("", typeCount); //$NON-NLS-1$
+ try {
+ IWorkingCopy workingCopy = null;
+ if (workingCopyMap != null) {
+ workingCopy = (IWorkingCopy) workingCopyMap.get(path);
+ }
+
+ ParserLanguage language = getLanguage(project, workingCopy);
+ if (language == null) {
+ return; // not C or C++
+ }
+
+ CodeReader reader = null;
+ Object stackObject = null;
+
+ IResource resource = null;
+ if (workingCopy != null) {
+ reader = createWorkingCopyReader(workingCopy);
+ resource = workingCopy.getResource();
+ if (resource != null) {
+ path = resource.getLocation();
+ }
+ stackObject = workingCopy;
+ } else {
+ IWorkspace workspace = CCorePlugin.getWorkspace();
+ if (workspace != null) {
+ IWorkspaceRoot wsRoot = workspace.getRoot();
+ if (wsRoot != null) {
+ resource = wsRoot.findMember(path, true);
+ }
+ }
+ if (resource != null) {
+ reader = createResourceReader(resource);
+ path = resource.getLocation();
+ stackObject = resource;
+ } else {
+ reader = createFileReader(path);
+ stackObject = path;
+ }
+ }
+
+ if (reader != null) {
+ fResourceStack.clear();
+ fScopeStack.clear();
+ fResourceStack.push(stackObject);
+ parseContents(path, resource, project, reader, language, progressMonitor);
+ fResourceStack.pop();
+ }
+ } finally {
+ progressMonitor.done();
+ }
+ }
+
+ private ParserLanguage getLanguage(IProject project, IWorkingCopy workingCopy) {
+ ParserLanguage projectLanguage = null;
+ if (project != null) {
+ if (CoreModel.hasCCNature(project)) {
+ projectLanguage = ParserLanguage.CPP;
+ } else if (CoreModel.hasCNature(project)) {
+ projectLanguage = ParserLanguage.C;
+ }
+ }
+
+ if (workingCopy != null) {
+ ParserLanguage workingCopyLanguage = null;
+ ITranslationUnit unit = workingCopy.getTranslationUnit();
+ if (unit != null) {
+ if (unit.isCLanguage()) {
+ workingCopyLanguage = ParserLanguage.C;
+ } else if (unit.isCXXLanguage()) {
+ workingCopyLanguage = ParserLanguage.CPP;
+ }
+ }
+ if (workingCopyLanguage != null) {
+ if (projectLanguage == null) {
+ return workingCopyLanguage;
+ } else if (projectLanguage.equals(ParserLanguage.CPP)) {
+ // if project is CPP then working copy must be CPP
+ return projectLanguage;
+ } else {
+ return workingCopyLanguage;
+ }
+ }
+ }
+ return projectLanguage;
+ }
+
+ private CodeReader createWorkingCopyReader(IWorkingCopy workingCopy) {
+ CodeReader reader = null;
+ IResource resource = workingCopy.getResource();
+ if (resource != null && resource.isAccessible()) {
+ char[] contents = workingCopy.getContents();
+ if (contents != null)
+ reader = new CodeReader(resource.getLocation().toOSString(), contents);
+ }
+ return reader;
+ }
+
+ private CodeReader createResourceReader(IResource resource) {
+ CodeReader reader = null;
+ if (resource.isAccessible() && resource instanceof IFile) {
+ IFile file = (IFile) resource;
+ InputStream contents = null;
+ try {
+ contents = file.getContents();
+ if (contents != null)
+ reader = new CodeReader(resource.getLocation().toOSString(), file.getCharset(), contents);
+ } catch (CoreException ex) {
+ ex.printStackTrace();
+ } catch (IOException e) {
+ } finally {
+ if (contents != null) {
+ try {
+ contents.close();
+ } catch (IOException io) {
+ // ignore
+ }
+ }
+ }
+ }
+ return reader;
+ }
+
+ private CodeReader createFileReader(IPath path) {
+ CodeReader reader = null;
+ try {
+ reader = new CodeReader(path.toOSString());
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ return reader;
+ }
+
+ private void parseContents(IPath realPath, IResource resource, IProject project, CodeReader reader, ParserLanguage language, IProgressMonitor progressMonitor) throws InterruptedException {
+ IScannerInfo scanInfo = null;
+
+ if (project != null) {
+ //TODO temporary workaround to catch managed build exceptions
+ try {
+ IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project);
+ if (provider != null) {
+ IScannerInfo buildScanInfo = provider.getScannerInformation(resource != null ? resource : project);
+ if (buildScanInfo != null)
+ scanInfo = new ScannerInfo(buildScanInfo.getDefinedSymbols(), buildScanInfo.getIncludePaths());
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ if (scanInfo == null)
+ scanInfo = new ScannerInfo();
+
+ try {
+ fProgressMonitor = progressMonitor;
+ IScanner scanner = ParserFactory.createScanner(reader, scanInfo,
+ ParserMode.STRUCTURAL_PARSE, language, this, ParserUtil.getScannerLogService(), null);
+ fParser = ParserFactory.createParser(scanner, this, ParserMode.STRUCTURAL_PARSE, language, ParserUtil.getParserLogService());
+
+ // start timer
+ int timeout = getParserTimeout();
+ if (timeout > 0) {
+ fTimeoutThread.setTimeout(timeout);
+ fTimeoutThread.setParser(fParser);
+ while (!fTimeoutThread.isReadyToRun()){
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ fTimeoutThread.startTimer();
+ }
+
+ fParser.parse();
+ } catch (ParserFactoryError e) {
+ CCorePlugin.log(e);
+ } catch (ParseError e) {
+ // no need to log
+ // CCorePlugin.log(e);
+ } catch (OperationCanceledException e) {
+ throw new InterruptedException();
+ } catch (Exception e) {
+ CCorePlugin.log(e);
+ } finally {
+ // stop timer
+ fTimeoutThread.stopTimer();
+ fTimeoutThread.setParser(null);
+ fProgressMonitor = null;
+ fParser = null;
+ }
+ }
+
+ public boolean acceptProblem(IProblem problem) {
+ return DefaultProblemHandler.ruleOnProblem(problem, ParserMode.COMPLETE_PARSE);
+ }
+ public void acceptUsingDirective(IASTUsingDirective usageDirective) {}
+ public void acceptUsingDeclaration(IASTUsingDeclaration usageDeclaration) {}
+ public void acceptASMDefinition(IASTASMDefinition asmDefinition) {}
+ public void acceptAbstractTypeSpecDeclaration(IASTAbstractTypeSpecifierDeclaration abstractDeclaration) {}
+ public void enterTemplateDeclaration(IASTTemplateDeclaration declaration) {}
+ public void enterTemplateSpecialization(IASTTemplateSpecialization specialization) {}
+ public void enterTemplateInstantiation(IASTTemplateInstantiation instantiation) {}
+ public void exitTemplateDeclaration(IASTTemplateDeclaration declaration) {}
+ public void exitTemplateSpecialization(IASTTemplateSpecialization specialization) {}
+ public void exitTemplateExplicitInstantiation(IASTTemplateInstantiation instantiation) {}
+ public void acceptParameterReference(IASTParameterReference reference) {}
+ public void acceptTemplateParameterReference(IASTTemplateParameterReference reference) {}
+ public void acceptTypedefReference(IASTTypedefReference reference) {}
+ public void acceptEnumeratorReference(IASTEnumeratorReference reference) {}
+ public void acceptClassReference(IASTClassReference reference) {}
+ public void acceptNamespaceReference(IASTNamespaceReference reference) {}
+ public void acceptVariableReference(IASTVariableReference reference) {}
+ public void acceptFieldReference(IASTFieldReference reference) {}
+ public void acceptEnumerationReference(IASTEnumerationReference reference) {}
+ public void acceptFunctionReference(IASTFunctionReference reference) {}
+ public void acceptMethodReference(IASTMethodReference reference) {}
+ public void acceptField(IASTField field) {}
+ public void acceptMacro(IASTMacro macro) {}
+ public void acceptVariable(IASTVariable variable) {}
+ public void acceptFunctionDeclaration(IASTFunction function) {}
+ public void acceptMethodDeclaration(IASTMethod method) {}
+ public void enterCodeBlock(IASTCodeScope scope) {}
+ public void exitCodeBlock(IASTCodeScope scope) {}
+ public void acceptFriendDeclaration(IASTDeclaration declaration) {}
+
+ public void enterLinkageSpecification(IASTLinkageSpecification linkageSpec) {
+ pushScope(linkageSpec);
+ }
+
+ public void exitLinkageSpecification(IASTLinkageSpecification linkageSpec) {
+ popScope();
+ }
+
+ public void enterCompilationUnit(IASTCompilationUnit compilationUnit) {
+ pushScope(compilationUnit);
+ }
+
+ public void exitCompilationUnit(IASTCompilationUnit compilationUnit) {
+ popScope();
+ }
+
+ public void enterFunctionBody(IASTFunction function) {
+ pushScope(function);
+ }
+
+ public void exitFunctionBody(IASTFunction function) {
+ popScope();
+ }
+
+ public void enterMethodBody(IASTMethod method) {
+ pushScope(method);
+ }
+
+ public void exitMethodBody(IASTMethod method) {
+ popScope();
+ }
+
+ public void enterNamespaceDefinition(IASTNamespaceDefinition namespaceDefinition) {
+ fLastDeclaration = namespaceDefinition;
+ acceptType(namespaceDefinition);
+ pushScope(namespaceDefinition);
+ }
+
+ public void exitNamespaceDefinition(IASTNamespaceDefinition namespaceDefinition) {
+ popScope();
+ }
+
+ public void enterClassSpecifier(IASTClassSpecifier classSpecification) {
+ fLastDeclaration = classSpecification;
+ acceptType(classSpecification);
+ pushScope(classSpecification);
+ }
+
+ public void exitClassSpecifier(IASTClassSpecifier classSpecification) {
+ popScope();
+ }
+
+ private void pushScope(IASTScope scope) {
+ if (fProgressMonitor.isCanceled())
+ throw new OperationCanceledException();
+ fScopeStack.push(scope);
+ }
+
+ private IASTScope popScope() {
+ if (fProgressMonitor.isCanceled())
+ throw new OperationCanceledException();
+ return (IASTScope) fScopeStack.pop();
+ }
+
+ public void acceptTypedefDeclaration(IASTTypedefDeclaration typedef) {
+ fLastDeclaration = typedef;
+ acceptType(typedef);
+ }
+
+ public void acceptEnumerationSpecifier(IASTEnumerationSpecifier enumeration) {
+ fLastDeclaration = enumeration;
+ acceptType(enumeration);
+ }
+
+ public void acceptElaboratedForewardDeclaration(IASTElaboratedTypeSpecifier elaboratedType) {
+ // acceptType(elaboratedType);
+ }
+
+ public void enterInclusion(IASTInclusion inclusion) {
+ if (fProgressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ String includePath = inclusion.getFullFileName();
+ IPath path = new Path(includePath);
+ path = PathUtil.getWorkspaceRelativePath(path);
+
+ IResource resource = null;
+ IWorkspace workspace = CCorePlugin.getWorkspace();
+ if (workspace != null) {
+ IWorkspaceRoot wsRoot = workspace.getRoot();
+ if (wsRoot != null) {
+ resource = wsRoot.findMember(path, true);
+ }
+ }
+ //TODO do inclusions get parsed as working copies?
+
+ Object stackObject = path;
+ if (resource != null)
+ stackObject = resource;
+
+ fResourceStack.push(stackObject);
+ }
+
+ public void exitInclusion(IASTInclusion inclusion) {
+ if (fProgressMonitor.isCanceled())
+ throw new OperationCanceledException();
+ fResourceStack.pop();
+ }
+
+ private class NodeTypeInfo {
+ int type;
+ String name;
+ String[] enclosingNames;
+ int offset;
+ int end;
+ IASTOffsetableNamedElement offsetable;
+
+ void init() {
+ type = 0;
+ name = null;
+ enclosingNames = null;
+ offset = 0;
+ end = 0;
+ offsetable = null;
+ }
+
+ boolean parseNodeForTypeInfo(ISourceElementCallbackDelegate node) {
+ init();
+
+ if (node instanceof IASTReference) {
+ IASTReference reference = (IASTReference) node;
+ offset = reference.getOffset();
+ end = offset + reference.getName().length();
+ } else if (node instanceof IASTOffsetableNamedElement) {
+ offsetable = (IASTOffsetableNamedElement) node;
+ offset = offsetable.getNameOffset() != 0 ? offsetable.getNameOffset() : offsetable.getStartingOffset();
+ end = offsetable.getNameEndOffset();
+ if (end == 0) {
+ end = offset + offsetable.getName().length();
+ }
+ }
+
+ if (node instanceof IASTReference)
+ node = fLastDeclaration;
+ if (node instanceof IASTReference) {
+ offsetable = (IASTOffsetableNamedElement) ((IASTReference) node).getReferencedElement();
+ name = ((IASTReference) node).getName();
+ } else if (node instanceof IASTOffsetableNamedElement) {
+ offsetable = (IASTOffsetableNamedElement) node;
+ name = offsetable.getName();
+ } else {
+ return false;
+ }
+
+ // skip unnamed structs
+ if (name == null || name.length() == 0)
+ return false;
+
+ // skip unused types
+ type = getElementType(offsetable);
+ if (type == 0) {
+ return false;
+ }
+
+ // collect enclosing names
+ if (offsetable instanceof IASTQualifiedNameElement) {
+ String[] names = ((IASTQualifiedNameElement) offsetable).getFullyQualifiedName();
+ if (names != null && names.length > 1) {
+ enclosingNames = new String[names.length - 1];
+ System.arraycopy(names, 0, enclosingNames, 0, names.length - 1);
+ }
+ }
+
+ return true;
+ }
+
+ }
+
+ private void acceptType(ISourceElementCallbackDelegate node) {
+ if (fProgressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ // skip local declarations
+ IASTScope currentScope = (IASTScope) fScopeStack.top();
+ if (currentScope instanceof IASTFunction || currentScope instanceof IASTMethod) {
+ return;
+ }
+
+ NodeTypeInfo nodeInfo = new NodeTypeInfo();
+ if (nodeInfo.parseNodeForTypeInfo(node)) {
+ TypeReference originalLocation = null;
+ Object originalRef = fResourceStack.bottom();
+ if (originalRef instanceof IWorkingCopy) {
+ IWorkingCopy workingCopy = (IWorkingCopy) originalRef;
+ originalLocation = new TypeReference(workingCopy, fProject);
+ } else if (originalRef instanceof IResource) {
+ IResource resource = (IResource) originalRef;
+ originalLocation = new TypeReference(resource, fProject);
+ } else if (originalRef instanceof IPath) {
+ IPath path = PathUtil.getProjectRelativePath((IPath)originalRef, fProject);
+ originalLocation = new TypeReference(path, fProject);
+ }
+
+ TypeReference resolvedLocation = null;
+ Object resolvedRef = fResourceStack.top();
+ if (resolvedRef instanceof IWorkingCopy) {
+ IWorkingCopy workingCopy = (IWorkingCopy) resolvedRef;
+ resolvedLocation = new TypeReference(workingCopy, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+ } else if (resolvedRef instanceof IResource) {
+ IResource resource = (IResource) resolvedRef;
+ resolvedLocation = new TypeReference(resource, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+ } else if (resolvedRef instanceof IPath) {
+ IPath path = PathUtil.getProjectRelativePath((IPath)resolvedRef, fProject);
+ resolvedLocation = new TypeReference(path, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+ }
+
+ if (fTypeToFind != null) {
+ if ((fTypeToFind.getCElementType() == nodeInfo.type || fTypeToFind.isUndefinedType()) && nodeInfo.name.equals(fTypeToFind.getName())) {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
+ if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
+ // add types to cache
+ ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
+ if (newType != null && node instanceof IASTClassSpecifier) {
+ addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
+ }
+ fProgressMonitor.worked(1);
+
+ fFoundType = true;
+ // terminate the parser
+ fParser.cancel();
+ }
+ }
+ } else {
+ // add types to cache
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
+ ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
+ if (newType != null && node instanceof IASTClassSpecifier) {
+ addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
+ }
+ fProgressMonitor.worked(1);
+ }
+ }
+ }
+
+ int getElementType(IASTOffsetableNamedElement offsetable) {
+ if (offsetable instanceof IASTClassSpecifier || offsetable instanceof IASTElaboratedTypeSpecifier) {
+ ASTClassKind kind = null;
+ if (offsetable instanceof IASTClassSpecifier) {
+ kind = ((IASTClassSpecifier) offsetable).getClassKind();
+ } else {
+ kind = ((IASTElaboratedTypeSpecifier) offsetable).getClassKind();
+ }
+ if (kind == ASTClassKind.CLASS) {
+ return ICElement.C_CLASS;
+ } else if (kind == ASTClassKind.STRUCT) {
+ return ICElement.C_STRUCT;
+ } else if (kind == ASTClassKind.UNION) {
+ return ICElement.C_UNION;
+ }
+ } else if (offsetable instanceof IASTNamespaceDefinition) {
+ return ICElement.C_NAMESPACE;
+ } else if (offsetable instanceof IASTEnumerationSpecifier) {
+ return ICElement.C_ENUMERATION;
+ } else if (offsetable instanceof IASTTypedefDeclaration) {
+ return ICElement.C_TYPEDEF;
+ }
+ return 0;
+ }
+
+ private void addSuperClasses(ITypeInfo type, IASTClassSpecifier classSpec, TypeReference location, Set processedClasses) {
+ Iterator baseIter = classSpec.getBaseClauses();
+ if (baseIter != null) {
+ while (baseIter.hasNext()) {
+ IASTBaseSpecifier baseSpec = (IASTBaseSpecifier) baseIter.next();
+ try {
+ ASTAccessVisibility baseAccess = baseSpec.getAccess();
+
+ IASTClassSpecifier parentClass = null;
+ IASTTypeSpecifier parentSpec = baseSpec.getParentClassSpecifier();
+ if (parentSpec instanceof IASTClassSpecifier)
+ parentClass = (IASTClassSpecifier) parentSpec;
+
+ if (parentClass != null) {
+ NodeTypeInfo nodeInfo = new NodeTypeInfo();
+ if (nodeInfo.parseNodeForTypeInfo(parentClass)) {
+ // add type to cache
+ ITypeInfo superType = addSuperType(type, nodeInfo.type, nodeInfo.name, nodeInfo.enclosingNames, location, baseAccess, baseSpec.isVirtual());
+
+ // recursively process super super classes
+ if (!processedClasses.contains(parentClass)) {
+ processedClasses.add(parentClass);
+ addSuperClasses(superType, parentClass, location, processedClasses);
+ }
+ }
+ }
+ } catch (ASTNotImplementedException e) {
+ }
+ }
+ }
+ }
+
+ private ITypeInfo addType(int type, QualifiedTypeName qualifiedName, TypeReference originalLocation, TypeReference resolvedLocation) {
+ ITypeInfo info = fTypeCache.getType(type, qualifiedName);
+ if (info == null || info.isUndefinedType()) {
+ // add new type to cache
+ if (info != null) {
+ info.setCElementType(type);
+ } else {
+ info = new TypeInfo(type, qualifiedName);
+ fTypeCache.insert(info);
+ }
+
+ info.addReference(originalLocation);
+ }
+
+ info.addReference(resolvedLocation);
+
+ return info;
+ }
+
+ private ITypeInfo addSuperType(ITypeInfo addToType, int type, String name, String[] enclosingNames, TypeReference location, ASTAccessVisibility access, boolean isVirtual) {
+ QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+ ITypeInfo superType = fTypeCache.getType(type, qualifiedName);
+ if (superType == null || superType.isUndefinedType()) {
+ if (superType != null) {
+ // merge with existing type
+ superType.setCElementType(type);
+ } else {
+ // add new type to cache
+ superType = new TypeInfo(type, qualifiedName);
+ fTypeCache.insert(superType);
+ }
+ }
+ superType.addDerivedReference(location);
+
+ if (fSuperTypeToFind != null && fSuperTypeToFind.equals(superType)) {
+ //TODO don't need to do anything here?
+ }
+ fTypeCache.addSupertype(addToType, superType, access, isVirtual);
+ fTypeCache.addSubtype(superType, addToType);
+ return superType;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.parser.ISourceElementRequestor#createReader(java.lang.String)
+ */
+ public CodeReader createReader(String finalPath, Iterator workingCopies) {
+ return ParserUtil.createReader(finalPath, workingCopies);
+ }
+
+ private static final int DEFAULT_PARSER_TIMEOUT = 30;
+
+ public int getParserTimeout() {
+ //TODO we shouldn't be trying to access the indexer prefs
+ //TODO clean this up
+ int timeout = 0;
+ try {
+ // here we just reuse the indexer timeout
+ String str = CCorePlugin.getDefault().getPluginPreferences().getString("CDT_INDEXER_TIMEOUT"); //$NON-NLS-1$
+ if (str != null && str.length() > 0) {
+ int val = Integer.valueOf(str).intValue();
+ if (val > 0) {
+ timeout = val;
+ }
+ }
+ } catch (NumberFormatException e) {
+ // do nothing
+ }
+
+ if (timeout == 0) {
+ timeout = DEFAULT_PARSER_TIMEOUT;
+ }
+ return timeout;
+ }
+
+}

Back to the top