From 5046e4cf6038735d1202194d5d96d281cfdbac4b Mon Sep 17 00:00:00 2001
From: Siegfried Pammer <siegfriedpammer@gmail.com>
Date: Fri, 15 Jul 2022 18:17:27 +0200
Subject: [PATCH] Fix #2718, Fix #2719, Fix #2725: Remove WPF
 compiler-generated code.

---
 .../CSharp/CSharpDecompiler.cs                | 73 +++++++++++-------
 .../WholeProjectDecompiler.cs                 | 29 ++++---
 .../ICSharpCode.Decompiler.csproj             |  1 +
 ICSharpCode.Decompiler/PartialTypeInfo.cs     | 76 +++++++++++++++++++
 ILSpy.BamlDecompiler/BamlConnectionId.cs      |  4 +-
 .../BamlDecompilationResult.cs                |  6 +-
 .../BamlResourceNodeFactory.cs                | 25 ++++--
 .../Properties/launchSettings.json            |  2 +-
 .../Rewrite/ConnectionIdRewritePass.cs        | 64 ++++++++++++----
 ILSpy.BamlDecompiler/XamlContext.cs           |  4 +
 ILSpy.BamlDecompiler/XamlDecompiler.cs        |  2 +-
 ILSpy/Languages/CSharpLanguage.cs             | 10 ++-
 ILSpy/Languages/IResourceFileHandler.cs       | 24 +++++-
 13 files changed, 250 insertions(+), 70 deletions(-)
 create mode 100644 ICSharpCode.Decompiler/PartialTypeInfo.cs

diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index dca1897f8..f0eca9c7f 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -26,6 +26,7 @@ using System.Reflection.PortableExecutable;
 using System.Text.RegularExpressions;
 using System.Threading;
 
+using ICSharpCode.Decompiler;
 using ICSharpCode.Decompiler.CSharp.OutputVisitor;
 using ICSharpCode.Decompiler.CSharp.Resolver;
 using ICSharpCode.Decompiler.CSharp.Syntax;
@@ -522,6 +523,14 @@ namespace ICSharpCode.Decompiler.CSharp
 			}
 		}
 
+		DecompileRun CreateDecompileRun()
+		{
+			return new DecompileRun(settings) {
+				DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
+				CancellationToken = CancellationToken
+			};
+		}
+
 		void RunTransforms(AstNode rootNode, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
 		{
 			var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
@@ -550,10 +559,7 @@ namespace ICSharpCode.Decompiler.CSharp
 		public SyntaxTree DecompileModuleAndAssemblyAttributes()
 		{
 			var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule);
-			var decompileRun = new DecompileRun(settings) {
-				DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
-				CancellationToken = CancellationToken
-			};
+			DecompileRun decompileRun = CreateDecompileRun();
 			syntaxTree = new SyntaxTree();
 			RequiredNamespaceCollector.CollectAttributeNamespaces(module, decompileRun.Namespaces);
 			DoDecompileModuleAndAssemblyAttributes(decompileRun, decompilationContext, syntaxTree);
@@ -639,10 +645,7 @@ namespace ICSharpCode.Decompiler.CSharp
 		public SyntaxTree DecompileWholeModuleAsSingleFile(bool sortTypes)
 		{
 			var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule);
-			var decompileRun = new DecompileRun(settings) {
-				DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
-				CancellationToken = CancellationToken
-			};
+			var decompileRun = CreateDecompileRun();
 			syntaxTree = new SyntaxTree();
 			RequiredNamespaceCollector.CollectNamespaces(module, decompileRun.Namespaces);
 			DoDecompileModuleAndAssemblyAttributes(decompileRun, decompilationContext, syntaxTree);
@@ -664,10 +667,7 @@ namespace ICSharpCode.Decompiler.CSharp
 		/// </summary>
 		public ILTransformContext CreateILTransformContext(ILFunction function)
 		{
-			var decompileRun = new DecompileRun(settings) {
-				DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
-				CancellationToken = CancellationToken
-			};
+			var decompileRun = CreateDecompileRun();
 			RequiredNamespaceCollector.CollectNamespaces(function.Method, module, decompileRun.Namespaces);
 			return new ILTransformContext(function, typeSystem, DebugInfoProvider, settings) {
 				CancellationToken = CancellationToken,
@@ -912,10 +912,7 @@ namespace ICSharpCode.Decompiler.CSharp
 			if (types == null)
 				throw new ArgumentNullException(nameof(types));
 			var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule);
-			var decompileRun = new DecompileRun(settings) {
-				DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
-				CancellationToken = CancellationToken
-			};
+			var decompileRun = CreateDecompileRun();
 			syntaxTree = new SyntaxTree();
 
 			foreach (var type in types)
@@ -957,10 +954,7 @@ namespace ICSharpCode.Decompiler.CSharp
 			if (type.ParentModule != typeSystem.MainModule)
 				throw new NotSupportedException("Decompiling types that are not part of the main module is not supported.");
 			var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule);
-			var decompileRun = new DecompileRun(settings) {
-				DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
-				CancellationToken = CancellationToken
-			};
+			var decompileRun = CreateDecompileRun();
 			syntaxTree = new SyntaxTree();
 			RequiredNamespaceCollector.CollectNamespaces(type.MetadataToken, module, decompileRun.Namespaces);
 			DoDecompileTypes(new[] { (TypeDefinitionHandle)type.MetadataToken }, decompileRun, decompilationContext, syntaxTree);
@@ -995,10 +989,7 @@ namespace ICSharpCode.Decompiler.CSharp
 			if (definitions == null)
 				throw new ArgumentNullException(nameof(definitions));
 			syntaxTree = new SyntaxTree();
-			var decompileRun = new DecompileRun(settings) {
-				DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
-				CancellationToken = CancellationToken
-			};
+			var decompileRun = CreateDecompileRun();
 			foreach (var entity in definitions)
 			{
 				if (entity.IsNil)
@@ -1100,6 +1091,20 @@ namespace ICSharpCode.Decompiler.CSharp
 			return SyntaxTreeToString(Decompile(definitions));
 		}
 
+		readonly Dictionary<TypeDefinitionHandle, PartialTypeInfo> partialTypes = new();
+
+		public void AddPartialTypeDefinition(PartialTypeInfo info)
+		{
+			if (!partialTypes.TryGetValue(info.DeclaringTypeDefinitionHandle, out var existingInfo))
+			{
+				partialTypes.Add(info.DeclaringTypeDefinitionHandle, info);
+			}
+			else
+			{
+				existingInfo.AddDeclaredMembers(info);
+			}
+		}
+
 		IEnumerable<EntityDeclaration> AddInterfaceImplHelpers(
 			EntityDeclaration memberDecl, IMethod method,
 			TypeSystemAstBuilder astBuilder)
@@ -1319,6 +1324,11 @@ namespace ICSharpCode.Decompiler.CSharp
 
 				var allOrderedEntities = typeDef.NestedTypes.Concat<IEntity>(allOrderedMembers).ToArray();
 
+				if (!partialTypes.TryGetValue((TypeDefinitionHandle)typeDef.MetadataToken, out var partialTypeInfo))
+				{
+					partialTypeInfo = null;
+				}
+
 				// Decompile members that are not compiler-generated.
 				foreach (var entity in allOrderedEntities)
 				{
@@ -1326,7 +1336,7 @@ namespace ICSharpCode.Decompiler.CSharp
 					{
 						continue;
 					}
-					DoDecompileMember(entity, recordDecompiler);
+					DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
 				}
 
 				// Decompile compiler-generated members that are still needed.
@@ -1338,7 +1348,7 @@ namespace ICSharpCode.Decompiler.CSharp
 						// Member is already decompiled.
 						continue;
 					}
-					DoDecompileMember(entity, recordDecompiler);
+					DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
 				}
 
 				// Add all decompiled members to syntax tree in the correct order.
@@ -1352,6 +1362,10 @@ namespace ICSharpCode.Decompiler.CSharp
 					// Remove the [DefaultMember] attribute if the class contains indexers
 					RemoveAttribute(typeDecl, KnownAttribute.DefaultMember);
 				}
+				if (partialTypeInfo != null)
+				{
+					typeDecl.Modifiers |= Modifiers.Partial;
+				}
 				if (settings.IntroduceRefModifiersOnStructs)
 				{
 					if (FindAttribute(typeDecl, KnownAttribute.Obsolete, out var attr))
@@ -1406,8 +1420,13 @@ namespace ICSharpCode.Decompiler.CSharp
 				Instrumentation.DecompilerEventSource.Log.DoDecompileTypeDefinition(typeDef.FullName, watch.ElapsedMilliseconds);
 			}
 
-			void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler)
+			void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, PartialTypeInfo partialType)
 			{
+				if (partialType != null && partialType.IsDeclaredMember(entity.MetadataToken))
+				{
+					return;
+				}
+
 				EntityDeclaration entityDecl;
 				switch (entity)
 				{
diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
index ad3ffdb8f..3057cbb6f 100644
--- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
@@ -149,8 +149,9 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 			}
 			TargetDirectory = targetDirectory;
 			directories.Clear();
-			var files = WriteCodeFilesInProject(moduleDefinition, cancellationToken).ToList();
-			files.AddRange(WriteResourceFilesInProject(moduleDefinition));
+			var resources = WriteResourceFilesInProject(moduleDefinition).ToList();
+			var files = WriteCodeFilesInProject(moduleDefinition, resources.SelectMany(r => r.partialTypes ?? Enumerable.Empty<PartialTypeInfo>()).ToList(), cancellationToken).ToList();
+			files.AddRange(resources.Select(r => (r.itemType, r.fileName)));
 			files.AddRange(WriteMiscellaneousFilesInProject(moduleDefinition));
 			if (StrongNameKeyFile != null)
 			{
@@ -202,7 +203,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 			return new[] { ("Compile", assemblyInfo) };
 		}
 
-		IEnumerable<(string itemType, string fileName)> WriteCodeFilesInProject(Metadata.PEFile module, CancellationToken cancellationToken)
+		IEnumerable<(string itemType, string fileName)> WriteCodeFilesInProject(Metadata.PEFile module, IList<PartialTypeInfo> partialTypes, CancellationToken cancellationToken)
 		{
 			var metadata = module.Metadata;
 			var files = module.Metadata.GetTopLevelTypeDefinitions().Where(td => IncludeTypeWhenDecompilingProject(module, td)).GroupBy(
@@ -237,6 +238,12 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 						try
 						{
 							CSharpDecompiler decompiler = CreateDecompiler(ts);
+
+							foreach (var partialType in partialTypes)
+							{
+								decompiler.AddPartialTypeDefinition(partialType);
+							}
+
 							decompiler.CancellationToken = cancellationToken;
 							var syntaxTree = decompiler.DecompileTypes(file.ToArray());
 							syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, Settings.CSharpFormattingOptions));
@@ -253,7 +260,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 		#endregion
 
 		#region WriteResourceFilesInProject
-		protected virtual IEnumerable<(string itemType, string fileName)> WriteResourceFilesInProject(Metadata.PEFile module)
+		protected virtual IEnumerable<(string itemType, string fileName, List<PartialTypeInfo> partialTypes)> WriteResourceFilesInProject(Metadata.PEFile module)
 		{
 			foreach (var r in module.Resources.Where(r => r.ResourceType == ResourceType.Embedded))
 			{
@@ -263,7 +270,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 				if (r.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
 				{
 					bool decodedIntoIndividualFiles;
-					var individualResources = new List<(string itemType, string fileName)>();
+					var individualResources = new List<(string itemType, string fileName, List<PartialTypeInfo> partialTypes)>();
 					try
 					{
 						var resourcesFile = new ResourcesFile(stream);
@@ -323,12 +330,12 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 						stream.Position = 0;
 						stream.CopyTo(fs);
 					}
-					yield return ("EmbeddedResource", fileName);
+					yield return ("EmbeddedResource", fileName, null);
 				}
 			}
 		}
 
-		protected virtual IEnumerable<(string itemType, string fileName)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
+		protected virtual IEnumerable<(string itemType, string fileName, List<PartialTypeInfo> partialTypes)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
 		{
 			if (fileName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
 			{
@@ -343,7 +350,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 							writer.AddResource(entry.Key, entry.Value);
 						}
 					}
-					return new[] { ("EmbeddedResource", resx) };
+					return new[] { ("EmbeddedResource", resx, (List<PartialTypeInfo>)null) };
 				}
 				catch (BadImageFormatException)
 				{
@@ -358,7 +365,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 			{
 				entryStream.CopyTo(fs);
 			}
-			return new[] { ("EmbeddedResource", fileName) };
+			return new[] { ("EmbeddedResource", fileName, (List<PartialTypeInfo>)null) };
 		}
 
 		string GetFileNameForResource(string fullName)
@@ -558,8 +565,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
 		/// <summary>
 		/// Cleans up a node name for use as a file system name. If <paramref name="separateAtDots"/> is active,
 		/// dots are seen as segment separators. Each segment is limited to maxSegmentLength characters.
-		/// (see <see cref="GetLongPathSupport"/>) If <paramref name="treatAsFileName"/> is active,
-		/// we check for file a extension and try to preserve it, if it's valid.
+		/// If <paramref name="treatAsFileName"/> is active, we check for file a extension and try to preserve it,
+		/// if it's valid.
 		/// </summary>
 		static string CleanUpName(string text, bool separateAtDots, bool treatAsFileName)
 		{
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 4f66c233f..c5011ed45 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -84,6 +84,7 @@
     <Compile Include="CSharp\Annotations.cs" />
     <Compile Include="CSharp\CallBuilder.cs" />
     <Compile Include="CSharp\CSharpLanguageVersion.cs" />
+    <Compile Include="PartialTypeInfo.cs" />
     <Compile Include="CSharp\ProjectDecompiler\IProjectFileWriter.cs" />
     <Compile Include="CSharp\OutputVisitor\GenericGrammarAmbiguityVisitor.cs" />
     <Compile Include="CSharp\ProjectDecompiler\IProjectInfoProvider.cs" />
diff --git a/ICSharpCode.Decompiler/PartialTypeInfo.cs b/ICSharpCode.Decompiler/PartialTypeInfo.cs
new file mode 100644
index 000000000..efe171bfa
--- /dev/null
+++ b/ICSharpCode.Decompiler/PartialTypeInfo.cs
@@ -0,0 +1,76 @@
+// Copyright (c) 2022 Siegfried Pammer
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// 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.Diagnostics;
+using System.Linq;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.Decompiler
+{
+	public class PartialTypeInfo
+	{
+		readonly HashSet<EntityHandle> declaredMembers = new();
+
+		public PartialTypeInfo(ITypeDefinition declaringTypeDefinition)
+		{
+			DeclaringTypeDefinitionHandle = (TypeDefinitionHandle)declaringTypeDefinition.MetadataToken;
+		}
+
+		public PartialTypeInfo(TypeDefinitionHandle declaringTypeDefinitionHandle)
+		{
+			DeclaringTypeDefinitionHandle = declaringTypeDefinitionHandle;
+		}
+
+		public TypeDefinitionHandle DeclaringTypeDefinitionHandle { get; }
+
+		public void AddDeclaredMember(IMember member)
+		{
+			declaredMembers.Add(member.MetadataToken);
+		}
+
+		public void AddDeclaredMember(EntityHandle handle)
+		{
+			declaredMembers.Add(handle);
+		}
+
+		public bool IsDeclaredMember(IMember member)
+		{
+			return declaredMembers.Contains(member.MetadataToken);
+		}
+
+		public bool IsDeclaredMember(EntityHandle handle)
+		{
+			return declaredMembers.Contains(handle);
+		}
+
+		public void AddDeclaredMembers(PartialTypeInfo info)
+		{
+			foreach (var member in info.declaredMembers)
+			{
+				declaredMembers.Add(member);
+			}
+		}
+
+		public string DebugOutput => string.Join(", ", declaredMembers.Select(m => MetadataTokens.GetToken(m).ToString("X")));
+	}
+}
\ No newline at end of file
diff --git a/ILSpy.BamlDecompiler/BamlConnectionId.cs b/ILSpy.BamlDecompiler/BamlConnectionId.cs
index 9bf19607d..30d11f0cf 100644
--- a/ILSpy.BamlDecompiler/BamlConnectionId.cs
+++ b/ILSpy.BamlDecompiler/BamlConnectionId.cs
@@ -20,6 +20,8 @@
 	THE SOFTWARE.
 */
 
+using ICSharpCode.Decompiler.TypeSystem;
+
 namespace ILSpy.BamlDecompiler
 {
 	/// <summary>
@@ -27,7 +29,7 @@ namespace ILSpy.BamlDecompiler
 	/// </summary>
 	internal sealed class FieldAssignment
 	{
-		public string FieldName;
+		public IField Field;
 	}
 
 	/// <summary>
diff --git a/ILSpy.BamlDecompiler/BamlDecompilationResult.cs b/ILSpy.BamlDecompiler/BamlDecompilationResult.cs
index e46651b8a..83e8942ed 100644
--- a/ILSpy.BamlDecompiler/BamlDecompilationResult.cs
+++ b/ILSpy.BamlDecompiler/BamlDecompilationResult.cs
@@ -18,6 +18,7 @@
 
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection.Metadata;
 using System.Xml.Linq;
 
 using ICSharpCode.Decompiler.TypeSystem;
@@ -31,11 +32,14 @@ namespace ILSpy.BamlDecompiler
 
 		public FullTypeName? TypeName { get; }
 
-		public BamlDecompilationResult(XDocument xaml, FullTypeName? typeName, IEnumerable<string> assemblyReferences)
+		public List<EntityHandle> GeneratedMembers { get; }
+
+		public BamlDecompilationResult(XDocument xaml, FullTypeName? typeName, IEnumerable<string> assemblyReferences, IEnumerable<EntityHandle> generatedMembers)
 		{
 			this.Xaml = xaml;
 			this.TypeName = typeName;
 			this.AssemblyReferences = assemblyReferences.ToList();
+			this.GeneratedMembers = generatedMembers.ToList();
 		}
 	}
 }
\ No newline at end of file
diff --git a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
index d61f20b79..be0a6ae1c 100644
--- a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
+++ b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
@@ -19,7 +19,9 @@
 using System;
 using System.ComponentModel.Composition;
 using System.IO;
+using System.Linq;
 
+using ICSharpCode.Decompiler;
 using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
 using ICSharpCode.Decompiler.Metadata;
 using ICSharpCode.ILSpy;
@@ -45,25 +47,34 @@ namespace ILSpy.BamlDecompiler
 	public sealed class BamlResourceFileHandler : IResourceFileHandler
 	{
 		public string EntryType => "Page";
-		public bool CanHandle(string name, DecompilationOptions options) => name.EndsWith(".baml", StringComparison.OrdinalIgnoreCase);
+		public bool CanHandle(string name, ResourceFileHandlerContext context) => name.EndsWith(".baml", StringComparison.OrdinalIgnoreCase);
 
-		public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options)
+		public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, ResourceFileHandlerContext context)
 		{
 			BamlDecompilerTypeSystem typeSystem = new BamlDecompilerTypeSystem(assembly.GetPEFileOrNull(), assembly.GetAssemblyResolver());
 			var decompiler = new XamlDecompiler(typeSystem, new BamlDecompilerSettings() {
-				ThrowOnAssemblyResolveErrors = options.DecompilerSettings.ThrowOnAssemblyResolveErrors
+				ThrowOnAssemblyResolveErrors = context.DecompilationOptions.DecompilerSettings.ThrowOnAssemblyResolveErrors
 			});
-			decompiler.CancellationToken = options.CancellationToken;
+			decompiler.CancellationToken = context.DecompilationOptions.CancellationToken;
 			var result = decompiler.Decompile(stream);
-			if (result.TypeName.HasValue)
+			var typeDefinition = result.TypeName.HasValue ? typeSystem.MainModule.GetTypeDefinition(result.TypeName.Value.TopLevelTypeName) : null;
+			if (typeDefinition != null)
 			{
-				fileName = WholeProjectDecompiler.CleanUpPath(result.TypeName.Value.ReflectionName) + ".xaml";
+				fileName = WholeProjectDecompiler.CleanUpPath(typeDefinition.ReflectionName) + ".xaml";
+				var partialTypeInfo = new PartialTypeInfo(typeDefinition);
+				foreach (var member in result.GeneratedMembers)
+				{
+					partialTypeInfo.AddDeclaredMember(member);
+				}
+				context.AddPartialTypeInfo(partialTypeInfo);
 			}
 			else
 			{
 				fileName = Path.ChangeExtension(fileName, ".xaml");
 			}
-			result.Xaml.Save(Path.Combine(options.SaveAsProjectDirectory, fileName));
+			string saveFileName = Path.Combine(context.DecompilationOptions.SaveAsProjectDirectory, fileName);
+			Directory.CreateDirectory(Path.GetDirectoryName(saveFileName));
+			result.Xaml.Save(saveFileName);
 			return fileName;
 		}
 	}
diff --git a/ILSpy.BamlDecompiler/Properties/launchSettings.json b/ILSpy.BamlDecompiler/Properties/launchSettings.json
index 253f16b70..93c6637b2 100644
--- a/ILSpy.BamlDecompiler/Properties/launchSettings.json
+++ b/ILSpy.BamlDecompiler/Properties/launchSettings.json
@@ -2,7 +2,7 @@
   "profiles": {
     "ILSpy.BamlDecompiler": {
       "commandName": "Executable",
-      "executablePath": "C:\\Users\\sie_p\\Projects\\ILSpy\\ILSpy\\bin\\Debug\\net472\\ILSpy.exe",
+      "executablePath": "$(SolutionDir)\\ILSpy\\bin\\Debug\\net6.0-windows\\ILSpy.exe",
       "commandLineArgs": "/separate"
     }
   }
diff --git a/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs b/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs
index f1797c8fe..ba05f6df7 100644
--- a/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs
+++ b/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs
@@ -25,13 +25,14 @@ using System.Xml.Linq;
 using ICSharpCode.Decompiler.CSharp;
 using ICSharpCode.Decompiler.IL;
 using ICSharpCode.Decompiler.IL.Transforms;
-using ICSharpCode.Decompiler.TypeSystem;
 using ICSharpCode.Decompiler.Util;
 
 using ILSpy.BamlDecompiler.Xaml;
 
 namespace ILSpy.BamlDecompiler.Rewrite
 {
+	using ICSharpCode.Decompiler.TypeSystem;
+
 	internal class ConnectionIdRewritePass : IRewritePass
 	{
 		static readonly TopLevelTypeName componentConnectorTypeName
@@ -61,8 +62,12 @@ namespace ILSpy.BamlDecompiler.Rewrite
 				if ((index = fieldAssignments.FindIndex(item => item.key.Contains(annotation.Id))) > -1)
 				{
 					var xName = ctx.GetKnownNamespace("Name", XamlContext.KnownNamespace_Xaml, element);
+					FieldAssignment fieldAssignment = fieldAssignments[index].value;
 					if (element.Attribute("Name") is null && element.Attribute(xName) is null)
-						element.Add(new XAttribute(xName, fieldAssignments[index].value.FieldName));
+					{
+						element.Add(new XAttribute(xName, fieldAssignment.Field.Name));
+					}
+					ctx.GeneratedMembers.Add(fieldAssignment.Field.MetadataToken);
 					found = true;
 				}
 				if ((index = eventMappings.FindIndex(item => item.key.Contains(annotation.Id))) > -1)
@@ -121,32 +126,61 @@ namespace ILSpy.BamlDecompiler.Rewrite
 				return;
 			var connect = connectorInterface.GetMethods(m => m.Name == "Connect").SingleOrDefault();
 
-			IMethod method = null;
-			MethodDefinition metadataEntry = default;
+			IMethod connectMethod = null;
+			MethodDefinition connectMetadataEntry = default;
 			var module = ctx.TypeSystem.MainModule.PEFile;
 
 			foreach (IMethod m in type.Methods)
 			{
-				if (m.ExplicitlyImplementedInterfaceMembers.Any(md => md.MemberDefinition.Equals(connect)))
+				if (connectMethod == null && m.ExplicitlyImplementedInterfaceMembers.Any(md => md.MemberDefinition.Equals(connect)))
 				{
-					method = m;
-					metadataEntry = module.Metadata
-						.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
-					break;
+					connectMethod = m;
+					connectMetadataEntry = module.Metadata
+						.GetMethodDefinition((MethodDefinitionHandle)connectMethod.MetadataToken);
+				}
+				else if (m.Parameters.Count == 0
+					&& m.ReturnType.Kind == TypeKind.Void
+					&& !m.IsStatic
+					&& m.Accessibility == Accessibility.Public
+					&& m.Name == "InitializeComponent"
+					&& m.GetAttributes().Any(a => a.AttributeType.ReflectionName == "System.CodeDom.Compiler.GeneratedCodeAttribute"))
+				{
+					ctx.GeneratedMembers.Add(m.MetadataToken);
+				}
+				else if (m.Parameters.Count == 0
+					&& m.ReturnType.Kind == TypeKind.Void
+					&& m.IsStatic
+					&& m.Accessibility == Accessibility.Public
+					&& m.Name == "Main"
+					&& m.DeclaringTypeDefinition.GetNonInterfaceBaseTypes().Any(t => t.ReflectionName == "System.Windows.Application")
+					&& m.GetAttributes().Any(a => a.AttributeType.ReflectionName == "System.CodeDom.Compiler.GeneratedCodeAttribute"))
+				{
+					ctx.GeneratedMembers.Add(m.MetadataToken);
 				}
 			}
 
-			if (method == null || metadataEntry.RelativeVirtualAddress <= 0)
+			if (type.Fields.FirstOrDefault(f => f.Name == "_contentLoaded" && f.Type.IsKnownType(KnownTypeCode.Boolean)) is {
+				Accessibility: Accessibility.Private, IsStatic: false
+			} contentLoadedField)
+			{
+				ctx.GeneratedMembers.Add(contentLoadedField.MetadataToken);
+			}
+
+			if (connectMethod == null || connectMetadataEntry.RelativeVirtualAddress <= 0)
 				return;
 
-			var body = module.Reader.GetMethodBody(metadataEntry.RelativeVirtualAddress);
+			ctx.GeneratedMembers.Add(connectMethod.MetadataToken);
+
+
+
+			var body = module.Reader.GetMethodBody(connectMetadataEntry.RelativeVirtualAddress);
 			var genericContext = new GenericContext(
-				classTypeParameters: method.DeclaringType?.TypeParameters,
-				methodTypeParameters: method.TypeParameters);
+				classTypeParameters: connectMethod.DeclaringType?.TypeParameters,
+				methodTypeParameters: connectMethod.TypeParameters);
 
 			// decompile method and optimize the switch
 			var ilReader = new ILReader(ctx.TypeSystem.MainModule);
-			var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, body, genericContext,
+			var function = ilReader.ReadIL((MethodDefinitionHandle)connectMethod.MetadataToken, body, genericContext,
 				ILFunctionKind.TopLevelFunction, ctx.CancellationToken);
 
 			var context = new ILTransformContext(function, ctx.TypeSystem, null) {
@@ -224,7 +258,7 @@ namespace ILSpy.BamlDecompiler.Rewrite
 				|| !(arg.MatchLdLoc(out var t) && t.Kind == VariableKind.Parameter && t.Index == 1))
 				return false;
 
-			field = new FieldAssignment { FieldName = fld.Name };
+			field = new FieldAssignment { Field = fld };
 			return true;
 		}
 
diff --git a/ILSpy.BamlDecompiler/XamlContext.cs b/ILSpy.BamlDecompiler/XamlContext.cs
index 437277f57..d9be0620c 100644
--- a/ILSpy.BamlDecompiler/XamlContext.cs
+++ b/ILSpy.BamlDecompiler/XamlContext.cs
@@ -23,6 +23,7 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
+using System.Reflection.Metadata;
 using System.Threading;
 using System.Xml.Linq;
 
@@ -40,6 +41,7 @@ namespace ILSpy.BamlDecompiler
 			TypeSystem = typeSystem;
 			NodeMap = new Dictionary<BamlRecord, BamlBlockNode>();
 			XmlNs = new XmlnsDictionary();
+			GeneratedMembers = new List<EntityHandle>();
 			XClassNames = new List<string>();
 		}
 
@@ -57,6 +59,8 @@ namespace ILSpy.BamlDecompiler
 
 		public List<string> XClassNames { get; }
 
+		public List<EntityHandle> GeneratedMembers { get; }
+
 		public XmlnsDictionary XmlNs { get; }
 
 		public static XamlContext Construct(IDecompilerTypeSystem typeSystem, BamlDocument document, CancellationToken token, BamlDecompilerSettings bamlDecompilerOptions)
diff --git a/ILSpy.BamlDecompiler/XamlDecompiler.cs b/ILSpy.BamlDecompiler/XamlDecompiler.cs
index e406516a2..0d5c5205c 100644
--- a/ILSpy.BamlDecompiler/XamlDecompiler.cs
+++ b/ILSpy.BamlDecompiler/XamlDecompiler.cs
@@ -121,7 +121,7 @@ namespace ILSpy.BamlDecompiler
 
 			var assemblyReferences = ctx.Baml.AssemblyIdMap.Select(a => a.Value.AssemblyFullName);
 			var typeName = ctx.XClassNames.FirstOrDefault() is string s ? (FullTypeName?)new FullTypeName(s) : null;
-			return new BamlDecompilationResult(xaml, typeName, assemblyReferences);
+			return new BamlDecompilationResult(xaml, typeName, assemblyReferences, ctx.GeneratedMembers);
 		}
 	}
 }
\ No newline at end of file
diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs
index abdafa2ec..fdbccd101 100644
--- a/ILSpy/Languages/CSharpLanguage.cs
+++ b/ILSpy/Languages/CSharpLanguage.cs
@@ -509,15 +509,17 @@ namespace ICSharpCode.ILSpy
 				this.options = options;
 			}
 
-			protected override IEnumerable<(string itemType, string fileName)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
+			protected override IEnumerable<(string itemType, string fileName, List<PartialTypeInfo> partialTypes)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
 			{
+				var context = new ResourceFileHandlerContext(options);
 				foreach (var handler in App.ExportProvider.GetExportedValues<IResourceFileHandler>())
 				{
-					if (handler.CanHandle(fileName, options))
+					if (handler.CanHandle(fileName, context))
 					{
 						entryStream.Position = 0;
-						fileName = handler.WriteResourceToFile(assembly, fileName, entryStream, options);
-						return new[] { (handler.EntryType, fileName) };
+						fileName = handler.WriteResourceToFile(assembly, fileName, entryStream, context);
+
+						return new[] { (handler.EntryType, fileName, context.PartialTypes) };
 					}
 				}
 				return base.WriteResourceToFile(fileName, resourceName, entryStream);
diff --git a/ILSpy/Languages/IResourceFileHandler.cs b/ILSpy/Languages/IResourceFileHandler.cs
index 43270bec4..8fe336f06 100644
--- a/ILSpy/Languages/IResourceFileHandler.cs
+++ b/ILSpy/Languages/IResourceFileHandler.cs
@@ -16,8 +16,10 @@
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
+using System.Collections.Generic;
 using System.IO;
 
+using ICSharpCode.Decompiler;
 using ICSharpCode.ILSpyX;
 
 namespace ICSharpCode.ILSpy
@@ -25,7 +27,25 @@ namespace ICSharpCode.ILSpy
 	public interface IResourceFileHandler
 	{
 		string EntryType { get; }
-		bool CanHandle(string name, DecompilationOptions options);
-		string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options);
+		bool CanHandle(string name, ResourceFileHandlerContext context);
+		string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, ResourceFileHandlerContext context);
+	}
+
+	public class ResourceFileHandlerContext
+	{
+		readonly List<PartialTypeInfo> partialTypes = new();
+		internal List<PartialTypeInfo> PartialTypes => partialTypes;
+
+		public DecompilationOptions DecompilationOptions { get; }
+
+		public ResourceFileHandlerContext(DecompilationOptions options)
+		{
+			this.DecompilationOptions = options;
+		}
+
+		public void AddPartialTypeInfo(PartialTypeInfo info)
+		{
+			this.PartialTypes.Add(info);
+		}
 	}
 }