Browse Source

Rename Util to Utils; added replaced "object CacheToken" with "CacheManager CacheManager"

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
2634564ad2
  1. 8
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  2. 31
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs
  3. 6
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  4. 2
      ICSharpCode.NRefactory.Tests/Utils/CSharpPrimitiveCastTests.cs
  5. 2
      ICSharpCode.NRefactory.Tests/Utils/TreeTraversalTests.cs
  6. 8
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  7. 14
      ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs
  8. 11
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  9. 6
      ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
  10. 6
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  11. 2
      ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs
  12. 20
      ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs
  13. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs
  14. 33
      ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs
  15. 8
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs
  16. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
  17. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
  18. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs
  19. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs
  20. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs
  21. 2
      ICSharpCode.NRefactory/Utils/BitVector16.cs
  22. 2
      ICSharpCode.NRefactory/Utils/BusyManager.cs
  23. 2
      ICSharpCode.NRefactory/Utils/CSharpPrimitiveCast.cs
  24. 137
      ICSharpCode.NRefactory/Utils/CacheManager.cs
  25. 2
      ICSharpCode.NRefactory/Utils/TreeTraversal.cs
  26. 15
      README

8
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs

@ -288,6 +288,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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 @@ -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?)));
}
}
}

31
ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs

@ -20,18 +20,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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 @@ -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);
}
}
}

6
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -63,8 +63,8 @@ @@ -63,8 +63,8 @@
<Compile Include="TypeSystem\TypeSystemTests.cs" />
<Compile Include="TypeSystem\TypeSystemTests.TestCase.cs" />
<Compile Include="Untested.cs" />
<Compile Include="Util\CSharpPrimitiveCastTests.cs" />
<Compile Include="Util\TreeTraversalTests.cs" />
<Compile Include="Utils\CSharpPrimitiveCastTests.cs" />
<Compile Include="Utils\TreeTraversalTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
@ -75,7 +75,7 @@ @@ -75,7 +75,7 @@
<ItemGroup>
<Folder Include="CSharp" />
<Folder Include="CSharp\Resolver" />
<Folder Include="Util" />
<Folder Include="Utils" />
<Folder Include="TypeSystem" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />

2
ICSharpCode.NRefactory.Tests/Util/CSharpPrimitiveCastTests.cs → ICSharpCode.NRefactory.Tests/Utils/CSharpPrimitiveCastTests.cs

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
using System;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.Util
namespace ICSharpCode.NRefactory.Utils
{
[TestFixture]
public class CSharpPrimitiveCastTests

2
ICSharpCode.NRefactory.Tests/Util/TreeTraversalTests.cs → ICSharpCode.NRefactory.Tests/Utils/TreeTraversalTests.cs

@ -6,7 +6,7 @@ using System.Collections.Generic; @@ -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

8
ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs

@ -300,7 +300,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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 @@ -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 @@ -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));
}
/// <summary>
@ -1306,7 +1306,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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)

14
ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs

@ -4,9 +4,9 @@ @@ -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 @@ -233,8 +233,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
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 @@ -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

11
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -261,14 +261,15 @@ @@ -261,14 +261,15 @@
<Compile Include="CSharp\Parser\mcs\support.cs" />
<Compile Include="CSharp\Parser\mcs\complete.cs" />
<Compile Include="CSharp\Parser\mcs\literal.cs" />
<Compile Include="Util\BitVector16.cs" />
<Compile Include="Util\BusyManager.cs" />
<Compile Include="Util\CSharpPrimitiveCast.cs" />
<Compile Include="Util\TreeTraversal.cs" />
<Compile Include="Utils\BitVector16.cs" />
<Compile Include="Utils\BusyManager.cs" />
<Compile Include="Utils\CacheManager.cs" />
<Compile Include="Utils\CSharpPrimitiveCast.cs" />
<Compile Include="Utils\TreeTraversal.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="CSharp\Resolver" />
<Folder Include="Util" />
<Folder Include="Utils" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

6
ICSharpCode.NRefactory/TypeSystem/ArrayType.cs

@ -49,13 +49,15 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -49,13 +49,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
public override IEnumerable<IType> GetBaseTypes(ITypeResolveContext context)
{
List<IType> baseTypes = new List<IType>();
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>
t = context.GetClass(typeof(IList<>));
if (t != null)
baseTypes.Add(t);
baseTypes.Add(new ParameterizedType(t, new[] { elementType }));
}
return baseTypes;
}

6
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -3,8 +3,6 @@ @@ -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 @@ -90,7 +88,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
#endregion
#region IsEnum / GetEnumUnderlyingType
#region IsEnum / IsDelegate
/// <summary>
/// Gets whether the type is an enumeration type.
/// </summary>
@ -116,7 +114,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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");
}

2
ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs

@ -23,6 +23,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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?)
/// </summary>
object GetValue(ITypeResolveContext context);
}

20
ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs

@ -5,6 +5,8 @@ using System; @@ -5,6 +5,8 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem
{
/// <summary>
@ -68,20 +70,12 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -68,20 +70,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
ISynchronizedTypeResolveContext Synchronize();
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// 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 <c>return this;</c>.
/// 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.
/// </remarks>
object CacheToken { get; }
CacheManager CacheManager { get; }
}
[ContractClassFor(typeof(ITypeResolveContext))]
@ -121,7 +115,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -121,7 +115,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
return null;
}
object ITypeResolveContext.CacheToken {
Utils.CacheManager ITypeResolveContext.CacheManager {
get { return null; }
}
}

2
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Util;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{

33
ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs

@ -6,6 +6,8 @@ using System.Collections.Generic; @@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
/// <summary>
@ -81,10 +83,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -81,10 +83,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <inheritdoc/>
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 @@ -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 @@ -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 @@ -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 @@ -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);
}
}
}

8
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs

@ -98,6 +98,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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 {

2
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs

@ -7,7 +7,7 @@ using System.Diagnostics.Contracts; @@ -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
{

3
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs

@ -4,7 +4,8 @@ @@ -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
{

2
ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -55,7 +55,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
/// <inheritdoc/>
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; }

4
ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs

@ -7,6 +7,8 @@ using System.Collections.ObjectModel; @@ -7,6 +7,8 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
/// <summary>
@ -154,7 +156,7 @@ 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; }
}

4
ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs

@ -6,6 +6,8 @@ using System.Collections.Generic; @@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
/// <summary>
@ -147,7 +149,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -147,7 +149,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
/// <inheritdoc/>
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.

2
ICSharpCode.NRefactory/Util/BitVector16.cs → ICSharpCode.NRefactory/Utils/BitVector16.cs

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
using System;
namespace ICSharpCode.NRefactory.Util
namespace ICSharpCode.NRefactory.Utils
{
/// <summary>
/// Holds 16 boolean values.

2
ICSharpCode.NRefactory/Util/BusyManager.cs → ICSharpCode.NRefactory/Utils/BusyManager.cs

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.Util
namespace ICSharpCode.NRefactory.Utils
{
/// <summary>
/// This class is used to prevent stack overflows by representing a 'busy' flag

2
ICSharpCode.NRefactory/Util/CSharpPrimitiveCast.cs → ICSharpCode.NRefactory/Utils/CSharpPrimitiveCast.cs

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
using System;
namespace ICSharpCode.NRefactory.Util
namespace ICSharpCode.NRefactory.Utils
{
/// <summary>
/// Static helper method for converting between primitive types.

137
ICSharpCode.NRefactory/Utils/CacheManager.cs

@ -0,0 +1,137 @@ @@ -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
{
/// <summary>
/// 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).
/// </summary>
/// <remarks>This class is thread-safe</remarks>
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;
/// <summary>
/// Registers a new cache type. This causes each CacheManager to allocate space for the new cache type.
/// </summary>
/// <param name="isThreadLocal">Specifies whether this cache is shared (multi-threaded) or whether
/// there is one instance per thread.</param>
/// <returns>Returns a token that can be used to access the cache.</returns>
public static CacheToken<T> RegisterType<T>(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<T>(mode, index);
}
readonly object lockObj = new object();
volatile object[] _sharedCaches = new object[nextSharedIndex];
ThreadLocal<object[]> threadLocalCaches = new ThreadLocal<object[]>(() => new object[nextThreadLocalIndex]);
/// <summary>
/// Gets the cache using the specified token.
/// </summary>
public T Get<T>(CacheToken<T> token) where T : class, new()
{
switch (token.Mode) {
case CacheMode.Shared:
object[] sharedCaches = this._sharedCaches;
if (token.Index < sharedCaches.Length) {
object c = sharedCaches[token.Index];
if (c != null)
return (T)c;
}
// it seems like the cache doesn't exist yet, so try to create it:
T newCache = new T();
lock (lockObj) {
sharedCaches = this._sharedCaches; // fetch fresh value after locking
// use double-checked locking
if (token.Index < sharedCaches.Length) {
object c = sharedCaches[token.Index];
if (c != null) {
// looks like someone else was faster creating it than this thread
return (T)c;
}
} else {
Array.Resize(ref sharedCaches, nextSharedIndex);
this._sharedCaches = sharedCaches;
}
sharedCaches[token.Index] = newCache;
}
return newCache;
case CacheMode.ThreadLocal:
object[] localCaches = threadLocalCaches.Value;
if (token.Index >= localCaches.Length) {
Array.Resize(ref localCaches, nextThreadLocalIndex);
threadLocalCaches.Value = localCaches;
}
object lc = localCaches[token.Index];
if (lc != null) {
return (T)lc;
} else {
T newLocalCache = new T();
localCaches[token.Index] = newLocalCache;
return newLocalCache;
}
default:
throw new ArgumentException("Invalid token");
}
}
*/
public event EventHandler Disposed;
/// <summary>
/// Invokes the <see cref="Disposed"/> event.
/// </summary>
public void Dispose()
{
//threadLocalCaches.Dispose(); // dispose the ThreadLocal<T>
// TODO: test whether this frees the referenced value on all threads
// fire Disposed() only once by removing the old event handlers
EventHandler disposed = Interlocked.Exchange(ref Disposed, null);
if (disposed != null)
disposed(this, EventArgs.Empty);
}
}
/*
public enum CacheMode
{
// don't use 0 so that default(CacheToken<...>) is an invalid mode
Shared = 1,
ThreadLocal = 2
}
public struct CacheToken<T> where T : class, new()
{
internal readonly CacheMode Mode;
internal readonly int Index;
internal CacheToken(CacheMode mode, int index)
{
this.Mode = mode;
this.Index = index;
}
}*/
}

2
ICSharpCode.NRefactory/Util/TreeTraversal.cs → ICSharpCode.NRefactory/Utils/TreeTraversal.cs

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.Util
namespace ICSharpCode.NRefactory.Utils
{
/// <summary>
/// Static helper methods for traversing trees.

15
README

@ -135,3 +135,18 @@ Q: What format do the .ToString() methods use? @@ -135,3 +135,18 @@ Q: What format do the .ToString() methods use?
A: They don't use any particular format. They're merely intended as a debugging aid.
Currently .ToString() usually matches .ReflectionName, but that may change in the future.
Q: Why are there extension methods IType.IsEnum() and IType.IsDelegate(), but no IType.IsStruct() or IType.IsInterface()?
A: Because if you're asking whether a type is a struct, it's very likely that you're asking the wrong question.
The distinction between class/struct/interface/enum/delegate is important in the world of type definitions, and there's
ITypeDefinition.ClassType to address this. But the distinction isn't so important in the world of types.
If whatever you are doing works with struct-types, then it likely will also work with enum-types, and also
with type parameters constraint to be a value-type.
So instead of asking IsStruct(), you really should be asking: IType.IsReferenceType == false
Enums and delegates are special because you can do special things with those types (e.g. subtract them from each other).
If you really need to know, you can do "type.GetDefinition() != null && type.GetDefinition().ClassType == WhatIWant" yourself,
but for the most part you should be fine with IsReferenceType, IsEnum and IsDelegate.

Loading…
Cancel
Save