From 783fc5529b5300ec0626704b5347b753dd75c0e7 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 1 Aug 2018 23:04:09 +0200 Subject: [PATCH 1/5] Upgrade ICSharpCode.Decompiler to 4.0.0.4285-beta1. --- build/Targets/Packages.props | 2 +- .../MetadataAsSourceFileService.cs | 29 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/build/Targets/Packages.props b/build/Targets/Packages.props index 2693ba9b86fb0..40a90c7223d20 100644 --- a/build/Targets/Packages.props +++ b/build/Targets/Packages.props @@ -14,7 +14,7 @@ 2.3.1 0.9.2 2.2.0 - 3.1.0.3652 + 4.0.0.4285-beta1 0.22.0 0.2.0 1.0.0 diff --git a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs index d67bac6c6fae3..1ed36d591d46f 100644 --- a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs +++ b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs @@ -7,12 +7,14 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.Transforms; +using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.MetadataAsSource; @@ -20,7 +22,6 @@ using Microsoft.CodeAnalysis.SymbolMapping; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; -using Mono.Cecil; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.MetadataAsSource @@ -224,10 +225,11 @@ private async Task DecompileSymbolAsync(Document temporaryDocument, IS } // Load the assembly. - var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyLocation, new ReaderParameters() { AssemblyResolver = new RoslynAssemblyResolver(compilation) }); + // TODO: Use a different PEFile overload that allows us to reuse the PEReader or Stream already created by Roslyn. + var pefile = new PEFile(assemblyLocation, PEStreamOptions.PrefetchEntireImage); // Initialize a decompiler with default settings. - var decompiler = new CSharpDecompiler(assemblyDefinition.MainModule, new DecompilerSettings()); + var decompiler = new CSharpDecompiler(pefile, new RoslynAssemblyResolver(compilation), new DecompilerSettings()); // Escape invalid identifiers to prevent Roslyn from failing to parse the generated code. // (This happens for example, when there is compiler-generated code that is not yet recognized/transformed by the decompiler.) decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); @@ -238,8 +240,8 @@ private async Task DecompileSymbolAsync(Document temporaryDocument, IS // Add header to match output of metadata-only view. // (This also makes debugging easier, because you can see which assembly was decompiled inside VS.) - var header = $"#region {FeaturesResources.Assembly} {assemblyDefinition.FullName}" + Environment.NewLine - + $"// {assemblyDefinition.MainModule.FileName}" + Environment.NewLine + var header = $"#region {FeaturesResources.Assembly} {pefile.FullName}" + Environment.NewLine + + $"// {assemblyLocation}" + Environment.NewLine + $"// Decompiled with ICSharpCode.Decompiler {decompilerVersion.FileVersion}" + Environment.NewLine + "#endregion" + Environment.NewLine; @@ -257,12 +259,7 @@ public RoslynAssemblyResolver(Compilation parentCompilation) this.parentCompilation = parentCompilation; } - public AssemblyDefinition Resolve(AssemblyNameReference name) - { - return Resolve(name, new ReaderParameters()); - } - - public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) + public PEFile Resolve(IAssemblyReference name) { foreach (var assembly in parentCompilation.GetReferencedAssemblySymbols()) { @@ -282,15 +279,21 @@ public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters p // reference assemblies should be fine here... var reference = parentCompilation.GetMetadataReference(assembly); - return AssemblyDefinition.ReadAssembly(reference.Display); + // TODO: Use a different PEFile overload that allows us to reuse the PEReader or Stream already created by Roslyn. + return new PEFile(reference.Display, PEStreamOptions.PrefetchMetadata); } // not found return null; } - public void Dispose() + public PEFile ResolveModule(PEFile mainModule, string moduleName) { + string baseDirectory = Path.GetDirectoryName(mainModule.FileName); + string moduleFileName = Path.Combine(baseDirectory, moduleName); + if (!File.Exists(moduleFileName)) + return null; + return new PEFile(moduleFileName, PEStreamOptions.PrefetchMetadata); } } From cd7e16670c38e7be9f66b3f25ebe221c72b6bef6 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 2 Aug 2018 08:30:12 +0200 Subject: [PATCH 2/5] Fix a bug in the RoslynAssemblyResolver when dealing with .NET Core/Standard projects. --- .../MetadataAsSourceFileService.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs index 1ed36d591d46f..9dcdccb1b3bcd 100644 --- a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs +++ b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs @@ -253,6 +253,7 @@ private async Task DecompileSymbolAsync(Document temporaryDocument, IS private class RoslynAssemblyResolver : IAssemblyResolver { private readonly Compilation parentCompilation; + private static readonly Version zeroVersion = new Version(0, 0, 0, 0); public RoslynAssemblyResolver(Compilation parentCompilation) { @@ -263,13 +264,20 @@ public PEFile Resolve(IAssemblyReference name) { foreach (var assembly in parentCompilation.GetReferencedAssemblySymbols()) { + // First, find the correct IAssemblySymbol by name and PublicKeyToken. if (assembly.Identity.Name != name.Name || !assembly.Identity.PublicKeyToken.SequenceEqual(name.PublicKeyToken ?? Array.Empty())) { continue; } - if (assembly.Identity.Version != name.Version + // Normally we skip versions that do not match, except if the reference is "mscorlib" (see comments below) + // or if the name.Version is '0.0.0.0'. This is because we require the metadata of all transitive references + // and modules, to achieve best decompilation results. + // In the case of .NET Standard projects for example, the 'netstandard' reference contains no references + // with actual versions. All versions are '0.0.0.0', therefore we have to ignore those version numbers, + // and can just use the references provided by Roslyn instead. + if (assembly.Identity.Version != name.Version && name.Version != zeroVersion && !string.Equals("mscorlib", assembly.Identity.Name, StringComparison.OrdinalIgnoreCase)) { // MSBuild treats mscorlib special for the purpose of assembly resolution/unification, where all @@ -277,7 +285,7 @@ public PEFile Resolve(IAssemblyReference name) continue; } - // reference assemblies should be fine here... + // reference assemblies should be fine here, we only need the metadata of references. var reference = parentCompilation.GetMetadataReference(assembly); // TODO: Use a different PEFile overload that allows us to reuse the PEReader or Stream already created by Roslyn. return new PEFile(reference.Display, PEStreamOptions.PrefetchMetadata); @@ -289,6 +297,8 @@ public PEFile Resolve(IAssemblyReference name) public PEFile ResolveModule(PEFile mainModule, string moduleName) { + // Primitive implementation to support multi-module assemblies + // where all modules are located next to the main module. string baseDirectory = Path.GetDirectoryName(mainModule.FileName); string moduleFileName = Path.Combine(baseDirectory, moduleName); if (!File.Exists(moduleFileName)) From 0ba5174cdde8543380b088d04e0fce5005e3bb7d Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 2 Aug 2018 08:47:01 +0200 Subject: [PATCH 3/5] Add comment about language version used during decompilation. --- .../MetadataAsSource/MetadataAsSourceFileService.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs index 9dcdccb1b3bcd..837a1ecbbbf95 100644 --- a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs +++ b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs @@ -225,11 +225,13 @@ private async Task DecompileSymbolAsync(Document temporaryDocument, IS } // Load the assembly. - // TODO: Use a different PEFile overload that allows us to reuse the PEReader or Stream already created by Roslyn. + // TODO: Use a different PEFile ctor overload that allows us to reuse the PEReader or Stream already created by Roslyn. var pefile = new PEFile(assemblyLocation, PEStreamOptions.PrefetchEntireImage); // Initialize a decompiler with default settings. - var decompiler = new CSharpDecompiler(pefile, new RoslynAssemblyResolver(compilation), new DecompilerSettings()); + // TODO: Use language version currently used by the project. + var settings = new DecompilerSettings(LanguageVersion.Latest); + var decompiler = new CSharpDecompiler(pefile, new RoslynAssemblyResolver(compilation), settings); // Escape invalid identifiers to prevent Roslyn from failing to parse the generated code. // (This happens for example, when there is compiler-generated code that is not yet recognized/transformed by the decompiler.) decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); @@ -287,7 +289,7 @@ public PEFile Resolve(IAssemblyReference name) // reference assemblies should be fine here, we only need the metadata of references. var reference = parentCompilation.GetMetadataReference(assembly); - // TODO: Use a different PEFile overload that allows us to reuse the PEReader or Stream already created by Roslyn. + // TODO: Use a different PEFile ctor overload that allows us to reuse the PEReader or Stream already created by Roslyn. return new PEFile(reference.Display, PEStreamOptions.PrefetchMetadata); } From dcf98acfe23c1b87311b237ee70b10482e5201ce Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Thu, 2 Aug 2018 09:56:10 -0500 Subject: [PATCH 4/5] Remove Mono.Cecil references Closes #29030 --- build/config/SignToolData.json | 4 ---- .../DevDivInsertionFiles/BuildDevDivInsertionFiles.vb | 8 ++------ src/VisualStudio/Setup/AssemblyRedirects.cs | 1 - src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj | 1 - 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/build/config/SignToolData.json b/build/config/SignToolData.json index 575728c648311..6d4a54855cf11 100644 --- a/build/config/SignToolData.json +++ b/build/config/SignToolData.json @@ -191,10 +191,6 @@ "Microsoft.VisualStudio.Threading.resources.dll", "Microsoft.VisualStudio.Validation.dll", "Microsoft.Win32.Primitives.dll", - "Mono.Cecil.dll", - "Mono.Cecil.Mdb.dll", - "Mono.Cecil.Pdb.dll", - "Mono.Cecil.Rocks.dll", "Nerdbank.FullDuplexStream.dll", "Newtonsoft.Json.dll", "NuGet.CommandLine.2.8.5.nupkg", diff --git a/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb b/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb index adbefec526ee0..36df9c8583552 100644 --- a/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb +++ b/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb @@ -1,4 +1,4 @@ -Imports System.IO.Packaging +Imports System.IO.Packaging Imports System.IO Imports System.Threading Imports Newtonsoft.Json @@ -574,10 +574,6 @@ Public Class BuildDevDivInsertionFiles add("Vsix\Roslyn.VisualStudio.Setup\System.Composition.Hosting.dll") add("Vsix\Roslyn.VisualStudio.Setup\System.Composition.TypedParts.dll") add("Vsix\Roslyn.VisualStudio.Setup\System.Threading.Tasks.Extensions.dll") - add("Vsix\Roslyn.VisualStudio.Setup\Mono.Cecil.dll") - add("Vsix\Roslyn.VisualStudio.Setup\Mono.Cecil.Mdb.dll") - add("Vsix\Roslyn.VisualStudio.Setup\Mono.Cecil.Pdb.dll") - add("Vsix\Roslyn.VisualStudio.Setup\Mono.Cecil.Rocks.dll") add("Vsix\Roslyn.VisualStudio.Setup\ICSharpCode.Decompiler.dll") add("Dlls\Microsoft.CodeAnalysis.VisualBasic.ExpressionCompiler\Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.ExpressionCompiler.vsdconfig") add("Dlls\Microsoft.CodeAnalysis.VisualBasic.ResultProvider\Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.ResultProvider.vsdconfig") @@ -945,4 +941,4 @@ set DEVPATH=%RoslynToolsRoot%;%DEVPATH%" Console.WriteLine(s) End If End Sub -End Class \ No newline at end of file +End Class diff --git a/src/VisualStudio/Setup/AssemblyRedirects.cs b/src/VisualStudio/Setup/AssemblyRedirects.cs index f81bf480cc05e..02f7fc3c634f5 100644 --- a/src/VisualStudio/Setup/AssemblyRedirects.cs +++ b/src/VisualStudio/Setup/AssemblyRedirects.cs @@ -44,7 +44,6 @@ [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\System.Threading.Tasks.Extensions.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Humanizer.dll")] -[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Mono.Cecil.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\ICSharpCode.Decompiler.dll")] [assembly: ProvideBindingRedirection( diff --git a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj index 92b075d1c574c..1078d111535a0 100644 --- a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj +++ b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj @@ -237,7 +237,6 @@ - From 3347e95cf0d3467c47b6548f7741a9760b5c50a8 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 2 Aug 2018 17:35:10 +0200 Subject: [PATCH 5/5] Removed TODO comments, see PR description. --- .../MetadataAsSource/MetadataAsSourceFileService.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs index 837a1ecbbbf95..a669a37648eb7 100644 --- a/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs +++ b/src/EditorFeatures/Core/Implementation/MetadataAsSource/MetadataAsSourceFileService.cs @@ -225,11 +225,9 @@ private async Task DecompileSymbolAsync(Document temporaryDocument, IS } // Load the assembly. - // TODO: Use a different PEFile ctor overload that allows us to reuse the PEReader or Stream already created by Roslyn. var pefile = new PEFile(assemblyLocation, PEStreamOptions.PrefetchEntireImage); // Initialize a decompiler with default settings. - // TODO: Use language version currently used by the project. var settings = new DecompilerSettings(LanguageVersion.Latest); var decompiler = new CSharpDecompiler(pefile, new RoslynAssemblyResolver(compilation), settings); // Escape invalid identifiers to prevent Roslyn from failing to parse the generated code. @@ -289,7 +287,6 @@ public PEFile Resolve(IAssemblyReference name) // reference assemblies should be fine here, we only need the metadata of references. var reference = parentCompilation.GetMetadataReference(assembly); - // TODO: Use a different PEFile ctor overload that allows us to reuse the PEReader or Stream already created by Roslyn. return new PEFile(reference.Display, PEStreamOptions.PrefetchMetadata); }