Browse Source

Fix #2807: Detect when a compiler-generated/hidden type needs to be decompiled in WholeProjectDecompiler.

pull/2828/head
Siegfried Pammer 3 years ago
parent
commit
71e4d51786
  1. 58
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs

58
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs

@ -32,6 +32,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Transforms; using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -206,8 +207,28 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
IEnumerable<(string itemType, string fileName)> WriteCodeFilesInProject(Metadata.PEFile module, IList<PartialTypeInfo> partialTypes, CancellationToken cancellationToken) IEnumerable<(string itemType, string fileName)> WriteCodeFilesInProject(Metadata.PEFile module, IList<PartialTypeInfo> partialTypes, CancellationToken cancellationToken)
{ {
var metadata = module.Metadata; var metadata = module.Metadata;
var files = module.Metadata.GetTopLevelTypeDefinitions().Where(td => IncludeTypeWhenDecompilingProject(module, td)).GroupBy( var files = module.Metadata.GetTopLevelTypeDefinitions().Where(td => IncludeTypeWhenDecompilingProject(module, td))
delegate (TypeDefinitionHandle h) { .GroupBy(GetFileFileNameForHandle, StringComparer.OrdinalIgnoreCase).ToList();
var progressReporter = ProgressIndicator;
var progress = new DecompilationProgress { TotalUnits = files.Count, Title = "Exporting project..." };
DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, Settings);
var workList = new HashSet<TypeDefinitionHandle>();
var processedTypes = new HashSet<TypeDefinitionHandle>();
ProcessFiles(files);
while (workList.Count > 0)
{
var additionalFiles = workList
.GroupBy(GetFileFileNameForHandle, StringComparer.OrdinalIgnoreCase).ToList();
workList.Clear();
ProcessFiles(additionalFiles);
files.AddRange(additionalFiles);
progress.TotalUnits = files.Count;
}
return files.Select(f => ("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken));
string GetFileFileNameForHandle(TypeDefinitionHandle h)
{
var type = metadata.GetTypeDefinition(h); var type = metadata.GetTypeDefinition(h);
string file = CleanUpFileName(metadata.GetString(type.Name)) + ".cs"; string file = CleanUpFileName(metadata.GetString(type.Name)) + ".cs";
string ns = metadata.GetString(type.Namespace); string ns = metadata.GetString(type.Namespace);
@ -222,10 +243,11 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
Directory.CreateDirectory(Path.Combine(TargetDirectory, dir)); Directory.CreateDirectory(Path.Combine(TargetDirectory, dir));
return Path.Combine(dir, file); return Path.Combine(dir, file);
} }
}, StringComparer.OrdinalIgnoreCase).ToList(); }
var progressReporter = ProgressIndicator;
var progress = new DecompilationProgress { TotalUnits = files.Count, Title = "Exporting project..." }; void ProcessFiles(List<IGrouping<string, TypeDefinitionHandle>> files)
DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, Settings); {
processedTypes.AddRange(files.SelectMany(f => f));
Parallel.ForEach( Parallel.ForEach(
Partitioner.Create(files, loadBalance: true), Partitioner.Create(files, loadBalance: true),
new ParallelOptions { new ParallelOptions {
@ -245,7 +267,27 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
} }
decompiler.CancellationToken = cancellationToken; decompiler.CancellationToken = cancellationToken;
var syntaxTree = decompiler.DecompileTypes(file.ToArray()); var declaredTypes = file.ToArray();
var syntaxTree = decompiler.DecompileTypes(declaredTypes);
foreach (var node in syntaxTree.Descendants)
{
var td = (node.GetResolveResult() as TypeResolveResult)?.Type.GetDefinition();
if (td?.ParentModule != ts.MainModule)
continue;
while (td?.DeclaringTypeDefinition != null)
{
td = td.DeclaringTypeDefinition;
}
if (td != null && td.MetadataToken is { IsNil: false } token && !processedTypes.Contains((TypeDefinitionHandle)token))
{
lock (workList)
{
workList.Add((TypeDefinitionHandle)token);
}
}
}
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, Settings.CSharpFormattingOptions)); syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, Settings.CSharpFormattingOptions));
} }
catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException)) catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException))
@ -257,7 +299,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
Interlocked.Increment(ref progress.UnitsCompleted); Interlocked.Increment(ref progress.UnitsCompleted);
progressReporter?.Report(progress); progressReporter?.Report(progress);
}); });
return files.Select(f => ("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken)); }
} }
#endregion #endregion

Loading…
Cancel
Save