Browse Source

Merge branch 'icsharpcode:master' into GuessFakeMethodAccessor

pull/2677/head
James May 3 years ago committed by GitHub
parent
commit
4aaf452b75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      .github/workflows/build-ilspy.yml
  2. 5
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 4
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. 47
      ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
  5. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  6. 4
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs
  7. 4
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs
  8. 4
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/SequenceOfNestedIfs.cs
  9. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/UnknownTypes.cs
  10. 19
      ICSharpCode.Decompiler.Tests/TestCases/PdbGen/CustomPdbId.xml
  11. 92
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/MetadataAttributes.cs
  12. 182
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  13. 10
      ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs
  14. 46
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  15. 14
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
  16. 2
      ICSharpCode.Decompiler/DecompileRun.cs
  17. 8
      ICSharpCode.Decompiler/Metadata/DotNetCorePathFinderExtensions.cs
  18. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  19. 14
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs
  20. 2
      ICSharpCode.Decompiler/Util/MultiDictionary.cs
  21. 2
      ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj
  22. 2
      ILSpy.Tests/ILSpy.Tests.csproj
  23. 17
      ILSpy/Analyzers/AnalyzeCommand.cs
  24. 4
      ILSpy/MainWindow.xaml.cs
  25. 75
      ILSpy/Metadata/DebugDirectory/CodeViewTreeNode.cs
  26. 62
      ILSpy/Metadata/DebugDirectory/DebugDirectoryEntryTreeNode.cs
  27. 83
      ILSpy/Metadata/DebugDirectory/PdbChecksumTreeNode.cs
  28. 45
      ILSpy/Metadata/DebugDirectoryTreeNode.cs
  29. 4
      ILSpy/Metadata/DebugMetadataTreeNode.cs
  30. 3
      ILSpy/Metadata/Helpers.cs
  31. 2
      ILSpy/Metadata/HexFilterControl.xaml.cs
  32. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  33. 1
      ILSpy/ViewModels/AnalyzerPaneModel.cs
  34. 2
      ILSpy/ViewModels/ToolPaneModel.cs
  35. 1
      packages.props

14
.github/workflows/build-ilspy.yml

@ -47,7 +47,7 @@ jobs: @@ -47,7 +47,7 @@ jobs:
run: msbuild ILSpy.sln /p:Configuration=${{ matrix.configuration }} /p:Platform=$env:BuildPlatform /m
- name: Execute unit tests
run: dotnet test --logger "trx;LogFileName=${{ matrix.configuration }}-test-results.trx" $env:Tests1 $env:Tests2 $env:Tests3
run: dotnet test --logger "junit;LogFileName=${{ matrix.configuration }}.xml" --results-directory test-results $env:Tests1 $env:Tests2 $env:Tests3
env:
Tests1: ICSharpCode.Decompiler.Tests\bin\${{ matrix.configuration }}\net6.0-windows\win-x64\ICSharpCode.Decompiler.Tests.dll
Tests2: ILSpy.Tests\bin\${{ matrix.configuration }}\net6.0-windows\ILSpy.Tests.dll
@ -58,17 +58,13 @@ jobs: @@ -58,17 +58,13 @@ jobs:
if: success() || failure()
with:
name: test-results-${{ matrix.configuration }}
path: '**/*.trx'
path: 'test-results/${{ matrix.configuration }}.xml'
- name: Create Test Report
uses: phoenix-actions/test-reporting@v6
if: github.event_name != 'pull_request' && (success() || failure())
uses: test-summary/action@v1
if: always()
with:
name: Unit Test Results (${{ matrix.configuration }})
path: '**/*.trx'
reporter: dotnet-trx
list-suites: 'all'
list-tests: 'failed'
paths: "test-results/${{ matrix.configuration }}.xml"
- name: Format check
run: python BuildTools\tidy.py

5
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -318,7 +318,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -318,7 +318,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
if ((flags & CompilerOptions.UseRoslynMask) != 0)
{
preprocessorSymbols.Add("NETCORE");
if (!flags.HasFlag(CompilerOptions.TargetNet40))
{
preprocessorSymbols.Add("NETCORE");
}
preprocessorSymbols.Add("ROSLYN");
preprocessorSymbols.Add("CS60");
preprocessorSymbols.Add("VB11");

4
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -54,6 +54,8 @@ @@ -54,6 +54,8 @@
<PackageReference Include="NUnit3TestAdapter" Version="$(NUnitAdapterVersion)" />
<PackageReference Include="coverlet.collector" Version="$(CoverletCollectorVersion)" />
<PackageReference Include="NUnit" Version="$(NUnitVersion)" />
<!-- used for xml test result files -->
<PackageReference Include="JunitXml.TestLogger" Version="$(JUnitXmlTestLoggerVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkVersion)" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="Mono.Cecil" Version="$(MonoCecilVersion)" />
@ -108,6 +110,7 @@ @@ -108,6 +110,7 @@
<Compile Include="Output\InsertParenthesesVisitorTests.cs" />
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
<Compile Include="TestAssemblyResolver.cs" />
<None Include="TestCases\Pretty\MetadataAttributes.cs" />
<None Include="TestCases\Correctness\ComInterop.cs" />
<Compile Include="TestCases\Correctness\DeconstructionTests.cs" />
<Compile Include="TestCases\Correctness\DynamicTests.cs" />
@ -309,6 +312,7 @@ @@ -309,6 +312,7 @@
<ItemGroup>
<Content Include="TestCases\PdbGen\ForLoopTests.xml" />
<Content Include="TestCases\PdbGen\CustomPdbId.xml" />
<Content Include="TestCases\PdbGen\HelloWorld.xml" />
<Content Include="TestCases\PdbGen\LambdaCapturing.xml" />
</ItemGroup>

47
ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Text;
@ -46,18 +47,38 @@ namespace ICSharpCode.Decompiler.Tests @@ -46,18 +47,38 @@ namespace ICSharpCode.Decompiler.Tests
TestGeneratePdb();
}
[Test]
public void CustomPdbId()
{
// Generate a PDB for an assembly using a randomly-generated ID, then validate that the PDB uses the specified ID
(string peFileName, string pdbFileName) = CompileTestCase(nameof(CustomPdbId));
var moduleDefinition = new PEFile(peFileName);
var resolver = new UniversalAssemblyResolver(peFileName, false, moduleDefinition.Metadata.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchEntireImage);
var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings());
var expectedPdbId = new BlobContentId(Guid.NewGuid(), (uint)Random.Shared.Next());
using (FileStream pdbStream = File.Open(Path.Combine(TestCasePath, nameof(CustomPdbId) + ".pdb"), FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
pdbStream.SetLength(0);
PortablePdbWriter.WritePdb(moduleDefinition, decompiler, new DecompilerSettings(), pdbStream, noLogo: true, pdbId: expectedPdbId);
pdbStream.Position = 0;
var metadataReader = MetadataReaderProvider.FromPortablePdbStream(pdbStream).GetMetadataReader();
var generatedPdbId = new BlobContentId(metadataReader.DebugMetadataHeader.Id);
Assert.AreEqual(expectedPdbId.Guid, generatedPdbId.Guid);
Assert.AreEqual(expectedPdbId.Stamp, generatedPdbId.Stamp);
}
}
private void TestGeneratePdb([CallerMemberName] string testName = null)
{
const PdbToXmlOptions options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.ThrowOnError | PdbToXmlOptions.IncludeTokens | PdbToXmlOptions.ResolveTokens | PdbToXmlOptions.IncludeMethodSpans;
string xmlFile = Path.Combine(TestCasePath, testName + ".xml");
string xmlContent = File.ReadAllText(xmlFile);
XDocument document = XDocument.Parse(xmlContent);
var files = document.Descendants("file").ToDictionary(f => f.Attribute("name").Value, f => f.Value);
Tester.CompileCSharpWithPdb(Path.Combine(TestCasePath, testName + ".expected"), files);
(string peFileName, string pdbFileName) = CompileTestCase(testName);
string peFileName = Path.Combine(TestCasePath, testName + ".expected.dll");
string pdbFileName = Path.Combine(TestCasePath, testName + ".expected.pdb");
var moduleDefinition = new PEFile(peFileName);
var resolver = new UniversalAssemblyResolver(peFileName, false, moduleDefinition.Metadata.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchEntireImage);
var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings());
@ -87,6 +108,20 @@ namespace ICSharpCode.Decompiler.Tests @@ -87,6 +108,20 @@ namespace ICSharpCode.Decompiler.Tests
Assert.AreEqual(Normalize(expectedFileName), Normalize(generatedFileName));
}
private (string peFileName, string pdbFileName) CompileTestCase(string testName)
{
string xmlFile = Path.Combine(TestCasePath, testName + ".xml");
string xmlContent = File.ReadAllText(xmlFile);
XDocument document = XDocument.Parse(xmlContent);
var files = document.Descendants("file").ToDictionary(f => f.Attribute("name").Value, f => f.Value);
Tester.CompileCSharpWithPdb(Path.Combine(TestCasePath, testName + ".expected"), files);
string peFileName = Path.Combine(TestCasePath, testName + ".expected.dll");
string pdbFileName = Path.Combine(TestCasePath, testName + ".expected.pdb");
return (peFileName, pdbFileName);
}
private void ProcessXmlFile(string fileName)
{
var document = XDocument.Load(fileName);

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -714,6 +714,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -714,6 +714,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
}
[Test]
public async Task MetadataAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
async Task RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null)
{
await Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings);

4
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs

@ -92,7 +92,7 @@ public static class Program @@ -92,7 +92,7 @@ public static class Program
pc = 2;
}
public override bool get_CheckClose()
public bool get_CheckClose()
{
switch (pc)
{
@ -106,7 +106,7 @@ public static class Program @@ -106,7 +106,7 @@ public static class Program
[DebuggerNonUserCode]
[CompilerGenerated]
public override int get_LastGenerated()
public int get_LastGenerated()
{
return current;
}

4
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs

@ -93,7 +93,7 @@ public static class Program @@ -93,7 +93,7 @@ public static class Program
pc = 2;
}
public override bool get_CheckClose()
public bool get_CheckClose()
{
switch (pc)
{
@ -107,7 +107,7 @@ public static class Program @@ -107,7 +107,7 @@ public static class Program
[DebuggerNonUserCode]
[CompilerGenerated]
public override int get_LastGenerated()
public int get_LastGenerated()
{
return current;
}

4
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/SequenceOfNestedIfs.cs

@ -12,11 +12,11 @@ public class SequenceOfNestedIfs @@ -12,11 +12,11 @@ public class SequenceOfNestedIfs
{
public bool _clear;
public Material _material;
public override bool CheckShader()
public virtual bool CheckShader()
{
return false;
}
public override void CreateMaterials()
public virtual void CreateMaterials()
{
if (!_clear)
{

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/UnknownTypes.cs

@ -2,7 +2,7 @@ internal class UnknownTypes @@ -2,7 +2,7 @@ internal class UnknownTypes
{
private readonly IInterface memberField;
public override bool CanExecute(CallbackQuery message)
public virtual bool CanExecute(CallbackQuery message)
{
return ((IInterface<SomeClass, bool>)(object)memberField).Execute(new SomeClass {
ChatId = StaticClass.GetChatId(message),

19
ICSharpCode.Decompiler.Tests/TestCases/PdbGen/CustomPdbId.xml

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<symbols>
<files>
<file id="1" name="ICSharpCode.Decompiler.Tests.TestCases.PdbGen\HelloWorld.cs" language="C#" checksumAlgorithm="SHA256"><![CDATA[using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.PdbGen;
public class HelloWorld
{
public static void Main(string[] args)
{
Console.ReadKey();
Console.WriteLine("Hello World!");
Console.ReadKey();
}
}
]]></file>
</files>
</symbols>

92
ICSharpCode.Decompiler.Tests/TestCases/Pretty/MetadataAttributes.cs

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class MetadataAttributes
{
private class MethodImplAttr
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public extern void A();
#if NETCORE
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public extern void B();
#endif
[MethodImpl(MethodImplOptions.ForwardRef)]
public extern void D();
[MethodImpl(MethodImplOptions.InternalCall)]
public extern void E();
[MethodImpl(MethodImplOptions.NoInlining)]
public extern void F();
[MethodImpl(MethodImplOptions.NoOptimization)]
public extern void G();
[PreserveSig]
public extern void H();
[MethodImpl(MethodImplOptions.Synchronized)]
public extern void I();
[MethodImpl(MethodImplOptions.Unmanaged)]
public extern void J();
[MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.Native)]
public extern void A1();
#if NETCORE
[MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.Native)]
public extern void B1();
#endif
[MethodImpl(MethodImplOptions.ForwardRef, MethodCodeType = MethodCodeType.Native)]
public extern void D1();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Native)]
public extern void E1();
[MethodImpl(MethodImplOptions.NoInlining, MethodCodeType = MethodCodeType.Native)]
public extern void F1();
[MethodImpl(MethodImplOptions.NoOptimization, MethodCodeType = MethodCodeType.Native)]
public extern void G1();
[MethodImpl(MethodImplOptions.PreserveSig, MethodCodeType = MethodCodeType.Native)]
public extern void H1();
[MethodImpl(MethodImplOptions.Synchronized, MethodCodeType = MethodCodeType.Native)]
public extern void I1();
[MethodImpl(MethodImplOptions.Unmanaged, MethodCodeType = MethodCodeType.Native)]
public extern void J1();
[MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.OPTIL)]
public extern void A2();
#if NETCORE
[MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.OPTIL)]
public extern void B2();
#endif
[MethodImpl(MethodImplOptions.ForwardRef, MethodCodeType = MethodCodeType.OPTIL)]
public extern void D2();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.OPTIL)]
public extern void E2();
[MethodImpl(MethodImplOptions.NoInlining, MethodCodeType = MethodCodeType.OPTIL)]
public extern void F2();
[MethodImpl(MethodImplOptions.NoOptimization, MethodCodeType = MethodCodeType.OPTIL)]
public extern void G2();
[MethodImpl(MethodImplOptions.PreserveSig, MethodCodeType = MethodCodeType.OPTIL)]
public extern void H2();
[MethodImpl(MethodImplOptions.Synchronized, MethodCodeType = MethodCodeType.OPTIL)]
public extern void I2();
[MethodImpl(MethodImplOptions.Unmanaged, MethodCodeType = MethodCodeType.OPTIL)]
public extern void J2();
[MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.OPTIL)]
public extern void A3();
#if NETCORE
[MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.Runtime)]
public extern void B3();
#endif
[MethodImpl(MethodImplOptions.ForwardRef, MethodCodeType = MethodCodeType.Runtime)]
public extern void D3();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
public extern void E3();
[MethodImpl(MethodImplOptions.NoInlining, MethodCodeType = MethodCodeType.Runtime)]
public extern void F3();
[MethodImpl(MethodImplOptions.NoOptimization, MethodCodeType = MethodCodeType.Runtime)]
public extern void G3();
[MethodImpl(MethodImplOptions.PreserveSig, MethodCodeType = MethodCodeType.Runtime)]
public extern void H3();
[MethodImpl(MethodImplOptions.Synchronized, MethodCodeType = MethodCodeType.Runtime)]
public extern void I3();
[MethodImpl(MethodImplOptions.Unmanaged, MethodCodeType = MethodCodeType.Runtime)]
public extern void J3();
}
}
}

182
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -289,6 +289,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -289,6 +289,9 @@ namespace ICSharpCode.Decompiler.CSharp
var methodSemantics = module.MethodSemanticsLookup.GetSemantics(methodHandle).Item2;
if (methodSemantics != 0 && methodSemantics != System.Reflection.MethodSemanticsAttributes.Other)
return true;
name = metadata.GetString(method.Name);
if (name == ".ctor" && method.RelativeVirtualAddress == 0 && metadata.GetTypeDefinition(method.GetDeclaringType()).Attributes.HasFlag(System.Reflection.TypeAttributes.Import))
return true;
if (settings.LocalFunctions && LocalFunctionDecompiler.IsLocalFunctionMethod(module, methodHandle))
return true;
if (settings.AnonymousMethods && methodHandle.HasGeneratedName(metadata) && methodHandle.IsCompilerGenerated(metadata))
@ -1107,6 +1110,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1107,6 +1110,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
yield break; // cannot create forwarder for static interface impl
}
if (memberDecl.HasModifier(Modifiers.Extern))
{
yield break; // cannot create forwarder for extern method
}
var genericContext = new Decompiler.TypeSystem.GenericContext(method);
var methodHandle = (MethodDefinitionHandle)method.MetadataToken;
foreach (var h in methodHandle.GetMethodImplementations(metadata))
@ -1244,9 +1251,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1244,9 +1251,12 @@ namespace ICSharpCode.Decompiler.CSharp
{
Debug.Assert(decompilationContext.CurrentTypeDefinition == typeDef);
var watch = System.Diagnostics.Stopwatch.StartNew();
var entityMap = new MultiDictionary<IEntity, EntityDeclaration>();
var workList = new Queue<IEntity>();
TypeSystemAstBuilder typeSystemAstBuilder;
try
{
var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
var entityDecl = typeSystemAstBuilder.ConvertEntity(typeDef);
var typeDecl = entityDecl as TypeDeclaration;
if (typeDecl == null)
@ -1289,16 +1299,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1289,16 +1299,6 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
foreach (var type in typeDef.NestedTypes)
{
if (!type.MetadataToken.IsNil && !MemberIsHidden(module.PEFile, type.MetadataToken, settings))
{
var nestedType = DoDecompile(type, decompileRun, decompilationContext.WithCurrentTypeDefinition(type));
SetNewModifier(nestedType);
typeDecl.Members.Add(nestedType);
}
}
decompileRun.EnumValueDisplayMode = typeDef.Kind == TypeKind.Enum
? DetectBestEnumValueDisplayMode(typeDef, module.PEFile)
: null;
@ -1309,60 +1309,38 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1309,60 +1309,38 @@ namespace ICSharpCode.Decompiler.CSharp
// For COM interop scenarios, the relative order of virtual functions/properties matters:
IEnumerable<IMember> allOrderedMembers = RequiresNativeOrdering(typeDef) ? GetMembersWithNativeOrdering(typeDef) :
fieldsAndProperties.Concat<IMember>(typeDef.Events).Concat<IMember>(typeDef.Methods);
fieldsAndProperties.Concat(typeDef.Events).Concat(typeDef.Methods);
foreach (var member in allOrderedMembers)
var allOrderedEntities = typeDef.NestedTypes.Concat<IEntity>(allOrderedMembers);
// Decompile members that are not compiler-generated.
foreach (var entity in allOrderedEntities)
{
if (member is IField || member is IProperty)
if (entity.MetadataToken.IsNil || MemberIsHidden(module.PEFile, entity.MetadataToken, settings))
{
var fieldOrProperty = member;
if (fieldOrProperty.MetadataToken.IsNil || MemberIsHidden(module.PEFile, fieldOrProperty.MetadataToken, settings))
{
continue;
}
if (fieldOrProperty is IField field)
{
if (typeDef.Kind == TypeKind.Enum && !field.IsConst)
continue;
var memberDecl = DoDecompile(field, decompileRun, decompilationContext.WithCurrentMember(field));
typeDecl.Members.Add(memberDecl);
}
else if (fieldOrProperty is IProperty property)
{
if (recordDecompiler?.PropertyIsGenerated(property) == true)
{
continue;
}
var propDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property));
typeDecl.Members.Add(propDecl);
}
}
else if (member is IMethod method)
{
if (recordDecompiler?.MethodIsGenerated(method) == true)
{
continue;
}
if (!method.MetadataToken.IsNil && !MemberIsHidden(module.PEFile, method.MetadataToken, settings))
{
var memberDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method));
typeDecl.Members.Add(memberDecl);
typeDecl.Members.AddRange(AddInterfaceImplHelpers(memberDecl, method, typeSystemAstBuilder));
}
}
else if (member is IEvent @event)
{
if (!@event.MetadataToken.IsNil && !MemberIsHidden(module.PEFile, @event.MetadataToken, settings))
{
var eventDecl = DoDecompile(@event, decompileRun, decompilationContext.WithCurrentMember(@event));
typeDecl.Members.Add(eventDecl);
}
continue;
}
else
DoDecompileMember(entity, recordDecompiler);
}
// Decompile compiler-generated members that are still needed.
while (workList.Count > 0)
{
var entity = workList.Dequeue();
if (entityMap.Contains(entity) || entity.MetadataToken.IsNil)
{
throw new ArgumentOutOfRangeException("Unexpected member type");
// Member is already decompiled.
continue;
}
DoDecompileMember(entity, recordDecompiler);
}
// Add all decompiled members to syntax tree in the correct order.
foreach (var member in allOrderedEntities)
{
typeDecl.Members.AddRange(entityMap[member]);
}
if (typeDecl.Members.OfType<IndexerDeclaration>().Any(idx => idx.PrivateImplementationType.IsNull))
{
// Remove the [DefaultMember] attribute if the class contains indexers
@ -1421,6 +1399,69 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1421,6 +1399,69 @@ namespace ICSharpCode.Decompiler.CSharp
watch.Stop();
Instrumentation.DecompilerEventSource.Log.DoDecompileTypeDefinition(typeDef.FullName, watch.ElapsedMilliseconds);
}
void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler)
{
EntityDeclaration entityDecl;
switch (entity)
{
case IField field:
if (typeDef.Kind == TypeKind.Enum && !field.IsConst)
{
return;
}
entityDecl = DoDecompile(field, decompileRun, decompilationContext.WithCurrentMember(field));
entityMap.Add(field, entityDecl);
break;
case IProperty property:
if (recordDecompiler?.PropertyIsGenerated(property) == true)
{
return;
}
entityDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property));
entityMap.Add(property, entityDecl);
break;
case IMethod method:
if (recordDecompiler?.MethodIsGenerated(method) == true)
{
return;
}
entityDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method));
entityMap.Add(method, entityDecl);
foreach (var helper in AddInterfaceImplHelpers(entityDecl, method, typeSystemAstBuilder))
{
entityMap.Add(method, helper);
}
break;
case IEvent @event:
entityDecl = DoDecompile(@event, decompileRun, decompilationContext.WithCurrentMember(@event));
entityMap.Add(@event, entityDecl);
break;
case ITypeDefinition type:
entityDecl = DoDecompile(type, decompileRun, decompilationContext.WithCurrentTypeDefinition(type));
SetNewModifier(entityDecl);
entityMap.Add(type, entityDecl);
break;
default:
throw new ArgumentOutOfRangeException("Unexpected member type");
}
foreach (var node in entityDecl.Descendants)
{
var rr = node.GetResolveResult();
if (rr is MemberResolveResult mrr
&& mrr.Member.DeclaringTypeDefinition == typeDef
&& !(mrr.Member is IMethod { IsLocalFunction: true }))
{
workList.Enqueue(mrr.Member);
}
else if (rr is TypeResolveResult trr
&& trr.Type.GetDefinition()?.DeclaringTypeDefinition == typeDef)
{
workList.Enqueue(trr.Type.GetDefinition());
}
}
}
}
EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, PEFile module)
@ -1529,6 +1570,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1529,6 +1570,16 @@ namespace ICSharpCode.Decompiler.CSharp
{
SetNewModifier(methodDecl);
}
else if (!method.IsStatic && !method.IsExplicitInterfaceImplementation
&& !method.IsVirtual && method.IsOverride
&& InheritanceHelper.GetBaseMember(method) == null && IsTypeHierarchyKnown(method.DeclaringType))
{
methodDecl.Modifiers &= ~Modifiers.Override;
if (!method.DeclaringTypeDefinition.IsSealed)
{
methodDecl.Modifiers |= Modifiers.Virtual;
}
}
if (IsCovariantReturnOverride(method))
{
RemoveAttribute(methodDecl, KnownAttribute.PreserveBaseOverrides);
@ -1536,6 +1587,21 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1536,6 +1587,21 @@ namespace ICSharpCode.Decompiler.CSharp
methodDecl.Modifiers |= Modifiers.Override;
}
return methodDecl;
bool IsTypeHierarchyKnown(IType type)
{
var definition = type.GetDefinition();
if (definition == null)
{
return false;
}
if (decompileRun.TypeHierarchyIsKnown.TryGetValue(definition, out var value))
return value;
value = method.DeclaringType.GetNonInterfaceBaseTypes().All(t => t.Kind != TypeKind.Unknown);
decompileRun.TypeHierarchyIsKnown.Add(definition, value);
return value;
}
}
finally
{

10
ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs

@ -302,7 +302,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -302,7 +302,15 @@ namespace ICSharpCode.Decompiler.CSharp
case OperandType.Sig:
case OperandType.Tok:
case OperandType.Type:
var handle = MetadataTokenHelpers.EntityHandleOrNil(instructions.ReadInt32());
EntityHandle handle;
try
{
handle = MetadataTokenHelpers.EntityHandleOrNil(instructions.ReadInt32());
}
catch (BadImageFormatException)
{
return;
}
if (handle.IsNil)
break;
switch (handle.Kind)

46
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -640,17 +640,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -640,17 +640,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
propertyDeclaration.Modifiers &= ~Modifiers.Readonly;
propertyDeclaration.Getter.Modifiers &= ~Modifiers.Readonly;
// Add C# 7.3 attributes on backing field:
var attributes = field.GetAttributes()
.Where(a => !attributeTypesToRemoveFromAutoProperties.Contains(a.AttributeType.FullName))
.Select(context.TypeSystemAstBuilder.ConvertAttribute).ToArray();
if (attributes.Length > 0)
var fieldDecl = propertyDeclaration.Parent?.Children.OfType<FieldDeclaration>()
.FirstOrDefault(fd => field.Equals(fd.GetSymbol()));
if (fieldDecl != null)
{
var section = new AttributeSection {
AttributeTarget = "field"
};
section.Attributes.AddRange(attributes);
propertyDeclaration.Attributes.Add(section);
fieldDecl.Remove();
// Add C# 7.3 attributes on backing field:
CSharpDecompiler.RemoveAttribute(fieldDecl, KnownAttribute.CompilerGenerated);
CSharpDecompiler.RemoveAttribute(fieldDecl, KnownAttribute.DebuggerBrowsable);
foreach (var section in fieldDecl.Attributes)
{
section.AttributeTarget = "field";
propertyDeclaration.Attributes.Add(section.Detach());
}
}
}
// Since the property instance is not changed, we can continue in the visitor as usual, so return null
@ -1010,23 +1012,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1010,23 +1012,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
ed.Variables.Add(new VariableInitializer(ev.Name));
ed.CopyAnnotationsFrom(ev);
if (ev.GetSymbol() is IEvent eventDef)
var fieldDecl = ev.Parent?.Children.OfType<FieldDeclaration>()
.FirstOrDefault(fd => fd.Variables.Single().Name == ev.Name);
if (fieldDecl != null)
{
IField field = eventDef.DeclaringType.GetFields(f => f.Name == ev.Name, GetMemberOptions.IgnoreInheritedMembers).SingleOrDefault();
if (field != null)
fieldDecl.Remove();
CSharpDecompiler.RemoveAttribute(fieldDecl, KnownAttribute.CompilerGenerated);
CSharpDecompiler.RemoveAttribute(fieldDecl, KnownAttribute.DebuggerBrowsable);
foreach (var section in fieldDecl.Attributes)
{
ed.AddAnnotation(field);
var attributes = field.GetAttributes()
.Where(a => !attributeTypesToRemoveFromAutoEvents.Contains(a.AttributeType.FullName))
.Select(context.TypeSystemAstBuilder.ConvertAttribute).ToArray();
if (attributes.Length > 0)
{
var section = new AttributeSection {
AttributeTarget = "field"
};
section.Attributes.AddRange(attributes);
ed.Attributes.Add(section);
}
section.AttributeTarget = "field";
ed.Attributes.Add(section.Detach());
}
}

14
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
return file.Reader.ReadDebugDirectory().Any(entry => entry.Type == DebugDirectoryEntryType.CodeView);
}
public static void WritePdb(PEFile file, CSharpDecompiler decompiler, DecompilerSettings settings, Stream targetStream, bool noLogo = false)
public static void WritePdb(PEFile file, CSharpDecompiler decompiler, DecompilerSettings settings, Stream targetStream, bool noLogo = false, BlobContentId? pdbId = null)
{
MetadataBuilder metadata = new MetadataBuilder();
MetadataReader reader = file.Metadata;
@ -195,10 +195,14 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -195,10 +195,14 @@ namespace ICSharpCode.Decompiler.DebugInfo
metadata.AddCustomDebugInformation(row.Parent, row.Guid, row.Blob);
}
var debugDir = file.Reader.ReadDebugDirectory().FirstOrDefault(dir => dir.Type == DebugDirectoryEntryType.CodeView);
var portable = file.Reader.ReadCodeViewDebugDirectoryData(debugDir);
var contentId = new BlobContentId(portable.Guid, debugDir.Stamp);
PortablePdbBuilder serializer = new PortablePdbBuilder(metadata, GetRowCounts(reader), entrypointHandle, blobs => contentId);
if (pdbId == null)
{
var debugDir = file.Reader.ReadDebugDirectory().FirstOrDefault(dir => dir.Type == DebugDirectoryEntryType.CodeView);
var portable = file.Reader.ReadCodeViewDebugDirectoryData(debugDir);
pdbId = new BlobContentId(portable.Guid, debugDir.Stamp);
}
PortablePdbBuilder serializer = new PortablePdbBuilder(metadata, GetRowCounts(reader), entrypointHandle, blobs => pdbId.Value);
BlobBuilder blobBuilder = new BlobBuilder();
serializer.Serialize(blobBuilder);
blobBuilder.WriteContentTo(targetStream);

2
ICSharpCode.Decompiler/DecompileRun.cs

@ -19,6 +19,8 @@ namespace ICSharpCode.Decompiler @@ -19,6 +19,8 @@ namespace ICSharpCode.Decompiler
public IDocumentationProvider DocumentationProvider { get; set; }
public Dictionary<ITypeDefinition, RecordDecompiler> RecordDecompilers { get; } = new Dictionary<ITypeDefinition, RecordDecompiler>();
public Dictionary<ITypeDefinition, bool> TypeHierarchyIsKnown { get; } = new();
Lazy<CSharp.TypeSystem.UsingScope> usingScope =>
new Lazy<CSharp.TypeSystem.UsingScope>(() => CreateUsingScope(Namespaces));

8
ICSharpCode.Decompiler/Metadata/DotNetCorePathFinderExtensions.cs

@ -73,13 +73,13 @@ namespace ICSharpCode.Decompiler.Metadata @@ -73,13 +73,13 @@ namespace ICSharpCode.Decompiler.Metadata
if (metadata.IsAssembly)
{
var thisAssemblyName = metadata.GetAssemblyDefinition().GetAssemblyName();
switch (thisAssemblyName.Name)
AssemblyDefinition assemblyDefinition = metadata.GetAssemblyDefinition();
switch (metadata.GetString(assemblyDefinition.Name))
{
case "mscorlib":
return $".NETFramework,Version=v{thisAssemblyName.Version.ToString(2)}";
return $".NETFramework,Version=v{assemblyDefinition.Version.ToString(2)}";
case "netstandard":
return $".NETStandard,Version=v{thisAssemblyName.Version.ToString(2)}";
return $".NETStandard,Version=v{assemblyDefinition.Version.ToString(2)}";
}
}

2
ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

@ -48,6 +48,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -48,6 +48,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
SpecialName,
DebuggerHidden,
DebuggerStepThrough,
DebuggerBrowsable,
// Assembly attributes:
AssemblyVersion,
@ -124,6 +125,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -124,6 +125,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(SpecialNameAttribute)),
new TopLevelTypeName("System.Diagnostics", nameof(DebuggerHiddenAttribute)),
new TopLevelTypeName("System.Diagnostics", nameof(DebuggerStepThroughAttribute)),
new TopLevelTypeName("System.Diagnostics", nameof(DebuggerBrowsableAttribute)),
// Assembly attributes:
new TopLevelTypeName("System.Reflection", nameof(AssemblyVersionAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(InternalsVisibleToAttribute)),

14
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

@ -333,6 +333,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -333,6 +333,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
var metadata = module.metadata;
var def = metadata.GetMethodDefinition(handle);
MethodImplAttributes implAttributes = def.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
int methodCodeType = (int)(def.ImplAttributes & MethodImplAttributes.CodeTypeMask);
#region DllImportAttribute
var info = def.GetImport();
@ -430,7 +431,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -430,7 +431,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
#endregion
#region PreserveSigAttribute
if (implAttributes == MethodImplAttributes.PreserveSig)
if (implAttributes == MethodImplAttributes.PreserveSig && methodCodeType == 0)
{
b.Add(KnownAttribute.PreserveSig);
implAttributes = 0;
@ -440,10 +441,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -440,10 +441,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
#region MethodImplAttribute
if (implAttributes != 0)
{
b.Add(KnownAttribute.MethodImpl,
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(MethodImplOptions)),
(int)implAttributes
);
var methodImpl = new AttributeBuilder(module, KnownAttribute.MethodImpl);
methodImpl.AddFixedArg(new TopLevelTypeName("System.Runtime.CompilerServices", nameof(MethodImplOptions)), (int)implAttributes);
if (methodCodeType != 0)
{
methodImpl.AddNamedArg("MethodCodeType", new TopLevelTypeName("System.Runtime.CompilerServices", nameof(MethodCodeType)), methodCodeType);
}
b.Add(methodImpl.Build());
}
#endregion

2
ICSharpCode.Decompiler/Util/MultiDictionary.cs

@ -105,7 +105,7 @@ namespace ICSharpCode.Decompiler.Util @@ -105,7 +105,7 @@ namespace ICSharpCode.Decompiler.Util
get { return this[key]; }
}
bool ILookup<TKey, TValue>.Contains(TKey key)
public bool Contains(TKey key)
{
return dict.ContainsKey(key);
}

2
ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -33,6 +33,8 @@ @@ -33,6 +33,8 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkVersion)" />
<PackageReference Include="NUnit" Version="$(NUnitVersion)" />
<PackageReference Include="NUnit3TestAdapter" Version="$(NUnitAdapterVersion)" />
<!-- used for xml test result files -->
<PackageReference Include="JunitXml.TestLogger" Version="$(JUnitXmlTestLoggerVersion)" />
<PackageReference Include="coverlet.collector" Version="$(CoverletCollectorVersion)" />
</ItemGroup>

2
ILSpy.Tests/ILSpy.Tests.csproj

@ -52,6 +52,8 @@ @@ -52,6 +52,8 @@
<PackageReference Include="NUnit3TestAdapter" Version="$(NUnitAdapterVersion)" />
<PackageReference Include="coverlet.collector" Version="$(CoverletCollectorVersion)" />
<PackageReference Include="NUnit" Version="$(NUnitVersion)" />
<!-- used for xml test result files -->
<PackageReference Include="JunitXml.TestLogger" Version="$(JUnitXmlTestLoggerVersion)" />
<PackageReference Include="Moq" Version="$(MoqVersion)" />
</ItemGroup>

17
ILSpy/Analyzers/AnalyzeCommand.cs

@ -58,24 +58,30 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -58,24 +58,30 @@ namespace ICSharpCode.ILSpy.Analyzers
public void Execute(TextViewContext context)
{
AnalyzerTreeView analyzerTreeView = MainWindow.Instance.AnalyzerTreeView;
if (analyzerTreeView == null)
{
return;
}
if (context.SelectedTreeNodes != null)
{
foreach (IMemberTreeNode node in context.SelectedTreeNodes)
{
MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member);
analyzerTreeView.Analyze(node.Member);
}
}
else if (context.Reference != null && context.Reference.Reference is IEntity entity)
{
MainWindow.Instance.AnalyzerTreeView.Analyze(entity);
analyzerTreeView.Analyze(entity);
}
}
public override bool CanExecute(object parameter)
{
if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin)
AnalyzerTreeView analyzerTreeView = MainWindow.Instance.AnalyzerTreeView;
if (analyzerTreeView != null && analyzerTreeView.IsKeyboardFocusWithin)
{
return MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode);
return analyzerTreeView.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode);
}
else
{
@ -85,7 +91,8 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -85,7 +91,8 @@ namespace ICSharpCode.ILSpy.Analyzers
public override void Execute(object parameter)
{
if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin)
AnalyzerTreeView analyzerTreeView = MainWindow.Instance.AnalyzerTreeView;
if (analyzerTreeView != null && analyzerTreeView.IsKeyboardFocusWithin)
{
foreach (IMemberTreeNode node in MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType<IMemberTreeNode>().ToArray())
{

4
ILSpy/MainWindow.xaml.cs

@ -89,7 +89,7 @@ namespace ICSharpCode.ILSpy @@ -89,7 +89,7 @@ namespace ICSharpCode.ILSpy
public AnalyzerTreeView AnalyzerTreeView {
get {
return FindResource("AnalyzerTreeView") as AnalyzerTreeView;
return !IsLoaded ? null : FindResource("AnalyzerTreeView") as AnalyzerTreeView;
}
}
@ -428,7 +428,7 @@ namespace ICSharpCode.ILSpy @@ -428,7 +428,7 @@ namespace ICSharpCode.ILSpy
MenuItem CreateMenuItem(ToolPaneModel pane)
{
MenuItem menuItem = new MenuItem();
menuItem.Command = new ToolPaneCommand(pane.ContentId);
menuItem.Command = pane.AssociatedCommand ?? new ToolPaneCommand(pane.ContentId);
menuItem.Header = pane.Title;
menuItem.Tag = pane;
var shortcutKey = pane.ShortcutKey;

75
ILSpy/Metadata/DebugDirectory/CodeViewTreeNode.cs

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// 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.
#nullable enable
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Metadata
{
sealed class CodeViewTreeNode : ILSpyTreeNode
{
readonly CodeViewDebugDirectoryData entry;
public CodeViewTreeNode(CodeViewDebugDirectoryData entry)
{
this.entry = entry;
}
override public object Text => nameof(DebugDirectoryEntryType.CodeView);
public override object ToolTip => "Associated PDB file description.";
public override object Icon => Images.Literal;
public override bool View(TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
tabPage.SupportsLanguageSwitching = false;
var dataGrid = Helpers.PrepareDataGrid(tabPage, this);
dataGrid.ItemsSource = new[] { entry };
tabPage.Content = dataGrid;
return true;
}
sealed class PdbChecksumDebugDirectoryDataEntry
{
readonly CodeViewDebugDirectoryData entry;
public PdbChecksumDebugDirectoryDataEntry(CodeViewDebugDirectoryData entry)
{
this.entry = entry;
}
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, Text.ToString());
language.WriteCommentLine(output, $"GUID: {entry.Guid}");
language.WriteCommentLine(output, $"Age: {entry.Age}");
language.WriteCommentLine(output, $"Path: {entry.Path}");
}
}
}

62
ILSpy/Metadata/DebugDirectory/DebugDirectoryEntryTreeNode.cs

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// 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.
#nullable enable
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Metadata
{
sealed class DebugDirectoryEntryTreeNode : ILSpyTreeNode
{
readonly PEFile module;
readonly PEReader reader;
readonly DebugDirectoryEntry entry;
public DebugDirectoryEntryTreeNode(PEFile module, DebugDirectoryEntry entry)
{
this.module = module;
this.reader = module.Reader;
this.entry = entry;
}
override public object Text => $"{entry.Type}";
public override object Icon => Images.Literal;
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, Text.ToString());
if (entry.DataSize > 0)
{
language.WriteCommentLine(output, $"Raw Data ({entry.DataSize}):");
int dataOffset = module.Reader.IsLoadedImage ? entry.DataRelativeVirtualAddress : entry.DataPointer;
var data = module.Reader.GetEntireImage().GetContent(dataOffset, entry.DataSize);
language.WriteCommentLine(output, data.ToHexString(data.Length));
}
else
{
language.WriteCommentLine(output, $"(no data)");
}
}
}
}

83
ILSpy/Metadata/DebugDirectory/PdbChecksumTreeNode.cs

@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// 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.
#nullable enable
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Metadata
{
sealed class PdbChecksumTreeNode : ILSpyTreeNode
{
readonly PdbChecksumDebugDirectoryData entry;
public PdbChecksumTreeNode(PdbChecksumDebugDirectoryData entry)
{
this.entry = entry;
}
override public object Text => nameof(DebugDirectoryEntryType.PdbChecksum);
public override object ToolTip
=> "The entry stores a crypto hash of the content of the symbol file the PE/COFF\n"
+ "file was built with. The hash can be used to validate that a given PDB file was\n"
+ "built with the PE/COFF file and not altered in any way. More than one entry can\n"
+ "be present if multiple PDBs were produced during the build of the PE/COFF file\n"
+ "(for example, private and public symbols).";
public override object Icon => Images.Literal;
public override bool View(TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
tabPage.SupportsLanguageSwitching = false;
var dataGrid = Helpers.PrepareDataGrid(tabPage, this);
dataGrid.ItemsSource = new[] { new PdbChecksumDebugDirectoryDataEntry(entry) };
tabPage.Content = dataGrid;
return true;
}
sealed class PdbChecksumDebugDirectoryDataEntry
{
readonly PdbChecksumDebugDirectoryData entry;
public PdbChecksumDebugDirectoryDataEntry(PdbChecksumDebugDirectoryData entry)
{
this.entry = entry;
}
public string AlgorithmName => entry.AlgorithmName;
public string Checksum => entry.Checksum.ToHexString(entry.Checksum.Length);
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, Text.ToString());
language.WriteCommentLine(output, $"AlgorithmName: {entry.AlgorithmName}");
language.WriteCommentLine(output, $"Checksum: {entry.Checksum.ToHexString(entry.Checksum.Length)}");
}
}
}

45
ILSpy/Metadata/DebugDirectoryTreeNode.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.Generic;
using System.Reflection.PortableExecutable;
@ -36,6 +38,7 @@ namespace ICSharpCode.ILSpy.Metadata @@ -36,6 +38,7 @@ namespace ICSharpCode.ILSpy.Metadata
public DebugDirectoryTreeNode(PEFile module)
{
this.module = module;
this.LazyLoading = true;
}
public override object Text => "Debug Directory";
@ -51,7 +54,10 @@ namespace ICSharpCode.ILSpy.Metadata @@ -51,7 +54,10 @@ namespace ICSharpCode.ILSpy.Metadata
var entries = new List<DebugDirectoryEntryView>();
foreach (var entry in module.Reader.ReadDebugDirectory())
{
entries.Add(new DebugDirectoryEntryView(entry));
int dataOffset = module.Reader.IsLoadedImage ? entry.DataRelativeVirtualAddress : entry.DataPointer;
var data = module.Reader.GetEntireImage().GetContent(dataOffset, entry.DataSize);
entries.Add(new DebugDirectoryEntryView(entry, data.ToHexString(data.Length)));
}
dataGrid.ItemsSource = entries.ToArray();
@ -60,6 +66,37 @@ namespace ICSharpCode.ILSpy.Metadata @@ -60,6 +66,37 @@ namespace ICSharpCode.ILSpy.Metadata
return true;
}
protected override void LoadChildren()
{
foreach (var entry in module.Reader.ReadDebugDirectory())
{
switch (entry.Type)
{
case DebugDirectoryEntryType.CodeView:
var codeViewData = module.Reader.ReadCodeViewDebugDirectoryData(entry);
this.Children.Add(new CodeViewTreeNode(codeViewData));
break;
case DebugDirectoryEntryType.EmbeddedPortablePdb:
var embeddedPortablePdbReader = module.Reader.ReadEmbeddedPortablePdbDebugDirectoryData(entry).GetMetadataReader();
this.Children.Add(new DebugMetadataTreeNode(module, isEmbedded: true, provider: embeddedPortablePdbReader));
break;
case DebugDirectoryEntryType.PdbChecksum:
var pdbChecksumData = module.Reader.ReadPdbChecksumDebugDirectoryData(entry);
this.Children.Add(new PdbChecksumTreeNode(pdbChecksumData));
break;
case DebugDirectoryEntryType.Unknown:
case DebugDirectoryEntryType.Coff:
case DebugDirectoryEntryType.Reproducible:
default:
this.Children.Add(new DebugDirectoryEntryTreeNode(module, entry));
break;
}
}
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, "Data Directories");
@ -67,7 +104,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -67,7 +104,6 @@ namespace ICSharpCode.ILSpy.Metadata
class DebugDirectoryEntryView
{
public int Characteristics { get; set; }
public uint Timestamp { get; set; }
public ushort MajorVersion { get; set; }
public ushort MinorVersion { get; set; }
@ -75,10 +111,11 @@ namespace ICSharpCode.ILSpy.Metadata @@ -75,10 +111,11 @@ namespace ICSharpCode.ILSpy.Metadata
public int SizeOfRawData { get; set; }
public int AddressOfRawData { get; set; }
public int PointerToRawData { get; set; }
public string RawData { get; set; }
public DebugDirectoryEntryView(DebugDirectoryEntry entry)
public DebugDirectoryEntryView(DebugDirectoryEntry entry, string data)
{
this.Characteristics = 0;
this.RawData = data;
this.Timestamp = entry.Stamp;
this.MajorVersion = entry.MajorVersion;
this.MinorVersion = entry.MinorVersion;

4
ILSpy/Metadata/DebugMetadataTreeNode.cs

@ -32,14 +32,12 @@ namespace ICSharpCode.ILSpy.Metadata @@ -32,14 +32,12 @@ namespace ICSharpCode.ILSpy.Metadata
{
private PEFile module;
private MetadataReader provider;
private AssemblyTreeNode assemblyTreeNode;
private bool isEmbedded;
public DebugMetadataTreeNode(PEFile module, bool isEmbedded, MetadataReader provider, AssemblyTreeNode assemblyTreeNode)
public DebugMetadataTreeNode(PEFile module, bool isEmbedded, MetadataReader provider)
{
this.module = module;
this.provider = provider;
this.assemblyTreeNode = assemblyTreeNode;
this.isEmbedded = isEmbedded;
this.Text = "Debug Metadata (" + (isEmbedded ? "Embedded" : "From portable PDB") + ")";
this.LazyLoading = true;

3
ILSpy/Metadata/Helpers.cs

@ -136,6 +136,7 @@ namespace ICSharpCode.ILSpy.Metadata @@ -136,6 +136,7 @@ namespace ICSharpCode.ILSpy.Metadata
{
return new DataGridCheckBoxColumn() {
Header = e.PropertyName,
SortMemberPath = e.PropertyName,
Binding = binding
};
}
@ -146,12 +147,14 @@ namespace ICSharpCode.ILSpy.Metadata @@ -146,12 +147,14 @@ namespace ICSharpCode.ILSpy.Metadata
{
return new DataGridTemplateColumn() {
Header = e.PropertyName,
SortMemberPath = e.PropertyName,
CellTemplate = GetOrCreateLinkCellTemplate(e.PropertyName, descriptor, binding)
};
}
return new DataGridTextColumn() {
Header = e.PropertyName,
SortMemberPath = e.PropertyName,
Binding = binding
};
}

2
ILSpy/Metadata/HexFilterControl.xaml.cs

@ -73,6 +73,8 @@ namespace ICSharpCode.ILSpy.Metadata @@ -73,6 +73,8 @@ namespace ICSharpCode.ILSpy.Metadata
public bool IsMatch(object value)
{
if (string.IsNullOrWhiteSpace(filter))
return true;
if (value == null)
return false;

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -210,7 +210,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -210,7 +210,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (debugInfo is PortableDebugInfoProvider ppdb
&& ppdb.GetMetadataReader() is System.Reflection.Metadata.MetadataReader reader)
{
this.Children.Add(new Metadata.DebugMetadataTreeNode(module, ppdb.IsEmbedded, reader, this));
this.Children.Add(new Metadata.DebugMetadataTreeNode(module, ppdb.IsEmbedded, reader));
}
this.Children.Add(new ReferenceFolderTreeNode(module, this));
if (module.Resources.Any())

1
ILSpy/ViewModels/AnalyzerPaneModel.cs

@ -31,6 +31,7 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -31,6 +31,7 @@ namespace ICSharpCode.ILSpy.ViewModels
ContentId = PaneContentId;
Title = Properties.Resources.Analyze;
ShortcutKey = new KeyGesture(Key.R, ModifierKeys.Control);
AssociatedCommand = ILSpyCommands.Analyze;
}
public override DataTemplate Template => (DataTemplate)MainWindow.Instance.FindResource("AnalyzerPaneTemplate");

2
ILSpy/ViewModels/ToolPaneModel.cs

@ -34,5 +34,7 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -34,5 +34,7 @@ namespace ICSharpCode.ILSpy.ViewModels
public KeyGesture ShortcutKey { get; protected set; }
public string Icon { get; protected set; }
public ICommand AssociatedCommand { get; set; }
}
}

1
packages.props

@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
<WpfStylesToolboxVersion>2.7.4</WpfStylesToolboxVersion>
<NUnitVersion>3.13.3</NUnitVersion>
<NUnitAdapterVersion>4.2.1</NUnitAdapterVersion>
<JUnitXmlTestLoggerVersion>3.0.110</JUnitXmlTestLoggerVersion>
<CoverletCollectorVersion>3.1.2</CoverletCollectorVersion>
<MicrosoftNETTestSdkVersion>17.0.0</MicrosoftNETTestSdkVersion>
<MoqVersion>4.16.1</MoqVersion>

Loading…
Cancel
Save