diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
index 1901f7f406..176c78323c 100644
--- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
+++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
@@ -288,6 +288,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreEqual(1, BetterConversion(typeof(short), typeof(int), typeof(long)));
Assert.AreEqual(1, BetterConversion(typeof(short), typeof(int), typeof(uint)));
Assert.AreEqual(2, BetterConversion(typeof(ushort), typeof(uint), typeof(int)));
+ Assert.AreEqual(1, BetterConversion(typeof(char), typeof(short), typeof(int)));
+ Assert.AreEqual(1, BetterConversion(typeof(char), typeof(ushort), typeof(int)));
+ Assert.AreEqual(1, BetterConversion(typeof(sbyte), typeof(long), typeof(ulong)));
+ Assert.AreEqual(2, BetterConversion(typeof(byte), typeof(ushort), typeof(short)));
+
+ Assert.AreEqual(1, BetterConversion(1, typeof(sbyte), typeof(byte)));
+ Assert.AreEqual(2, BetterConversion(1, typeof(ushort), typeof(sbyte)));
}
[Test]
@@ -302,6 +309,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreEqual(2, BetterConversion(typeof(byte), typeof(ulong?), typeof(uint)));
Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(ulong?), typeof(int)));
Assert.AreEqual(2, BetterConversion(typeof(ushort?), typeof(long?), typeof(int?)));
+ Assert.AreEqual(0, BetterConversion(typeof(sbyte), typeof(int?), typeof(uint?)));
}
}
}
diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs
index 72a60d7d8e..1f7c3cc008 100644
--- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs
+++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs
@@ -20,18 +20,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return argumentTypes.Select(t => new ResolveResult(t.ToTypeReference().Resolve(context))).ToArray();
}
- DefaultMethod MakeMethod(params Type[] parameterTypes)
+ DefaultMethod MakeMethod(params object[] parameterTypesOrDefaultValues)
{
DefaultMethod m = new DefaultMethod(dummyClass, "Method");
- foreach (var type in parameterTypes) {
- m.Parameters.Add(new DefaultParameter(type.ToTypeReference(), string.Empty));
+ foreach (var typeOrDefaultValue in parameterTypesOrDefaultValues) {
+ Type type = typeOrDefaultValue as Type;
+ if (type != null)
+ m.Parameters.Add(new DefaultParameter(type.ToTypeReference(), string.Empty));
+ else if (Type.GetTypeCode(typeOrDefaultValue.GetType()) > TypeCode.Object)
+ m.Parameters.Add(new DefaultParameter(typeOrDefaultValue.GetType().ToTypeReference(), string.Empty) {
+ DefaultValue = new SimpleConstantValue(typeOrDefaultValue.GetType().ToTypeReference(), typeOrDefaultValue)
+ });
+ else
+ throw new ArgumentException(typeOrDefaultValue.ToString());
}
return m;
}
- DefaultMethod MakeParamsMethod(params Type[] parameterTypes)
+ DefaultMethod MakeParamsMethod(params object[] parameterTypesOrDefaultValues)
{
- DefaultMethod m = MakeMethod(parameterTypes);
+ DefaultMethod m = MakeMethod(parameterTypesOrDefaultValues);
((DefaultParameter)m.Parameters.Last()).IsParams = true;
return m;
}
@@ -102,5 +110,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreEqual(OverloadResolutionErrors.ArgumentTypeMismatch, r.AddCandidate(MakeParamsMethod(typeof(int))));
Assert.IsFalse(r.BestCandidateIsExpandedForm);
}
+
+ [Test]
+ public void PreferMethodWithoutOptionalParameters()
+ {
+ var m1 = MakeMethod();
+ var m2 = MakeMethod(1);
+
+ OverloadResolution r = new OverloadResolution(context, MakeArgumentList());
+ Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
+ Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
+ Assert.IsFalse(r.IsAmbiguous);
+ Assert.AreSame(m1, r.BestCandidate);
+ }
}
}
diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
index 2f3aa3af46..55095c94c5 100644
--- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
+++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
@@ -63,8 +63,8 @@
-
-
+
+
@@ -75,7 +75,7 @@
-
+
diff --git a/ICSharpCode.NRefactory.Tests/Util/CSharpPrimitiveCastTests.cs b/ICSharpCode.NRefactory.Tests/Utils/CSharpPrimitiveCastTests.cs
similarity index 98%
rename from ICSharpCode.NRefactory.Tests/Util/CSharpPrimitiveCastTests.cs
rename to ICSharpCode.NRefactory.Tests/Utils/CSharpPrimitiveCastTests.cs
index f03531081d..fc73adcd71 100644
--- a/ICSharpCode.NRefactory.Tests/Util/CSharpPrimitiveCastTests.cs
+++ b/ICSharpCode.NRefactory.Tests/Utils/CSharpPrimitiveCastTests.cs
@@ -4,7 +4,7 @@
using System;
using NUnit.Framework;
-namespace ICSharpCode.NRefactory.Util
+namespace ICSharpCode.NRefactory.Utils
{
[TestFixture]
public class CSharpPrimitiveCastTests
diff --git a/ICSharpCode.NRefactory.Tests/Util/TreeTraversalTests.cs b/ICSharpCode.NRefactory.Tests/Utils/TreeTraversalTests.cs
similarity index 96%
rename from ICSharpCode.NRefactory.Tests/Util/TreeTraversalTests.cs
rename to ICSharpCode.NRefactory.Tests/Utils/TreeTraversalTests.cs
index 9def9c4a0a..dae0f43c81 100644
--- a/ICSharpCode.NRefactory.Tests/Util/TreeTraversalTests.cs
+++ b/ICSharpCode.NRefactory.Tests/Utils/TreeTraversalTests.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
-namespace ICSharpCode.NRefactory.Util
+namespace ICSharpCode.NRefactory.Utils
{
[TestFixture]
public class TreeTraversalTests
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
index 4cd75ea666..de945defb2 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
@@ -300,7 +300,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
switch (op) {
case UnaryOperatorType.Minus:
if (code == TypeCode.UInt32) {
- IType targetType = context.GetClass(typeof(long)) ?? SharedTypes.UnknownType;
+ IType targetType = TypeCode.Int64.ToTypeReference().Resolve(context);
type = targetType;
if (isNullable) targetType = NullableType.Create(targetType, context);
return ResolveCast(targetType, expression);
@@ -309,7 +309,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case UnaryOperatorType.Plus:
case UnaryOperatorType.BitNot:
if (code >= TypeCode.Char && code <= TypeCode.UInt16) {
- IType targetType = context.GetClass(typeof(int)) ?? SharedTypes.UnknownType;
+ IType targetType = TypeCode.Int32.ToTypeReference().Resolve(context);
type = targetType;
if (isNullable) targetType = NullableType.Create(targetType, context);
return ResolveCast(targetType, expression);
@@ -676,7 +676,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return rhs;
return ResolveBinaryOperator(op, lhs, rhs);
}
- return new ResolveResult(context.GetClass(typeof(bool)) ?? SharedTypes.UnknownType);
+ return new ResolveResult(TypeCode.Boolean.ToTypeReference().Resolve(context));
}
///
@@ -1306,7 +1306,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
object CSharpPrimitiveCast(TypeCode targetType, object input)
{
- return Util.CSharpPrimitiveCast.Cast(targetType, input, this.CheckForOverflow);
+ return Utils.CSharpPrimitiveCast.Cast(targetType, input, this.CheckForOverflow);
}
ResolveResult CheckErrorAndResolveCast(IType targetType, ResolveResult expression)
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs
index 0ffe159d83..cb48d6d430 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs
@@ -4,9 +4,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
-using ICSharpCode.NRefactory.Util;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
@@ -233,8 +233,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
///
int BetterFunctionMember(Candidate c1, Candidate c2)
{
- if (c1.ErrorCount < c2.ErrorCount) return 1;
- if (c1.ErrorCount > c2.ErrorCount) return 2;
+ // prefer applicable members (part of heuristic that produces a best candidate even if none is applicable)
+ if (c1.ErrorCount == 0 && c2.ErrorCount > 0)
+ return 1;
+ if (c1.ErrorCount > 0 && c2.ErrorCount == 0)
+ return 2;
// C# 4.0 spec: §7.5.3.2 Better function member
bool c1IsBetter = false;
@@ -261,6 +264,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return 1;
if (!c1IsBetter && c2IsBetter)
return 2;
+
+ // prefer members with less errors (part of heuristic that produces a best candidate even if none is applicable)
+ if (c1.ErrorCount < c2.ErrorCount) return 1;
+ if (c1.ErrorCount > c2.ErrorCount) return 2;
+
if (!c1IsBetter && !c2IsBetter) {
// we need the tie-breaking rules
diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
index a94dc4e16d..eae194c109 100644
--- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
+++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
@@ -261,14 +261,15 @@
-
-
-
-
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
index f4ac157255..8fcbc60b0c 100644
--- a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
@@ -49,13 +49,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
public override IEnumerable GetBaseTypes(ITypeResolveContext context)
{
List baseTypes = new List();
- IType t = context.GetClass(typeof(Array));
+ // PERF: if profiling shows the GetClass(typeof()) here to be a problem, create
+ // a static cache for the ITypeDefinitions
+ ITypeDefinition t = context.GetClass(typeof(Array));
if (t != null)
baseTypes.Add(t);
if (dimensions == 1) { // single-dimensional arrays implement IList
t = context.GetClass(typeof(IList<>));
if (t != null)
- baseTypes.Add(t);
+ baseTypes.Add(new ParameterizedType(t, new[] { elementType }));
}
return baseTypes;
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
index a13104e239..fd2eede773 100644
--- a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
@@ -3,8 +3,6 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using ICSharpCode.NRefactory.Util;
namespace ICSharpCode.NRefactory.TypeSystem
{
@@ -90,7 +88,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
#endregion
- #region IsEnum / GetEnumUnderlyingType
+ #region IsEnum / IsDelegate
///
/// Gets whether the type is an enumeration type.
///
@@ -116,7 +114,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (def.BaseTypes.Count == 1)
return def.BaseTypes[0].Resolve(context);
else
- return context.GetClass(typeof(int)) ?? SharedTypes.UnknownType;
+ return TypeCode.Int32.ToTypeReference().Resolve(context);
} else {
throw new ArgumentException("enumType must be an enum");
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs b/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs
index 14e421ea41..d27354dd37 100644
--- a/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs
@@ -23,6 +23,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// - string
/// - IType (for typeof-expressions)
/// and arrays of these values. Enum values are returned using the underlying primitive integer.
+ ///
+ /// TODO: how do we represent errors (value not available?)
///
object GetValue(ITypeResolveContext context);
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs
index c2a42172cf..177c6efb60 100644
--- a/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs
@@ -5,6 +5,8 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
+using ICSharpCode.NRefactory.Utils;
+
namespace ICSharpCode.NRefactory.TypeSystem
{
///
@@ -68,20 +70,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
ISynchronizedTypeResolveContext Synchronize();
///
- /// Returns an object if caching information based on this resolve context is allowed,
+ /// Returns the cache manager associated with this resolve context,
/// or null if caching is not allowed.
- /// Whenever the resolve context changes in some way, this property must return a new object.
+ /// Whenever the resolve context changes in some way, this property must return a new object to
+ /// ensure that old caches are cleared.
///
- ///
- /// This allows consumers to see whether their cache is still valid by comparing the current
- /// CacheToken with the one they saw before.
- ///
- /// For ISynchronizedTypeResolveContext, this property could be implemented as return this;.
- /// However, it is a bad idea to use an object is large or that references a large object graph
- /// -- consumers may store a reference to the cache token indefinately, possible extending the
- /// lifetime of the ITypeResolveContext.
- ///
- object CacheToken { get; }
+ CacheManager CacheManager { get; }
}
[ContractClassFor(typeof(ITypeResolveContext))]
@@ -121,7 +115,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
return null;
}
- object ITypeResolveContext.CacheToken {
+ Utils.CacheManager ITypeResolveContext.CacheManager {
get { return null; }
}
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs
index adc85ab49e..289feb6703 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs
@@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
-using ICSharpCode.NRefactory.Util;
+using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs
index 25534bb86a..ec6c12386b 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using ICSharpCode.NRefactory.Utils;
+
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
///
@@ -81,10 +83,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
///
public virtual ISynchronizedTypeResolveContext Synchronize()
{
- return Synchronize(new object());
+ return Synchronize(new CacheManager(), true);
}
- ISynchronizedTypeResolveContext Synchronize(object cacheToken)
+ ISynchronizedTypeResolveContext Synchronize(CacheManager cacheManager, bool isTopLevel)
{
ISynchronizedTypeResolveContext[] sync = new ISynchronizedTypeResolveContext[children.Length];
bool success = false;
@@ -94,7 +96,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
if (sync[i] == null)
throw new InvalidOperationException(children[i] + ".ToString() returned null");
}
- ISynchronizedTypeResolveContext r = new CompositeSynchronizedTypeResolveContext(sync, cacheToken);
+ ISynchronizedTypeResolveContext r = new CompositeSynchronizedTypeResolveContext(sync, cacheManager, isTopLevel);
success = true;
return r;
} finally {
@@ -108,7 +110,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
- public virtual object CacheToken {
+ public virtual CacheManager CacheManager {
// We don't know if our input contexts are mutable, so, to be on the safe side,
// we don't implement caching here.
get { return null; }
@@ -116,13 +118,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
sealed class CompositeSynchronizedTypeResolveContext : CompositeTypeResolveContext, ISynchronizedTypeResolveContext
{
- readonly object cacheToken;
+ readonly CacheManager cacheManager;
+ readonly bool isTopLevel;
- public CompositeSynchronizedTypeResolveContext(ISynchronizedTypeResolveContext[] children, object cacheToken)
+ public CompositeSynchronizedTypeResolveContext(ISynchronizedTypeResolveContext[] children, CacheManager cacheManager, bool isTopLevel)
: base(children)
{
- Debug.Assert(cacheToken != null);
- this.cacheToken = cacheToken;
+ Debug.Assert(cacheManager != null);
+ this.cacheManager = cacheManager;
+ this.isTopLevel = isTopLevel;
}
public void Dispose()
@@ -130,18 +134,23 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
foreach (ISynchronizedTypeResolveContext element in children) {
element.Dispose();
}
+ if (isTopLevel) {
+ // When the top-level synchronized block is closed, clear any cached data
+ // (the cache token isn't valid anymore)
+ cacheManager.Dispose();
+ }
}
- public override object CacheToken {
+ public override CacheManager CacheManager {
// I expect CompositeTypeResolveContext to be used for almost all resolver operations,
- // so this is the only place where implementing cacheToken is really important.
- get { return cacheToken; }
+ // so this is the only place where implementing CacheManager is really important.
+ get { return cacheManager; }
}
public override ISynchronizedTypeResolveContext Synchronize()
{
// re-use the same cache token for nested synchronized contexts
- return base.Synchronize(cacheToken);
+ return base.Synchronize(cacheManager, false);
}
}
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs
index d886df57e5..ceef58b593 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs
@@ -98,6 +98,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
+ public object GetDefaultValue(ITypeResolveContext context)
+ {
+ if (defaultValue == null)
+ throw new InvalidOperationException();
+ else
+ return defaultValue.GetValue(context);
+ }
+
public DomRegion Region {
get { return region; }
set {
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
index 4aa8c80cb6..f4a7e74d33 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
@@ -7,7 +7,7 @@ using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
-using ICSharpCode.NRefactory.Util;
+using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
index 9d098ebff9..1d137aa494 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
@@ -4,7 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using ICSharpCode.NRefactory.Util;
+
+using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs
index 8ed811d13a..2f64267ab7 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs
@@ -55,7 +55,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
///
- public virtual object CacheToken {
+ public virtual Utils.CacheManager CacheManager {
// Don't forward this by default; we don't know what derived classes are doing;
// it might not be cache-safe.
get { return null; }
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs
index 5b1da950c2..47fe35d53b 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs
@@ -7,6 +7,8 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
+using ICSharpCode.NRefactory.Utils;
+
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
///
@@ -154,7 +156,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
#endregion
#region Synchronization
- public object CacheToken {
+ public CacheManager CacheManager {
get { return null; }
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs
index ae712b638d..a7d0d87208 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
+using ICSharpCode.NRefactory.Utils;
+
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
///
@@ -147,7 +149,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
///
- public object CacheToken {
+ public CacheManager CacheManager {
// TypeStorage is mutable, so caching is a bad idea.
// We could provide a CacheToken if we update it on every modication, but
// that's not worth the effort as TypeStorage is rarely directly used in resolve operations.
diff --git a/ICSharpCode.NRefactory/Util/BitVector16.cs b/ICSharpCode.NRefactory/Utils/BitVector16.cs
similarity index 97%
rename from ICSharpCode.NRefactory/Util/BitVector16.cs
rename to ICSharpCode.NRefactory/Utils/BitVector16.cs
index e6c4ff72e7..82f4124070 100644
--- a/ICSharpCode.NRefactory/Util/BitVector16.cs
+++ b/ICSharpCode.NRefactory/Utils/BitVector16.cs
@@ -3,7 +3,7 @@
using System;
-namespace ICSharpCode.NRefactory.Util
+namespace ICSharpCode.NRefactory.Utils
{
///
/// Holds 16 boolean values.
diff --git a/ICSharpCode.NRefactory/Util/BusyManager.cs b/ICSharpCode.NRefactory/Utils/BusyManager.cs
similarity index 97%
rename from ICSharpCode.NRefactory/Util/BusyManager.cs
rename to ICSharpCode.NRefactory/Utils/BusyManager.cs
index bf6cb7e6fb..27f9901a00 100644
--- a/ICSharpCode.NRefactory/Util/BusyManager.cs
+++ b/ICSharpCode.NRefactory/Utils/BusyManager.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
-namespace ICSharpCode.NRefactory.Util
+namespace ICSharpCode.NRefactory.Utils
{
///
/// This class is used to prevent stack overflows by representing a 'busy' flag
diff --git a/ICSharpCode.NRefactory/Util/CSharpPrimitiveCast.cs b/ICSharpCode.NRefactory/Utils/CSharpPrimitiveCast.cs
similarity index 99%
rename from ICSharpCode.NRefactory/Util/CSharpPrimitiveCast.cs
rename to ICSharpCode.NRefactory/Utils/CSharpPrimitiveCast.cs
index 3f40718f6f..e7cfbdb911 100644
--- a/ICSharpCode.NRefactory/Util/CSharpPrimitiveCast.cs
+++ b/ICSharpCode.NRefactory/Utils/CSharpPrimitiveCast.cs
@@ -3,7 +3,7 @@
using System;
-namespace ICSharpCode.NRefactory.Util
+namespace ICSharpCode.NRefactory.Utils
{
///
/// Static helper method for converting between primitive types.
diff --git a/ICSharpCode.NRefactory/Utils/CacheManager.cs b/ICSharpCode.NRefactory/Utils/CacheManager.cs
new file mode 100644
index 0000000000..bfb05248e8
--- /dev/null
+++ b/ICSharpCode.NRefactory/Utils/CacheManager.cs
@@ -0,0 +1,137 @@
+// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.Threading;
+
+namespace ICSharpCode.NRefactory.Utils
+{
+ ///
+ /// Allows the registration of static "caching types" which can then be used to efficiently retrieve an
+ /// instance per CacheManager (or even per CacheManager and thread).
+ ///
+ /// This class is thread-safe
+ public sealed class CacheManager : IDisposable
+ {
+ /* Lots of code commented out because I don't know if it's useful, clients can usually replicate
+ * the functionality much more easily and only need the Disposed event to ensure cleanup.
+ *
+ * Actually, what I've implemented here looks very much like .NET's internal System.LocalDataStore
+ * (used for Thread.GetData/SetData)
+ *
+ static int nextSharedIndex, nextThreadLocalIndex;
+
+ ///
+ /// Registers a new cache type. This causes each CacheManager to allocate space for the new cache type.
+ ///
+ /// Specifies whether this cache is shared (multi-threaded) or whether
+ /// there is one instance per thread.
+ /// Returns a token that can be used to access the cache.
+ public static CacheToken RegisterType(CacheMode mode) where T : class, new()
+ {
+ int index;
+ switch (mode) {
+ case CacheMode.Shared:
+ index = Interlocked.Increment(ref nextSharedIndex);
+ break;
+ case CacheMode.ThreadLocal:
+ index = Interlocked.Increment(ref nextThreadLocalIndex);
+ break;
+ default:
+ throw new ArgumentException("Invalid value for CacheMode", "mode");
+ }
+ return new CacheToken(mode, index);
+ }
+
+ readonly object lockObj = new object();
+ volatile object[] _sharedCaches = new object[nextSharedIndex];
+ ThreadLocal