From c54632e7cb7e80355d7861da07883207577adec9 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 14 Jul 2018 15:09:15 +0200 Subject: [PATCH] Fix some type system bugs. --- .../CSharp/CSharpDecompiler.cs | 3 +-- .../CSharp/RequiredNamespaceCollector.cs | 11 ++--------- ICSharpCode.Decompiler/IL/ILReader.cs | 18 +++++++++++------- .../IL/Transforms/DelegateConstruction.cs | 2 +- .../TypeSystem/GenericContext.cs | 11 +++++++++++ 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 26d5bd0d3..5dc977d0a 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -1005,10 +1005,9 @@ namespace ICSharpCode.Decompiler.CSharp UseDebugSymbols = settings.UseDebugSymbols, DebugInfo = DebugInfoProvider }; - var genericContext = new Decompiler.TypeSystem.GenericContext(decompilationContext); var methodDef = typeSystem.ModuleDefinition.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); var methodBody = typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); - var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, genericContext, CancellationToken); + var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: CancellationToken); function.CheckInvariant(ILPhase.Normal); if (entityDecl != null) { diff --git a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs index 27a90226c..05ded2555 100644 --- a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs +++ b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs @@ -117,21 +117,14 @@ namespace ICSharpCode.Decompiler.CSharp static void CollectNamespacesForTypeReference(IType type, HashSet namespaces) { switch (type) { - case ArrayType arrayType: - namespaces.Add(arrayType.Namespace); - CollectNamespacesForTypeReference(arrayType.ElementType, namespaces); - break; case ParameterizedType parameterizedType: namespaces.Add(parameterizedType.Namespace); CollectNamespacesForTypeReference(parameterizedType.GenericType, namespaces); foreach (var arg in parameterizedType.TypeArguments) CollectNamespacesForTypeReference(arg, namespaces); break; - case ByReferenceType byReferenceType: - CollectNamespacesForTypeReference(byReferenceType.ElementType, namespaces); - break; - case PointerType pointerType: - CollectNamespacesForTypeReference(pointerType.ElementType, namespaces); + case TypeWithElementType typeWithElementType: + CollectNamespacesForTypeReference(typeWithElementType.ElementType, namespaces); break; case TupleType tupleType: foreach (var elementType in tupleType.ElementTypes) { diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 13338be68..e7ed07686 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -92,13 +92,11 @@ namespace ICSharpCode.Decompiler.IL throw new ArgumentException("methodDefinitionHandle.IsNil"); this.method = module.GetDefinition(methodDefinitionHandle); if (genericContext.ClassTypeParameters == null && genericContext.MethodTypeParameters == null) { - if (method.DeclaringType.TypeParameterCount > 0 || method.TypeParameters.Count > 0) { - // no generic context specified, but it's a generic method: use the method's own type parameters - genericContext = new GenericContext(method); - } + // no generic context specified: use the method's own type parameters + genericContext = new GenericContext(method); } else { // generic context specified, so specialize the method for it: - this.method = this.method.Specialize(new TypeParameterSubstitution(genericContext.ClassTypeParameters, genericContext.MethodTypeParameters)); + this.method = this.method.Specialize(genericContext.ToSubstitution()); } this.genericContext = genericContext; var methodDefinition = metadata.GetMethodDefinition(methodDefinitionHandle); @@ -177,7 +175,13 @@ namespace ICSharpCode.Decompiler.IL int offset = 0; if (!method.IsStatic) { offset = 1; - parameterVariables[paramIndex++] = CreateILVariable(-1, method.DeclaringType, "this"); + IType declaringType = method.DeclaringType; + if (declaringType.IsUnbound()) { + // If method is a definition (and not specialized), the declaring type is also just a definition, + // and needs to be converted into a normally usable type. + declaringType = new ParameterizedType(declaringType, declaringType.TypeParameters); + } + parameterVariables[paramIndex++] = CreateILVariable(-1, declaringType, "this"); } while (paramIndex < parameterVariables.Length) { IType type = method.Parameters[paramIndex - offset].Type; @@ -480,7 +484,7 @@ namespace ICSharpCode.Decompiler.IL ReadInstructions(cancellationToken); var blockBuilder = new BlockBuilder(body, variableByExceptionHandler); blockBuilder.CreateBlocks(mainContainer, instructionBuilder, isBranchTarget, cancellationToken); - var function = new ILFunction(this.method, body.GetCodeSize(), genericContext, mainContainer); + var function = new ILFunction(this.method, body.GetCodeSize(), this.genericContext, mainContainer); CollectionExtensions.AddRange(function.Variables, parameterVariables); CollectionExtensions.AddRange(function.Variables, localVariables); CollectionExtensions.AddRange(function.Variables, stackVariables); diff --git a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs index 71fbce258..c73abfe78 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs @@ -140,7 +140,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (subst.MethodTypeArguments != null) { foreach (var t in subst.MethodTypeArguments) { if (t is ITypeParameter tp) - classTypeParameters.Add(tp); + methodTypeParameters.Add(tp); else return null; } diff --git a/ICSharpCode.Decompiler/TypeSystem/GenericContext.cs b/ICSharpCode.Decompiler/TypeSystem/GenericContext.cs index ef52234e4..13e3a54fa 100644 --- a/ICSharpCode.Decompiler/TypeSystem/GenericContext.cs +++ b/ICSharpCode.Decompiler/TypeSystem/GenericContext.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 ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -70,5 +71,15 @@ namespace ICSharpCode.Decompiler.TypeSystem else return DummyTypeParameter.GetMethodTypeParameter(index); } + + internal TypeParameterSubstitution ToSubstitution() + { + // The TS prefers 'null' over empty lists in substitutions, and we need our substitution + // to compare equal to the ones created by the TS. + return new TypeParameterSubstitution( + classTypeArguments: ClassTypeParameters?.Count > 0 ? ClassTypeParameters : null, + methodTypeArguments: MethodTypeParameters?.Count > 0 ? MethodTypeParameters : null + ); + } } }