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