From c869a4fc16ac0f189be87ceb821047f886d17ff1 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 9 Mar 2018 22:50:50 +0100 Subject: [PATCH] Fix #1085: The type system can now parameterize not just type definitions, but also unknown types. This improves decompilation when references assemblies cannot be found. --- .../CSharp/Resolver/CSharpConversions.cs | 9 ++- .../CSharp/Resolver/TypeInference.cs | 12 ++-- .../CSharp/Syntax/TypeSystemAstBuilder.cs | 58 ++++++++-------- .../TypeSystem/DecompilerTypeSystem.cs | 7 +- ICSharpCode.Decompiler/TypeSystem/IType.cs | 6 ++ .../TypeSystem/ITypeDefinition.cs | 2 - .../AbstractResolvedTypeParameter.cs | 6 +- .../TypeSystem/Implementation/AbstractType.cs | 7 +- .../DefaultResolvedTypeDefinition.cs | 6 +- .../Implementation/DummyTypeParameter.cs | 37 +++++++++- .../TypeSystem/Implementation/UnknownType.cs | 9 +-- .../TypeSystem/NullableType.cs | 4 +- .../TypeSystem/ParameterizedType.cs | 69 ++++++++----------- 13 files changed, 130 insertions(+), 102 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs index dbd211f6f..35cbdc6c1 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs @@ -477,9 +477,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver { ParameterizedType pt = interfaceType as ParameterizedType; if (pt != null) { - KnownTypeCode tc = pt.GetDefinition().KnownTypeCode; - if (tc == KnownTypeCode.IListOfT || tc == KnownTypeCode.ICollectionOfT || tc == KnownTypeCode.IEnumerableOfT || tc == KnownTypeCode.IReadOnlyListOfT) { - return pt.GetTypeArgument(0); + switch (pt.GetDefinition()?.KnownTypeCode) { + case KnownTypeCode.IListOfT: + case KnownTypeCode.ICollectionOfT: + case KnownTypeCode.IEnumerableOfT: + case KnownTypeCode.IReadOnlyListOfT: + return pt.GetTypeArgument(0); } } return null; diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs index 8e5cab2bc..e3f1dcac2 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs @@ -596,7 +596,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver ParameterizedType pU = U as ParameterizedType; ParameterizedType pV = V as ParameterizedType; if (pU != null && pV != null - && object.Equals(pU.GetDefinition(), pV.GetDefinition()) + && object.Equals(pU.GenericType, pV.GenericType) && pU.TypeParameterCount == pV.TypeParameterCount) { Log.Indent(); @@ -657,7 +657,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver ParameterizedType uniqueBaseType = null; foreach (IType baseU in U.GetAllBaseTypes()) { ParameterizedType pU = baseU as ParameterizedType; - if (pU != null && object.Equals(pU.GetDefinition(), pV.GetDefinition()) && pU.TypeParameterCount == pV.TypeParameterCount) { + if (pU != null && object.Equals(pU.GenericType, pV.GenericType) && pU.TypeParameterCount == pV.TypeParameterCount) { if (uniqueBaseType == null) uniqueBaseType = pU; else @@ -671,7 +671,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver IType Vi = pV.GetTypeArgument(i); if (Ui.IsReferenceType == true) { // look for variance - ITypeParameter Xi = pV.GetDefinition().TypeParameters[i]; + ITypeParameter Xi = pV.TypeParameters[i]; switch (Xi.Variance) { case VarianceModifier.Covariant: MakeLowerBoundInference(Ui, Vi); @@ -697,7 +697,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver { if (rt == null || rt.TypeParameterCount != 1) return false; - switch (rt.GetDefinition().KnownTypeCode) { + switch (rt.GetDefinition()?.KnownTypeCode) { case KnownTypeCode.IEnumerableOfT: case KnownTypeCode.ICollectionOfT: case KnownTypeCode.IListOfT: @@ -743,7 +743,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver ParameterizedType uniqueBaseType = null; foreach (IType baseV in V.GetAllBaseTypes()) { ParameterizedType pV = baseV as ParameterizedType; - if (pV != null && object.Equals(pU.GetDefinition(), pV.GetDefinition()) && pU.TypeParameterCount == pV.TypeParameterCount) { + if (pV != null && object.Equals(pU.GenericType, pV.GenericType) && pU.TypeParameterCount == pV.TypeParameterCount) { if (uniqueBaseType == null) uniqueBaseType = pV; else @@ -757,7 +757,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver IType Vi = uniqueBaseType.GetTypeArgument(i); if (Ui.IsReferenceType == true) { // look for variance - ITypeParameter Xi = pU.GetDefinition().TypeParameters[i]; + ITypeParameter Xi = pU.TypeParameters[i]; switch (Xi.Variance) { case VarianceModifier.Covariant: MakeUpperBoundInference(Ui, Vi); diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index c9949ab40..e86971177 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -233,10 +233,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax } ParameterizedType pt = type as ParameterizedType; if (pt != null) { - if (pt.Name == "Nullable" && pt.Namespace == "System" && pt.TypeParameterCount == 1) { + if (pt.IsKnownType(KnownTypeCode.NullableOfT)) { return ConvertType(pt.TypeArguments[0]).MakeNullableType(); } - return ConvertTypeHelper(pt.GetDefinition(), pt.TypeArguments); + return ConvertTypeHelper(pt.GenericType, pt.TypeArguments); } ITypeDefinition typeDef = type as ITypeDefinition; if (typeDef != null) { @@ -254,22 +254,22 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax return new SimpleType(type.Name); } - AstType ConvertTypeHelper(ITypeDefinition typeDef, IReadOnlyList typeArguments) + AstType ConvertTypeHelper(IType genericType, IReadOnlyList typeArguments) { - Debug.Assert(typeArguments.Count >= typeDef.TypeParameterCount); - - string keyword = KnownTypeReference.GetCSharpNameByTypeCode(typeDef.KnownTypeCode); - if (keyword != null) - return new PrimitiveType(keyword); + Debug.Assert(typeArguments.Count >= genericType.TypeParameterCount); + Debug.Assert(genericType is ITypeDefinition || genericType.Kind == TypeKind.Unknown); + + ITypeDefinition typeDef = genericType as ITypeDefinition; + if (typeDef != null) { + string keyword = KnownTypeReference.GetCSharpNameByTypeCode(typeDef.KnownTypeCode); + if (keyword != null) + return new PrimitiveType(keyword); + } // The number of type parameters belonging to outer classes - int outerTypeParameterCount; - if (typeDef.DeclaringType != null) - outerTypeParameterCount = typeDef.DeclaringType.TypeParameterCount; - else - outerTypeParameterCount = 0; + int outerTypeParameterCount = genericType.DeclaringType?.TypeParameterCount ?? 0; - if (resolver != null) { + if (resolver != null && typeDef != null) { // Look if there's an alias to the target type if (UseAliases) { for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) { @@ -297,32 +297,32 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax if (!trr.IsError && TypeMatches(trr.Type, typeDef, typeArguments)) { // We can use the short type name SimpleType shortResult = new SimpleType(typeDef.Name); - AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount); + AddTypeArguments(shortResult, typeDef.TypeParameters, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount); return shortResult; } } } - if (AlwaysUseShortTypeNames) { - var shortResult = new SimpleType(typeDef.Name); - AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount); + if (AlwaysUseShortTypeNames || (typeDef == null && genericType.DeclaringType == null)) { + var shortResult = new SimpleType(genericType.Name); + AddTypeArguments(shortResult, genericType.TypeParameters, typeArguments, outerTypeParameterCount, genericType.TypeParameterCount); return shortResult; } MemberType result = new MemberType(); - if (typeDef.DeclaringTypeDefinition != null) { + if (genericType.DeclaringType != null) { // Handle nested types - result.Target = ConvertTypeHelper(typeDef.DeclaringTypeDefinition, typeArguments); + result.Target = ConvertTypeHelper(genericType.DeclaringType, typeArguments); } else { // Handle top-level types - if (string.IsNullOrEmpty(typeDef.Namespace)) { + if (string.IsNullOrEmpty(genericType.Namespace)) { result.Target = new SimpleType("global"); result.IsDoubleColon = true; } else { - result.Target = ConvertNamespace(typeDef.Namespace); + result.Target = ConvertNamespace(genericType.Namespace); } } - result.MemberName = typeDef.Name; - AddTypeArguments(result, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount); + result.MemberName = genericType.Name; + AddTypeArguments(result, genericType.TypeParameters, typeArguments, outerTypeParameterCount, genericType.TypeParameterCount); return result; } @@ -348,21 +348,21 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax return true; } } - + /// /// Adds type arguments to the result type. /// /// The result AST node (a SimpleType or MemberType) - /// The type definition that owns the type parameters + /// The type parameters /// The list of type arguments /// Index of first type argument to add /// Index after last type argument to add - void AddTypeArguments(AstType result, ITypeDefinition typeDef, IReadOnlyList typeArguments, int startIndex, int endIndex) + void AddTypeArguments(AstType result, IReadOnlyList typeParameters, IReadOnlyList typeArguments, int startIndex, int endIndex) { - Debug.Assert(endIndex <= typeDef.TypeParameterCount); + Debug.Assert(endIndex <= typeParameters.Count); for (int i = startIndex; i < endIndex; i++) { if (ConvertUnboundTypeArguments && typeArguments[i].Kind == TypeKind.UnboundTypeArgument) { - result.AddChild(new SimpleType(typeDef.TypeParameters[i].Name), Roles.TypeArgument); + result.AddChild(new SimpleType(typeParameters[i].Name), Roles.TypeArgument); } else { result.AddChild(ConvertType(typeArguments[i]), Roles.TypeArgument); } diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index ea3782e97..f0c20804b 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -223,9 +223,6 @@ namespace ICSharpCode.Decompiler.TypeSystem IMethod method; if (!methodLookupCache.TryGetValue(methodReference, out method)) { method = FindNonGenericMethod(methodReference.GetElementMethod()); - if (method == null) { - method = CreateFakeMethod(methodReference); - } if (methodReference.CallingConvention == MethodCallingConvention.VarArg) { method = new VarArgInstanceMethod( method, @@ -254,7 +251,7 @@ namespace ICSharpCode.Decompiler.TypeSystem { ITypeDefinition typeDef = Resolve(methodReference.DeclaringType).GetDefinition(); if (typeDef == null) - return null; + return CreateFakeMethod(methodReference); IEnumerable methods; if (methodReference.Name == ".ctor") { methods = typeDef.GetConstructors(); @@ -286,7 +283,7 @@ namespace ICSharpCode.Decompiler.TypeSystem continue; return method; } - return null; + return CreateFakeMethod(methodReference); } static bool CompareTypes(IType a, IType b) diff --git a/ICSharpCode.Decompiler/TypeSystem/IType.cs b/ICSharpCode.Decompiler/TypeSystem/IType.cs index 2d3b66796..39ab79163 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IType.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IType.cs @@ -81,6 +81,12 @@ namespace ICSharpCode.Decompiler.TypeSystem /// int TypeParameterCount { get; } + /// + /// Gets the type parameters. + /// Returns an empty list if this type is not generic. + /// + IReadOnlyList TypeParameters { get; } + /// /// Gets the type arguments passed to this type. /// If this type is a generic type definition that is not parameterized, this property returns the type parameters, diff --git a/ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs index bf15c1f51..fde2ac004 100644 --- a/ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs +++ b/ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs @@ -101,8 +101,6 @@ namespace ICSharpCode.Decompiler.TypeSystem /// Non-partial classes have a single part that represents the whole class. /// IReadOnlyList Parts { get; } - - IReadOnlyList TypeParameters { get; } IReadOnlyList NestedTypes { get; } IReadOnlyList Members { get; } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs index cb4c283e1..63db9706c 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs @@ -204,8 +204,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return 0; } } + IReadOnlyList IType.TypeParameters { + get { return EmptyList.Instance; } + } + IReadOnlyList IType.TypeArguments { - get { return Empty.Array; } + get { return EmptyList.Instance; } } public abstract IEnumerable DirectBaseTypes { get; } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs index 8db2c5734..0562f7bfb 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs @@ -59,9 +59,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return 0; } } - readonly static IReadOnlyList emptyTypeArguments = new IType[0]; + public virtual IReadOnlyList TypeParameters { + get { return EmptyList.Instance; } + } + public virtual IReadOnlyList TypeArguments { - get { return emptyTypeArguments; } + get { return EmptyList.Instance; } } public virtual IType DeclaringType { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs index d6194370f..884219d21 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs @@ -457,11 +457,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return parts[0].TypeParameters.Count; } } - public IReadOnlyList TypeArguments { - get { - return TypeParameters; - } - } + public IReadOnlyList TypeArguments => TypeParameters; #region DirectBaseTypes IList directBaseTypes; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs index 114f03dcc..94928c156 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs @@ -16,6 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; using System.Collections.Generic; using System.Threading; using ICSharpCode.Decompiler.Util; @@ -26,6 +27,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation { static ITypeParameter[] methodTypeParameters = { new DummyTypeParameter(SymbolKind.Method, 0) }; static ITypeParameter[] classTypeParameters = { new DummyTypeParameter(SymbolKind.TypeDefinition, 0) }; + static IReadOnlyList[] classTypeParameterLists = { EmptyList.Instance }; public static ITypeParameter GetMethodTypeParameter(int index) { @@ -60,7 +62,38 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } return tps[index]; } - + + /// + /// Gets a list filled with dummy type parameters. + /// + internal static IReadOnlyList GetClassTypeParameterList(int length) + { + IReadOnlyList[] tps = classTypeParameterLists; + while (length >= tps.Length) { + // We don't have a normal type parameter for this index, so we need to extend our array. + // Because the array can be used concurrently from multiple threads, we have to use + // Interlocked.CompareExchange. + IReadOnlyList[] newTps = new IReadOnlyList[length + 1]; + tps.CopyTo(newTps, 0); + for (int i = tps.Length; i < newTps.Length; i++) { + var newList = new ITypeParameter[i]; + for (int j = 0; j < newList.Length; j++) { + newList[j] = GetClassTypeParameter(j); + } + newTps[i] = newList; + } + var oldTps = Interlocked.CompareExchange(ref classTypeParameterLists, newTps, tps); + if (oldTps == tps) { + // exchange successful + tps = newTps; + } else { + // exchange not successful + tps = oldTps; + } + } + return tps[length]; + } + sealed class NormalizeMethodTypeParametersVisitor : TypeVisitor { public override IType VisitTypeParameter(ITypeParameter type) @@ -83,7 +116,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } } } - + static readonly NormalizeMethodTypeParametersVisitor normalizeMethodTypeParameters = new NormalizeMethodTypeParametersVisitor(); static readonly NormalizeClassTypeParametersVisitor normalizeClassTypeParameters = new NormalizeClassTypeParametersVisitor(); diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs index 6edc52371..e1ffdb6b4 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.Diagnostics; namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -91,10 +92,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return namespaceKnown ? fullTypeName.ReflectionName : "?"; } } - public override int TypeParameterCount { - get { return fullTypeName.TypeParameterCount; } - } - + public override int TypeParameterCount => fullTypeName.TypeParameterCount; + public override IReadOnlyList TypeParameters => DummyTypeParameter.GetClassTypeParameterList(TypeParameterCount); + public override IReadOnlyList TypeArguments => TypeParameters; + public override bool? IsReferenceType { get { return isReferenceType; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/NullableType.cs b/ICSharpCode.Decompiler/TypeSystem/NullableType.cs index 505d08f9a..27a7322ba 100644 --- a/ICSharpCode.Decompiler/TypeSystem/NullableType.cs +++ b/ICSharpCode.Decompiler/TypeSystem/NullableType.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.TypeSystem if (type == null) throw new ArgumentNullException("type"); ParameterizedType pt = type as ParameterizedType; - return pt != null && pt.TypeParameterCount == 1 && pt.GetDefinition().KnownTypeCode == KnownTypeCode.NullableOfT; + return pt != null && pt.TypeParameterCount == 1 && pt.GenericType.IsKnownType(KnownTypeCode.NullableOfT); } public static bool IsNonNullableValueType(IType type) @@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.TypeSystem if (type == null) throw new ArgumentNullException("type"); ParameterizedType pt = type as ParameterizedType; - if (pt != null && pt.TypeParameterCount == 1 && pt.GetDefinition().KnownTypeCode == KnownTypeCode.NullableOfT) + if (pt != null && pt.TypeParameterCount == 1 && pt.GenericType.IsKnownType(KnownTypeCode.NullableOfT)) return pt.GetTypeArgument(0); else return type; diff --git a/ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs b/ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs index d13aade8e..61ebbfe7b 100644 --- a/ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs +++ b/ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs @@ -36,12 +36,12 @@ namespace ICSharpCode.Decompiler.TypeSystem /// the type arguments. /// [Serializable] - public sealed class ParameterizedType : IType, ICompilationProvider + public sealed class ParameterizedType : IType { - readonly ITypeDefinition genericType; + readonly IType genericType; readonly IType[] typeArguments; - public ParameterizedType(ITypeDefinition genericType, IEnumerable typeArguments) + public ParameterizedType(IType genericType, IEnumerable typeArguments) { if (genericType == null) throw new ArgumentNullException("genericType"); @@ -53,11 +53,12 @@ namespace ICSharpCode.Decompiler.TypeSystem throw new ArgumentException("Cannot use ParameterizedType with 0 type arguments."); if (genericType.TypeParameterCount != this.typeArguments.Length) throw new ArgumentException("Number of type arguments must match the type definition's number of type parameters"); + ICompilationProvider gp = genericType as ICompilationProvider; for (int i = 0; i < this.typeArguments.Length; i++) { if (this.typeArguments[i] == null) throw new ArgumentNullException("typeArguments[" + i + "]"); ICompilationProvider p = this.typeArguments[i] as ICompilationProvider; - if (p != null && p.Compilation != genericType.Compilation) + if (p != null && gp != null && p.Compilation != gp.Compilation) throw new InvalidOperationException("Cannot parameterize a type with type arguments from a different compilation."); } } @@ -66,7 +67,7 @@ namespace ICSharpCode.Decompiler.TypeSystem /// Fast internal version of the constructor. (no safety checks) /// Keeps the array that was passed and assumes it won't be modified. /// - internal ParameterizedType(ITypeDefinition genericType, IType[] typeArguments) + internal ParameterizedType(IType genericType, IType[] typeArguments) { Debug.Assert(genericType.TypeParameterCount == typeArguments.Length); this.genericType = genericType; @@ -77,8 +78,8 @@ namespace ICSharpCode.Decompiler.TypeSystem get { return genericType.Kind; } } - public ICompilation Compilation { - get { return genericType.Compilation; } + public IType GenericType { + get { return genericType; } } public bool? IsReferenceType { @@ -87,18 +88,18 @@ namespace ICSharpCode.Decompiler.TypeSystem public IType DeclaringType { get { - ITypeDefinition declaringTypeDef = genericType.DeclaringTypeDefinition; - if (declaringTypeDef != null && declaringTypeDef.TypeParameterCount > 0 - && declaringTypeDef.TypeParameterCount <= genericType.TypeParameterCount) + IType declaringType = genericType.DeclaringType; + if (declaringType != null && declaringType.TypeParameterCount > 0 + && declaringType.TypeParameterCount <= genericType.TypeParameterCount) { - IType[] newTypeArgs = new IType[declaringTypeDef.TypeParameterCount]; + IType[] newTypeArgs = new IType[declaringType.TypeParameterCount]; Array.Copy(this.typeArguments, 0, newTypeArgs, 0, newTypeArgs.Length); - return new ParameterizedType(declaringTypeDef, newTypeArgs); + return new ParameterizedType(declaringType, newTypeArgs); } - return declaringTypeDef; + return declaringType; } } - + public int TypeParameterCount { get { return typeArguments.Length; } } @@ -135,34 +136,26 @@ namespace ICSharpCode.Decompiler.TypeSystem { return ReflectionName; } - - public IReadOnlyList TypeArguments { - get { - return typeArguments; - } - } - public bool IsParameterized { - get { - return true; - } - } + public IReadOnlyList TypeArguments => typeArguments; /// - /// Same as 'parameterizedType.TypeArguments[index]', but is a bit more efficient (doesn't require the read-only wrapper). + /// Same as 'parameterizedType.TypeArguments[index]'. /// public IType GetTypeArgument(int index) { return typeArguments[index]; } - + + public IReadOnlyList TypeParameters => genericType.TypeParameters; + /// /// Gets the definition of the generic type. /// For ParameterizedType, this method never returns null. /// public ITypeDefinition GetDefinition() { - return genericType; + return genericType as ITypeDefinition; } public ITypeReference ToTypeReference() @@ -313,9 +306,6 @@ namespace ICSharpCode.Decompiler.TypeSystem public IType VisitChildren(TypeVisitor visitor) { IType g = genericType.AcceptVisitor(visitor); - ITypeDefinition def = g as ITypeDefinition; - if (def == null) - return g; // Keep ta == null as long as no elements changed, allocate the array only if necessary. IType[] ta = (g != genericType) ? new IType[typeArguments.Length] : null; for (int i = 0; i < typeArguments.Length; i++) { @@ -332,10 +322,10 @@ namespace ICSharpCode.Decompiler.TypeSystem if (ta != null) ta[i] = r; } - if (def == genericType && ta == null) + if (ta == null) return this; else - return new ParameterizedType(def, ta ?? typeArguments); + return new ParameterizedType(g, ta ?? typeArguments); } } @@ -367,21 +357,18 @@ namespace ICSharpCode.Decompiler.TypeSystem get { return genericType; } } - public ReadOnlyCollection TypeArguments { + public IReadOnlyList TypeArguments { get { - return Array.AsReadOnly(typeArguments); + return typeArguments; } } public IType Resolve(ITypeResolveContext context) { IType baseType = genericType.Resolve(context); - ITypeDefinition baseTypeDef = baseType.GetDefinition(); - if (baseTypeDef == null) - return baseType; - int tpc = baseTypeDef.TypeParameterCount; + int tpc = baseType.TypeParameterCount; if (tpc == 0) - return baseTypeDef; + return baseType; IType[] resolvedTypes = new IType[tpc]; for (int i = 0; i < resolvedTypes.Length; i++) { if (i < typeArguments.Length) @@ -389,7 +376,7 @@ namespace ICSharpCode.Decompiler.TypeSystem else resolvedTypes[i] = SpecialType.UnknownType; } - return new ParameterizedType(baseTypeDef, resolvedTypes); + return new ParameterizedType(baseType, resolvedTypes); } public override string ToString()