mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
2004-07-15 Chris Wiebe
Initial draft for the type hierarchy view. * browser/*
This commit is contained in:
parent
b1ee9d479f
commit
5d526c2acd
21 changed files with 4537 additions and 143 deletions
|
@ -1,3 +1,8 @@
|
|||
2004-07-15 Chris Wiebe
|
||||
|
||||
Initial draft for the type hierarchy view.
|
||||
* browser/*
|
||||
|
||||
2004-07-06 Bogdan Gheorghe
|
||||
Handled the case of CContainer in both updateIndexAddResource and
|
||||
updateIndexRemoveResource.
|
||||
|
|
|
@ -14,6 +14,8 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
|
||||
import org.eclipse.cdt.core.browser.typehierarchy.TypeHierarchyBuilder;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.ElementChangedEvent;
|
||||
|
@ -48,7 +50,7 @@ public class AllTypesCache {
|
|||
|
||||
private static final int INITIAL_DELAY = 5000;
|
||||
private static IWorkingCopyProvider fgWorkingCopyProvider;
|
||||
private static TypeCacheManager fgTypeCacheManager;
|
||||
private static TypeHierarchyBuilder fgTypeHierarchyBuilder;
|
||||
private static IElementChangedListener fgElementChangedListener;
|
||||
private static IPropertyChangeListener fgPropertyChangeListener;
|
||||
private static boolean fgEnableIndexing = true;
|
||||
|
@ -63,7 +65,8 @@ public class AllTypesCache {
|
|||
*/
|
||||
public static void initialize(IWorkingCopyProvider workingCopyProvider) {
|
||||
fgWorkingCopyProvider = workingCopyProvider;
|
||||
fgTypeCacheManager = new TypeCacheManager(fgWorkingCopyProvider);
|
||||
TypeCacheManager.getInstance().setWorkingCopyProvider(fgWorkingCopyProvider);
|
||||
fgTypeHierarchyBuilder = new TypeHierarchyBuilder();
|
||||
|
||||
// load prefs
|
||||
Preferences prefs = CCorePlugin.getDefault().getPluginPreferences();
|
||||
|
@ -77,13 +80,13 @@ public class AllTypesCache {
|
|||
}
|
||||
|
||||
// start jobs in background after INITIAL_DELAY
|
||||
fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY);
|
||||
TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY);
|
||||
|
||||
// add delta listener
|
||||
fgElementChangedListener = new IElementChangedListener() {
|
||||
public void elementChanged(ElementChangedEvent event) {
|
||||
fgTypeCacheManager.processDelta(event.getDelta());
|
||||
fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
|
||||
TypeCacheManager.getInstance().processDelta(event.getDelta());
|
||||
TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
|
||||
}
|
||||
};
|
||||
CoreModel.getDefault().addElementChangedListener(fgElementChangedListener);
|
||||
|
@ -96,9 +99,9 @@ public class AllTypesCache {
|
|||
String value = (String) event.getNewValue();
|
||||
fgEnableIndexing = Boolean.valueOf(value).booleanValue();
|
||||
if (!fgEnableIndexing) {
|
||||
fgTypeCacheManager.cancelJobs();
|
||||
TypeCacheManager.getInstance().cancelJobs();
|
||||
} else {
|
||||
fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
|
||||
TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,8 +122,8 @@ public class AllTypesCache {
|
|||
CCorePlugin.getDefault().getPluginPreferences().removePropertyChangeListener(fgPropertyChangeListener);
|
||||
|
||||
// terminate all running jobs
|
||||
if (fgTypeCacheManager != null) {
|
||||
fgTypeCacheManager.cancelJobs();
|
||||
if (TypeCacheManager.getInstance() != null) {
|
||||
TypeCacheManager.getInstance().cancelJobs();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +142,7 @@ public class AllTypesCache {
|
|||
public boolean shouldContinue() { return true; }
|
||||
};
|
||||
for (int i = 0; i < projects.length; ++i) {
|
||||
fgTypeCacheManager.getCache(projects[i]).accept(visitor);
|
||||
TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
|
||||
}
|
||||
return (ITypeInfo[]) fAllTypes.toArray(new ITypeInfo[fAllTypes.size()]);
|
||||
}
|
||||
|
@ -167,7 +170,7 @@ public class AllTypesCache {
|
|||
public boolean shouldContinue() { return true; }
|
||||
};
|
||||
for (int i = 0; i < projects.length; ++i) {
|
||||
fgTypeCacheManager.getCache(projects[i]).accept(visitor);
|
||||
TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
|
||||
}
|
||||
return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
|
||||
}
|
||||
|
@ -198,7 +201,7 @@ public class AllTypesCache {
|
|||
public boolean shouldContinue() { return true; }
|
||||
};
|
||||
for (int i = 0; i < projects.length; ++i) {
|
||||
fgTypeCacheManager.getCache(projects[i]).accept(visitor);
|
||||
TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
|
||||
}
|
||||
return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
|
||||
}
|
||||
|
@ -224,7 +227,7 @@ public class AllTypesCache {
|
|||
public boolean shouldContinue() { return true; }
|
||||
};
|
||||
for (int i = 0; i < projects.length; ++i) {
|
||||
ITypeCache cache = fgTypeCacheManager.getCache(projects[i]);
|
||||
ITypeCache cache = TypeCacheManager.getInstance().getCache(projects[i]);
|
||||
cache.accept(visitor);
|
||||
if (includeGlobalNamespace) {
|
||||
fTypesFound.add(cache.getGlobalNamespace());
|
||||
|
@ -243,7 +246,7 @@ public class AllTypesCache {
|
|||
for (int i = 0; i < projects.length; ++i) {
|
||||
IProject project = projects[i];
|
||||
if (project.exists() && project.isOpen()) {
|
||||
if (!fgTypeCacheManager.getCache(project).isUpToDate())
|
||||
if (!TypeCacheManager.getInstance().getCache(project).isUpToDate())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +280,7 @@ public class AllTypesCache {
|
|||
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);
|
||||
TypeCacheManager.getInstance().getCache(project).reconcileAndWait(true, Job.SHORT, monitor);
|
||||
}
|
||||
monitor.done();
|
||||
}
|
||||
|
@ -293,17 +296,36 @@ public class AllTypesCache {
|
|||
if (location == null) {
|
||||
// cancel background jobs
|
||||
IProject project = info.getEnclosingProject();
|
||||
fgTypeCacheManager.getCache(project).cancelJobs();
|
||||
TypeCacheManager.getInstance().getCache(project).cancelJobs();
|
||||
|
||||
// start the search job
|
||||
fgTypeCacheManager.getCache(project).locateTypeAndWait(info, Job.SHORT, monitor);
|
||||
TypeCacheManager.getInstance().getCache(project).locateTypeAndWait(info, Job.SHORT, monitor);
|
||||
|
||||
// get the newly parsed location
|
||||
location = info.getResolvedReference();
|
||||
|
||||
// resume background jobs
|
||||
fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
|
||||
TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
public static ITypeInfo getTypeForElement(ICElement elem) {
|
||||
return TypeUtil.getTypeForElement(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a type hierarchy for this type containing
|
||||
* this type and all of its supertypes and subtypes in the workspace.
|
||||
*
|
||||
* @param info the given type
|
||||
* @param monitor the given progress monitor
|
||||
* @return a type hierarchy for the given type
|
||||
*/
|
||||
public static ITypeHierarchy createTypeHierarchy(ICElement type, IProgressMonitor monitor) throws CModelException {
|
||||
ITypeInfo info = TypeUtil.getTypeForElement(type);
|
||||
if (info != null)
|
||||
return fgTypeHierarchyBuilder.createTypeHierarchy(info, fgEnableIndexing, monitor);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
package org.eclipse.cdt.core.browser;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
|
||||
import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
|
||||
|
@ -145,11 +146,6 @@ public interface ITypeInfo extends Comparable {
|
|||
*/
|
||||
public ITypeReference getResolvedReference();
|
||||
|
||||
/**
|
||||
* Returns the corresponding CElement or <code>null</code> if not found.
|
||||
*/
|
||||
public ICElement getCElement();
|
||||
|
||||
/**
|
||||
* Returns true if the type can be substituted.
|
||||
*/
|
||||
|
@ -157,4 +153,52 @@ public interface ITypeInfo extends Comparable {
|
|||
|
||||
public ITypeCache getCache();
|
||||
public void setCache(ITypeCache typeCache);
|
||||
|
||||
/**
|
||||
* Returns true if other types extend this type.
|
||||
*/
|
||||
public boolean hasSubTypes();
|
||||
|
||||
/** Gets all types which extend this type.
|
||||
* @return array of types, or <code>null</code> if none found.
|
||||
*/
|
||||
public ITypeInfo[] getSubTypes();
|
||||
|
||||
/**
|
||||
* Returns true if this type has base classes.
|
||||
*/
|
||||
public boolean hasSuperTypes();
|
||||
|
||||
/** Gets the base classes.
|
||||
* @return array of types, or <code>null</code> if none found.
|
||||
*/
|
||||
public ITypeInfo[] getSuperTypes();
|
||||
|
||||
/**
|
||||
* Gets the base class access visibility (PRIVATE, PROTECTED, PUBLIC)
|
||||
*/
|
||||
public ASTAccessVisibility getSuperTypeAccess(ITypeInfo subType);
|
||||
|
||||
/**
|
||||
* Adds a derived class reference, i.e. this type is used as
|
||||
* a base class at the given location.
|
||||
*/
|
||||
public void addDerivedReference(ITypeReference location);
|
||||
|
||||
/** Gets the originating locations where this type was
|
||||
* used as a base class.
|
||||
* @return all known source references, or an empty
|
||||
* array if none found.
|
||||
*/
|
||||
public ITypeReference[] getDerivedReferences();
|
||||
|
||||
/**
|
||||
* Returns true if the type is a class or struct.
|
||||
*/
|
||||
public boolean isClass();
|
||||
|
||||
/**
|
||||
* Returns true if type is referenced in the given scope.
|
||||
*/
|
||||
public boolean isReferenced(ITypeSearchScope scope);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,10 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.browser;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
|
||||
import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
|
||||
import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
|
@ -22,6 +25,8 @@ public class TypeInfo implements ITypeInfo
|
|||
protected IQualifiedTypeName fQualifiedName;
|
||||
protected ITypeReference[] fSourceRefs = null;
|
||||
protected int fSourceRefsCount = 0;
|
||||
protected ITypeReference[] fDerivedSourceRefs = null;
|
||||
protected int fDerivedSourceRefsCount = 0;
|
||||
|
||||
protected final static int INITIAL_REFS_SIZE = 1;
|
||||
protected final static int REFS_GROW_BY = 2;
|
||||
|
@ -54,26 +59,6 @@ public class TypeInfo implements ITypeInfo
|
|||
return null;
|
||||
}
|
||||
|
||||
public ICElement getCElement() {
|
||||
ITypeReference ref = getResolvedReference();
|
||||
if (ref != null) {
|
||||
ICElement[] elems = ref.getCElements();
|
||||
if (elems != null && elems.length > 0) {
|
||||
if (elems.length == 1)
|
||||
return elems[0];
|
||||
|
||||
for (int i = 0; i < elems.length; ++i) {
|
||||
ICElement elem = elems[i];
|
||||
if (elem.getElementType() == fElementType && elem.getElementName().equals(getName())) {
|
||||
//TODO should check fully qualified name
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ITypeReference getResolvedReference() {
|
||||
for (int i = 0; i < fSourceRefsCount; ++i) {
|
||||
ITypeReference location = fSourceRefs[i];
|
||||
|
@ -85,7 +70,26 @@ public class TypeInfo implements ITypeInfo
|
|||
}
|
||||
|
||||
public boolean isReferenced() {
|
||||
return (fSourceRefs != null);
|
||||
return (fSourceRefs != null || fDerivedSourceRefs != null);
|
||||
}
|
||||
|
||||
public boolean isReferenced(ITypeSearchScope scope) {
|
||||
if (scope == null || scope.isWorkspaceScope())
|
||||
return true;
|
||||
|
||||
// check if path is in scope
|
||||
for (int i = 0; i < fSourceRefsCount; ++i) {
|
||||
ITypeReference location = fSourceRefs[i];
|
||||
if (scope.encloses(location.getPath()))
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < fDerivedSourceRefsCount; ++i) {
|
||||
ITypeReference location = fDerivedSourceRefs[i];
|
||||
if (scope.encloses(location.getPath()))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isUndefinedType() {
|
||||
|
@ -256,4 +260,64 @@ public class TypeInfo implements ITypeInfo
|
|||
public void setCache(ITypeCache typeCache) {
|
||||
fTypeCache = typeCache;
|
||||
}
|
||||
|
||||
public void addDerivedReference(ITypeReference location) {
|
||||
if (fDerivedSourceRefs == null) {
|
||||
fDerivedSourceRefs = new ITypeReference[INITIAL_REFS_SIZE];
|
||||
fDerivedSourceRefsCount = 0;
|
||||
} else if (fDerivedSourceRefsCount == fDerivedSourceRefs.length) {
|
||||
ITypeReference[] refs = new ITypeReference[fDerivedSourceRefs.length + REFS_GROW_BY];
|
||||
System.arraycopy(fDerivedSourceRefs, 0, refs, 0, fDerivedSourceRefsCount);
|
||||
fDerivedSourceRefs = refs;
|
||||
}
|
||||
fDerivedSourceRefs[fDerivedSourceRefsCount] = location;
|
||||
++fDerivedSourceRefsCount;
|
||||
}
|
||||
|
||||
public ITypeReference[] getDerivedReferences() {
|
||||
if (fDerivedSourceRefs != null) {
|
||||
ITypeReference[] refs = new ITypeReference[fDerivedSourceRefsCount];
|
||||
System.arraycopy(fDerivedSourceRefs, 0, refs, 0, fDerivedSourceRefsCount);
|
||||
return refs;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasSubTypes() {
|
||||
return (fDerivedSourceRefs != null);
|
||||
}
|
||||
|
||||
public ITypeInfo[] getSubTypes() {
|
||||
if (fTypeCache != null) {
|
||||
return fTypeCache.getSubtypes(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasSuperTypes() {
|
||||
if (fTypeCache != null) {
|
||||
return (fTypeCache.getSupertypes(this) != null);
|
||||
}
|
||||
return false;
|
||||
// return true; //TODO can't know this until we parse
|
||||
}
|
||||
|
||||
public ITypeInfo[] getSuperTypes() {
|
||||
if (fTypeCache != null) {
|
||||
return fTypeCache.getSupertypes(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ASTAccessVisibility getSuperTypeAccess(ITypeInfo superType) {
|
||||
if (fTypeCache != null) {
|
||||
return fTypeCache.getSupertypeAccess(this, superType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isClass() {
|
||||
return (fElementType == ICElement.C_CLASS
|
||||
|| fElementType == ICElement.C_STRUCT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Created on Jul 5, 2004
|
||||
*
|
||||
* TODO To change the template for this generated file go to
|
||||
* Window - Preferences - Java - Code Style - Code Templates
|
||||
*/
|
||||
package org.eclipse.cdt.core.browser;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.Flags;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICElementVisitor;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.model.IMember;
|
||||
import org.eclipse.cdt.core.model.IMethodDeclaration;
|
||||
import org.eclipse.cdt.core.model.IParent;
|
||||
import org.eclipse.cdt.core.model.IStructure;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
|
||||
import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
|
||||
import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
|
||||
/**
|
||||
* @author CWiebe
|
||||
*
|
||||
* TODO To change the template for this generated type comment go to
|
||||
* Window - Preferences - Java - Code Style - Code Templates
|
||||
*/
|
||||
public class TypeUtil {
|
||||
|
||||
public static ICElement getDeclaringType(ICElement type) {
|
||||
ICElement parentElement = type.getParent();
|
||||
if (parentElement != null && isClassOrStruct(parentElement)) {
|
||||
return parentElement;
|
||||
}
|
||||
|
||||
if (isClassOrStruct(type)) {
|
||||
while (parentElement != null) {
|
||||
if (isClassOrStruct(parentElement)) {
|
||||
return parentElement;
|
||||
} else if (parentElement instanceof IMember) {
|
||||
parentElement = parentElement.getParent();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isClassOrStruct(ICElement type) {
|
||||
int kind = type.getElementType();
|
||||
// case ICElement.C_TEMPLATE_CLASS:
|
||||
// case ICElement.C_TEMPLATE_STRUCT:
|
||||
return (kind == ICElement.C_CLASS || kind == ICElement.C_STRUCT);
|
||||
}
|
||||
|
||||
public static boolean isClass(ICElement type) {
|
||||
return (type.getElementType() == ICElement.C_CLASS);
|
||||
}
|
||||
|
||||
public static boolean isNamespace(ICElement type) {
|
||||
return (type.getElementType() == ICElement.C_NAMESPACE);
|
||||
}
|
||||
|
||||
public static ICElement[] getTypes(ICElement elem) {
|
||||
final List typeList = new ArrayList(3);
|
||||
try {
|
||||
elem.accept(new ICElementVisitor() {
|
||||
public boolean visit(ICElement element) throws CoreException {
|
||||
// TODO Auto-generated method stub
|
||||
if (element instanceof IStructure) {
|
||||
typeList.add(element);
|
||||
}
|
||||
return false;
|
||||
}});
|
||||
} catch (CoreException e) {
|
||||
}
|
||||
return (ICElement[])typeList.toArray(new ICElement[typeList.size()]);
|
||||
}
|
||||
|
||||
public static IQualifiedTypeName getFullyQualifiedName(ICElement type) {
|
||||
String name = type.getElementName();
|
||||
IQualifiedTypeName qualifiedName = new QualifiedTypeName(name);
|
||||
ICElement parent = type.getParent();
|
||||
while (parent != null && (isNamespace(parent) || isClass(parent))) {
|
||||
qualifiedName = new QualifiedTypeName(parent.getElementName()).append(qualifiedName);
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
public static ITypeInfo getTypeForElement(ICElement elem, IProgressMonitor monitor) {
|
||||
if (elem != null) {
|
||||
ICProject cProject = elem.getCProject();
|
||||
IQualifiedTypeName qualifiedName = getFullyQualifiedName(elem);
|
||||
if (qualifiedName != null) {
|
||||
final ITypeSearchScope fScope = new TypeSearchScope(true);
|
||||
if (!AllTypesCache.isCacheUpToDate(fScope)) {
|
||||
AllTypesCache.updateCache(fScope, monitor);
|
||||
}
|
||||
|
||||
ITypeCache cache = TypeCacheManager.getInstance().getCache(cProject.getProject());
|
||||
ITypeInfo info = cache.getType(elem.getElementType(), qualifiedName);
|
||||
if (info != null) {
|
||||
ITypeReference ref = info.getResolvedReference();
|
||||
if (ref == null) {
|
||||
ref = AllTypesCache.resolveTypeLocation(info, monitor);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ITypeInfo getTypeForElement(ICElement elem) {
|
||||
return getTypeForElement(elem, new NullProgressMonitor());
|
||||
}
|
||||
|
||||
public static ICElement getElementForType(ITypeInfo type, IProgressMonitor monitor) {
|
||||
final ITypeSearchScope fScope = new TypeSearchScope(true);
|
||||
if (!AllTypesCache.isCacheUpToDate(fScope)) {
|
||||
AllTypesCache.updateCache(fScope, monitor);
|
||||
}
|
||||
ITypeReference ref = type.getResolvedReference();
|
||||
if (ref == null) {
|
||||
ref = AllTypesCache.resolveTypeLocation(type, monitor);
|
||||
}
|
||||
if (ref != null) {
|
||||
ICElement[] elems = ref.getCElements();
|
||||
if (elems != null && elems.length > 0) {
|
||||
if (elems.length == 1)
|
||||
return elems[0];
|
||||
|
||||
for (int i = 0; i < elems.length; ++i) {
|
||||
ICElement elem = elems[i];
|
||||
if (elem.getElementType() == type.getCElementType() && elem.getElementName().equals(type.getName())) {
|
||||
//TODO should check fully qualified name
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static ICElement getElementForType(ITypeInfo type) {
|
||||
return getElementForType(type, new NullProgressMonitor());
|
||||
}
|
||||
|
||||
public static IMethodDeclaration[] getMethods(ICElement elem) {
|
||||
if (elem instanceof IStructure) {
|
||||
try {
|
||||
List list = ((IParent)elem).getChildrenOfType(ICElement.C_METHOD_DECLARATION);
|
||||
if (list != null && !list.isEmpty()) {
|
||||
return (IMethodDeclaration[]) list.toArray(new IMethodDeclaration[list.size()]);
|
||||
}
|
||||
} catch (CModelException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ICElement[] getFields(ICElement elem) {
|
||||
if (elem instanceof IStructure) {
|
||||
try {
|
||||
List list = ((IParent)elem).getChildrenOfType(ICElement.C_FIELD);
|
||||
if (list != null && !list.isEmpty()) {
|
||||
return (ICElement[]) list.toArray(new ICElement[list.size()]);
|
||||
}
|
||||
} catch (CModelException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds a method by name.
|
||||
* This searches for a method with a name and signature. Parameter types are only
|
||||
* compared by the simple name, no resolving for the fully qualified type name is done.
|
||||
* Constructors are only compared by parameters, not the name.
|
||||
* @param name The name of the method to find
|
||||
* @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
|
||||
* @param isConstructor If the method is a constructor
|
||||
* @param methods The methods to search in
|
||||
* @return The found method or <code>null</code>, if nothing found
|
||||
*/
|
||||
// TODO move methods to CModelUtil
|
||||
public static IMethodDeclaration findMethod(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, IMethodDeclaration[] methods) throws CModelException {
|
||||
for (int i= methods.length - 1; i >= 0; i--) {
|
||||
if (isSameMethodSignature(name, paramTypes, isConstructor, isDestructor, methods[i])) {
|
||||
return methods[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a method equals to the given signature.
|
||||
* Parameter types are only compared by the simple name, no resolving for
|
||||
* the fully qualified type name is done. Constructors are only compared by
|
||||
* parameters, not the name.
|
||||
* @param name Name of the method
|
||||
* @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
|
||||
* @param isConstructor Specifies if the method is a constructor
|
||||
* @return Returns <code>true</code> if the method has the given name and parameter types and constructor state.
|
||||
*/
|
||||
//TODO move methods to CModelUtil
|
||||
public static boolean isSameMethodSignature(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, IMethodDeclaration curr) throws CModelException {
|
||||
if (isConstructor || isDestructor || name.equals(curr.getElementName())) {
|
||||
if ((isConstructor == curr.isConstructor()) && (isDestructor == curr.isDestructor())) {
|
||||
String[] currParamTypes= curr.getParameterTypes();
|
||||
if (paramTypes.length == currParamTypes.length) {
|
||||
for (int i= 0; i < paramTypes.length; i++) {
|
||||
String t1= Signature.getSimpleName(Signature.toString(paramTypes[i]));
|
||||
String t2= Signature.getSimpleName(Signature.toString(currParamTypes[i]));
|
||||
if (!t1.equals(t2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a method in a type.
|
||||
* This searches for a method with the same name and signature. Parameter types are only
|
||||
* compared by the simple name, no resolving for the fully qualified type name is done.
|
||||
* Constructors are only compared by parameters, not the name.
|
||||
* @param name The name of the method to find
|
||||
* @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
|
||||
* @param isConstructor If the method is a constructor
|
||||
* @return The first found method or <code>null</code>, if nothing found
|
||||
*/
|
||||
// TODO move methods to CModelUtil
|
||||
public static IMethodDeclaration findMethod(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, ICElement type) throws CModelException {
|
||||
return findMethod(name, paramTypes, isConstructor, isDestructor, getMethods(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a method declararion in a type's hierarchy. The search is top down, so this
|
||||
* returns the first declaration of the method in the hierarchy.
|
||||
* This searches for a method with a name and signature. Parameter types are only
|
||||
* compared by the simple name, no resolving for the fully qualified type name is done.
|
||||
* Constructors are only compared by parameters, not the name.
|
||||
* @param type Searches in this type's supertypes.
|
||||
* @param name The name of the method to find
|
||||
* @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
|
||||
* @param isConstructor If the method is a constructor
|
||||
* @return The first method found or null, if nothing found
|
||||
*/
|
||||
// TODO move methods to CModelUtil
|
||||
public static IMethodDeclaration findMethodDeclarationInHierarchy(ITypeHierarchy hierarchy, ICElement type, String name, String[] paramTypes, boolean isConstructor, boolean isDestructor) throws CModelException {
|
||||
ICElement[] superTypes= hierarchy.getAllSupertypes(type);
|
||||
for (int i= superTypes.length - 1; i >= 0; i--) {
|
||||
IMethodDeclaration first= findMethod(name, paramTypes, isConstructor, isDestructor, superTypes[i]);
|
||||
if (first != null && first.getVisibility() != ASTAccessVisibility.PRIVATE) {
|
||||
// the order getAllSupertypes does make assumptions of the order of inner elements -> search recursivly
|
||||
IMethodDeclaration res= findMethodDeclarationInHierarchy(hierarchy, TypeUtil.getDeclaringType(first), name, paramTypes, isConstructor, isDestructor);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,451 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2004 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.browser.typehierarchy;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.eclipse.cdt.core.browser.TypeUtil;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICElementDelta;
|
||||
import org.eclipse.cdt.core.model.IMember;
|
||||
import org.eclipse.cdt.core.model.IParent;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.internal.core.model.CElement;
|
||||
|
||||
/*
|
||||
* Collects changes (reported through fine-grained deltas) that can affect a type hierarchy.
|
||||
*/
|
||||
public class ChangeCollector {
|
||||
|
||||
/*
|
||||
* A table from ICElements to TypeDeltas
|
||||
*/
|
||||
HashMap changes = new HashMap();
|
||||
|
||||
TypeHierarchy hierarchy;
|
||||
|
||||
public ChangeCollector(TypeHierarchy hierarchy) {
|
||||
this.hierarchy = hierarchy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the children of the given delta to the list of changes.
|
||||
*/
|
||||
private void addAffectedChildren(ICElementDelta delta) throws CModelException {
|
||||
// ICElementDelta[] children = delta.getAffectedChildren();
|
||||
// for (int i = 0, length = children.length; i < length; i++) {
|
||||
// ICElementDelta child = children[i];
|
||||
// ICElement childElement = child.getElement();
|
||||
// switch (childElement.getElementType()) {
|
||||
// case ICElement.IMPORT_CONTAINER:
|
||||
// addChange((IImportContainer)childElement, child);
|
||||
// break;
|
||||
// case ICElement.IMPORT_DECLARATION:
|
||||
// addChange((IImportDeclaration)childElement, child);
|
||||
// break;
|
||||
// case ICElement.TYPE:
|
||||
// addChange((ICElement)childElement, child);
|
||||
// break;
|
||||
// case ICElement.INITIALIZER:
|
||||
// case ICElement.FIELD:
|
||||
// case ICElement.METHOD:
|
||||
// addChange((IMember)childElement, child);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the given delta on a compilation unit to the list of changes.
|
||||
*/
|
||||
public void addChange(ITranslationUnit cu, ICElementDelta newDelta) throws CModelException {
|
||||
// int newKind = newDelta.getKind();
|
||||
// switch (newKind) {
|
||||
// case ICElementDelta.ADDED:
|
||||
// ArrayList allTypes = new ArrayList();
|
||||
// getAllTypesFromElement(cu, allTypes);
|
||||
// for (int i = 0, length = allTypes.size(); i < length; i++) {
|
||||
// ICElement type = (ICElement)allTypes.get(i);
|
||||
// addTypeAddition(type, (SimpleDelta)this.changes.get(type));
|
||||
// }
|
||||
// break;
|
||||
// case ICElementDelta.REMOVED:
|
||||
// allTypes = new ArrayList();
|
||||
// getAllTypesFromHierarchy((JavaElement)cu, allTypes);
|
||||
// for (int i = 0, length = allTypes.size(); i < length; i++) {
|
||||
// ICElement type = (ICElement)allTypes.get(i);
|
||||
// addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
|
||||
// }
|
||||
// break;
|
||||
// case ICElementDelta.CHANGED:
|
||||
// addAffectedChildren(newDelta);
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
/* private void addChange(IImportContainer importContainer, ICElementDelta newDelta) throws CModelException {
|
||||
int newKind = newDelta.getKind();
|
||||
if (newKind == ICElementDelta.CHANGED) {
|
||||
addAffectedChildren(newDelta);
|
||||
return;
|
||||
}
|
||||
SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importContainer);
|
||||
if (existingDelta != null) {
|
||||
switch (newKind) {
|
||||
case ICElementDelta.ADDED:
|
||||
if (existingDelta.getKind() == ICElementDelta.REMOVED) {
|
||||
// REMOVED then ADDED
|
||||
this.changes.remove(importContainer);
|
||||
}
|
||||
break;
|
||||
case ICElementDelta.REMOVED:
|
||||
if (existingDelta.getKind() == ICElementDelta.ADDED) {
|
||||
// ADDED then REMOVED
|
||||
this.changes.remove(importContainer);
|
||||
}
|
||||
break;
|
||||
// CHANGED handled above
|
||||
}
|
||||
} else {
|
||||
SimpleDelta delta = new SimpleDelta();
|
||||
switch (newKind) {
|
||||
case ICElementDelta.ADDED:
|
||||
delta.added();
|
||||
break;
|
||||
case ICElementDelta.REMOVED:
|
||||
delta.removed();
|
||||
break;
|
||||
}
|
||||
this.changes.put(importContainer, delta);
|
||||
}
|
||||
}
|
||||
|
||||
private void addChange(IImportDeclaration importDecl, ICElementDelta newDelta) {
|
||||
SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importDecl);
|
||||
int newKind = newDelta.getKind();
|
||||
if (existingDelta != null) {
|
||||
switch (newKind) {
|
||||
case ICElementDelta.ADDED:
|
||||
if (existingDelta.getKind() == ICElementDelta.REMOVED) {
|
||||
// REMOVED then ADDED
|
||||
this.changes.remove(importDecl);
|
||||
}
|
||||
break;
|
||||
case ICElementDelta.REMOVED:
|
||||
if (existingDelta.getKind() == ICElementDelta.ADDED) {
|
||||
// ADDED then REMOVED
|
||||
this.changes.remove(importDecl);
|
||||
}
|
||||
break;
|
||||
// CHANGED cannot happen for import declaration
|
||||
}
|
||||
} else {
|
||||
SimpleDelta delta = new SimpleDelta();
|
||||
switch (newKind) {
|
||||
case ICElementDelta.ADDED:
|
||||
delta.added();
|
||||
break;
|
||||
case ICElementDelta.REMOVED:
|
||||
delta.removed();
|
||||
break;
|
||||
}
|
||||
this.changes.put(importDecl, delta);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adds a change for the given member (a method, a field or an initializer) and the types it defines.
|
||||
*/
|
||||
private void addChange(IMember member, ICElementDelta newDelta) throws CModelException {
|
||||
// int newKind = newDelta.getKind();
|
||||
// switch (newKind) {
|
||||
// case ICElementDelta.ADDED:
|
||||
// ArrayList allTypes = new ArrayList();
|
||||
// getAllTypesFromElement(member, allTypes);
|
||||
// for (int i = 0, length = allTypes.size(); i < length; i++) {
|
||||
// ICElement innerType = (ICElement)allTypes.get(i);
|
||||
// addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
|
||||
// }
|
||||
// break;
|
||||
// case ICElementDelta.REMOVED:
|
||||
// allTypes = new ArrayList();
|
||||
// getAllTypesFromHierarchy((JavaElement)member, allTypes);
|
||||
// for (int i = 0, length = allTypes.size(); i < length; i++) {
|
||||
// ICElement type = (ICElement)allTypes.get(i);
|
||||
// addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
|
||||
// }
|
||||
// break;
|
||||
// case ICElementDelta.CHANGED:
|
||||
// addAffectedChildren(newDelta);
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a change for the given type and the types it defines.
|
||||
*/
|
||||
private void addChange(ICElement type, ICElementDelta newDelta) throws CModelException {
|
||||
// int newKind = newDelta.getKind();
|
||||
// SimpleDelta existingDelta = (SimpleDelta)this.changes.get(type);
|
||||
// switch (newKind) {
|
||||
// case ICElementDelta.ADDED:
|
||||
// addTypeAddition(type, existingDelta);
|
||||
// ArrayList allTypes = new ArrayList();
|
||||
// getAllTypesFromElement(type, allTypes);
|
||||
// for (int i = 0, length = allTypes.size(); i < length; i++) {
|
||||
// ICElement innerType = (ICElement)allTypes.get(i);
|
||||
// addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
|
||||
// }
|
||||
// break;
|
||||
// case ICElementDelta.REMOVED:
|
||||
// addTypeRemoval(type, existingDelta);
|
||||
// allTypes = new ArrayList();
|
||||
// getAllTypesFromHierarchy((JavaElement)type, allTypes);
|
||||
// for (int i = 0, length = allTypes.size(); i < length; i++) {
|
||||
// ICElement innerType = (ICElement)allTypes.get(i);
|
||||
// addTypeRemoval(innerType, (SimpleDelta)this.changes.get(innerType));
|
||||
// }
|
||||
// break;
|
||||
// case ICElementDelta.CHANGED:
|
||||
// addTypeChange(type, newDelta.getFlags(), existingDelta);
|
||||
// addAffectedChildren(newDelta);
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
/* private void addTypeAddition(ICElement type, SimpleDelta existingDelta) throws CModelException {
|
||||
if (existingDelta != null) {
|
||||
switch (existingDelta.getKind()) {
|
||||
case ICElementDelta.REMOVED:
|
||||
// REMOVED then ADDED
|
||||
boolean hasChange = false;
|
||||
if (hasSuperTypeChange(type)) {
|
||||
existingDelta.superTypes();
|
||||
hasChange = true;
|
||||
}
|
||||
if (hasVisibilityChange(type)) {
|
||||
existingDelta.modifiers();
|
||||
hasChange = true;
|
||||
}
|
||||
if (!hasChange) {
|
||||
this.changes.remove(type);
|
||||
}
|
||||
break;
|
||||
// CHANGED then ADDED
|
||||
// or ADDED then ADDED: should not happen
|
||||
}
|
||||
} else {
|
||||
// check whether the type addition affects the hierarchy
|
||||
String typeName = type.getElementName();
|
||||
if (this.hierarchy.hasSupertype(typeName)
|
||||
|| this.hierarchy.subtypesIncludeSupertypeOf(type)
|
||||
|| this.hierarchy.missingTypes.contains(typeName)) {
|
||||
SimpleDelta delta = new SimpleDelta();
|
||||
delta.added();
|
||||
this.changes.put(type, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* private void addTypeChange(ICElement type, int newFlags, SimpleDelta existingDelta) throws CModelException {
|
||||
if (existingDelta != null) {
|
||||
switch (existingDelta.getKind()) {
|
||||
case ICElementDelta.CHANGED:
|
||||
// CHANGED then CHANGED
|
||||
int existingFlags = existingDelta.getFlags();
|
||||
boolean hasChange = false;
|
||||
if ((existingFlags & ICElementDelta.F_SUPER_TYPES) != 0
|
||||
&& hasSuperTypeChange(type)) {
|
||||
existingDelta.superTypes();
|
||||
hasChange = true;
|
||||
}
|
||||
if ((existingFlags & ICElementDelta.F_MODIFIERS) != 0
|
||||
&& hasVisibilityChange(type)) {
|
||||
existingDelta.modifiers();
|
||||
hasChange = true;
|
||||
}
|
||||
if (!hasChange) {
|
||||
// super types and visibility are back to the ones in the existing hierarchy
|
||||
this.changes.remove(type);
|
||||
}
|
||||
break;
|
||||
// ADDED then CHANGED: leave it as ADDED
|
||||
// REMOVED then CHANGED: should not happen
|
||||
}
|
||||
} else {
|
||||
// check whether the type change affects the hierarchy
|
||||
SimpleDelta typeDelta = null;
|
||||
if ((newFlags & ICElementDelta.F_SUPER_TYPES) != 0
|
||||
&& this.hierarchy.includesTypeOrSupertype(type)) {
|
||||
typeDelta = new SimpleDelta();
|
||||
typeDelta.superTypes();
|
||||
}
|
||||
if ((newFlags & ICElementDelta.F_MODIFIERS) != 0
|
||||
&& this.hierarchy.hasSupertype(type.getElementName())) {
|
||||
if (typeDelta == null) {
|
||||
typeDelta = new SimpleDelta();
|
||||
}
|
||||
typeDelta.modifiers();
|
||||
}
|
||||
if (typeDelta != null) {
|
||||
this.changes.put(type, typeDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* private void addTypeRemoval(ICElement type, SimpleDelta existingDelta) {
|
||||
if (existingDelta != null) {
|
||||
switch (existingDelta.getKind()) {
|
||||
case ICElementDelta.ADDED:
|
||||
// ADDED then REMOVED
|
||||
this.changes.remove(type);
|
||||
break;
|
||||
case ICElementDelta.CHANGED:
|
||||
// CHANGED then REMOVED
|
||||
existingDelta.removed();
|
||||
break;
|
||||
// REMOVED then REMOVED: should not happen
|
||||
}
|
||||
} else {
|
||||
// check whether the type removal affects the hierarchy
|
||||
if (this.hierarchy.contains(type)) {
|
||||
SimpleDelta typeDelta = new SimpleDelta();
|
||||
typeDelta.removed();
|
||||
this.changes.put(type, typeDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
* Returns all types defined in the given element excluding the given element.
|
||||
*/
|
||||
private void getAllTypesFromElement(ICElement element, ArrayList allTypes) throws CModelException {
|
||||
switch (element.getElementType()) {
|
||||
case ICElement.C_UNIT:
|
||||
ICElement[] types = TypeUtil.getTypes((ITranslationUnit)element);
|
||||
for (int i = 0, length = types.length; i < length; i++) {
|
||||
ICElement type = types[i];
|
||||
allTypes.add(type);
|
||||
getAllTypesFromElement(type, allTypes);
|
||||
}
|
||||
break;
|
||||
case ICElement.C_CLASS:
|
||||
case ICElement.C_STRUCT:
|
||||
// types = ((ICElement)element).getTypes();
|
||||
types = TypeUtil.getTypes((ICElement)element);
|
||||
for (int i = 0, length = types.length; i < length; i++) {
|
||||
ICElement type = types[i];
|
||||
allTypes.add(type);
|
||||
getAllTypesFromElement(type, allTypes);
|
||||
}
|
||||
break;
|
||||
// case ICElement.INITIALIZER:
|
||||
// case ICElement.FIELD:
|
||||
case ICElement.C_METHOD:
|
||||
if (element instanceof IParent) {
|
||||
ICElement[] children = ((IParent)element).getChildren();
|
||||
for (int i = 0, length = children.length; i < length; i++) {
|
||||
ICElement type = (ICElement)children[i];
|
||||
allTypes.add(type);
|
||||
getAllTypesFromElement(type, allTypes);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns all types in the existing hierarchy that have the given element as a parent.
|
||||
*/
|
||||
private void getAllTypesFromHierarchy(CElement element, ArrayList allTypes) {
|
||||
switch (element.getElementType()) {
|
||||
case ICElement.C_UNIT:
|
||||
ArrayList types = (ArrayList)this.hierarchy.files.get(element);
|
||||
if (types != null) {
|
||||
allTypes.addAll(types);
|
||||
}
|
||||
break;
|
||||
case ICElement.C_CLASS:
|
||||
case ICElement.C_STRUCT:
|
||||
// case ICElement.INITIALIZER:
|
||||
// case ICElement.FIELD:
|
||||
case ICElement.C_METHOD:
|
||||
types = (ArrayList)this.hierarchy.files.get(((IMember)element).getTranslationUnit());
|
||||
if (types != null) {
|
||||
for (int i = 0, length = types.size(); i < length; i++) {
|
||||
ICElement type = (ICElement)types.get(i);
|
||||
if (element.isAncestorOf(type)) {
|
||||
allTypes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSuperTypeChange(ICElement type) throws CModelException {
|
||||
// // check super class
|
||||
// ICElement superclass = this.hierarchy.getSuperclass(type);
|
||||
// String existingSuperclassName = superclass == null ? null : superclass.getElementName();
|
||||
// String newSuperclassName = type.getSuperclassName();
|
||||
// if (existingSuperclassName != null && !existingSuperclassName.equals(newSuperclassName)) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// // check super interfaces
|
||||
// ICElement[] existingSuperInterfaces = this.hierarchy.getSuperInterfaces(type);
|
||||
// String[] newSuperInterfaces = type.getSuperInterfaceNames();
|
||||
// if (existingSuperInterfaces.length != newSuperInterfaces.length) {
|
||||
// return true;
|
||||
// }
|
||||
// for (int i = 0, length = newSuperInterfaces.length; i < length; i++) {
|
||||
// String superInterfaceName = newSuperInterfaces[i];
|
||||
// if (!superInterfaceName.equals(newSuperInterfaces[i])) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasVisibilityChange(ICElement type) throws CModelException {
|
||||
// int existingFlags = this.hierarchy.getCachedFlags(type);
|
||||
// int newFlags = type.getFlags();
|
||||
// return existingFlags != newFlags;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether the hierarchy needs refresh according to the changes collected so far.
|
||||
*/
|
||||
public boolean needsRefresh() {
|
||||
return changes.size() != 0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
Iterator iterator = this.changes.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry)iterator.next();
|
||||
buffer.append(((CElement)entry.getKey()).toDebugString());
|
||||
buffer.append(entry.getValue());
|
||||
if (iterator.hasNext()) {
|
||||
buffer.append('\n');
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2004 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.browser.typehierarchy;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
/**
|
||||
* A type hierarchy provides navigations between a type and its resolved
|
||||
* supertypes and subtypes for a specific type or for all types within a region.
|
||||
* Supertypes may extend outside of the type hierarchy's region in which it was
|
||||
* created such that the root of the hierarchy is always included. For example, if a type
|
||||
* hierarchy is created for a <code>java.io.File</code>, and the region the hierarchy was
|
||||
* created in is the package fragment <code>java.io</code>, the supertype
|
||||
* <code>java.lang.Object</code> will still be included.
|
||||
* <p>
|
||||
* A type hierarchy is static and can become stale. Although consistent when
|
||||
* created, it does not automatically track changes in the model.
|
||||
* As changes in the model potentially invalidate the hierarchy, change notifications
|
||||
* are sent to registered <code>ICElementHierarchyChangedListener</code>s. Listeners should
|
||||
* use the <code>exists</code> method to determine if the hierarchy has become completely
|
||||
* invalid (for example, when the type or project the hierarchy was created on
|
||||
* has been removed). To refresh a hierarchy, use the <code>refresh</code> method.
|
||||
* </p>
|
||||
* <p>
|
||||
* The type hierarchy may contain cycles due to malformed supertype declarations.
|
||||
* Most type hierarchy queries are oblivious to cycles; the <code>getAll* </code>
|
||||
* methods are implemented such that they are unaffected by cycles.
|
||||
* </p>
|
||||
* <p>
|
||||
* This interface is not intended to be implemented by clients.
|
||||
* </p>
|
||||
*/
|
||||
public interface ITypeHierarchy {
|
||||
/**
|
||||
* Adds the given listener for changes to this type hierarchy. Listeners are
|
||||
* notified when this type hierarchy changes and needs to be refreshed.
|
||||
* Has no effect if an identical listener is already registered.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
|
||||
/**
|
||||
* Returns whether the given type is part of this hierarchy.
|
||||
*
|
||||
* @param type the given type
|
||||
* @return true if the given type is part of this hierarchy, false otherwise
|
||||
*/
|
||||
boolean contains(ICElement type);
|
||||
/**
|
||||
* Returns whether the type and project this hierarchy was created on exist.
|
||||
* @return true if the type and project this hierarchy was created on exist, false otherwise
|
||||
*/
|
||||
boolean exists();
|
||||
|
||||
/**
|
||||
* Returns all resolved subtypes (direct and indirect) of the
|
||||
* given type, in no particular order, limited to the
|
||||
* types in this type hierarchy's graph. An empty array
|
||||
* is returned if there are no resolved subtypes for the
|
||||
* given type.
|
||||
*
|
||||
* @param type the given type
|
||||
* @return all resolved subtypes (direct and indirect) of the given type
|
||||
*/
|
||||
ICElement[] getAllSubtypes(ICElement type);
|
||||
/**
|
||||
* Returns all resolved superclasses of the
|
||||
* given class, in bottom-up order. An empty array
|
||||
* is returned if there are no resolved superclasses for the
|
||||
* given class.
|
||||
*
|
||||
* <p>NOTE: once a type hierarchy has been created, it is more efficient to
|
||||
* query the hierarchy for superclasses than to query a class recursively up
|
||||
* the superclass chain. Querying an element performs a dynamic resolution,
|
||||
* whereas the hierarchy returns a pre-computed result.
|
||||
*
|
||||
* @param type the given type
|
||||
* @return all resolved superclasses of the given class, in bottom-up order, an empty
|
||||
* array if none.
|
||||
*/
|
||||
ICElement[] getAllSupertypes(ICElement type);
|
||||
|
||||
/**
|
||||
* Returns all classes in the graph which have no resolved superclass,
|
||||
* in no particular order.
|
||||
*
|
||||
* @return all classes in the graph which have no resolved superclass
|
||||
*/
|
||||
ICElement[] getRootClasses();
|
||||
|
||||
/**
|
||||
* Returns the direct resolved subtypes of the given type,
|
||||
* in no particular order, limited to the types in this
|
||||
* type hierarchy's graph.
|
||||
* If the type is a class, this returns the resolved subclasses.
|
||||
* If the type is an interface, this returns both the classes which implement
|
||||
* the interface and the interfaces which extend it.
|
||||
*
|
||||
* @param type the given type
|
||||
* @return the direct resolved subtypes of the given type limited to the types in this
|
||||
* type hierarchy's graph
|
||||
*/
|
||||
ICElement[] getSubtypes(ICElement type);
|
||||
|
||||
/**
|
||||
* Returns the resolved supertypes of the given type,
|
||||
* in no particular order, limited to the types in this
|
||||
* type hierarchy's graph.
|
||||
* For classes, this returns its superclass and the interfaces that the class implements.
|
||||
* For interfaces, this returns the interfaces that the interface extends. As a consequence
|
||||
* <code>java.lang.Object</code> is NOT considered to be a supertype of any interface
|
||||
* type.
|
||||
*
|
||||
* @param type the given type
|
||||
* @return the resolved supertypes of the given type limited to the types in this
|
||||
* type hierarchy's graph
|
||||
*/
|
||||
ICElement[] getSupertypes(ICElement type);
|
||||
/**
|
||||
* Returns the type this hierarchy was computed for.
|
||||
* Returns <code>null</code> if this hierarchy was computed for a region.
|
||||
*
|
||||
* @return the type this hierarchy was computed for
|
||||
*/
|
||||
ICElement getType();
|
||||
/**
|
||||
* Re-computes the type hierarchy reporting progress.
|
||||
*
|
||||
* @param monitor the given progress monitor
|
||||
* @exception JavaModelException if unable to refresh the hierarchy
|
||||
*/
|
||||
void refresh(IProgressMonitor monitor) throws CModelException;
|
||||
/**
|
||||
* Removes the given listener from this type hierarchy.
|
||||
* Has no affect if an identical listener is not registered.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
|
||||
/**
|
||||
* Stores the type hierarchy in an output stream. This stored hierarchy can be load by
|
||||
* ICElement#loadTypeHierachy(IJavaProject, InputStream, IProgressMonitor).
|
||||
* Listeners of this hierarchy are not stored.
|
||||
*
|
||||
* Only hierarchies created by the following methods can be store:
|
||||
* <ul>
|
||||
* <li>ICElement#newSupertypeHierarchy(IProgressMonitor)</li>
|
||||
* <li>ICElement#newTypeHierarchy(IJavaProject, IProgressMonitor)</li>
|
||||
* <li>ICElement#newTypeHierarchy(IProgressMonitor)</li>
|
||||
* </u>
|
||||
*
|
||||
* @param outputStream output stream where the hierarchy will be stored
|
||||
* @param monitor the given progress monitor
|
||||
* @exception JavaModelException if unable to store the hierarchy in the ouput stream
|
||||
* @see ICElement#loadTypeHierachy(java.io.InputStream, IProgressMonitor)
|
||||
* @since 2.1
|
||||
*/
|
||||
void store(OutputStream outputStream, IProgressMonitor monitor) throws CModelException;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2004 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.browser.typehierarchy;
|
||||
|
||||
/**
|
||||
* A listener which gets notified when a particular type hierarchy object
|
||||
* changes.
|
||||
* <p>
|
||||
* This interface may be implemented by clients.
|
||||
* </p>
|
||||
*/
|
||||
public interface ITypeHierarchyChangedListener {
|
||||
/**
|
||||
* Notifies that the given type hierarchy has changed in some way and should
|
||||
* be refreshed at some point to make it consistent with the current state of
|
||||
* the Java model.
|
||||
*
|
||||
* @param typeHierarchy the given type hierarchy
|
||||
*/
|
||||
void typeHierarchyChanged(ITypeHierarchy typeHierarchy);
|
||||
}
|
|
@ -0,0 +1,591 @@
|
|||
/*******************************************************************************
|
||||
* 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.typehierarchy;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.ICLogConstants;
|
||||
import org.eclipse.cdt.core.browser.AllTypesCache;
|
||||
import org.eclipse.cdt.core.browser.ITypeInfo;
|
||||
import org.eclipse.cdt.core.browser.TypeUtil;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.ElementChangedEvent;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICElementDelta;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.model.IElementChangedListener;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
|
||||
import org.eclipse.cdt.core.search.ICSearchScope;
|
||||
import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
|
||||
import org.eclipse.cdt.internal.core.model.CElement;
|
||||
import org.eclipse.cdt.internal.core.model.Util;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.ISafeRunnable;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
|
||||
public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener {
|
||||
|
||||
public static boolean DEBUG = false;
|
||||
|
||||
private static final class TypeEntry {
|
||||
ITypeInfo type;
|
||||
ASTAccessVisibility access;
|
||||
TypeEntry(ITypeInfo type, ASTAccessVisibility access) {
|
||||
this.type = type;
|
||||
this.access = access;
|
||||
}
|
||||
}
|
||||
private static final int INITIAL_SUPER_TYPES = 1;
|
||||
private static final int INITIAL_SUB_TYPES = 1;
|
||||
private static final ITypeInfo[] NO_TYPES = new ITypeInfo[0];
|
||||
private ArrayList fAllTypes = new ArrayList();
|
||||
private ArrayList fRootTypes = new ArrayList();
|
||||
private Map fTypeToSuperTypes = new HashMap();
|
||||
private Map fTypeToSubTypes = new HashMap();
|
||||
|
||||
private ITypeInfo fFocusType;
|
||||
|
||||
/**
|
||||
* The progress monitor to report work completed too.
|
||||
*/
|
||||
protected IProgressMonitor fProgressMonitor = null;
|
||||
/**
|
||||
* Change listeners - null if no one is listening.
|
||||
*/
|
||||
protected ArrayList fChangeListeners = null;
|
||||
|
||||
/*
|
||||
* A map from Openables to ArrayLists of ITypes
|
||||
*/
|
||||
public Map files = null;
|
||||
|
||||
/**
|
||||
* Whether this hierarchy should contains subtypes.
|
||||
*/
|
||||
protected boolean fComputeSubtypes;
|
||||
|
||||
/**
|
||||
* The scope this hierarchy should restrain itsef in.
|
||||
*/
|
||||
ICSearchScope fScope;
|
||||
|
||||
/*
|
||||
* Whether this hierarchy needs refresh
|
||||
*/
|
||||
public boolean fNeedsRefresh = true;
|
||||
/*
|
||||
* Collects changes to types
|
||||
*/
|
||||
protected ChangeCollector fChangeCollector;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TypeHierarchy on the given type.
|
||||
*/
|
||||
public TypeHierarchy(ITypeInfo type) {
|
||||
fFocusType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the type to the collection of root classes
|
||||
* if the classes is not already present in the collection.
|
||||
*/
|
||||
public void addRootType(ITypeInfo type) {
|
||||
if (!fRootTypes.contains(type)) {
|
||||
fRootTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given supertype to the type.
|
||||
*/
|
||||
public void addSuperType(ITypeInfo type, ITypeInfo superType, ASTAccessVisibility access) {
|
||||
Collection superEntries = (Collection) fTypeToSuperTypes.get(type);
|
||||
if (superEntries == null) {
|
||||
superEntries = new ArrayList(INITIAL_SUPER_TYPES);
|
||||
fTypeToSuperTypes.put(type, superEntries);
|
||||
}
|
||||
Collection subTypes = (Collection) fTypeToSubTypes.get(superType);
|
||||
if (subTypes == null) {
|
||||
subTypes = new ArrayList(INITIAL_SUB_TYPES);
|
||||
fTypeToSubTypes.put(superType, subTypes);
|
||||
}
|
||||
if (!subTypes.contains(type)) {
|
||||
subTypes.add(type);
|
||||
}
|
||||
for (Iterator i = superEntries.iterator(); i.hasNext(); ) {
|
||||
TypeEntry entry = (TypeEntry)i.next();
|
||||
if (entry.type.equals(superType)) {
|
||||
// update the access
|
||||
entry.access = access;
|
||||
return; // don't add if already exists
|
||||
}
|
||||
}
|
||||
TypeEntry typeEntry = new TypeEntry(superType, access);
|
||||
superEntries.add(typeEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given subtype to the type.
|
||||
*/
|
||||
protected void addSubType(ITypeInfo type, ITypeInfo subType) {
|
||||
Collection subTypes = (Collection) fTypeToSubTypes.get(type);
|
||||
if (subTypes == null) {
|
||||
subTypes = new ArrayList(INITIAL_SUB_TYPES);
|
||||
fTypeToSubTypes.put(type, subTypes);
|
||||
}
|
||||
if (!subTypes.contains(subType)) {
|
||||
subTypes.add(subType);
|
||||
}
|
||||
|
||||
Collection superEntries = (Collection) fTypeToSuperTypes.get(subType);
|
||||
if (superEntries == null) {
|
||||
superEntries = new ArrayList(INITIAL_SUPER_TYPES);
|
||||
fTypeToSuperTypes.put(subType, superEntries);
|
||||
}
|
||||
for (Iterator i = superEntries.iterator(); i.hasNext(); ) {
|
||||
TypeEntry entry = (TypeEntry)i.next();
|
||||
if (entry.type.equals(type))
|
||||
return; // don't add if already exists
|
||||
}
|
||||
// default to private access
|
||||
TypeEntry typeEntry = new TypeEntry(type, ASTAccessVisibility.PRIVATE);
|
||||
superEntries.add(typeEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if type already has the given supertype.
|
||||
*/
|
||||
public boolean hasSuperType(ITypeInfo type, ITypeInfo superType) {
|
||||
Collection entries = (Collection) fTypeToSuperTypes.get(type);
|
||||
if (entries != null) {
|
||||
for (Iterator i = entries.iterator(); i.hasNext(); ) {
|
||||
TypeEntry entry = (TypeEntry)i.next();
|
||||
if (entry.type.equals(superType))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of supertypes for the given type - will never return null.
|
||||
*/
|
||||
public ITypeInfo[] getSuperTypes(ITypeInfo type) {
|
||||
Collection entries = (Collection) fTypeToSuperTypes.get(type);
|
||||
if (entries != null) {
|
||||
ArrayList superTypes = new ArrayList(INITIAL_SUPER_TYPES);
|
||||
for (Iterator i = entries.iterator(); i.hasNext(); ) {
|
||||
TypeEntry entry = (TypeEntry)i.next();
|
||||
superTypes.add(entry.type);
|
||||
}
|
||||
return (ITypeInfo[])superTypes.toArray(new ITypeInfo[superTypes.size()]);
|
||||
}
|
||||
return NO_TYPES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of subtypes for the given type - will never return null.
|
||||
*/
|
||||
public ITypeInfo[] getSubTypes(ITypeInfo type) {
|
||||
Collection subTypes = (Collection) fTypeToSubTypes.get(type);
|
||||
if (subTypes != null) {
|
||||
return (ITypeInfo[])subTypes.toArray(new ITypeInfo[subTypes.size()]);
|
||||
}
|
||||
return NO_TYPES;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#addTypeHierarchyChangedListener(org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchyChangedListener)
|
||||
*/
|
||||
public void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
|
||||
ArrayList listeners = fChangeListeners;
|
||||
if (listeners == null) {
|
||||
fChangeListeners = listeners = new ArrayList();
|
||||
}
|
||||
|
||||
// register with JavaCore to get Java element delta on first listener added
|
||||
if (listeners.size() == 0) {
|
||||
CoreModel.getDefault().addElementChangedListener(this);
|
||||
}
|
||||
|
||||
// add listener only if it is not already present
|
||||
if (listeners.indexOf(listener) == -1) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see ITypeHierarchy
|
||||
*/
|
||||
public synchronized void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
|
||||
ArrayList listeners = fChangeListeners;
|
||||
if (listeners == null) {
|
||||
return;
|
||||
}
|
||||
listeners.remove(listener);
|
||||
|
||||
// deregister from JavaCore on last listener removed
|
||||
if (listeners.isEmpty()) {
|
||||
CoreModel.getDefault().removeElementChangedListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the change effects this hierarchy, and fires
|
||||
* change notification if required.
|
||||
*/
|
||||
public void elementChanged(ElementChangedEvent event) {
|
||||
// type hierarchy change has already been fired
|
||||
if (fNeedsRefresh) return;
|
||||
|
||||
if (isAffected(event.getDelta())) {
|
||||
fNeedsRefresh = true;
|
||||
fireChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given delta could change this type hierarchy
|
||||
*/
|
||||
public synchronized boolean isAffected(ICElementDelta delta) {
|
||||
ICElement element= delta.getElement();
|
||||
// switch (element.getElementType()) {
|
||||
// case ICElement.C_MODEL:
|
||||
// return isAffectedByCModel(delta, element);
|
||||
// case ICElement.C_PROJECT:
|
||||
// return isAffectedByCProject(delta, element);
|
||||
// case ICElement.C_UNIT:
|
||||
// return isAffectedByOpenable(delta, element);
|
||||
// }
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies listeners that this hierarchy has changed and needs
|
||||
* refreshing. Note that listeners can be removed as we iterate
|
||||
* through the list.
|
||||
*/
|
||||
public void fireChange() {
|
||||
ArrayList listeners = fChangeListeners;
|
||||
if (listeners == null) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
System.out.println("FIRING hierarchy change ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
if (fFocusType != null) {
|
||||
System.out.println(" for hierarchy focused on " + fFocusType.toString()); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
// clone so that a listener cannot have a side-effect on this list when being notified
|
||||
listeners = (ArrayList)listeners.clone();
|
||||
for (int i= 0; i < listeners.size(); i++) {
|
||||
final ITypeHierarchyChangedListener listener= (ITypeHierarchyChangedListener)listeners.get(i);
|
||||
Platform.run(new ISafeRunnable() {
|
||||
public void handleException(Throwable exception) {
|
||||
Util.log(exception, "Exception occurred in listener of Type hierarchy change notification", ICLogConstants.CDT); //$NON-NLS-1$
|
||||
}
|
||||
public void run() throws Exception {
|
||||
listener.typeHierarchyChanged(TypeHierarchy.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#contains(org.eclipse.cdt.core.model.ICElement)
|
||||
*/
|
||||
public boolean contains(ICElement type) {
|
||||
// classes
|
||||
ITypeInfo info = AllTypesCache.getTypeForElement(type);
|
||||
|
||||
if (info == null)
|
||||
return false;
|
||||
|
||||
if (fTypeToSuperTypes.get(info) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// root classes
|
||||
if (fRootTypes.contains(type)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ITypeHierarchy
|
||||
*/
|
||||
public boolean exists() {
|
||||
if (!fNeedsRefresh) return true;
|
||||
|
||||
return (fFocusType == null || fFocusType.exists()) && cProject().exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the C project this hierarchy was created in.
|
||||
*/
|
||||
public ICProject cProject() {
|
||||
IProject project = fFocusType.getCache().getProject();
|
||||
return findCProject(project);
|
||||
}
|
||||
private ICProject findCProject(IProject project) {
|
||||
try {
|
||||
ICProject[] cProjects = CoreModel.getDefault().getCModel().getCProjects();
|
||||
if (cProjects != null) {
|
||||
for (int i = 0; i < cProjects.length; ++i) {
|
||||
ICProject cProject = cProjects[i];
|
||||
if (project.equals(cProjects[i].getProject()))
|
||||
return cProject;
|
||||
}
|
||||
}
|
||||
} catch (CModelException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllClasses()
|
||||
*/
|
||||
public ICElement[] getAllClasses() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getRootClasses()
|
||||
*/
|
||||
public ICElement[] getRootClasses() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSubtypes(org.eclipse.cdt.core.model.ICElement)
|
||||
*/
|
||||
public ICElement[] getSubtypes(ICElement type) {
|
||||
List list = new ArrayList();
|
||||
ITypeInfo info = TypeUtil.getTypeForElement(type);
|
||||
Collection entries = (Collection) fTypeToSubTypes.get(info);
|
||||
if (entries != null) {
|
||||
for (Iterator i = entries.iterator(); i.hasNext(); ) {
|
||||
ITypeInfo subType = (ITypeInfo)i.next();
|
||||
ICElement elem = TypeUtil.getElementForType(subType);
|
||||
if (elem != null) {
|
||||
list.add(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ICElement[])list.toArray(new ICElement[list.size()]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement)
|
||||
*/
|
||||
public ICElement[] getAllSubtypes(ICElement type) {
|
||||
List list = new ArrayList();
|
||||
ITypeInfo info = TypeUtil.getTypeForElement(type);
|
||||
addSubs(info, list);
|
||||
//convert list to ICElements
|
||||
ICElement[] elems = new ICElement[list.size()];
|
||||
int count = 0;
|
||||
for (Iterator i = list.iterator(); i.hasNext(); ) {
|
||||
ITypeInfo subType = (ITypeInfo) i.next();
|
||||
elems[count++] = TypeUtil.getElementForType(subType);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
private void addSubs(ITypeInfo type, List list) {
|
||||
Collection entries = (Collection) fTypeToSubTypes.get(type);
|
||||
if (entries != null) {
|
||||
for (Iterator i = entries.iterator(); i.hasNext(); ) {
|
||||
ITypeInfo subType = (ITypeInfo)i.next();
|
||||
if (!list.contains(subType)) {
|
||||
list.add(subType);
|
||||
}
|
||||
addSubs(subType, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSupertypes(org.eclipse.cdt.core.model.ICElement)
|
||||
*/
|
||||
public ICElement[] getSupertypes(ICElement type) {
|
||||
List list = new ArrayList();
|
||||
ITypeInfo info = TypeUtil.getTypeForElement(type);
|
||||
Collection entries = (Collection) fTypeToSuperTypes.get(info);
|
||||
if (entries != null) {
|
||||
for (Iterator i = entries.iterator(); i.hasNext(); ) {
|
||||
TypeEntry entry = (TypeEntry)i.next();
|
||||
ITypeInfo superType = entry.type;
|
||||
ICElement elem = TypeUtil.getElementForType(superType);
|
||||
if (elem != null) {
|
||||
list.add(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ICElement[])list.toArray(new ICElement[list.size()]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement)
|
||||
*/
|
||||
public ICElement[] getAllSupertypes(ICElement type) {
|
||||
List list = new ArrayList();
|
||||
ITypeInfo info = TypeUtil.getTypeForElement(type);
|
||||
addSupers(info, list);
|
||||
//convert list to ICElements
|
||||
ICElement[] elems = new ICElement[list.size()];
|
||||
int count = 0;
|
||||
for (Iterator i = list.iterator(); i.hasNext(); ) {
|
||||
ITypeInfo superType = (ITypeInfo) i.next();
|
||||
elems[count++] = TypeUtil.getElementForType(superType);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
private void addSupers(ITypeInfo type, List list) {
|
||||
Collection entries = (Collection) fTypeToSuperTypes.get(type);
|
||||
if (entries != null) {
|
||||
for (Iterator i = entries.iterator(); i.hasNext(); ) {
|
||||
TypeEntry entry = (TypeEntry)i.next();
|
||||
ITypeInfo superType = entry.type;
|
||||
if (!list.contains(superType)) {
|
||||
list.add(superType);
|
||||
}
|
||||
addSupers(superType, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getType()
|
||||
*/
|
||||
public ICElement getType() {
|
||||
if (fFocusType != null)
|
||||
return TypeUtil.getElementForType(fFocusType);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ITypeHierarchy
|
||||
* TODO (jerome) should use a PerThreadObject to build the hierarchy instead of synchronizing
|
||||
* (see also isAffected(IJavaElementDelta))
|
||||
*/
|
||||
public synchronized void refresh(IProgressMonitor monitor) throws CModelException {
|
||||
try {
|
||||
fProgressMonitor = monitor;
|
||||
if (monitor != null) {
|
||||
if (fFocusType != null) {
|
||||
monitor.beginTask(TypeHierarchyMessages.getFormattedString("hierarchy.creatingOnType", fFocusType.getQualifiedTypeName().getFullyQualifiedName()), 100); //$NON-NLS-1$
|
||||
} else {
|
||||
monitor.beginTask(TypeHierarchyMessages.getString("hierarchy.creating"), 100); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
long start = -1;
|
||||
if (DEBUG) {
|
||||
start = System.currentTimeMillis();
|
||||
if (fComputeSubtypes) {
|
||||
System.out.println("CREATING TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
} else {
|
||||
System.out.println("CREATING SUPER TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
if (fFocusType != null) {
|
||||
System.out.println(" on type " + fFocusType.toString()); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
compute();
|
||||
// initializeRegions();
|
||||
fNeedsRefresh = false;
|
||||
fChangeCollector = null;
|
||||
|
||||
if (DEBUG) {
|
||||
if (fComputeSubtypes) {
|
||||
System.out.println("CREATED TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
} else {
|
||||
System.out.println("CREATED SUPER TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
System.out.println(this.toString());
|
||||
}
|
||||
} catch (CModelException e) {
|
||||
throw e;
|
||||
} catch (CoreException e) {
|
||||
throw new CModelException(e);
|
||||
} finally {
|
||||
if (monitor != null) {
|
||||
monitor.done();
|
||||
}
|
||||
fProgressMonitor = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute this type hierarchy.
|
||||
*/
|
||||
protected void compute() throws CModelException, CoreException {
|
||||
if (fFocusType != null) {
|
||||
// HierarchyBuilder builder =
|
||||
// new IndexBasedHierarchyBuilder(
|
||||
// this,
|
||||
// this.scope);
|
||||
// builder.build(this.computeSubtypes);
|
||||
|
||||
// initialize(1);
|
||||
// buildSupertypes();
|
||||
|
||||
} // else a RegionBasedTypeHierarchy should be used
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this hierarchy's internal tables with the given size.
|
||||
*/
|
||||
/* protected void initialize(int size) {
|
||||
if (size < 10) {
|
||||
size = 10;
|
||||
}
|
||||
int smallSize = (size / 2);
|
||||
this.classToSuperclass = new HashMap(size);
|
||||
this.interfaces = new ArrayList(smallSize);
|
||||
this.missingTypes = new ArrayList(smallSize);
|
||||
this.rootClasses = new TypeVector();
|
||||
this.typeToSubtypes = new HashMap(smallSize);
|
||||
this.typeToSuperInterfaces = new HashMap(smallSize);
|
||||
this.typeFlags = new HashMap(smallSize);
|
||||
|
||||
this.projectRegion = new Region();
|
||||
this.packageRegion = new Region();
|
||||
this.files = new HashMap(5);
|
||||
}
|
||||
*/
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#store(java.io.OutputStream, org.eclipse.core.runtime.IProgressMonitor)
|
||||
*/
|
||||
public void store(OutputStream outputStream, IProgressMonitor monitor) throws CModelException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004 QNX Software Systems and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the 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.typehierarchy;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.browser.ITypeInfo;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICModelStatusConstants;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
|
||||
import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
|
||||
import org.eclipse.cdt.internal.core.model.CModelStatus;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
|
||||
public class TypeHierarchyBuilder {
|
||||
|
||||
public TypeHierarchyBuilder() {
|
||||
}
|
||||
|
||||
public ITypeHierarchy createTypeHierarchy(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
|
||||
TypeHierarchy typeHierarchy = new TypeHierarchy(info);
|
||||
Set processedTypes = new HashSet();
|
||||
addSuperClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor);
|
||||
|
||||
typeHierarchy.addRootType(info);
|
||||
processedTypes.clear();
|
||||
addSubClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor);
|
||||
|
||||
return typeHierarchy;
|
||||
}
|
||||
|
||||
private void addSuperClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
|
||||
if (type.hasSuperTypes()) {
|
||||
ITypeInfo[] superTypes = TypeCacheManager.getInstance().locateSuperTypesAndWait(type, enableIndexing, Job.SHORT, monitor);
|
||||
if (superTypes == null)
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
|
||||
|
||||
for (int i = 0; i < superTypes.length; ++i) {
|
||||
ITypeInfo superType = superTypes[i];
|
||||
|
||||
// recursively process sub sub classes
|
||||
if (!processedTypes.contains(superType)) {
|
||||
processedTypes.add(superType);
|
||||
addSuperClasses(typeHierarchy, superType, processedTypes, enableIndexing, monitor);
|
||||
}
|
||||
|
||||
ASTAccessVisibility access = type.getSuperTypeAccess(superType);
|
||||
|
||||
typeHierarchy.addSuperType(type, superType, access);
|
||||
}
|
||||
} else {
|
||||
typeHierarchy.addRootType(type);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSubClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
|
||||
if (type.hasSubTypes()) {
|
||||
ITypeInfo[] subTypes = TypeCacheManager.getInstance().locateSubTypesAndWait(type, enableIndexing, Job.SHORT, monitor);
|
||||
if (subTypes == null)
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
|
||||
|
||||
for (int i = 0; i < subTypes.length; ++i) {
|
||||
ITypeInfo subType = subTypes[i];
|
||||
|
||||
// recursively process sub sub classes
|
||||
if (!processedTypes.contains(subType)) {
|
||||
processedTypes.add(subType);
|
||||
addSubClasses(typeHierarchy, subType, processedTypes, enableIndexing, monitor);
|
||||
}
|
||||
|
||||
typeHierarchy.addSubType(type, subType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private IStructure findCElementForType(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
|
||||
if (!info.exists())
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
|
||||
|
||||
if (!info.isClass())
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES));
|
||||
|
||||
// first we need to resolve the type location
|
||||
ITypeReference location = TypeCacheManager.getInstance().locateTypeAndWait(info, enableIndexing, Job.SHORT, monitor);
|
||||
if (location == null)
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
|
||||
|
||||
ICElement cElem = location.getCElement();
|
||||
if (cElem == null)
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
|
||||
|
||||
if (!(cElem instanceof IStructure))
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES));
|
||||
|
||||
IStructure cClass = (IStructure)cElem;
|
||||
|
||||
// check if type exists in cache
|
||||
ITypeInfo type = TypeCacheManager.getInstance().getTypeForElement(cElem);
|
||||
if (type == null || !type.equals(info))
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
|
||||
|
||||
return cClass;
|
||||
}
|
||||
|
||||
private ITypeInfo findTypeInCache(ITypeCache cache, String name) {
|
||||
IQualifiedTypeName qualName = new QualifiedTypeName(name);
|
||||
ITypeInfo[] superTypes = cache.getTypes(qualName);
|
||||
for (int i = 0; i < superTypes.length; ++i) {
|
||||
ITypeInfo superType = superTypes[i];
|
||||
if (superType.isClass()) {
|
||||
return superType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
|
@ -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.core.browser.typehierarchy;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class TypeHierarchyMessages {
|
||||
|
||||
private static final String RESOURCE_BUNDLE= TypeHierarchyMessages.class.getName();
|
||||
|
||||
private static ResourceBundle fgResourceBundle;
|
||||
static {
|
||||
try {
|
||||
fgResourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE);
|
||||
} catch (MissingResourceException x) {
|
||||
fgResourceBundle = null;
|
||||
}
|
||||
}
|
||||
|
||||
private TypeHierarchyMessages() {
|
||||
}
|
||||
|
||||
public static String getString(String key) {
|
||||
try {
|
||||
return fgResourceBundle.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return '!' + key + '!';
|
||||
} catch (NullPointerException e) {
|
||||
return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFormattedString(String key, String arg) {
|
||||
return getFormattedString(key, new String[] { arg });
|
||||
}
|
||||
|
||||
public static String getFormattedString(String key, String[] args) {
|
||||
return MessageFormat.format(getString(key), args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2000, 2004 QNX Software Systems and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the 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
|
||||
###############################################################################
|
||||
|
||||
### hierarchy
|
||||
hierarchy.nullProject = Project argument cannot be null
|
||||
hierarchy.nullRegion = Region cannot be null
|
||||
hierarchy.nullFocusType = Type focus cannot be null
|
||||
hierarchy.creating = Creating type hierarchy...
|
||||
hierarchy.creatingOnType = Creating type hierarchy on {0}...
|
|
@ -15,6 +15,7 @@ import org.eclipse.cdt.core.browser.ITypeInfo;
|
|||
import org.eclipse.cdt.core.browser.ITypeInfoVisitor;
|
||||
import org.eclipse.cdt.core.browser.ITypeReference;
|
||||
import org.eclipse.cdt.core.browser.ITypeSearchScope;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
@ -40,6 +41,22 @@ public interface ITypeCache extends ISchedulingRule {
|
|||
*/
|
||||
public void insert(ITypeInfo info);
|
||||
|
||||
/** Adds subtype to type.
|
||||
*
|
||||
* @param type
|
||||
* @param subtype
|
||||
*/
|
||||
public void addSubtype(ITypeInfo type, ITypeInfo subtype);
|
||||
|
||||
/** Adds supertype to type.
|
||||
*
|
||||
* @param type the type
|
||||
* @param supertype the supertype
|
||||
* @param the access visibility (PUBLIC, PROTECTED, PRIVATE)
|
||||
* @param isVirtual <code>true</code> if virtual base class
|
||||
*/
|
||||
public void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual);
|
||||
|
||||
/** Removes type from cache.
|
||||
*
|
||||
* @param info
|
||||
|
@ -134,6 +151,29 @@ public interface ITypeCache extends ISchedulingRule {
|
|||
*/
|
||||
public ITypeInfo[] getEnclosedTypes(ITypeInfo info, int kinds[]);
|
||||
|
||||
/** Returns all types in the cache are supertypes of the given type.
|
||||
*
|
||||
* @param info the given type
|
||||
* @return Array of supertypes, or <code>null</code> if none found.
|
||||
*/
|
||||
public ITypeInfo[] getSupertypes(ITypeInfo info);
|
||||
|
||||
/** Returns the supertype access visiblity.
|
||||
*
|
||||
* @param type the given type
|
||||
* @param supertype the supertype
|
||||
* @return the visibility (PRIVATE, PROTECTED, PUBLIC) or <code>null</code> if none found.
|
||||
*/
|
||||
public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType);
|
||||
|
||||
|
||||
/** Returns all types in the cache which extend the given type.
|
||||
*
|
||||
* @param info the given type
|
||||
* @return Array of subtypes, or <code>null</code> if none found.
|
||||
*/
|
||||
public ITypeInfo[] getSubtypes(ITypeInfo info);
|
||||
|
||||
/** Returns the project associated with this cache.
|
||||
*
|
||||
* @return the project
|
||||
|
@ -154,5 +194,11 @@ public interface ITypeCache extends ISchedulingRule {
|
|||
public void locateType(ITypeInfo info, int priority, int delay);
|
||||
public ITypeReference locateTypeAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
|
||||
|
||||
public void locateSupertypes(ITypeInfo info, int priority, int delay);
|
||||
public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
|
||||
|
||||
public void locateSubtypes(ITypeInfo info, int priority, int delay);
|
||||
public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
|
||||
|
||||
public ITypeInfo getGlobalNamespace();
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
|
|||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
|
||||
public class IndexerTypesJob extends IndexerJob {
|
||||
|
||||
|
@ -108,6 +109,14 @@ public class IndexerTypesJob extends IndexerJob {
|
|||
String[] enclosingNames = getEnclosingNames(word, slash);
|
||||
addType(input, project, entry, type, name, enclosingNames, monitor);
|
||||
}
|
||||
} else if (decodedType == IIndexConstants.DERIVED_SUFFIX) {
|
||||
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);
|
||||
addSuperTypeReference(input, project, entry, name, enclosingNames, monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,4 +184,37 @@ public class IndexerTypesJob extends IndexerJob {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addSuperTypeReference(IndexInput input, IProject project, IEntryResult entry, String name, String[] enclosingNames, IProgressMonitor monitor) throws InterruptedException, IOException {
|
||||
QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
|
||||
ITypeInfo info = fTypeCache.getType(ICElement.C_CLASS, qualifiedName);
|
||||
if (info == null)
|
||||
info = fTypeCache.getType(ICElement.C_STRUCT, qualifiedName);
|
||||
if (info == null) {
|
||||
// add dummy type to cache
|
||||
info = new TypeInfo(0, qualifiedName);
|
||||
fTypeCache.insert(info);
|
||||
}
|
||||
int[] references = entry.getFileReferences();
|
||||
if (references != null && references.length > 0) {
|
||||
for (int i = 0; i < references.length; ++i) {
|
||||
if (monitor.isCanceled())
|
||||
throw new InterruptedException();
|
||||
|
||||
IndexedFile file = input.getIndexedFile(references[i]);
|
||||
if (file != null && file.getPath() != null) {
|
||||
IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
|
||||
info.addDerivedReference(new TypeReference(path, project));
|
||||
//
|
||||
// // get absolute path
|
||||
// IPath path = new Path(file.getPath());
|
||||
// IPath projectPath = project.getFullPath();
|
||||
// if (projectPath.isPrefixOf(path)) {
|
||||
// path = project.getLocation().append(path.removeFirstSegments(projectPath.segmentCount()));
|
||||
// }
|
||||
// info.addDerivedReference(new TypeReference(path, project));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 SubTypeLocatorJob extends BasicJob {
|
||||
|
||||
public static final Object FAMILY = new Object();
|
||||
private ITypeInfo fLocateType;
|
||||
private ITypeCache fTypeCache;
|
||||
private IWorkingCopyProvider fWorkingCopyProvider;
|
||||
|
||||
public SubTypeLocatorJob(ITypeInfo info, ITypeCache typeCache, IWorkingCopyProvider workingCopyProvider) {
|
||||
super(TypeCacheMessages.getString("SubTypeLocatorJob.jobName"), FAMILY); //$NON-NLS-1$
|
||||
fLocateType = info;
|
||||
fTypeCache = typeCache;
|
||||
fWorkingCopyProvider= workingCopyProvider;
|
||||
}
|
||||
|
||||
public ITypeInfo getType() {
|
||||
return fLocateType;
|
||||
}
|
||||
|
||||
protected IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException {
|
||||
boolean success = false;
|
||||
long startTime = System.currentTimeMillis();
|
||||
trace("SubTypeLocatorJob: started"); //$NON-NLS-1$
|
||||
|
||||
try {
|
||||
monitor.beginTask(TypeCacheMessages.getString("SubTypeLocatorJob.taskName"), 100); //$NON-NLS-1$
|
||||
|
||||
if (monitor.isCanceled())
|
||||
throw new InterruptedException();
|
||||
|
||||
TypeParser parser = new TypeParser(fTypeCache, fWorkingCopyProvider);
|
||||
success = parser.findSubTypes(fLocateType, new SubProgressMonitor(monitor, 100));
|
||||
|
||||
if (monitor.isCanceled())
|
||||
throw new InterruptedException();
|
||||
|
||||
} finally {
|
||||
long executionTime = System.currentTimeMillis() - startTime;
|
||||
if (success)
|
||||
trace("SubTypeLocatorJob: completed ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
else
|
||||
trace("SubTypeLocatorJob: aborted ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
monitor.done();
|
||||
}
|
||||
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ 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.ICElement;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
|
||||
import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
@ -49,6 +50,29 @@ public class TypeCache implements ITypeCache {
|
|||
private final IWorkingCopyProvider fWorkingCopyProvider;
|
||||
private final Collection fDeltas = new ArrayList();
|
||||
private final ITypeInfo fGlobalNamespace;
|
||||
private final Map fTypeToSubTypes = new HashMap();
|
||||
private final Map fTypeToSuperTypes = new HashMap();
|
||||
|
||||
private static final class SuperTypeEntry {
|
||||
ITypeInfo superType;
|
||||
ASTAccessVisibility access;
|
||||
boolean isVirtual;
|
||||
SuperTypeEntry(ITypeInfo superType, ASTAccessVisibility access, boolean isVirtual) {
|
||||
this.superType = superType;
|
||||
this.access = access;
|
||||
this.isVirtual = isVirtual;
|
||||
}
|
||||
}
|
||||
|
||||
private SuperTypeEntry findSuperTypeEntry(Collection entryCollection, ITypeInfo superType) {
|
||||
for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
|
||||
SuperTypeEntry e = (SuperTypeEntry) i.next();
|
||||
if (e.superType.equals(superType)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final int[] ENCLOSING_TYPES = {ICElement.C_NAMESPACE, ICElement.C_CLASS, ICElement.C_STRUCT, 0};
|
||||
|
||||
|
@ -330,6 +354,62 @@ public class TypeCache implements ITypeCache {
|
|||
fTypeKeyMap.clear();
|
||||
}
|
||||
|
||||
public synchronized void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual) {
|
||||
Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
|
||||
if (entryCollection == null) {
|
||||
entryCollection = new ArrayList();
|
||||
fTypeToSuperTypes.put(type, entryCollection);
|
||||
}
|
||||
if (findSuperTypeEntry(entryCollection, supertype) == null) {
|
||||
entryCollection.add(new SuperTypeEntry(supertype, access, isVirtual));
|
||||
supertype.setCache(this);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ITypeInfo[] getSupertypes(ITypeInfo type) {
|
||||
Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
|
||||
if (entryCollection != null && !entryCollection.isEmpty()) {
|
||||
ITypeInfo[] superTypes = new ITypeInfo[entryCollection.size()];
|
||||
int count = 0;
|
||||
for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
|
||||
SuperTypeEntry e = (SuperTypeEntry) i.next();
|
||||
superTypes[count++] = e.superType;
|
||||
}
|
||||
return superTypes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType) {
|
||||
Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
|
||||
if (entryCollection != null && !entryCollection.isEmpty()) {
|
||||
SuperTypeEntry e = findSuperTypeEntry(entryCollection, superType);
|
||||
if (e != null)
|
||||
return e.access;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized void addSubtype(ITypeInfo type, ITypeInfo subtype) {
|
||||
Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
|
||||
if (typeCollection == null) {
|
||||
typeCollection = new ArrayList();
|
||||
fTypeToSubTypes.put(type, typeCollection);
|
||||
}
|
||||
if (!typeCollection.contains(subtype)) {
|
||||
typeCollection.add(subtype);
|
||||
subtype.setCache(this);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ITypeInfo[] getSubtypes(ITypeInfo type) {
|
||||
Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
|
||||
if (typeCollection != null && !typeCollection.isEmpty()) {
|
||||
return (ITypeInfo[]) typeCollection.toArray(new ITypeInfo[typeCollection.size()]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized void accept(ITypeInfoVisitor visitor) {
|
||||
for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
|
||||
Map.Entry entry = (Map.Entry) mapIter.next();
|
||||
|
@ -579,6 +659,13 @@ public class TypeCache implements ITypeCache {
|
|||
locatorJob.cancel();
|
||||
}
|
||||
}
|
||||
jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
|
||||
for (int i = 0; i < jobs.length; ++i) {
|
||||
SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
|
||||
if (locatorJob.getType().getEnclosingProject().equals(fProject)) {
|
||||
locatorJob.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void locateType(ITypeInfo info, int priority, int delay) {
|
||||
|
@ -626,4 +713,77 @@ public class TypeCache implements ITypeCache {
|
|||
|
||||
return info.getResolvedReference();
|
||||
}
|
||||
|
||||
public void locateSupertypes(ITypeInfo info, int priority, int delay) {
|
||||
ITypeInfo[] superTypes = getSupertypes(info);
|
||||
if (superTypes != null)
|
||||
return; // nothing to do
|
||||
|
||||
locateType(info, priority, delay);
|
||||
}
|
||||
|
||||
public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
|
||||
locateSupertypes(info, priority, 0);
|
||||
|
||||
// wait for jobs to complete
|
||||
IJobManager jobManager = Platform.getJobManager();
|
||||
Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
|
||||
for (int i = 0; i < jobs.length; ++i) {
|
||||
SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
|
||||
if (locatorJob.getType().equals(info)) {
|
||||
try {
|
||||
locatorJob.join(monitor);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getSupertypes(info);
|
||||
}
|
||||
|
||||
public void locateSubtypes(ITypeInfo info, int priority, int delay) {
|
||||
ITypeInfo[] subTypes = getSubtypes(info);
|
||||
if (subTypes != null)
|
||||
return; // nothing to do
|
||||
|
||||
// cancel any scheduled or running jobs for this type
|
||||
IJobManager jobManager = Platform.getJobManager();
|
||||
Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
|
||||
for (int i = 0; i < jobs.length; ++i) {
|
||||
SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
|
||||
if (locatorJob.getType().equals(info)) {
|
||||
locatorJob.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// check again, in case some jobs finished in the meantime
|
||||
subTypes = getSubtypes(info);
|
||||
if (subTypes != null)
|
||||
return; // nothing to do
|
||||
|
||||
// create a new job
|
||||
SubTypeLocatorJob locatorJob = new SubTypeLocatorJob(info, this, fWorkingCopyProvider);
|
||||
// schedule the new job
|
||||
locatorJob.setPriority(priority);
|
||||
locatorJob.schedule(delay);
|
||||
}
|
||||
|
||||
public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
|
||||
locateSubtypes(info, priority, 0);
|
||||
|
||||
// wait for jobs to complete
|
||||
IJobManager jobManager = Platform.getJobManager();
|
||||
Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
|
||||
for (int i = 0; i < jobs.length; ++i) {
|
||||
SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
|
||||
if (locatorJob.getType().equals(info)) {
|
||||
try {
|
||||
locatorJob.join(monitor);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getSubtypes(info);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ package org.eclipse.cdt.internal.core.browser.cache;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.browser.IQualifiedTypeName;
|
||||
import org.eclipse.cdt.core.browser.ITypeInfo;
|
||||
import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
|
||||
import org.eclipse.cdt.core.browser.QualifiedTypeName;
|
||||
import org.eclipse.cdt.core.browser.TypeSearchScope;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICElementDelta;
|
||||
|
@ -23,13 +26,23 @@ 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;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
|
||||
public class TypeCacheManager {
|
||||
|
||||
private Map fCacheMap = new HashMap();
|
||||
private static final TypeCacheManager fgInstance = new TypeCacheManager();
|
||||
private Map fCacheMap;
|
||||
private IWorkingCopyProvider fWorkingCopyProvider;
|
||||
|
||||
public TypeCacheManager(IWorkingCopyProvider workingCopyProvider) {
|
||||
private TypeCacheManager() {
|
||||
fCacheMap = new HashMap();
|
||||
}
|
||||
|
||||
public static TypeCacheManager getInstance() {
|
||||
return fgInstance;
|
||||
}
|
||||
|
||||
public void setWorkingCopyProvider(IWorkingCopyProvider workingCopyProvider) {
|
||||
fWorkingCopyProvider = workingCopyProvider;
|
||||
}
|
||||
|
||||
|
@ -194,4 +207,40 @@ public class TypeCacheManager {
|
|||
jobManager.cancel(TypeCacherJob.FAMILY);
|
||||
jobManager.cancel(TypeLocatorJob.FAMILY);
|
||||
}
|
||||
|
||||
public ITypeInfo[] locateSuperTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
|
||||
ITypeInfo[] superTypes = info.getSuperTypes();
|
||||
if (superTypes == null) {
|
||||
// cancel background jobs
|
||||
IProject project = info.getEnclosingProject();
|
||||
getCache(project).cancelJobs();
|
||||
|
||||
// start the search job
|
||||
getCache(project).locateSupertypesAndWait(info, priority, monitor);
|
||||
|
||||
superTypes = info.getSuperTypes();
|
||||
|
||||
// resume background jobs
|
||||
reconcile(enableIndexing, Job.BUILD, 0);
|
||||
}
|
||||
return superTypes;
|
||||
}
|
||||
|
||||
public ITypeInfo[] locateSubTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
|
||||
ITypeInfo[] subTypes = info.getSubTypes();
|
||||
if (subTypes == null) {
|
||||
// cancel background jobs
|
||||
IProject project = info.getEnclosingProject();
|
||||
getCache(project).cancelJobs();
|
||||
|
||||
// start the search job
|
||||
getCache(project).locateSubtypesAndWait(info, priority, monitor);
|
||||
|
||||
subTypes = info.getSubTypes();
|
||||
|
||||
// resume background jobs
|
||||
reconcile(enableIndexing, Job.BUILD, 0);
|
||||
}
|
||||
return subTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,7 @@ TypeCacherJob.taskName=Updating Type Cache...
|
|||
|
||||
TypeLocatorJob.jobName=Type Locator
|
||||
TypeLocatorJob.taskName=Searching for Type Declaration...
|
||||
SubTypeLocatorJob.jobName=Subtype Locator
|
||||
SubTypeLocatorJob.taskName=Searching for Subtypes...
|
||||
|
||||
TypeCache.globalNamespace=(global)
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.browser.ITypeInfo;
|
||||
|
@ -49,7 +50,12 @@ 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.ASTAccessVisibility;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTClassKind;
|
||||
import org.eclipse.cdt.core.parser.ast.ASTNotImplementedException;
|
||||
import org.eclipse.cdt.core.parser.ast.IASTBaseSpecifier;
|
||||
import org.eclipse.cdt.core.parser.ast.IASTTypeSpecifier;
|
||||
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;
|
||||
|
@ -113,6 +119,8 @@ public class TypeParser implements ISourceElementRequestor {
|
|||
private final SimpleStack fScopeStack = new SimpleStack();
|
||||
private final SimpleStack fResourceStack = new SimpleStack();
|
||||
private ITypeInfo fTypeToFind;
|
||||
private ITypeInfo fSuperTypeToFind;
|
||||
private Set fProcessedTypes = new HashSet();
|
||||
private boolean fFoundType;
|
||||
|
||||
public TypeParser(ITypeCache typeCache, IWorkingCopyProvider provider) {
|
||||
|
@ -247,6 +255,75 @@ public class TypeParser implements ISourceElementRequestor {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean findSubTypes(ITypeInfo info, IProgressMonitor monitor) throws InterruptedException {
|
||||
if (monitor == null)
|
||||
monitor = new NullProgressMonitor();
|
||||
|
||||
if (monitor.isCanceled())
|
||||
throw new InterruptedException();
|
||||
|
||||
fScope = new TypeSearchScope();
|
||||
ITypeReference[] refs = info.getDerivedReferences();
|
||||
if (refs == null || refs.length == 0)
|
||||
return false; // no source references
|
||||
|
||||
for (int i = 0; i < refs.length; ++i) {
|
||||
ITypeReference location = refs[i];
|
||||
IPath path = location.getPath();
|
||||
fScope.add(path, false, null);
|
||||
}
|
||||
|
||||
Map workingCopyMap = null;
|
||||
if (fWorkingCopyProvider != null) {
|
||||
IWorkingCopy[] workingCopies = fWorkingCopyProvider.getWorkingCopies();
|
||||
if (workingCopies != null && workingCopies.length > 0) {
|
||||
workingCopyMap = new HashMap(workingCopies.length);
|
||||
for (int i = 0; i < workingCopies.length; ++i) {
|
||||
IWorkingCopy workingCopy = workingCopies[i];
|
||||
IPath wcPath = workingCopy.getOriginalElement().getPath();
|
||||
if (fScope.encloses(wcPath)) {
|
||||
// // always flush working copies from cache?
|
||||
// fTypeCache.flush(wcPath);
|
||||
fScope.add(wcPath, false, null);
|
||||
workingCopyMap.put(wcPath, workingCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fProject = fTypeCache.getProject();
|
||||
IPath[] searchPaths = fTypeCache.getPaths(fScope);
|
||||
Collection workingCopyPaths = new HashSet();
|
||||
if (workingCopyMap != null) {
|
||||
collectWorkingCopiesInProject(workingCopyMap, fProject, workingCopyPaths);
|
||||
//TODO what about working copies outside the workspace?
|
||||
}
|
||||
|
||||
monitor.beginTask("", searchPaths.length + workingCopyPaths.size()); //$NON-NLS-1$
|
||||
try {
|
||||
fTypeToFind = null;
|
||||
fSuperTypeToFind = info;
|
||||
fFoundType = false;
|
||||
for (Iterator pathIter = workingCopyPaths.iterator(); pathIter.hasNext(); ) {
|
||||
IPath path = (IPath) pathIter.next();
|
||||
parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
|
||||
}
|
||||
for (int i = 0; i < searchPaths.length; ++i) {
|
||||
IPath path = searchPaths[i];
|
||||
if (!workingCopyPaths.contains(path)) {
|
||||
parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
|
||||
} else {
|
||||
monitor.worked(1);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fTypeToFind = null;
|
||||
fFoundType = false;
|
||||
monitor.done();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void collectWorkingCopiesInProject(Map workingCopyMap, IProject project, Collection workingCopyPaths) {
|
||||
for (Iterator mapIter = workingCopyMap.entrySet().iterator(); mapIter.hasNext(); ) {
|
||||
Map.Entry entry = (Map.Entry) mapIter.next();
|
||||
|
@ -583,76 +660,6 @@ public class TypeParser implements ISourceElementRequestor {
|
|||
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;
|
||||
}
|
||||
|
||||
if (fTypeToFind != null) {
|
||||
if ((fTypeToFind.getCElementType() == type || fTypeToFind.isUndefinedType()) && name.equals(fTypeToFind.getName())) {
|
||||
String[] enclosingNames = getEnclosingNames(offsetable);
|
||||
QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
|
||||
if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
|
||||
fFoundType = true;
|
||||
|
||||
// add types to cache
|
||||
addType(type, name, enclosingNames, fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
|
||||
fProgressMonitor.worked(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// add types to cache
|
||||
addType(type, name, getEnclosingNames(offsetable), fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
|
||||
fProgressMonitor.worked(1);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getEnclosingNames(IASTOffsetableNamedElement elem) {
|
||||
String[] enclosingNames = null;
|
||||
if (elem instanceof IASTQualifiedNameElement) {
|
||||
|
@ -665,6 +672,140 @@ public class TypeParser implements ISourceElementRequestor {
|
|||
return enclosingNames;
|
||||
}
|
||||
|
||||
|
||||
private class NodeTypeInfo {
|
||||
int type;
|
||||
String name;
|
||||
String[] enclosingNames;
|
||||
int offset;
|
||||
int end;
|
||||
IASTOffsetableNamedElement offsetable;
|
||||
|
||||
void init() {
|
||||
type = 0;
|
||||
name = null;
|
||||
enclosingNames = null;
|
||||
offset = 0;
|
||||
end = 0;
|
||||
offsetable = null;
|
||||
}
|
||||
|
||||
boolean parseNodeForTypeInfo(ISourceElementCallbackDelegate node) {
|
||||
init();
|
||||
|
||||
if (node instanceof IASTReference) {
|
||||
IASTReference reference = (IASTReference) node;
|
||||
offset = reference.getOffset();
|
||||
end = offset + reference.getName().length();
|
||||
} else if (node instanceof IASTOffsetableNamedElement) {
|
||||
offsetable = (IASTOffsetableNamedElement) node;
|
||||
offset = offsetable.getNameOffset() != 0 ? offsetable.getNameOffset() : offsetable.getStartingOffset();
|
||||
end = offsetable.getNameEndOffset();
|
||||
if (end == 0) {
|
||||
end = offset + offsetable.getName().length();
|
||||
}
|
||||
}
|
||||
|
||||
if (node instanceof IASTReference)
|
||||
node = fLastDeclaration;
|
||||
if (node instanceof IASTReference) {
|
||||
offsetable = (IASTOffsetableNamedElement) ((IASTReference) node).getReferencedElement();
|
||||
name = ((IASTReference) node).getName();
|
||||
} else if (node instanceof IASTOffsetableNamedElement) {
|
||||
offsetable = (IASTOffsetableNamedElement) node;
|
||||
name = offsetable.getName();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// skip unnamed structs
|
||||
if (name == null || name.length() == 0)
|
||||
return false;
|
||||
|
||||
// skip unused types
|
||||
type = getElementType(offsetable);
|
||||
if (type == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// collect enclosing names
|
||||
if (offsetable instanceof IASTQualifiedNameElement) {
|
||||
String[] names = ((IASTQualifiedNameElement) offsetable).getFullyQualifiedName();
|
||||
if (names != null && names.length > 1) {
|
||||
enclosingNames = new String[names.length - 1];
|
||||
System.arraycopy(names, 0, enclosingNames, 0, names.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void acceptType(ISourceElementCallbackDelegate node) {
|
||||
if (fProgressMonitor.isCanceled())
|
||||
throw new OperationCanceledException();
|
||||
|
||||
// skip local declarations
|
||||
IASTScope currentScope = (IASTScope) fScopeStack.top();
|
||||
if (currentScope instanceof IASTFunction || currentScope instanceof IASTMethod) {
|
||||
return;
|
||||
}
|
||||
|
||||
NodeTypeInfo nodeInfo = new NodeTypeInfo();
|
||||
if (nodeInfo.parseNodeForTypeInfo(node)) {
|
||||
TypeReference originalLocation = null;
|
||||
Object originalRef = fResourceStack.bottom();
|
||||
if (originalRef instanceof IWorkingCopy) {
|
||||
IWorkingCopy workingCopy = (IWorkingCopy) originalRef;
|
||||
originalLocation = new TypeReference(workingCopy, fProject);
|
||||
} else if (originalRef instanceof IResource) {
|
||||
IResource resource = (IResource) originalRef;
|
||||
originalLocation = new TypeReference(resource, fProject);
|
||||
} else if (originalRef instanceof IPath) {
|
||||
IPath path = PathUtil.getProjectRelativePath((IPath)originalRef, fProject);
|
||||
originalLocation = new TypeReference(path, fProject);
|
||||
}
|
||||
|
||||
TypeReference resolvedLocation = null;
|
||||
Object resolvedRef = fResourceStack.top();
|
||||
if (resolvedRef instanceof IWorkingCopy) {
|
||||
IWorkingCopy workingCopy = (IWorkingCopy) resolvedRef;
|
||||
resolvedLocation = new TypeReference(workingCopy, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
|
||||
} else if (resolvedRef instanceof IResource) {
|
||||
IResource resource = (IResource) resolvedRef;
|
||||
resolvedLocation = new TypeReference(resource, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
|
||||
} else if (resolvedRef instanceof IPath) {
|
||||
IPath path = PathUtil.getProjectRelativePath((IPath)resolvedRef, fProject);
|
||||
resolvedLocation = new TypeReference(path, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
|
||||
}
|
||||
|
||||
if (fTypeToFind != null) {
|
||||
if ((fTypeToFind.getCElementType() == nodeInfo.type || fTypeToFind.isUndefinedType()) && nodeInfo.name.equals(fTypeToFind.getName())) {
|
||||
QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
|
||||
if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
|
||||
fFoundType = true;
|
||||
|
||||
// add types to cache
|
||||
ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
|
||||
if (newType != null && node instanceof IASTClassSpecifier) {
|
||||
addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
|
||||
}
|
||||
fProgressMonitor.worked(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// add types to cache
|
||||
QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
|
||||
ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
|
||||
if (newType != null && node instanceof IASTClassSpecifier) {
|
||||
addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
|
||||
}
|
||||
fProgressMonitor.worked(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getElementType(IASTOffsetableNamedElement offsetable) {
|
||||
if (offsetable instanceof IASTClassSpecifier || offsetable instanceof IASTElaboratedTypeSpecifier) {
|
||||
ASTClassKind kind = null;
|
||||
|
@ -690,8 +831,40 @@ public class TypeParser implements ISourceElementRequestor {
|
|||
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);
|
||||
private void addSuperClasses(ITypeInfo type, IASTClassSpecifier classSpec, TypeReference location, Set processedClasses) {
|
||||
Iterator baseIter = classSpec.getBaseClauses();
|
||||
if (baseIter != null) {
|
||||
while (baseIter.hasNext()) {
|
||||
IASTBaseSpecifier baseSpec = (IASTBaseSpecifier) baseIter.next();
|
||||
try {
|
||||
String baseName = baseSpec.getParentClassName();
|
||||
ASTAccessVisibility baseAccess = baseSpec.getAccess();
|
||||
|
||||
IASTClassSpecifier parentClass = null;
|
||||
IASTTypeSpecifier parentSpec = baseSpec.getParentClassSpecifier();
|
||||
if (parentSpec instanceof IASTClassSpecifier)
|
||||
parentClass = (IASTClassSpecifier) parentSpec;
|
||||
|
||||
if (parentClass != null) {
|
||||
NodeTypeInfo nodeInfo = new NodeTypeInfo();
|
||||
if (nodeInfo.parseNodeForTypeInfo(parentClass)) {
|
||||
// add type to cache
|
||||
ITypeInfo superType = addSuperType(type, nodeInfo.type, nodeInfo.name, nodeInfo.enclosingNames, location, baseAccess, baseSpec.isVirtual());
|
||||
|
||||
// recursively process super super classes
|
||||
if (!processedClasses.contains(parentClass)) {
|
||||
processedClasses.add(parentClass);
|
||||
addSuperClasses(superType, parentClass, location, processedClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ASTNotImplementedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ITypeInfo addType(int type, QualifiedTypeName qualifiedName, TypeReference originalLocation, TypeReference resolvedLocation) {
|
||||
ITypeInfo info = fTypeCache.getType(type, qualifiedName);
|
||||
if (info == null || info.isUndefinedType()) {
|
||||
// add new type to cache
|
||||
|
@ -702,32 +875,35 @@ public class TypeParser implements ISourceElementRequestor {
|
|||
fTypeCache.insert(info);
|
||||
}
|
||||
|
||||
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);
|
||||
info.addReference(originalLocation);
|
||||
}
|
||||
|
||||
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(resolvedLocation);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private ITypeInfo addSuperType(ITypeInfo addToType, int type, String name, String[] enclosingNames, TypeReference location, ASTAccessVisibility access, boolean isVirtual) {
|
||||
QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
|
||||
ITypeInfo superType = fTypeCache.getType(type, qualifiedName);
|
||||
if (superType == null || superType.isUndefinedType()) {
|
||||
if (superType != null) {
|
||||
// merge with existing type
|
||||
superType.setCElementType(type);
|
||||
} else {
|
||||
// add new type to cache
|
||||
superType = new TypeInfo(type, qualifiedName);
|
||||
fTypeCache.insert(superType);
|
||||
}
|
||||
}
|
||||
info.addReference(location);
|
||||
superType.addDerivedReference(location);
|
||||
|
||||
if (fSuperTypeToFind != null && fSuperTypeToFind.equals(superType)) {
|
||||
//TODO don't need to do anything here?
|
||||
}
|
||||
fTypeCache.addSupertype(addToType, superType, access, isVirtual);
|
||||
fTypeCache.addSubtype(superType, addToType);
|
||||
return superType;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
|
|
@ -441,7 +441,7 @@ public abstract class CElement extends PlatformObject implements ICElement {
|
|||
* Returns true if this element is an ancestor of the given element,
|
||||
* otherwise false.
|
||||
*/
|
||||
protected boolean isAncestorOf(ICElement e) {
|
||||
public boolean isAncestorOf(ICElement e) {
|
||||
ICElement parent= e.getParent();
|
||||
while (parent != null && !parent.equals(this)) {
|
||||
parent= parent.getParent();
|
||||
|
|
Loading…
Add table
Reference in a new issue