From 177fb85a0049bc8fca431b5bbba1c1280c3bf369 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 7 Oct 2011 17:24:13 +0200 Subject: [PATCH] Fix infinite recursion when resolving the base type of "class Test : Test.Base { public class Base {} }" --- .../Resolver/MemberTypeOrNamespaceReference.cs | 10 +++++++++- .../CSharp/Resolver/NameLookupTests.cs | 8 ++++++++ ICSharpCode.NRefactory/Utils/BusyManager.cs | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/MemberTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory.CSharp/Resolver/MemberTypeOrNamespaceReference.cs index 6bc3ea87e3..e702a131bd 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/MemberTypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/MemberTypeOrNamespaceReference.cs @@ -91,7 +91,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver for (int i = 0; i < typeArgs.Length; i++) { typeArgs[i] = typeArguments[i].Resolve(context); } - ResolveResult rr = r.ResolveMemberType(targetRR, identifier, typeArgs); + ResolveResult rr; + using (var busyLock = BusyManager.Enter(this)) { + if (busyLock.Success) { + rr = r.ResolveMemberType(targetRR, identifier, typeArgs); + } else { + // This can happen for "class Test : $Test.Base$ { public class Base {} }": + return ErrorResolveResult.UnknownError; // don't cache this error + } + } if (cacheManager != null) cacheManager.SetShared(this, rr); return rr; diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs index 39c2c06012..fc9baf6f15 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs @@ -860,5 +860,13 @@ class B Assert.AreEqual("T", m.Parameters[0].Type.Resolve(context).Name); Assert.AreEqual("X", m.Parameters[1].Type.Resolve(context).Name); } + + [Test] + public void InheritingInnerClassShouldNotCauseStackOverflow() + { + string program = @"class Test : $Test.Base$, Test.ITest { public class Base {} interface ITest {} }"; + var result = Resolve(program); + Assert.AreEqual("Test.Base", result.Type.FullName); + } } } diff --git a/ICSharpCode.NRefactory/Utils/BusyManager.cs b/ICSharpCode.NRefactory/Utils/BusyManager.cs index 2c7f161aa4..51704eceeb 100644 --- a/ICSharpCode.NRefactory/Utils/BusyManager.cs +++ b/ICSharpCode.NRefactory/Utils/BusyManager.cs @@ -27,7 +27,7 @@ namespace ICSharpCode.NRefactory.Utils /// However, using a simple 'bool busy' is not thread-safe, so we use a /// thread-static BusyManager. /// - static class BusyManager + public static class BusyManager { public struct BusyLock : IDisposable {