diff options
Diffstat (limited to 'core/org.eclipse.cdt.core/browser/org')
15 files changed, 2386 insertions, 0 deletions
diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java new file mode 100644 index 00000000000..1257fa18cae --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java @@ -0,0 +1,295 @@ +/******************************************************************************* + * 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.model.CoreModel; +import org.eclipse.cdt.core.model.ElementChangedEvent; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICElementDelta; +import org.eclipse.cdt.core.model.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.TypeCacherJob; +import org.eclipse.cdt.internal.core.browser.util.ArrayUtil; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.jobs.Job; + +/** + * Manages a search cache for types in the workspace. Instead of returning objects of type <code>ICElement</code> + * the methods of this class returns a list of the lightweight objects <code>TypeInfo</code>. + * <P> + * 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. + * <P> + * If <code>getTypes</code> 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 TypeCacherJob fgJob; + private static TypeCacheDeltaListener fgDeltaListener; + + /** + * 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(); + } + + /** + * Initializes the AllTypesCache service. + * + * @param provider A working copy provider. + */ + public static void initialize(IWorkingCopyProvider provider) { + fgCache= new TypeCache(); + fgJob= new TypeCacherJob(fgCache, provider); + fgDeltaListener= new TypeCacheDeltaListener(fgCache, fgJob); + + // add delta listener + CoreModel.getDefault().addElementChangedListener(fgDeltaListener); + + // schedule job to run after INITIAL_DELAY + if (fgJob.getState() != Job.RUNNING) { + fgJob.setSearchPaths(null); + fgJob.setPriority(Job.BUILD); + fgJob.schedule(INITIAL_DELAY); + } + } + + /** + * Terminates the service provided by AllTypesCache. + */ + public static void terminate() { + // remove delta listener + CoreModel.getDefault().removeElementChangedListener(fgDeltaListener); + + // terminate background job + fgJob.cancel(); + } + + /* + * Returns the actual type cache. + */ + public static TypeCache getCache() { + return fgCache; + } + + /** + * Returns true if the type cache is up to date. + */ + public static boolean isCacheUpToDate() { + return !fgCache.isDirty(); + } + + /** + * 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 <code>TypeInfo</code> 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 + if (fgJob.getState() != Job.RUNNING) { + // boost priority since action was user-initiated + fgJob.setSearchPaths(null); + fgJob.setPriority(Job.SHORT); + fgJob.schedule(); + } + + // wait for job to finish + try { + fgJob.join(monitor); + if (monitor != null) + monitor.done(); + } catch (InterruptedException ex) { + return; + } + } + + 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); + } + } + } + + /** + * Listener for changes to CModel. + * @see org.eclipse.cdt.core.model.IElementChangedListener + * @since 3.0 + */ + private static class TypeCacheDeltaListener implements IElementChangedListener { + + private TypeCache fTypeCache; + private TypeCacherJob fTypeCacherJob; + private Set fPaths= new HashSet(5); + private Set fPrefixes= new HashSet(5); + private boolean fFlushAll= false; + + public TypeCacheDeltaListener(TypeCache cache, TypeCacherJob job) { + fTypeCache= cache; + fTypeCacherJob= job; + } + + /* + * @see IElementChangedListener#elementChanged + */ + public void elementChanged(ElementChangedEvent event) { + fPaths.clear(); + fPrefixes.clear(); + fFlushAll= false; + + boolean needsFlushing= processDelta(event.getDelta()); + if (needsFlushing) { + // cancel background job + if (fTypeCacherJob.getState() == Job.RUNNING) { + // wait for job to finish? + try { + fTypeCacherJob.cancel(); + fTypeCacherJob.join(); + } catch (InterruptedException ex) { + } + } + + if (fFlushAll) { + // flush the entire cache + fTypeCacherJob.setSearchPaths(null); + fTypeCache.flushAll(); + } else { + // flush affected files from cache + Set searchPaths= new HashSet(10); + getPrefixMatches(fPrefixes, searchPaths); + searchPaths.addAll(fPaths); + fTypeCacherJob.setSearchPaths(searchPaths); + fTypeCache.flush(searchPaths); + } + + // restart the background job + fTypeCacherJob.setPriority(Job.BUILD); + fTypeCacherJob.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); + + switch (elem.getElementType()) { + case ICElement.C_MODEL: + { + if (isAddedOrRemoved) { + // CModel has changed + // flush the entire cache + fFlushAll= true; + return true; + } + 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/core/browser/ITypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java new file mode 100644 index 00000000000..eceb6f4f065 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * 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.ICProject; +import org.eclipse.cdt.core.search.ICSearchScope; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; + +/** + * Type information. + */ +public interface ITypeInfo { + + /** + * Gets the CElement type. + */ + public int getType(); + + /** + * Gets the type name. + */ + public String getName(); + + /** + * Gets the enclosing type names. + */ + public String[] getEnclosingNames(); + + /** + * Gets the resource where type is located. + */ + public IResource getResource(); + + /** + * Gets the relative path where type is located. + */ + public IPath getPath(); + + /** + * Gets the absolute path where type is located. + */ + public IPath getLocation(); + + /** + * Gets the start offset of type position. + */ + public int getStartOffset(); + + /** + * Gets the end offset of type position. + */ + 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(); + + /** + * Gets the fully qualified type container name: Includes enclosing type names, but + * not filename. Identifiers are separated by colons. + */ + public String getParentName(); + + /** + * Gets the type qualified name: Includes enclosing type names, but + * not filename. Identifiers are separated by colons. + */ + public String getQualifiedName(); + + /** + * Gets the fully qualified type container name: Filename or + * enclosing type name with filename. + * All identifiers are separated by colons. + */ + 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(); + + /** 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 + * <code>null</code> if not found. + */ + public IPath resolveIncludePath(ICProject cProject); +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java new file mode 100644 index 00000000000..fff39f72225 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java @@ -0,0 +1,430 @@ +/******************************************************************************* + * 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 java.util.Arrays; +import java.util.Comparator; + +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.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.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); + } + + 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 String getName() { + return name; + } + + 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]); + } + return buf.toString(); + } + 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(); + } + + 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; + + 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; + } + } + 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; + + // 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(); + } + } + } + return false; + } + + public int hashCode() { + if (hashString == null) { + hashCode= getHashString().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; + } + if (!(obj instanceof TypeInfo)) { + return false; + } + TypeInfo info= (TypeInfo)obj; + if (hashCode() != info.hashCode()) + return false; + return getHashString().equals(info.getHashString()); + } + + public int compareTo(Object obj) { + if (obj == this) { + return 0; + } + if( !(obj instanceof TypeInfo)) { + throw new ClassCastException(); + } + TypeInfo info= (TypeInfo)obj; + return getHashString().compareTo(info.getHashString()); + } + + public static boolean isValidType(int type) { + switch (type) { + case ICElement.C_NAMESPACE: + case ICElement.C_CLASS: + case ICElement.C_STRUCT: + 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/internal/core/browser/cache/TypeCache.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java new file mode 100644 index 00000000000..90dadd6971c --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * 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 java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.eclipse.cdt.core.browser.TypeInfo; +import org.eclipse.core.runtime.IPath; + +public class TypeCache { + + 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); + + public TypeReference(TypeInfo info, IPath path) { + fRealInfo= info; + fPaths.add(path); + } + + public TypeInfo getInfo() { + return fRealInfo; + } + + public void addPath(IPath path) { + fPaths.add(path); + } + + public void removePath(IPath path) { + fPaths.remove(path); + } + + public Collection getPaths() { + return fPaths; + } + }; + + public TypeCache() { + } + + public synchronized void markAsDirty(boolean dirty) { + fIsDirty= dirty; + } + + 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 synchronized boolean contains(IPath path) { + return fFileMap.containsKey(path); + } + + 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); + } + } + } + + public synchronized void flushAll() { + // flush the entire cache + fFileMap.clear(); + fTypeMap.clear(); + fIsDirty= true; + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.java new file mode 100644 index 00000000000..395d2c30ca7 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the 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.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class TypeCacheMessages { + + private static final String RESOURCE_BUNDLE= TypeCacheMessages.class.getName(); + + private static ResourceBundle fgResourceBundle; + static { + try { + fgResourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE); + } catch (MissingResourceException x) { + fgResourceBundle = null; + } + } + + private TypeCacheMessages() { + } + + public static String getString(String key) { + try { + return fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } catch (NullPointerException e) { + return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + public static String getFormattedString(String key, String arg) { + return getFormattedString(key, new String[] { arg }); + } + + public static String getFormattedString(String key, String[] args) { + return MessageFormat.format(getString(key), args); + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties new file mode 100644 index 00000000000..273052e91ae --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2004 QNX Software Systems Ltd. and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Common Public License v0.5 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/cpl-v05.html +# +# Contributors: +# QNX Software Systems - Initial API and implementation +############################################################################### + +TypeCacherJob.jobName=TypeCache +TypeCacherJob.taskName=Updating Type Info... diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java new file mode 100644 index 00000000000..2e1dd094915 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacherJob.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * 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.core.CCorePlugin; +import org.eclipse.cdt.core.browser.AllTypesCache.IWorkingCopyProvider; +import org.eclipse.cdt.core.model.IWorkingCopy; +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.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; + + +/** + * Background job for filling the type cache. + * @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; + } + }; + + /** + * Constant identifying the job family identifier for the background job. + * @see IJobManager#join(Object, IProgressMonitor) + * @since 3.0 + */ + private static final Object FAMILY= new Object(); + + private DelegatedProgressMonitor fProgressMonitor; + private Set fSearchPaths= new HashSet(50); + private TypeCache fTypeCache; + private IWorkingCopyProvider fWorkingCopyProvider; + + public TypeCacherJob(TypeCache cache, IWorkingCopyProvider provider) { + super(TypeCacheMessages.getString("TypeCacherJob.jobName")); //$NON-NLS-1$ + setPriority(BUILD); + setSystem(true); + //setRule(MUTEX_RULE); + fTypeCache= cache; + fWorkingCopyProvider= provider; + } + + /* (non-Javadoc) + * @see org.eclipse.core.internal.jobs.InternalJob#belongsTo(java.lang.Object) + */ + public boolean belongsTo(Object family) { + return family == FAMILY; + } + + 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) { + fProgressMonitor= new DelegatedProgressMonitor(monitor); + + try { + search(fProgressMonitor); + fProgressMonitor.done(); + } catch(InterruptedException ex) { + return Status.CANCEL_STATUS; + } catch (OperationCanceledException ex) { + return Status.CANCEL_STATUS; + } finally { + fProgressMonitor= null; + } + + 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 { + if (fProgressMonitor != null) + fProgressMonitor.addDelegate(monitor); + super.join(); + } + + private void search(IProgressMonitor monitor) throws InterruptedException { + + monitor.beginTask(TypeCacheMessages.getString("TypeCacherJob.taskName"), 100); //$NON-NLS-1$ + + IWorkspace workspace= CCorePlugin.getWorkspace(); + if (workspace == null) + throw new InterruptedException(); + + ICSearchScope scope= new CWorkspaceScope(); + + // 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); + } + } + + Set allSearchPaths= pathCollector.getPaths(); + if (allSearchPaths == null) + allSearchPaths= new HashSet(); + + // remove cached files + allSearchPaths.removeAll(fTypeCache.getAllFiles()); + + if (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(); + } +} 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 new file mode 100644 index 00000000000..0e3e726c77f --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeMatchCollector.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * 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 new file mode 100644 index 00000000000..e20b01c0270 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeMatchLocator.java @@ -0,0 +1,561 @@ +/******************************************************************************* + * 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.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= (Object) 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) { + return ParserUtil.createReader(finalPath); + } + + /* (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(); + reader= new CharArrayReader(workingCopy.getContents()); + } else { + currentResource= workspaceRoot.findMember(path, true); + if (currentResource != null && currentResource instanceof IFile) { + IFile file= (IFile) currentResource; + try { + reader= new InputStreamReader(file.getContents()); + } catch (CoreException ex) { + 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() ); + parser = ParserFactory.createParser( scanner, this, ParserMode.COMPLETE_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; + } + +} 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 new file mode 100644 index 00000000000..352140e53ef --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPathCollector.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * 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 new file mode 100644 index 00000000000..47def56dd5f --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeSearchPattern.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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/ArrayUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/ArrayUtil.java new file mode 100644 index 00000000000..4cd93b656b4 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/ArrayUtil.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the 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.util; + +/** + * A helper class which allows you to perform some + * simple set operations on int arrays. + */ +public class ArrayUtil { + private ArrayUtil() { + } + + // returns true if set contains elem + public static boolean contains(int[] set, int elem) { + if (set == null) + return false; + for (int i= 0; i < set.length; ++i) { + if (set[i] == elem) + return true; + } + return false; + } + + // returns true if set contains all of subset + public static boolean containsAll(int[] set, int[] subset) { + if (set == null || subset == null) + return false; + for (int i= 0; i < subset.length; ++i) { + if (!contains(set, subset[i])) + return false; + } + return true; + } + + // return a copy of fromSet + public static int[] clone(int[] fromSet) { + if (fromSet == null) + return null; + int[] newSet= new int[fromSet.length]; + for (int i= 0; i < fromSet.length; ++i) { + newSet[i]= fromSet[i]; + } + return newSet; + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/DelegatedProgressMonitor.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/DelegatedProgressMonitor.java new file mode 100644 index 00000000000..a28a746d674 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/DelegatedProgressMonitor.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * 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.util; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IProgressMonitorWithBlocking; +import org.eclipse.core.runtime.IStatus; + +/** + * A wrapper around one or more progress monitors. Forwards + * <code>IProgressMonitor</code> and <code>IProgressMonitorWithBlocking</code> + * methods to the delegate monitors. + */ +public class DelegatedProgressMonitor implements IProgressMonitor, IProgressMonitorWithBlocking { + + private static int INITIAL_DELEGATE_COUNT = 2; + private final ArrayList fDelegateList = new ArrayList(INITIAL_DELEGATE_COUNT); + private String fTaskName; + private String fSubTask; + private int fTotalWork = IProgressMonitor.UNKNOWN; + private double fWorked; + private boolean fIsBlocked = false; + private boolean fIsCanceled = false; + + /** + * Creates a new delegated monitor. + */ + public DelegatedProgressMonitor() { + } + + /** + * Creates a new delegated monitor, and adds a delegate. + */ + public DelegatedProgressMonitor(IProgressMonitor delegate) { + addDelegate(delegate); + } + + /* + * @see IProgressMonitor#beginTask + */ + public synchronized void beginTask(String name, int totalWork) { + fTaskName = name; + fTotalWork = totalWork; + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + delegate.beginTask(fTaskName, fTotalWork); + } + }); + } + + /* + * @see IProgressMonitor#done + */ + public synchronized void done() { + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + delegate.done(); + } + }); + } + + /* + * @see IProgressMonitor#setTaskName + */ + public synchronized void setTaskName(String name) { + fTaskName = name; + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + delegate.setTaskName(fTaskName); + } + }); + } + + /* + * @see IProgressMonitor#subTask + */ + public synchronized void subTask(String name) { + fSubTask = name; + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + delegate.subTask(fSubTask); + } + }); + } + + /* + * @see IProgressMonitor#worked + */ + public void worked(int work) { + internalWorked(work); + } + + /* + * @see IProgressMonitor#internalWorked + */ + public synchronized void internalWorked(double internalWork) { + fWorked += internalWork; + final double fInternalWork = internalWork; + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + delegate.internalWorked(fInternalWork); + } + }); + } + + /* + * @see IProgressMonitor#isCanceled + */ + public synchronized boolean isCanceled() { + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + fIsCanceled |= delegate.isCanceled(); + } + }); + return fIsCanceled; + } + + /* + * @see IProgressMonitor#setCanceled + */ + public synchronized void setCanceled(boolean canceled) { + fIsCanceled = canceled; + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + delegate.setCanceled(fIsCanceled); + } + }); + } + + /* + * @see IProgressMonitor#setBlocked + */ + public synchronized void setBlocked(IStatus reason) { + fIsBlocked = true; + final IStatus fReason = reason; + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + if (delegate instanceof IProgressMonitorWithBlocking) + ((IProgressMonitorWithBlocking) delegate).setBlocked(fReason); + } + }); + } + + /* + * @see IProgressMonitor#clearBlocked + */ + public synchronized void clearBlocked() { + fIsBlocked = false; + visitDelegates(new IDelegateVisitor() { + public void visit(IProgressMonitor delegate) { + if (delegate instanceof IProgressMonitorWithBlocking) + ((IProgressMonitorWithBlocking) delegate).clearBlocked(); + } + }); + } + + /** + * Adds a delegate. + */ + public synchronized void addDelegate(IProgressMonitor delegate) { + if (fDelegateList.indexOf(delegate) == -1) { + if (fTaskName != null) + syncUp(delegate); + fDelegateList.add(delegate); + } + } + + /** + * Brings delegate in sync with current progress. + */ + private void syncUp(IProgressMonitor delegate) { + delegate.beginTask(fTaskName, fTotalWork); + delegate.internalWorked(fWorked); + if (fSubTask != null && fSubTask.length() > 0) + delegate.subTask(fSubTask); + if (fIsBlocked && delegate instanceof IProgressMonitorWithBlocking) + ((IProgressMonitorWithBlocking) delegate).setBlocked(null); + } + + /** + * Removes a delegate. + */ + public synchronized void removeDelegate(IProgressMonitor delegate) { + int index = fDelegateList.indexOf(delegate); + if (index != -1) { + fDelegateList.remove(index); + } + } + + /** + * Returns the delegate list. + * + * @return An array of progress monitors added using <code>addDelegate()</code>. + */ + public synchronized IProgressMonitor[] getDelegates() { + return (IProgressMonitor[]) fDelegateList.toArray(); + } + + /** + * Defines a delegate visitor. + */ + private static interface IDelegateVisitor { + public void visit(IProgressMonitor delegate); + } + + /** + * Visits each delegate in the delegates list. + */ + private void visitDelegates(IDelegateVisitor visitor) { + // Clone the delegates since they could remove themselves when called + ArrayList delegatesList = (ArrayList) fDelegateList.clone(); + for (Iterator i = delegatesList.iterator(); i.hasNext(); ) { + IProgressMonitor delegate = (IProgressMonitor) i.next(); + visitor.visit(delegate); + } + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/PathUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/PathUtil.java new file mode 100644 index 00000000000..b638a54fbf1 --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/PathUtil.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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.util; + +import java.io.File; +import java.io.IOException; + +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; + } + } + public static boolean isWindowsSystem() { + return fWindows; + } + + public static Path getCanonicalPath(String fullPath) { + File file = new File(fullPath); + try { + String canonPath = file.getCanonicalPath(); + return new Path(canonPath); + } catch (IOException ex) { + } + return new Path(fullPath); + } +} diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java new file mode 100644 index 00000000000..6e06dbc5e3c --- /dev/null +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/util/SimpleStack.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * 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.util; + +import java.util.ArrayList; + +/** + * A helper class which allows you to perform some simple + * stack operations. Avoids the extra overhead of + * synchronization in Java.Util.Stack. + */ +public class SimpleStack { + + private static int INITIAL_STACK_SIZE = 10; + private ArrayList items; + private static boolean VERBOSE = false; + + public SimpleStack() { + items = new ArrayList(INITIAL_STACK_SIZE); + } + + public SimpleStack(int initialSize) { + items = new ArrayList(initialSize); + } + + public Object push(Object item) { + items.add(item); + if (VERBOSE) + trace("push on stack: " + item); //$NON-NLS-1$ + return item; + } + + public Object pop() { + int top = items.size()-1; + if (top < 0) + return null; + Object item = items.get(top); + items.remove(top); + if (VERBOSE) + trace("pop from stack: " + item); //$NON-NLS-1$ + return item; + } + + public Object top() { + int top = items.size()-1; + if (top < 0) + return null; + return items.get(top); + } + + public boolean isEmpty() { + return (items.size() == 0); + } + + public Object[] toArray() { + return items.toArray(); + } + + public Object[] toArray(Object a[]) { + return items.toArray(a); + } + + private static void trace(String msg) { + System.out.println("(" + Thread.currentThread() + ") " + msg); //$NON-NLS-1$ //$NON-NLS-2$ + } +} |