From f5fbd76f3dfbc7e048162eccd239b251a0624f35 Mon Sep 17 00:00:00 2001 From: Chris Wiebe Date: Tue, 31 Aug 2004 22:57:52 +0000 Subject: [PATCH] 2004-08-31 Chris Wiebe Fix for 68883 * browser/org/eclipse/cdt/core/browser/AllTypesCache.java * browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java * browser/org/eclipse/cdt/core/browser/ITypeInfo.java * browser/org/eclipse/cdt/core/browser/TypeInfo.java * browser/org/eclipse/cdt/core/browser/TypeUtil.java * browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java * browser/org/eclipse/cdt/core/browser/cache/ITypeCache.java * browser/org/eclipse/cdt/core/browser/cache/TypeCache.java * browser/org/eclipse/cdt/core/browser/cache/TypeCacheManager.java --- .../browser/ChangeLog-browser | 13 ++ .../cdt/core/browser/AllTypesCache.java | 55 ++--- .../browser/ITypeCacheChangedListener.java | 32 +++ .../eclipse/cdt/core/browser/ITypeInfo.java | 2 +- .../eclipse/cdt/core/browser/TypeInfo.java | 4 +- .../eclipse/cdt/core/browser/TypeUtil.java | 92 +++----- .../browser/typehierarchy/TypeHierarchy.java | 28 +-- .../core/browser/cache/ITypeCache.java | 5 +- .../core/browser/cache/TypeCache.java | 16 +- .../core/browser/cache/TypeCacheManager.java | 207 +++++++++++++++++- 10 files changed, 320 insertions(+), 134 deletions(-) create mode 100644 core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java diff --git a/core/org.eclipse.cdt.core/browser/ChangeLog-browser b/core/org.eclipse.cdt.core/browser/ChangeLog-browser index ffeb38777bc..a13047d83a4 100644 --- a/core/org.eclipse.cdt.core/browser/ChangeLog-browser +++ b/core/org.eclipse.cdt.core/browser/ChangeLog-browser @@ -1,3 +1,16 @@ +2004-08-31 Chris Wiebe + + Fix for 68883 + * browser/org/eclipse/cdt/core/browser/AllTypesCache.java + * browser/org/eclipse/cdt/core/browser/ITypeCacheChangedListener.java + * browser/org/eclipse/cdt/core/browser/ITypeInfo.java + * browser/org/eclipse/cdt/core/browser/TypeInfo.java + * browser/org/eclipse/cdt/core/browser/TypeUtil.java + * browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java + * browser/org/eclipse/cdt/core/browser/cache/ITypeCache.java + * browser/org/eclipse/cdt/core/browser/cache/TypeCache.java + * browser/org/eclipse/cdt/core/browser/cache/TypeCacheManager.java + 2004-08-26 Chris Wiebe make QualifiedTypeName immutable class 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 99d5e49b1a5..b2e16338db3 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 @@ -23,7 +23,6 @@ import org.eclipse.cdt.core.model.ICElement; 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.TypeCacheMessages; import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager; import org.eclipse.cdt.internal.core.browser.util.ArrayUtil; import org.eclipse.core.resources.IProject; @@ -55,7 +54,7 @@ public class AllTypesCache { private static IPropertyChangeListener fgPropertyChangeListener; static boolean fgEnableIndexing = true; - /** Preference key for enabling background cache */ + /** Preference key for enabling background cache */ public final static String ENABLE_BACKGROUND_TYPE_CACHE = "enableBackgroundTypeCache"; //$NON-NLS-1$ /** @@ -85,8 +84,7 @@ public class AllTypesCache { // add delta listener fgElementChangedListener = new IElementChangedListener() { public void elementChanged(ElementChangedEvent event) { - TypeCacheManager.getInstance().processDelta(event.getDelta()); - TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0); + TypeCacheManager.getInstance().processElementChanged(event, fgEnableIndexing); } }; CoreModel.getDefault().addElementChangedListener(fgElementChangedListener); @@ -282,15 +280,7 @@ public class AllTypesCache { * @param monitor the progress monitor */ public static 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 - TypeCacheManager.getInstance().getCache(project).reconcileAndWait(true, Job.SHORT, monitor); - } - monitor.done(); + TypeCacheManager.getInstance().updateCache(scope, monitor); } /** @@ -300,26 +290,7 @@ public class AllTypesCache { * @param monitor the progress monitor */ public static ITypeReference resolveTypeLocation(ITypeInfo info, IProgressMonitor monitor) { - ITypeReference location = info.getResolvedReference(); - if (location == null) { - // cancel background jobs - IProject project = info.getEnclosingProject(); - TypeCacheManager.getInstance().getCache(project).cancelJobs(); - - // start the search job - TypeCacheManager.getInstance().getCache(project).locateTypeAndWait(info, Job.SHORT, monitor); - - // get the newly parsed location - location = info.getResolvedReference(); - - // resume background jobs - TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0); - } - return location; - } - - public static ITypeInfo getTypeForElement(ICElement elem) { - return TypeUtil.getTypeForElement(elem); + return TypeCacheManager.getInstance().resolveTypeLocation(info, monitor, fgEnableIndexing); } /** Returns first type in the cache which matches the given @@ -359,9 +330,25 @@ public class AllTypesCache { * @return a type hierarchy for the given type */ public static ITypeHierarchy createTypeHierarchy(ICElement type, IProgressMonitor monitor) throws CModelException { - ITypeInfo info = TypeUtil.getTypeForElement(type); + 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..1f78994b9aa --- /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 Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.browser; + +import org.eclipse.core.resources.IProject; + + +/** + * A listener which gets notified when the type cache changes. + *

+ * This interface may be implemented by clients. + *

+ */ +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 fe2c89fea01..b664faa58a8 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 @@ -75,7 +75,7 @@ public interface ITypeInfo extends Comparable { /** Gets the enclosing namespace for this type. * @return the enclosing namespace, or null if none exists. */ - public ITypeInfo getEnclosingNamespace(); + public ITypeInfo getEnclosingNamespace(boolean includeGlobalNamespace); /** Gets the first enclosing type which matches one of the given kinds. * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS, C_STRUCT 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 40ac9a54f1a..b575a4e94a7 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 @@ -149,9 +149,9 @@ public class TypeInfo implements ITypeInfo return getEnclosingType(KNOWN_TYPES); } - public ITypeInfo getEnclosingNamespace() { + public ITypeInfo getEnclosingNamespace(boolean includeGlobalNamespace) { if (fTypeCache != null) { - return fTypeCache.getEnclosingNamespace(this); + return fTypeCache.getEnclosingNamespace(this, includeGlobalNamespace); } return null; } diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeUtil.java index 2e3dec8d986..4032d357239 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,17 +13,14 @@ 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.ICElementVisitor; -import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.IEnumeration; import org.eclipse.cdt.core.model.IMember; import org.eclipse.cdt.core.model.IMethodDeclaration; +import org.eclipse.cdt.core.model.INamespace; import org.eclipse.cdt.core.model.IParent; import org.eclipse.cdt.core.model.IStructure; import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; -import org.eclipse.cdt.internal.core.browser.cache.ITypeCache; -import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; /** * @author CWiebe @@ -33,7 +30,30 @@ import org.eclipse.core.runtime.NullProgressMonitor; */ public class TypeUtil { - public static ICElement getDeclaringType(ICElement type) { + public static boolean isDeclaredType(ICElement elem) { + int type = elem.getElementType(); + return (type == ICElement.C_CLASS + || type == ICElement.C_STRUCT + || type == ICElement.C_ENUMERATION + || type == ICElement.C_UNION + || type == ICElement.C_TYPEDEF + || type == ICElement.C_NAMESPACE); + } + + public static ICElement getDeclaringContainerType(ICElement elem) { + while (elem != null) { + if (elem instanceof IStructure + || elem instanceof INamespace + || elem instanceof IEnumeration) { + return elem; + } + elem = elem.getParent(); + } + + return null; + } + + public static ICElement getDeclaringClass(ICElement type) { ICElement parentElement = type.getParent(); if (parentElement != null && isClassOrStruct(parentElement)) { return parentElement; @@ -97,64 +117,6 @@ public class TypeUtil { return qualifiedName; } - public static ITypeInfo getTypeForElement(ICElement elem, IProgressMonitor monitor) { - if (elem != null) { - ICProject cProject = elem.getCProject(); - IQualifiedTypeName qualifiedName = getFullyQualifiedName(elem); - if (qualifiedName != null) { - final ITypeSearchScope fScope = new TypeSearchScope(true); - if (!AllTypesCache.isCacheUpToDate(fScope)) { - AllTypesCache.updateCache(fScope, monitor); - } - - ITypeCache cache = TypeCacheManager.getInstance().getCache(cProject.getProject()); - ITypeInfo info = cache.getType(elem.getElementType(), qualifiedName); - if (info != null) { - ITypeReference ref = info.getResolvedReference(); - if (ref == null) { - ref = AllTypesCache.resolveTypeLocation(info, monitor); - } - return info; - } - } - } - return null; - } - - public static ITypeInfo getTypeForElement(ICElement elem) { - return getTypeForElement(elem, new NullProgressMonitor()); - } - - public static ICElement getElementForType(ITypeInfo type, IProgressMonitor monitor) { - final ITypeSearchScope fScope = new TypeSearchScope(true); - if (!AllTypesCache.isCacheUpToDate(fScope)) { - AllTypesCache.updateCache(fScope, monitor); - } - ITypeReference ref = type.getResolvedReference(); - if (ref == null) { - ref = AllTypesCache.resolveTypeLocation(type, monitor); - } - if (ref != null) { - ICElement[] elems = ref.getCElements(); - if (elems != null && elems.length > 0) { - if (elems.length == 1) - return elems[0]; - - for (int i = 0; i < elems.length; ++i) { - ICElement elem = elems[i]; - if (elem.getElementType() == type.getCElementType() && elem.getElementName().equals(type.getName())) { - //TODO should check fully qualified name - return elem; - } - } - } - } - return null; - } - public static ICElement getElementForType(ITypeInfo type) { - return getElementForType(type, new NullProgressMonitor()); - } - public static IMethodDeclaration[] getMethods(ICElement elem) { if (elem instanceof IStructure) { try { @@ -267,7 +229,7 @@ public class TypeUtil { IMethodDeclaration first= findMethod(name, paramTypes, isConstructor, isDestructor, superTypes[i]); if (first != null && first.getVisibility() != ASTAccessVisibility.PRIVATE) { // the order getAllSupertypes does make assumptions of the order of inner elements -> search recursivly - IMethodDeclaration res= findMethodDeclarationInHierarchy(hierarchy, TypeUtil.getDeclaringType(first), name, paramTypes, isConstructor, isDestructor); + IMethodDeclaration res= findMethodDeclarationInHierarchy(hierarchy, TypeUtil.getDeclaringClass(first), name, paramTypes, isConstructor, isDestructor); if (res != null) { return res; } 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 index 07caef7c2a6..bc6c2e28fe1 100644 --- 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 @@ -21,7 +21,6 @@ import java.util.Map; import org.eclipse.cdt.core.ICLogConstants; import org.eclipse.cdt.core.browser.AllTypesCache; import org.eclipse.cdt.core.browser.ITypeInfo; -import org.eclipse.cdt.core.browser.TypeUtil; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ElementChangedEvent; @@ -33,7 +32,6 @@ 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.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.Platform; @@ -314,7 +312,7 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { */ public boolean contains(ICElement type) { // classes - ITypeInfo info = AllTypesCache.getTypeForElement(type); + ITypeInfo info = AllTypesCache.getTypeForElement(type, true, true, null); if (info == null) return false; @@ -381,12 +379,12 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { */ public ICElement[] getSubtypes(ICElement type) { List list = new ArrayList(); - ITypeInfo info = TypeUtil.getTypeForElement(type); + 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 = TypeUtil.getElementForType(subType); + ICElement elem = AllTypesCache.getElementForType(subType, true, true, null); if (elem != null) { list.add(elem); } @@ -400,14 +398,14 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { */ public ICElement[] getAllSubtypes(ICElement type) { List list = new ArrayList(); - ITypeInfo info = TypeUtil.getTypeForElement(type); + 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++] = TypeUtil.getElementForType(subType); + elems[count++] = AllTypesCache.getElementForType(subType, true, true, null); } return elems; } @@ -430,13 +428,13 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { */ public ICElement[] getSupertypes(ICElement type) { List list = new ArrayList(); - ITypeInfo info = TypeUtil.getTypeForElement(type); + 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 = TypeUtil.getElementForType(superType); + ICElement elem = AllTypesCache.getElementForType(superType, true, true, null); if (elem != null) { list.add(elem); } @@ -450,14 +448,14 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { */ public ICElement[] getAllSupertypes(ICElement type) { List list = new ArrayList(); - ITypeInfo info = TypeUtil.getTypeForElement(type); + 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++] = TypeUtil.getElementForType(superType); + elems[count++] = AllTypesCache.getElementForType(superType, true, true, null); } return elems; } @@ -481,7 +479,7 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { */ public ICElement getType() { if (fFocusType != null) - return TypeUtil.getElementForType(fFocusType); + return AllTypesCache.getElementForType(fFocusType, true, true, null); return null; } @@ -526,10 +524,6 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { } System.out.println(this.toString()); } - } catch (CModelException e) { - throw e; - } catch (CoreException e) { - throw new CModelException(e); } finally { if (monitor != null) { monitor.done(); @@ -541,7 +535,7 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener { /** * Compute this type hierarchy. */ - protected void compute() throws CModelException, CoreException { + protected void compute() { if (fFocusType != null) { // HierarchyBuilder builder = // new IndexBasedHierarchyBuilder( diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java index d43d0f82e0c..3f0f13326e4 100644 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java @@ -132,9 +132,10 @@ public interface ITypeCache extends ISchedulingRule { * null if none exists. * * @param type the ICElement type - * @return the namespace + * @param includeGlobalNamespace true if the global (default) namespace should be returned + * @return the enclosing namespace, or null if not found. */ - public ITypeInfo getEnclosingNamespace(ITypeInfo info); + public ITypeInfo getEnclosingNamespace(ITypeInfo info, boolean includeGlobalNamespace); /** Gets the root namespace of which encloses the given type. * diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java index 905eeebbc86..01a35be01e1 100644 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java @@ -19,6 +19,7 @@ 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; @@ -52,6 +53,7 @@ public class TypeCache implements ITypeCache { final ITypeInfo fGlobalNamespace; private final Map fTypeToSubTypes = new HashMap(); private final Map fTypeToSuperTypes = new HashMap(); + private ITypeCacheChangedListener fChangeListener = null; private static final class SuperTypeEntry { ITypeInfo superType; @@ -105,6 +107,9 @@ public class TypeCache implements ITypeCache { } } } + // TODO finer-grained change deltas + if (fChangeListener != null) + fChangeListener.typeCacheChanged(fProject); } } @@ -299,6 +304,11 @@ public class TypeCache implements ITypeCache { 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; @@ -554,7 +564,7 @@ public class TypeCache implements ITypeCache { return null; } - public synchronized ITypeInfo getEnclosingNamespace(ITypeInfo info) { + public synchronized ITypeInfo getEnclosingNamespace(ITypeInfo info, boolean includeGlobalNamespace) { IQualifiedTypeName enclosingName = info.getQualifiedTypeName().getEnclosingTypeName(); if (enclosingName != null) { // look for namespace @@ -568,9 +578,11 @@ public class TypeCache implements ITypeCache { enclosingType = (ITypeInfo) fTypeKeyMap.get(new HashKey(enclosingName, kinds[i])); } if (enclosingType != null) { - return getEnclosingNamespace(enclosingType); + return getEnclosingNamespace(enclosingType, includeGlobalNamespace); } } + if (includeGlobalNamespace) + return fGlobalNamespace; return null; } diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java index ba731eb7f71..b98bfb678dc 100644 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java @@ -10,27 +10,45 @@ *******************************************************************************/ 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.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.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; -public class TypeCacheManager { - +public class TypeCacheManager implements ITypeCacheChangedListener { 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 TypeCacheManager() { fCacheMap = new HashMap(); @@ -45,8 +63,7 @@ public class TypeCacheManager { } public synchronized void updateProject(IProject project) { - TypeCacheDelta cacheDelta = new TypeCacheDelta(project); - getCache(project).addDelta(cacheDelta); + addCacheDelta(project, null); } private static final int PATH_ENTRY_FLAGS = ICElementDelta.F_ADDED_PATHENTRY_SOURCE @@ -69,8 +86,7 @@ public class TypeCacheManager { ICProject cProject = elem.getCProject(); IProject project = cProject.getProject(); if (added || removed || pathEntryChanged) { - TypeCacheDelta cacheDelta = new TypeCacheDelta(project, delta); - getCache(project).addDelta(cacheDelta); + addCacheDelta(project, delta); } } break; @@ -84,8 +100,7 @@ public class TypeCacheManager { return; } else { if (added || removed || pathEntryChanged || contentChanged) { - TypeCacheDelta cacheDelta = new TypeCacheDelta(project, delta); - getCache(project).addDelta(cacheDelta); + addCacheDelta(project, delta); } } } @@ -103,8 +118,7 @@ public class TypeCacheManager { ICProject cProject = elem.getCProject(); IProject project = cProject.getProject(); if (added || removed) { - TypeCacheDelta cacheDelta = new TypeCacheDelta(project, delta); - getCache(project).addDelta(cacheDelta); + addCacheDelta(project, delta); } } break; @@ -120,6 +134,17 @@ public class TypeCacheManager { } } + private void addCacheDelta(IProject project, ICElementDelta delta) { + if (delta == null) { + getCache(project).addDelta(new TypeCacheDelta(project)); + } else { + getCache(project).addDelta(new TypeCacheDelta(project, delta)); + } + // TODO finer-grained flush needed, for now just flush the whole map + fTypeToElementMap.clear(); + fElementToTypeMap.clear(); + } + public synchronized void processWorkingCopyDelta(ICElementDelta delta) { // ignore workies copies for now return; @@ -175,7 +200,7 @@ public class TypeCacheManager { synchronized(fCacheMap) { ITypeCache cache = (ITypeCache) fCacheMap.get(project); if (cache == null) { - cache = new TypeCache(project, fWorkingCopyProvider); + cache = new TypeCache(project, fWorkingCopyProvider, this); fCacheMap.put(project, cache); } return cache; @@ -241,4 +266,164 @@ public class TypeCacheManager { } 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, monitor); + } + 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 synchronized void processElementChanged(ElementChangedEvent event, boolean enableIndexing) { + processDelta(event.getDelta()); + reconcile(enableIndexing, Job.BUILD, 0); + } + + 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 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) { + 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) { + 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; + } }