Browse Source

Merge pull request #848 from siegfriedpammer/netstd-support

Implement basic support for .net standard/core assembly references
pull/850/head
Siegfried Pammer 8 years ago committed by GitHub
parent
commit
da7a48b96f
  1. 125
      ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs
  2. 44
      ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs
  3. 24
      ICSharpCode.Decompiler/DotNetCore/UnresolvedAssemblyNameReference.cs
  4. 5
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  5. 1
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  6. 2
      ICSharpCode.Decompiler/Output/TextTokenWriter.cs
  7. 25
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  8. 81
      ICSharpCode.Decompiler/Util/KeyComparer.cs
  9. 3
      ILSpy/ILSpy.csproj
  10. 1
      ILSpy/Images/ILSpyNewIconList.txt
  11. BIN
      ILSpy/Images/Warning.png
  12. 47
      ILSpy/Languages/CSharpLanguage.cs
  13. 1
      ILSpy/Languages/Language.cs
  14. 76
      ILSpy/LoadedAssembly.cs
  15. 16
      ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
  16. 2
      ILSpy/TreeNodes/MethodTreeNode.cs
  17. 3
      ILSpy/TreeNodes/ReferenceFolderTreeNode.cs

125
ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using Mono.Cecil;
using Newtonsoft.Json.Linq;
namespace ICSharpCode.Decompiler
{
public class DotNetCorePathFinder
{
class DotNetCorePackageInfo
{
public readonly string Name;
public readonly string Version;
public readonly string Type;
public readonly string Path;
public readonly string[] RuntimeComponents;
public DotNetCorePackageInfo(string fullName, string type, string path, string[] runtimeComponents)
{
var parts = fullName.Split('/');
this.Name = parts[0];
this.Version = parts[1];
this.Type = type;
this.Path = path;
this.RuntimeComponents = runtimeComponents ?? new string[0];
}
}
static readonly string[] LookupPaths = new string[] {
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget\\packages")
};
readonly Dictionary<string, DotNetCorePackageInfo> packages;
ISet<string> packageBasePaths = new HashSet<string>(StringComparer.Ordinal);
readonly string assemblyName;
readonly string basePath;
readonly string targetFrameworkId;
readonly string version;
readonly string dotnetBasePath = FindDotNetExeDirectory();
readonly Dictionary<string, UnresolvedAssemblyNameReference> loadInfo;
public DotNetCorePathFinder(string parentAssemblyFileName, string targetFrameworkId, string version, Dictionary<string, UnresolvedAssemblyNameReference> loadInfo)
{
this.assemblyName = Path.GetFileNameWithoutExtension(parentAssemblyFileName);
this.basePath = Path.GetDirectoryName(parentAssemblyFileName);
this.targetFrameworkId = targetFrameworkId;
this.version = version;
this.loadInfo = loadInfo;
var depsJsonFileName = Path.Combine(basePath, $"{assemblyName}.deps.json");
if (!File.Exists(depsJsonFileName)) {
loadInfo.AddMessage(assemblyName, MessageKind.Error, $"{assemblyName}.deps.json could not be found!");
return;
}
packages = LoadPackageInfos(depsJsonFileName, targetFrameworkId).ToDictionary(i => i.Name);
foreach (var path in LookupPaths) {
foreach (var pk in packages) {
foreach (var item in pk.Value.RuntimeComponents) {
var itemPath = Path.GetDirectoryName(item);
var fullPath = Path.Combine(path, pk.Value.Name, pk.Value.Version, itemPath);
if (Directory.Exists(fullPath))
packageBasePaths.Add(fullPath);
}
}
}
}
public string TryResolveDotNetCore(AssemblyNameReference name)
{
foreach (var basePath in packageBasePaths) {
if (File.Exists(Path.Combine(basePath, name.Name + ".dll"))) {
return Path.Combine(basePath, name.Name + ".dll");
} else if (File.Exists(Path.Combine(basePath, name.Name + ".exe"))) {
return Path.Combine(basePath, name.Name + ".exe");
}
}
return FallbackToDotNetSharedDirectory(name, version);
}
static IEnumerable<DotNetCorePackageInfo> LoadPackageInfos(string depsJsonFileName, string targetFramework)
{
var dependencies = JObject.Parse(File.ReadAllText(depsJsonFileName));
var runtimeInfos = dependencies["targets"][targetFramework].Children().OfType<JProperty>().ToArray();
var libraries = dependencies["libraries"].Children().OfType<JProperty>().ToArray();
foreach (var library in libraries) {
var type = library.First()["type"].ToString();
var path = library.First()["path"]?.ToString();
var runtimeInfo = runtimeInfos.FirstOrDefault(r => r.Name == library.Name)?.First()["runtime"]?.Children().OfType<JProperty>().Select(i => i.Name).ToArray();
yield return new DotNetCorePackageInfo(library.Name, type, path, runtimeInfo);
}
}
string FallbackToDotNetSharedDirectory(AssemblyNameReference name, string version)
{
if (dotnetBasePath == null) return null;
var basePath = Path.Combine(dotnetBasePath, "shared\\Microsoft.NETCore.App", version);
if (File.Exists(Path.Combine(basePath, name.Name + ".dll"))) {
return Path.Combine(basePath, name.Name + ".dll");
} else if (File.Exists(Path.Combine(basePath, name.Name + ".exe"))) {
return Path.Combine(basePath, name.Name + ".exe");
}
return null;
}
static string FindDotNetExeDirectory()
{
string dotnetExeName = (Environment.OSVersion.Platform == PlatformID.Unix) ? "dotnet" : "dotnet.exe";
foreach (var item in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator)) {
try {
if (File.Exists(Path.Combine(item, dotnetExeName)))
return item;
} catch (ArgumentException) { }
}
return null;
}
}
}

44
ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using Mono.Cecil;
using Newtonsoft.Json.Linq;
namespace ICSharpCode.Decompiler
{
public static class DotNetCorePathFinderExtensions
{
public static string DetectTargetFrameworkId(this AssemblyDefinition assembly)
{
if (assembly == null)
throw new ArgumentNullException(nameof(assembly));
const string TargetFrameworkAttributeName = "System.Runtime.Versioning.TargetFrameworkAttribute";
foreach (var attribute in assembly.CustomAttributes) {
if (attribute.AttributeType.FullName != TargetFrameworkAttributeName)
continue;
var blobReader = new BlobReader(attribute.GetBlob(), null);
if (blobReader.ReadUInt16() == 0x0001) {
return blobReader.ReadSerString();
}
}
return string.Empty;
}
public static void AddMessage(this Dictionary<string, UnresolvedAssemblyNameReference> container, string fullName, MessageKind kind, string message)
{
if (container == null)
throw new ArgumentNullException(nameof(container));
if (!container.TryGetValue(fullName, out var referenceInfo)) {
referenceInfo = new UnresolvedAssemblyNameReference(fullName);
container.Add(fullName, referenceInfo);
}
referenceInfo.Messages.Add((kind, message));
}
}
}

24
ICSharpCode.Decompiler/DotNetCore/UnresolvedAssemblyNameReference.cs

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler
{
public sealed class UnresolvedAssemblyNameReference
{
public string FullName { get; }
public bool HasErrors => Messages.Any(m => m.Item1 == MessageKind.Error);
public List<(MessageKind, string)> Messages { get; } = new List<(MessageKind, string)>();
public UnresolvedAssemblyNameReference(string fullName)
{
this.FullName = fullName;
}
}
public enum MessageKind { Error, Warning, Info }
}

5
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -45,6 +45,7 @@ @@ -45,6 +45,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.0" />
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
</ItemGroup>
@ -262,6 +263,9 @@ @@ -262,6 +263,9 @@
<Compile Include="Documentation\XmlDocKeyProvider.cs" />
<Compile Include="Documentation\XmlDocLoader.cs" />
<Compile Include="Documentation\XmlDocumentationProvider.cs" />
<Compile Include="DotNetCore\DotNetCorePathFinder.cs" />
<Compile Include="DotNetCore\DotNetCorePathFinderExtensions.cs" />
<Compile Include="DotNetCore\UnresolvedAssemblyNameReference.cs" />
<Compile Include="IL\ControlFlow\AsyncAwaitDecompiler.cs" />
<Compile Include="IL\ControlFlow\ControlFlowGraph.cs" />
<Compile Include="IL\ControlFlow\StateRangeAnalysis.cs" />
@ -276,6 +280,7 @@ @@ -276,6 +280,7 @@
<Compile Include="IL\Transforms\NullCoalescingTransform.cs" />
<Compile Include="IL\Transforms\TransformCollectionAndObjectInitializers.cs" />
<Compile Include="Output\TextTokenWriter.cs" />
<Compile Include="Util\KeyComparer.cs" />
<Compile Include="Util\UnicodeNewline.cs" />
<Compile Include="FlowAnalysis\ControlFlowNode.cs" />
<Compile Include="FlowAnalysis\DataFlowVisitor.cs" />

1
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -50,7 +50,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -50,7 +50,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILTransformContext context;
string[] currentFieldNames;
Dictionary<ILVariable, string> mapping;
Dictionary<string, int> reservedVariableNames;
const char maxLoopVariableName = 'n';

2
ICSharpCode.Decompiler/Output/TextTokenWriter.cs

@ -40,8 +40,6 @@ namespace ICSharpCode.Decompiler @@ -40,8 +40,6 @@ namespace ICSharpCode.Decompiler
bool firstUsingDeclaration;
bool lastUsingDeclaration;
TextLocation? lastEndOfLine;
public bool FoldBraces = false;
public TextTokenWriter(ITextOutput output, DecompilerSettings settings, IDecompilerTypeSystem typeSystem)

25
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -44,9 +44,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -44,9 +44,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
CecilLoader cecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference, ShortenInterfaceImplNames = false };
typeReferenceCecilLoader.SetCurrentModule(moduleDefinition);
IUnresolvedAssembly mainAssembly = cecilLoader.LoadModule(moduleDefinition);
// Load referenced assemblies and type-forwarder references.
// This is necessary to make .NET Core/PCL binaries work better.
var referencedAssemblies = new List<IUnresolvedAssembly>();
var assemblyReferenceQueue = new Queue<AssemblyNameReference>(moduleDefinition.AssemblyReferences);
var processedAssemblyReferences = new HashSet<AssemblyNameReference>(AssemblyNameReferenceComparer.Instance);
var processedAssemblyReferences = new HashSet<AssemblyNameReference>(KeyComparer.Create((AssemblyNameReference reference) => reference.FullName));
while (assemblyReferenceQueue.Count > 0) {
var asmRef = assemblyReferenceQueue.Dequeue();
if (!processedAssemblyReferences.Add(asmRef))
@ -61,6 +63,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -61,6 +63,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
compilation = new SimpleCompilation(mainAssembly, referencedAssemblies);
// Primitive types are necessary to avoid assertions in ILReader.
// Fallback to MinimalCorlib to provide the primitive types.
if (compilation.FindType(KnownTypeCode.Void).Kind == TypeKind.Unknown || compilation.FindType(KnownTypeCode.Void).Kind == TypeKind.Unknown) {
referencedAssemblies.Add(MinimalCorlib.Instance);
compilation = new SimpleCompilation(mainAssembly, referencedAssemblies);
@ -68,25 +72,6 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -68,25 +72,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
context = new SimpleTypeResolveContext(compilation.MainAssembly);
}
class AssemblyNameReferenceComparer : IEqualityComparer<AssemblyNameReference>
{
public static readonly AssemblyNameReferenceComparer Instance = new AssemblyNameReferenceComparer();
public bool Equals(AssemblyNameReference x, AssemblyNameReference y)
{
if (x == y)
return true;
if (x == null || y == null)
return false;
return x.FullName.Equals(y.FullName);
}
public int GetHashCode(AssemblyNameReference obj)
{
return obj.FullName.GetHashCode();
}
}
public ICompilation Compilation {
get { return compilation; }
}

81
ICSharpCode.Decompiler/Util/KeyComparer.cs

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
// Copyright (c) 2010-2013 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.
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.Util
{
public static class KeyComparer
{
public static KeyComparer<TElement, TKey> Create<TElement, TKey>(Func<TElement, TKey> keySelector)
{
return new KeyComparer<TElement, TKey>(keySelector, Comparer<TKey>.Default, EqualityComparer<TKey>.Default);
}
public static KeyComparer<TElement, TKey> Create<TElement, TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, IEqualityComparer<TKey> equalityComparer)
{
return new KeyComparer<TElement, TKey>(keySelector, comparer, equalityComparer);
}
public static IComparer<TElement> Create<TElement, TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer)
{
return new KeyComparer<TElement, TKey>(keySelector, comparer, EqualityComparer<TKey>.Default);
}
public static IEqualityComparer<TElement> Create<TElement, TKey>(Func<TElement, TKey> keySelector, IEqualityComparer<TKey> equalityComparer)
{
return new KeyComparer<TElement, TKey>(keySelector, Comparer<TKey>.Default, equalityComparer);
}
}
public class KeyComparer<TElement, TKey> : IComparer<TElement>, IEqualityComparer<TElement>
{
readonly Func<TElement, TKey> keySelector;
readonly IComparer<TKey> keyComparer;
readonly IEqualityComparer<TKey> keyEqualityComparer;
public KeyComparer(Func<TElement, TKey> keySelector, IComparer<TKey> keyComparer, IEqualityComparer<TKey> keyEqualityComparer)
{
if (keySelector == null)
throw new ArgumentNullException("keySelector");
if (keyComparer == null)
throw new ArgumentNullException("keyComparer");
if (keyEqualityComparer == null)
throw new ArgumentNullException("keyEqualityComparer");
this.keySelector = keySelector;
this.keyComparer = keyComparer;
this.keyEqualityComparer = keyEqualityComparer;
}
public int Compare(TElement x, TElement y)
{
return keyComparer.Compare(keySelector(x), keySelector(y));
}
public bool Equals(TElement x, TElement y)
{
return keyEqualityComparer.Equals(keySelector(x), keySelector(y));
}
public int GetHashCode(TElement obj)
{
return keyEqualityComparer.GetHashCode(keySelector(obj));
}
}
}

3
ILSpy/ILSpy.csproj

@ -275,7 +275,7 @@ @@ -275,7 +275,7 @@
<Compile Include="TreeNodes\ResourceNodes\ResourceTreeNode.cs" />
<Compile Include="TreeNodes\ThreadingSupport.cs" />
<Compile Include="TreeNodes\TypeTreeNode.cs" />
<EmbeddedResource Include="TextView\ILAsm-Mode.xshd" />
<EmbeddedResource Include="TextView\ILAsm-Mode.xshd" />
</ItemGroup>
<ItemGroup>
@ -339,6 +339,7 @@ @@ -339,6 +339,7 @@
<Resource Include="Images\OverlayStatic.png" />
<Resource Include="Images\VirtualMethod.png" />
<Resource Include="Images\PInvokeMethod.png" />
<Resource Include="Images\Warning.png" />
</ItemGroup>
<ItemGroup>

1
ILSpy/Images/ILSpyNewIconList.txt

@ -58,3 +58,4 @@ SubTypes.png new (Fugue: arrow-turn-270.png) @@ -58,3 +58,4 @@ SubTypes.png new (Fugue: arrow-turn-270.png)
SuperTypes.png new (Fugue: arrow-turn-090-left.png)
ViewCode.png BitmapResources-data\Icons.16x16.FormsDesigner.ViewCode.png
VirtualMethod.png new (SharpDevelop-Team)
Warning.png new (Fugue: exclamation.png (32x32))

BIN
ILSpy/Images/Warning.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

47
ILSpy/Languages/CSharpLanguage.cs

@ -31,6 +31,9 @@ using ICSharpCode.Decompiler.CSharp; @@ -31,6 +31,9 @@ using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.TypeSystem;
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy
{
@ -46,10 +49,6 @@ namespace ICSharpCode.ILSpy @@ -46,10 +49,6 @@ namespace ICSharpCode.ILSpy
bool showAllMembers = false;
int transformCount = int.MaxValue;
public CSharpLanguage()
{
}
#if DEBUG
internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{
@ -106,6 +105,7 @@ namespace ICSharpCode.ILSpy @@ -106,6 +105,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
AddReferenceWarningMessage(method.Module.Assembly, output);
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
CSharpDecompiler decompiler = CreateDecompiler(method.Module, options);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method), decompiler.TypeSystem);
@ -161,6 +161,7 @@ namespace ICSharpCode.ILSpy @@ -161,6 +161,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
AddReferenceWarningMessage(property.Module.Assembly, output);
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
CSharpDecompiler decompiler = CreateDecompiler(property.Module, options);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property), decompiler.TypeSystem);
@ -168,6 +169,7 @@ namespace ICSharpCode.ILSpy @@ -168,6 +169,7 @@ namespace ICSharpCode.ILSpy
/*
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
AddReferenceWarningMessage(output);
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true);
if (field.IsLiteral) {
@ -216,6 +218,7 @@ namespace ICSharpCode.ILSpy @@ -216,6 +218,7 @@ namespace ICSharpCode.ILSpy
*/
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
AddReferenceWarningMessage(ev.Module.Assembly, output);
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
CSharpDecompiler decompiler = CreateDecompiler(ev.Module, options);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(ev), decompiler.TypeSystem);
@ -223,6 +226,7 @@ namespace ICSharpCode.ILSpy @@ -223,6 +226,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
AddReferenceWarningMessage(type.Module.Assembly, output);
WriteCommentLine(output, TypeToString(type, includeNamespace: true));
CSharpDecompiler decompiler = CreateDecompiler(type.Module, options);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type), decompiler.TypeSystem);
@ -282,6 +286,40 @@ namespace ICSharpCode.ILSpy @@ -282,6 +286,40 @@ namespace ICSharpCode.ILSpy
return null;
}
void AddReferenceWarningMessage(AssemblyDefinition assembly, ITextOutput output)
{
var loadedAssembly = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.AssemblyDefinition == assembly);
if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.Any(i => i.Value.HasErrors))
return;
const string line1 = "Warning: Some assembly references could not be loaded. This might lead to incorrect decompilation of some parts,";
const string line2 = "for ex. property getter/setter access. To get optimal decompilation results, please manually add the references to the list of loaded assemblies.";
if (output is ISmartTextOutput fancyOutput) {
fancyOutput.AddUIElement(() => new StackPanel {
Margin = new Thickness(5),
Orientation = Orientation.Horizontal,
Children = {
new Image {
Width = 32,
Height = 32,
Source = Images.LoadImage(this, "Images/Warning.png")
},
new TextBlock {
Margin = new Thickness(5, 0, 0, 0),
Text = line1 + Environment.NewLine + line2
}
}
});
fancyOutput.WriteLine();
fancyOutput.AddButton(Images.ViewCode, "Show assembly load log", delegate {
MainWindow.Instance.SelectNode(MainWindow.Instance.FindTreeNode(assembly).Children.OfType<ReferenceFolderTreeNode>().First());
});
fancyOutput.WriteLine();
} else {
WriteCommentLine(output, line1);
WriteCommentLine(output, line2);
}
}
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
if (options.FullDecompilation && options.SaveAsProjectDirectory != null) {
@ -290,6 +328,7 @@ namespace ICSharpCode.ILSpy @@ -290,6 +328,7 @@ namespace ICSharpCode.ILSpy
decompiler.DecompileProject(assembly.ModuleDefinition, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken);
} else {
base.DecompileAssembly(assembly, output, options);
AddReferenceWarningMessage(assembly.AssemblyDefinition, output);
output.WriteLine();
ModuleDefinition mainModule = assembly.ModuleDefinition;
if (mainModule.Types.Count > 0) {

1
ILSpy/Languages/Language.cs

@ -18,7 +18,6 @@ @@ -18,7 +18,6 @@
using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler;
using Mono.Cecil;

76
ILSpy/LoadedAssembly.cs

@ -17,9 +17,12 @@ @@ -17,9 +17,12 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.Options;
using Mono.Cecil;
@ -34,7 +37,9 @@ namespace ICSharpCode.ILSpy @@ -34,7 +37,9 @@ namespace ICSharpCode.ILSpy
readonly AssemblyList assemblyList;
readonly string fileName;
readonly string shortName;
readonly Lazy<string> targetFrameworkId;
readonly Dictionary<string, UnresolvedAssemblyNameReference> loadedAssemblyReferences = new Dictionary<string, UnresolvedAssemblyNameReference>();
public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null)
{
if (assemblyList == null)
@ -46,8 +51,16 @@ namespace ICSharpCode.ILSpy @@ -46,8 +51,16 @@ namespace ICSharpCode.ILSpy
this.assemblyTask = Task.Factory.StartNew<ModuleDefinition>(LoadAssembly, stream); // requires that this.fileName is set
this.shortName = Path.GetFileNameWithoutExtension(fileName);
this.targetFrameworkId = new Lazy<string>(AssemblyDefinition.DetectTargetFrameworkId, false);
}
/// <summary>
/// Returns a target framework identifier in the form '&lt;framework&gt;Version=v&lt;version&gt;'.
/// </summary>
public string TargetFrameworkId => targetFrameworkId.Value;
public Dictionary<string, UnresolvedAssemblyNameReference> LoadedAssemblyReferencesInfo => loadedAssemblyReferences;
/// <summary>
/// Gets the Cecil ModuleDefinition.
/// Can be null when there was a load error.
@ -72,18 +85,12 @@ namespace ICSharpCode.ILSpy @@ -72,18 +85,12 @@ namespace ICSharpCode.ILSpy
return module != null ? module.Assembly : null;
}
}
public AssemblyList AssemblyList {
get { return assemblyList; }
}
public string FileName {
get { return fileName; }
}
public string ShortName {
get { return shortName; }
}
public AssemblyList AssemblyList => assemblyList;
public string FileName => fileName;
public string ShortName => shortName;
public string Text {
get {
@ -94,14 +101,10 @@ namespace ICSharpCode.ILSpy @@ -94,14 +101,10 @@ namespace ICSharpCode.ILSpy
}
}
}
public bool IsLoaded {
get { return assemblyTask.IsCompleted; }
}
public bool HasLoadError {
get { return assemblyTask.IsFaulted; }
}
public bool IsLoaded => assemblyTask.IsCompleted;
public bool HasLoadError => assemblyTask.IsFaulted;
public bool IsAutoLoaded { get; set; }
@ -234,12 +237,15 @@ namespace ICSharpCode.ILSpy @@ -234,12 +237,15 @@ namespace ICSharpCode.ILSpy
{
return assemblyList.assemblyLookupCache.GetOrAdd(fullName, LookupReferencedAssemblyInternal);
}
DotNetCorePathFinder dotNetCorePathFinder;
LoadedAssembly LookupReferencedAssemblyInternal(string fullName)
{
foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) {
if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))
if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase)) {
return asm;
}
}
if (assemblyLoadDisableCount > 0)
return null;
@ -248,9 +254,24 @@ namespace ICSharpCode.ILSpy @@ -248,9 +254,24 @@ namespace ICSharpCode.ILSpy
// Call this method on the GUI thread.
return (LoadedAssembly)App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Func<string, LoadedAssembly>(LookupReferencedAssembly), fullName);
}
var targetFramework = TargetFrameworkId.Split(new[] { ",Version=v" }, StringSplitOptions.None);
var name = AssemblyNameReference.Parse(fullName);
string file = GacInterop.FindAssemblyInNetGac(name);
string file = null;
switch (targetFramework[0]) {
case ".NETCoreApp":
case ".NETStandard":
if (targetFramework.Length != 2) break;
if (dotNetCorePathFinder == null) {
var version = targetFramework[1].Length == 3 ? targetFramework[1] + ".0" : targetFramework[1];
dotNetCorePathFinder = new DotNetCorePathFinder(fileName, TargetFrameworkId, version, this.loadedAssemblyReferences);
}
file = dotNetCorePathFinder.TryResolveDotNetCore(name);
break;
default:
file = GacInterop.FindAssemblyInNetGac(name);
break;
}
if (file == null) {
string dir = Path.GetDirectoryName(this.fileName);
if (File.Exists(Path.Combine(dir, name.Name + ".dll")))
@ -259,9 +280,10 @@ namespace ICSharpCode.ILSpy @@ -259,9 +280,10 @@ namespace ICSharpCode.ILSpy
file = Path.Combine(dir, name.Name + ".exe");
}
if (file != null) {
var loaded = assemblyList.OpenAssembly(file, true);
return loaded;
loadedAssemblyReferences.AddMessage(fullName, MessageKind.Info, "Success - Loading from: " + file);
return assemblyList.OpenAssembly(file, true);
} else {
loadedAssemblyReferences.AddMessage(fullName, MessageKind.Error, "Could not find reference: " + fullName);
return null;
}
}

16
ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs

@ -88,10 +88,22 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -88,10 +88,22 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
var loaded = parentAssembly.LoadedAssembly.LoadedAssemblyReferencesInfo.TryGetValue(r.FullName, out var info);
if (r.IsWindowsRuntime) {
language.WriteCommentLine(output, r.Name + " [WinRT]");
language.WriteCommentLine(output, r.Name + " [WinRT]" + (!loaded ? " (unresolved)" : ""));
} else {
language.WriteCommentLine(output, r.FullName);
language.WriteCommentLine(output, r.FullName + (!loaded ? " (unresolved)" : ""));
}
if (loaded) {
output.Indent();
language.WriteCommentLine(output, "Assembly reference loading information:");
if (info.HasErrors)
language.WriteCommentLine(output, "There were some problems during assembly reference load, see below for more information!");
foreach (var item in info.Messages) {
language.WriteCommentLine(output, $"{item.Item1}: {item.Item2}");
}
output.Unindent();
output.WriteLine();
}
}
}

2
ILSpy/TreeNodes/MethodTreeNode.cs

@ -17,7 +17,9 @@ @@ -17,7 +17,9 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using ICSharpCode.Decompiler;

3
ILSpy/TreeNodes/ReferenceFolderTreeNode.cs

@ -61,7 +61,10 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -61,7 +61,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, $"Detected Target-Framework-Id: {parentAssembly.LoadedAssembly.TargetFrameworkId}");
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
output.WriteLine();
language.WriteCommentLine(output, "Referenced assemblies (in metadata order):");
// Show metadata order of references
foreach (var r in module.AssemblyReferences)
new AssemblyReferenceTreeNode(r, parentAssembly).Decompile(language, output, options);

Loading…
Cancel
Save