Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…ove WPF compiler-generated code.
  • Loading branch information
siegfriedpammer authored and Charlie Lin committed Jul 16, 2022
1 parent 6a90277 commit dd1c37a
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 70 deletions.
73 changes: 46 additions & 27 deletions ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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;
Expand Down Expand Up @@ -522,6 +523,14 @@ IDocumentationProvider CreateDefaultDocumentationProvider()
}
}

DecompileRun CreateDecompileRun()
{
return new DecompileRun(settings) {
DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(),
CancellationToken = CancellationToken
};
}

void RunTransforms(AstNode rootNode, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
{
var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
Expand Down Expand Up @@ -550,10 +559,7 @@ string SyntaxTreeToString(SyntaxTree syntaxTree)
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);
Expand Down Expand Up @@ -639,10 +645,7 @@ public SyntaxTree DecompileWholeModuleAsSingleFile()
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);
Expand All @@ -664,10 +667,7 @@ public SyntaxTree DecompileWholeModuleAsSingleFile(bool sortTypes)
/// </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,
Expand Down Expand Up @@ -912,10 +912,7 @@ public SyntaxTree DecompileTypes(IEnumerable<TypeDefinitionHandle> types)
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)
Expand Down Expand Up @@ -957,10 +954,7 @@ public SyntaxTree DecompileType(FullTypeName fullTypeName)
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);
Expand Down Expand Up @@ -995,10 +989,7 @@ public SyntaxTree Decompile(IEnumerable<EntityHandle> definitions)
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)
Expand Down Expand Up @@ -1100,6 +1091,20 @@ public string DecompileAsString(IEnumerable<EntityHandle> definitions)
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)
Expand Down Expand Up @@ -1319,14 +1324,19 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun

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)
{
if (entity.MetadataToken.IsNil || MemberIsHidden(module.PEFile, entity.MetadataToken, settings))
{
continue;
}
DoDecompileMember(entity, recordDecompiler);
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
}

// Decompile compiler-generated members that are still needed.
Expand All @@ -1338,7 +1348,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
// Member is already decompiled.
continue;
}
DoDecompileMember(entity, recordDecompiler);
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
}

// Add all decompiled members to syntax tree in the correct order.
Expand All @@ -1352,6 +1362,10 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
// 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))
Expand Down Expand Up @@ -1406,8 +1420,13 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,9 @@ protected WholeProjectDecompiler(
}
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)
{
Expand Down Expand Up @@ -202,7 +203,7 @@ CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
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(
Expand Down Expand Up @@ -237,6 +238,12 @@ CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
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));
Expand All @@ -253,7 +260,7 @@ CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
#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))
{
Expand All @@ -263,7 +270,7 @@ CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
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);
Expand Down Expand Up @@ -323,12 +330,12 @@ CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
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))
{
Expand All @@ -343,7 +350,7 @@ CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
writer.AddResource(entry.Key, entry.Value);
}
}
return new[] { ("EmbeddedResource", resx) };
return new[] { ("EmbeddedResource", resx, (List<PartialTypeInfo>)null) };
}
catch (BadImageFormatException)
{
Expand All @@ -358,7 +365,7 @@ CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
{
entryStream.CopyTo(fs);
}
return new[] { ("EmbeddedResource", fileName) };
return new[] { ("EmbeddedResource", fileName, (List<PartialTypeInfo>)null) };
}

string GetFileNameForResource(string fullName)
Expand Down Expand Up @@ -558,8 +565,8 @@ public static string SanitizeFileName(string fileName)
/// <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)
{
Expand Down
1 change: 1 addition & 0 deletions ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
76 changes: 76 additions & 0 deletions ICSharpCode.Decompiler/PartialTypeInfo.cs
Original file line number Diff line number Diff line change
@@ -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")));
}
}
4 changes: 3 additions & 1 deletion ILSpy.BamlDecompiler/BamlConnectionId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

using ICSharpCode.Decompiler.TypeSystem;

namespace ILSpy.BamlDecompiler
{
/// <summary>
/// Represents a field assignment of a XAML code-behind class.
/// </summary>
internal sealed class FieldAssignment
{
public string FieldName;
public IField Field;
}

/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion ILSpy.BamlDecompiler/BamlDecompilationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Xml.Linq;

using ICSharpCode.Decompiler.TypeSystem;
Expand All @@ -31,11 +32,14 @@ public class BamlDecompilationResult

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();
}
}
}
Loading

0 comments on commit dd1c37a

Please # to comment.