@ -369,6 +369,7 @@ namespace ICSharpCode.SharpDevelop.Dom
@@ -369,6 +369,7 @@ namespace ICSharpCode.SharpDevelop.Dom
}
volatile IClass [ ] inheritanceTreeCache ;
volatile IClass [ ] inheritanceTreeClassesOnlyCache ;
public IEnumerable < IClass > ClassInheritanceTree {
get {
@ -398,7 +399,7 @@ namespace ICSharpCode.SharpDevelop.Dom
@@ -398,7 +399,7 @@ namespace ICSharpCode.SharpDevelop.Dom
return inheritanceTree ;
}
inheritanceTree = CalculateClassInheritanceTree ( ) ;
inheritanceTree = CalculateClassInheritanceTree ( false ) ;
this . inheritanceTreeCache = inheritanceTree ;
if ( ! KeepInheritanceTree )
@ -408,12 +409,51 @@ namespace ICSharpCode.SharpDevelop.Dom
@@ -408,12 +409,51 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
public IEnumerable < IClass > ClassInheritanceTreeClassesOnly {
get {
// Notes:
// the ClassInheritanceTree must work even if the following things happen:
// - cyclic inheritance
// - multithreaded calls
// Recursive calls are possible if the SearchType request done by GetUnderlyingClass()
// uses ClassInheritanceTree.
// Such recursive calls are tricky, they have caused incorrect behavior (SD2-1474)
// or performance problems (SD2-1510) in the past.
// As of revision 3769, NRefactoryAstConvertVisitor sets up the SearchClassReturnType
// used for base types so that it does not look up inner classes in the class itself,
// so the ClassInheritanceTree is not used created in those cases.
// However, other language bindings might not set up base types correctly, so it's
// still possible that ClassInheritanceTree is called recursivly.
// In that case, we'll return an invalid inheritance tree because of
// ProxyReturnType's automatic stack overflow prevention.
// We do not use locks to protect against multithreaded calls because
// resolving one class's base types can cause getting the inheritance tree
// of another class -> beware of deadlocks
IClass [ ] inheritanceTreeClassesOnly = this . inheritanceTreeClassesOnlyCache ;
if ( inheritanceTreeClassesOnly ! = null ) {
return inheritanceTreeClassesOnly ;
}
inheritanceTreeClassesOnly = CalculateClassInheritanceTree ( true ) ;
this . inheritanceTreeClassesOnlyCache = inheritanceTreeClassesOnly ;
if ( ! KeepInheritanceTree )
DomCache . RegisterForClear ( ClearCachedInheritanceTree ) ;
return inheritanceTreeClassesOnly ;
}
}
void ClearCachedInheritanceTree ( )
{
inheritanceTreeClassesOnlyCache = null ;
inheritanceTreeCache = null ;
}
IClass [ ] CalculateClassInheritanceTree ( )
IClass [ ] CalculateClassInheritanceTree ( bool ignoreInterfaces )
{
List < IClass > visitedList = new List < IClass > ( ) ;
Queue < IReturnType > typesToVisit = new Queue < IReturnType > ( ) ;
@ -422,7 +462,7 @@ namespace ICSharpCode.SharpDevelop.Dom
@@ -422,7 +462,7 @@ namespace ICSharpCode.SharpDevelop.Dom
IReturnType nextType ;
do {
if ( currentClass ! = null ) {
if ( ! visitedList . Contains ( currentClass ) ) {
if ( ( ! ignoreInterfaces | | currentClass . ClassType ! = ClassType . Interface ) & & ! visitedList . Contains ( currentClass ) ) {
visitedList . Add ( currentClass ) ;
foreach ( IReturnType type in currentClass . BaseTypes ) {
typesToVisit . Enqueue ( type ) ;