diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index 81bed0532..1e4e1bf2e 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -52,6 +52,7 @@
+
@@ -108,6 +109,7 @@
+
diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
index dffc1d64d..e8984124b 100644
--- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
@@ -579,6 +579,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
}
+ [Test]
+ public void CovariantReturns([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
+ {
+ RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
+ }
+
void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null)
{
Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings);
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
index 69f703a42..edfbab540 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
@@ -36,6 +36,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Issue1747();
CallAmbiguousOutParam();
CallWithInParam();
+ Issue2444.M2();
}
#region ConstructorTest
@@ -334,6 +335,38 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
}
#endif
#endregion
+
+ #region #2444
+ public struct Issue2444
+ {
+ public class X { }
+ public class Y { }
+
+ public static implicit operator Issue2444(X x)
+ {
+ Console.WriteLine("#2444: op_Implicit(X)");
+ return new Issue2444();
+ }
+
+ public static implicit operator Issue2444(Y y)
+ {
+ Console.WriteLine("#2444: op_Implicit(Y)");
+ return new Issue2444();
+ }
+
+ public static void M1(Issue2444 z)
+ {
+ Console.WriteLine(string.Format("#2444: M1({0})", z));
+ }
+
+ public static void M2()
+ {
+ Console.WriteLine("#2444: before M1");
+ M1((X)null);
+ Console.WriteLine("#2444: after M1");
+ }
+ }
+ #endregion
}
class IndexerTests
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml
index aebd4ff9f..1d41df003 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml
@@ -1,7 +1,7 @@
-
-
- t.FullName == "System.Windows.Forms.Control");
@@ -1768,7 +1783,15 @@ namespace ICSharpCode.Decompiler.CSharp
var accessorHandle = (MethodDefinitionHandle)(property.Getter ?? property.Setter).MetadataToken;
var accessor = metadata.GetMethodDefinition(accessorHandle);
if (!accessorHandle.GetMethodImplementations(metadata).Any() && accessor.HasFlag(System.Reflection.MethodAttributes.Virtual) == accessor.HasFlag(System.Reflection.MethodAttributes.NewSlot))
+ {
SetNewModifier(propertyDecl);
+ }
+ if (getterHasBody && IsCovariantReturnOverride(property.Getter))
+ {
+ RemoveAttribute(getter, KnownAttribute.PreserveBaseOverrides);
+ propertyDecl.Modifiers &= ~(Modifiers.New | Modifiers.Virtual);
+ propertyDecl.Modifiers |= Modifiers.Override;
+ }
return propertyDecl;
}
catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException))
diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
index 7cf420ba7..e6e276a7a 100644
--- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
@@ -1148,7 +1148,7 @@ namespace ICSharpCode.Decompiler.CSharp
var conversions = CSharpConversions.Get(expressionBuilder.compilation);
IType targetType = method.ReturnType;
var conv = conversions.ImplicitConversion(argument.Type, targetType);
- if (!(conv.IsUserDefined && conv.Method.Equals(method)))
+ if (!(conv.IsUserDefined && conv.IsValid && conv.Method.Equals(method)))
{
// implicit conversion to targetType isn't directly possible, so first insert a cast to the argument type
argument = argument.ConvertTo(method.Parameters[0].Type, expressionBuilder);
diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
index 2fbdc8bf0..264361f63 100644
--- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
@@ -1618,7 +1618,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
else
{
- return compilation.FindType(stackType.ToKnownTypeCode(sign));
+ return compilation.FindType(stackType, sign);
}
}
@@ -1644,7 +1644,7 @@ namespace ICSharpCode.Decompiler.CSharp
stackType = StackType.I8;
}
}
- return compilation.FindType(stackType.ToKnownTypeCode(sign));
+ return compilation.FindType(stackType, sign);
}
///
@@ -3568,7 +3568,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
else if (!value.Type.Equals(SpecialType.NullType) && !fallback.Type.Equals(SpecialType.NullType) && !value.Type.Equals(fallback.Type))
{
- targetType = compilation.FindType(inst.UnderlyingResultType.ToKnownTypeCode());
+ targetType = compilation.FindType(inst.UnderlyingResultType);
}
else
{
@@ -3731,7 +3731,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
else
{
- resultType = compilation.FindType(inst.ResultType.ToKnownTypeCode());
+ resultType = compilation.FindType(inst.ResultType);
}
foreach (var section in inst.Sections)
diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
index 4e4707ae1..25eadffae 100644
--- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
@@ -36,6 +36,8 @@ using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
+using Microsoft.Win32;
+
using static ICSharpCode.Decompiler.Metadata.MetadataExtensions;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
@@ -126,7 +128,6 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
// per-run members
HashSet directories = new HashSet(Platform.FileNameComparer);
-
readonly IProjectFileWriter projectWriter;
public void DecompileProject(PEFile moduleDefinition, string targetDirectory, CancellationToken cancellationToken = default(CancellationToken))
@@ -252,7 +253,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
#region WriteResourceFilesInProject
protected virtual IEnumerable<(string itemType, string fileName)> WriteResourceFilesInProject(Metadata.PEFile module)
{
- foreach (var r in module.Resources.Where(r => r.ResourceType == Metadata.ResourceType.Embedded))
+ foreach (var r in module.Resources.Where(r => r.ResourceType == ResourceType.Embedded))
{
Stream stream = r.TryOpenStream();
stream.Position = 0;
@@ -268,7 +269,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
foreach (var (name, value) in resourcesFile)
{
- string fileName = Path.Combine(name.Split('/').Select(p => CleanUpFileName(p)).ToArray());
+ string fileName = CleanUpFileName(name)
+ .Replace('/', Path.DirectorySeparatorChar);
string dirName = Path.GetDirectoryName(fileName);
if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName))
{
@@ -359,8 +361,15 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
string GetFileNameForResource(string fullName)
{
- string[] splitName = fullName.Split('.');
- string fileName = CleanUpFileName(fullName);
+ // Clean up the name first and ensure the length does not exceed the maximum length
+ // supported by the OS.
+ fullName = CleanUpDirectoryName(fullName);
+ // The purpose of the below algorithm is to "maximize" the directory name and "minimize" the file name.
+ // That is, a full name of the form "Namespace1.Namespace2{...}.NamespaceN.ResourceName" is split such that
+ // the directory part Namespace1\Namespace2\... reuses as many existing directories as
+ // possible, and only the remaining name parts are used as prefix for the filename.
+ string[] splitName = fullName.Split(Path.DirectorySeparatorChar);
+ string fileName = string.Join(".", splitName);
string separator = Path.DirectorySeparatorChar.ToString();
for (int i = splitName.Length - 1; i > 0; i--)
{
@@ -368,7 +377,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
if (directories.Contains(ns))
{
string name = string.Join(".", splitName, i, splitName.Length - i);
- fileName = Path.Combine(ns, CleanUpFileName(name));
+ fileName = Path.Combine(ns, name);
break;
}
}
@@ -526,10 +535,50 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
}
#endregion
+ static readonly Lazy<(bool longPathsEnabled, int maxPathLength, int maxSegmentLength)> longPathSupport =
+ new Lazy<(bool longPathsEnabled, int maxPathLength, int maxSegmentLength)>(GetLongPathSupport, isThreadSafe: true);
+
+ static (bool longPathsEnabled, int maxPathLength, int maxSegmentLength) GetLongPathSupport()
+ {
+ try
+ {
+ switch (Environment.OSVersion.Platform)
+ {
+ case PlatformID.MacOSX:
+ case PlatformID.Unix:
+ return (true, int.MaxValue, int.MaxValue);
+ case PlatformID.Win32NT:
+ const string key = @"SYSTEM\CurrentControlSet\Control\FileSystem";
+ var fileSystem = Registry.LocalMachine.OpenSubKey(key);
+ var value = (int?)fileSystem.GetValue("LongPathsEnabled");
+ if (value == 1)
+ {
+ return (true, int.MaxValue, 255);
+ }
+ return (false, 200, 30);
+ default:
+ return (false, 200, 30);
+ }
+ }
+ catch
+ {
+ return (false, 200, 30);
+ }
+ }
+
///
/// Cleans up a node name for use as a file name.
///
public static string CleanUpFileName(string text)
+ {
+ return CleanUpFileName(text, separateAtDots: false);
+ }
+
+ ///
+ /// Cleans up a node name for use as a file system name. If is active,
+ /// dots are seen as segment separators. Each segment is limited to 255 characters.
+ ///
+ static string CleanUpFileName(string text, bool separateAtDots)
{
int pos = text.IndexOf(':');
if (pos > 0)
@@ -540,16 +589,38 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
text = text.Trim();
// Whitelist allowed characters, replace everything else:
StringBuilder b = new StringBuilder(text.Length);
+ int currentSegmentLength = 0;
+ var (supportsLongPaths, maxPathLength, maxSegmentLength) = longPathSupport.Value;
foreach (var c in text)
{
+ currentSegmentLength++;
if (char.IsLetterOrDigit(c) || c == '-' || c == '_')
- b.Append(c);
+ {
+ // if the current segment exceeds 255 characters,
+ // skip until the end of the segment.
+ if (currentSegmentLength <= maxSegmentLength)
+ b.Append(c);
+ }
else if (c == '.' && b.Length > 0 && b[b.Length - 1] != '.')
- b.Append('.'); // allow dot, but never two in a row
+ {
+ // if the current segment exceeds 255 characters,
+ // skip until the end of the segment.
+ if (separateAtDots || currentSegmentLength <= maxSegmentLength)
+ b.Append('.'); // allow dot, but never two in a row
+
+ // Reset length at end of segment.
+ if (separateAtDots)
+ currentSegmentLength = 0;
+ }
else
- b.Append('-');
- if (b.Length >= 200)
- break; // limit to 200 chars
+ {
+ // if the current segment exceeds 255 characters,
+ // skip until the end of the segment.
+ if (currentSegmentLength <= maxSegmentLength)
+ b.Append('-');
+ }
+ if (b.Length >= maxPathLength && !supportsLongPaths)
+ break; // limit to 200 chars, if long paths are not supported.
}
if (b.Length == 0)
b.Append('-');
@@ -567,7 +638,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
///
public static string CleanUpDirectoryName(string text)
{
- return CleanUpFileName(text).Replace('.', Path.DirectorySeparatorChar);
+ return CleanUpFileName(text, separateAtDots: true).Replace('.', Path.DirectorySeparatorChar);
}
static bool IsReservedFileSystemName(string name)
diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
index 1bfef1ecf..868f7fe59 100644
--- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
+++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
@@ -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.Linq;
@@ -45,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public static CSharpOperators Get(ICompilation compilation)
{
CacheManager cache = compilation.CacheManager;
- CSharpOperators operators = (CSharpOperators)cache.GetShared(typeof(CSharpOperators));
+ CSharpOperators? operators = (CSharpOperators?)cache.GetShared(typeof(CSharpOperators));
if (operators == null)
{
operators = (CSharpOperators)cache.GetOrAddShared(typeof(CSharpOperators), new CSharpOperators(compilation));
@@ -59,7 +61,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
List result = new List(methods);
foreach (OperatorMethod method in methods)
{
- OperatorMethod lifted = method.Lift(this);
+ OperatorMethod? lifted = method.Lift(this);
if (lifted != null)
result.Add(lifted);
}
@@ -111,20 +113,20 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return parameters; }
}
- public IType ReturnType { get; internal set; }
+ public IType ReturnType { get; internal set; } = null!; // initialized by derived class ctor
public ICompilation Compilation {
get { return compilation; }
}
- public virtual OperatorMethod Lift(CSharpOperators operators)
+ public virtual OperatorMethod? Lift(CSharpOperators operators)
{
return null;
}
public System.Reflection.Metadata.EntityHandle MetadataToken => default;
- ITypeDefinition IEntity.DeclaringTypeDefinition {
+ ITypeDefinition? IEntity.DeclaringTypeDefinition {
get { return null; }
}
@@ -226,7 +228,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return b.ToString();
}
- bool IMember.Equals(IMember obj, TypeVisitor typeNormalization)
+ bool IMember.Equals(IMember? obj, TypeVisitor? typeNormalization)
{
return this == obj;
}
@@ -238,7 +240,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
public virtual bool CanEvaluateAtCompileTime { get { return false; } }
- public virtual object Invoke(CSharpResolver resolver, object input)
+ public virtual object? Invoke(CSharpResolver resolver, object? input)
{
throw new NotSupportedException();
}
@@ -265,7 +267,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return true; }
}
- public override object Invoke(CSharpResolver resolver, object input)
+ public override object? Invoke(CSharpResolver resolver, object? input)
{
if (input == null)
return null;
@@ -296,11 +298,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region Unary operator definitions
// C# 4.0 spec: §7.7.1 Unary plus operator
- OperatorMethod[] unaryPlusOperators;
+ OperatorMethod[]? unaryPlusOperators;
public OperatorMethod[] UnaryPlusOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref unaryPlusOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref unaryPlusOperators);
if (ops != null)
{
return ops;
@@ -321,11 +323,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
// C# 4.0 spec: §7.7.2 Unary minus operator
- OperatorMethod[] uncheckedUnaryMinusOperators;
+ OperatorMethod[]? uncheckedUnaryMinusOperators;
public OperatorMethod[] UncheckedUnaryMinusOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref uncheckedUnaryMinusOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref uncheckedUnaryMinusOperators);
if (ops != null)
{
return ops;
@@ -343,11 +345,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] checkedUnaryMinusOperators;
+ OperatorMethod[]? checkedUnaryMinusOperators;
public OperatorMethod[] CheckedUnaryMinusOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref checkedUnaryMinusOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref checkedUnaryMinusOperators);
if (ops != null)
{
return ops;
@@ -366,11 +368,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
// C# 4.0 spec: §7.7.3 Logical negation operator
- OperatorMethod[] logicalNegationOperators;
+ OperatorMethod[]? logicalNegationOperators;
public OperatorMethod[] LogicalNegationOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalNegationOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref logicalNegationOperators);
if (ops != null)
{
return ops;
@@ -385,11 +387,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
// C# 4.0 spec: §7.7.4 Bitwise complement operator
- OperatorMethod[] bitwiseComplementOperators;
+ OperatorMethod[]? bitwiseComplementOperators;
public OperatorMethod[] BitwiseComplementOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseComplementOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref bitwiseComplementOperators);
if (ops != null)
{
return ops;
@@ -411,7 +413,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
internal class BinaryOperatorMethod : OperatorMethod
{
public virtual bool CanEvaluateAtCompileTime { get { return false; } }
- public virtual object Invoke(CSharpResolver resolver, object lhs, object rhs)
+ public virtual object? Invoke(CSharpResolver resolver, object? lhs, object? rhs)
{
throw new NotSupportedException();
}
@@ -444,7 +446,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return true; }
}
- public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
+ public override object? Invoke(CSharpResolver resolver, object? lhs, object? rhs)
{
if (lhs == null || rhs == null)
return null;
@@ -480,11 +482,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region Arithmetic operators
// C# 4.0 spec: §7.8.1 Multiplication operator
- OperatorMethod[] multiplicationOperators;
+ OperatorMethod[]? multiplicationOperators;
public OperatorMethod[] MultiplicationOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref multiplicationOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref multiplicationOperators);
if (ops != null)
{
return ops;
@@ -505,11 +507,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
// C# 4.0 spec: §7.8.2 Division operator
- OperatorMethod[] divisionOperators;
+ OperatorMethod[]? divisionOperators;
public OperatorMethod[] DivisionOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref divisionOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref divisionOperators);
if (ops != null)
{
return ops;
@@ -530,11 +532,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
// C# 4.0 spec: §7.8.3 Remainder operator
- OperatorMethod[] remainderOperators;
+ OperatorMethod[]? remainderOperators;
public OperatorMethod[] RemainderOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref remainderOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref remainderOperators);
if (ops != null)
{
return ops;
@@ -555,11 +557,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
// C# 4.0 spec: §7.8.3 Addition operator
- OperatorMethod[] additionOperators;
+ OperatorMethod[]? additionOperators;
public OperatorMethod[] AdditionOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref additionOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref additionOperators);
if (ops != null)
{
return ops;
@@ -600,18 +602,18 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return canEvaluateAtCompileTime; }
}
- public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
+ public override object? Invoke(CSharpResolver? resolver, object? lhs, object? rhs)
{
return string.Concat(lhs, rhs);
}
}
// C# 4.0 spec: §7.8.4 Subtraction operator
- OperatorMethod[] subtractionOperators;
+ OperatorMethod[]? subtractionOperators;
public OperatorMethod[] SubtractionOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref subtractionOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref subtractionOperators);
if (ops != null)
{
return ops;
@@ -632,11 +634,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
// C# 4.0 spec: §7.8.5 Shift operators
- OperatorMethod[] shiftLeftOperators;
+ OperatorMethod[]? shiftLeftOperators;
public OperatorMethod[] ShiftLeftOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftLeftOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref shiftLeftOperators);
if (ops != null)
{
return ops;
@@ -653,11 +655,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] shiftRightOperators;
+ OperatorMethod[]? shiftRightOperators;
public OperatorMethod[] ShiftRightOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftRightOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref shiftRightOperators);
if (ops != null)
{
return ops;
@@ -695,7 +697,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return Type != TypeCode.Object; }
}
- public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
+ public override object Invoke(CSharpResolver resolver, object? lhs, object? rhs)
{
if (lhs == null && rhs == null)
return !Negate; // ==: true; !=: false
@@ -719,7 +721,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return equal ^ Negate;
}
- public override OperatorMethod Lift(CSharpOperators operators)
+ public override OperatorMethod? Lift(CSharpOperators operators)
{
if (Type == TypeCode.Object || Type == TypeCode.String)
return null;
@@ -746,7 +748,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return baseMethod.CanEvaluateAtCompileTime; }
}
- public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
+ public override object Invoke(CSharpResolver resolver, object? lhs, object? rhs)
{
return baseMethod.Invoke(resolver, lhs, rhs);
}
@@ -764,11 +766,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
TypeCode.Boolean
};
- OperatorMethod[] valueEqualityOperators;
+ OperatorMethod[]? valueEqualityOperators;
public OperatorMethod[] ValueEqualityOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref valueEqualityOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref valueEqualityOperators);
if (ops != null)
{
return ops;
@@ -782,11 +784,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] valueInequalityOperators;
+ OperatorMethod[]? valueInequalityOperators;
public OperatorMethod[] ValueInequalityOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref valueInequalityOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref valueInequalityOperators);
if (ops != null)
{
return ops;
@@ -800,11 +802,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] referenceEqualityOperators;
+ OperatorMethod[]? referenceEqualityOperators;
public OperatorMethod[] ReferenceEqualityOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceEqualityOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref referenceEqualityOperators);
if (ops != null)
{
return ops;
@@ -819,11 +821,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] referenceInequalityOperators;
+ OperatorMethod[]? referenceInequalityOperators;
public OperatorMethod[] ReferenceInequalityOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceInequalityOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref referenceInequalityOperators);
if (ops != null)
{
return ops;
@@ -857,7 +859,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return true; }
}
- public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
+ public override object? Invoke(CSharpResolver resolver, object? lhs, object? rhs)
{
if (lhs == null || rhs == null)
return null;
@@ -873,11 +875,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] lessThanOperators;
+ OperatorMethod[]? lessThanOperators;
public OperatorMethod[] LessThanOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref lessThanOperators);
if (ops != null)
{
return ops;
@@ -897,11 +899,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] lessThanOrEqualOperators;
+ OperatorMethod[]? lessThanOrEqualOperators;
public OperatorMethod[] LessThanOrEqualOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOrEqualOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref lessThanOrEqualOperators);
if (ops != null)
{
return ops;
@@ -921,11 +923,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] greaterThanOperators;
+ OperatorMethod[]? greaterThanOperators;
public OperatorMethod[] GreaterThanOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref greaterThanOperators);
if (ops != null)
{
return ops;
@@ -945,11 +947,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] greaterThanOrEqualOperators;
+ OperatorMethod[]? greaterThanOrEqualOperators;
public OperatorMethod[] GreaterThanOrEqualOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOrEqualOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref greaterThanOrEqualOperators);
if (ops != null)
{
return ops;
@@ -971,11 +973,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#endregion
#region Bitwise operators
- OperatorMethod[] logicalAndOperators;
+ OperatorMethod[]? logicalAndOperators;
public OperatorMethod[] LogicalAndOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalAndOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref logicalAndOperators);
if (ops != null)
{
return ops;
@@ -990,11 +992,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
- OperatorMethod[] bitwiseAndOperators;
+ OperatorMethod[]? bitwiseAndOperators;
public OperatorMethod[] BitwiseAndOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseAndOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref bitwiseAndOperators);
if (ops != null)
{
return ops;
@@ -1013,11 +1015,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
- OperatorMethod[] logicalOrOperators;
+ OperatorMethod[]? logicalOrOperators;
public OperatorMethod[] LogicalOrOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalOrOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref logicalOrOperators);
if (ops != null)
{
return ops;
@@ -1031,11 +1033,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- OperatorMethod[] bitwiseOrOperators;
+ OperatorMethod[]? bitwiseOrOperators;
public OperatorMethod[] BitwiseOrOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseOrOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref bitwiseOrOperators);
if (ops != null)
{
return ops;
@@ -1057,11 +1059,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// we produce "true | null" = "null" when it should be true. However, this is irrelevant
// because bool? cannot be a compile-time type.
- OperatorMethod[] bitwiseXorOperators;
+ OperatorMethod[]? bitwiseXorOperators;
public OperatorMethod[] BitwiseXorOperators {
get {
- OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseXorOperators);
+ OperatorMethod[]? ops = LazyInit.VolatileRead(ref bitwiseXorOperators);
if (ops != null)
{
return ops;
@@ -1081,7 +1083,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#endregion
#region User-defined operators
- public static IMethod LiftUserDefinedOperator(IMethod m)
+ public static IMethod? LiftUserDefinedOperator(IMethod m)
{
if (IsComparisonOperator(m))
{
@@ -1129,9 +1131,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public IReadOnlyList NonLiftedParameters => nonLiftedOperator.Parameters;
public IType NonLiftedReturnType => nonLiftedOperator.ReturnType;
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- LiftedUserDefinedOperator op = obj as LiftedUserDefinedOperator;
+ LiftedUserDefinedOperator? op = obj as LiftedUserDefinedOperator;
return op != null && this.nonLiftedOperator.Equals(op.nonLiftedOperator);
}
diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
index c6fd018e8..334ca0e6a 100644
--- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
@@ -2259,20 +2259,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
var declaringType = member.DeclaringType;
if (member.IsExplicitInterfaceImplementation)
return false;
- if (declaringType != null && declaringType.Kind == TypeKind.Interface)
- {
- return member.Accessibility != Accessibility.Public;
- }
switch (member.SymbolKind)
{
case SymbolKind.Constructor:
return !member.IsStatic;
case SymbolKind.Destructor:
return false;
- case SymbolKind.Method:
- return !((IMethod)member).IsLocalFunction;
default:
- return true;
+ if (declaringType?.Kind == TypeKind.Interface)
+ {
+ return member.Accessibility != Accessibility.Public;
+ }
+ return member is not IMethod method || !method.IsLocalFunction;
}
}
diff --git a/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
index fdc87c352..23223a805 100644
--- a/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
+++ b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
@@ -66,7 +66,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
string BuildFileNameFromTypeName(TypeDefinitionHandle handle)
{
var typeName = handle.GetFullTypeName(reader).TopLevelTypeName;
- return Path.Combine(WholeProjectDecompiler.CleanUpFileName(typeName.Namespace), WholeProjectDecompiler.CleanUpFileName(typeName.Name) + ".cs");
+ return Path.Combine(WholeProjectDecompiler.CleanUpDirectoryName(typeName.Namespace), WholeProjectDecompiler.CleanUpFileName(typeName.Name) + ".cs");
}
foreach (var sourceFile in reader.GetTopLevelTypeDefinitions().GroupBy(BuildFileNameFromTypeName))
diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs
index 6f901f084..fc3797092 100644
--- a/ICSharpCode.Decompiler/DecompilerSettings.cs
+++ b/ICSharpCode.Decompiler/DecompilerSettings.cs
@@ -140,12 +140,14 @@ namespace ICSharpCode.Decompiler
recordClasses = false;
withExpressions = false;
usePrimaryConstructorSyntax = false;
+ covariantReturns = false;
}
}
public CSharp.LanguageVersion GetMinimumRequiredVersion()
{
- if (nativeIntegers || initAccessors || functionPointers || forEachWithGetEnumeratorExtension || recordClasses)
+ if (nativeIntegers || initAccessors || functionPointers || forEachWithGetEnumeratorExtension
+ || recordClasses || withExpressions || usePrimaryConstructorSyntax || covariantReturns)
return CSharp.LanguageVersion.Preview;
if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement
|| staticLocalFunctions || ranges || switchExpressions)
@@ -194,6 +196,24 @@ namespace ICSharpCode.Decompiler
}
}
+ bool covariantReturns = true;
+
+ ///
+ /// Decompile C# 9 covariant return types.
+ ///
+ [Category("C# 9.0 / VS 2019.8")]
+ [Description("DecompilerSettings.CovariantReturns")]
+ public bool CovariantReturns {
+ get { return covariantReturns; }
+ set {
+ if (covariantReturns != value)
+ {
+ covariantReturns = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+
bool initAccessors = true;
///
diff --git a/ICSharpCode.Decompiler/Disassembler/ILParser.cs b/ICSharpCode.Decompiler/Disassembler/ILParser.cs
index 4cb364790..4b606c83f 100644
--- a/ICSharpCode.Decompiler/Disassembler/ILParser.cs
+++ b/ICSharpCode.Decompiler/Disassembler/ILParser.cs
@@ -107,5 +107,21 @@ namespace ICSharpCode.Decompiler.Disassembler
{
return opCode == ILOpCode.Ret || opCode == ILOpCode.Endfilter || opCode == ILOpCode.Endfinally;
}
+
+ public static int GetHeaderSize(BlobReader bodyBlockReader)
+ {
+ byte header = bodyBlockReader.ReadByte();
+ if ((header & 3) == 3)
+ {
+ // fat
+ ushort largeHeader = (ushort)((bodyBlockReader.ReadByte() << 8) | header);
+ return (byte)(largeHeader >> 12) * 4;
+ }
+ else
+ {
+ // tiny
+ return 1;
+ }
+ }
}
}
diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
index 6403a231f..3d085f25d 100644
--- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
+++ b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
@@ -58,6 +58,11 @@ namespace ICSharpCode.Decompiler.Disassembler
///
public bool ShowMetadataTokensInBase10 { get; set; }
+ ///
+ /// Show raw RVA offset and bytes before each instruction.
+ ///
+ public bool ShowRawRVAOffsetAndBytes { get; set; }
+
///
/// Optional provider for sequence points.
///
@@ -90,15 +95,18 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Method begins at RVA 0x{0:x4}", methodDefinition.RelativeVirtualAddress);
if (methodDefinition.RelativeVirtualAddress == 0)
{
- output.WriteLine("// Code size {0} (0x{0:x})", 0);
+ output.WriteLine("// Header size: {0}", 0);
+ output.WriteLine("// Code size: {0} (0x{0:x})", 0);
output.WriteLine(".maxstack {0}", 0);
output.WriteLine();
return;
}
MethodBodyBlock body;
+ BlobReader bodyBlockReader;
try
{
body = module.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
+ bodyBlockReader = module.Reader.GetSectionData(methodDefinition.RelativeVirtualAddress).GetReader();
}
catch (BadImageFormatException ex)
{
@@ -106,7 +114,9 @@ namespace ICSharpCode.Decompiler.Disassembler
return;
}
var blob = body.GetILReader();
- output.WriteLine("// Code size {0} (0x{0:x})", blob.Length);
+ int headerSize = ILParser.GetHeaderSize(bodyBlockReader);
+ output.WriteLine("// Header size: {0}", headerSize);
+ output.WriteLine("// Code size: {0} (0x{0:x})", blob.Length);
output.WriteLine(".maxstack {0}", body.MaxStack);
var entrypointHandle = MetadataTokens.MethodDefinitionHandle(module.Reader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress);
@@ -123,14 +133,14 @@ namespace ICSharpCode.Decompiler.Disassembler
blob.Reset();
HashSet branchTargets = GetBranchTargets(blob);
blob.Reset();
- WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob);
+ WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob, methodDefinition.RelativeVirtualAddress + headerSize);
}
else
{
while (blob.RemainingBytes > 0)
{
cancellationToken.ThrowIfCancellationRequested();
- WriteInstruction(output, metadata, handle, ref blob);
+ WriteInstruction(output, metadata, handle, ref blob, methodDefinition.RelativeVirtualAddress);
}
WriteExceptionHandlers(module, handle, body);
}
@@ -276,7 +286,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Indent();
}
- void WriteStructureBody(ILStructure s, HashSet branchTargets, ref BlobReader body)
+ void WriteStructureBody(ILStructure s, HashSet branchTargets, ref BlobReader body, int methodRva)
{
bool isFirstInstructionInStructure = true;
bool prevInstructionWasBranch = false;
@@ -289,7 +299,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{
ILStructure child = s.Children[childIndex++];
WriteStructureHeader(child);
- WriteStructureBody(child, branchTargets, ref body);
+ WriteStructureBody(child, branchTargets, ref body, methodRva);
WriteStructureFooter(child);
}
else
@@ -300,7 +310,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
var currentOpCode = ILParser.DecodeOpCode(ref body);
body.Offset = offset; // reset IL stream
- WriteInstruction(output, metadata, s.MethodHandle, ref body);
+ WriteInstruction(output, metadata, s.MethodHandle, ref body, methodRva);
prevInstructionWasBranch = currentOpCode.IsBranch()
|| currentOpCode.IsReturn()
|| currentOpCode == ILOpCode.Throw
@@ -333,7 +343,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
}
- protected virtual void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodDefinition, ref BlobReader blob)
+ protected virtual void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodHandle, ref BlobReader blob, int methodRva)
{
int offset = blob.Offset;
if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count)
@@ -358,10 +368,11 @@ namespace ICSharpCode.Decompiler.Disassembler
}
}
ILOpCode opCode = ILParser.DecodeOpCode(ref blob);
- output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
- output.Write(": ");
if (opCode.IsDefined())
{
+ WriteRVA(blob, offset + methodRva, opCode);
+ output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
+ output.Write(": ");
WriteOpCode(opCode);
switch (opCode.GetOperandType())
{
@@ -464,12 +475,40 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteMetadataToken(userString, metadataToken, spaceBefore: true);
break;
case OperandType.Switch:
+ var tmp = blob;
int[] targets = ILParser.DecodeSwitchTargets(ref blob);
- output.Write(" (");
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.WriteLine(" (");
+ }
+ else
+ {
+ output.Write(" (");
+ }
+ tmp.ReadInt32();
for (int i = 0; i < targets.Length; i++)
{
if (i > 0)
- output.Write(", ");
+ {
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.WriteLine(",");
+ }
+ else
+ {
+ output.Write(", ");
+ }
+ }
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"{tmp.ReadByte():X2}{tmp.ReadByte():X2}{tmp.ReadByte():X2}{tmp.ReadByte():X2}");
+ output.Write(" */ ");
+ }
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write(" ");
+ }
output.WriteLocalReference($"IL_{targets[i]:x4}", targets[i]);
}
output.Write(")");
@@ -479,11 +518,11 @@ namespace ICSharpCode.Decompiler.Disassembler
int index = blob.ReadUInt16();
if (opCode == ILOpCode.Ldloc || opCode == ILOpCode.Ldloca || opCode == ILOpCode.Stloc)
{
- DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteVariableReference(output, metadata, methodHandle, index);
}
else
{
- DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteParameterReference(output, metadata, methodHandle, index);
}
break;
case OperandType.ShortVariable:
@@ -491,11 +530,11 @@ namespace ICSharpCode.Decompiler.Disassembler
index = blob.ReadByte();
if (opCode == ILOpCode.Ldloc_s || opCode == ILOpCode.Ldloca_s || opCode == ILOpCode.Stloc_s)
{
- DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteVariableReference(output, metadata, methodHandle, index);
}
else
{
- DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteParameterReference(output, metadata, methodHandle, index);
}
break;
}
@@ -505,8 +544,22 @@ namespace ICSharpCode.Decompiler.Disassembler
ushort opCodeValue = (ushort)opCode;
if (opCodeValue > 0xFF)
{
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"0x{offset + methodRva:X8} {(ushort)opCode >> 8:X2}");
+ output.Write(" */ ");
+ }
+ output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
+ output.Write(": ");
// split 16-bit value into two emitbyte directives
output.WriteLine($".emitbyte 0x{(byte)(opCodeValue >> 8):x}");
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"0x{offset + methodRva + 1:X8} {(ushort)opCode & 0xFF:X2}");
+ output.Write(" */ ");
+ }
// add label
output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset + 1), offset + 1, isDefinition: true);
output.Write(": ");
@@ -514,12 +567,49 @@ namespace ICSharpCode.Decompiler.Disassembler
}
else
{
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"0x{offset + methodRva:X8} {(ushort)opCode & 0xFF:X2}");
+ output.Write(" */ ");
+ }
+ output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
+ output.Write(": ");
output.Write($".emitbyte 0x{(byte)opCodeValue:x}");
}
}
output.WriteLine();
}
+ void WriteRVA(BlobReader blob, int offset, ILOpCode opCode)
+ {
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ var tmp = blob;
+ if (opCode == ILOpCode.Switch)
+ {
+ tmp.ReadInt32();
+ }
+ else
+ {
+ ILParser.SkipOperand(ref tmp, opCode);
+ }
+ output.Write($"0x{offset:X8} {(ushort)opCode:X2}");
+ int appendSpaces = (ushort)opCode > 0xFF ? 14 : 16;
+ while (blob.Offset < tmp.Offset)
+ {
+ output.Write($"{blob.ReadByte():X2}");
+ appendSpaces -= 2;
+ }
+ if (appendSpaces > 0)
+ {
+ output.Write(new string(' ', appendSpaces));
+ }
+ output.Write(" */ ");
+ }
+ }
+
private void WriteOpCode(ILOpCode opCode)
{
var opCodeInfo = new OpCodeInfo(opCode, opCode.GetDisplayName());
diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
index 861ba7fb2..67cd3ee9b 100644
--- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
+++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
@@ -61,6 +61,11 @@ namespace ICSharpCode.Decompiler.Disassembler
set => methodBodyDisassembler.ShowMetadataTokensInBase10 = value;
}
+ public bool ShowRawRVAOffsetAndBytes {
+ get => methodBodyDisassembler.ShowRawRVAOffsetAndBytes;
+ set => methodBodyDisassembler.ShowRawRVAOffsetAndBytes = value;
+ }
+
public IDebugInfoProvider DebugInfo {
get => methodBodyDisassembler.DebugInfo;
set => methodBodyDisassembler.DebugInfo = value;
diff --git a/ICSharpCode.Decompiler/Documentation/XmlDocumentationElement.cs b/ICSharpCode.Decompiler/Documentation/XmlDocumentationElement.cs
index 61948f6ca..088f6808b 100644
--- a/ICSharpCode.Decompiler/Documentation/XmlDocumentationElement.cs
+++ b/ICSharpCode.Decompiler/Documentation/XmlDocumentationElement.cs
@@ -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.Linq;
@@ -23,7 +25,6 @@ using System.Text;
using System.Threading;
using System.Xml.Linq;
-using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
@@ -35,15 +36,10 @@ namespace ICSharpCode.Decompiler.Documentation
///
public class XmlDocumentationElement
{
- static XmlDocumentationElement Create(string documentationComment, IEntity declaringEntity)
- {
- return new XmlDocumentationElement(XElement.Parse(documentationComment), declaringEntity, null);
- }
-
- readonly XElement element;
- readonly IEntity declaringEntity;
- readonly Func crefResolver;
- volatile string textContent;
+ readonly XElement? element;
+ readonly IEntity? declaringEntity;
+ readonly Func? crefResolver;
+ volatile string? textContent;
///
/// Inheritance level; used to prevent cyclic doc inheritance.
@@ -53,7 +49,7 @@ namespace ICSharpCode.Decompiler.Documentation
///
/// Creates a new documentation element.
///
- public XmlDocumentationElement(XElement element, IEntity declaringEntity, Func crefResolver)
+ public XmlDocumentationElement(XElement element, IEntity? declaringEntity, Func? crefResolver)
{
if (element == null)
throw new ArgumentNullException(nameof(element));
@@ -65,7 +61,7 @@ namespace ICSharpCode.Decompiler.Documentation
///
/// Creates a new documentation element.
///
- public XmlDocumentationElement(string text, IEntity declaringEntity)
+ public XmlDocumentationElement(string text, IEntity? declaringEntity)
{
if (text == null)
throw new ArgumentNullException(nameof(text));
@@ -77,26 +73,26 @@ namespace ICSharpCode.Decompiler.Documentation
/// Gets the entity on which this documentation was originally declared.
/// May return null.
///
- public IEntity DeclaringEntity {
+ public IEntity? DeclaringEntity {
get { return declaringEntity; }
}
- IEntity referencedEntity;
+ IEntity? referencedEntity;
volatile bool referencedEntityInitialized;
///
/// Gets the entity referenced by the 'cref' attribute.
/// May return null.
///
- public IEntity ReferencedEntity {
+ public IEntity? ReferencedEntity {
get {
if (!referencedEntityInitialized)
{
- string cref = GetAttribute("cref");
+ string? cref = GetAttribute("cref");
try
{
if (!string.IsNullOrEmpty(cref) && crefResolver != null)
- referencedEntity = crefResolver(cref);
+ referencedEntity = crefResolver(cref!);
}
catch
{
@@ -120,7 +116,7 @@ namespace ICSharpCode.Decompiler.Documentation
///
/// Gets the attribute value.
///
- public string GetAttribute(string name)
+ public string? GetAttribute(string? name)
{
return element?.Attribute(name)?.Value;
}
@@ -148,7 +144,7 @@ namespace ICSharpCode.Decompiler.Documentation
}
}
- IList children;
+ IList? children;
///
/// Gets the child elements.
@@ -159,7 +155,7 @@ namespace ICSharpCode.Decompiler.Documentation
return EmptyList.Instance;
return LazyInitializer.EnsureInitialized(
ref this.children,
- () => CreateElements(element.Nodes(), declaringEntity, crefResolver, nestingLevel));
+ () => CreateElements(element.Nodes(), declaringEntity, crefResolver, nestingLevel))!;
}
}
@@ -168,7 +164,7 @@ namespace ICSharpCode.Decompiler.Documentation
"remarks", "returns", "threadsafety", "value"
};
- static List CreateElements(IEnumerable childObjects, IEntity declaringEntity, Func crefResolver, int nestingLevel)
+ static List CreateElements(IEnumerable childObjects, IEntity? declaringEntity, Func? crefResolver, int nestingLevel)
{
List list = new List();
foreach (var child in childObjects)
@@ -188,23 +184,24 @@ namespace ICSharpCode.Decompiler.Documentation
{
if (nestingLevel < 5 && childElement.Name == "inheritdoc")
{
- string cref = childElement.Attribute("cref").Value;
- IEntity inheritedFrom = null;
- string inheritedDocumentation = null;
- if (cref != null)
+ string? cref = childElement.Attribute("cref")?.Value;
+ IEntity? inheritedFrom = null;
+ string? inheritedDocumentation = null;
+ if (cref != null && crefResolver != null)
{
inheritedFrom = crefResolver(cref);
if (inheritedFrom != null)
- inheritedDocumentation = inheritedFrom.GetDocumentation();
+ inheritedDocumentation = "" + inheritedFrom.GetDocumentation() + "";
}
else
{
- foreach (IMember baseMember in InheritanceHelper.GetBaseMembers((IMember)declaringEntity, includeImplementedInterfaces: true))
+ foreach (IMember baseMember in InheritanceHelper.GetBaseMembers((IMember?)declaringEntity, includeImplementedInterfaces: true))
{
inheritedDocumentation = baseMember.GetDocumentation();
if (inheritedDocumentation != null)
{
inheritedFrom = baseMember;
+ inheritedDocumentation = "" + inheritedDocumentation + "";
break;
}
}
@@ -212,10 +209,10 @@ namespace ICSharpCode.Decompiler.Documentation
if (inheritedDocumentation != null)
{
- var doc = XDocument.Parse(inheritedDocumentation);
+ var doc = XDocument.Parse(inheritedDocumentation).Element("doc");
// XPath filter not yet implemented
- if (childElement.Parent == null && childElement.Attribute("select").Value == null)
+ if (childElement.Parent?.Parent == null && childElement.Attribute("select")?.Value == null)
{
// Inheriting documentation at the root level
List doNotInherit = new List();
@@ -225,7 +222,7 @@ namespace ICSharpCode.Decompiler.Documentation
var inheritedChildren = doc.Nodes().Where(
inheritedObject => {
- XElement inheritedElement = inheritedObject as XElement;
+ XElement? inheritedElement = inheritedObject as XElement;
return !(inheritedElement != null && doNotInherit.Contains(inheritedElement.Name.LocalName));
});
@@ -244,14 +241,14 @@ namespace ICSharpCode.Decompiler.Documentation
if (string.IsNullOrWhiteSpace(list[0].textContent))
list.RemoveAt(0);
else
- list[0].textContent = list[0].textContent.TrimStart();
+ list[0].textContent = list[0].textContent!.TrimStart();
}
if (list.Count > 0 && list[list.Count - 1].IsTextNode)
{
if (string.IsNullOrWhiteSpace(list[list.Count - 1].textContent))
list.RemoveAt(list.Count - 1);
else
- list[list.Count - 1].textContent = list[list.Count - 1].textContent.TrimEnd();
+ list[list.Count - 1].textContent = list[list.Count - 1].textContent!.TrimEnd();
}
return list;
}
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 962f6795a..7ebd56f7c 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -19,26 +19,30 @@
True
ICSharpCode.Decompiler.snk
1701;1702;1591;1573
+
+ embedded
+ true
+ true
+ true
true
- true
ICSharpCode.Decompiler.nuspec
Configuration=$(Configuration)
- portable
- true
True
$(DefineConstants);STEP
- portable
- true
+
+
+
+ true
@@ -49,6 +53,7 @@
+
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec.template b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec.template
index 6c4d3d3c9..d371363fb 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec.template
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec.template
@@ -25,7 +25,6 @@
-
diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs
index d84dc5ee5..b6205914b 100644
--- a/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs
+++ b/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs
@@ -157,7 +157,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{
identifierValueTargets.Add(value, otherBranch.TargetBlock);
block.Instructions.RemoveAt(statement.ChildIndex + 1);
- statement.ReplaceWith(otherBranch);
+ statement.ReplaceWith(branchToTarget);
}
else
{
diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs
index 0f0a000dc..83e78cb82 100644
--- a/ICSharpCode.Decompiler/IL/ILReader.cs
+++ b/ICSharpCode.Decompiler/IL/ILReader.cs
@@ -1170,7 +1170,7 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction Push(ILInstruction inst)
{
Debug.Assert(inst.ResultType != StackType.Void);
- IType type = compilation.FindType(inst.ResultType.ToKnownTypeCode());
+ IType type = compilation.FindType(inst.ResultType);
var v = new ILVariable(VariableKind.StackSlot, type, inst.ResultType);
v.HasGeneratedName = true;
currentStack = currentStack.Push(v);
diff --git a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
index 766da7b98..1f3251fd2 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
@@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
for (int j = 0; j < uninlinedArgs.Length; j++)
{
var arg = copiedExpr.Children[j];
- var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode());
+ var type = context.TypeSystem.FindType(arg.ResultType);
uninlinedArgs[j] = new ILVariable(VariableKind.StackSlot, type, arg.ResultType) {
Name = "C_" + arg.StartILOffset,
HasGeneratedName = true,
diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILExtraction.cs b/ICSharpCode.Decompiler/IL/Transforms/ILExtraction.cs
index 5840dffe1..55582a852 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/ILExtraction.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/ILExtraction.cs
@@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
FlagsBeingMoved |= predecessor.Flags;
MoveActions.Add(delegate {
- var type = context.TypeSystem.FindType(predecessor.ResultType.ToKnownTypeCode());
+ var type = context.TypeSystem.FindType(predecessor.ResultType);
var v = Function.RegisterVariable(VariableKind.StackSlot, type);
predecessor.ReplaceWith(new LdLoc(v));
return new StLoc(v, predecessor);
@@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
// We've reached the target block, and extraction is possible all the way.
int insertIndex = inst.ChildIndex;
- var type = context.TypeSystem.FindType(instToExtract.ResultType.ToKnownTypeCode());
+ var type = context.TypeSystem.FindType(instToExtract.ResultType);
// Move instToExtract itself:
var v = function.RegisterVariable(VariableKind.StackSlot, type);
instToExtract.ReplaceWith(new LdLoc(v));
diff --git a/ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs
index 39bbfd425..d2c5c400c 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs
@@ -87,7 +87,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
var call = (CallInstruction)arg.Parent;
Debug.Assert(context.Function == call.Ancestors.OfType().First());
- var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode());
+ var type = context.TypeSystem.FindType(arg.ResultType);
var v = context.Function.RegisterVariable(VariableKind.NamedArgument, type);
context.Step($"Introduce named argument '{v.Name}'", arg);
if (!(call.Parent is Block namedArgBlock) || namedArgBlock.Kind != BlockKind.CallWithNamedArgs)
diff --git a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
index 835c91d67..44f73e3e4 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
@@ -712,7 +712,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!MatchNullableCtor(trueInst, out var utype, out var exprToLift))
{
isNullCoalescingWithNonNullableFallback = true;
- utype = context.TypeSystem.FindType(trueInst.ResultType.ToKnownTypeCode());
+ utype = context.TypeSystem.FindType(trueInst.ResultType);
exprToLift = trueInst;
if (nullableVars.Count == 1 && exprToLift.MatchLdLoc(nullableVars[0]))
{
diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
index aae66c064..2ce7b2b62 100644
--- a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
@@ -102,11 +102,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
// C# 9 attributes:
NativeInteger,
+ PreserveBaseOverrides,
}
static class KnownAttributes
{
- internal const int Count = (int)KnownAttribute.NativeInteger + 1;
+ internal const int Count = (int)KnownAttribute.PreserveBaseOverrides + 1;
static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{
default,
@@ -167,6 +168,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Security.Permissions", "PermissionSetAttribute"),
// C# 9 attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "NativeIntegerAttribute"),
+ new TopLevelTypeName("System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute"),
};
public static ref readonly TopLevelTypeName GetTypeName(this KnownAttribute attr)
diff --git a/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs b/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs
index 4898ee5e1..df8e396f1 100644
--- a/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs
@@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.TypeSystem
@@ -66,6 +67,19 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
return type.ToTypeReference().Resolve(new SimpleTypeResolveContext(compilation));
}
+
+ public static IType FindType(this ICompilation compilation, StackType stackType, Sign sign = Sign.None)
+ {
+ switch (stackType)
+ {
+ case StackType.Unknown:
+ return SpecialType.UnknownType;
+ case StackType.Ref:
+ return new ByReferenceType(SpecialType.UnknownType);
+ default:
+ return compilation.FindType(stackType.ToKnownTypeCode(sign));
+ }
+ }
#endregion
#region Type.ToTypeReference()
diff --git a/ICSharpCode.Decompiler/Util/CacheManager.cs b/ICSharpCode.Decompiler/Util/CacheManager.cs
index 2c3bae375..6ccb1e141 100644
--- a/ICSharpCode.Decompiler/Util/CacheManager.cs
+++ b/ICSharpCode.Decompiler/Util/CacheManager.cs
@@ -34,9 +34,9 @@ namespace ICSharpCode.Decompiler.Util
// There used to be a thread-local dictionary here, but I removed it as it was causing memory
// leaks in some use cases.
- public object GetShared(object key)
+ public object? GetShared(object key)
{
- object value;
+ object? value;
sharedDict.TryGetValue(key, out value);
return value;
}
diff --git a/ILSpy.AddIn/Commands/NuGetReferenceForILSpy.cs b/ILSpy.AddIn/Commands/NuGetReferenceForILSpy.cs
index 45b183c4b..bc61779f7 100644
--- a/ILSpy.AddIn/Commands/NuGetReferenceForILSpy.cs
+++ b/ILSpy.AddIn/Commands/NuGetReferenceForILSpy.cs
@@ -8,6 +8,8 @@ using EnvDTE;
using Microsoft.VisualStudio.Shell;
+using VSLangProj;
+
namespace ICSharpCode.ILSpy.AddIn.Commands
{
///
@@ -33,8 +35,8 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
if (itemData is ProjectItem projectItem)
{
- var properties = Utils.GetProperties(projectItem.Properties, "Type");
- if ((properties[0] as string) == "Package")
+ var properties = Utils.GetProperties(projectItem.Properties, "Type", "ExtenderCATID");
+ if (((properties[0] as string) == "Package") || ((properties[1] as string) == PrjBrowseObjectCATID.prjCATIDCSharpReferenceBrowseObject))
{
return new NuGetReferenceForILSpy(projectItem);
}
diff --git a/ILSpy.AddIn/Commands/OpenReferenceCommand.cs b/ILSpy.AddIn/Commands/OpenReferenceCommand.cs
index fd4a9dc82..953bc5a67 100644
--- a/ILSpy.AddIn/Commands/OpenReferenceCommand.cs
+++ b/ILSpy.AddIn/Commands/OpenReferenceCommand.cs
@@ -68,14 +68,6 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
return;
}
- // Handle NuGet references
- var nugetRefItem = NuGetReferenceForILSpy.Detect(itemObject);
- if (nugetRefItem != null)
- {
- OpenAssembliesInILSpy(nugetRefItem.GetILSpyParameters());
- return;
- }
-
// Handle project references
var projectRefItem = ProjectReferenceForILSpy.Detect(itemObject);
if (projectRefItem != null)
@@ -96,6 +88,14 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
OpenAssembliesInILSpy(projectRefItem.GetILSpyParameters());
return;
}
+
+ // Handle NuGet references
+ var nugetRefItem = NuGetReferenceForILSpy.Detect(itemObject);
+ if (nugetRefItem != null)
+ {
+ OpenAssembliesInILSpy(nugetRefItem.GetILSpyParameters());
+ return;
+ }
}
internal static void Register(ILSpyAddInPackage owner)
diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj
index dd5da5176..af12ddabc 100644
--- a/ILSpy.AddIn/ILSpy.AddIn.csproj
+++ b/ILSpy.AddIn/ILSpy.AddIn.csproj
@@ -48,7 +48,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -165,6 +165,12 @@
Designer
+
+ Designer
+
+
+ Designer
+
true
Always
@@ -203,6 +209,8 @@
true
+ false
+ true
diff --git a/ILSpy.AddIn/ILSpyAddIn.en-US.vsct b/ILSpy.AddIn/ILSpyAddIn.en-US.vsct
index a6a3c6947..e52c29d25 100644
--- a/ILSpy.AddIn/ILSpyAddIn.en-US.vsct
+++ b/ILSpy.AddIn/ILSpyAddIn.en-US.vsct
@@ -56,7 +56,7 @@
Open in ILSpy
-
+
-
-
-
-
-
diff --git a/ILSpy.AddIn/ILSpyAddIn.vsct b/ILSpy.AddIn/ILSpyAddIn.vsct
index 3d992eae7..b95259168 100644
--- a/ILSpy.AddIn/ILSpyAddIn.vsct
+++ b/ILSpy.AddIn/ILSpyAddIn.vsct
@@ -64,6 +64,14 @@
+
+
+
+
+
+
+
+
@@ -75,6 +83,8 @@
+
+
@@ -89,6 +99,11 @@
+
+
+
+
+
diff --git a/ILSpy.AddIn/ILSpyAddIn.zh-Hans.vsct b/ILSpy.AddIn/ILSpyAddIn.zh-Hans.vsct
index d50bfb062..406299119 100644
--- a/ILSpy.AddIn/ILSpyAddIn.zh-Hans.vsct
+++ b/ILSpy.AddIn/ILSpyAddIn.zh-Hans.vsct
@@ -34,7 +34,7 @@
group; your package should define its own command set in order to avoid collisions
with command ids defined by other packages. -->
-
+
@@ -84,9 +84,9 @@
ILSpy
-
+
-
+
diff --git a/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs b/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs
index 7728ede9d..f57910e9f 100644
--- a/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs
+++ b/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs
@@ -168,7 +168,11 @@ namespace ILSpy.BamlDecompiler.Tests
var res = module.Resources.First();
Stream bamlStream = LoadBaml(res, name + ".baml");
Assert.IsNotNull(bamlStream);
- XDocument document = BamlResourceEntryNode.LoadIntoDocument(module, resolver, bamlStream, CancellationToken.None);
+
+ BamlDecompilerTypeSystem typeSystem = new BamlDecompilerTypeSystem(module, resolver);
+ var decompiler = new XamlDecompiler(typeSystem, new BamlDecompilerSettings());
+
+ XDocument document = decompiler.Decompile(bamlStream).Xaml;
XamlIsEqual(File.ReadAllText(sourcePath), document.ToString());
}
diff --git a/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj
index c31e409d6..986e28d29 100644
--- a/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj
+++ b/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj
@@ -40,6 +40,7 @@
+
diff --git a/ILSpy.BamlDecompiler/BamlDecompilationResult.cs b/ILSpy.BamlDecompiler/BamlDecompilationResult.cs
new file mode 100644
index 000000000..f76d86d9e
--- /dev/null
+++ b/ILSpy.BamlDecompiler/BamlDecompilationResult.cs
@@ -0,0 +1,36 @@
+// Copyright (c) 2021 Siegfried Pammer
+//
+// 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.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace ILSpy.BamlDecompiler
+{
+ public class BamlDecompilationResult
+ {
+ public XDocument Xaml { get; }
+ public List AssemblyReferences { get; }
+
+ public BamlDecompilationResult(XDocument xaml, IEnumerable assemblyReferences)
+ {
+ this.Xaml = xaml;
+ this.AssemblyReferences = assemblyReferences.ToList();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy.BamlDecompiler/BamlDecompilerSettings.cs b/ILSpy.BamlDecompiler/BamlDecompilerSettings.cs
new file mode 100644
index 000000000..464298ad0
--- /dev/null
+++ b/ILSpy.BamlDecompiler/BamlDecompilerSettings.cs
@@ -0,0 +1,50 @@
+// Copyright (c) 2021 Siegfried Pammer
+//
+// 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.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace ILSpy.BamlDecompiler
+{
+ public class BamlDecompilerSettings : INotifyPropertyChanged
+ {
+ bool throwOnAssemblyResolveErrors = true;
+
+ [Browsable(false)]
+ public bool ThrowOnAssemblyResolveErrors {
+ get { return throwOnAssemblyResolveErrors; }
+ set {
+ if (throwOnAssemblyResolveErrors != value)
+ {
+ throwOnAssemblyResolveErrors = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy.BamlDecompiler/BamlDecompilerTypeSystem.cs b/ILSpy.BamlDecompiler/BamlDecompilerTypeSystem.cs
new file mode 100644
index 000000000..f43a2d28c
--- /dev/null
+++ b/ILSpy.BamlDecompiler/BamlDecompilerTypeSystem.cs
@@ -0,0 +1,144 @@
+// Copyright (c) 2021 Siegfried Pammer
+//
+// 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;
+using System.Linq;
+using System.Reflection.Metadata;
+
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.Decompiler.TypeSystem.Implementation;
+using ICSharpCode.Decompiler.Util;
+
+namespace ILSpy.BamlDecompiler
+{
+ class BamlDecompilerTypeSystem : SimpleCompilation, IDecompilerTypeSystem
+ {
+ string[] defaultBamlReferences = new[] {
+ "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
+ "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
+ "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
+ "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
+ "PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
+ "PresentationUI, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
+ "System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
+ };
+
+ public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
+ {
+ if (mainModule == null)
+ throw new ArgumentNullException(nameof(mainModule));
+ if (assemblyResolver == null)
+ throw new ArgumentNullException(nameof(assemblyResolver));
+ // Load referenced assemblies and type-forwarder references.
+ // This is necessary to make .NET Core/PCL binaries work better.
+ var referencedAssemblies = new List();
+ var assemblyReferenceQueue = new Queue<(bool IsAssembly, PEFile MainModule, object Reference)>();
+ var mainMetadata = mainModule.Metadata;
+ foreach (var h in mainMetadata.GetModuleReferences())
+ {
+ var moduleRef = mainMetadata.GetModuleReference(h);
+ var moduleName = mainMetadata.GetString(moduleRef.Name);
+ foreach (var fileHandle in mainMetadata.AssemblyFiles)
+ {
+ var file = mainMetadata.GetAssemblyFile(fileHandle);
+ if (mainMetadata.StringComparer.Equals(file.Name, moduleName) && file.ContainsMetadata)
+ {
+ assemblyReferenceQueue.Enqueue((false, mainModule, moduleName));
+ break;
+ }
+ }
+ }
+ foreach (var refs in mainModule.AssemblyReferences)
+ {
+ assemblyReferenceQueue.Enqueue((true, mainModule, refs));
+ }
+ foreach (var bamlReference in defaultBamlReferences)
+ {
+ assemblyReferenceQueue.Enqueue((true, mainModule, AssemblyNameReference.Parse(bamlReference)));
+ }
+ var comparer = KeyComparer.Create(((bool IsAssembly, PEFile MainModule, object Reference) reference) =>
+ reference.IsAssembly ? "A:" + ((IAssemblyReference)reference.Reference).FullName :
+ "M:" + reference.Reference);
+ var processedAssemblyReferences = new HashSet<(bool IsAssembly, PEFile Parent, object Reference)>(comparer);
+ while (assemblyReferenceQueue.Count > 0)
+ {
+ var asmRef = assemblyReferenceQueue.Dequeue();
+ if (!processedAssemblyReferences.Add(asmRef))
+ continue;
+ PEFile asm;
+ if (asmRef.IsAssembly)
+ {
+ asm = assemblyResolver.Resolve((IAssemblyReference)asmRef.Reference);
+ }
+ else
+ {
+ asm = assemblyResolver.ResolveModule(asmRef.MainModule, (string)asmRef.Reference);
+ }
+ if (asm != null)
+ {
+ referencedAssemblies.Add(asm);
+ var metadata = asm.Metadata;
+ foreach (var h in metadata.ExportedTypes)
+ {
+ var exportedType = metadata.GetExportedType(h);
+ switch (exportedType.Implementation.Kind)
+ {
+ case HandleKind.AssemblyReference:
+ assemblyReferenceQueue.Enqueue((true, asm, new ICSharpCode.Decompiler.Metadata.AssemblyReference(asm, (AssemblyReferenceHandle)exportedType.Implementation)));
+ break;
+ case HandleKind.AssemblyFile:
+ var file = metadata.GetAssemblyFile((AssemblyFileHandle)exportedType.Implementation);
+ assemblyReferenceQueue.Enqueue((false, asm, metadata.GetString(file.Name)));
+ break;
+ }
+ }
+ }
+ }
+ var mainModuleWithOptions = mainModule.WithOptions(TypeSystemOptions.Default);
+ var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(TypeSystemOptions.Default));
+ // Primitive types are necessary to avoid assertions in ILReader.
+ // Fallback to MinimalCorlib to provide the primitive types.
+ if (!HasType(KnownTypeCode.Void) || !HasType(KnownTypeCode.Int32))
+ {
+ Init(mainModule.WithOptions(TypeSystemOptions.Default), referencedAssembliesWithOptions.Concat(new[] { MinimalCorlib.Instance }));
+ }
+ else
+ {
+ Init(mainModuleWithOptions, referencedAssembliesWithOptions);
+ }
+ this.MainModule = (MetadataModule)base.MainModule;
+
+ bool HasType(KnownTypeCode code)
+ {
+ TopLevelTypeName name = KnownTypeReference.Get(code).TypeName;
+ if (!mainModule.GetTypeDefinition(name).IsNil)
+ return true;
+ foreach (var file in referencedAssemblies)
+ {
+ if (!file.GetTypeDefinition(name).IsNil)
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public new MetadataModule MainModule { get; }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
index bbb4ddbc8..4c9a93cf8 100644
--- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
+++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
@@ -17,27 +17,17 @@
// DEALINGS IN THE SOFTWARE.
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Highlighting;
-using ICSharpCode.Decompiler.Metadata;
-using ICSharpCode.Decompiler.TypeSystem;
-using ICSharpCode.Decompiler.TypeSystem.Implementation;
-using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
-using ILSpy.BamlDecompiler.Baml;
-
-using SRM = System.Reflection.Metadata;
-
namespace ILSpy.BamlDecompiler
{
public sealed class BamlResourceEntryNode : ResourceEntryNode
@@ -75,131 +65,11 @@ namespace ILSpy.BamlDecompiler
{
var asm = this.Ancestors().OfType().First().LoadedAssembly;
using var data = OpenStream();
- XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), asm.GetAssemblyResolver(), data, cancellationToken);
- output.Write(xamlDocument.ToString());
- }
-
- internal static XDocument LoadIntoDocument(PEFile module, IAssemblyResolver assemblyResolver,
- Stream stream, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
- var document = BamlReader.ReadDocument(stream, cancellationToken);
- var xaml = new XamlDecompiler().Decompile(new BamlDecompilerTypeSystem(module, assemblyResolver), document, cancellationToken, new BamlDecompilerOptions(), null);
- return xaml;
- }
-
- class BamlDecompilerTypeSystem : SimpleCompilation, IDecompilerTypeSystem
- {
- string[] defaultBamlReferences = new[] {
- "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
- "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
- "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
- "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
- "PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
- "PresentationUI, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
- "System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
- };
-
- public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
- {
- if (mainModule == null)
- throw new ArgumentNullException(nameof(mainModule));
- if (assemblyResolver == null)
- throw new ArgumentNullException(nameof(assemblyResolver));
- // Load referenced assemblies and type-forwarder references.
- // This is necessary to make .NET Core/PCL binaries work better.
- var referencedAssemblies = new List();
- var assemblyReferenceQueue = new Queue<(bool IsAssembly, PEFile MainModule, object Reference)>();
- var mainMetadata = mainModule.Metadata;
- foreach (var h in mainMetadata.GetModuleReferences())
- {
- var moduleRef = mainMetadata.GetModuleReference(h);
- var moduleName = mainMetadata.GetString(moduleRef.Name);
- foreach (var fileHandle in mainMetadata.AssemblyFiles)
- {
- var file = mainMetadata.GetAssemblyFile(fileHandle);
- if (mainMetadata.StringComparer.Equals(file.Name, moduleName) && file.ContainsMetadata)
- {
- assemblyReferenceQueue.Enqueue((false, mainModule, moduleName));
- break;
- }
- }
- }
- foreach (var refs in mainModule.AssemblyReferences)
- {
- assemblyReferenceQueue.Enqueue((true, mainModule, refs));
- }
- foreach (var bamlReference in defaultBamlReferences)
- {
- assemblyReferenceQueue.Enqueue((true, mainModule, AssemblyNameReference.Parse(bamlReference)));
- }
- var comparer = KeyComparer.Create(((bool IsAssembly, PEFile MainModule, object Reference) reference) =>
- reference.IsAssembly ? "A:" + ((IAssemblyReference)reference.Reference).FullName :
- "M:" + reference.Reference);
- var processedAssemblyReferences = new HashSet<(bool IsAssembly, PEFile Parent, object Reference)>(comparer);
- while (assemblyReferenceQueue.Count > 0)
- {
- var asmRef = assemblyReferenceQueue.Dequeue();
- if (!processedAssemblyReferences.Add(asmRef))
- continue;
- PEFile asm;
- if (asmRef.IsAssembly)
- {
- asm = assemblyResolver.Resolve((IAssemblyReference)asmRef.Reference);
- }
- else
- {
- asm = assemblyResolver.ResolveModule(asmRef.MainModule, (string)asmRef.Reference);
- }
- if (asm != null)
- {
- referencedAssemblies.Add(asm);
- var metadata = asm.Metadata;
- foreach (var h in metadata.ExportedTypes)
- {
- var exportedType = metadata.GetExportedType(h);
- switch (exportedType.Implementation.Kind)
- {
- case SRM.HandleKind.AssemblyReference:
- assemblyReferenceQueue.Enqueue((true, asm, new AssemblyReference(asm, (SRM.AssemblyReferenceHandle)exportedType.Implementation)));
- break;
- case SRM.HandleKind.AssemblyFile:
- var file = metadata.GetAssemblyFile((SRM.AssemblyFileHandle)exportedType.Implementation);
- assemblyReferenceQueue.Enqueue((false, asm, metadata.GetString(file.Name)));
- break;
- }
- }
- }
- }
- var mainModuleWithOptions = mainModule.WithOptions(TypeSystemOptions.Default);
- var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(TypeSystemOptions.Default));
- // Primitive types are necessary to avoid assertions in ILReader.
- // Fallback to MinimalCorlib to provide the primitive types.
- if (!HasType(KnownTypeCode.Void) || !HasType(KnownTypeCode.Int32))
- {
- Init(mainModule.WithOptions(TypeSystemOptions.Default), referencedAssembliesWithOptions.Concat(new[] { MinimalCorlib.Instance }));
- }
- else
- {
- Init(mainModuleWithOptions, referencedAssembliesWithOptions);
- }
- this.MainModule = (MetadataModule)base.MainModule;
-
- bool HasType(KnownTypeCode code)
- {
- TopLevelTypeName name = KnownTypeReference.Get(code).TypeName;
- if (mainModule.GetTypeDefinition(name) != null)
- return true;
- foreach (var file in referencedAssemblies)
- {
- if (file.GetTypeDefinition(name) != null)
- return true;
- }
- return false;
- }
- }
-
- public new MetadataModule MainModule { get; }
+ BamlDecompilerTypeSystem typeSystem = new BamlDecompilerTypeSystem(asm.GetPEFileOrNull(), asm.GetAssemblyResolver());
+ var decompiler = new XamlDecompiler(typeSystem, new BamlDecompilerSettings());
+ decompiler.CancellationToken = cancellationToken;
+ var result = decompiler.Decompile(data);
+ output.Write(result.Xaml.ToString());
}
}
}
diff --git a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
index 107949a3a..f2c0b375c 100644
--- a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
+++ b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
@@ -46,9 +46,14 @@ namespace ILSpy.BamlDecompiler
public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options)
{
- var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetPEFileOrNull(), assembly.GetAssemblyResolver(), stream, options.CancellationToken);
+ BamlDecompilerTypeSystem typeSystem = new BamlDecompilerTypeSystem(assembly.GetPEFileOrNull(), assembly.GetAssemblyResolver());
+ var decompiler = new XamlDecompiler(typeSystem, new BamlDecompilerSettings() {
+ ThrowOnAssemblyResolveErrors = options.DecompilerSettings.ThrowOnAssemblyResolveErrors
+ });
+ decompiler.CancellationToken = options.CancellationToken;
fileName = Path.ChangeExtension(fileName, ".xaml");
- document.Save(Path.Combine(options.SaveAsProjectDirectory, fileName));
+ var result = decompiler.Decompile(stream);
+ result.Xaml.Save(Path.Combine(options.SaveAsProjectDirectory, fileName));
return fileName;
}
}
diff --git a/ILSpy.BamlDecompiler/XamlContext.cs b/ILSpy.BamlDecompiler/XamlContext.cs
index 4b281bac3..31c010986 100644
--- a/ILSpy.BamlDecompiler/XamlContext.cs
+++ b/ILSpy.BamlDecompiler/XamlContext.cs
@@ -48,7 +48,7 @@ namespace ILSpy.BamlDecompiler
public IDecompilerTypeSystem TypeSystem { get; }
public CancellationToken CancellationToken { get; private set; }
- public BamlDecompilerOptions BamlDecompilerOptions { get; private set; }
+ public BamlDecompilerSettings Settings { get; private set; }
public BamlContext Baml { get; private set; }
public BamlNode RootNode { get; private set; }
@@ -56,11 +56,11 @@ namespace ILSpy.BamlDecompiler
public XmlnsDictionary XmlNs { get; }
- public static XamlContext Construct(IDecompilerTypeSystem typeSystem, BamlDocument document, CancellationToken token, BamlDecompilerOptions bamlDecompilerOptions)
+ public static XamlContext Construct(IDecompilerTypeSystem typeSystem, BamlDocument document, CancellationToken token, BamlDecompilerSettings bamlDecompilerOptions)
{
var ctx = new XamlContext(typeSystem);
ctx.CancellationToken = token;
- ctx.BamlDecompilerOptions = bamlDecompilerOptions ?? new BamlDecompilerOptions();
+ ctx.Settings = bamlDecompilerOptions ?? new BamlDecompilerSettings();
ctx.Baml = BamlContext.ConstructContext(typeSystem, document, token);
ctx.RootNode = BamlNode.Parse(document, token);
diff --git a/ILSpy.BamlDecompiler/XamlDecompiler.cs b/ILSpy.BamlDecompiler/XamlDecompiler.cs
index dafe597f6..84dc908ef 100644
--- a/ILSpy.BamlDecompiler/XamlDecompiler.cs
+++ b/ILSpy.BamlDecompiler/XamlDecompiler.cs
@@ -20,11 +20,15 @@
THE SOFTWARE.
*/
-using System.Collections.Generic;
+using System;
+using System.IO;
using System.Linq;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
using System.Threading;
using System.Xml.Linq;
+using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ILSpy.BamlDecompiler.Baml;
@@ -32,7 +36,7 @@ using ILSpy.BamlDecompiler.Rewrite;
namespace ILSpy.BamlDecompiler
{
- internal class XamlDecompiler
+ public class XamlDecompiler
{
static readonly IRewritePass[] rewritePasses = new IRewritePass[] {
new XClassRewritePass(),
@@ -42,9 +46,66 @@ namespace ILSpy.BamlDecompiler
new DocumentRewritePass(),
};
- public XDocument Decompile(IDecompilerTypeSystem typeSystem, BamlDocument document, CancellationToken token, BamlDecompilerOptions bamlDecompilerOptions, List assemblyReferences)
+ private BamlDecompilerTypeSystem typeSystem;
+ private BamlDecompilerSettings settings;
+ private MetadataModule module;
+
+ public BamlDecompilerSettings Settings {
+ get { return settings; }
+ set { settings = value; }
+ }
+
+ public CancellationToken CancellationToken { get; set; }
+
+ public XamlDecompiler(string fileName, BamlDecompilerSettings settings)
+ : this(CreateTypeSystemFromFile(fileName, settings), settings)
+ {
+ }
+
+ public XamlDecompiler(string fileName, IAssemblyResolver assemblyResolver, BamlDecompilerSettings settings)
+ : this(LoadPEFile(fileName, settings), assemblyResolver, settings)
+ {
+ }
+
+ public XamlDecompiler(PEFile module, IAssemblyResolver assemblyResolver, BamlDecompilerSettings settings)
+ : this(new BamlDecompilerTypeSystem(module, assemblyResolver), settings)
+ {
+ }
+
+ internal XamlDecompiler(BamlDecompilerTypeSystem typeSystem, BamlDecompilerSettings settings)
{
- var ctx = XamlContext.Construct(typeSystem, document, token, bamlDecompilerOptions);
+ this.typeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem));
+ this.settings = settings;
+ this.module = typeSystem.MainModule;
+ if (module.TypeSystemOptions.HasFlag(TypeSystemOptions.Uncached))
+ throw new ArgumentException("Cannot use an uncached type system in the decompiler.");
+ }
+
+ static PEFile LoadPEFile(string fileName, BamlDecompilerSettings settings)
+ {
+ return new PEFile(
+ fileName,
+ new FileStream(fileName, FileMode.Open, FileAccess.Read),
+ streamOptions: PEStreamOptions.PrefetchEntireImage,
+ metadataOptions: MetadataReaderOptions.None
+ );
+ }
+
+ static BamlDecompilerTypeSystem CreateTypeSystemFromFile(string fileName, BamlDecompilerSettings settings)
+ {
+ var file = LoadPEFile(fileName, settings);
+ var resolver = new UniversalAssemblyResolver(fileName, settings.ThrowOnAssemblyResolveErrors,
+ file.DetectTargetFrameworkId(), file.DetectRuntimePack(),
+ PEStreamOptions.PrefetchMetadata,
+ MetadataReaderOptions.None);
+ return new BamlDecompilerTypeSystem(file, resolver);
+ }
+
+ public BamlDecompilationResult Decompile(Stream stream)
+ {
+ var ct = CancellationToken;
+ var document = BamlReader.ReadDocument(stream, ct);
+ var ctx = XamlContext.Construct(typeSystem, document, ct, settings);
var handler = HandlerMap.LookupHandler(ctx.RootNode.Type);
var elem = handler.Translate(ctx, ctx.RootNode, null);
@@ -54,18 +115,12 @@ namespace ILSpy.BamlDecompiler
foreach (var pass in rewritePasses)
{
- token.ThrowIfCancellationRequested();
+ ct.ThrowIfCancellationRequested();
pass.Run(ctx, xaml);
}
- if (assemblyReferences != null)
- assemblyReferences.AddRange(ctx.Baml.AssemblyIdMap.Select(a => a.Value.AssemblyFullName));
-
- return xaml;
+ var assemblyReferences = ctx.Baml.AssemblyIdMap.Select(a => a.Value.AssemblyFullName);
+ return new BamlDecompilationResult(xaml, assemblyReferences);
}
}
-
- public class BamlDecompilerOptions
- {
- }
}
\ No newline at end of file
diff --git a/ILSpy.Package/ILSpy.Package.wapproj b/ILSpy.Package/ILSpy.Package.wapproj
index 24d162a0d..f4b80e71b 100644
--- a/ILSpy.Package/ILSpy.Package.wapproj
+++ b/ILSpy.Package/ILSpy.Package.wapproj
@@ -75,5 +75,10 @@
+
+
+ PreserveNewest
+
+
\ No newline at end of file
diff --git a/ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj b/ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
index 86d29d632..ebfd1b301 100644
--- a/ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
+++ b/ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
@@ -38,8 +38,8 @@
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
- PerMonitorV2, PerMonitor
- True
-
-
- true
-
-
+
+
+
+ PerMonitorV2, PerMonitor
+ True
-
-
-
-
+ True
+
+
+
+
+
+
+
-
-
+
+
diff --git a/SharpTreeView/ICSharpCode.TreeView.csproj b/SharpTreeView/ICSharpCode.TreeView.csproj
index 8b9158e43..5cec02258 100644
--- a/SharpTreeView/ICSharpCode.TreeView.csproj
+++ b/SharpTreeView/ICSharpCode.TreeView.csproj
@@ -23,8 +23,10 @@
true
+
+
-
+
diff --git a/doc/third-party-notices.txt b/doc/third-party-notices.txt
index 39961ecc9..3f54b3b86 100644
--- a/doc/third-party-notices.txt
+++ b/doc/third-party-notices.txt
@@ -415,6 +415,34 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+License Notice for K4os.Compression.LZ4 (part of ILSpy)
+---------------------------
+
+https://github.com/MiloszKrajewski/K4os.Compression.LZ4/blob/master/LICENSE
+
+MIT License
+
+Copyright (c) 2017 Milosz Krajewski
+
+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.
+
+
License Notice for LightJson (part of ICSharpCode.Decompiler)
---------------------------
diff --git a/packages.props b/packages.props
index e6a52a39c..c6daebed2 100644
--- a/packages.props
+++ b/packages.props
@@ -11,11 +11,13 @@
5.0.1
5.0.0
3.11.0-1.final
- 0.11.3
+ 0.11.4
6.1.1
- 3.12.0
- 3.13.0
- 4.14.1
+ 2.6.1
+ 3.13.2
+ 4.0.0
+ 16.11.0
+ 4.16.1
2017.7.26.1241
1.1.0-beta2-20115-01