Browse Source

Fix #2076: VS AddIn opens reference assembly.

pull/2081/head v6.1
Siegfried Pammer 5 years ago
parent
commit
4b865c27e4
  1. 2
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 16
      ICSharpCode.Decompiler/Metadata/DotNetCorePathFinder.cs
  3. 33
      ICSharpCode.Decompiler/Metadata/DotNetCorePathFinderExtensions.cs
  4. 20
      ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
  5. 23
      ILSpy.AddIn/AssemblyFileFinder.cs
  6. 3
      ILSpy.AddIn/Commands/OpenILSpyCommand.cs
  7. 4
      ILSpy.AddIn/ILSpyInstance.cs
  8. 4
      ILSpy/ILSpy.csproj
  9. 4
      ILSpy/LoadedAssembly.cs
  10. 9
      ILSpy/MainWindow.xaml.cs

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

@ -185,7 +185,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -185,7 +185,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return Regex.Replace(il, @"'<PrivateImplementationDetails>\{[0-9A-F-]+\}'", "'<PrivateImplementationDetails>'");
}
static readonly string coreRefAsmPath = new DotNetCorePathFinder(new Version(3, 1)).GetReferenceAssemblyPath(".NETCoreApp, Version = v3.1");
static readonly string coreRefAsmPath = new DotNetCorePathFinder(TargetFrameworkIdentifier.NETCoreApp, new Version(3, 1)).GetReferenceAssemblyPath(".NETCoreApp, Version = v3.1");
static readonly string refAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2");

16
ICSharpCode.Decompiler/Metadata/DotNetCorePathFinder.cs

@ -66,16 +66,9 @@ namespace ICSharpCode.Decompiler.Metadata @@ -66,16 +66,9 @@ namespace ICSharpCode.Decompiler.Metadata
readonly Version targetFrameworkVersion;
readonly string dotnetBasePath = FindDotNetExeDirectory();
public DotNetCorePathFinder(Version targetFrameworkVersion)
public DotNetCorePathFinder(TargetFrameworkIdentifier targetFramework, Version targetFrameworkVersion)
{
this.targetFrameworkVersion = targetFrameworkVersion;
}
public DotNetCorePathFinder(string parentAssemblyFileName, string targetFrameworkIdString, TargetFrameworkIdentifier targetFramework, Version targetFrameworkVersion, ReferenceLoadInfo loadInfo = null)
{
string assemblyName = Path.GetFileNameWithoutExtension(parentAssemblyFileName);
string basePath = Path.GetDirectoryName(parentAssemblyFileName);
this.targetFrameworkVersion = targetFrameworkVersion;
if (targetFramework == TargetFrameworkIdentifier.NETStandard) {
// .NET Standard 2.1 is implemented by .NET Core 3.0 or higher
@ -83,6 +76,13 @@ namespace ICSharpCode.Decompiler.Metadata @@ -83,6 +76,13 @@ namespace ICSharpCode.Decompiler.Metadata
this.targetFrameworkVersion = new Version(3, 0, 0);
}
}
}
public DotNetCorePathFinder(string parentAssemblyFileName, string targetFrameworkIdString, TargetFrameworkIdentifier targetFramework, Version targetFrameworkVersion, ReferenceLoadInfo loadInfo = null)
: this(targetFramework, targetFrameworkVersion)
{
string assemblyName = Path.GetFileNameWithoutExtension(parentAssemblyFileName);
string basePath = Path.GetDirectoryName(parentAssemblyFileName);
searchPaths.Add(basePath);

33
ICSharpCode.Decompiler/Metadata/DotNetCorePathFinderExtensions.cs

@ -20,20 +20,26 @@ using System; @@ -20,20 +20,26 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.Metadata
{
public static class DotNetCorePathFinderExtensions
{
static readonly string RefPathPattern =
static readonly string PathPattern =
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<type>.NETFramework)[/\\]v(?<version>[^/\\]+)[/\\])" +
@"|((?<type>Microsoft\.NET)[/\\]assembly[/\\]GAC_(MSIL|32|64)[/\\])" +
@"|((?<type>Microsoft\.NET)[/\\]Framework(64)?[/\\](?<version>[^/\\]+)[/\\])" +
@"|(NuGetFallbackFolder[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\]ref[/\\])" +
@"|(shared[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\])";
@"|(shared[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\])" +
@"|(packs[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)\\ref([/\\].*)?[/\\])";
static readonly string RefPathPattern =
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<type>.NETFramework)[/\\]v(?<version>[^/\\]+)[/\\])" +
@"|(NuGetFallbackFolder[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\]ref[/\\])" +
@"|(packs[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)\\ref([/\\].*)?[/\\])";
public static string DetectTargetFrameworkId(this PEFile assembly)
{
@ -99,7 +105,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -99,7 +105,7 @@ namespace ICSharpCode.Decompiler.Metadata
* - .NETCore -> C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Console.dll
* - .NETStandard -> C:\Program Files\dotnet\sdk\NuGetFallbackFolder\netstandard.library\2.0.3\build\netstandard2.0\ref\netstandard.dll
*/
var pathMatch = Regex.Match(assemblyPath, RefPathPattern,
var pathMatch = Regex.Match(assemblyPath, PathPattern,
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
if (pathMatch.Success) {
var type = pathMatch.Groups["type"].Value;
@ -121,6 +127,25 @@ namespace ICSharpCode.Decompiler.Metadata @@ -121,6 +127,25 @@ namespace ICSharpCode.Decompiler.Metadata
return string.Empty;
}
public static bool IsReferenceAssembly(this PEFile assembly)
{
return IsReferenceAssembly(assembly.Reader, assembly.FileName);
}
public static bool IsReferenceAssembly(this PEReader assembly, string assemblyPath)
{
if (assembly == null)
throw new ArgumentNullException(nameof(assembly));
var metadata = assembly.GetMetadataReader();
if (metadata.GetCustomAttributes(Handle.AssemblyDefinition).HasKnownAttribute(metadata, KnownAttribute.ReferenceAssembly))
return true;
// Try to detect reference assembly through specific path pattern
var refPathMatch = Regex.Match(assemblyPath, RefPathPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
return refPathMatch.Success;
}
}
public class ReferenceLoadInfo

20
ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs

@ -92,16 +92,19 @@ namespace ICSharpCode.Decompiler.Metadata @@ -92,16 +92,19 @@ namespace ICSharpCode.Decompiler.Metadata
public UniversalAssemblyResolver(string mainAssemblyFileName, bool throwOnError, string targetFramework,
PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default)
{
this.mainAssemblyFileName = mainAssemblyFileName;
this.throwOnError = throwOnError;
this.streamOptions = streamOptions;
this.metadataOptions = metadataOptions;
this.targetFramework = targetFramework ?? string.Empty;
(targetFrameworkIdentifier, targetFrameworkVersion) = ParseTargetFramework(this.targetFramework);
this.mainAssemblyFileName = mainAssemblyFileName;
this.baseDirectory = Path.GetDirectoryName(mainAssemblyFileName);
this.throwOnError = throwOnError;
if (string.IsNullOrWhiteSpace(this.baseDirectory))
this.baseDirectory = Environment.CurrentDirectory;
AddSearchDirectory(baseDirectory);
if (mainAssemblyFileName != null) {
string baseDirectory = Path.GetDirectoryName(mainAssemblyFileName);
if (string.IsNullOrWhiteSpace(this.baseDirectory))
this.baseDirectory = Environment.CurrentDirectory;
AddSearchDirectory(baseDirectory);
}
}
internal static (TargetFrameworkIdentifier, Version) ParseTargetFramework(string targetFramework)
@ -191,7 +194,10 @@ namespace ICSharpCode.Decompiler.Metadata @@ -191,7 +194,10 @@ namespace ICSharpCode.Decompiler.Metadata
if (IsZeroOrAllOnes(targetFrameworkVersion))
goto default;
if (dotNetCorePathFinder == null) {
dotNetCorePathFinder = new DotNetCorePathFinder(mainAssemblyFileName, targetFramework, targetFrameworkIdentifier, targetFrameworkVersion);
if (mainAssemblyFileName == null)
dotNetCorePathFinder = new DotNetCorePathFinder(targetFrameworkIdentifier, targetFrameworkVersion);
else
dotNetCorePathFinder = new DotNetCorePathFinder(mainAssemblyFileName, targetFramework, targetFrameworkIdentifier, targetFrameworkVersion);
foreach (var directory in directories) {
dotNetCorePathFinder.AddSearchDirectory(directory);
}

23
ILSpy.AddIn/AssemblyFileFinder.cs

@ -1,32 +1,29 @@ @@ -1,32 +1,29 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.AddIn
{
public class AssemblyFileFinder
{
public static string FindAssemblyFile(AssemblyDefinition assemblyDefinition, string assemblyFile)
public static string FindAssemblyFile(Mono.Cecil.AssemblyDefinition assemblyDefinition, string assemblyFile)
{
var assemblyResolver = new UniversalAssemblyResolver(assemblyFile, false,
DetectTargetFrameworkId(assemblyDefinition, assemblyFile));
string tfi = DetectTargetFrameworkId(assemblyDefinition, assemblyFile);
UniversalAssemblyResolver assemblyResolver;
if (IsReferenceAssembly(assemblyDefinition, assemblyFile)) {
assemblyResolver.RemoveSearchDirectory(Path.GetDirectoryName(assemblyFile));
assemblyResolver = new UniversalAssemblyResolver(null, throwOnError: false, tfi);
} else {
assemblyResolver = new UniversalAssemblyResolver(assemblyFile, throwOnError: false, tfi);
}
return assemblyResolver.FindAssemblyFile(
ICSharpCode.Decompiler.Metadata.AssemblyNameReference.Parse(assemblyDefinition.Name.FullName));
return assemblyResolver.FindAssemblyFile(AssemblyNameReference.Parse(assemblyDefinition.Name.FullName));
}
static readonly string RefPathPattern = @"NuGetFallbackFolder[/\\][^/\\]+[/\\][^/\\]+[/\\]ref[/\\]";
public static bool IsReferenceAssembly(AssemblyDefinition assemblyDef, string assemblyFile)
public static bool IsReferenceAssembly(Mono.Cecil.AssemblyDefinition assemblyDef, string assemblyFile)
{
if (assemblyDef.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.Runtime.CompilerServices.ReferenceAssemblyAttribute"))
return true;
@ -40,7 +37,7 @@ namespace ICSharpCode.ILSpy.AddIn @@ -40,7 +37,7 @@ namespace ICSharpCode.ILSpy.AddIn
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<1>.NETFramework)[/\\]v(?<2>[^/\\]+)[/\\])" +
@"|((NuGetFallbackFolder|packs)[/\\](?<1>[^/\\]+)\\(?<2>[^/\\]+)([/\\].*)?[/\\]ref[/\\])";
public static string DetectTargetFrameworkId(AssemblyDefinition assembly, string assemblyPath = null)
public static string DetectTargetFrameworkId(Mono.Cecil.AssemblyDefinition assembly, string assemblyPath = null)
{
if (assembly == null)
throw new ArgumentNullException(nameof(assembly));

3
ILSpy.AddIn/Commands/OpenILSpyCommand.cs

@ -80,8 +80,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands @@ -80,8 +80,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
using (var assemblyDef = AssemblyDefinition.ReadAssembly(reference.Display)) {
string assemblyName = assemblyDef.Name.Name;
string resolvedAssemblyFile = AssemblyFileFinder.FindAssemblyFile(assemblyDef, reference.Display);
dict.Add(assemblyName,
new DetectedReference(assemblyName, resolvedAssemblyFile, false));
dict.Add(assemblyName, new DetectedReference(assemblyName, resolvedAssemblyFile, false));
}
}
foreach (var projectReference in parentProject.ProjectReferences) {

4
ILSpy.AddIn/ILSpyInstance.cs

@ -12,11 +12,11 @@ namespace ICSharpCode.ILSpy.AddIn @@ -12,11 +12,11 @@ namespace ICSharpCode.ILSpy.AddIn
{
public ILSpyParameters(IEnumerable<string> assemblyFileNames, params string[] arguments)
{
this.AssemblyFileNames = assemblyFileNames;
this.AssemblyFileNames = assemblyFileNames.ToArray();
this.Arguments = arguments;
}
public IEnumerable<string> AssemblyFileNames { get; private set; }
public string[] AssemblyFileNames { get; private set; }
public string[] Arguments { get; private set; }
}

4
ILSpy/ILSpy.csproj

@ -128,9 +128,7 @@ @@ -128,9 +128,7 @@
<Compile Include="Commands\ShowDebugSteps.cs" />
<Compile Include="Commands\SortAssemblyListCommand.cs" />
<Compile Include="Controls\BoolToVisibilityConverter.cs" />
<Compile Include="Controls\CustomDialog.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Controls\CustomDialog.cs" />
<Compile Include="Controls\GridViewColumnAutoSize.cs" />
<Compile Include="Controls\MarkupExtensions.cs" />
<Compile Include="Controls\ResourceObjectTable.xaml.cs">

4
ILSpy/LoadedAssembly.cs

@ -27,6 +27,8 @@ using System.Runtime.CompilerServices; @@ -27,6 +27,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.PdbProvider;
@ -405,7 +407,7 @@ namespace ICSharpCode.ILSpy @@ -405,7 +407,7 @@ namespace ICSharpCode.ILSpy
lock (loadingAssemblies) {
loadingAssemblies.Remove(file);
}
});
}, DispatcherPriority.Normal);
return asm;
}

9
ILSpy/MainWindow.xaml.cs

@ -408,6 +408,9 @@ namespace ICSharpCode.ILSpy @@ -408,6 +408,9 @@ namespace ICSharpCode.ILSpy
found = true;
} else {
IEntity mr = await Task.Run(() => FindEntityInRelevantAssemblies(navigateTo, relevantAssemblies));
// Make sure we wait for assemblies being loaded...
// BeginInvoke in LoadedAssembly.LookupReferencedAssemblyInternal
await Dispatcher.InvokeAsync(delegate { }, DispatcherPriority.Normal);
if (mr != null && mr.ParentModule.PEFile != null) {
found = true;
if (AssemblyTreeView.SelectedItem == initialSelection) {
@ -483,6 +486,12 @@ namespace ICSharpCode.ILSpy @@ -483,6 +486,12 @@ namespace ICSharpCode.ILSpy
return false;
}
// We intentionally ignore reference assemblies, so that the loop continues looking for another assembly that might have a usable definition.
if (module.IsReferenceAssembly()) {
typeHandle = default;
return false;
}
switch (typeRef) {
case GetPotentiallyNestedClassTypeReference topLevelType:
typeHandle = topLevelType.ResolveInPEFile(module);

Loading…
Cancel
Save