diff --git a/BuildTools/appveyor-install.ps1 b/BuildTools/appveyor-install.ps1 index 9897ab827..db3950f43 100644 --- a/BuildTools/appveyor-install.ps1 +++ b/BuildTools/appveyor-install.ps1 @@ -3,6 +3,7 @@ $ErrorActionPreference = "Stop" $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463"; $baseCommitRev = 1; +# make sure this list matches artifacts-only branches list in appveyor.yml! $masterBranches = @("master", "3.2.x"); $globalAssemblyInfoTemplateFile = "ILSpy/Properties/AssemblyInfo.template.cs"; diff --git a/BuildTools/update-assemblyinfo.ps1 b/BuildTools/update-assemblyinfo.ps1 index b5fbe0aba..e304522a8 100644 --- a/BuildTools/update-assemblyinfo.ps1 +++ b/BuildTools/update-assemblyinfo.ps1 @@ -3,6 +3,7 @@ $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463"; $baseCommitRev = 1; +# make sure this list matches artifacts-only branches list in appveyor.yml! $masterBranches = @("master", "3.2.x"); $globalAssemblyInfoTemplateFile = "ILSpy/Properties/AssemblyInfo.template.cs"; diff --git a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs index 4d645e696..9288a1cd2 100644 --- a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs +++ b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; +using ICSharpCode.Decompiler.Util; using LightJson.Serialization; using Mono.Cecil; @@ -27,7 +28,7 @@ namespace ICSharpCode.Decompiler this.Version = parts[1]; this.Type = type; this.Path = path; - this.RuntimeComponents = runtimeComponents ?? new string[0]; + this.RuntimeComponents = runtimeComponents ?? Empty.Array; } } diff --git a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs index 7fb8f2561..7a1545792 100644 --- a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs +++ b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using ICSharpCode.Decompiler.TypeSystem.Implementation; using Mono.Cecil; @@ -8,7 +9,11 @@ namespace ICSharpCode.Decompiler { public static class DotNetCorePathFinderExtensions { - public static string DetectTargetFrameworkId(this AssemblyDefinition assembly) + static readonly string RefPathPattern = + @"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<1>.NETFramework)[/\\]v(?<2>[^/\\]+)[/\\])" + + @"|(NuGetFallbackFolder[/\\](?<1>[^/\\]+)\\(?<2>[^/\\]+)([/\\].*)?[/\\]ref[/\\])"; + + public static string DetectTargetFrameworkId(this AssemblyDefinition assembly, string assemblyPath = null) { if (assembly == null) throw new ArgumentNullException(nameof(assembly)); @@ -24,6 +29,31 @@ namespace ICSharpCode.Decompiler } } + // Optionally try to detect target version through assembly path as a fallback (use case: reference assemblies) + if (assemblyPath != null) { + /* + * Detected path patterns (examples): + * + * - .NETFramework -> C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll + * - .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, + RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture); + if (pathMatch.Success) { + var type = pathMatch.Groups[1].Value; + var version = pathMatch.Groups[2].Value; + + if (type == ".NETFramework") { + return $".NETFramework,Version=v{version}"; + } else if (type.Contains("netcore")) { + return $".NETCoreApp,Version=v{version}"; + } else if (type.Contains("netstandard")) { + return $".NETStandard,Version=v{version}"; + } + } + } + return string.Empty; } } diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 23d0fc910..4a377e5c5 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -1093,21 +1093,47 @@ namespace ICSharpCode.Decompiler.IL return inst; default: Warn("Expected native int or pointer, but got " + inst.ResultType); - return inst; + return new Conv(inst, PrimitiveType.I, false, Sign.None); } } ILInstruction PopFieldTarget(IField field) { - return field.DeclaringType.IsReferenceType == true ? Pop(StackType.O) : PopPointer(); + switch (field.DeclaringType.IsReferenceType) { + case true: + return Pop(StackType.O); + case false: + return PopPointer(); + default: + // field in unresolved type + if (PeekStackType() == StackType.O) + return Pop(); + else + return PopPointer(); + } } + /// + /// Like PopFieldTarget, but supports ldfld's special behavior for fields of temporary value types. + /// ILInstruction PopLdFldTarget(IField field) { - if (field.DeclaringType.IsReferenceType == true) - return Pop(StackType.O); - - return PeekStackType() == StackType.O ? new AddressOf(Pop()) : PopPointer(); + switch (field.DeclaringType.IsReferenceType) { + case true: + return Pop(StackType.O); + case false: + // field of value type: ldfld can handle temporaries + if (PeekStackType() == StackType.O) + return new AddressOf(Pop()); + else + return PopPointer(); + default: + // field in unresolved type + if (PeekStackType() == StackType.O) + return Pop(StackType.O); + else + return PopPointer(); + } } private ILInstruction Return() diff --git a/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs b/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs index 166484078..87917b8d4 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs @@ -25,7 +25,20 @@ namespace ICSharpCode.Decompiler.IL internal override void CheckInvariant(ILPhase phase) { base.CheckInvariant(phase); - Debug.Assert(field.DeclaringType.IsReferenceType == true ? (target.ResultType == StackType.O) : (target.ResultType == StackType.I || target.ResultType == StackType.Ref)); + switch (field.DeclaringType.IsReferenceType) { + case true: + Debug.Assert(target.ResultType == StackType.O, + "Class fields can only be accessed with an object on the stack"); + break; + case false: + Debug.Assert(target.ResultType == StackType.I || target.ResultType == StackType.Ref, + "Struct fields can only be accessed with a pointer on the stack"); + break; + case null: + // field of unresolved type + Debug.Assert(target.ResultType == StackType.O || target.ResultType == StackType.I || target.ResultType == StackType.Ref); + break; + } } } } diff --git a/ILSpy.AddIn/AssemblyFileFinder.cs b/ILSpy.AddIn/AssemblyFileFinder.cs new file mode 100644 index 000000000..9a5f003a9 --- /dev/null +++ b/ILSpy.AddIn/AssemblyFileFinder.cs @@ -0,0 +1,61 @@ +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.Util; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.AddIn +{ + public class AssemblyFileFinder + { + public static string FindAssemblyFile(AssemblyDefinition assemblyDefinition, string assemblyFile) + { + var assemblyName = assemblyDefinition.Name; + + var detectedTargetFramework = assemblyDefinition.DetectTargetFrameworkId(assemblyFile); + if (string.IsNullOrEmpty(detectedTargetFramework)) { + // Without a target framework id it makes no sense to continue + return null; + } + + var targetFramework = detectedTargetFramework.Split(new[] { ",Version=v" }, StringSplitOptions.None); + string file = null; + switch (targetFramework[0]) { + case ".NETCoreApp": + case ".NETStandard": + if (targetFramework.Length != 2) + return FindAssemblyFromGAC(assemblyDefinition); + var version = targetFramework[1].Length == 3 ? targetFramework[1] + ".0" : targetFramework[1]; + var dotNetCorePathFinder = new DotNetCorePathFinder(assemblyFile, detectedTargetFramework, version); + file = dotNetCorePathFinder.TryResolveDotNetCore(assemblyName); + if (file != null) + return file; + return FindAssemblyFromGAC(assemblyDefinition); + default: + return FindAssemblyFromGAC(assemblyDefinition); + } + } + + static string FindAssemblyFromGAC(AssemblyDefinition assemblyDefinition) + { + return GacInterop.FindAssemblyInNetGac(assemblyDefinition.Name); + } + + static readonly string RefPathPattern = @"NuGetFallbackFolder[/\\][^/\\]+[/\\][^/\\]+[/\\]ref[/\\]"; + + public static bool IsReferenceAssembly(AssemblyDefinition assemblyDef, string assemblyFile) + { + if (assemblyDef.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.Runtime.CompilerServices.ReferenceAssemblyAttribute")) + return true; + + // Try to detect reference assembly through specific path pattern + var refPathMatch = Regex.Match(assemblyFile, RefPathPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); + return refPathMatch.Success; + } + + } +} diff --git a/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs b/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs index a80748ce1..958b0e00a 100644 --- a/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs +++ b/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs @@ -106,8 +106,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands owner.ShowMessage(OLEMSGICON.OLEMSGICON_WARNING, "Symbol can't be opened. This might happen while project is loading.", Environment.NewLine, invalidSymbolReference.AssemblyFile); - } - if (invalidSymbolReference.IsProjectReference) { + } else if (invalidSymbolReference.IsProjectReference) { // Some project references don't have assemblies, maybe not compiled yet? if (owner.ShowMessage( OLEMSGBUTTON.OLEMSGBUTTON_YESNO, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_WARNING, diff --git a/ILSpy.AddIn/Commands/OpenILSpyCommand.cs b/ILSpy.AddIn/Commands/OpenILSpyCommand.cs index 9bbd1ae6f..8e8e48193 100644 --- a/ILSpy.AddIn/Commands/OpenILSpyCommand.cs +++ b/ILSpy.AddIn/Commands/OpenILSpyCommand.cs @@ -89,8 +89,8 @@ namespace ICSharpCode.ILSpy.AddIn.Commands foreach (var reference in parentProject.MetadataReferences) { using (var assemblyDef = AssemblyDefinition.ReadAssembly(reference.Display)) { string assemblyName = assemblyDef.Name.Name; - if (IsReferenceAssembly(assemblyDef)) { - string resolvedAssemblyFile = GacInterop.FindAssemblyInNetGac(assemblyDef.Name); + if (AssemblyFileFinder.IsReferenceAssembly(assemblyDef, reference.Display)) { + string resolvedAssemblyFile = AssemblyFileFinder.FindAssemblyFile(assemblyDef, reference.Display); dict.Add(assemblyName, new DetectedReference(assemblyName, resolvedAssemblyFile, false)); } else { @@ -127,11 +127,6 @@ namespace ICSharpCode.ILSpy.AddIn.Commands return null; } - - protected bool IsReferenceAssembly(AssemblyDefinition assemblyDef) - { - return assemblyDef.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.Runtime.CompilerServices.ReferenceAssemblyAttribute"); - } } class OpenILSpyCommand : ILSpyCommand diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj index 26fdc6f75..320a1d5e1 100644 --- a/ILSpy.AddIn/ILSpy.AddIn.csproj +++ b/ILSpy.AddIn/ILSpy.AddIn.csproj @@ -85,6 +85,7 @@ + diff --git a/appveyor.yml b/appveyor.yml index fe610097e..69468dc04 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,8 +31,7 @@ for: - branches: only: - master - - 3.0.x - - 3.1.x + - 3.2.x artifacts: - path: ILSpy_binaries.zip name: ILSpy %APPVEYOR_REPO_BRANCH% %ILSPY_VERSION_NUMBER% binaries