diff --git a/core/org.eclipse.cdt.core/browser/ChangeLog b/core/org.eclipse.cdt.core/browser/ChangeLog index 841433d4536..cc15e311dfc 100644 --- a/core/org.eclipse.cdt.core/browser/ChangeLog +++ b/core/org.eclipse.cdt.core/browser/ChangeLog @@ -1,3 +1,7 @@ +2004-05-12 Chris Wiebe + Heavy refactoring of type cache to address scalability + concerns. + 2004-05-06 Chris Wiebe Creating a new Job to handle the changes, instead of reusing the same job. 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 eb0212ae3c6..760792427bf 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 @@ -10,106 +10,98 @@ *******************************************************************************/ package org.eclipse.cdt.core.browser; +import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ElementChangedEvent; +import org.eclipse.cdt.core.model.IElementChangedListener; import org.eclipse.cdt.core.model.IWorkingCopy; -import org.eclipse.cdt.core.search.ICSearchScope; -import org.eclipse.cdt.core.search.SearchEngine; -import org.eclipse.cdt.internal.core.browser.cache.TypeCache; -import org.eclipse.cdt.internal.core.browser.cache.TypeCacheDeltaListener; -import org.eclipse.cdt.internal.core.browser.cache.TypeCacherJob; +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; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Platform; 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.IJobManager; import org.eclipse.core.runtime.jobs.Job; /** - * Manages a search cache for types in the workspace. Instead of returning objects of type ICElement - * the methods of this class returns a list of the lightweight objects TypeInfo. + * Manages a search cache for types in the workspace. Instead of returning + * objects of type ICElement the methods of this class returns a + * list of the lightweight objects TypeInfo. *

- * AllTypesCache runs asynchronously using a background job to rebuild the cache as needed. - * If the cache becomes dirty again while the background job is running, the job is restarted. + * AllTypesCache runs asynchronously using a background job to rebuild the cache + * as needed. If the cache becomes dirty again while the background job is + * running, the job is restarted. *

- * If getTypes is called in response to a user action, a progress dialog is shown. - * If called before the background job has finished, getTypes waits - * for the completion of the background job. + * If getTypes is called in response to a user action, a progress + * dialog is shown. If called before the background job has finished, getTypes + * waits for the completion of the background job. */ public class AllTypesCache { - - private static final int INITIAL_DELAY= 5000; - private static TypeCache fgCache; - private static IWorkingCopyProvider fWorkingCopyProvider; - private static TypeCacheDeltaListener fgDeltaListener; + + private static final int INITIAL_DELAY = 5000; + private static IWorkingCopyProvider fgWorkingCopyProvider; + private static TypeCacheManager fgTypeCacheManager; + private static IElementChangedListener fgElementChangedListener; private static IPropertyChangeListener fgPropertyChangeListener; - private static boolean fBackgroundJobEnabled; + private static boolean fgEnableIndexing = true; /** Preference key for enabling background cache */ - public final static String ENABLE_BACKGROUND_TYPE_CACHE = "enableBackgroundTypeCache"; //$NON-NLS-1$ - - /** - * Defines a simple interface in order to provide - * a level of abstraction between the Core and UI - * code. - */ - public static interface IWorkingCopyProvider { - public IWorkingCopy[] getWorkingCopies(); - } + 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 provider) { + public static void initialize(IWorkingCopyProvider workingCopyProvider) { + fgWorkingCopyProvider = workingCopyProvider; + fgTypeCacheManager = new TypeCacheManager(fgWorkingCopyProvider); // load prefs - Preferences prefs= CCorePlugin.getDefault().getPluginPreferences(); + Preferences prefs = CCorePlugin.getDefault().getPluginPreferences(); if (prefs.contains(ENABLE_BACKGROUND_TYPE_CACHE)) { - fBackgroundJobEnabled= prefs.getBoolean(ENABLE_BACKGROUND_TYPE_CACHE); + fgEnableIndexing = prefs.getBoolean(ENABLE_BACKGROUND_TYPE_CACHE); } else { prefs.setDefault(ENABLE_BACKGROUND_TYPE_CACHE, true); prefs.setValue(ENABLE_BACKGROUND_TYPE_CACHE, true); CCorePlugin.getDefault().savePluginPreferences(); - fBackgroundJobEnabled= true; + fgEnableIndexing = true; } + + // start jobs in background after INITIAL_DELAY + fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY); - fgCache= new TypeCache(); - fWorkingCopyProvider = provider; - fgDeltaListener= new TypeCacheDeltaListener(fgCache, fWorkingCopyProvider, fBackgroundJobEnabled); + // add delta listener + fgElementChangedListener = new IElementChangedListener() { + public void elementChanged(ElementChangedEvent event) { + fgTypeCacheManager.processDelta(event.getDelta()); + fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0); + } + }; + CoreModel.getDefault().addElementChangedListener(fgElementChangedListener); - fgPropertyChangeListener= new IPropertyChangeListener() { + // add property change listener + fgPropertyChangeListener = new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { - String property= event.getProperty(); + String property = event.getProperty(); if (property.equals(ENABLE_BACKGROUND_TYPE_CACHE)) { - String value= (String)event.getNewValue(); - fBackgroundJobEnabled= Boolean.valueOf(value).booleanValue(); - fgDeltaListener.setBackgroundJobEnabled(fBackgroundJobEnabled); - if (!fBackgroundJobEnabled) { - // terminate all background jobs - IJobManager jobMgr = Platform.getJobManager(); - jobMgr.cancel(TypeCacherJob.FAMILY); + String value = (String) event.getNewValue(); + fgEnableIndexing = Boolean.valueOf(value).booleanValue(); + if (!fgEnableIndexing) { + fgTypeCacheManager.cancelJobs(); + } else { + fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0); } } } }; - // add property change listener prefs.addPropertyChangeListener(fgPropertyChangeListener); - - if (fBackgroundJobEnabled) { - TypeCacherJob typeCacherJob = new TypeCacherJob(fgCache, fWorkingCopyProvider); - typeCacherJob.setSearchPaths(null); - typeCacherJob.setPriority(Job.BUILD); - typeCacherJob.schedule(INITIAL_DELAY); - } - // add delta listener - CoreModel.getDefault().addElementChangedListener(fgDeltaListener); } /** @@ -117,69 +109,161 @@ public class AllTypesCache { */ public static void terminate() { // remove delta listener - CoreModel.getDefault().removeElementChangedListener(fgDeltaListener); + if (fgElementChangedListener != null) + CoreModel.getDefault().removeElementChangedListener(fgElementChangedListener); - // terminate all background jobs - IJobManager jobMgr = Platform.getJobManager(); - jobMgr.cancel(TypeCacherJob.FAMILY); + // remove property change listener + if (fgPropertyChangeListener != null) + CCorePlugin.getDefault().getPluginPreferences().removePropertyChangeListener(fgPropertyChangeListener); + + // terminate all running jobs + if (fgTypeCacheManager != null) { + fgTypeCacheManager.cancelJobs(); + } } - /* - * Returns the actual type cache. + /** + * Returns all types in the workspace. */ - public static TypeCache getCache() { - return fgCache; + public static ITypeInfo[] getAllTypes() { + final Collection fAllTypes = new ArrayList(); + TypeSearchScope workspaceScope = new TypeSearchScope(true); + IProject[] projects = workspaceScope.getEnclosingProjects(); + ITypeInfoVisitor visitor = new ITypeInfoVisitor() { + public void visit(ITypeInfo info) { + fAllTypes.add(info); + } + }; + for (int i = 0; i < projects.length; ++i) { + fgTypeCacheManager.getCache(projects[i]).accept(visitor); + } + return (ITypeInfo[]) fAllTypes.toArray(new ITypeInfo[fAllTypes.size()]); + } + + /** + * Returns all types in the given scope. + * + * @param scope The search scope + * @param kinds Array containing CElement types: C_NAMESPACE, C_CLASS, + * C_UNION, C_ENUMERATION, C_TYPEDEF + */ + public static ITypeInfo[] getTypes(ITypeSearchScope scope, int[] kinds) { + final Collection fTypesFound = new ArrayList(); + final ITypeSearchScope fScope = scope; + final int[] fKinds = kinds; + IProject[] projects = scope.getEnclosingProjects(); + ITypeInfoVisitor visitor = new ITypeInfoVisitor() { + public void visit(ITypeInfo info) { + if (info.isEnclosed(fScope) && ArrayUtil.contains(fKinds, info.getCElementType())) { + fTypesFound.add(info); + } + } + }; + for (int i = 0; i < projects.length; ++i) { + fgTypeCacheManager.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 + */ + public static ITypeInfo[] getTypes(ITypeSearchScope scope, IQualifiedTypeName qualifiedName, int[] kinds) { + final Collection fTypesFound = new ArrayList(); + final ITypeSearchScope fScope = scope; + final int[] fKinds = kinds; + final IQualifiedTypeName fQualifiedName = qualifiedName; + IProject[] projects = scope.getEnclosingProjects(); + ITypeInfoVisitor visitor = new ITypeInfoVisitor() { + public void visit(ITypeInfo info) { + if (fQualifiedName.equals(info.getQualifiedTypeName()) + && ArrayUtil.contains(fKinds, info.getCElementType())) { + fTypesFound.add(info); + } + } + }; + for (int i = 0; i < projects.length; ++i) { + fgTypeCacheManager.getCache(projects[i]).accept(visitor); + } + return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]); } /** * Returns true if the type cache is up to date. */ - public static boolean isCacheUpToDate() { - return !fgCache.isDirty(); + 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 (!fgTypeCacheManager.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) { + } + } + } } /** - * Returns all types in the given scope. - * @param scope The search scope - * @param kinds Array containing CElement types: - * C_NAMESPACE, C_CLASS, C_UNION, C_ENUMERATION, C_TYPEDEF - * @param monitor Progress monitor to display search progress - * @param typesFound The resulting TypeInfo elements are added to this collection - */ - public static void getTypes(ICSearchScope scope, int[] kinds, IProgressMonitor monitor, Collection typesFound) { - if (!isCacheUpToDate()) { - // start job if not already running - IJobManager jobMgr = Platform.getJobManager(); - Job[] jobs = jobMgr.find(TypeCacherJob.FAMILY); - if (jobs.length == 0) { - // boost priority since action was user-initiated - TypeCacherJob typeCacherJob = new TypeCacherJob(fgCache, fWorkingCopyProvider); - typeCacherJob.setSearchPaths(null); - typeCacherJob.setPriority(Job.SHORT); - typeCacherJob.schedule(); - } - - // wait for job to finish - jobs = jobMgr.find(TypeCacherJob.FAMILY); - try { - for (int i = 0; i < jobs.length; ++i) { - TypeCacherJob job = (TypeCacherJob) jobs[i]; - job.join(monitor); - } - if (monitor != null) - monitor.done(); - } catch (InterruptedException ex) { - return; - } + * Updates the type cache. + * + * @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 + fgTypeCacheManager.getCache(project).reconcileAndWait(true, Job.SHORT, monitor); } - - boolean isWorkspaceScope= scope.equals(SearchEngine.createWorkspaceScope()); - for (Iterator typesIter= fgCache.getAllTypes().iterator(); typesIter.hasNext(); ) { - ITypeInfo info= (ITypeInfo) typesIter.next(); - if ( ArrayUtil.contains(kinds, info.getType()) && - (isWorkspaceScope || info.isEnclosed(scope)) ) { - typesFound.add(info); - } + monitor.done(); + } + + /** + * Resolves a type location. + * + * @param info the type to search for + * @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(); + fgTypeCacheManager.getCache(project).cancelJobs(); + + // start the search job + fgTypeCacheManager.getCache(project).locateTypeAndWait(info, Job.SHORT, monitor); + + // get the newly parsed location + location = info.getResolvedReference(); + + // resume background jobs + fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0); } + return location; } } diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java new file mode 100644 index 00000000000..81ebd60a5bb --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IQualifiedTypeName.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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; + +public interface IQualifiedTypeName extends Comparable { + + public final static String QUALIFIER = "::"; //$NON-NLS-1$ + + public String getName(); + + public String[] getEnclosingNames(); + + public String getFullyQualifiedName(); + + public IQualifiedTypeName getEnclosingTypeName(); + + public boolean isEmpty(); + public boolean isGlobal(); + + public IQualifiedTypeName append(String qualifiedName); + public IQualifiedTypeName append(String[] names); + public IQualifiedTypeName append(IQualifiedTypeName typeName); + + public String[] segments(); + public String segment(int index); + public int segmentCount(); + public String lastSegment(); + public int matchingFirstSegments(IQualifiedTypeName typeName); + public IQualifiedTypeName removeFirstSegments(int count); + public IQualifiedTypeName removeLastSegments(int count); + public boolean isPrefixOf(IQualifiedTypeName typeName); + + public boolean isLowLevel(); + public boolean validate(); +} 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 eceb6f4f065..84519f65cc9 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 @@ -10,11 +10,7 @@ *******************************************************************************/ 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.search.ICSearchScope; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IPath; +import org.eclipse.core.resources.IProject; /** * Type information. @@ -24,7 +20,23 @@ public interface ITypeInfo { /** * Gets the CElement type. */ - public int getType(); + public int getCElementType(); + + /** + * Sets the CElement type. + */ + public void setCElementType(int type); + + /** + * Returns true if the element type is unknown. + */ + public boolean isUndefinedType(); + + /** + * Returns true if this type can enclose other types, + * i.e. it is a namespace, class, or struct. + */ + public boolean isQualifierType(); /** * Gets the type name. @@ -32,81 +44,37 @@ public interface ITypeInfo { public String getName(); /** - * Gets the enclosing type names. + * Gets the qualified type name. */ - public String[] getEnclosingNames(); + public IQualifiedTypeName getQualifiedTypeName(); /** - * Gets the resource where type is located. + * Gets the enclosing type. */ - public IResource getResource(); + public ITypeInfo getEnclosingType(); /** - * Gets the relative path where type is located. + * Gets the enclosing project. */ - public IPath getPath(); - - /** - * Gets the absolute path where type is located. - */ - public IPath getLocation(); - - /** - * Gets the start offset of type position. - */ - public int getStartOffset(); + public IProject getEnclosingProject(); /** - * Gets the end offset of type position. + * Returns true if type is enclosed in the given scope. */ - public int getEndOffset(); - - /** - * Returns true if type is enclosed in the given scope - */ - public boolean isEnclosed(ICSearchScope scope); - - /** - * Gets the filename where this type is located. - */ - public String getFileName(); + public boolean isEnclosed(ITypeSearchScope scope); /** - * Gets the fully qualified type container name: Includes enclosing type names, but - * not filename. Identifiers are separated by colons. + * Adds a source reference. */ - public String getParentName(); - - /** - * Gets the type qualified name: Includes enclosing type names, but - * not filename. Identifiers are separated by colons. - */ - public String getQualifiedName(); + public void addReference(ITypeReference location); /** - * Gets the fully qualified type container name: Filename or - * enclosing type name with filename. - * All identifiers are separated by colons. + * Returns all known source references. */ - public String getQualifiedParentName(); - - /** - * Gets the fully qualified type name: Includes enclosing type names and - * filename. All identifiers are separated by colons. - */ - public String getFullyQualifiedName(); - - /** - * Gets the CElement which corresponds to this type. - */ - public ICElement getCElement(); + public ITypeReference[] getReferences(); - /** Gets the include path for this type. - * - * @param cProject the C Project to use as a reference. - * @return The path to this type, relative to the longest - * matching include path in the given project, or - * null if not found. + /** + * Returns parsed source location with offset and length. */ - public IPath resolveIncludePath(ICProject cProject); + public ITypeReference getResolvedReference(); } diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfoVisitor.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfoVisitor.java new file mode 100644 index 00000000000..39769d2dff8 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfoVisitor.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * 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; + +public interface ITypeInfoVisitor { + public void visit(ITypeInfo info); +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeReference.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeReference.java new file mode 100644 index 00000000000..8a547e59082 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeReference.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * 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.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.model.IWorkingCopy; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; + +public interface ITypeReference { + + /** + * Returns the full, absolute path of this reference + * relative to the workspace, or null if no path can be + * determined. + */ + public IPath getPath(); + + /** + * Returns the absolute path in the local file system + * to this reference, or null if no path can be + * determined. + */ + public IPath getLocation(); + + /** + * Returns the resource. + */ + public IResource getResource(); + + /** + * Returns the working copy. + */ + public IWorkingCopy getWorkingCopy(); + + /** + * Returns the project. + */ + public IProject getProject(); + + /** + * Returns the offset. + */ + public int getOffset(); + + /** + * Returns the length. + */ + public int getLength(); + + /** + * Returns the CElement located at the stored offset and length. + */ + public ICElement getCElement(); + + /** + * Returns a translation unit for this location. + */ + public ITranslationUnit getTranslationUnit(); + + /** Gets the path for this location, relative to one of + * the given project's include paths. + * + * @param project the project to use as a reference. + * @return The path to this location, relative to the longest + * matching include path in the given project. + */ + public IPath getRelativeIncludePath(IProject project); + + /** Gets the path for this location, relative to the + * given path. + * + * @param relativeToPath the path to use as a reference. + * @return The path to this location, relative to the + * given path. + */ + public IPath getRelativePath(IPath relativeToPath); +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java new file mode 100644 index 00000000000..c4f6e9bf031 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeSearchScope.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the 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 java.util.Collection; + +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.IWorkingCopy; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +public interface ITypeSearchScope { + + public boolean isPathScope(); + public boolean isProjectScope(); + public boolean isWorkspaceScope(); + public boolean isEmpty(); + + public boolean encloses(ITypeSearchScope scope); + public boolean encloses(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, IProject enclosingProject); + public void add(IProject project); + public void add(ICElement elem); + public void add(ITypeSearchScope scope); + public void addWorkspace(); + public void clear(); + public IProject[] getEnclosingProjects(); + + public Collection pathSet(); + public Collection containerSet(); + public Collection projectSet(); + public Collection enclosingProjectSet(); +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IWorkingCopyProvider.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IWorkingCopyProvider.java new file mode 100644 index 00000000000..00a83a4c256 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/IWorkingCopyProvider.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the 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.cdt.core.model.IWorkingCopy; + +/** + * Defines a simple interface in order to provide + * a level of abstraction between the Core and UI + * code. + */ +public interface IWorkingCopyProvider { + public IWorkingCopy[] getWorkingCopies(); +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java new file mode 100644 index 00000000000..153b18790ef --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/QualifiedTypeName.java @@ -0,0 +1,278 @@ +/******************************************************************************* + * 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 java.util.ArrayList; + +import org.eclipse.cdt.core.CConventions; +import org.eclipse.core.runtime.IStatus; + +public class QualifiedTypeName implements IQualifiedTypeName { + + private String[] fSegments; + private int fHashCode; + + public QualifiedTypeName(IQualifiedTypeName typeName) { + this(typeName.segments()); + } + + public QualifiedTypeName(String[] names) { + fSegments = new String[names.length]; + System.arraycopy(names, 0, fSegments, 0, names.length); + } + + public QualifiedTypeName(String name, String[] enclosingNames) { + if (enclosingNames != null) { + fSegments = new String[enclosingNames.length + 1]; + System.arraycopy(enclosingNames, 0, fSegments, 0, enclosingNames.length); + fSegments[fSegments.length - 1] = name; + } else { + fSegments = new String[] { name }; + } + } + + public QualifiedTypeName(String qualifiedName) { + int qualifierIndex = qualifiedName.indexOf(QUALIFIER, 0); + if (qualifierIndex == -1) { + fSegments = new String[] { qualifiedName }; + } else { + ArrayList namesList = new ArrayList(5); + int lastIndex = 0; + String nextName; + while (qualifierIndex >= 0) { + nextName = qualifiedName.substring(lastIndex, qualifierIndex); + lastIndex = qualifierIndex + QUALIFIER.length(); + namesList.add(nextName); + qualifierIndex = qualifiedName.indexOf(QUALIFIER, lastIndex); + } + nextName = qualifiedName.substring(lastIndex); + namesList.add(nextName); + fSegments = (String[]) namesList.toArray(new String[namesList.size()]); + } + } + + public String getName() { + if (fSegments.length > 0) { + return fSegments[fSegments.length - 1]; + } + return null; + } + + public String[] getEnclosingNames() { + if (fSegments.length > 1) { + String[] enclosingNames = new String[fSegments.length - 1]; + System.arraycopy(fSegments, 0, enclosingNames, 0, fSegments.length - 1); + return enclosingNames; + } + return null; + } + + public String getFullyQualifiedName() { + if (fSegments.length > 0) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < fSegments.length; ++i) { + if (i > 0) { + buf.append(QUALIFIER); + } + buf.append(fSegments[i]); + } + return buf.toString(); + } + return null; + } + + public IQualifiedTypeName getEnclosingTypeName() { + String[] enclosingNames = getEnclosingNames(); + if (enclosingNames != null) { + return new QualifiedTypeName(enclosingNames); + } + return null; + } + +// TODO extra methods eg matchingFirstSegments() etc + public boolean isEmpty() { + return fSegments.length == 0; + } + + public boolean isGlobal() { + if (fSegments.length <= 1) { + return true; + } else if (fSegments[0] == null || fSegments[0].length() == 0) { + return true; + } + return false; + } + + + public int segmentCount() { + return fSegments.length; + } + + public String[] segments() { + return fSegments; + } + + public String segment(int index) { + if (index >= fSegments.length) { + return null; + } + return fSegments[index]; + } + + public String lastSegment() { + if (fSegments.length > 0) { + return fSegments[fSegments.length - 1]; + } + return null; + } + + public int matchingFirstSegments(IQualifiedTypeName typeName) { + int max = Math.min(fSegments.length, typeName.segmentCount()); + int count = 0; + for (int i = 0; i < max; ++i) { + if (!fSegments[i].equals(typeName.segment(i))) { + return count; + } + count++; + } + return count; + } + + public boolean isPrefixOf(IQualifiedTypeName typeName) { + if (isEmpty()) + return true; + + if (fSegments.length > typeName.segmentCount()) { + return false; + } + + for (int i = 0; i < fSegments.length; ++i) { + if (!fSegments[i].equals(typeName.segment(i))) { + return false; + } + } + return true; + } + + public IQualifiedTypeName append(String[] names) { + String[] newNames = new String[fSegments.length + names.length]; + System.arraycopy(fSegments, 0, newNames, 0, fSegments.length); + System.arraycopy(names, 0, newNames, fSegments.length, names.length); + return new QualifiedTypeName(newNames); + } + + public IQualifiedTypeName append(IQualifiedTypeName typeName) { + return append(typeName.segments()); + } + + public IQualifiedTypeName append(String qualifiedName) { + return append(new QualifiedTypeName(qualifiedName)); + } + + public IQualifiedTypeName removeFirstSegments(int count) { + if (count == 0) { + return new QualifiedTypeName(this); + } else if (count >= fSegments.length || count < 0) { + return new QualifiedTypeName(new String[0]); + } else { + int newSize = fSegments.length - count; + String[] newNames = new String[newSize]; + System.arraycopy(fSegments, count, newNames, 0, newSize); + return new QualifiedTypeName(newNames); + } + } + + public IQualifiedTypeName removeLastSegments(int count) { + if (count == 0) { + return new QualifiedTypeName(this); + } else if (count >= fSegments.length || count < 0) { + return new QualifiedTypeName(new String[0]); + } else { + int newSize = fSegments.length - count; + String[] newNames = new String[newSize]; + System.arraycopy(fSegments, 0, newNames, 0, newSize); + return new QualifiedTypeName(newNames); + } + } + + public boolean isLowLevel() { + for (int i = 0; i < fSegments.length; ++i) { + if (fSegments[i].startsWith("_")) { //$NON-NLS-1$ + return true; + } + } + return false; + } + + public boolean validate() { + for (int i = 0; i < fSegments.length; ++i) { + if (!isValidSegment(fSegments[i])) { + return false; + } + } + return true; + } + + private static boolean isValidSegment(String segment) { + // type name must follow C conventions + IStatus val= CConventions.validateIdentifier(segment); + return (val.getSeverity() != IStatus.ERROR); + } + + public int hashCode() { + if (fHashCode == 0) { + String name = getFullyQualifiedName(); + if (name != null) + fHashCode = name.hashCode(); + } + return fHashCode; + } + + public String toString() { + return getFullyQualifiedName(); + } + + public int compareTo(Object obj) { + if (obj == this) { + return 0; + } + if (!(obj instanceof IQualifiedTypeName)) { + throw new ClassCastException(); + } + IQualifiedTypeName typeName = (IQualifiedTypeName) obj; + return getFullyQualifiedName().compareTo(typeName.getFullyQualifiedName()); + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof IQualifiedTypeName)) { + return false; + } + IQualifiedTypeName typeName = (IQualifiedTypeName) obj; + return matchSegments(fSegments, typeName.segments()); + } + + private static boolean matchSegments(String[] a, String[] b) { + if (a == null && b == null) + return true; + if (a == null || b == null) + return false; + if (a.length != b.length) + return false; + for (int i = 0; i < a.length; ++i) { + if (!a[i].equals(b[i])) + return false; + } + return true; + } +} 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 1e1017eb21b..47581b047ea 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 @@ -10,331 +10,130 @@ *******************************************************************************/ package org.eclipse.cdt.core.browser; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.model.CModelException; -import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; -import org.eclipse.cdt.core.model.ICProject; -import org.eclipse.cdt.core.model.IParent; -import org.eclipse.cdt.core.parser.IScannerInfo; -import org.eclipse.cdt.core.parser.IScannerInfoProvider; -import org.eclipse.cdt.core.search.ICSearchScope; -import org.eclipse.core.resources.IFile; +import org.eclipse.cdt.internal.core.browser.cache.ITypeCache; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; - -/** - * To change the template for this generated type comment go to - * Window>Preferences>Java>Code Generation>Code and Comments - */ public class TypeInfo implements ITypeInfo, Comparable { - protected final static String scopeResolutionOperator= "::"; //$NON-NLS-1$ - protected final static String fileScopeSeparator= " : "; //$NON-NLS-1$ - private String hashString= null; - private int hashCode= 0; - private String name= null; - private int type= 0; - private String[] enclosingNames= null; - private IResource resource= null; - private IPath path= null; - private int startOffset= 0; - private int endOffset= 0; - private ICElement cElement= null; - - public TypeInfo(String name, int type, String[] enclosingNames, IResource resource, IPath path, int startOffset, int endOffset) { - init(name, type, enclosingNames, resource, path, startOffset, endOffset); + private ITypeCache fTypeCache; + private int fElementType; + private QualifiedTypeName fQualifiedName; + private Set fSourceRefs = new HashSet(); + + public TypeInfo(int elementType, IQualifiedTypeName typeName, ITypeCache typeCache) { + fElementType = elementType; + fQualifiedName = new QualifiedTypeName(typeName); + fTypeCache = typeCache; } - public TypeInfo(String fullName, int type, IPath path, int startOffset, int endOffset) { - String name= fullName; - String parentName= null; - int qualifierIndex= fullName.lastIndexOf(scopeResolutionOperator); - if (qualifierIndex >= 0) { - parentName= fullName.substring(0, qualifierIndex); - name= fullName.substring(qualifierIndex+2); - } - String[] enclosingNames= null; - if (parentName != null) - enclosingNames= parseScopedName(parentName); - - init(name, type, enclosingNames, null, path, startOffset, endOffset); - } - - public TypeInfo(TypeInfo info) { - init(info.name, info.type, info.enclosingNames, info.resource, info.path, info.startOffset, info.endOffset); - } - - private void init(String name, int type, String[] enclosingNames, IResource resource, IPath path, int startOffset, int endOffset) { - this.name= name; - this.type= type; - if (enclosingNames != null) { - this.enclosingNames= new String[enclosingNames.length]; - System.arraycopy(enclosingNames, 0, this.enclosingNames, 0, enclosingNames.length); - } - this.resource= resource; - if (path == null && resource != null) - path= resource.getFullPath(); - this.path= path; - this.startOffset= startOffset; - this.endOffset= endOffset; + public void addReference(ITypeReference location) { + fSourceRefs.add(location); } + public ITypeReference[] getReferences() { + return (ITypeReference[]) fSourceRefs.toArray(new ITypeReference[fSourceRefs.size()]); + } + + public ITypeReference getResolvedReference() { + for (Iterator i = fSourceRefs.iterator(); i.hasNext(); ) { + ITypeReference location = (ITypeReference) i.next(); + if (location.getLength() != 0) { + return location; + } + } + return null; + } + + public boolean isReferenced() { + return !fSourceRefs.isEmpty(); + } + + public boolean isUndefinedType() { + return fElementType == 0; + } + + public boolean isQualifierType() { + return (fElementType == ICElement.C_NAMESPACE + || fElementType == ICElement.C_CLASS + || fElementType == ICElement.C_STRUCT); + } + + public int getCElementType() { + return fElementType; + } + + public void setCElementType(int type) { + fElementType = type; + } + + public IQualifiedTypeName getQualifiedTypeName() { + return fQualifiedName; + } + public String getName() { - return name; + return fQualifiedName.getName(); } - public int getType() { - return type; - } - - public String[] getEnclosingNames() { - return enclosingNames; - } - - public IResource getResource() { - return resource; - } - - public IPath getPath() { - if (resource != null) - return resource.getFullPath(); - else - return path; - } - - public IPath getLocation() { - if (resource != null) - return resource.getLocation(); - else - return path; - } - - public int getStartOffset() { - return startOffset; - } - - public int getEndOffset() { - return endOffset; - } - - public String getFileName() { - if (resource != null) - return resource.getName(); - else if (path != null) - return path.lastSegment(); - else - return null; - } - - public String getParentName() { - if (enclosingNames != null) { - StringBuffer buf= new StringBuffer(); - for (int i= 0; i < enclosingNames.length; ++i) { - if (i > 0) - buf.append(scopeResolutionOperator); - buf.append(enclosingNames[i]); + public ITypeInfo getEnclosingType() { + ITypeInfo enclosingType = null; + if (fTypeCache != null) { + IQualifiedTypeName parentName = fQualifiedName.getEnclosingTypeName(); + if (parentName != null) { + ITypeInfo[] types = fTypeCache.getTypes(parentName); + for (int i = 0; i < types.length; ++i) { + ITypeInfo info = types[i]; + if (info.isQualifierType()) { + enclosingType = info; + break; + } else if (info.isUndefinedType()) { + enclosingType = info; + // don't break, in case we can still find a defined type + } + } } - return buf.toString(); } - return null; + return enclosingType; + } + + public IProject getEnclosingProject() { + if (fTypeCache != null) { + return fTypeCache.getProject(); + } else { + return null; + } } - public String getQualifiedParentName() { - StringBuffer buf= new StringBuffer(); - String fileName = getFileName(); - if (fileName != null) - buf.append(fileName); - String parentName = getParentName(); - if (parentName != null) { - if (fileName != null) - buf.append(fileScopeSeparator); - buf.append(parentName); - } - return buf.toString(); - } - - public String getQualifiedName() { - StringBuffer buf= new StringBuffer(); - String parentName = getParentName(); - if (parentName != null) - buf.append(parentName); - String name = getName(); - if (name != null) { - if (parentName != null) - buf.append(scopeResolutionOperator); - buf.append(name); - } - return buf.toString(); - } - - public String getFullyQualifiedName() { - StringBuffer buf= new StringBuffer(); - String fileName = getFileName(); - if (fileName != null) - buf.append(fileName); - String parentName = getParentName(); - if (parentName != null) { - if (fileName != null) - buf.append(fileScopeSeparator); - buf.append(parentName); - } - String name = getName(); - if (name != null) - if (parentName != null) - buf.append(scopeResolutionOperator); - else if (fileName != null) - buf.append(fileScopeSeparator); - buf.append(name); - return buf.toString(); - } - public String toString() { - return getFullyQualifiedName(); + return fQualifiedName.toString(); } - public ICElement getCElement() { - if (cElement == null) - cElement= resolveCElement(); - return cElement; - } - - private ICElement resolveCElement() { - if (resource != null && resource.getType() == IResource.FILE) { - ICElement parentElement= CoreModel.getDefault().create((IFile)resource); - if (parentElement instanceof IParent) { - if (enclosingNames != null) { - for (int i= 0; i < enclosingNames.length; ++i) { - parentElement= findCElement(parentElement, enclosingNames[i]); - if (parentElement == null) - break; - } - } - if (parentElement != null) - return findCElement(parentElement, name); - } - } - return null; - } - - private ICElement findCElement(ICElement celement, String name) { - if (isValidType(celement.getElementType()) && celement.getElementName().equals(name)) - return celement; - try { - if (celement instanceof IParent) { - ICElement[] children = ((IParent)celement).getChildren(); - for (int i = 0; i < children.length; i++) { - ICElement child= children[i]; - if (isValidType(child.getElementType()) && child.getElementName().equals(name)) - return child; - } - } - } catch (CModelException e) { - - } - return null; - } - - public IPath resolveIncludePath(ICProject cProject) { - IPath fullPath= getLocation(); - if (cProject == null || fullPath == null) - return null; - IProject project= cProject.getProject(); - IScannerInfoProvider provider= CCorePlugin.getDefault().getScannerInfoProvider(project); - if (provider != null) { - IScannerInfo info= provider.getScannerInformation(project); - if (info != null) { - String[] includePaths= info.getIncludePaths(); - IPath relativePath= null; - int mostSegments= 0; - for (int i= 0; i < includePaths.length; ++i) { - IPath includePath= new Path(includePaths[i]); - if (includePath.isPrefixOf(fullPath)) { - int segments= includePath.matchingFirstSegments(fullPath); - if (segments > mostSegments) { - relativePath= fullPath.removeFirstSegments(segments).setDevice(null); - mostSegments= segments; - } - } - } - return relativePath; - } - } - return null; - } - - public boolean isEnclosed(ICSearchScope scope) { - if (scope == null) - return false; + public boolean isEnclosed(ITypeSearchScope scope) { + if (scope == null || scope.isWorkspaceScope()) + return true; // check if path is in scope - IPath path= getPath(); - if (path != null && scope.encloses(path.toString())) - return true; - - // check include paths of enclosing projects - IPath[] projectPaths= scope.enclosingProjects(); - if (projectPaths != null) { - for (int i= 0; i < projectPaths.length; ++i) { - IPath projPath= projectPaths[i]; - ICElement elem= CoreModel.getDefault().create(projPath); - if (elem != null && elem instanceof ICProject) { - ICProject proj= (ICProject) elem; - if (resolveIncludePath(proj) != null) - return true; - // TODO search referenced projects too? - // IProject[] refs= proj.getProject().getReferencedProjects(); - } - } + for (Iterator i = fSourceRefs.iterator(); i.hasNext(); ) { + ITypeReference location = (ITypeReference) i.next(); + if (scope.encloses(location.getPath())) + return true; } + return false; } public int hashCode() { - if (hashString == null) { - hashCode= getHashString().hashCode(); - } + int hashCode = fQualifiedName.hashCode() + fElementType; + IProject project = getEnclosingProject(); + if (project != null) + hashCode += project.hashCode(); return hashCode; } - private String getHashString() { - if (hashString == null) { - StringBuffer buf= new StringBuffer(64); - - IPath path= getLocation(); - if (path != null) - buf.append(path.toString()); - - buf.append(" ["); //$NON-NLS-1$ - buf.append(startOffset); - buf.append("-"); //$NON-NLS-1$ - buf.append(endOffset); - buf.append("] "); //$NON-NLS-1$ - - String parentName= getParentName(); - if (parentName != null && parentName.length() > 0) { - buf.append(parentName); - buf.append(scopeResolutionOperator); - } - String name= getName(); - if (name != null && name.length() > 0) - buf.append(name); - - buf.append(":"); //$NON-NLS-1$ - buf.append(type); - - hashString= buf.toString(); - } - return hashString; - } - public boolean equals(Object obj) { if (obj == this) { return true; @@ -342,10 +141,20 @@ public class TypeInfo implements ITypeInfo, Comparable if (!(obj instanceof TypeInfo)) { return false; } - TypeInfo info= (TypeInfo)obj; + ITypeInfo info= (TypeInfo)obj; if (hashCode() != info.hashCode()) return false; - return getHashString().equals(info.getHashString()); + if (fElementType == info.getCElementType() + && fQualifiedName.equals(info.getQualifiedTypeName())) { + IProject project1 = getEnclosingProject(); + IProject project2 = info.getEnclosingProject(); + if (project1 == null && project2 == null) + return true; + if (project1 == null || project2 == null) + return false; + return project1.equals(project2); + } + return false; } public int compareTo(Object obj) { @@ -356,7 +165,9 @@ public class TypeInfo implements ITypeInfo, Comparable throw new ClassCastException(); } TypeInfo info= (TypeInfo)obj; - return getHashString().compareTo(info.getHashString()); + if (fElementType != info.fElementType) + return (fElementType < info.fElementType) ? -1 : 1; + return fQualifiedName.compareTo(info.getQualifiedTypeName()); } public static boolean isValidType(int type) { @@ -367,68 +178,10 @@ public class TypeInfo implements ITypeInfo, Comparable case ICElement.C_UNION: case ICElement.C_ENUMERATION: case ICElement.C_TYPEDEF: -// case ICElement.C_TEMPLATE_CLASS: -// case ICElement.C_TEMPLATE_STRUCT: -// case ICElement.C_TEMPLATE_UNION: return true; default: return false; } } - - public static String[] parseScopedName(String scopedName) { - ArrayList names= new ArrayList(5); - int lastIndex= 0; - String nextName; - int qualifierIndex= scopedName.indexOf(scopeResolutionOperator, 0); - while (qualifierIndex >= 0) { - nextName= scopedName.substring(lastIndex, qualifierIndex); - lastIndex= qualifierIndex + scopeResolutionOperator.length(); - names.add(nextName); - qualifierIndex= scopedName.indexOf(scopeResolutionOperator, lastIndex); - } - nextName= scopedName.substring(lastIndex); - names.add(nextName); - return (String[]) names.toArray(new String[names.size()]); - } - - final static private Comparator TYPE_NAME_COMPARATOR= new Comparator() { - public int compare(Object o1, Object o2) { - return ((ITypeInfo)o1).getName().compareTo(((ITypeInfo)o2).getName()); - } - }; - - public static ITypeInfo findType(String name, IPath path, ITypeInfo[] elements) { - if (elements == null) - return null; - - ITypeInfo key= new TypeInfo(name, 0, path, 0, 0); - - int index= Arrays.binarySearch(elements, key, TYPE_NAME_COMPARATOR); - if (index >= 0 && index < elements.length) { - for (int i= index - 1; i >= 0; i--) { - ITypeInfo curr= elements[i]; - if (key.getName().equals(curr.getName())) { - if (key.getQualifiedName().equals(curr.getQualifiedName())) { - return curr; - } - } else { - break; - } - } - for (int i= index; i < elements.length; i++) { - ITypeInfo curr= elements[i]; - if (key.getName().equals(curr.getName())) { - if (key.getQualifiedName().equals(curr.getQualifiedName())) { - return curr; - } - } else { - break; - } - } - } - return null; - } - } diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeReference.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeReference.java new file mode 100644 index 00000000000..c5c46ebc8c6 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeReference.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * 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.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ITranslationUnit; +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.IResource; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + + +public class TypeReference implements ITypeReference { + private IPath fPath; + private IProject fProject; + private IResource fResource; + private IWorkingCopy fWorkingCopy; + private int fOffset; + private int fLength; + + public TypeReference(IPath path, IProject project, int offset, int length) { + fPath = path; + fProject = project; + fWorkingCopy = null; + fResource = null; + fOffset = offset; + fLength = length; + } + + public TypeReference(IResource resource, IProject project, int offset, int length) { + fPath = null; + fProject = project; + fWorkingCopy = null; + fResource = resource; + fOffset = offset; + fLength = length; + } + + public TypeReference(IWorkingCopy workingCopy, IProject project, int offset, int length) { + fPath = null; + fProject = project; + fWorkingCopy = workingCopy; + fResource = null; + fOffset = offset; + fLength = length; + } + + public TypeReference(IPath path, IProject project) { + this(path, project, 0, 0); + } + + public TypeReference(IResource resource, IProject project) { + this(resource, project, 0, 0); + } + + public TypeReference(IWorkingCopy workingCopy, IProject project) { + this(workingCopy, project, 0, 0); + } + + public IPath getPath() { + if (fWorkingCopy != null) { + return fWorkingCopy.getPath(); + } else if (fResource != null) { + return fResource.getFullPath(); + } else { + return fPath; + } + } + + public IPath getLocation() { + if (fWorkingCopy != null) { + IResource resource = fWorkingCopy.getUnderlyingResource(); + if (resource != null) { + return resource.getLocation(); + } else { + return null; + } + } else if (fResource != null) { + return fResource.getLocation(); + } else if (fPath != null) { + return fPath; + } else if (fProject != null) { + return fProject.getLocation(); + } else { + return null; + } + } + + public IResource getResource() { + return fResource; + } + + public IWorkingCopy getWorkingCopy() { + return fWorkingCopy; + } + + public IProject getProject() { + if (fProject != null) { + return fProject; + } else { + if (fWorkingCopy != null) { + ICProject cProject = fWorkingCopy.getCProject(); + if (cProject != null) { + return cProject.getProject(); + } else { + return null; + } + } else if (fResource != null) { + return fResource.getProject(); + } else { + return null; + } + } + } + + public ITranslationUnit getTranslationUnit() { + ITranslationUnit unit = null; + if (fWorkingCopy != null) { + unit = fWorkingCopy.getTranslationUnit(); + } else if (fResource != null) { + ICElement elem = CoreModel.getDefault().create(fResource); + if (elem instanceof ITranslationUnit) + unit = (ITranslationUnit) elem; + } else { + IPath path = getLocation(); + ICElement elem = CoreModel.getDefault().create(path); + if (elem instanceof ITranslationUnit) + unit = (ITranslationUnit) elem; + } + + if (unit == null) { + IProject project = getProject(); + if (project != null) { + ICProject cProject = findCProject(project); + if (cProject != null) { + IPath path = getLocation(); + ICElement elem = CoreModel.getDefault().createTranslationUnitFrom(cProject, path); + if (elem instanceof ITranslationUnit) + unit = (ITranslationUnit) elem; + } + } + } + return unit; + } + + private ICProject findCProject(IProject project) { + try { + ICProject[] cProjects = CoreModel.getDefault().getCModel().getCProjects(); + if (cProjects != null) { + for (int i = 0; i < cProjects.length; ++i) { + ICProject cProject = cProjects[i]; + if (project.equals(cProjects[i].getProject())) + return cProject; + } + } + } catch (CModelException e) { + } + return null; + } + + public ICElement getCElement() { + ITranslationUnit unit = getTranslationUnit(); + if (unit != null) { + try { + return unit.getElementAtOffset(fOffset); + } catch (CModelException e) { + } + } + return null; + } + + public int getOffset() { + return fOffset; + } + + public int getLength() { + return fLength; + } + + public IPath getRelativeIncludePath(IProject project) { + IPath path = getLocation(); + if (path != null) { + IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project); + if (provider != null) { + IScannerInfo info = provider.getScannerInformation(project); + if (info != null) { + String[] includePaths = info.getIncludePaths(); + IPath relativePath = null; + int mostSegments = 0; + for (int i = 0; i < includePaths.length; ++i) { + IPath includePath = new Path(includePaths[i]); + if (includePath.isPrefixOf(path)) { + int segments = includePath.matchingFirstSegments(path); + if (segments > mostSegments) { + relativePath = path.removeFirstSegments(segments).setDevice(null); + mostSegments = segments; + } + } + } + if (relativePath != null) + path = relativePath; + } + } + } + return path; + } + + public IPath getRelativePath(IPath relativeToPath) { + IPath path = getPath(); + if (path != null) { + int segments = relativeToPath.matchingFirstSegments(path); + if (segments > 0) { + IPath prefix = relativeToPath.removeFirstSegments(segments).removeLastSegments(1); + IPath suffix = path.removeFirstSegments(segments); + IPath relativePath = new Path(""); //$NON-NLS-1$ + for (int i = 0; i < prefix.segmentCount(); ++i) { + relativePath = relativePath.append(".." + IPath.SEPARATOR); //$NON-NLS-1$ + } + return relativePath.append(suffix); + } + } + return path; + } + + public String toString() { + IPath path = getLocation(); + if (path != null) { + if (fLength == 0 && fOffset == 0) { + return path.toString(); + } else { + return path.toString() + ":" + fOffset + "-" + (fOffset + fLength); //$NON-NLS-1$//$NON-NLS-2$ + } + } else { + return ""; //$NON-NLS-1$ + } + } + + public int hashCode() { + return toString().hashCode(); + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ITypeReference)) { + return false; + } + ITypeReference ref = (ITypeReference)obj; + return toString().equals(ref.toString()); + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java new file mode 100644 index 00000000000..e7385c3f182 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeSearchScope.java @@ -0,0 +1,417 @@ +/******************************************************************************* + * 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 java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.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; + +public class TypeSearchScope implements ITypeSearchScope { + + private Set fPathSet = new HashSet(); + private Set fContainerSet = new HashSet(); + private Set fProjectSet = new HashSet(); + private Set fEnclosingProjectSet = new HashSet(); + private boolean fWorkspaceScope = false; + + // cached arrays + private IProject[] fAllProjects = null; + private IProject[] fProjects = null; + private IPath[] fContainerPaths = null; + + public TypeSearchScope() { + } + + public TypeSearchScope(boolean workspaceScope) { + fWorkspaceScope = workspaceScope; + } + + public TypeSearchScope(ITypeSearchScope scope) { + add(scope); + } + + public Collection pathSet() { + return fPathSet; + } + public Collection containerSet() { + return fContainerSet; + } + public Collection projectSet() { + return fProjectSet; + } + public Collection enclosingProjectSet() { + return fEnclosingProjectSet; + } + + public boolean encloses(ITypeSearchScope scope) { + if (isWorkspaceScope()) + return true; + + if (!scope.pathSet().isEmpty()) { + // check if this scope encloses the other scope's paths + for (Iterator i = scope.pathSet().iterator(); i.hasNext(); ) { + IPath path = (IPath) i.next(); + if (!encloses(path)) + return false; + } + } + + if (!scope.containerSet().isEmpty()) { + // check if this scope encloses the other scope's containers + for (Iterator i = scope.containerSet().iterator(); i.hasNext(); ) { + IPath path = (IPath) i.next(); + if (!encloses(path)) + return false; + } + } + + if (!scope.projectSet().isEmpty()) { + // check if this scope encloses the other scope's projects + for (Iterator i = scope.projectSet().iterator(); i.hasNext(); ) { + IProject project = (IProject) i.next(); + if (!encloses(project)) + return false; + } + } + + return true; + } + + public boolean encloses(IProject project) { + if (isWorkspaceScope()) + return true; + + // check projects that were explicity added to scope + if (fProjectSet.contains(project)) + return true; + + return false; + } + + public boolean encloses(IPath path) { + if (isWorkspaceScope()) + return true; + + // check files that were explicity added to scope + if (fPathSet.contains(path)) + return true; + + // check containers that were explicity added to scope + // including subdirs + if (fContainerSet.contains(path)) + return true; + if (fContainerPaths == null) { + fContainerPaths = (IPath[]) fContainerSet.toArray(new IPath[fContainerSet.size()]); +// java.util.Arrays.sort(fContainerPaths); + } + for (int i = 0; i < fContainerPaths.length; ++i) { + if (fContainerPaths[i].isPrefixOf(path)) { + return true; + } + } + + // check projects that were explicity added to scope + if (fProjectSet.contains(path)) + return true; + + // check projects that were explicity added to scope + if (fProjects == null) { + fProjects = (IProject[]) fProjectSet.toArray(new IProject[fProjectSet.size()]); + } + // check if one of the projects contains path + for (int i = 0; i < fProjects.length; ++i) { + if (projectContainsPath(fProjects[i], path, false)) { + return true; + } + } + + return false; + } + + public boolean encloses(String path) { + return encloses(new Path(path)); + } + + public boolean encloses(ICElement element) { + return encloses(element.getPath()); + } + + public boolean encloses(IWorkingCopy workingCopy) { + return encloses(workingCopy.getOriginalElement().getPath()); + } + + public IProject[] getEnclosingProjects() { + if (isWorkspaceScope()) { + return getAllProjects(); + } else { + return (IProject[]) fEnclosingProjectSet.toArray(new IProject[fEnclosingProjectSet.size()]); + } + } + + private static boolean projectContainsPath(IProject project, IPath path, boolean checkIncludePaths) { + IPath projectPath = project.getFullPath(); + if (projectPath.isPrefixOf(path)) { +// ISourceRoot[] sourceRoots = null; +// try { +// sourceRoots = cProject.getSourceRoots(); +// } catch (CModelException ex) { +// } +// if (sourceRoots != null) { +// for (int j = 0; j < sourceRoots.length; ++j) { +// ISourceRoot root = sourceRoots[j]; +// if (root.isOnSourceEntry(path)) +// return true; +// } +// } + return true; + } + + if (checkIncludePaths) { + //TODO this appears to be very slow -- cache this? + IPath[] includePaths = getIncludePaths(project); + if (includePaths != null) { + for (int i = 0; i < includePaths.length; ++i) { + IPath include = includePaths[i]; + if (include.isPrefixOf(path) || include.equals(path)) + return true; + } + } + } + + return false; + } + + private static IPath[] getIncludePaths(IProject project) { + IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project); + if (provider != null) { + IScannerInfo info = provider.getScannerInformation(project); + if (info != null) { + String[] includes = info.getIncludePaths(); + if (includes != null && includes.length > 0) { + IPath[] includePaths = new IPath[includes.length]; + for (int i = 0; i < includes.length; ++i) { + includePaths[i] = new Path(includes[i]); + } +// java.util.Arrays.sort(includePaths); + return includePaths; + } + } + } + return null; + } + + private static IProject[] getAllProjects() { + IProject[] projects = getCProjects(); + if (projects == null) + projects = new IProject[0]; + return projects; + } + + 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; + } else { + 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(); + } + + public boolean isProjectScope() { + return !fProjectSet.isEmpty(); + } + + public boolean isWorkspaceScope() { + return fWorkspaceScope; + } + + public boolean isEmpty() { + return (!isWorkspaceScope() && fPathSet.isEmpty() && fContainerSet.isEmpty() && fProjectSet.isEmpty()); + } + + public void add(IWorkingCopy workingCopy) { + IPath path = workingCopy.getOriginalElement().getPath(); + IProject enclosingProject = null; + ICProject cProject = workingCopy.getCProject(); + if (cProject != null) + enclosingProject = cProject.getProject(); + fPathSet.add(path); + if (enclosingProject != null) + addEnclosingProject(enclosingProject); + } + + public void add(IPath path, boolean addSubfolders, IProject enclosingProject) { + if (addSubfolders) { + fContainerSet.add(path); + fContainerPaths = null; + } else { + fPathSet.add(path); + } + if (enclosingProject != null) { + addEnclosingProject(enclosingProject); + } else { + // check all projects in workspace + if (fAllProjects == null) { + fAllProjects = getAllProjects(); + } + // check if one of the projects contains path + for (int i = 0; i < fAllProjects.length; ++i) { + if (projectContainsPath(fAllProjects[i], path, false)) { + addEnclosingProject(fAllProjects[i]); + break; + } + } + } + } + + public void add(IProject project) { + fProjectSet.add(project); + fProjects = null; + fAllProjects = null; + addEnclosingProject(project); + } + + private void addEnclosingProject(IProject project) { + fEnclosingProjectSet.add(project); + } + + public void addWorkspace() { + fWorkspaceScope = true; + fProjects = null; + fAllProjects = null; + } + + public void add(ICElement elem) { + if (elem == null) + return; + + switch (elem.getElementType()) { + case ICElement.C_MODEL: { + addWorkspace(); + break; + } + + case ICElement.C_PROJECT: { + IProject project = ((ICProject)elem).getProject(); + add(project); + break; + } + + case ICElement.C_CCONTAINER: { + IProject project = null; + ICProject cProject = elem.getCProject(); + if (cProject != null) + project = cProject.getProject(); + add(elem.getPath(), true, project); + break; + } + + case ICElement.C_UNIT: { + IProject project = null; + ICProject cProject = elem.getCProject(); + if (cProject != null) + project = cProject.getProject(); + add(elem.getPath(), false, project); + break; + } + + case ICElement.C_INCLUDE: + case ICElement.C_NAMESPACE: + case ICElement.C_TEMPLATE_CLASS: + case ICElement.C_CLASS: + case ICElement.C_STRUCT: + case ICElement.C_UNION: + case ICElement.C_ENUMERATION: + case ICElement.C_TYPEDEF: { + IProject project = null; + ICProject cProject = elem.getCProject(); + if (cProject != null) + project = cProject.getProject(); + add(elem.getPath(), false, project); + break; + } + } + } + + public void add(ITypeSearchScope scope) { + fPathSet.addAll(scope.pathSet()); + fContainerSet.addAll(scope.containerSet()); + fProjectSet.addAll(scope.projectSet()); + fEnclosingProjectSet.addAll(scope.enclosingProjectSet()); + fProjects = null; + fAllProjects = null; + fContainerPaths = null; + fWorkspaceScope |= scope.isWorkspaceScope(); + } + + public void clear() { + fPathSet.clear(); + fContainerSet.clear(); + fProjectSet.clear(); + fEnclosingProjectSet.clear(); + fWorkspaceScope = false; + fProjects = null; + fAllProjects = null; + fContainerPaths = null; + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/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..96df32d2581 --- /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 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.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..2a5a6f631f1 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * 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.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.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 true if cache is empty + */ + public boolean isEmpty(); + + /** Returns whether cache is complete. + * + * @return true if cache is up to date. + */ + public boolean isUpToDate(); + + /** Inserts type into cache. + * + * @param info + */ + public void insert(ITypeInfo info); + + /** 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 null 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 null 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 + * @return Array of types + */ + public ITypeInfo[] getTypes(IQualifiedTypeName qualifiedName); + + /** Returns first type in the cache which matches the given + * type and name. If no type is found, null + * 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); + + /** 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); + +} 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..a6d6e36be83 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerDependenciesJob.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * 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.internal.core.browser.cache; + +import java.io.IOException; + +import org.eclipse.cdt.core.browser.ITypeSearchScope; +import org.eclipse.cdt.internal.core.CharOperation; +import org.eclipse.cdt.internal.core.browser.util.PathUtil; +import org.eclipse.cdt.internal.core.index.IEntryResult; +import org.eclipse.cdt.internal.core.index.IIndex; +import org.eclipse.cdt.internal.core.index.impl.BlocksIndexInput; +import org.eclipse.cdt.internal.core.index.impl.IndexInput; +import org.eclipse.cdt.internal.core.index.impl.IndexedFile; +import org.eclipse.cdt.internal.core.search.indexing.IIndexConstants; +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(IIndexConstants.INCLUDE_REF); + 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(); + + IndexedFile 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) { + char[] word = entry.getWord(); + int firstSlash = CharOperation.indexOf(IIndexConstants.SEPARATOR, word, 0); + String include = String.valueOf(CharOperation.subarray(word, firstSlash + 1, -1)); + return PathUtil.getWorkspaceRelativePath(include); + } +} 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..7d24e7147a4 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerJob.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation 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: + * IBM Corp. - Rational Software - 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.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.IJob; +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 IJob { + + private IndexManager fIndexManager; + private IProject fProject; + private IIndex fProjectIndex = null; + public static final String FAMILY= "BasicTypeIndexerJob"; //$NON-NLS-1$ + + public IndexerJob(IndexManager indexManager, IProject project) { + fIndexManager = indexManager; + fProject = project; + } + + 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(); + } else { + 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; + + ReadWriteMonitor monitor = fIndexManager.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 + fIndexManager.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 + return fIndexManager.getIndex(path, true /*reuse index file*/, false /*do not create if none*/); + } +} + 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..33bdc1bc1b4 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * 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.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.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.CharOperation; +import org.eclipse.cdt.internal.core.browser.util.PathUtil; +import org.eclipse.cdt.internal.core.index.IEntryResult; +import org.eclipse.cdt.internal.core.index.IIndex; +import org.eclipse.cdt.internal.core.index.impl.BlocksIndexInput; +import org.eclipse.cdt.internal.core.index.impl.IndexInput; +import org.eclipse.cdt.internal.core.index.impl.IndexedFile; +import org.eclipse.cdt.internal.core.search.indexing.IIndexConstants; +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(IIndexConstants.NAMESPACE_DECL); + if (namespaceEntries != null) { + //TODO subprogress monitor + for (int i = 0; i < namespaceEntries.length; ++i) { + if (monitor.isCanceled()) + throw new InterruptedException(); + + IEntryResult entry = namespaceEntries[i]; + char[] word = entry.getWord(); + int firstSlash = CharOperation.indexOf(IIndexConstants.SEPARATOR, word, 0); + int slash = CharOperation.indexOf(IIndexConstants.SEPARATOR, word, firstSlash + 1); + String name = String.valueOf(CharOperation.subarray(word, firstSlash + 1, slash)); + if (name.length() != 0) { + String[] enclosingNames = getEnclosingNames(word, slash); + 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(IIndexConstants.TYPE_DECL); + if (typeEntries != null) { + //TODO subprogress monitor + for (int i = 0; i < typeEntries.length; ++i) { + if (monitor.isCanceled()) + throw new InterruptedException(); + + IEntryResult entry = typeEntries[i]; + char[] word = entry.getWord(); + int firstSlash = CharOperation.indexOf(IIndexConstants.SEPARATOR, word, 0); + char decodedType = word[firstSlash + 1]; + int type = getElementType(decodedType); + if (type != 0) { + firstSlash += 2; + int slash = CharOperation.indexOf(IIndexConstants.SEPARATOR, word, firstSlash + 1); + String name = String.valueOf(CharOperation.subarray(word, firstSlash + 1, slash)); + if (name.length() != 0) { // skip anonymous structs + String[] enclosingNames = getEnclosingNames(word, slash); + addType(input, project, entry, type, name, enclosingNames, monitor); + } + } + } + } + } + + private int getElementType(char decodedType) { + switch (decodedType) { + case IIndexConstants.CLASS_SUFFIX : + return ICElement.C_CLASS; + case IIndexConstants.STRUCT_SUFFIX : + return ICElement.C_STRUCT; + case IIndexConstants.TYPEDEF_SUFFIX : + return ICElement.C_TYPEDEF; + case IIndexConstants.ENUM_SUFFIX : + return ICElement.C_ENUMERATION; + case IIndexConstants.UNION_SUFFIX : + return ICElement.C_UNION; + } + return 0; + } + + private String[] getEnclosingNames(char[] word, int slash) { + String[] enclosingNames= null; + if (slash != -1 && slash + 1 < word.length) { + char[][] temp = CharOperation.splitOn('/', CharOperation.subarray(word, slash + 1, -1)); + enclosingNames= new String[temp.length]; + for (int i = 0; i < temp.length; i++) { + enclosingNames[i] = String.valueOf(temp[temp.length - i - 1]); + } + } + return enclosingNames; + } + + 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) { + if (info == null) { + info = new TypeInfo(type, qualifiedName, fTypeCache); + fTypeCache.insert(info); + } else { + info.setCElementType(type); + } + 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)); + } + } + } + } + } +} 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 90dadd6971c..d36fd10e347 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 @@ -18,135 +18,399 @@ 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.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.TypeInfo; +import org.eclipse.cdt.core.browser.TypeSearchScope; +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 { +public class TypeCache implements ITypeCache { - private static final int INITIAL_FILE_COUNT= 100; - private static final int INITIAL_TYPE_COUNT= INITIAL_FILE_COUNT*20; - private final Map fFileMap= new HashMap(INITIAL_FILE_COUNT); - private final Map fTypeMap= new HashMap(INITIAL_TYPE_COUNT); - private boolean fIsDirty= true; - - private static final class TypeReference { - private TypeInfo fRealInfo= null; - private Set fPaths= new HashSet(1); + private static final int INITIAL_TYPE_COUNT = 100; + private final Map fTypeNameMap = new HashMap(INITIAL_TYPE_COUNT); + private final IProject fProject; + private final IWorkingCopyProvider fWorkingCopyProvider; + private final Collection fDeltas = new ArrayList(); - public TypeReference(TypeInfo info, IPath path) { - fRealInfo= info; - fPaths.add(path); - } - - public TypeInfo getInfo() { - return fRealInfo; - } - - public void addPath(IPath path) { - fPaths.add(path); + private IJobChangeListener fJobChangeListener = new IJobChangeListener() { + public void aboutToRun(IJobChangeEvent event) { } - public void removePath(IPath path) { - fPaths.remove(path); + public void awake(IJobChangeEvent event) { } - - public Collection getPaths() { - return fPaths; + + 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); + // 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); + } + } + } + } + } + } + } + + public void running(IJobChangeEvent event) { + } + + public void scheduled(IJobChangeEvent event) { + } + + public void sleeping(IJobChangeEvent event) { } }; - - public TypeCache() { + + public TypeCache(IProject project, IWorkingCopyProvider workingCopyProvider) { + fProject = project; + fWorkingCopyProvider = workingCopyProvider; + fDeltas.add(new TypeCacheDelta(fProject)); } - public synchronized void markAsDirty(boolean dirty) { - fIsDirty= dirty; + 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 synchronized boolean isDirty() { - return fIsDirty; - } - - public synchronized Set getAllFiles() { - return fFileMap.keySet(); - } - - public synchronized Set getAllTypes() { - return fTypeMap.keySet(); - } - - private TypeInfo addTypeReference(TypeInfo info, IPath path) { - // we use info as a key here. the actual value found in - // the map corresponds to the 'real' TypeInfo object with - // the same hashCode - TypeReference typeRef= (TypeReference) fTypeMap.get(info); - if (typeRef == null) { - // add this type to cache - typeRef= new TypeReference(info, path); - fTypeMap.put(info, typeRef); - } else if (typeRef.getInfo() != info) { - typeRef.addPath(path); - } - return typeRef.getInfo(); - } - - private void removeTypeReference(TypeInfo info, IPath path) { - // we use info as a key here. the actual value found in - // the map corresponds to the 'real' TypeInfo object with - // the same hashCode - TypeReference typeRef= (TypeReference) fTypeMap.get(info); - if (typeRef == null) - return; - - typeRef.removePath(path); - for (Iterator i= typeRef.getPaths().iterator(); i.hasNext(); ) { - IPath p= (IPath) i.next(); - fFileMap.remove(p); - } - fTypeMap.remove(info); - } - - public synchronized void insert(IPath path, Collection types) { - Collection typeSet= (Collection) fFileMap.get(path); - if (typeSet == null) - typeSet= new ArrayList(types.size()); - for (Iterator typesIter= types.iterator(); typesIter.hasNext(); ) { - TypeInfo info= (TypeInfo)typesIter.next(); - TypeInfo newType= addTypeReference(info, path); - typeSet.add(newType); - } - fFileMap.put(path, typeSet); + public IProject getProject() { + return fProject; } - public synchronized boolean contains(IPath path) { - return fFileMap.containsKey(path); + public synchronized boolean isEmpty() { + return fTypeNameMap.isEmpty(); } + public synchronized void insert(ITypeInfo info) { + // check if enclosing types are already in cache + IQualifiedTypeName typeName = info.getQualifiedTypeName().getEnclosingTypeName(); + if (typeName != null) { + while (!typeName.isEmpty()) { + boolean foundType = false; + Collection typeCollection = (Collection) fTypeNameMap.get(typeName.getName()); + if (typeCollection == null) { + typeCollection = new HashSet(); + fTypeNameMap.put(typeName.getName(), typeCollection); + } else { + for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) { + ITypeInfo curr = (ITypeInfo) typeIter.next(); + if (curr.getQualifiedTypeName().equals(typeName)) { + foundType = true; + break; + } + } + } + if (!foundType) { + // create a dummy type to take this place (type 0 == unknown) + ITypeInfo dummyType = new TypeInfo(0, typeName, this); + typeCollection.add(dummyType); + } + typeName = typeName.removeLastSegments(1); + } + } + + Collection typeCollection = (Collection) fTypeNameMap.get(info.getName()); + if (typeCollection == null) { + typeCollection = new HashSet(); + fTypeNameMap.put(info.getName(), typeCollection); + } + typeCollection.add(info); + } + + public synchronized void remove(ITypeInfo info) { + Collection typeCollection = (Collection) fTypeNameMap.get(info.getName()); + if (typeCollection != null) { + typeCollection.remove(info); + } + } + + public synchronized void flush(ITypeSearchScope scope) { + if (scope.encloses(fProject)) { + flushAll(); + } else { + for (Iterator mapIter = fTypeNameMap.entrySet().iterator(); mapIter.hasNext(); ) { + Map.Entry entry = (Map.Entry) mapIter.next(); + Collection typeCollection = (Collection) entry.getValue(); + for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) { + ITypeInfo info = (ITypeInfo) typeIter.next(); + if (info.isEnclosed(scope)) { + typeIter.remove(); + } + } + if (typeCollection.isEmpty()) + mapIter.remove(); + } + } + } + public synchronized void flush(IPath path) { - Collection typeSet= (Collection) fFileMap.get(path); - if (typeSet != null) { - for (Iterator typesIter= typeSet.iterator(); typesIter.hasNext(); ) { - TypeInfo info= (TypeInfo)typesIter.next(); - removeTypeReference(info, path); - } - fFileMap.remove(path); - } - fIsDirty= true; - } - - public synchronized void flush(Set paths) { - if (paths != null) { - // flush paths from cache - for (Iterator i= paths.iterator(); i.hasNext(); ) { - IPath path= (IPath) i.next(); - flush(path); - } - } + ITypeSearchScope scope = new TypeSearchScope(); + scope.add(path, false, null); + flush(scope); } public synchronized void flushAll() { // flush the entire cache - fFileMap.clear(); - fTypeMap.clear(); - fIsDirty= true; + fTypeNameMap.clear(); + } + + public synchronized void accept(ITypeInfoVisitor visitor) { + for (Iterator mapIter = fTypeNameMap.entrySet().iterator(); mapIter.hasNext(); ) { + Map.Entry entry = (Map.Entry) mapIter.next(); + Collection typeCollection = (Collection) entry.getValue(); + for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) { + ITypeInfo info = (ITypeInfo) typeIter.next(); + visitor.visit(info); + } + } + } + + public synchronized IPath[] getPaths(ITypeSearchScope scope) { + final Set fPathSet = new HashSet(); + final ITypeSearchScope fScope = scope; + accept(new ITypeInfoVisitor() { + public void visit(ITypeInfo info) { + if (fScope == null || info.isEnclosed(fScope)) { + ITypeReference[] refs = info.getReferences(); + for (int i = 0; i < refs.length; ++i) { + IPath path = refs[i].getPath(); + if (fScope == null || fScope.encloses(path)) + fPathSet.add(path); + } + } + } + }); + return (IPath[]) fPathSet.toArray(new IPath[fPathSet.size()]); + } + + public synchronized ITypeInfo[] getTypes(ITypeSearchScope scope) { + final Collection fTypesFound = new ArrayList(); + final ITypeSearchScope fScope = scope; + accept(new ITypeInfoVisitor() { + public void visit(ITypeInfo info) { + if (fScope == null || info.isEnclosed(fScope)) { + fTypesFound.add(info); + } + } + }); + return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]); + } + + public synchronized ITypeInfo[] getTypes(IQualifiedTypeName qualifiedName) { + Collection results = new ArrayList(); + Collection typeCollection = (Collection) fTypeNameMap.get(qualifiedName.getName()); + if (typeCollection != null) { + for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) { + ITypeInfo info = (ITypeInfo) typeIter.next(); + if (info.getQualifiedTypeName().equals(qualifiedName)) { + results.add(info); + } + } + } + return (ITypeInfo[]) results.toArray(new ITypeInfo[results.size()]); + } + + public synchronized ITypeInfo getType(int type, IQualifiedTypeName qualifiedName) { + Collection typeCollection = (Collection) fTypeNameMap.get(qualifiedName.getName()); + if (typeCollection != null) { + for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) { + ITypeInfo info = (ITypeInfo) typeIter.next(); + if (info.getQualifiedTypeName().equals(qualifiedName) + && (info.getCElementType() == type || info.getCElementType() == 0)) { + return info; + } + } + } + return null; + } + + 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; + synchronized(fDeltas) { + // grab all the remaining deltas + TypeCacheDelta[] jobDeltas = (TypeCacheDelta[]) fDeltas.toArray(new TypeCacheDelta[fDeltas.size()]); + + // create a new job + deltaJob = new TypeCacherJob(this, jobDeltas, enableIndexing); + // assign deltas to job + if (jobDeltas != null) { + for (int i = 0; i < jobDeltas.length; ++i) { + jobDeltas[i].assignToJob(deltaJob); + } + } + } + + // 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(); + } + } + } + + 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(); } } 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..0cd143bc51c --- /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 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.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/TypeCacheDeltaListener.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheDeltaListener.java deleted file mode 100644 index 9adf1df2749..00000000000 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheDeltaListener.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Created on Apr 20, 2004 - * - * To change the template for this generated file go to - * Window - Preferences - Java - Code Generation - Code and Comments - */ -package org.eclipse.cdt.internal.core.browser.cache; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.eclipse.cdt.core.browser.AllTypesCache.IWorkingCopyProvider; -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.IElementChangedListener; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.jobs.IJobManager; -import org.eclipse.core.runtime.jobs.Job; - - -/** - * Listener for changes to CModel. - * @see org.eclipse.cdt.core.model.IElementChangedListener - * @since 3.0 - */ -public class TypeCacheDeltaListener implements IElementChangedListener { - - private TypeCache fTypeCache; - private IWorkingCopyProvider fWorkingCopyProvider; - private Set fPaths= new HashSet(5); - private Set fPrefixes= new HashSet(5); - private boolean fFlushAll= false; - private boolean fCreateBackgroundJob= true; - - public TypeCacheDeltaListener(TypeCache cache, IWorkingCopyProvider workingCopyProvider, boolean createBackgroundJob) { - fTypeCache= cache; - fWorkingCopyProvider = workingCopyProvider; - fCreateBackgroundJob= createBackgroundJob; - } - - public void setBackgroundJobEnabled(boolean enabled) { - fCreateBackgroundJob= enabled; - } - - /* - * @see IElementChangedListener#elementChanged - */ - public void elementChanged(ElementChangedEvent event) { - fPaths.clear(); - fPrefixes.clear(); - fFlushAll= false; - - boolean needsFlushing= processDelta(event.getDelta()); - if (needsFlushing) { - // cancel background job - IJobManager jobMgr = Platform.getJobManager(); - jobMgr.cancel(TypeCacherJob.FAMILY); - TypeCacherJob typeCacherJob = new TypeCacherJob(fTypeCache, fWorkingCopyProvider); - if (fFlushAll) { - // flush the entire cache - typeCacherJob.setSearchPaths(null); - fTypeCache.flushAll(); - } else { - // flush affected files from cache - Set searchPaths= new HashSet(10); - getPrefixMatches(fPrefixes, searchPaths); - searchPaths.addAll(fPaths); - typeCacherJob.setSearchPaths(searchPaths); - fTypeCache.flush(searchPaths); - } - - // restart the background job - if (fCreateBackgroundJob) { - typeCacherJob.setPriority(Job.BUILD); - typeCacherJob.schedule(); - } - } - } - - /* - * returns true if the cache needs to be flushed - */ - private boolean processDelta(ICElementDelta delta) { - ICElement elem= delta.getElement(); - int pathEntryChanged= ICElementDelta.F_ADDED_PATHENTRY_SOURCE | ICElementDelta.F_REMOVED_PATHENTRY_SOURCE | - ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE | ICElementDelta.F_CHANGED_PATHENTRY_MACRO; - boolean isAddedOrRemoved= (((delta.getKind() != ICElementDelta.CHANGED) - || ((delta.getFlags() & pathEntryChanged) != 0)) && (delta.getFlags() & ICElementDelta.F_CHILDREN) == 0); - switch (elem.getElementType()) { - case ICElement.C_MODEL: - return processDeltaChildren(delta); - - case ICElement.C_PROJECT: - case ICElement.C_CCONTAINER: - { - if (isAddedOrRemoved) { - // project or folder has changed - // flush all files with matching prefix - IPath path= elem.getPath(); - if (path != null) - fPrefixes.add(path); - return true; - } - return processDeltaChildren(delta); - } - - 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: - case ICElement.C_INCLUDE: - case ICElement.C_UNIT: - { - if (isAddedOrRemoved) { - // CElement has changed - // flush file from cache - IPath path= elem.getPath(); - if (path != null) - fPaths.add(path); - return true; - } - return processDeltaChildren(delta); - } - - default: - // fields, methods, imports ect - return false; - } - } - - private boolean processDeltaChildren(ICElementDelta delta) { - ICElementDelta[] children= delta.getAffectedChildren(); - for (int i= 0; i < children.length; i++) { - if (processDelta(children[i])) { - return true; - } - } - return false; - } - - private boolean getPrefixMatches(Set prefixes, Set results) { - Set pathSet= fTypeCache.getAllFiles(); - if (pathSet.isEmpty() || prefixes == null || prefixes.isEmpty()) - return false; - - for (Iterator pathIter= pathSet.iterator(); pathIter.hasNext(); ) { - IPath path= (IPath) pathIter.next(); - - // find paths which match prefix - for (Iterator prefixIter= prefixes.iterator(); prefixIter.hasNext(); ) { - IPath prefix= (IPath) prefixIter.next(); - if (prefix.isPrefixOf(path)) { - results.add(path); - break; - } - } - } - - return !results.isEmpty(); - } -} 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..6f4c802aaa1 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * 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.internal.core.browser.cache; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.browser.IWorkingCopyProvider; +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.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.Platform; +import org.eclipse.core.runtime.jobs.IJobManager; + +public class TypeCacheManager { + + private Map fCacheMap = new HashMap(); + private IWorkingCopyProvider fWorkingCopyProvider; + + public TypeCacheManager(IWorkingCopyProvider workingCopyProvider) { + fWorkingCopyProvider = workingCopyProvider; + } + + public synchronized void updateProject(IProject project) { + TypeCacheDelta cacheDelta = new TypeCacheDelta(project); + getCache(project).addDelta(cacheDelta); + } + + 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; + + public synchronized void 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 hasChildren = ((delta.getFlags() & ICElementDelta.F_CHILDREN) != 0); + + switch (elem.getElementType()) { + case ICElement.C_PROJECT: + case ICElement.C_CCONTAINER: { + ICProject cProject = elem.getCProject(); + IProject project = cProject.getProject(); + if (added || removed || pathEntryChanged) { + TypeCacheDelta cacheDelta = new TypeCacheDelta(project, delta); + getCache(project).addDelta(cacheDelta); + } + } + break; + + case ICElement.C_UNIT: { + ICProject cProject = elem.getCProject(); + IProject project = cProject.getProject(); + ITranslationUnit unit = (ITranslationUnit) elem; + if (unit.isWorkingCopy()) { + processWorkingCopyDelta(delta); + return; + } else { + 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) { + processDelta(children[i]); + } + } + } + } + + public synchronized void processWorkingCopyDelta(ICElementDelta delta) { + // ignore workies copies for now + return; +/* 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); + fCacheMap.put(project, cache); + } + return cache; + } + } + + public synchronized void reconcile(boolean enableIndexing, int priority, int delay) { + 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) { + 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); + } +} 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 index 273052e91ae..bfdf6461efa 100644 --- 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 @@ -9,5 +9,11 @@ # QNX Software Systems - Initial API and implementation ############################################################################### -TypeCacherJob.jobName=TypeCache -TypeCacherJob.taskName=Updating Type Info... +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... 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 index 59d7d456c61..d05c42f492b 100644 --- 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 @@ -10,29 +10,18 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.browser.cache; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.browser.AllTypesCache.IWorkingCopyProvider; -import org.eclipse.cdt.core.model.IWorkingCopy; +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.core.search.ICSearchScope; -import org.eclipse.cdt.internal.core.browser.util.DelegatedProgressMonitor; import org.eclipse.cdt.internal.core.model.CModelManager; -import org.eclipse.cdt.internal.core.search.CWorkspaceScope; -import org.eclipse.cdt.internal.core.search.PatternSearchJob; import org.eclipse.cdt.internal.core.search.indexing.IndexManager; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.runtime.IPath; +import org.eclipse.core.resources.IProject; 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.SubProgressMonitor; -import org.eclipse.core.runtime.jobs.ISchedulingRule; -import org.eclipse.core.runtime.jobs.Job; /** @@ -40,169 +29,197 @@ import org.eclipse.core.runtime.jobs.Job; * @see org.eclipse.core.runtime.jobs.Job * @since 3.0 */ -public class TypeCacherJob extends Job { - - /** - * An "identity rule" that forces jobs to be queued. - * @see org.eclipse.core.runtime.jobs.ISchedulingRule - * @since 3.0 - */ - final static ISchedulingRule MUTEX_RULE= new ISchedulingRule() { - public boolean contains(ISchedulingRule rule) { - return rule == this; - } - public boolean isConflicting(ISchedulingRule rule) { - return rule == this; - } - }; +public class TypeCacherJob extends BasicJob { - /** - * Constant identifying the job family identifier for the background job. - * @see IJobManager#join(Object, IProgressMonitor) - * @since 3.0 - */ - public static final Object FAMILY= new Object(); + public static final Object FAMILY = new Object(); + private IndexManager fIndexManager; + private ITypeCache fTypeCache; + private TypeCacheDelta[] fDeltas; + private boolean fEnableIndexing; - private Set fSearchPaths= new HashSet(50); - private TypeCache fTypeCache; - private IWorkingCopyProvider fWorkingCopyProvider; - private DelegatedProgressMonitor fProgressMonitor= new DelegatedProgressMonitor(); - - public TypeCacherJob(TypeCache cache, IWorkingCopyProvider provider) { - super(TypeCacheMessages.getString("TypeCacherJob.jobName")); //$NON-NLS-1$ + public TypeCacherJob(ITypeCache typeCache, TypeCacheDelta[] deltas, boolean enableIndexing) { + super(TypeCacheMessages.getString("TypeCacherJob.defaultJobName"), FAMILY); //$NON-NLS-1$ + fTypeCache = typeCache; + fDeltas = deltas; + fEnableIndexing = enableIndexing; + fIndexManager = CModelManager.getDefault().getIndexManager(); setPriority(BUILD); setSystem(true); - //setRule(MUTEX_RULE); - fTypeCache= cache; - fWorkingCopyProvider= provider; + setRule(typeCache); + setName(TypeCacheMessages.getFormattedString("TypeCacherJob.jobName", fTypeCache.getProject().getName())); //$NON-NLS-1$ + } + + public ITypeCache getCache() { + return fTypeCache; } - /* (non-Javadoc) - * @see org.eclipse.core.internal.jobs.InternalJob#belongsTo(java.lang.Object) - */ - public boolean belongsTo(Object family) { - return family == FAMILY; + public TypeCacheDelta[] getDeltas() { + return fDeltas; } - - public void setSearchPaths(Set paths) { - fSearchPaths.clear(); - if (paths != null) - fSearchPaths.addAll(paths); - } - + /* (non-Javadoc) * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor) */ - public IStatus run(IProgressMonitor monitor) { - if (monitor.isCanceled()) - return Status.CANCEL_STATUS; - - fProgressMonitor.init(); - fProgressMonitor.addDelegate(monitor); + protected IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException { + boolean success = false; + long startTime = System.currentTimeMillis(); + trace("TypeCacherJob: started"); //$NON-NLS-1$ try { - search(fProgressMonitor); - fProgressMonitor.done(); - } catch(InterruptedException ex) { - return Status.CANCEL_STATUS; - } catch (OperationCanceledException ex) { - return Status.CANCEL_STATUS; - } finally { - fProgressMonitor.removeAllDelegates(); - fProgressMonitor.init(); - } + 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; } - /** - * Forwards progress info to the progress monitor and - * blocks until the job is finished. - * - * @param monitor Optional progress monitor. - * @throws InterruptedException - * - * @see Job#join - */ - public void join(IProgressMonitor monitor) throws InterruptedException { - fProgressMonitor.addDelegate(monitor); - super.join(); - } - - private void search(IProgressMonitor monitor) throws InterruptedException { + private void flush(ITypeSearchScope scope, IProgressMonitor monitor) throws InterruptedException { + // flush the cache + boolean success = true; + IProject project = fTypeCache.getProject(); - monitor.beginTask(TypeCacheMessages.getString("TypeCacherJob.taskName"), 100); //$NON-NLS-1$ - - IWorkspace workspace= CCorePlugin.getWorkspace(); - if (workspace == null) - throw new InterruptedException(); - - ICSearchScope scope= new CWorkspaceScope(); + monitor.beginTask("", 100); //$NON-NLS-1$ - // search for types and #include references - TypeSearchPattern pattern= new TypeSearchPattern(); - for (Iterator pathIter= fSearchPaths.iterator(); pathIter.hasNext(); ) { - IPath path= (IPath) pathIter.next(); - pattern.addDependencySearch(path); - } - TypeSearchPathCollector pathCollector= new TypeSearchPathCollector(); - - CModelManager modelManager= CModelManager.getDefault(); - IndexManager indexManager= modelManager.getIndexManager(); - - if (monitor.isCanceled()) - throw new InterruptedException(); - - SubProgressMonitor subMonitor= new SubProgressMonitor(monitor, 5); - - /* index search */ - indexManager.performConcurrentJob( - new PatternSearchJob( - pattern, - scope, - pathCollector, - indexManager - ), - ICSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, - subMonitor, - null ); - - if (monitor.isCanceled()) - throw new InterruptedException(); - - if (!fSearchPaths.isEmpty()) { - // flush all affected files from cache - fTypeCache.flush(fSearchPaths); - Set dependencyPaths= pathCollector.getDependencyPaths(); - if (dependencyPaths != null && !dependencyPaths.isEmpty()) { - fTypeCache.flush(dependencyPaths); + fTypeCache.flush(scope); + if (!scope.encloses(project)) { + if (project.exists() && project.isOpen()) { + success = false; + if (fEnableIndexing) { + success = fIndexManager.performConcurrentJob( + new IndexerDependenciesJob(fIndexManager, fTypeCache, scope), + ICSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor, null); + } } } - Set allSearchPaths= pathCollector.getPaths(); - if (allSearchPaths == null) - allSearchPaths= new HashSet(); - - // remove cached files - allSearchPaths.removeAll(fTypeCache.getAllFiles()); - - if (monitor.isCanceled()) + if (!success || monitor.isCanceled()) { throw new InterruptedException(); - - subMonitor= new SubProgressMonitor(monitor, 95); + } - IWorkingCopy[] workingCopies= null; - if (fWorkingCopyProvider != null) - workingCopies= fWorkingCopyProvider.getWorkingCopies(); - - TypeMatchCollector collector= new TypeMatchCollector(fTypeCache, subMonitor); - TypeMatchLocator matchLocator= new TypeMatchLocator(collector); - matchLocator.locateMatches(allSearchPaths, workspace, workingCopies); - - if (monitor.isCanceled()) - throw new InterruptedException(); - - fTypeCache.markAsDirty(false); 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 = false; + if (fEnableIndexing) { + success = fIndexManager.performConcurrentJob( + new IndexerTypesJob(fIndexManager, fTypeCache, scope), + ICSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor, null); + } + } + + if (!success || monitor.isCanceled()) { + throw new InterruptedException(); + } + + monitor.done(); + } + + 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; + } + } + } } + 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..d5ebd5472ea --- /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 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.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/TypeMatchCollector.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeMatchCollector.java deleted file mode 100644 index 0e3e726c77f..00000000000 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeMatchCollector.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * 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.internal.core.browser.cache; - -import java.util.ArrayList; - -import org.eclipse.cdt.core.browser.TypeInfo; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; - -public class TypeMatchCollector { - private ArrayList results= new ArrayList(); - private TypeCache typeCache; - private IProgressMonitor progressMonitor; - - public TypeMatchCollector(TypeCache cache, IProgressMonitor monitor) { - progressMonitor= monitor; - typeCache= cache; - } - - public IProgressMonitor getProgressMonitor() { - return progressMonitor; - } - - public boolean beginParsing(IPath path) { - // check if path is in the cache already - if (typeCache.contains(path)) - return false; - - results.clear(); - return true; - } - - public void doneParsing(IPath path) { - if (!results.isEmpty()) { - // add types to cache - typeCache.insert(path, results); - } - } - - public void acceptType(String name, int type, String[] enclosingNames, IResource resource, IPath path, int startOffset, int endOffset) { - // create new type info - TypeInfo info= new TypeInfo(name, type, enclosingNames, resource, path, startOffset, endOffset); - results.add(info); - } -} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeMatchLocator.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeMatchLocator.java deleted file mode 100644 index a1965b6d8b7..00000000000 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeMatchLocator.java +++ /dev/null @@ -1,578 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 IBM Corporation 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: - * IBM Corp. - Rational Software - initial implementation - * QNX Software Systems - adapted for type search - *******************************************************************************/ -package org.eclipse.cdt.internal.core.browser.cache; - -import java.io.CharArrayReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.InputStreamReader; -import java.io.Reader; -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.model.CoreModel; -import org.eclipse.cdt.core.model.ICElement; -import org.eclipse.cdt.core.model.IWorkingCopy; -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.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.ParserUtil; -import org.eclipse.cdt.core.parser.ScannerInfo; -import org.eclipse.cdt.core.parser.ast.ASTClassKind; -import org.eclipse.cdt.core.parser.ast.IASTASMDefinition; -import org.eclipse.cdt.core.parser.ast.IASTAbstractTypeSpecifierDeclaration; -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.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.core.search.ICSearchConstants; -import org.eclipse.cdt.core.search.ICSearchPattern; -import org.eclipse.cdt.internal.core.browser.util.PathUtil; -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; - -public class TypeMatchLocator implements ISourceElementRequestor, ICSearchConstants { - private ISourceElementCallbackDelegate lastDeclaration; - private ICSearchPattern searchPattern; - private TypeMatchCollector resultCollector; - private IProgressMonitor progressMonitor; - private IWorkspaceRoot workspaceRoot= null; - private SimpleStack scopeStack= new SimpleStack(); - private SimpleStack resourceStack= new SimpleStack(); - private static boolean VERBOSE= false; - - public TypeMatchLocator(TypeMatchCollector collector) { - super(); - searchPattern= new TypeSearchPattern(); - resultCollector= collector; - progressMonitor= collector.getProgressMonitor(); - if (progressMonitor == null) - progressMonitor= new NullProgressMonitor(); - } - - 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 acceptTypedefDeclaration(IASTTypedefDeclaration typedef){ - lastDeclaration = typedef; - check( DECLARATIONS, typedef ); - } - - public void acceptEnumerationSpecifier(IASTEnumerationSpecifier enumeration){ - lastDeclaration = enumeration; - check( DECLARATIONS, enumeration ); - } - - public void acceptElaboratedForewardDeclaration(IASTElaboratedTypeSpecifier elaboratedType){ - check( DECLARATIONS, elaboratedType ); - } - - 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) { - lastDeclaration = namespaceDefinition; - check( DECLARATIONS, namespaceDefinition ); - check( DEFINITIONS, namespaceDefinition ); - pushScope( namespaceDefinition ); - } - public void exitNamespaceDefinition(IASTNamespaceDefinition namespaceDefinition) { - popScope(); - } - - public void enterClassSpecifier(IASTClassSpecifier classSpecification) { - lastDeclaration = classSpecification; - check( DECLARATIONS, classSpecification ); - pushScope( classSpecification ); - } - public void exitClassSpecifier(IASTClassSpecifier classSpecification) { - popScope(); - } - - public void enterInclusion(IASTInclusion inclusion) { - String includePath = inclusion.getFullFileName(); - - IPath path = new Path( includePath ); - IResource resource = null; - - if (workspaceRoot != null) - resource = workspaceRoot.getFileForLocation( path ); - - if (resource == null) { - // we need to standardize the paths for external headers - path = PathUtil.getCanonicalPath(includePath); - } - - if (resource != null) - resourceStack.push(resource); - else - resourceStack.push(path); - - if (progressMonitor.isCanceled()) - throw new OperationCanceledException(); - } - - public void exitInclusion(IASTInclusion inclusion) { - resourceStack.pop(); - - if (progressMonitor.isCanceled()) - throw new OperationCanceledException(); - } - - protected void report( ISourceElementCallbackDelegate node, int accuracyLevel ){ - int offset = 0; - int end = 0; - IASTOffsetableNamedElement offsetable = null; - String name = null; - int type = 0; - - if( node instanceof IASTReference ){ - IASTReference reference = (IASTReference) node; - offset = reference.getOffset(); - end = offset + reference.getName().length(); - if (VERBOSE) - verbose("Report Match: " + reference.getName()); //$NON-NLS-1$ - } 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 (VERBOSE) - verbose("Report Match: " + offsetable.getName()); //$NON-NLS-1$ - } - - if (node instanceof IASTReference) - node = lastDeclaration; - - 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; - } - - // skip unnamed structs - if (name == null || name.length() == 0) - return; - - // skip unused types - type= getElementType(offsetable); - if (type == 0) { - return; - } - - // collect enclosing names - String[] enclosingNames = null; - 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); - } - } - -// // collect enclosing files -// IPath[] enclosingPaths= null; -// Object[] sourceRefs= resourceStack.toArray(); -// // assert(sourceRefs.length > 0) -// -// // walk through resource stack and -// // collect enclosing paths -// enclosingPaths= new IPath[sourceRefs.length-1]; -// for (int i= 0; i < sourceRefs.length-1; ++i) { -// Object obj= sourceRefs[i]; -// IPath sourcePath= null; -// if (obj instanceof IResource) { -// IResource res= (IResource) obj; -// enclosingPaths[i]= res.getFullPath(); -// } else { -// enclosingPaths[i]= (IPath) obj; -// } -// } - - IResource resource= null; - IPath path= null; - Object obj= resourceStack.top(); - if (obj instanceof IResource) - resource= (IResource) obj; - else - path= (IPath) obj; - - resultCollector.acceptType(name, type, enclosingNames, resource, path, offset, end); - } - - private void check( LimitTo limit, ISourceElementCallbackDelegate node ){ - - if (progressMonitor.isCanceled()) - throw new OperationCanceledException(); - - // skip local declarations - IASTScope currentScope= (IASTScope)scopeStack.top(); - if (currentScope instanceof IASTFunction || currentScope instanceof IASTMethod) { - return; - } - - // always limit == DECLARATIONS -// -// if( !searchPattern.canAccept( limit ) ) -// return; - - int level = ICSearchPattern.IMPOSSIBLE_MATCH; - - if( node instanceof IASTReference ){ - level = searchPattern.matchLevel( ((IASTReference)node).getReferencedElement(), limit ); - } else { - level = searchPattern.matchLevel( node, limit ); - } - - if( level != ICSearchPattern.IMPOSSIBLE_MATCH ) - { - report( node, level ); - } - } - - private void pushScope( IASTScope scope ){ - scopeStack.push(scope); - - if (progressMonitor.isCanceled()) - throw new OperationCanceledException(); - } - - private IASTScope popScope(){ - IASTScope oldScope= (IASTScope) scopeStack.pop(); - - if (progressMonitor.isCanceled()) - throw new OperationCanceledException(); - - return oldScope; - } - - private static void verbose(String log) { - System.out.println("(" + Thread.currentThread() + ") " + log); //$NON-NLS-1$ //$NON-NLS-2$ - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.core.parser.ISourceElementRequestor#createReader(java.lang.String) - */ - public Reader createReader(String finalPath, Iterator workingCopies) { - return ParserUtil.createReader(finalPath, workingCopies); - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.core.parser.ISourceElementRequestor#parserTimeout() - */ - public boolean parserTimeout() { - return false; - } - - - public void locateMatches(Set searchPaths, IWorkspace workspace, IWorkingCopy[] workingCopies) throws InterruptedException { - workspaceRoot= (workspace != null) ? workspace.getRoot() : null; - - Set searchablePaths= new HashSet(searchPaths); - Map workingCopyMap= null; - - 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(); - workingCopyMap.put(wcPath, workingCopy); - searchablePaths.add(wcPath); - } - } - - progressMonitor.beginTask("", searchablePaths.size()); //$NON-NLS-1$ - - for (Iterator i= searchablePaths.iterator(); i.hasNext(); ) { - - if (progressMonitor.isCanceled()) - throw new InterruptedException(); - - IPath path= (IPath) i.next(); - - if (!resultCollector.beginParsing(path)) - continue; - - Reader reader= null; - IPath realPath= null; - IProject project= null; - IResource currentResource= null; - IPath currentPath= null; - - progressMonitor.worked(1); - - if (workspaceRoot != null) { - IWorkingCopy workingCopy= null; - if (workingCopyMap != null) - workingCopy= (IWorkingCopy) workingCopyMap.get(path); - if (workingCopy != null) { - currentResource= workingCopy.getResource(); - if (currentResource != null && currentResource.isAccessible()) { - reader= new CharArrayReader(workingCopy.getContents()); - } else { - continue; - } - } else { - currentResource= workspaceRoot.findMember(path, true); - if (currentResource != null) { - if (currentResource.isAccessible() && currentResource instanceof IFile) { - IFile file= (IFile) currentResource; - try { - reader= new InputStreamReader(file.getContents()); - } catch (CoreException ex) { - continue; - } - } else { - continue; - } - } - } - } - - if (currentResource == null) { - try { - reader= new FileReader(path.toFile()); - } catch (FileNotFoundException ex) { - continue; - } - currentPath= path; - realPath= currentPath; - project= null; - } else { - currentPath= null; - realPath= currentResource.getLocation(); - project= currentResource.getProject(); - } - - if (currentResource != null) - resourceStack.push(currentResource); - else - resourceStack.push(currentPath); - - parseMatches(path, reader, realPath, project); - - resourceStack.pop(); - - resultCollector.doneParsing(path); - - if (progressMonitor.isCanceled()) - throw new InterruptedException(); - } - - progressMonitor.done(); - } - - private void parseMatches(IPath path, Reader reader, IPath realPath, IProject project) throws InterruptedException { - //Get the scanner info - IScannerInfo scanInfo = new ScannerInfo(); - IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project); - if (provider != null){ - IScannerInfo buildScanInfo = provider.getScannerInformation(project); - if( buildScanInfo != null ) - scanInfo = new ScannerInfo(buildScanInfo.getDefinedSymbols(), buildScanInfo.getIncludePaths()); - } - - ParserLanguage language = null; - if( project != null ){ - language = CoreModel.getDefault().hasCCNature( project ) ? ParserLanguage.CPP : ParserLanguage.C; - } else { - //TODO no project, what language do we use? - language = ParserLanguage.CPP; - } - - IParser parser = null; - try - { - IScanner scanner = ParserFactory.createScanner( reader, realPath.toOSString(), scanInfo, ParserMode.COMPLETE_PARSE, language, this, ParserUtil.getScannerLogService(), null ); - parser = ParserFactory.createParser( scanner, this, ParserMode.STRUCTURAL_PARSE, language, ParserUtil.getParserLogService() ); - } - catch( ParserFactoryError pfe ) - { - - } - - if (VERBOSE) - verbose("*** New Search for path: " + path); //$NON-NLS-1$ - - try { - parser.parse(); - } - catch(OperationCanceledException ex) { - throw new InterruptedException(); - } - catch(Exception ex) { - if (VERBOSE){ - ex.printStackTrace(); - } - } - catch(VirtualMachineError vmErr){ - if (VERBOSE){ - verbose("TypeMatchLocator VM Error: "); //$NON-NLS-1$ - vmErr.printStackTrace(); - } - } - } - - private 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; - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.core.parser.ISourceElementRequestor#acceptFriendDeclaration(org.eclipse.cdt.core.parser.ast.IASTDeclaration) - */ - public void acceptFriendDeclaration(IASTDeclaration declaration) { - // TODO Auto-generated method stub - - } - -} 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..d2ab7c0048a --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java @@ -0,0 +1,730 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation 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: + * IBM Corp. - Rational Software - initial implementation + * QNX Software Systems - adapted for type search + *******************************************************************************/ +package org.eclipse.cdt.internal.core.browser.cache; + +import java.io.CharArrayReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +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.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.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.ParserUtil; +import org.eclipse.cdt.core.parser.ScannerInfo; +import org.eclipse.cdt.core.parser.ast.ASTClassKind; +import org.eclipse.cdt.core.parser.ast.IASTTypedefDeclaration; +import org.eclipse.cdt.core.parser.ast.IASTASMDefinition; +import org.eclipse.cdt.core.parser.ast.IASTAbstractTypeSpecifierDeclaration; +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.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.PathUtil; +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; + private ISourceElementCallbackDelegate fLastDeclaration; + private SimpleStack fScopeStack = new SimpleStack(); + private SimpleStack fResourceStack = new SimpleStack(); + private ITypeInfo fTypeToFind; + private boolean fFoundType; + + public TypeParser(ITypeCache typeCache, IWorkingCopyProvider provider) { + fTypeCache = typeCache; + fWorkingCopyProvider = provider; + } + + 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(); + 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? + } + + boolean foundType = false; + 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; + } + + 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++ + } + + Reader reader = null; + Object stackObject = null; + + if (workingCopy != null) { + reader = createWorkingCopyReader(workingCopy); + IResource resource = workingCopy.getResource(); + if (resource != null) { + path = resource.getLocation(); + } + stackObject = workingCopy; + } else { + IResource resource = null; + 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.push(stackObject); + parseContents(path, 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 Reader createWorkingCopyReader(IWorkingCopy workingCopy) { + Reader reader = null; + IResource resource = workingCopy.getResource(); + if (resource != null && resource.isAccessible()) { + char[] contents = workingCopy.getContents(); + if (contents != null) + reader = new CharArrayReader(contents); + } + return reader; + } + + private Reader createResourceReader(IResource resource) { + Reader reader = null; + if (resource.isAccessible() && resource instanceof IFile) { + IFile file = (IFile) resource; + try { + InputStream contents = file.getContents(); + if (contents != null) + reader = new InputStreamReader(contents); + } catch (CoreException ex) { + ex.printStackTrace(); + } + } + return reader; + } + + private Reader createFileReader(IPath path) { + Reader reader = null; + File file = path.toFile(); + if (file != null) { + try { + reader = new FileReader(file); + } catch (FileNotFoundException ex) { + ex.printStackTrace(); + } + } + return reader; + } + + private void parseContents(IPath realPath, IProject project, Reader 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(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, realPath.toOSString(), scanInfo, + ParserMode.STRUCTURAL_PARSE, language, this, ParserUtil.getScannerLogService(), null); + IParser parser = ParserFactory.createParser(scanner, this, ParserMode.STRUCTURAL_PARSE, language, ParserUtil.getParserLogService()); + parser.parse(); + } catch (ParserFactoryError e) { + e.printStackTrace(); + } catch (ParseError e) { + e.printStackTrace(); + } catch (OperationCanceledException e) { + throw new InterruptedException(); + } catch (Exception e) { + e.printStackTrace(); + } catch (VirtualMachineError e) { + e.printStackTrace(); + } finally { + fProgressMonitor = 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 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; + } + + int offset = 0; + int end = 0; + IASTOffsetableNamedElement offsetable = null; + String name = null; + int type = 0; + + 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; + } + + // skip unnamed structs + if (name == null || name.length() == 0) + return; + + // skip unused types + type = getElementType(offsetable); + if (type == 0) { + return; + } + + // collect enclosing names + String[] enclosingNames = null; + 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); + } + } + + // add types to cache + addType(type, name, enclosingNames, fResourceStack.bottom(), fResourceStack.top(), offset, end - offset); + fProgressMonitor.worked(1); + } + + private 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 addType(int type, String name, String[] enclosingNames, Object originalRef, Object resolvedRef, int offset, int length) { + QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames); + ITypeInfo info = fTypeCache.getType(type, qualifiedName); + if (info == null || info.isUndefinedType()) { + if (info == null) { + info = new TypeInfo(type, qualifiedName, fTypeCache); + fTypeCache.insert(info); + } else { + info.setCElementType(type); + } + + TypeReference location; + if (originalRef instanceof IWorkingCopy) { + IWorkingCopy workingCopy = (IWorkingCopy) originalRef; + location = new TypeReference(workingCopy, fProject); + } else if (originalRef instanceof IResource) { + IResource resource = (IResource) originalRef; + location = new TypeReference(resource, fProject); + } else { + IPath path = (IPath) originalRef; + location = new TypeReference(path, fProject); + } + info.addReference(location); + } + + TypeReference location; + if (resolvedRef instanceof IWorkingCopy) { + IWorkingCopy workingCopy = (IWorkingCopy) resolvedRef; + location = new TypeReference(workingCopy, fProject, offset, length); + } else if (resolvedRef instanceof IResource) { + IResource resource = (IResource) resolvedRef; + location = new TypeReference(resource, fProject, offset, length); + } else { + IPath path = (IPath) resolvedRef; + location = new TypeReference(path, fProject, offset, length); + } + info.addReference(location); + + if (fTypeToFind != null && fTypeToFind.equals(info)) { + fFoundType = true; + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.parser.ISourceElementRequestor#createReader(java.lang.String) + */ + public Reader createReader(String finalPath, Iterator workingCopies) { + return ParserUtil.createReader(finalPath, workingCopies); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.parser.ISourceElementRequestor#parserTimeout() + */ + public boolean parserTimeout() { + if (fFoundType || fProgressMonitor.isCanceled()) + return true; + + return false; + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPathCollector.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPathCollector.java deleted file mode 100644 index 352140e53ef..00000000000 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPathCollector.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * 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.internal.core.browser.cache; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.eclipse.cdt.internal.core.search.IIndexSearchRequestor; -import org.eclipse.core.runtime.Path; - -/** - * Collects type and dependency paths from search results. - */ -public class TypeSearchPathCollector implements IIndexSearchRequestor { - - public Set typePaths= new HashSet(5); - public Set dependencyPaths= new HashSet(5); - - public void acceptClassDeclaration(String resourcePath, char[] simpleTypeName, char[][] enclosingTypeNames) { - typePaths.add(resourcePath); - } - - public void acceptNamespaceDeclaration(String resourcePath, char[] typeName, char[][] enclosingTypeNames) { - typePaths.add(resourcePath); - } - - public void acceptIncludeDeclaration(String resourcePath, char[] decodedSimpleName) { - dependencyPaths.add(resourcePath); - } - - public void acceptConstructorDeclaration(String resourcePath, char[] typeName, int parameterCount) { } - public void acceptConstructorReference(String resourcePath, char[] typeName, int parameterCount) { } - public void acceptFieldDeclaration(String resourcePath, char[] fieldName) { } - public void acceptFieldReference(String resourcePath, char[] fieldName) { } - public void acceptInterfaceDeclaration(String resourcePath, char[] simpleTypeName, char[][] enclosingTypeNames, char[] packageName) { } - public void acceptFunctionDeclaration(String resourcePath, char[] methodName, int parameterCount) { } - public void acceptMethodDeclaration(String resourcePath, char[] methodName, int parameterCount, char[][] enclosingTypeNames) { } - public void acceptMethodReference(String resourcePath, char[] methodName, int parameterCount) { } - public void acceptPackageReference(String resourcePath, char[] packageName) { } - public void acceptVariableDeclaration(String resourcePath, char[] simpleTypeName) { } - public void acceptFieldDeclaration(String resourcePath, char[] simpleTypeName, char[][] enclosingTypeNames) { } - public void acceptMacroDeclaration(String resourcePath, char[] decodedSimpleName) { } - public void acceptSuperTypeReference(String resourcePath, char[] qualification, char[] typeName, char[] enclosingTypeName, char classOrInterface, char[] superQualification, char[] superTypeName, char superClassOrInterface, int modifiers) { } - public void acceptSuperTypeReference(String resourcePath, char[] qualification, char[] typeName, char classOrInterface, char[] superQualification, char[] superTypeName, char superClassOrInterface, int modifiers) { } - public void acceptTypeReference(String resourcePath, char[] typeName) { } - - /** - * Returns the paths that have been collected. - */ - public Set getPaths() { - Set pathSet= new HashSet(typePaths.size()); - for (Iterator i= typePaths.iterator(); i.hasNext(); ) { - String path= (String) i.next(); - pathSet.add(new Path(path)); - } - return pathSet; - } - - /** - * Returns the dependency paths that have been collected. - */ - public Set getDependencyPaths() { - Set pathSet= new HashSet(dependencyPaths.size()); - for (Iterator i= dependencyPaths.iterator(); i.hasNext(); ) { - String path= (String) i.next(); - pathSet.add(new Path(path)); - } - return pathSet; - } -} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPattern.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPattern.java deleted file mode 100644 index 47def56dd5f..00000000000 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPattern.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * 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.internal.core.browser.cache; - -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.search.ICSearchConstants; -import org.eclipse.cdt.core.search.OrPattern; -import org.eclipse.cdt.core.search.SearchEngine; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IPath; - - -public final class TypeSearchPattern extends OrPattern { - public TypeSearchPattern() { - super(); - addPattern(SearchEngine.createSearchPattern("*", ICSearchConstants.NAMESPACE, ICSearchConstants.DECLARATIONS, false)); //$NON-NLS-1$ - addPattern(SearchEngine.createSearchPattern("*", ICSearchConstants.CLASS, ICSearchConstants.DECLARATIONS, false)); //$NON-NLS-1$ - addPattern(SearchEngine.createSearchPattern("*", ICSearchConstants.STRUCT, ICSearchConstants.DECLARATIONS, false)); //$NON-NLS-1$ - addPattern(SearchEngine.createSearchPattern("*", ICSearchConstants.UNION, ICSearchConstants.DECLARATIONS, false)); //$NON-NLS-1$ - addPattern(SearchEngine.createSearchPattern("*", ICSearchConstants.ENUM, ICSearchConstants.DECLARATIONS, false)); //$NON-NLS-1$ - addPattern(SearchEngine.createSearchPattern("*", ICSearchConstants.TYPEDEF, ICSearchConstants.DECLARATIONS, false)); //$NON-NLS-1$ - } - - public void addDependencySearch(IPath path) { - // convert path to absolute or the search will fail - IResource res= CCorePlugin.getWorkspace().getRoot().findMember(path); - if (res != null) - path= res.getRawLocation(); - if (path != null) - addPattern(createPattern(path.toOSString(), ICSearchConstants.INCLUDE, ICSearchConstants.REFERENCES, ICSearchConstants.EXACT_MATCH, true)); - } -} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/PathUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/PathUtil.java index b638a54fbf1..e86f4ba3abf 100644 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/PathUtil.java +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/PathUtil.java @@ -13,22 +13,37 @@ package org.eclipse.cdt.internal.core.browser.util; import java.io.File; import java.io.IOException; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; public class PathUtil { - private static boolean fWindows = false; - static { - String os = System.getProperty("os.name"); //$NON-NLS-1$ - if (os != null && os.startsWith("Win")) { //$NON-NLS-1$ - fWindows= true; - } - } + private static boolean fGotOS = false; + private static boolean fIsWindows = false; + public static boolean isWindowsSystem() { - return fWindows; + if (!fGotOS) { + String os = System.getProperty("os.name"); //$NON-NLS-1$ + if (os != null && os.startsWith("Win")) { //$NON-NLS-1$ + fIsWindows= true; + } + fGotOS = true; + } + return fIsWindows; } - public static Path getCanonicalPath(String fullPath) { + public static IWorkspaceRoot getWorkspaceRoot() { + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + if (workspace != null) { + return workspace.getRoot(); + } + return null; + } + + public static IPath getCanonicalPath(String fullPath) { File file = new File(fullPath); try { String canonPath = file.getCanonicalPath(); @@ -37,4 +52,36 @@ public class PathUtil { } return new Path(fullPath); } + + public static IPath getCanonicalPath(IPath fullPath) { + return getCanonicalPath(fullPath.toString()); + } + + public static IPath getWorkspaceRelativePath(IPath fullPath) { + IWorkspaceRoot workspaceRoot = getWorkspaceRoot(); + if (workspaceRoot != null) { + IPath workspaceLocation = workspaceRoot.getLocation(); + if (workspaceLocation != null && workspaceLocation.isPrefixOf(fullPath)) { + int segments = fullPath.matchingFirstSegments(workspaceLocation); + IPath relPath = fullPath.setDevice(null).removeFirstSegments(segments); + return new Path("").addTrailingSeparator().append(relPath); //$NON-NLS-1$ + } + } + return fullPath; + } + + public static IPath getWorkspaceRelativePath(String fullPath) { + return getWorkspaceRelativePath(new Path(fullPath)); + } + + public static IPath getRawLocation(IPath wsRelativePath) { + IWorkspaceRoot workspaceRoot = getWorkspaceRoot(); + if (workspaceRoot != null && wsRelativePath != null) { + IPath workspaceLocation = workspaceRoot.getLocation(); + if (workspaceLocation != null && !workspaceLocation.isPrefixOf(wsRelativePath)) { + return workspaceLocation.append(wsRelativePath); + } + } + return wsRelativePath; + } } diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java index 6e06dbc5e3c..0c32f5bc85e 100644 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java @@ -56,6 +56,12 @@ public class SimpleStack { return items.get(top); } + public Object bottom() { + if (items.size() == 0) + return null; + return items.get(0); + } + public boolean isEmpty() { return (items.size() == 0); } diff --git a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeAction.java b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeAction.java index 26b6a532396..2e41338018c 100644 --- a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeAction.java +++ b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeAction.java @@ -11,23 +11,19 @@ package org.eclipse.cdt.internal.ui.browser.opentype; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Collection; - import org.eclipse.cdt.core.browser.AllTypesCache; 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.TypeSearchScope; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.resources.FileStorage; -import org.eclipse.cdt.core.search.ICSearchScope; -import org.eclipse.cdt.core.search.SearchEngine; import org.eclipse.cdt.internal.ui.editor.CEditor; import org.eclipse.cdt.internal.ui.util.EditorUtility; import org.eclipse.cdt.internal.ui.util.ExceptionHandler; import org.eclipse.cdt.ui.CUIPlugin; -import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IStorage; -import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.IAction; @@ -44,45 +40,35 @@ import org.eclipse.ui.IWorkbenchWindowActionDelegate; import org.eclipse.ui.PartInitException; import org.eclipse.ui.texteditor.ITextEditor; -/** - * To change the template for this generated type comment go to - * Window>Preferences>Java>Code Generation>Code and Comments - */ public class OpenTypeAction implements IWorkbenchWindowActionDelegate { public OpenTypeAction() { super(); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) */ - public void run(IAction action) { - - final ICSearchScope scope= SearchEngine.createWorkspaceScope(); - final int[] kinds= { ICElement.C_NAMESPACE, ICElement.C_CLASS, ICElement.C_STRUCT, - ICElement.C_UNION, ICElement.C_ENUMERATION, ICElement.C_TYPEDEF }; - final Collection typeList= new ArrayList(); - - if (AllTypesCache.isCacheUpToDate()) { - // run without progress monitor - AllTypesCache.getTypes(scope, kinds, null, typeList); - } else { - IRunnableWithProgress runnable= new IRunnableWithProgress() { + public void run(IAction action) { + final ITypeSearchScope fScope = new TypeSearchScope(true); + if (!AllTypesCache.isCacheUpToDate(fScope)) { + IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - AllTypesCache.getTypes(scope, kinds, monitor, typeList); + AllTypesCache.updateCache(fScope, monitor); if (monitor.isCanceled()) { throw new InterruptedException(); } } }; - - IRunnableContext runnableContext= new ProgressMonitorDialog(getShell()); + + IRunnableContext runnableContext = new ProgressMonitorDialog(getShell()); try { runnableContext.run(true, true, runnable); } catch (InvocationTargetException e) { - String title= OpenTypeMessages.getString("OpenTypeAction.exception.title"); //$NON-NLS-1$ - String message= OpenTypeMessages.getString("OpenTypeAction.exception.message"); //$NON-NLS-1$ + String title = OpenTypeMessages.getString("OpenTypeAction.exception.title"); //$NON-NLS-1$ + String message = OpenTypeMessages.getString("OpenTypeAction.exception.message"); //$NON-NLS-1$ ExceptionHandler.handle(e, title, message); return; } catch (InterruptedException e) { @@ -90,38 +76,62 @@ public class OpenTypeAction implements IWorkbenchWindowActionDelegate { return; } } - - if (typeList.isEmpty()) { - String title= OpenTypeMessages.getString("OpenTypeAction.notypes.title"); //$NON-NLS-1$ - String message= OpenTypeMessages.getString("OpenTypeAction.notypes.message"); //$NON-NLS-1$ + + ITypeInfo[] elements = AllTypesCache.getAllTypes(); + if (elements.length == 0) { + String title = OpenTypeMessages.getString("OpenTypeAction.notypes.title"); //$NON-NLS-1$ + String message = OpenTypeMessages.getString("OpenTypeAction.notypes.message"); //$NON-NLS-1$ MessageDialog.openInformation(getShell(), title, message); return; } - - ITypeInfo[] elements= (ITypeInfo[])typeList.toArray(new ITypeInfo[typeList.size()]); - - OpenTypeDialog dialog= new OpenTypeDialog(getShell()); + + OpenTypeDialog dialog = new OpenTypeDialog(getShell()); dialog.setElements(elements); - - int result= dialog.open(); + int result = dialog.open(); if (result != IDialogConstants.OK_ID) return; - ITypeInfo info= (ITypeInfo)dialog.getFirstResult(); + ITypeInfo info = (ITypeInfo) dialog.getFirstResult(); if (info == null) return; + + ITypeReference location = info.getResolvedReference(); + if (location == null) { + final ITypeInfo[] typesToResolve = new ITypeInfo[] { info }; + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + AllTypesCache.resolveTypeLocation(typesToResolve[0], monitor); + if (monitor.isCanceled()) { + throw new InterruptedException(); + } + } + }; + + IRunnableContext runnableContext = new ProgressMonitorDialog(getShell()); + try { + runnableContext.run(true, true, runnable); + } catch (InvocationTargetException e) { + String title = OpenTypeMessages.getString("OpenTypeAction.exception.title"); //$NON-NLS-1$ + String message = OpenTypeMessages.getString("OpenTypeAction.exception.message"); //$NON-NLS-1$ + ExceptionHandler.handle(e, title, message); + return; + } catch (InterruptedException e) { + // cancelled by user + return; + } - if (!openTypeInEditor(info)) - { - // could not find definition - String pathString= null; - IPath path= info.getLocation(); - if (path != null) - pathString= path.toString(); - else - pathString= OpenTypeMessages.getString("OpenTypeAction.errorNoPath"); //$NON-NLS-1$ - String title= OpenTypeMessages.getString("OpenTypeAction.errorTitle"); //$NON-NLS-1$ - String message= OpenTypeMessages.getFormattedString("OpenTypeAction.errorMessage", pathString); //$NON-NLS-1$ + location = info.getResolvedReference(); + } + + if (location == null) { + // could not resolve location + String title = OpenTypeMessages.getString("OpenTypeAction.errorTitle"); //$NON-NLS-1$ + String message = OpenTypeMessages.getFormattedString("OpenTypeAction.errorTypeNotFound", info.getQualifiedTypeName().toString()); //$NON-NLS-1$ + MessageDialog.openError(getShell(), title, message); + } else if (!openTypeInEditor(location)) { + // error opening editor + String title = OpenTypeMessages.getString("OpenTypeAction.errorTitle"); //$NON-NLS-1$ + String message = OpenTypeMessages.getFormattedString("OpenTypeAction.errorOpenEditor", location.getPath().toString()); //$NON-NLS-1$ MessageDialog.openError(getShell(), title, message); } } @@ -129,77 +139,73 @@ public class OpenTypeAction implements IWorkbenchWindowActionDelegate { protected Shell getShell() { return CUIPlugin.getActiveWorkbenchShell(); } - + /** * Opens an editor and displays the selected type. + * * @param info Type to display. * @return true if succesfully displayed. */ - private boolean openTypeInEditor(ITypeInfo info) { - IResource res= null; - IEditorPart editorPart= null; - IPath path= info.getPath(); - ICElement celement= info.getCElement(); - - // attempt to locate the resource - if (celement != null) - res= celement.getUnderlyingResource(); - if (res == null) - res= info.getResource(); - if (res == null && path != null) { - IWorkspaceRoot wsRoot= CUIPlugin.getWorkspace().getRoot(); - res= wsRoot.getFileForLocation(path); - } - + private boolean openTypeInEditor(ITypeReference location) { + ICElement cElement = location.getCElement(); + IEditorPart editorPart = null; + try { - // open resource in editor - if (res != null) - editorPart= EditorUtility.openInEditor(res); + if (cElement != null) + editorPart = EditorUtility.openInEditor(cElement); if (editorPart == null) { // open as external file - IStorage storage = new FileStorage(path); - editorPart= EditorUtility.openInEditor(storage); + IPath path = location.getLocation(); + if (path != null) { + IStorage storage = new FileStorage(path); + editorPart = EditorUtility.openInEditor(storage); + } } if (editorPart == null) return false; - } catch (CModelException ex){ + } catch (CModelException ex) { ex.printStackTrace(); return false; - } - catch(PartInitException ex) { + } catch (PartInitException ex) { ex.printStackTrace(); return false; } - - // highlight the type in the editor - if (celement != null && editorPart instanceof CEditor) { - CEditor editor= (CEditor)editorPart; - editor.setSelection(celement); - return true; - } else if (editorPart instanceof ITextEditor) { - ITextEditor editor= (ITextEditor)editorPart; - editor.selectAndReveal(info.getStartOffset(), info.getName().length()); - return true; - } + // highlight the type in the editor + if (cElement != null && editorPart instanceof CEditor) { + CEditor editor = (CEditor) editorPart; + editor.setSelection(cElement); + return true; + } else if (editorPart instanceof ITextEditor) { + ITextEditor editor = (ITextEditor) editorPart; + editor.selectAndReveal(location.getOffset(), location.getLength()); + return true; + } return false; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose() */ public void dispose() { } - - /* (non-Javadoc) + + /* + * (non-Javadoc) + * * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow) */ public void init(IWorkbenchWindow window) { } - - /* (non-Javadoc) - * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection) + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, + * org.eclipse.jface.viewers.ISelection) */ public void selectionChanged(IAction action, ISelection selection) { } -} +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeMessages.properties b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeMessages.properties index c7cfee12801..30b90303c70 100644 --- a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeMessages.properties +++ b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/internal/ui/browser/opentype/OpenTypeMessages.properties @@ -13,13 +13,12 @@ OpenTypeAction.exception.title=Exception OpenTypeAction.exception.message=Unexpected exception. See log for details. OpenTypeAction.notypes.title=Type Selection OpenTypeAction.notypes.message=No types available. - OpenTypeAction.description=Open a type in the editor OpenTypeAction.tooltip=Open a Type OpenTypeAction.label=Open Type... OpenTypeAction.errorTitle=Open Type -OpenTypeAction.errorMessage=Could not uniquely map the type name to a type. Path is {0} -OpenTypeAction.errorNoPath=Unknown +OpenTypeAction.errorOpenEditor=Error opening editor for file \"{0}\" +OpenTypeAction.errorTypeNotFound=Could not locate definition of type \"{0}\" OpenTypeDialog.title=Open Type OpenTypeDialog.message=&Choose a type (? = any character, * = any string): diff --git a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoLabelProvider.java b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoLabelProvider.java index 9b92b519cc9..a6516e1a352 100644 --- a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoLabelProvider.java +++ b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoLabelProvider.java @@ -8,25 +8,25 @@ * Contributors: * IBM Corporation - initial API and implementation * QNX Software Systems - adapted for use in CDT - *******************************************************************************/ + ***************************************************************f****************/ package org.eclipse.cdt.ui.browser.typeinfo; +import org.eclipse.cdt.core.browser.IQualifiedTypeName; import org.eclipse.cdt.core.browser.ITypeInfo; +import org.eclipse.cdt.core.browser.ITypeReference; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.internal.ui.CPluginImages; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.swt.graphics.Image; public class TypeInfoLabelProvider extends LabelProvider { - public static final int SHOW_FULLYQUALIFIED= 0x01; - public static final int SHOW_FILENAME_POSTFIX= 0x02; - public static final int SHOW_FILENAME_ONLY= 0x04; - public static final int SHOW_ROOT_POSTFIX= 0x08; - public static final int SHOW_TYPE_ONLY= 0x10; - public static final int SHOW_TYPE_CONTAINER_ONLY= 0x20; + public static final int SHOW_TYPE_ONLY= 0x01; + public static final int SHOW_ENCLOSING_TYPE_ONLY= 0x02; + public static final int SHOW_PATH= 0x04; private static final Image HEADER_ICON= CPluginImages.get(CPluginImages.IMG_OBJS_TUNIT_HEADER); private static final Image SOURCE_ICON= CPluginImages.get(CPluginImages.IMG_OBJS_TUNIT); @@ -37,6 +37,7 @@ public class TypeInfoLabelProvider extends LabelProvider { private static final Image TYPEDEF_ICON= CPluginImages.get(CPluginImages.IMG_OBJS_TYPEDEF); private static final Image UNION_ICON= CPluginImages.get(CPluginImages.IMG_OBJS_UNION); private static final Image ENUM_ICON= CPluginImages.get(CPluginImages.IMG_OBJS_ENUMERATION); + private static final Image UNKNOWN_TYPE_ICON= CPluginImages.get(CPluginImages.IMG_OBJS_UNKNOWN_TYPE); private int fFlags; @@ -56,43 +57,33 @@ public class TypeInfoLabelProvider extends LabelProvider { return super.getText(element); ITypeInfo typeRef= (ITypeInfo) element; + IQualifiedTypeName qualifiedName = typeRef.getQualifiedTypeName(); StringBuffer buf= new StringBuffer(); if (isSet(SHOW_TYPE_ONLY)) { String name= typeRef.getName(); if (name != null && name.length() > 0) buf.append(name); - } else if (isSet(SHOW_TYPE_CONTAINER_ONLY)) { - String name= typeRef.getQualifiedParentName(); - if (name != null && name.length() > 0) - buf.append(name); - } else if (isSet(SHOW_FILENAME_ONLY)) { - String name= typeRef.getFileName(); - if (name != null && name.length() > 0) - buf.append(name); - } else { - if (isSet(SHOW_FULLYQUALIFIED)) { - String name= typeRef.getFullyQualifiedName(); - if (name != null && name.length() > 0) - buf.append(name); - } - else { - String name= typeRef.getParentName(); - if (name != null && name.length() > 0) - buf.append(name); - } - - if (isSet(SHOW_FILENAME_POSTFIX)) { - String name= typeRef.getFileName(); - if (name != null && name.length() > 0) { - buf.append(TypeInfoMessages.getString("TypeInfoLabelProvider.dash")); //$NON-NLS-1$ - buf.append(name); - } + } else if (isSet(SHOW_ENCLOSING_TYPE_ONLY)) { + IQualifiedTypeName parentName= qualifiedName.getEnclosingTypeName(); + if (parentName != null) { + buf.append(parentName.getFullyQualifiedName()); + } else { + buf.append(TypeInfoMessages.getString("TypeInfoLabelProvider.globalScope")); //$NON-NLS-1$ } } - - if (isSet(SHOW_ROOT_POSTFIX)) { - IPath path= typeRef.getPath(); + + if (isSet(SHOW_PATH)) { + IPath path = null; + ITypeReference ref = typeRef.getResolvedReference(); + if (ref != null) { + path = ref.getPath(); + } else { + IProject project = typeRef.getEnclosingProject(); + if (project != null) { + path = project.getFullPath(); + } + } if (path != null) { buf.append(TypeInfoMessages.getString("TypeInfoLabelProvider.dash"));//$NON-NLS-1$ buf.append(path.toString()); @@ -109,31 +100,26 @@ public class TypeInfoLabelProvider extends LabelProvider { return super.getImage(element); ITypeInfo typeRef= (ITypeInfo) element; - if (isSet(SHOW_TYPE_CONTAINER_ONLY)) { - return getContainerIcon(typeRef); - } else if (isSet(SHOW_FILENAME_ONLY)) { - return getFileIcon(typeRef.getPath()); - } else { - return getTypeIcon(typeRef.getType()); - } - } - - public static Image getContainerIcon(ITypeInfo typeRef) - { - //TODO get enclosing types and parent type icon - return getFileIcon(typeRef.getPath()); - } - - public static Image getFileIcon(IPath path) - { - if (path != null) { - if (CoreModel.isValidHeaderUnitName(path.lastSegment())) { - return HEADER_ICON; + if (isSet(SHOW_ENCLOSING_TYPE_ONLY)) { + ITypeInfo parentInfo = typeRef.getEnclosingType(); + if (parentInfo != null) { + return getTypeIcon(parentInfo.getCElementType()); + } else { + IPath path = null; + ITypeReference ref = typeRef.getResolvedReference(); + if (ref != null) { + path = ref.getPath(); + if (CoreModel.isValidHeaderUnitName(path.lastSegment())) { + return HEADER_ICON; + } + } + return SOURCE_ICON; } } - return SOURCE_ICON; + + return getTypeIcon(typeRef.getCElementType()); } - + public static Image getTypeIcon(int type) { switch (type) @@ -160,7 +146,7 @@ public class TypeInfoLabelProvider extends LabelProvider { return TYPEDEF_ICON; default: - return CLASS_ICON; + return UNKNOWN_TYPE_ICON; } } } diff --git a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoMessages.properties b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoMessages.properties index 0fa80b8eed7..16ba904ee46 100644 --- a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoMessages.properties +++ b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeInfoMessages.properties @@ -21,4 +21,5 @@ TypeSelectionDialog.filterUnions=union TypeSelectionDialog.filterLowLevelTypes=Show low-level types TypeInfoLabelProvider.default_filename=default +TypeInfoLabelProvider.globalScope=(global) TypeInfoLabelProvider.dash=\ - diff --git a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeSelectionDialog.java b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeSelectionDialog.java index 472cadcfd33..0d3ba571735 100644 --- a/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeSelectionDialog.java +++ b/core/org.eclipse.cdt.ui/browser/org/eclipse/cdt/ui/browser/typeinfo/TypeSelectionDialog.java @@ -18,7 +18,10 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import org.eclipse.cdt.core.browser.*; +import org.eclipse.cdt.core.browser.IQualifiedTypeName; +import org.eclipse.cdt.core.browser.ITypeInfo; +import org.eclipse.cdt.core.browser.QualifiedTypeName; +import org.eclipse.cdt.core.browser.TypeInfo; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.internal.ui.util.StringMatcher; import org.eclipse.cdt.ui.CUIPlugin; @@ -49,11 +52,10 @@ public class TypeSelectionDialog extends TwoPaneElementSelector { private static final char END_SYMBOL = '<'; private static final char ANY_STRING = '*'; - private final static String scopeResolutionOperator = "::"; //$NON-NLS-1$ - - private StringMatcher fMatcher; - private StringMatcher fQualifierMatcher; - private StringMatcher fScopedQualifierMatcher; + + private StringMatcher fNameMatcher = null; + private StringMatcher[] fSegmentMatchers = null; + private boolean fMatchRootQualifier = false; private Collection fVisibleTypes = new HashSet(); private boolean fShowLowLevelTypes = false; @@ -61,26 +63,42 @@ public class TypeSelectionDialog extends TwoPaneElementSelector { * @see FilteredList.FilterMatcher#setFilter(String, boolean) */ public void setFilter(String pattern, boolean ignoreCase, boolean ignoreWildCards) { - int qualifierIndex = pattern.lastIndexOf(scopeResolutionOperator); + // parse pattern into segments + QualifiedTypeName qualifiedName = new QualifiedTypeName(pattern); + String[] segments = qualifiedName.segments(); + int length = segments.length; - // type - if (qualifierIndex == -1) { - fQualifierMatcher = null; - fScopedQualifierMatcher = null; - fMatcher = new StringMatcher(adjustPattern(pattern), ignoreCase, ignoreWildCards); - // qualified type - } else { - String prefixPattern = pattern.substring(0, qualifierIndex + scopeResolutionOperator.length()); - fQualifierMatcher = new StringMatcher(adjustPattern(prefixPattern), ignoreCase, ignoreWildCards); - StringBuffer buf = new StringBuffer(); - buf.append(ANY_STRING); - buf.append(scopeResolutionOperator); - buf.append(prefixPattern); - String scopedPattern = buf.toString(); - fScopedQualifierMatcher = new StringMatcher(adjustPattern(scopedPattern), ignoreCase, ignoreWildCards); - String namePattern = pattern.substring(qualifierIndex + scopeResolutionOperator.length()); - fMatcher = new StringMatcher(adjustPattern(namePattern), ignoreCase, ignoreWildCards); + // append wildcard to innermost segment + segments[length-1] = adjustPattern(segments[length-1]); + + fMatchRootQualifier = false; + fSegmentMatchers = new StringMatcher[length]; + int count = 0; + for (int i = 0; i < length; ++i) { + if (segments[i].length() > 0) { + // create StringMatcher for this segment + fSegmentMatchers[count++] = new StringMatcher(segments[i], ignoreCase, ignoreWildCards); + } else if (i == 0) { + // allow outermost segment to be blank (e.g. "::foo*") + fMatchRootQualifier = true; + } else { + // skip over blank segments (e.g. treat "foo::::b*" as "foo::b*") + } } + if (count != length) { + if (count > 0) { + // resize array + StringMatcher[] newMatchers = new StringMatcher[count]; + System.arraycopy(fSegmentMatchers, 0, newMatchers, 0, count); + fSegmentMatchers = newMatchers; + } else { + // fallback to wildcard (should never get here) + fSegmentMatchers = new StringMatcher[1]; + fSegmentMatchers[0] = new StringMatcher(String.valueOf(ANY_STRING), ignoreCase, ignoreWildCards); + } + } + // match simple name with innermost segment + fNameMatcher = fSegmentMatchers[fSegmentMatchers.length-1]; } public void setVisibleTypes(Collection visibleTypes) { @@ -100,18 +118,6 @@ public class TypeSelectionDialog extends TwoPaneElementSelector { return fShowLowLevelTypes; } - private boolean isLowLevelType(ITypeInfo info) { - String[] enclosingNames = info.getEnclosingNames(); - // filter out low-level system types eg __FILE - if (enclosingNames != null) { - for (int i = 0; i < enclosingNames.length; ++i) { - if (enclosingNames[i].startsWith("_")) //$NON-NLS-1$ - return true; - } - } - return info.getName().startsWith("_"); //$NON-NLS-1$ - } - /* * @see FilteredList.FilterMatcher#match(Object) */ @@ -120,39 +126,80 @@ public class TypeSelectionDialog extends TwoPaneElementSelector { return false; TypeInfo info = (TypeInfo) element; + IQualifiedTypeName qualifiedName = info.getQualifiedTypeName(); - if (fVisibleTypes != null && !fVisibleTypes.contains(new Integer(info.getType()))) + if (fVisibleTypes != null && !fVisibleTypes.contains(new Integer(info.getCElementType()))) return false; - if (!fShowLowLevelTypes && isLowLevelType(info)) + if (!fShowLowLevelTypes && qualifiedName.isLowLevel()) return false; - if (!fMatcher.match(info.getName())) + if (!fMatchRootQualifier && !fNameMatcher.match(qualifiedName.getName())) return false; - if (fQualifierMatcher == null) - return true; - - if (fQualifierMatcher.match(info.getQualifiedName())) - return true; - else - return fScopedQualifierMatcher.match(info.getQualifiedName()); + return matchQualifiedName(qualifiedName); } - - private String adjustPattern(String pattern) { + + private boolean matchQualifiedName(IQualifiedTypeName qualifiedName) { + String[] segments = qualifiedName.segments(); + boolean matchFound = false; + boolean moreNames = true; + int matchOffset = 0; + while (!matchFound && moreNames) { + matchFound = true; + for (int i = 0; i < fSegmentMatchers.length; ++i) { + int dropOut = 0; + if (i < (segments.length - matchOffset)) { + // ok to continue +// dropOut = false; + } else { + ++dropOut; + } + + if (matchOffset + i >= segments.length) { + ++dropOut; + } + + if (dropOut > 0) { + if (dropOut != 2) { + // shouldn't get here + matchFound = false; + moreNames = false; + } + matchFound = false; + moreNames = false; + break; + } + + StringMatcher matcher = fSegmentMatchers[i]; + String name = segments[matchOffset + i]; + if (name == null || !matcher.match(name)) { + matchFound = false; + break; + } + } + + if (fMatchRootQualifier) { + // must match outermost name (eg ::foo) + moreNames = false; + } else { + ++matchOffset; + } + } + return matchFound; + } + + private static String adjustPattern(String pattern) { int length = pattern.length(); if (length > 0) { switch (pattern.charAt(length - 1)) { case END_SYMBOL: - pattern = pattern.substring(0, length - 1); - break; + return pattern.substring(0, length - 1); case ANY_STRING: - break; - default: - pattern = pattern + ANY_STRING; + return pattern; } } - return pattern; + return pattern + ANY_STRING; } } @@ -183,7 +230,7 @@ public class TypeSelectionDialog extends TwoPaneElementSelector { private static final String SETTINGS_SHOW_LOWLEVEL = "show_lowlevel"; //$NON-NLS-1$ private static final TypeInfoLabelProvider fElementRenderer = new TypeInfoLabelProvider(TypeInfoLabelProvider.SHOW_TYPE_ONLY); - private static final TypeInfoLabelProvider fQualifierRenderer = new TypeInfoLabelProvider(TypeInfoLabelProvider.SHOW_TYPE_CONTAINER_ONLY + TypeInfoLabelProvider.SHOW_ROOT_POSTFIX); + private static final TypeInfoLabelProvider fQualifierRenderer = new TypeInfoLabelProvider(TypeInfoLabelProvider.SHOW_ENCLOSING_TYPE_ONLY + TypeInfoLabelProvider.SHOW_PATH); private static final TypeFilterMatcher fFilterMatcher = new TypeFilterMatcher(); private static final StringComparator fStringComparator = new StringComparator(); @@ -319,7 +366,7 @@ public class TypeSelectionDialog extends TwoPaneElementSelector { break; default: return; - }; + } Image icon = TypeInfoLabelProvider.getTypeIcon(type); Composite composite = new Composite(parent, SWT.NONE); diff --git a/core/org.eclipse.cdt.ui/icons/full/obj16/unknown_type_obj.gif b/core/org.eclipse.cdt.ui/icons/full/obj16/unknown_type_obj.gif new file mode 100644 index 00000000000..1be1a678a54 Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/full/obj16/unknown_type_obj.gif differ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java index b5a0002a843..7f447cd0e04 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java @@ -52,6 +52,7 @@ public class CPluginImages { public static final String IMG_OBJS_UNION= NAME_PREFIX + "union_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_TYPEDEF= NAME_PREFIX + "typedef_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_ENUMERATION= NAME_PREFIX + "enum_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJS_UNKNOWN_TYPE= NAME_PREFIX + "unknown_type_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_ENUMERATOR= NAME_PREFIX + "enumerator_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_FUNCTION= NAME_PREFIX + "function_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_PUBLIC_METHOD= NAME_PREFIX + "method_public_obj.gif"; //$NON-NLS-1$ @@ -114,6 +115,7 @@ public class CPluginImages { public static final ImageDescriptor DESC_OBJS_UNION= createManaged(T_OBJ, IMG_OBJS_UNION); public static final ImageDescriptor DESC_OBJS_TYPEDEF= createManaged(T_OBJ, IMG_OBJS_TYPEDEF); public static final ImageDescriptor DESC_OBJS_ENUMERATION= createManaged(T_OBJ, IMG_OBJS_ENUMERATION); + public static final ImageDescriptor DESC_OBJS_UNKNOWN_TYPE= createManaged(T_OBJ, IMG_OBJS_UNKNOWN_TYPE); public static final ImageDescriptor DESC_OBJS_ENUMERATOR= createManaged(T_OBJ, IMG_OBJS_ENUMERATOR); public static final ImageDescriptor DESC_OBJS_FUNCTION= createManaged(T_OBJ, IMG_OBJS_FUNCTION); public static final ImageDescriptor DESC_OBJS_PUBLIC_METHOD= createManaged(T_OBJ, IMG_OBJS_PUBLIC_METHOD); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java index f7f2c5ab30e..bdead8b0e1f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java @@ -22,6 +22,7 @@ import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.browser.AllTypesCache; +import org.eclipse.cdt.core.browser.IWorkingCopyProvider; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.IWorkingCopy; @@ -341,7 +342,7 @@ public class CUIPlugin extends AbstractUIPlugin { registerAdapters(); CPluginImages.initialize(); - AllTypesCache.initialize(new AllTypesCache.IWorkingCopyProvider() { + AllTypesCache.initialize(new IWorkingCopyProvider() { public IWorkingCopy[] getWorkingCopies() { return CUIPlugin.getSharedWorkingCopies(); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassWizardPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassWizardPage.java index 2f3ca37bcc3..92076793ec3 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassWizardPage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassWizardPage.java @@ -15,15 +15,18 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Comparator; import org.eclipse.cdt.core.CConventions; import org.eclipse.cdt.core.browser.AllTypesCache; +import org.eclipse.cdt.core.browser.IQualifiedTypeName; 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.QualifiedTypeName; import org.eclipse.cdt.core.browser.TypeInfo; +import org.eclipse.cdt.core.browser.TypeSearchScope; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; @@ -31,12 +34,10 @@ import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.IStructure; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.IWorkingCopy; -import org.eclipse.cdt.core.search.ICSearchScope; -import org.eclipse.cdt.core.search.SearchEngine; import org.eclipse.cdt.internal.ui.dialogs.StatusInfo; import org.eclipse.cdt.internal.ui.dialogs.StatusUtil; import org.eclipse.cdt.internal.ui.util.ExceptionHandler; -import org.eclipse.cdt.internal.ui.wizards.*; +import org.eclipse.cdt.internal.ui.wizards.BaseClassSelectionDialog; import org.eclipse.cdt.internal.ui.wizards.NewWizardMessages; import org.eclipse.cdt.internal.ui.wizards.dialogfields.DialogField; import org.eclipse.cdt.internal.ui.wizards.dialogfields.IDialogFieldListener; @@ -46,9 +47,9 @@ import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil; import org.eclipse.cdt.internal.ui.wizards.dialogfields.LinkToFileGroup; import org.eclipse.cdt.internal.ui.wizards.dialogfields.ListDialogField; import org.eclipse.cdt.internal.ui.wizards.dialogfields.SelectionButtonDialogFieldGroup; -import org.eclipse.cdt.internal.ui.wizards.dialogfields.Separator; -import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringButtonDialogField; import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringDialogField; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringButtonDialogField; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.Separator; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.CodeGeneration; import org.eclipse.cdt.ui.PreferenceConstants; @@ -106,7 +107,10 @@ public class NewClassWizardPage extends WizardPage implements Listener { private ICElement eSelection = null; // default location where source files will be created private IPath defaultSourceFolder = null; - + private ITypeSearchScope fClassScope = null; + private final int[] fClassTypes= { ICElement.C_CLASS, ICElement.C_STRUCT }; + private IProject fSelectedProject = null; + // cache of newly-created files private ITranslationUnit parentHeaderTU = null; private ITranslationUnit parentBodyTU = null; @@ -185,10 +189,15 @@ public class NewClassWizardPage extends WizardPage implements Listener { public void init() { eSelection = getSelectionCElement(currentSelection); + fSelectedProject = getSelectionProject(currentSelection); + + fClassScope = new TypeSearchScope(); + fClassScope.add(fSelectedProject); + IResource resource = getSelectionResourceElement(currentSelection); if (resource != null) defaultSourceFolder = resource.getLocation().makeAbsolute(); - if (hasCppNature && defaultSourceFolder != null) { + if (fSelectedProject != null && hasCppNature && defaultSourceFolder != null) { fAccessButtons.setEnabled(false); setPageComplete(false); } else { @@ -332,9 +341,9 @@ public class NewClassWizardPage extends WizardPage implements Listener { private void classPageChangeControlPressed(DialogField field) { if (field == fBaseClassDialogField) { - ITypeInfo info= chooseBaseClass(); - if (info != null) { - fBaseClassDialogField.setText(info.getQualifiedName()); + ITypeInfo info= chooseBaseClass(); + if (info != null) { + fBaseClassDialogField.setText(info.getQualifiedTypeName().getFullyQualifiedName()); } } } @@ -463,19 +472,10 @@ public class NewClassWizardPage extends WizardPage implements Listener { return elementsOfTypeClassInProject; } - ICProject cProject= eSelection.getCProject(); - ICElement[] elements= new ICElement[] { cProject }; - final ICSearchScope scope= SearchEngine.createCSearchScope(elements, true); - final int[] kinds= { ICElement.C_CLASS, ICElement.C_STRUCT }; - final Collection typeList= new ArrayList(); - - if (AllTypesCache.isCacheUpToDate()) { - // run without progress monitor - AllTypesCache.getTypes(scope, kinds, null, typeList); - } else { - IRunnableWithProgress runnable= new IRunnableWithProgress() { + if (!AllTypesCache.isCacheUpToDate(fClassScope)) { + IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - AllTypesCache.getTypes(scope, kinds, monitor, typeList); + AllTypesCache.updateCache(fClassScope, monitor); if (monitor.isCanceled()) { throw new InterruptedException(); } @@ -488,20 +488,17 @@ public class NewClassWizardPage extends WizardPage implements Listener { String title= NewWizardMessages.getString("NewClassWizardPage.getProjectClasses.exception.title"); //$NON-NLS-1$ String message= NewWizardMessages.getString("NewClassWizardPage.getProjectClasses.exception.message"); //$NON-NLS-1$ ExceptionHandler.handle(e, title, message); - return null; + elementsOfTypeClassInProject = new ITypeInfo[0]; + return elementsOfTypeClassInProject; } catch (InterruptedException e) { // cancelled by user - return null; + elementsOfTypeClassInProject = new ITypeInfo[0]; + return elementsOfTypeClassInProject; } } - - if (typeList.isEmpty()) { - elementsOfTypeClassInProject= new ITypeInfo[0]; - } else { - elementsOfTypeClassInProject= (ITypeInfo[]) typeList.toArray(new ITypeInfo[typeList.size()]); - Arrays.sort(elementsOfTypeClassInProject, TYPE_NAME_COMPARATOR); - } - + + elementsOfTypeClassInProject = AllTypesCache.getTypes(fClassScope, fClassTypes); + Arrays.sort(elementsOfTypeClassInProject, TYPE_NAME_COMPARATOR); return elementsOfTypeClassInProject; } @@ -577,8 +574,41 @@ public class NewClassWizardPage extends WizardPage implements Listener { if (monitor == null) { monitor= new NullProgressMonitor(); } + monitor.beginTask(NewWizardMessages.getString("NewTypeWizardPage.operationdesc"), 10); //$NON-NLS-1$ - try{ + + try { + // resolve location of base class + String baseClassName = getBaseClassName(); + ITypeInfo baseClass = null; + if ((baseClassName != null) && (baseClassName.length() > 0)) + { + ITypeInfo[] classElements = findClassElementsInProject(); + baseClass = findInList(classElements, new QualifiedTypeName(baseClassName)); + if (baseClass != null && baseClass.getResolvedReference() == null) { + final ITypeInfo[] typesToResolve = new ITypeInfo[] { baseClass }; + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { + AllTypesCache.resolveTypeLocation(typesToResolve[0], progressMonitor); + if (progressMonitor.isCanceled()) { + throw new InterruptedException(); + } + } + }; + + try { + getContainer().run(true, true, runnable); + } catch (InvocationTargetException e) { + String title= NewWizardMessages.getString("NewClassWizardPage.getProjectClasses.exception.title"); //$NON-NLS-1$ + String message= NewWizardMessages.getString("NewClassWizardPage.getProjectClasses.exception.message"); //$NON-NLS-1$ + ExceptionHandler.handle(e, title, message); + return false; + } catch (InterruptedException e) { + // cancelled by user + return false; + } + } + } String lineDelimiter= null; lineDelimiter= System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -588,7 +618,7 @@ public class NewClassWizardPage extends WizardPage implements Listener { monitor.worked(1); if(parentHeaderTU != null){ - String header = constructHeaderFileContent(parentHeaderTU, lineDelimiter); + String header = constructHeaderFileContent(parentHeaderTU, lineDelimiter, baseClass); IWorkingCopy headerWC = parentHeaderTU.getSharedWorkingCopy(null, CUIPlugin.getDefault().getBufferFactory()); headerWC.getBuffer().append(header); synchronized(headerWC) { @@ -597,7 +627,7 @@ public class NewClassWizardPage extends WizardPage implements Listener { } //createdClass= (IStructure)headerWC.getElement(getNewClassName()); createdClass= headerWC.getElement(getNewClassName()); - headerWC.destroy(); + headerWC.destroy(); } if(parentBodyTU != null){ String body = constructBodyFileContent(lineDelimiter); @@ -607,7 +637,7 @@ public class NewClassWizardPage extends WizardPage implements Listener { bodyWC.reconcile(); bodyWC.commit(true, monitor); } - bodyWC.destroy(); + bodyWC.destroy(); } return true; @@ -781,42 +811,31 @@ public class NewClassWizardPage extends WizardPage implements Listener { } // ------------ Constructing File Contents ----------------- - protected String constructHeaderFileContent(ITranslationUnit header, String lineDelimiter){ + protected String constructHeaderFileContent(ITranslationUnit header, String lineDelimiter, ITypeInfo baseClass) { StringBuffer text = new StringBuffer(); boolean extendingBase = false; String baseClassName = getBaseClassName(); String baseClassFileName = ""; //$NON-NLS-1$ - boolean systemIncludePath= false; + boolean systemIncludePath = false; - if((baseClassName != null) && (baseClassName.length() > 0)) - { + if (baseClass != null) { extendingBase = true; - - ITypeInfo[] classElements = findClassElementsInProject(); - ITypeInfo baseClass = findInList(baseClassName, null, classElements); - - if (baseClass != null) { - IPath projectPath= null; - IPath baseClassPath= null; - ICProject cProject= eSelection.getCProject(); - if (cProject != null) { - projectPath= cProject.getPath(); - baseClassPath= baseClass.resolveIncludePath(cProject); - if (baseClassPath != null && projectPath != null && !projectPath.isPrefixOf(baseClassPath)) { - systemIncludePath= true; - } + ITypeReference location = baseClass.getResolvedReference(); + if (location != null) { + IPath projectPath = fSelectedProject.getFullPath(); + IPath relativePath = location.getRelativeIncludePath(fSelectedProject); + if (!relativePath.equals(location.getLocation())) { + systemIncludePath = true; + } else { + if (projectPath.isPrefixOf(location.getPath()) && projectPath.isPrefixOf(header.getPath())) + relativePath = location.getRelativePath(header.getPath()); } - if (baseClassPath == null) - baseClassPath= resolveRelativePath(baseClass.getPath(), header.getPath(), projectPath); - - if (baseClassPath != null) - baseClassFileName= baseClassPath.toString(); - else - baseClassFileName= baseClass.getFileName(); - } else { - baseClassFileName = baseClassName + HEADER_EXT; + baseClassFileName = relativePath.toString(); } } + if (baseClassFileName.length() == 0) { + baseClassFileName = baseClassName + HEADER_EXT; + } if(isIncludeGuard()){ text.append("#ifndef "); //$NON-NLS-1$ @@ -900,25 +919,6 @@ public class NewClassWizardPage extends WizardPage implements Listener { return text.toString(); } - private IPath resolveRelativePath(IPath baseClassPath, IPath headerPath, IPath projectPath) { - if (baseClassPath == null || headerPath == null || projectPath == null) - return baseClassPath; - - if (projectPath.isPrefixOf(baseClassPath) && projectPath.isPrefixOf(headerPath)) { - int segments= headerPath.matchingFirstSegments(baseClassPath); - if (segments > 0) { - IPath headerPrefix= headerPath.removeFirstSegments(segments).removeLastSegments(1); - IPath baseClassSuffix= baseClassPath.removeFirstSegments(segments); - IPath relativeBaseClassPath= new Path(""); //$NON-NLS-1$ - for (int i= 0; i < headerPrefix.segmentCount(); ++i) { - relativeBaseClassPath= relativeBaseClassPath.append(".." + IPath.SEPARATOR); //$NON-NLS-1$ - } - return relativeBaseClassPath.append(baseClassSuffix); - } - } - return baseClassPath; - } - protected String constructBodyFileContent(String lineDelimiter){ StringBuffer text = new StringBuffer(); text.append("#include \""); //$NON-NLS-1$ @@ -1008,10 +1008,14 @@ public class NewClassWizardPage extends WizardPage implements Listener { } // must not exist - ITypeInfo[] elementsFound= findClassElementsInProject(); - if(foundInList(getNewClassName(), getContainerPath(linkedResourceGroupForHeader), elementsFound)){ + ITypeInfo[] elementsFound = findClassElementsInProject(); + QualifiedTypeName typeName = new QualifiedTypeName(getNewClassName()); + if (foundInList(elementsFound, typeName)) { status.setWarning(NewWizardMessages.getString("NewClassWizardPage.error.ClassNameExists")); //$NON-NLS-1$ } +// if(foundInList(getNewClassName(), getContainerPath(linkedResourceGroupForHeader), elementsFound)){ +// status.setWarning(NewWizardMessages.getString("NewClassWizardPage.error.ClassNameExists")); //$NON-NLS-1$ +// } return status; } /** @@ -1039,29 +1043,51 @@ public class NewClassWizardPage extends WizardPage implements Listener { } // if class does not exist, give warning - ITypeInfo[] elementsFound = findClassElementsInProject(); - if(!foundInList(baseClassName, null, elementsFound)){ + ITypeInfo[] elementsFound = findClassElementsInProject(); + if (!foundInList(elementsFound, new QualifiedTypeName(baseClassName))) { status.setWarning(NewWizardMessages.getString("NewClassWizardPage.warning.BaseClassNotExists")); //$NON-NLS-1$ } return status; } - /** - * A comparator for simple type names - */ - final static private Comparator TYPE_NAME_COMPARATOR= new Comparator() { - public int compare(Object o1, Object o2) { - return ((ITypeInfo)o1).getName().compareTo(((ITypeInfo)o2).getName()); - } - }; - private ITypeInfo findInList(String name, IPath path, ITypeInfo[] elements) { - if (elements == null || elements.length == 0) - return null; - return TypeInfo.findType(name, path, elements); + private boolean foundInList(ITypeInfo[] elements, IQualifiedTypeName typeName){ + return (findInList(elements, typeName) != null); } - private boolean foundInList(String name, IPath path, ITypeInfo[] elements){ - return (findInList(name, path, elements) != null); - } + private Comparator TYPE_NAME_COMPARATOR = new Comparator() { + public int compare(Object o1, Object o2) { + return ((ITypeInfo)o1).getName().compareTo(((ITypeInfo)o2).getName()); + } + }; + private ITypeInfo findInList(ITypeInfo[] elements, IQualifiedTypeName typeName) { + if (elements == null || elements.length == 0) + return null; + + TypeInfo key = new TypeInfo(0, typeName, null); + int index = Arrays.binarySearch(elements, key, TYPE_NAME_COMPARATOR); + if (index >= 0 && index < elements.length) { + for (int i = index - 1; i >= 0; --i) { + ITypeInfo curr = elements[i]; + if (key.getName().equals(curr.getName())) { + if (key.getQualifiedTypeName().equals(curr.getQualifiedTypeName())) { + return curr; + } + } else { + break; + } + } + for (int i = index; i < elements.length; ++i) { + ITypeInfo curr = elements[i]; + if (key.getName().equals(curr.getName())) { + if (key.getQualifiedTypeName().equals(curr.getQualifiedTypeName())) { + return curr; + } + } else { + break; + } + } + } + return null; + } }