From b788441c78cbbdaaf1d33e15837bfdbfee2e6fcd Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 6 Aug 2020 23:17:25 +0200 Subject: [PATCH] DecompilerTypeSystem: If some known types are present in referenced assemblies but others are missing; add the missing known types to the compilation. This ensures that FindType(KnownTypeCode).GetDefinition() always returns a usable definition. --- .../TypeSystem/DecompilerTypeSystem.cs | 18 ++++++----- .../Implementation/MinimalCorlib.cs | 30 ++++++++++++------- .../TypeSystem/KnownTypeReference.cs | 12 ++++++++ 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index 98fd65194..9c126bbcf 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -224,24 +224,26 @@ namespace ICSharpCode.Decompiler.TypeSystem var mainModuleWithOptions = mainModule.WithOptions(typeSystemOptions); var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(typeSystemOptions)); // Primitive types are necessary to avoid assertions in ILReader. - // Fallback to MinimalCorlib to provide the primitive types. - if (!HasType(KnownTypeCode.Void) || !HasType(KnownTypeCode.Int32)) { - Init(mainModule.WithOptions(typeSystemOptions), referencedAssembliesWithOptions.Concat(new[] { MinimalCorlib.Instance })); + // Other known types are necessary in order for transforms to work (e.g. Task for async transform). + // Figure out which known types are missing from our type system so far: + var missingKnownTypes = KnownTypeReference.AllKnownTypes.Where(IsMissing).ToList(); + if (missingKnownTypes.Count > 0) { + Init(mainModule.WithOptions(typeSystemOptions), referencedAssembliesWithOptions.Concat(new[] { MinimalCorlib.CreateWithTypes(missingKnownTypes) })); } else { Init(mainModuleWithOptions, referencedAssembliesWithOptions); } this.MainModule = (MetadataModule)base.MainModule; - bool HasType(KnownTypeCode code) + bool IsMissing(KnownTypeReference knownType) { - TopLevelTypeName name = KnownTypeReference.Get(code).TypeName; + var name = knownType.TypeName; if (!mainModule.GetTypeDefinition(name).IsNil) - return true; + return false; foreach (var file in referencedAssemblies) { if (!file.GetTypeDefinition(name).IsNil) - return true; + return false; } - return false; + return true; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs index fbab0db4b..d98fe5d54 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs @@ -31,22 +31,25 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation /// public sealed class MinimalCorlib : IModule { - public static readonly IModuleReference Instance = new CorlibModuleReference(); + /// + /// Minimal corlib instance containing all known types. + /// + public static readonly IModuleReference Instance = new CorlibModuleReference(KnownTypeReference.AllKnownTypes); + + public static IModuleReference CreateWithTypes(IEnumerable types) + { + return new CorlibModuleReference(types); + } public ICompilation Compilation { get; } CorlibTypeDefinition[] typeDefinitions; readonly CorlibNamespace rootNamespace; - private MinimalCorlib(ICompilation compilation) + private MinimalCorlib(ICompilation compilation, IEnumerable types) { this.Compilation = compilation; - this.typeDefinitions = new CorlibTypeDefinition[KnownTypeReference.KnownTypeCodeCount]; + this.typeDefinitions = types.Select(ktr => new CorlibTypeDefinition(this, ktr.KnownTypeCode)).ToArray(); this.rootNamespace = new CorlibNamespace(this, null, string.Empty, string.Empty); - for (int i = 0; i < KnownTypeReference.KnownTypeCodeCount; i++) { - if (KnownTypeReference.Get((KnownTypeCode)i) != null) { - typeDefinitions[i] = new CorlibTypeDefinition(this, (KnownTypeCode)i); - } - } } bool IModule.IsMainModule => Compilation.MainModule == this; @@ -65,7 +68,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName) { foreach (var typeDef in typeDefinitions) { - if (typeDef != null && typeDef.FullTypeName == topLevelTypeName) + if (typeDef.FullTypeName == topLevelTypeName) return typeDef; } return null; @@ -81,9 +84,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation sealed class CorlibModuleReference : IModuleReference { + readonly IEnumerable types; + + public CorlibModuleReference(IEnumerable types) + { + this.types = types; + } + IModule IModuleReference.Resolve(ITypeResolveContext context) { - return new MinimalCorlib(context.Compilation); + return new MinimalCorlib(context.Compilation, types); } } diff --git a/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs b/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs index a6981f2b2..d3a121ffc 100644 --- a/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs +++ b/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; namespace ICSharpCode.Decompiler.TypeSystem { @@ -235,6 +236,17 @@ namespace ICSharpCode.Decompiler.TypeSystem return knownTypeReferences[(int)typeCode]; } + public static IEnumerable AllKnownTypes { + get { + for (int i = 0; i < KnownTypeCodeCount; i++) { + var ktr = Get((KnownTypeCode)i); + if (ktr == null) + continue; + yield return ktr; + } + } + } + readonly KnownTypeCode knownTypeCode; readonly string namespaceName; readonly string name;