diff --git a/ICSharpCode.NRefactory/CSharp/Analysis/MinimalResolveContext.cs b/ICSharpCode.NRefactory/CSharp/Analysis/MinimalResolveContext.cs index e7f6380ccb..e2a395d226 100644 --- a/ICSharpCode.NRefactory/CSharp/Analysis/MinimalResolveContext.cs +++ b/ICSharpCode.NRefactory/CSharp/Analysis/MinimalResolveContext.cs @@ -44,14 +44,21 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis private MinimalResolveContext() { List types = new List(); - types.Add(systemObject = new DefaultTypeDefinition(this, "System", "Object") { - Accessibility = Accessibility.Public - }); - types.Add(systemValueType = new DefaultTypeDefinition(this, "System", "ValueType") { - Accessibility = Accessibility.Public, - BaseTypes = { systemObject } - }); + + systemObject = new DefaultTypeDefinition(this, "System", "Object") { + Accessibility = Accessibility.Public + }; + systemValueType = new DefaultTypeDefinition(this, "System", "ValueType") { + Accessibility = Accessibility.Public, + BaseTypes = { systemObject } + }; + // TypeCode.Empty = void + types.Add(new VoidTypeDefinition(this)); + // types are added in the order they are defined in the TypeCode enum + types.Add(systemObject); + types.Add(CreateClass("System", "DBNull")); types.Add(CreateStruct("System", "Boolean")); + types.Add(CreateStruct("System", "Char")); types.Add(CreateStruct("System", "SByte")); types.Add(CreateStruct("System", "Byte")); types.Add(CreateStruct("System", "Int16")); @@ -63,16 +70,23 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis types.Add(CreateStruct("System", "Single")); types.Add(CreateStruct("System", "Double")); types.Add(CreateStruct("System", "Decimal")); - types.Add(new DefaultTypeDefinition(this, "System", "String") { - Accessibility = Accessibility.Public, - BaseTypes = { systemObject } - }); - types.Add(new VoidTypeDefinition(this)); + types.Add(CreateStruct("System", "DateTime")); + types.Add(systemValueType); // misuse unused enum value (TypeCode)17 for System.ValueType + types.Add(CreateClass("System", "String")); foreach (ITypeDefinition type in types) type.Freeze(); this.types = types.AsReadOnly(); } + ITypeDefinition CreateClass(string nameSpace, string name) + { + return new DefaultTypeDefinition(this, nameSpace, name) { + Kind = TypeKind.Class, + Accessibility = Accessibility.Public, + BaseTypes = { systemObject } + }; + } + ITypeDefinition CreateStruct(string nameSpace, string name) { return new DefaultTypeDefinition(this, nameSpace, name) { @@ -91,6 +105,11 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis return null; } + public ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode) + { + return types[(int)typeCode]; + } + public IEnumerable GetTypes() { return types; diff --git a/ICSharpCode.NRefactory/Documentation/IDStringProvider.cs b/ICSharpCode.NRefactory/Documentation/IDStringProvider.cs index e22ed5b9b8..0c28f2a127 100644 --- a/ICSharpCode.NRefactory/Documentation/IDStringProvider.cs +++ b/ICSharpCode.NRefactory/Documentation/IDStringProvider.cs @@ -240,6 +240,15 @@ namespace ICSharpCode.NRefactory.Documentation static int AppendParameterizedTypeName(StringBuilder b, ITypeReference type, IList typeArguments, ITypeResolveContext context) { + KnownTypeReference knownType = type as KnownTypeReference; + if (knownType != null) { + if (!string.IsNullOrEmpty(knownType.Namespace)) { + b.Append(knownType.Namespace); + b.Append('.'); + } + b.Append(knownType.Name); + return 0; + } GetClassTypeReference gctr = type as GetClassTypeReference; if (gctr != null) { if (!string.IsNullOrEmpty(gctr.Namespace)) { diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs index 28dd8e0aa9..6da0ef7fef 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs @@ -32,6 +32,16 @@ namespace ICSharpCode.NRefactory.TypeSystem #endif public interface ITypeResolveContext { + /// + /// Gets the definition for a known type. + /// + /// Returns the type definition; or null if the type was not found + /// + /// This method will may only be called with the 'known types' (see members of KnownTypeReference). + /// As a special case, TypeCode.Empty is used to represent System.Void. + /// + ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode); + /// /// Retrieves a type. /// diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs index 41484d784f..77b71e6b17 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs @@ -66,6 +66,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation this.children = children; } + /// + public virtual ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode) + { + foreach (ITypeResolveContext context in children) { + ITypeDefinition d = context.GetKnownTypeDefinition(typeCode); + if (d != null) + return d; + } + return null; + } + /// public ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer) { @@ -117,7 +128,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (sync[i] == null) throw new InvalidOperationException(children[i] + ".Synchronize() returned null"); } - ISynchronizedTypeResolveContext r = new CompositeSynchronizedTypeResolveContext(sync, new CacheManager(), true); + var knownTypeDefinitions = new ITypeDefinition[ReflectionHelper.ByTypeCodeArraySize]; + var r = new CompositeSynchronizedTypeResolveContext(sync, knownTypeDefinitions, new CacheManager(), true); success = true; return r; } finally { @@ -141,12 +153,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation { readonly CacheManager cacheManager; readonly bool isTopLevel; + readonly ITypeDefinition[] knownTypeDefinitions; - public CompositeSynchronizedTypeResolveContext(ITypeResolveContext[] children, CacheManager cacheManager, bool isTopLevel) + public CompositeSynchronizedTypeResolveContext(ITypeResolveContext[] children, ITypeDefinition[] knownTypeDefinitions, CacheManager cacheManager, bool isTopLevel) : base(children) { Debug.Assert(cacheManager != null); this.cacheManager = cacheManager; + this.knownTypeDefinitions = knownTypeDefinitions; this.isTopLevel = isTopLevel; } @@ -167,11 +181,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return cacheManager; } } + public override ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode) + { + ITypeDefinition typeDef = knownTypeDefinitions[(int)typeCode]; + if (typeDef != null) + return typeDef; + typeDef = base.GetKnownTypeDefinition(typeCode); + knownTypeDefinitions[(int)typeCode] = typeDef; + return typeDef; + } + public override ISynchronizedTypeResolveContext Synchronize() { // re-use the same cache manager for nested synchronized contexts if (isTopLevel) - return new CompositeSynchronizedTypeResolveContext(children, cacheManager, false); + return new CompositeSynchronizedTypeResolveContext(children, knownTypeDefinitions, cacheManager, false); else return this; } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs index c0df2456bd..b2632d0193 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs @@ -81,29 +81,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (context == null) throw new ArgumentNullException("context"); - /* TODO PERF: caching disabled until we measure how much of an advantage it is - * (and whether other approaches like caching only the last N resolve calls in a thread-static cache would work better) - * Maybe even make a distinction between the really common type references (e.g. primitiveTypeReferences) and - * normal GetClassTypeReferences? - CacheManager cacheManager = context.CacheManager; - if (cacheManager != null) { - CachedResult result = this.v_cachedResult; - if (result != null && result.CacheManager == cacheManager) - return result.Result; - IType newResult = DoResolve(context); - this.v_cachedResult = new CachedResult(cacheManager, newResult); - cacheManager.Disposed += delegate { v_cachedResult = null; }; // maybe optimize this to use interface call instead of delegate? - return newResult; - } else { - return DoResolve(context); - } +// CacheManager cache = context.CacheManager; +// if (cache != null) { +// IType cachedType = cache.GetShared(this) as IType; +// if (cachedType != null) +// return cachedType; +// } - } - - IType DoResolve(ITypeResolveContext context) - { - */ - return context.GetTypeDefinition(nameSpace, name, typeParameterCount, StringComparer.Ordinal) ?? SharedTypes.UnknownType; + IType type = context.GetTypeDefinition(nameSpace, name, typeParameterCount, StringComparer.Ordinal) ?? SharedTypes.UnknownType; +// if (cache != null) +// cache.SetShared(this, type); + return type; } public override string ToString() diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs index e9612d1f8c..ee0b06ed60 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs @@ -82,5 +82,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation // it might not be cache-safe. get { return null; } } + + /// + public virtual ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode) + { + return target.GetKnownTypeDefinition(typeCode); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs index c00daf635d..30db64757e 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs @@ -177,6 +177,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation #endregion #region IProjectContent implementation + public ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode) + { + readerWriterLock.EnterReadLock(); + try { + return types.GetKnownTypeDefinition(typeCode); + } finally { + readerWriterLock.ExitReadLock(); + } + } + public ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer) { readerWriterLock.EnterReadLock(); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs index 93d8d46dfe..e8c3ee98de 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs @@ -236,6 +236,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return null; } + /// + public ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode) + { + return GetTypeDefinition("System", ReflectionHelper.GetShortNameByTypeCode(typeCode), 0, StringComparer.Ordinal); + } + /// public IEnumerable GetTypes() { diff --git a/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs index 6255211f6f..b2ad99027a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs @@ -25,87 +25,88 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Contains well-known type references. /// - public static class KnownTypeReference + [Serializable] + public sealed class KnownTypeReference : ITypeReference { /// /// Gets a type reference pointing to the void type. /// - public static readonly ITypeReference Void = new GetClassTypeReference("System", "Void", 0); + public static readonly KnownTypeReference Void = new KnownTypeReference(TypeCode.Empty); /// /// Gets a type reference pointing to the object type. /// - public static readonly ITypeReference Object = new GetClassTypeReference("System", "Object", 0); + public static readonly KnownTypeReference Object = new KnownTypeReference(TypeCode.Object); /// /// Gets a type reference pointing to the bool type. /// - public static readonly ITypeReference Boolean = new GetClassTypeReference("System", "Boolean", 0); + public static readonly KnownTypeReference Boolean = new KnownTypeReference(TypeCode.Boolean); + + /// + /// Gets a type reference pointing to the char type. + /// + public static readonly KnownTypeReference Char = new KnownTypeReference(TypeCode.Char); /// /// Gets a type reference pointing to the sbyte type. /// - public static readonly ITypeReference SByte = new GetClassTypeReference("System", "SByte", 0); + public static readonly KnownTypeReference SByte = new KnownTypeReference(TypeCode.SByte); /// /// Gets a type reference pointing to the byte type. /// - public static readonly ITypeReference Byte = new GetClassTypeReference("System", "Byte", 0); + public static readonly KnownTypeReference Byte = new KnownTypeReference(TypeCode.Byte); /// /// Gets a type reference pointing to the short type. /// - public static readonly ITypeReference Int16 = new GetClassTypeReference("System", "Int16", 0); + public static readonly KnownTypeReference Int16 = new KnownTypeReference(TypeCode.Int16); /// /// Gets a type reference pointing to the ushort type. /// - public static readonly ITypeReference UInt16 = new GetClassTypeReference("System", "UInt16", 0); + public static readonly KnownTypeReference UInt16 = new KnownTypeReference(TypeCode.UInt16); /// /// Gets a type reference pointing to the int type. /// - public static readonly ITypeReference Int32 = new GetClassTypeReference("System", "Int32", 0); + public static readonly KnownTypeReference Int32 = new KnownTypeReference(TypeCode.Int32); /// /// Gets a type reference pointing to the uint type. /// - public static readonly ITypeReference UInt32 = new GetClassTypeReference("System", "UInt32", 0); + public static readonly KnownTypeReference UInt32 = new KnownTypeReference(TypeCode.UInt32); /// /// Gets a type reference pointing to the long type. /// - public static readonly ITypeReference Int64 = new GetClassTypeReference("System", "Int64", 0); + public static readonly KnownTypeReference Int64 = new KnownTypeReference(TypeCode.Int64); /// /// Gets a type reference pointing to the ulong type. /// - public static readonly ITypeReference UInt64 = new GetClassTypeReference("System", "UInt64", 0); - - /// - /// Gets a type reference pointing to the string type. - /// - public static readonly ITypeReference String = new GetClassTypeReference("System", "String", 0); - - /// - /// Gets a type reference pointing to the char type. - /// - public static readonly ITypeReference Char = new GetClassTypeReference("System", "Char", 0); + public static readonly KnownTypeReference UInt64 = new KnownTypeReference(TypeCode.UInt64); /// /// Gets a type reference pointing to the float type. /// - public static readonly ITypeReference Single = new GetClassTypeReference("System", "Single", 0); + public static readonly KnownTypeReference Single = new KnownTypeReference(TypeCode.Single); /// /// Gets a type reference pointing to the double type. /// - public static readonly ITypeReference Double = new GetClassTypeReference("System", "Double", 0); + public static readonly KnownTypeReference Double = new KnownTypeReference(TypeCode.Double); /// /// Gets a type reference pointing to the decimal type. /// - public static readonly ITypeReference Decimal = new GetClassTypeReference("System", "Decimal", 0); + public static readonly KnownTypeReference Decimal = new KnownTypeReference(TypeCode.Decimal); + + /// + /// Gets a type reference pointing to the string type. + /// + public static readonly KnownTypeReference String = new KnownTypeReference(TypeCode.String); /// /// Gets a type reference pointing to the System.Type type. @@ -125,5 +126,25 @@ namespace ICSharpCode.NRefactory.TypeSystem }; } } + + readonly TypeCode typeCode; + + public KnownTypeReference(TypeCode typeCode) + { + this.typeCode = typeCode; + } + + public IType Resolve(ITypeResolveContext context) + { + return context.GetKnownTypeDefinition(typeCode) ?? SharedTypes.UnknownType; + } + + public string Namespace { + get { return "System"; } + } + + public string Name { + get { return ReflectionHelper.GetShortNameByTypeCode(typeCode); } + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs b/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs index 59084ec995..3919f84955 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs @@ -220,37 +220,36 @@ namespace ICSharpCode.NRefactory.TypeSystem #endregion #region GetTypeCode - static readonly Dictionary typeNameToCodeDict = new Dictionary { - { "Object", TypeCode.Object }, - { "DBNull", TypeCode.DBNull }, - { "Boolean", TypeCode.Boolean }, - { "Char", TypeCode.Char }, - { "SByte", TypeCode.SByte }, - { "Byte", TypeCode.Byte }, - { "Int16", TypeCode.Int16 }, - { "UInt16", TypeCode.UInt16 }, - { "Int32", TypeCode.Int32 }, - { "UInt32", TypeCode.UInt32 }, - { "Int64", TypeCode.Int64 }, - { "UInt64", TypeCode.UInt64 }, - { "Single", TypeCode.Single }, - { "Double", TypeCode.Double }, - { "Decimal", TypeCode.Decimal }, - { "DateTime", TypeCode.DateTime }, - { "String", TypeCode.String } + static readonly string[] typeNamesByTypeCode = { + "Void", "Object", "DBNull", "Boolean", "Char", + "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", + "Single", "Double", "Decimal", "DateTime", null, "String" }; + internal static int ByTypeCodeArraySize { + get { return typeNamesByTypeCode.Length; } + } + + internal static string GetShortNameByTypeCode(TypeCode typeCode) + { + return typeNamesByTypeCode[(int)typeCode]; + } + /// /// Gets the type code for the specified type, or TypeCode.Empty if none of the other type codes matches. /// public static TypeCode GetTypeCode(IType type) { ITypeDefinition def = type as ITypeDefinition; - TypeCode typeCode; - if (def != null && def.TypeParameterCount == 0 && def.Namespace == "System" && typeNameToCodeDict.TryGetValue(def.Name, out typeCode)) - return typeCode; - else - return TypeCode.Empty; + if (def != null && def.TypeParameterCount == 0 && def.Namespace == "System") { + string[] typeNames = typeNamesByTypeCode; + string name = def.Name; + for (int i = 1; i < typeNames.Length; i++) { + if (name == typeNames[i]) + return (TypeCode)i; + } + } + return TypeCode.Empty; } #endregion