Browse Source

Merge branch 'nullable'

pull/2447/head
Daniel Grunwald 5 years ago
parent
commit
544d9bb217
  1. 2
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
  3. 143
      ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs
  4. 3
      ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs
  5. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ArrayCreateExpression.cs
  6. 8
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs
  7. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/SwitchExpression.cs
  8. 3
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/PreProcessorDirective.cs
  9. 12
      ICSharpCode.Decompiler/CSharp/Syntax/Role.cs
  10. 14
      ICSharpCode.Decompiler/CSharp/Syntax/Roles.cs
  11. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/LocalFunctionDeclarationStatement.cs
  12. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/SwitchStatement.cs
  13. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EntityDeclaration.cs
  14. 3
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedFieldDeclaration.cs
  15. 7
      ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs
  16. 5
      ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs
  17. 7
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  18. 20
      ICSharpCode.Decompiler/IL/ILVariable.cs
  19. 3
      ICSharpCode.Decompiler/IL/InstructionFlags.cs
  20. 3
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
  21. 508
      ICSharpCode.Decompiler/IL/Instructions.cs
  22. 85
      ICSharpCode.Decompiler/IL/Instructions.tt
  23. 7
      ICSharpCode.Decompiler/IL/Instructions/Await.cs
  24. 5
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  25. 47
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  26. 32
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  27. 25
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  28. 5
      ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
  29. 15
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  30. 6
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs
  31. 5
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  32. 3
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  33. 13
      ICSharpCode.Decompiler/IL/Instructions/DeconstructResultInstruction.cs
  34. 3
      ICSharpCode.Decompiler/IL/Instructions/DefaultValue.cs
  35. 43
      ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs
  36. 7
      ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs
  37. 39
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  38. 22
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  39. 5
      ICSharpCode.Decompiler/IL/Instructions/ILVariableCollection.cs
  40. 9
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  41. 3
      ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs
  42. 3
      ICSharpCode.Decompiler/IL/Instructions/LdLen.cs
  43. 13
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  44. 3
      ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
  45. 3
      ICSharpCode.Decompiler/IL/Instructions/LogicInstructions.cs
  46. 30
      ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs
  47. 3
      ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs
  48. 3
      ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs
  49. 3
      ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs
  50. 75
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  51. 13
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  52. 7
      ICSharpCode.Decompiler/IL/Instructions/StLoc.cs
  53. 13
      ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs
  54. 4
      ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs
  55. 11
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  56. 3
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  57. 3
      ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs
  58. 16
      ICSharpCode.Decompiler/IL/Patterns/AnyNode.cs
  59. 13
      ICSharpCode.Decompiler/IL/Patterns/ListMatch.cs
  60. 5
      ICSharpCode.Decompiler/IL/Patterns/Match.cs
  61. 3
      ICSharpCode.Decompiler/IL/PrimitiveType.cs
  62. 4
      ICSharpCode.Decompiler/IL/SemanticHelper.cs
  63. 1
      ICSharpCode.Decompiler/IL/SlotInfo.cs
  64. 1
      ICSharpCode.Decompiler/IL/StackType.cs
  65. 3
      ICSharpCode.Decompiler/IL/Transforms/FixLoneIsInst.cs
  66. 3
      ICSharpCode.Decompiler/IL/Transforms/FixRemainingIncrements.cs
  67. 17
      ICSharpCode.Decompiler/IL/Transforms/ILExtraction.cs
  68. 8
      ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs
  69. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs
  70. 6
      ICSharpCode.Decompiler/TypeSystem/IMember.cs
  71. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/SyntheticRangeIndexer.cs
  72. 1
      ICSharpCode.Decompiler/Util/BitSet.cs
  73. 13
      ICSharpCode.Decompiler/Util/BusyManager.cs
  74. 2
      ICSharpCode.Decompiler/Util/CacheManager.cs
  75. 6
      ICSharpCode.Decompiler/Util/CallbackOnDispose.cs
  76. 35
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs
  77. 5
      ICSharpCode.Decompiler/Util/EmptyList.cs
  78. 5
      ICSharpCode.Decompiler/Util/ExtensionMethods.cs
  79. 24
      ICSharpCode.Decompiler/Util/FileUtility.cs
  80. 26
      ICSharpCode.Decompiler/Util/GraphVizGraph.cs
  81. 7
      ICSharpCode.Decompiler/Util/Interval.cs
  82. 3
      ICSharpCode.Decompiler/Util/KeyComparer.cs
  83. 7
      ICSharpCode.Decompiler/Util/LongSet.cs
  84. 5
      ICSharpCode.Decompiler/Util/MultiDictionary.cs
  85. 8
      ICSharpCode.Decompiler/Util/NullAttributes.cs
  86. 3
      ICSharpCode.Decompiler/Util/Platform.cs
  87. 15
      ICSharpCode.Decompiler/Util/ProjectedList.cs
  88. 7
      ICSharpCode.Decompiler/Util/ReferenceComparer.cs
  89. 27
      ICSharpCode.Decompiler/Util/ResourcesFile.cs
  90. 15
      ICSharpCode.Decompiler/Util/TreeTraversal.cs
  91. 7
      ICSharpCode.Decompiler/Util/UnicodeNewline.cs
  92. 14
      ICSharpCode.Decompiler/Util/UnionFind.cs
  93. 23
      ICSharpCode.Decompiler/Util/Win32Resources.cs
  94. 4
      ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj

2
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -543,7 +543,7 @@ namespace ICSharpCode.Decompiler.CSharp
argumentList.Arguments.ToList(), argumentList.ArgumentNames); argumentList.Arguments.ToList(), argumentList.ArgumentNames);
if (((AssignmentExpression)assignment).Left is IndexerExpression indexer && !indexer.Target.IsNull) if (((AssignmentExpression)assignment).Left is IndexerExpression indexer && !indexer.Target.IsNull)
indexer.Target.ReplaceWith(n => null); indexer.Target.Remove();
if (value != null) if (value != null)
return assignment; return assignment;

4
ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs

@ -128,9 +128,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return null; } get { return null; }
} }
IType IEntity.DeclaringType { public IType DeclaringType => SpecialType.UnknownType;
get { return null; }
}
IMember IMember.MemberDefinition { IMember IMember.MemberDefinition {
get { return this; } get { return this; }

143
ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs

@ -1,4 +1,5 @@
// #nullable enable
//
// AstNode.cs // AstNode.cs
// //
// Author: // Author:
@ -39,7 +40,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public abstract class AstNode : AbstractAnnotatable, IFreezable, INode, ICloneable public abstract class AstNode : AbstractAnnotatable, IFreezable, INode, ICloneable
{ {
// the Root role must be available when creating the null nodes, so we can't put it in the Roles class // the Root role must be available when creating the null nodes, so we can't put it in the Roles class
internal static readonly Role<AstNode> RootRole = new Role<AstNode>("Root"); internal static readonly Role<AstNode?> RootRole = new Role<AstNode?>("Root", null);
#region Null #region Null
public static readonly AstNode Null = new NullAstNode(); public static readonly AstNode Null = new NullAstNode();
@ -73,7 +74,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return visitor.VisitNullNode(this, data); return visitor.VisitNullNode(this, data);
} }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode? other, PatternMatching.Match match)
{ {
return other == null || other.IsNull; return other == null || other.IsNull;
} }
@ -81,7 +82,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
#endregion #endregion
#region PatternPlaceholder #region PatternPlaceholder
public static implicit operator AstNode(PatternMatching.Pattern pattern) public static implicit operator AstNode?(PatternMatching.Pattern? pattern)
{ {
return pattern != null ? new PatternPlaceholder(pattern) : null; return pattern != null ? new PatternPlaceholder(pattern) : null;
} }
@ -114,23 +115,23 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return visitor.VisitPatternPlaceholder(this, child, data); return visitor.VisitPatternPlaceholder(this, child, data);
} }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode? other, PatternMatching.Match match)
{ {
return child.DoMatch(other, match); return child.DoMatch(other, match);
} }
bool PatternMatching.INode.DoMatchCollection(Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo) bool PatternMatching.INode.DoMatchCollection(Role? role, PatternMatching.INode? pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
{ {
return child.DoMatchCollection(role, pos, match, backtrackingInfo); return child.DoMatchCollection(role, pos, match, backtrackingInfo);
} }
} }
#endregion #endregion
AstNode parent; AstNode? parent;
AstNode prevSibling; AstNode? prevSibling;
AstNode nextSibling; AstNode? nextSibling;
AstNode firstChild; AstNode? firstChild;
AstNode lastChild; AstNode? lastChild;
// Flags, from least significant to most significant bits: // Flags, from least significant to most significant bits:
// - Role.RoleIndexBits: role index // - Role.RoleIndexBits: role index
@ -157,7 +158,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
if (!IsFrozen) if (!IsFrozen)
{ {
for (AstNode child = firstChild; child != null; child = child.nextSibling) for (AstNode? child = firstChild; child != null; child = child.nextSibling)
child.Freeze(); child.Freeze();
flags |= frozenBit; flags |= frozenBit;
} }
@ -197,7 +198,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
} }
public AstNode Parent { public AstNode? Parent {
get { return parent; } get { return parent; }
} }
@ -224,19 +225,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
flags = (flags & ~roleIndexMask) | role.Index; flags = (flags & ~roleIndexMask) | role.Index;
} }
public AstNode NextSibling { public AstNode? NextSibling {
get { return nextSibling; } get { return nextSibling; }
} }
public AstNode PrevSibling { public AstNode? PrevSibling {
get { return prevSibling; } get { return prevSibling; }
} }
public AstNode FirstChild { public AstNode? FirstChild {
get { return firstChild; } get { return firstChild; }
} }
public AstNode LastChild { public AstNode? LastChild {
get { return lastChild; } get { return lastChild; }
} }
@ -248,8 +249,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public IEnumerable<AstNode> Children { public IEnumerable<AstNode> Children {
get { get {
AstNode next; AstNode? next;
for (AstNode cur = firstChild; cur != null; cur = next) for (AstNode? cur = firstChild; cur != null; cur = next)
{ {
Debug.Assert(cur.parent == this); Debug.Assert(cur.parent == this);
// Remember next before yielding cur. // Remember next before yielding cur.
@ -265,7 +266,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
public IEnumerable<AstNode> Ancestors { public IEnumerable<AstNode> Ancestors {
get { get {
for (AstNode cur = parent; cur != null; cur = cur.parent) for (AstNode? cur = parent; cur != null; cur = cur.parent)
{ {
yield return cur; yield return cur;
} }
@ -277,7 +278,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
public IEnumerable<AstNode> AncestorsAndSelf { public IEnumerable<AstNode> AncestorsAndSelf {
get { get {
for (AstNode cur = this; cur != null; cur = cur.parent) for (AstNode? cur = this; cur != null; cur = cur.parent)
{ {
yield return cur; yield return cur;
} }
@ -298,18 +299,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return GetDescendantsImpl(true); } get { return GetDescendantsImpl(true); }
} }
public IEnumerable<AstNode> DescendantNodes(Func<AstNode, bool> descendIntoChildren = null) public IEnumerable<AstNode> DescendantNodes(Func<AstNode, bool>? descendIntoChildren = null)
{ {
return GetDescendantsImpl(false, descendIntoChildren); return GetDescendantsImpl(false, descendIntoChildren);
} }
public IEnumerable<AstNode> DescendantNodesAndSelf(Func<AstNode, bool> descendIntoChildren = null) public IEnumerable<AstNode> DescendantNodesAndSelf(Func<AstNode, bool>? descendIntoChildren = null)
{ {
return GetDescendantsImpl(true, descendIntoChildren); return GetDescendantsImpl(true, descendIntoChildren);
} }
IEnumerable<AstNode> GetDescendantsImpl(bool includeSelf, Func<AstNode, bool> descendIntoChildren = null) IEnumerable<AstNode> GetDescendantsImpl(bool includeSelf, Func<AstNode, bool>? descendIntoChildren = null)
{ {
if (includeSelf) if (includeSelf)
{ {
@ -318,9 +319,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
yield break; yield break;
} }
Stack<AstNode> nextStack = new Stack<AstNode>(); Stack<AstNode?> nextStack = new Stack<AstNode?>();
nextStack.Push(null); nextStack.Push(null);
AstNode pos = firstChild; AstNode? pos = firstChild;
while (pos != null) while (pos != null)
{ {
// Remember next before yielding pos. // Remember next before yielding pos.
@ -339,7 +340,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Gets the first child with the specified role. /// Gets the first child with the specified role.
/// Returns the role's null object if the child is not found. /// Returns the role's null object if the child is not found.
/// </summary> /// </summary>
public T GetChildByRole<T>(Role<T> role) where T : AstNode public T GetChildByRole<T>(Role<T> role) where T : AstNode?
{ {
if (role == null) if (role == null)
throw new ArgumentNullException(nameof(role)); throw new ArgumentNullException(nameof(role));
@ -352,12 +353,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return role.NullObject; return role.NullObject;
} }
public T GetParent<T>() where T : AstNode public T? GetParent<T>() where T : AstNode
{ {
return Ancestors.OfType<T>().FirstOrDefault(); return Ancestors.OfType<T>().FirstOrDefault();
} }
public AstNode GetParent(Func<AstNode, bool> pred) public AstNode GetParent(Func<AstNode, bool>? pred)
{ {
return Ancestors.FirstOrDefault(pred); return Ancestors.FirstOrDefault(pred);
} }
@ -392,7 +393,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
AddChildUnsafe(child, role); AddChildUnsafe(child, role);
} }
public void AddChildWithExistingRole(AstNode child) public void AddChildWithExistingRole(AstNode? child)
{ {
if (child == null || child.IsNull) if (child == null || child.IsNull)
return; return;
@ -419,13 +420,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
else else
{ {
lastChild.nextSibling = child; lastChild!.nextSibling = child;
child.prevSibling = lastChild; child.prevSibling = lastChild;
lastChild = child; lastChild = child;
} }
} }
public void InsertChildBefore<T>(AstNode nextSibling, T child, Role<T> role) where T : AstNode public void InsertChildBefore<T>(AstNode? nextSibling, T child, Role<T> role) where T : AstNode
{ {
if (role == null) if (role == null)
throw new ArgumentNullException(nameof(role)); throw new ArgumentNullException(nameof(role));
@ -469,7 +470,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
nextSibling.prevSibling = child; nextSibling.prevSibling = child;
} }
public void InsertChildAfter<T>(AstNode prevSibling, T child, Role<T> role) where T : AstNode public void InsertChildAfter<T>(AstNode? prevSibling, T child, Role<T> role) where T : AstNode
{ {
InsertChildBefore((prevSibling == null || prevSibling.IsNull) ? firstChild : prevSibling.nextSibling, child, role); InsertChildBefore((prevSibling == null || prevSibling.IsNull) ? firstChild : prevSibling.nextSibling, child, role);
} }
@ -511,7 +512,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <summary> /// <summary>
/// Replaces this node with the new node. /// Replaces this node with the new node.
/// </summary> /// </summary>
public void ReplaceWith(AstNode newNode) public void ReplaceWith(AstNode? newNode)
{ {
if (newNode == null || newNode.IsNull) if (newNode == null || newNode.IsNull)
{ {
@ -578,7 +579,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
nextSibling = null; nextSibling = null;
} }
public AstNode ReplaceWith(Func<AstNode, AstNode> replaceFunction) public AstNode? ReplaceWith(Func<AstNode, AstNode?> replaceFunction)
{ {
if (replaceFunction == null) if (replaceFunction == null)
throw new ArgumentNullException(nameof(replaceFunction)); throw new ArgumentNullException(nameof(replaceFunction));
@ -587,10 +588,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node"); throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node");
} }
AstNode oldParent = parent; AstNode oldParent = parent;
AstNode oldSuccessor = nextSibling; AstNode? oldSuccessor = nextSibling;
Role oldRole = this.Role; Role oldRole = this.Role;
Remove(); Remove();
AstNode replacement = replaceFunction(this); AstNode? replacement = replaceFunction(this);
if (oldSuccessor != null && oldSuccessor.parent != oldParent) if (oldSuccessor != null && oldSuccessor.parent != oldParent)
throw new InvalidOperationException("replace function changed nextSibling of node being replaced?"); throw new InvalidOperationException("replace function changed nextSibling of node being replaced?");
if (!(replacement == null || replacement.IsNull)) if (!(replacement == null || replacement.IsNull))
@ -626,7 +627,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
copy.flags &= ~frozenBit; // unfreeze the copy copy.flags &= ~frozenBit; // unfreeze the copy
// Then perform a deep copy: // Then perform a deep copy:
for (AstNode cur = firstChild; cur != null; cur = cur.nextSibling) for (AstNode? cur = firstChild; cur != null; cur = cur.nextSibling)
{ {
copy.AddChildUnsafe(cur.Clone(), cur.Role); copy.AddChildUnsafe(cur.Clone(), cur.Role);
} }
@ -649,37 +650,37 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public abstract S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data); public abstract S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data);
#region Pattern Matching #region Pattern Matching
protected static bool MatchString(string pattern, string text) protected static bool MatchString(string? pattern, string? text)
{ {
return PatternMatching.Pattern.MatchString(pattern, text); return PatternMatching.Pattern.MatchString(pattern, text);
} }
protected internal abstract bool DoMatch(AstNode other, PatternMatching.Match match); protected internal abstract bool DoMatch(AstNode? other, PatternMatching.Match match);
bool PatternMatching.INode.DoMatch(PatternMatching.INode other, PatternMatching.Match match) bool PatternMatching.INode.DoMatch(PatternMatching.INode? other, PatternMatching.Match match)
{ {
AstNode o = other as AstNode; AstNode? o = other as AstNode;
// try matching if other is null, or if other is an AstNode // try matching if other is null, or if other is an AstNode
return (other == null || o != null) && DoMatch(o, match); return (other == null || o != null) && DoMatch(o, match);
} }
bool PatternMatching.INode.DoMatchCollection(Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo) bool PatternMatching.INode.DoMatchCollection(Role? role, PatternMatching.INode? pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo? backtrackingInfo)
{ {
AstNode o = pos as AstNode; AstNode? o = pos as AstNode;
return (pos == null || o != null) && DoMatch(o, match); return (pos == null || o != null) && DoMatch(o, match);
} }
PatternMatching.INode PatternMatching.INode.NextSibling { PatternMatching.INode? PatternMatching.INode.NextSibling {
get { return nextSibling; } get { return nextSibling; }
} }
PatternMatching.INode PatternMatching.INode.FirstChild { PatternMatching.INode? PatternMatching.INode.FirstChild {
get { return firstChild; } get { return firstChild; }
} }
#endregion #endregion
public AstNode GetNextNode() public AstNode? GetNextNode()
{ {
if (NextSibling != null) if (NextSibling != null)
return NextSibling; return NextSibling;
@ -693,7 +694,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
/// <returns>The next node.</returns> /// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param> /// <param name="pred">The predicate.</param>
public AstNode GetNextNode(Func<AstNode, bool> pred) public AstNode? GetNextNode(Func<AstNode, bool> pred)
{ {
var next = GetNextNode(); var next = GetNextNode();
while (next != null && !pred(next)) while (next != null && !pred(next))
@ -701,7 +702,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return next; return next;
} }
public AstNode GetPrevNode() public AstNode? GetPrevNode()
{ {
if (PrevSibling != null) if (PrevSibling != null)
return PrevSibling; return PrevSibling;
@ -715,7 +716,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
/// <returns>The next node.</returns> /// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param> /// <param name="pred">The predicate.</param>
public AstNode GetPrevNode(Func<AstNode, bool> pred) public AstNode? GetPrevNode(Func<AstNode, bool> pred)
{ {
var prev = GetPrevNode(); var prev = GetPrevNode();
while (prev != null && !pred(prev)) while (prev != null && !pred(prev))
@ -723,7 +724,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return prev; return prev;
} }
// filters all non c# nodes (comments, white spaces or pre processor directives) // filters all non c# nodes (comments, white spaces or pre processor directives)
public AstNode GetCSharpNodeBefore(AstNode node) public AstNode? GetCSharpNodeBefore(AstNode node)
{ {
var n = node.PrevSibling; var n = node.PrevSibling;
while (n != null) while (n != null)
@ -740,7 +741,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
/// <returns>The next node.</returns> /// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param> /// <param name="pred">The predicate.</param>
public AstNode GetNextSibling(Func<AstNode, bool> pred) public AstNode? GetNextSibling(Func<AstNode, bool> pred)
{ {
var next = NextSibling; var next = NextSibling;
while (next != null && !pred(next)) while (next != null && !pred(next))
@ -753,7 +754,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
/// <returns>The next node.</returns> /// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param> /// <param name="pred">The predicate.</param>
public AstNode GetPrevSibling(Func<AstNode, bool> pred) public AstNode? GetPrevSibling(Func<AstNode, bool> pred)
{ {
var prev = PrevSibling; var prev = PrevSibling;
while (prev != null && !pred(prev)) while (prev != null && !pred(prev))
@ -767,7 +768,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End exclusive) /// (End exclusive)
/// </summary> /// </summary>
public AstNode GetNodeAt(int line, int column, Predicate<AstNode> pred = null) public AstNode? GetNodeAt(int line, int column, Predicate<AstNode>? pred = null)
{ {
return GetNodeAt(new TextLocation(line, column), pred); return GetNodeAt(new TextLocation(line, column), pred);
} }
@ -777,9 +778,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End exclusive) /// (End exclusive)
/// </summary> /// </summary>
public AstNode GetNodeAt(TextLocation location, Predicate<AstNode> pred = null) public AstNode? GetNodeAt(TextLocation location, Predicate<AstNode>? pred = null)
{ {
AstNode result = null; AstNode? result = null;
AstNode node = this; AstNode node = this;
while (node.LastChild != null) while (node.LastChild != null)
{ {
@ -806,7 +807,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End exclusive) /// (End exclusive)
/// </summary> /// </summary>
public T GetNodeAt<T>(int line, int column) where T : AstNode public T? GetNodeAt<T>(int line, int column) where T : AstNode
{ {
return GetNodeAt<T>(new TextLocation(line, column)); return GetNodeAt<T>(new TextLocation(line, column));
} }
@ -816,9 +817,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End exclusive) /// (End exclusive)
/// </summary> /// </summary>
public T GetNodeAt<T>(TextLocation location) where T : AstNode public T? GetNodeAt<T>(TextLocation location) where T : AstNode
{ {
T result = null; T? result = null;
AstNode node = this; AstNode node = this;
while (node.LastChild != null) while (node.LastChild != null)
{ {
@ -848,7 +849,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End inclusive) /// (End inclusive)
/// </summary> /// </summary>
public AstNode GetAdjacentNodeAt(int line, int column, Predicate<AstNode> pred = null) public AstNode? GetAdjacentNodeAt(int line, int column, Predicate<AstNode>? pred = null)
{ {
return GetAdjacentNodeAt(new TextLocation(line, column), pred); return GetAdjacentNodeAt(new TextLocation(line, column), pred);
} }
@ -858,9 +859,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End inclusive) /// (End inclusive)
/// </summary> /// </summary>
public AstNode GetAdjacentNodeAt(TextLocation location, Predicate<AstNode> pred = null) public AstNode? GetAdjacentNodeAt(TextLocation location, Predicate<AstNode>? pred = null)
{ {
AstNode result = null; AstNode? result = null;
AstNode node = this; AstNode node = this;
while (node.LastChild != null) while (node.LastChild != null)
{ {
@ -887,7 +888,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End inclusive) /// (End inclusive)
/// </summary> /// </summary>
public T GetAdjacentNodeAt<T>(int line, int column) where T : AstNode public T? GetAdjacentNodeAt<T>(int line, int column) where T : AstNode
{ {
return GetAdjacentNodeAt<T>(new TextLocation(line, column)); return GetAdjacentNodeAt<T>(new TextLocation(line, column));
} }
@ -897,9 +898,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration. /// the current method declaration.
/// (End inclusive) /// (End inclusive)
/// </summary> /// </summary>
public T GetAdjacentNodeAt<T>(TextLocation location) where T : AstNode public T? GetAdjacentNodeAt<T>(TextLocation location) where T : AstNode
{ {
T result = null; T? result = null;
AstNode node = this; AstNode node = this;
while (node.LastChild != null) while (node.LastChild != null)
{ {
@ -908,8 +909,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
child = child.prevSibling; child = child.prevSibling;
if (child != null && location <= child.EndLocation) if (child != null && location <= child.EndLocation)
{ {
if (child is T) if (child is T t)
result = (T)child; result = t;
node = child; node = child;
} }
else else
@ -928,7 +929,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
public AstNode GetNodeContaining(TextLocation startLocation, TextLocation endLocation) public AstNode GetNodeContaining(TextLocation startLocation, TextLocation endLocation)
{ {
for (AstNode child = firstChild; child != null; child = child.nextSibling) for (AstNode? child = firstChild; child != null; child = child.nextSibling)
{ {
if (child.StartLocation <= startLocation && endLocation <= child.EndLocation) if (child.StartLocation <= startLocation && endLocation <= child.EndLocation)
return child.GetNodeContaining(startLocation, endLocation); return child.GetNodeContaining(startLocation, endLocation);
@ -949,10 +950,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
public IEnumerable<AstNode> GetNodesBetween(TextLocation start, TextLocation end) public IEnumerable<AstNode> GetNodesBetween(TextLocation start, TextLocation end)
{ {
AstNode node = this; AstNode? node = this;
while (node != null) while (node != null)
{ {
AstNode next; AstNode? next;
if (start <= node.StartLocation && node.EndLocation <= end) if (start <= node.StartLocation && node.EndLocation <= end)
{ {
// Remember next before yielding node. // Remember next before yielding node.
@ -984,7 +985,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <param name='formattingOptions'> /// <param name='formattingOptions'>
/// Formatting options. /// Formatting options.
/// </param> /// </param>
public virtual string ToString(CSharpFormattingOptions formattingOptions) public virtual string ToString(CSharpFormattingOptions? formattingOptions)
{ {
if (IsNull) if (IsNull)
return ""; return "";

3
ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole ReadonlyRole = new TokenRole("readonly"); public static readonly TokenRole ReadonlyRole = new TokenRole("readonly");
public static readonly TokenRole NullableRole = new TokenRole("?"); public static readonly TokenRole NullableRole = new TokenRole("?");
public static readonly TokenRole PointerRole = new TokenRole("*"); public static readonly TokenRole PointerRole = new TokenRole("*");
public static readonly Role<ArraySpecifier> ArraySpecifierRole = new Role<ArraySpecifier>("ArraySpecifier"); public static readonly Role<ArraySpecifier> ArraySpecifierRole = new Role<ArraySpecifier>("ArraySpecifier", null);
public AstNodeCollection<AttributeSection> Attributes { public AstNodeCollection<AttributeSection> Attributes {
get { return base.GetChildrenByRole(AttributeRole); } get { return base.GetChildrenByRole(AttributeRole); }
} }
@ -299,4 +299,3 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
} }
} }

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ArrayCreateExpression.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class ArrayCreateExpression : Expression public class ArrayCreateExpression : Expression
{ {
public readonly static TokenRole NewKeywordRole = new TokenRole("new"); public readonly static TokenRole NewKeywordRole = new TokenRole("new");
public readonly static Role<ArraySpecifier> AdditionalArraySpecifierRole = new Role<ArraySpecifier>("AdditionalArraySpecifier"); public readonly static Role<ArraySpecifier> AdditionalArraySpecifierRole = new Role<ArraySpecifier>("AdditionalArraySpecifier", null);
public readonly static Role<ArrayInitializerExpression> InitializerRole = new Role<ArrayInitializerExpression>("Initializer", ArrayInitializerExpression.Null); public readonly static Role<ArrayInitializerExpression> InitializerRole = new Role<ArrayInitializerExpression>("Initializer", ArrayInitializerExpression.Null);
public CSharpTokenNode NewToken { public CSharpTokenNode NewToken {

8
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs

@ -16,13 +16,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.CSharp.Syntax namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
public class QueryExpression : Expression public class QueryExpression : Expression
{ {
public static readonly Role<QueryClause> ClauseRole = new Role<QueryClause>("Clause"); public static readonly Role<QueryClause> ClauseRole = new Role<QueryClause>("Clause", null);
#region Null #region Null
public new static readonly QueryExpression Null = new NullQueryExpression(); public new static readonly QueryExpression Null = new NullQueryExpression();
@ -420,7 +418,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class QueryOrderClause : QueryClause public class QueryOrderClause : QueryClause
{ {
public static readonly TokenRole OrderbyKeywordRole = new TokenRole("orderby"); public static readonly TokenRole OrderbyKeywordRole = new TokenRole("orderby");
public static readonly Role<QueryOrdering> OrderingRole = new Role<QueryOrdering>("Ordering"); public static readonly Role<QueryOrdering> OrderingRole = new Role<QueryOrdering>("Ordering", null);
public CSharpTokenNode OrderbyToken { public CSharpTokenNode OrderbyToken {
get { return GetChildByRole(OrderbyKeywordRole); } get { return GetChildByRole(OrderbyKeywordRole); }
@ -585,4 +583,4 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return o != null && this.Projection.DoMatch(o.Projection, match) && this.Key.DoMatch(o.Key, match); return o != null && this.Projection.DoMatch(o.Projection, match) && this.Key.DoMatch(o.Key, match);
} }
} }
} }

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/SwitchExpression.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class SwitchExpression : Expression public class SwitchExpression : Expression
{ {
public static readonly TokenRole SwitchKeywordRole = new TokenRole("switch"); public static readonly TokenRole SwitchKeywordRole = new TokenRole("switch");
public static readonly Role<SwitchExpressionSection> SwitchSectionRole = new Role<SwitchExpressionSection>("SwitchSection"); public static readonly Role<SwitchExpressionSection> SwitchSectionRole = new Role<SwitchExpressionSection>("SwitchSection", null);
public Expression Expression { public Expression Expression {
get { return GetChildByRole(Roles.Expression); } get { return GetChildByRole(Roles.Expression); }

3
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/PreProcessorDirective.cs

@ -69,7 +69,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class PragmaWarningPreprocessorDirective : PreProcessorDirective public class PragmaWarningPreprocessorDirective : PreProcessorDirective
{ {
public static readonly Role<PrimitiveExpression> WarningRole = new Role<PrimitiveExpression>("Warning"); public static readonly Role<PrimitiveExpression> WarningRole = new Role<PrimitiveExpression>("Warning", null);
public static readonly TokenRole PragmaKeywordRole = new TokenRole("#pragma"); public static readonly TokenRole PragmaKeywordRole = new TokenRole("#pragma");
public static readonly TokenRole WarningKeywordRole = new TokenRole("warning"); public static readonly TokenRole WarningKeywordRole = new TokenRole("warning");
@ -200,4 +200,3 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
} }
} }

12
ICSharpCode.Decompiler/CSharp/Syntax/Role.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Threading; using System.Threading;
@ -64,7 +66,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Represents the role a node plays within its parent. /// Represents the role a node plays within its parent.
/// All nodes with this role have type T. /// All nodes with this role have type T.
/// </summary> /// </summary>
public class Role<T> : Role where T : class public class Role<T> : Role where T : class?
{ {
readonly string name; // helps with debugging the AST readonly string name; // helps with debugging the AST
readonly T nullObject; readonly T nullObject;
@ -86,21 +88,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return node is T; return node is T;
} }
[Obsolete("Use the other overload explicitly specifying the nullObject.")]
public Role(string name) public Role(string name)
{ {
if (name == null) if (name == null)
throw new ArgumentNullException(nameof(name)); throw new ArgumentNullException(nameof(name));
this.name = name; this.name = name;
this.nullObject = null!;
} }
public Role(string name, T nullObject) public Role(string name, T nullObject)
{ {
if (name == null) this.name = name ?? throw new ArgumentNullException(nameof(name));
throw new ArgumentNullException(nameof(name));
if (nullObject == null)
throw new ArgumentNullException(nameof(nullObject));
this.nullObject = nullObject; this.nullObject = nullObject;
this.name = name;
} }
public override string ToString() public override string ToString()

14
ICSharpCode.Decompiler/CSharp/Syntax/Roles.cs

@ -34,18 +34,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
// some pre defined constants for common roles // some pre defined constants for common roles
public static readonly Role<Identifier> Identifier = new Role<Identifier>("Identifier", Syntax.Identifier.Null); public static readonly Role<Identifier> Identifier = new Role<Identifier>("Identifier", Syntax.Identifier.Null);
public static readonly Role<BlockStatement> Body = new Role<BlockStatement>("Body", BlockStatement.Null); public static readonly Role<BlockStatement> Body = new Role<BlockStatement>("Body", BlockStatement.Null);
public static readonly Role<ParameterDeclaration> Parameter = new Role<ParameterDeclaration>("Parameter"); public static readonly Role<ParameterDeclaration> Parameter = new Role<ParameterDeclaration>("Parameter", null);
public static readonly Role<Expression> Argument = new Role<Expression>("Argument", Syntax.Expression.Null); public static readonly Role<Expression> Argument = new Role<Expression>("Argument", Syntax.Expression.Null);
public static readonly Role<AstType> Type = new Role<AstType>("Type", AstType.Null); public static readonly Role<AstType> Type = new Role<AstType>("Type", AstType.Null);
public static readonly Role<Expression> Expression = new Role<Expression>("Expression", Syntax.Expression.Null); public static readonly Role<Expression> Expression = new Role<Expression>("Expression", Syntax.Expression.Null);
public static readonly Role<Expression> TargetExpression = new Role<Expression>("Target", Syntax.Expression.Null); public static readonly Role<Expression> TargetExpression = new Role<Expression>("Target", Syntax.Expression.Null);
public readonly static Role<Expression> Condition = new Role<Expression>("Condition", Syntax.Expression.Null); public readonly static Role<Expression> Condition = new Role<Expression>("Condition", Syntax.Expression.Null);
public static readonly Role<TypeParameterDeclaration> TypeParameter = new Role<TypeParameterDeclaration>("TypeParameter"); public static readonly Role<TypeParameterDeclaration> TypeParameter = new Role<TypeParameterDeclaration>("TypeParameter", null);
public static readonly Role<AstType> TypeArgument = new Role<AstType>("TypeArgument", AstType.Null); public static readonly Role<AstType> TypeArgument = new Role<AstType>("TypeArgument", AstType.Null);
public readonly static Role<Constraint> Constraint = new Role<Constraint>("Constraint"); public readonly static Role<Constraint> Constraint = new Role<Constraint>("Constraint", null);
public static readonly Role<VariableInitializer> Variable = new Role<VariableInitializer>("Variable", VariableInitializer.Null); public static readonly Role<VariableInitializer> Variable = new Role<VariableInitializer>("Variable", VariableInitializer.Null);
public static readonly Role<Statement> EmbeddedStatement = new Role<Statement>("EmbeddedStatement", Statement.Null); public static readonly Role<Statement> EmbeddedStatement = new Role<Statement>("EmbeddedStatement", Statement.Null);
public readonly static Role<EntityDeclaration> TypeMemberRole = new Role<EntityDeclaration>("TypeMember"); public readonly static Role<EntityDeclaration> TypeMemberRole = new Role<EntityDeclaration>("TypeMember", null);
public static readonly Role<VariableDesignation> VariableDesignationRole = new Role<VariableDesignation>("VariableDesignation", VariableDesignation.Null); public static readonly Role<VariableDesignation> VariableDesignationRole = new Role<VariableDesignation>("VariableDesignation", VariableDesignation.Null);
@ -68,12 +68,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole Colon = new TokenRole(":"); public static readonly TokenRole Colon = new TokenRole(":");
public static readonly TokenRole DoubleColon = new TokenRole("::"); public static readonly TokenRole DoubleColon = new TokenRole("::");
public static readonly TokenRole Arrow = new TokenRole("=>"); public static readonly TokenRole Arrow = new TokenRole("=>");
public static readonly Role<Comment> Comment = new Role<Comment>("Comment"); public static readonly Role<Comment> Comment = new Role<Comment>("Comment", null);
public static readonly Role<PreProcessorDirective> PreProcessorDirective = new Role<PreProcessorDirective>("PreProcessorDirective"); public static readonly Role<PreProcessorDirective> PreProcessorDirective = new Role<PreProcessorDirective>("PreProcessorDirective", null);
public readonly static Role<AstType> BaseType = new Role<AstType>("BaseType", AstType.Null); public readonly static Role<AstType> BaseType = new Role<AstType>("BaseType", AstType.Null);
public static readonly Role<Attribute> Attribute = new Role<Attribute>("Attribute"); public static readonly Role<Attribute> Attribute = new Role<Attribute>("Attribute", null);
public static readonly Role<CSharpTokenNode> AttributeTargetRole = new Role<CSharpTokenNode>("AttributeTarget", CSharpTokenNode.Null); public static readonly Role<CSharpTokenNode> AttributeTargetRole = new Role<CSharpTokenNode>("AttributeTarget", CSharpTokenNode.Null);
public readonly static TokenRole WhereKeyword = new TokenRole("where"); public readonly static TokenRole WhereKeyword = new TokenRole("where");

2
ICSharpCode.Decompiler/CSharp/Syntax/Statements/LocalFunctionDeclarationStatement.cs

@ -22,7 +22,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
public class LocalFunctionDeclarationStatement : Statement public class LocalFunctionDeclarationStatement : Statement
{ {
public static readonly Role<MethodDeclaration> MethodDeclarationRole = new Role<MethodDeclaration>("Method"); public static readonly Role<MethodDeclaration> MethodDeclarationRole = new Role<MethodDeclaration>("Method", null);
public MethodDeclaration Declaration { public MethodDeclaration Declaration {
get { return GetChildByRole(MethodDeclarationRole); } get { return GetChildByRole(MethodDeclarationRole); }

4
ICSharpCode.Decompiler/CSharp/Syntax/Statements/SwitchStatement.cs

@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class SwitchStatement : Statement public class SwitchStatement : Statement
{ {
public static readonly TokenRole SwitchKeywordRole = new TokenRole("switch"); public static readonly TokenRole SwitchKeywordRole = new TokenRole("switch");
public static readonly Role<SwitchSection> SwitchSectionRole = new Role<SwitchSection>("SwitchSection"); public static readonly Role<SwitchSection> SwitchSectionRole = new Role<SwitchSection>("SwitchSection", null);
public CSharpTokenNode SwitchToken { public CSharpTokenNode SwitchToken {
get { return GetChildByRole(SwitchKeywordRole); } get { return GetChildByRole(SwitchKeywordRole); }
@ -134,7 +134,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
#endregion #endregion
public static readonly Role<CaseLabel> CaseLabelRole = new Role<CaseLabel>("CaseLabel"); public static readonly Role<CaseLabel> CaseLabelRole = new Role<CaseLabel>("CaseLabel", null);
public override NodeType NodeType { public override NodeType NodeType {
get { get {

4
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EntityDeclaration.cs

@ -25,8 +25,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
public abstract class EntityDeclaration : AstNode public abstract class EntityDeclaration : AstNode
{ {
public static readonly Role<AttributeSection> AttributeRole = new Role<AttributeSection>("Attribute"); public static readonly Role<AttributeSection> AttributeRole = new Role<AttributeSection>("Attribute", null);
public static readonly Role<CSharpModifierToken> ModifierRole = new Role<CSharpModifierToken>("Modifier"); public static readonly Role<CSharpModifierToken> ModifierRole = new Role<CSharpModifierToken>("Modifier", null);
public static readonly Role<AstType> PrivateImplementationTypeRole = new Role<AstType>("PrivateImplementationType", AstType.Null); public static readonly Role<AstType> PrivateImplementationTypeRole = new Role<AstType>("PrivateImplementationType", AstType.Null);
public override NodeType NodeType { public override NodeType NodeType {

3
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedFieldDeclaration.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class FixedFieldDeclaration : EntityDeclaration public class FixedFieldDeclaration : EntityDeclaration
{ {
public static readonly TokenRole FixedKeywordRole = new TokenRole("fixed"); public static readonly TokenRole FixedKeywordRole = new TokenRole("fixed");
public static readonly Role<FixedVariableInitializer> VariableRole = new Role<FixedVariableInitializer>("FixedVariable"); public static readonly Role<FixedVariableInitializer> VariableRole = new Role<FixedVariableInitializer>("FixedVariable", null);
public override SymbolKind SymbolKind { public override SymbolKind SymbolKind {
get { return SymbolKind.Field; } get { return SymbolKind.Field; }
@ -67,4 +67,3 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
} }
} }

7
ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Daniel Grunwald #nullable enable
// Copyright (c) 2017 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -84,7 +85,7 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{ {
OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
} }
@ -94,6 +95,6 @@ namespace ICSharpCode.Decompiler.IL
PropertyChanged?.Invoke(this, e); PropertyChanged?.Invoke(this, e);
} }
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
} }
} }

5
ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs

@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@ -20,7 +21,7 @@ namespace ICSharpCode.Decompiler.IL
return target; return target;
} }
public static ILInstruction GetNextSibling(this ILInstruction instruction) public static ILInstruction? GetNextSibling(this ILInstruction? instruction)
{ {
if (instruction?.Parent == null) if (instruction?.Parent == null)
return null; return null;

7
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -145,12 +146,12 @@ namespace ICSharpCode.Decompiler.IL
/// ///
/// Returns SpecialType.UnknownType for unsupported instructions. /// Returns SpecialType.UnknownType for unsupported instructions.
/// </summary> /// </summary>
public static IType InferType(this ILInstruction inst, ICompilation compilation) public static IType InferType(this ILInstruction inst, ICompilation? compilation)
{ {
switch (inst) switch (inst)
{ {
case NewObj newObj: case NewObj newObj:
return newObj.Method.DeclaringType; return newObj.Method.DeclaringType ?? SpecialType.UnknownType;
case NewArr newArr: case NewArr newArr:
if (compilation != null) if (compilation != null)
return new ArrayType(compilation, newArr.Type, newArr.Indices.Count); return new ArrayType(compilation, newArr.Type, newArr.Indices.Count);

20
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -19,7 +20,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -192,7 +192,7 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
public string Name { get; set; } public string? Name { get; set; }
public bool HasGeneratedName { get; set; } public bool HasGeneratedName { get; set; }
@ -202,7 +202,7 @@ namespace ICSharpCode.Decompiler.IL
/// <remarks> /// <remarks>
/// This property is set automatically when the variable is added to the <c>ILFunction.Variables</c> collection. /// This property is set automatically when the variable is added to the <c>ILFunction.Variables</c> collection.
/// </remarks> /// </remarks>
public ILFunction Function { get; internal set; } public ILFunction? Function { get; internal set; }
/// <summary> /// <summary>
/// Gets the block container in which this variable is captured. /// Gets the block container in which this variable is captured.
@ -212,7 +212,7 @@ namespace ICSharpCode.Decompiler.IL
/// <remarks> /// <remarks>
/// This property returns null for variables that are not captured. /// This property returns null for variables that are not captured.
/// </remarks> /// </remarks>
public BlockContainer CaptureScope { get; internal set; } public BlockContainer? CaptureScope { get; internal set; }
/// <summary> /// <summary>
/// Gets the index of this variable within the <c>Function.Variables</c> collection. /// Gets the index of this variable within the <c>Function.Variables</c> collection.
@ -309,7 +309,7 @@ namespace ICSharpCode.Decompiler.IL
return list.Count - 1; return list.Count - 1;
} }
void RemoveInstruction<T>(List<T> list, int index, T inst) where T : class, IInstructionWithVariableOperand void RemoveInstruction<T>(List<T> list, int index, T? inst) where T : class, IInstructionWithVariableOperand
{ {
Debug.Assert(list[index] == inst); Debug.Assert(list[index] == inst);
int indexToMove = list.Count - 1; int indexToMove = list.Count - 1;
@ -370,7 +370,7 @@ namespace ICSharpCode.Decompiler.IL
/// The field which was converted to a local variable. /// The field which was converted to a local variable.
/// Set when the variable is from a 'yield return' or 'async' state machine. /// Set when the variable is from a 'yield return' or 'async' state machine.
/// </summary> /// </summary>
public IField StateMachineField; public IField? StateMachineField;
public ILVariable(VariableKind kind, IType type, int? index = null) public ILVariable(VariableKind kind, IType type, int? index = null)
{ {
@ -398,7 +398,7 @@ namespace ICSharpCode.Decompiler.IL
CheckInvariant(); CheckInvariant();
} }
public override string ToString() public override string? ToString()
{ {
return Name; return Name;
} }
@ -472,7 +472,7 @@ namespace ICSharpCode.Decompiler.IL
if (CaptureScope != null) if (CaptureScope != null)
{ {
output.Write(" captured in "); output.Write(" captured in ");
output.WriteLocalReference(CaptureScope.EntryPoint.Label, CaptureScope); output.WriteLocalReference(CaptureScope.EntryPoint?.Label, CaptureScope);
} }
if (StateMachineField != null) if (StateMachineField != null)
{ {
@ -528,7 +528,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public static readonly ILVariableEqualityComparer Instance = new ILVariableEqualityComparer(); public static readonly ILVariableEqualityComparer Instance = new ILVariableEqualityComparer();
public bool Equals(ILVariable x, ILVariable y) public bool Equals(ILVariable? x, ILVariable? y)
{ {
if (x == y) if (x == y)
return true; return true;

3
ICSharpCode.Decompiler/IL/InstructionFlags.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

3
ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

508
ICSharpCode.Decompiler/IL/Instructions.cs

File diff suppressed because it is too large Load Diff

85
ICSharpCode.Decompiler/IL/Instructions.tt

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #> <#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #> <#@ import namespace="System.Linq" #>
@ -32,7 +34,7 @@
AbstractBaseClass, CustomArguments(("left", null), ("right", null)), HasFlag("InstructionFlags.None")), AbstractBaseClass, CustomArguments(("left", null), ("right", null)), HasFlag("InstructionFlags.None")),
new OpCode("CallInstruction", "Instruction with a list of arguments.", new OpCode("CallInstruction", "Instruction with a list of arguments.",
AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}),
CustomWriteTo, MayThrow, SideEffect), CustomConstructor, CustomWriteTo, MayThrow, SideEffect),
new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" }, new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" },
new OpCode("CompoundAssignmentInstruction", "Common instruction for compound assignments.", new OpCode("CompoundAssignmentInstruction", "Common instruction for compound assignments.",
AbstractBaseClass, CustomConstructor, CustomArguments(("target", null), ("value", null))), AbstractBaseClass, CustomConstructor, CustomArguments(("target", null), ("value", null))),
@ -68,7 +70,7 @@
new ChildInfo("init") { CanInlineInto = true }, new ChildInfo("init") { CanInlineInto = true },
new ChildInfo("body") new ChildInfo("body")
}), }),
CustomInvariant("Debug.Assert(Variable.Kind == VariableKind.PinnedRegionLocal);")), CustomInvariant("DebugAssert(Variable.Kind == VariableKind.PinnedRegionLocal);")),
new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.", new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.",
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags, CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags,
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && IsLifted == o.IsLifted")), MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && IsLifted == o.IsLifted")),
@ -215,11 +217,11 @@
new OpCode("ldnull", "Loads the null reference.", new OpCode("ldnull", "Loads the null reference.",
CustomClassName("LdNull"), NoArguments, ResultType("O")), CustomClassName("LdNull"), NoArguments, ResultType("O")),
new OpCode("ldftn", "Load method pointer", new OpCode("ldftn", "Load method pointer",
CustomClassName("LdFtn"), NoArguments, HasMethodOperand, ResultType("I")), CustomClassName("LdFtn"), NoArguments, HasMethodOperand(), ResultType("I")),
new OpCode("ldvirtftn", "Load method pointer", new OpCode("ldvirtftn", "Load method pointer",
CustomClassName("LdVirtFtn"), Unary, HasMethodOperand, MayThrow, ResultType("I")), CustomClassName("LdVirtFtn"), Unary, HasMethodOperand(), MayThrow, ResultType("I")),
new OpCode("ldvirtdelegate", "Virtual delegate construction", new OpCode("ldvirtdelegate", "Virtual delegate construction",
CustomClassName("LdVirtDelegate"), Unary, HasTypeOperand, HasMethodOperand, CustomClassName("LdVirtDelegate"), Unary, HasTypeOperand, HasMethodOperand(),
MayThrow, ResultType("O")), MayThrow, ResultType("O")),
new OpCode("ldtypetoken", "Loads runtime representation of metadata token", new OpCode("ldtypetoken", "Loads runtime representation of metadata token",
CustomClassName("LdTypeToken"), NoArguments, HasTypeOperand, ResultType("O")), CustomClassName("LdTypeToken"), NoArguments, HasTypeOperand, ResultType("O")),
@ -287,7 +289,7 @@
+ "The input must be an object reference (O)." + Environment.NewLine + "The input must be an object reference (O)." + Environment.NewLine
+ "If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty." + Environment.NewLine + "If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty." + Environment.NewLine
+ "Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null." + Environment.NewLine, + "Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null." + Environment.NewLine,
CustomArguments(("argument", new[] { "O" })), ResultType("Ref"), HasMethodOperand), CustomArguments(("argument", new[] { "O" })), ResultType("Ref"), HasMethodOperand(nullable: true)),
new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).", new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).",
CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")), CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")),
@ -297,7 +299,7 @@
new OpCode("user.logic.operator", "Use of user-defined &amp;&amp; or || operator.", new OpCode("user.logic.operator", "Use of user-defined &amp;&amp; or || operator.",
CustomClassName("UserDefinedLogicOperator"), CustomClassName("UserDefinedLogicOperator"),
HasMethodOperand, ResultType("O"), HasMethodOperand(), ResultType("O"),
CustomChildren(new []{ CustomChildren(new []{
new ChildInfo("left") { CanInlineInto = true }, new ChildInfo("left") { CanInlineInto = true },
new ChildInfo("right") { CanInlineInto = false } // only executed depending on value of left new ChildInfo("right") { CanInlineInto = false } // only executed depending on value of left
@ -337,7 +339,7 @@
CustomClassName("DynamicIsEventInstruction"), Dynamic, CustomArguments(("argument", new[] { "O" })), CustomWriteTo), CustomClassName("DynamicIsEventInstruction"), Dynamic, CustomArguments(("argument", new[] { "O" })), CustomWriteTo),
new OpCode("match", "ILAst representation of C# patterns", new OpCode("match", "ILAst representation of C# patterns",
CustomClassName("MatchInstruction"), HasVariableOperand("Store"), HasMethodOperand, CustomClassName("MatchInstruction"), HasVariableOperand("Store"), HasMethodOperand(nullable: true),
BoolFlag("IsDeconstructCall"), BoolFlag("IsDeconstructTuple"), BoolFlag("CheckType"), BoolFlag("CheckNotNull"), BoolFlag("IsDeconstructCall"), BoolFlag("IsDeconstructTuple"), BoolFlag("CheckType"), BoolFlag("CheckNotNull"),
CustomChildren(new []{ CustomChildren(new []{
new ChildInfo("testedOperand") { CanInlineInto = true }, new ChildInfo("testedOperand") { CanInlineInto = true },
@ -371,8 +373,8 @@
}; };
#> #>
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -437,7 +439,7 @@ namespace <#=opCode.Namespace#>
} }
<# } #> <# } #>
<# if (opCode.GeneratePerformMatch) { #> <# if (opCode.GeneratePerformMatch) { #>
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) protected internal override bool PerformMatch(ILInstruction? other, ref Patterns.Match match)
{ {
var o = other as <#=opCode.Name#>; var o = other as <#=opCode.Name#>;
return <#=string.Join(" && ", opCode.PerformMatchConditions)#>; return <#=string.Join(" && ", opCode.PerformMatchConditions)#>;
@ -637,10 +639,15 @@ namespace ICSharpCode.Decompiler.IL
public string TypeName; public string TypeName;
public string Name; public string Name;
public string FieldName; public string FieldName;
public bool IsReferenceType = true;
public override string ToString() public override string ToString()
{ {
return "out " + TypeName + " " + Name; if (IsReferenceType) {
return "[NotNullWhen(true)] out " + TypeName + "? " + Name;
} else {
return "out " + TypeName + " " + Name;
}
} }
} }
@ -866,7 +873,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.WriteArguments.Add("output.Write(\", \");"); opCode.WriteArguments.Add("output.Write(\", \");");
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output, options);"); opCode.WriteArguments.Add("this." + arg + ".WriteTo(output, options);");
opCode.Members.Add("public static readonly SlotInfo " + children[i].SlotName + " = " + children[i].GetSlotInit() + ";"); opCode.Members.Add("public static readonly SlotInfo " + children[i].SlotName + " = " + children[i].GetSlotInit() + ";");
opCode.Members.Add("ILInstruction " + arg + ";"); opCode.Members.Add("ILInstruction " + arg + " = null!;");
opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine
+ "\tget { return this." + arg + "; }" + Environment.NewLine + "\tget { return this." + arg + "; }" + Environment.NewLine
+ "\tset {" + Environment.NewLine + "\tset {" + Environment.NewLine
@ -885,7 +892,7 @@ namespace ICSharpCode.Decompiler.IL
checkString += " || "; checkString += " || ";
checkString += arg + ".ResultType == " + expectedTypeCode; checkString += arg + ".ResultType == " + expectedTypeCode;
} }
opCode.Invariants.Add("Debug.Assert(" + checkString + ");"); opCode.Invariants.Add("DebugAssert(" + checkString + ");");
} }
} }
opCode.WriteArguments.Add("output.Write(')');"); opCode.WriteArguments.Add("output.Write(')');");
@ -1008,8 +1015,7 @@ namespace ICSharpCode.Decompiler.IL
Action<OpCode> action = opCode => { Action<OpCode> action = opCode => {
opCode.ConstructorParameters.Add("ILVariable variable"); opCode.ConstructorParameters.Add("ILVariable variable");
opCode.Members.Add("ILVariable variable;"); opCode.Members.Add("ILVariable variable;");
opCode.ConstructorBody.Add("Debug.Assert(variable != null);"); opCode.ConstructorBody.Add("this.variable = variable ?? throw new ArgumentNullException(nameof(variable));");
opCode.ConstructorBody.Add("this.variable = variable;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILVariable", Name = "variable", FieldName = "Variable" }); opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILVariable", Name = "variable", FieldName = "Variable" });
opCode.PerformMatchConditions.Add("variable == o.variable"); opCode.PerformMatchConditions.Add("variable == o.variable");
opCode.GenerateWriteTo = true; opCode.GenerateWriteTo = true;
@ -1019,7 +1025,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.Members.Add(@"public ILVariable Variable { opCode.Members.Add(@"public ILVariable Variable {
get { return variable; } get { return variable; }
set { set {
Debug.Assert(value != null); DebugAssert(value != null);
if (IsConnected) if (IsConnected)
variable.RemoveAccessInstruction(this); variable.RemoveAccessInstruction(this);
variable = value; variable = value;
@ -1048,8 +1054,8 @@ protected override void Disconnected()
} }
".Replace("Access", accessType)); ".Replace("Access", accessType));
if (generateCheckInvariant) { if (generateCheckInvariant) {
opCode.Invariants.Add("Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));"); opCode.Invariants.Add("DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));");
opCode.Invariants.Add("Debug.Assert(phase <= ILPhase.InILReader || variable.Function.Variables[variable.IndexInFunction] == variable);"); opCode.Invariants.Add("DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);");
} }
}; };
if (accessType == "Load") { if (accessType == "Load") {
@ -1093,22 +1099,26 @@ protected override void Disconnected()
opCode.WriteOperand.Add("type.WriteTo(output);"); opCode.WriteOperand.Add("type.WriteTo(output);");
}; };
static Action<OpCode> HasMethodOperand = opCode => { static Action<OpCode> HasMethodOperand(bool nullable = false)
opCode.ConstructorParameters.Add("IMethod method"); {
opCode.Members.Add("readonly IMethod method;"); return opCode => {
opCode.ConstructorBody.Add("this.method = method;"); string n = nullable ? "?" : "";
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IMethod", Name = "method", FieldName = "Method" }); opCode.ConstructorParameters.Add($"IMethod{n} method");
opCode.PerformMatchConditions.Add("object.Equals(method, o.method)"); opCode.Members.Add($"readonly IMethod{n} method;");
opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine opCode.ConstructorBody.Add("this.method = method;");
+ "public IMethod Method { get { return method; } }"); opCode.MatchParameters.Add(new MatchParamInfo { TypeName = $"IMethod{n}", Name = "method", FieldName = "Method", IsReferenceType = !nullable });
opCode.GenerateWriteTo = true; opCode.PerformMatchConditions.Add("object.Equals(method, o.method)");
opCode.WriteOperand.Add("if (method != null) {"); opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine
opCode.WriteOperand.Add("\toutput.Write(' ');"); + $"public IMethod{n} Method => method;");
opCode.WriteOperand.Add("\tmethod.WriteTo(output);"); opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("}"); opCode.WriteOperand.Add("if (method != null) {");
opCode.Interfaces.Add("IInstructionWithMethodOperand"); opCode.WriteOperand.Add("\toutput.Write(' ');");
}; opCode.WriteOperand.Add("\tmethod.WriteTo(output);");
opCode.WriteOperand.Add("}");
opCode.Interfaces.Add("IInstructionWithMethodOperand");
};
}
static Action<OpCode> HasMemberOperand = opCode => { static Action<OpCode> HasMemberOperand = opCode => {
opCode.ConstructorParameters.Add("IMember member"); opCode.ConstructorParameters.Add("IMember member");
opCode.Members.Add("readonly IMember member;"); opCode.Members.Add("readonly IMember member;");
@ -1139,7 +1149,12 @@ protected override void Disconnected()
return opCode => { return opCode => {
NoArguments(opCode); NoArguments(opCode);
opCode.ConstructorParameters.Add(operandType + " value"); opCode.ConstructorParameters.Add(operandType + " value");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = operandType, Name = "value", FieldName = "Value" }); opCode.MatchParameters.Add(new MatchParamInfo {
TypeName = operandType,
Name = "value",
FieldName = "Value",
IsReferenceType = operandType == "string"
});
opCode.PerformMatchConditions.Add("this.Value == o.Value"); opCode.PerformMatchConditions.Add("this.Value == o.Value");
opCode.Members.Add("public readonly " + operandType + " Value;"); opCode.Members.Add("public readonly " + operandType + " Value;");
opCode.ConstructorBody.Add("this.Value = value;"); opCode.ConstructorBody.Add("this.Value = value;");

7
ICSharpCode.Decompiler/IL/Instructions/Await.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Daniel Grunwald #nullable enable
// Copyright (c) 2017 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -22,7 +23,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
partial class Await partial class Await
{ {
public IMethod GetAwaiterMethod; public IMethod? GetAwaiterMethod;
public IMethod GetResultMethod; public IMethod? GetResultMethod;
} }
} }

5
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -214,5 +215,3 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
} }

47
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014-2016 Daniel Grunwald #nullable enable
// Copyright (c) 2014-2016 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -16,14 +17,13 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary> /// <summary>
@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.IL
public readonly BlockKind Kind; public readonly BlockKind Kind;
public readonly InstructionCollection<ILInstruction> Instructions; public readonly InstructionCollection<ILInstruction> Instructions;
ILInstruction finalInstruction; ILInstruction finalInstruction = null!;
/// <summary> /// <summary>
/// For blocks in a block container, this field holds /// For blocks in a block container, this field holds
@ -124,10 +124,10 @@ namespace ICSharpCode.Decompiler.IL
foreach (var inst in Instructions) foreach (var inst in Instructions)
{ {
var stloc = inst as StLoc; var stloc = inst as StLoc;
Debug.Assert(stloc != null, "Instructions in CallWithNamedArgs must be assignments"); DebugAssert(stloc != null, "Instructions in CallWithNamedArgs must be assignments");
Debug.Assert(stloc.Variable.Kind == VariableKind.NamedArgument); DebugAssert(stloc.Variable.Kind == VariableKind.NamedArgument);
Debug.Assert(stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 1); DebugAssert(stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 1);
Debug.Assert(stloc.Variable.LoadInstructions.Single().Parent == finalInstruction); DebugAssert(stloc.Variable.LoadInstructions.Single().Parent == finalInstruction);
} }
var call = (CallInstruction)finalInstruction; var call = (CallInstruction)finalInstruction;
if (call.IsInstanceCall) if (call.IsInstanceCall)
@ -140,22 +140,22 @@ namespace ICSharpCode.Decompiler.IL
case BlockKind.ArrayInitializer: case BlockKind.ArrayInitializer:
var final = finalInstruction as LdLoc; var final = finalInstruction as LdLoc;
Debug.Assert(final != null && final.Variable.IsSingleDefinition && final.Variable.Kind == VariableKind.InitializerTarget); Debug.Assert(final != null && final.Variable.IsSingleDefinition && final.Variable.Kind == VariableKind.InitializerTarget);
IType type = null; IType? type = null;
Debug.Assert(Instructions[0].MatchStLoc(final.Variable, out var init) && init.MatchNewArr(out type)); Debug.Assert(Instructions[0].MatchStLoc(final!.Variable, out var init) && init.MatchNewArr(out type));
for (int i = 1; i < Instructions.Count; i++) for (int i = 1; i < Instructions.Count; i++)
{ {
Debug.Assert(Instructions[i].MatchStObj(out ILInstruction target, out _, out var t) && type != null && type.Equals(t)); DebugAssert(Instructions[i].MatchStObj(out ILInstruction? target, out _, out var t) && type != null && type.Equals(t));
Debug.Assert(target.MatchLdElema(out t, out ILInstruction array) && type.Equals(t)); DebugAssert(target.MatchLdElema(out t, out ILInstruction? array) && type.Equals(t));
Debug.Assert(array.MatchLdLoc(out ILVariable v) && v == final.Variable); DebugAssert(array.MatchLdLoc(out ILVariable? v) && v == final.Variable);
} }
break; break;
case BlockKind.CollectionInitializer: case BlockKind.CollectionInitializer:
case BlockKind.ObjectInitializer: case BlockKind.ObjectInitializer:
var final2 = finalInstruction as LdLoc; var final2 = finalInstruction as LdLoc;
Debug.Assert(final2 != null); Debug.Assert(final2 != null);
var initVar2 = final2.Variable; var initVar2 = final2!.Variable;
Debug.Assert(initVar2.StoreCount == 1 && initVar2.Kind == VariableKind.InitializerTarget); Debug.Assert(initVar2.StoreCount == 1 && initVar2.Kind == VariableKind.InitializerTarget);
IType type2 = null; IType? type2 = null;
bool condition = Instructions[0].MatchStLoc(final2.Variable, out var init2); bool condition = Instructions[0].MatchStLoc(final2.Variable, out var init2);
Debug.Assert(condition); Debug.Assert(condition);
Debug.Assert(init2 is NewObj Debug.Assert(init2 is NewObj
@ -300,7 +300,7 @@ namespace ICSharpCode.Decompiler.IL
public void Remove() public void Remove()
{ {
Debug.Assert(ChildIndex > 0); Debug.Assert(ChildIndex > 0);
var container = (BlockContainer)Parent; var container = (BlockContainer)Parent!;
Debug.Assert(container.Blocks[ChildIndex] == this); Debug.Assert(container.Blocks[ChildIndex] == this);
container.Blocks.SwapRemoveAt(ChildIndex); container.Blocks.SwapRemoveAt(ChildIndex);
} }
@ -325,7 +325,7 @@ namespace ICSharpCode.Decompiler.IL
/// Gets the predecessor of the given instruction. /// Gets the predecessor of the given instruction.
/// Returns null if inst.Parent is not a block. /// Returns null if inst.Parent is not a block.
/// </summary> /// </summary>
public static ILInstruction GetPredecessor(ILInstruction inst) public static ILInstruction? GetPredecessor(ILInstruction inst)
{ {
if (inst.Parent is Block block && inst.ChildIndex > 0) if (inst.Parent is Block block && inst.ChildIndex > 0)
{ {
@ -341,7 +341,8 @@ namespace ICSharpCode.Decompiler.IL
/// If inst is a block consisting of a single instruction, returns that instruction. /// If inst is a block consisting of a single instruction, returns that instruction.
/// Otherwise, returns the input instruction. /// Otherwise, returns the input instruction.
/// </summary> /// </summary>
public static ILInstruction Unwrap(ILInstruction inst) [return: NotNullIfNotNull("inst")]
public static ILInstruction? Unwrap(ILInstruction? inst)
{ {
if (inst is Block block) if (inst is Block block)
{ {
@ -355,19 +356,19 @@ namespace ICSharpCode.Decompiler.IL
/// Gets the closest parent Block. /// Gets the closest parent Block.
/// Returns null, if the instruction is not a descendant of a Block. /// Returns null, if the instruction is not a descendant of a Block.
/// </summary> /// </summary>
public static Block FindClosestBlock(ILInstruction inst) public static Block? FindClosestBlock(ILInstruction? inst)
{ {
var curr = inst; var curr = inst;
while (curr != null) while (curr != null)
{ {
if (curr is Block) if (curr is Block b)
return (Block)curr; return b;
curr = curr.Parent; curr = curr.Parent;
} }
return null; return null;
} }
public bool MatchInlineAssignBlock(out CallInstruction call, out ILInstruction value) public bool MatchInlineAssignBlock([NotNullWhen(true)] out CallInstruction? call, [NotNullWhen(true)] out ILInstruction? value)
{ {
call = null; call = null;
value = null; value = null;
@ -385,7 +386,7 @@ namespace ICSharpCode.Decompiler.IL
return this.FinalInstruction.MatchLdLoc(tmp); return this.FinalInstruction.MatchLdLoc(tmp);
} }
public bool MatchIfAtEndOfBlock(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst) public bool MatchIfAtEndOfBlock([NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out ILInstruction? trueInst, [NotNullWhen(true)] out ILInstruction? falseInst)
{ {
condition = null; condition = null;
trueInst = null; trueInst = null;

32
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -19,11 +20,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary> /// <summary>
@ -57,13 +58,18 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
Block entryPoint; Block? entryPoint;
/// <summary> /// <summary>
/// Gets the container's entry point. This is the first block in the Blocks collection. /// Gets the container's entry point. This is the first block in the Blocks collection.
/// </summary> /// </summary>
public Block EntryPoint { public Block EntryPoint {
get { return entryPoint; } get {
// HACK: While it's possible to have BlockContainers without entry point,
// normally every container must have an entry point according to its invariant.
// Thus it's easier on the transforms if this property returns a non-nullable EntryPoint.
return entryPoint!;
}
private set { private set {
if (entryPoint != null && IsConnected) if (entryPoint != null && IsConnected)
entryPoint.IncomingEdgeCount--; entryPoint.IncomingEdgeCount--;
@ -102,7 +108,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override void InstructionCollectionUpdateComplete() protected internal override void InstructionCollectionUpdateComplete()
{ {
base.InstructionCollectionUpdateComplete(); base.InstructionCollectionUpdateComplete();
this.EntryPoint = this.Blocks.FirstOrDefault(); this.EntryPoint = this.Blocks.FirstOrDefault()!;
} }
protected override void Connected() protected override void Connected()
@ -174,7 +180,7 @@ namespace ICSharpCode.Decompiler.IL
return Blocks[index]; return Blocks[index];
} }
protected override void SetChild(int index, ILInstruction value) protected override void SetChild(int index, ILInstruction? value)
{ {
if (Blocks[index] != value) if (Blocks[index] != value)
throw new InvalidOperationException("Cannot replace blocks in BlockContainer"); throw new InvalidOperationException("Cannot replace blocks in BlockContainer");
@ -189,12 +195,12 @@ namespace ICSharpCode.Decompiler.IL
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase);
Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]); Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]);
Debug.Assert(!IsConnected || EntryPoint?.IncomingEdgeCount >= 1); Debug.Assert(!IsConnected || EntryPoint.IncomingEdgeCount >= 1);
Debug.Assert(EntryPoint == null || Parent is ILFunction || !ILRangeIsEmpty); Debug.Assert(Parent is ILFunction || !ILRangeIsEmpty);
Debug.Assert(Blocks.All(b => b.HasFlag(InstructionFlags.EndPointUnreachable))); Debug.Assert(Blocks.All(b => b.HasFlag(InstructionFlags.EndPointUnreachable)));
Debug.Assert(Blocks.All(b => b.Kind == BlockKind.ControlFlow)); // this also implies that the blocks don't use FinalInstruction Debug.Assert(Blocks.All(b => b.Kind == BlockKind.ControlFlow)); // this also implies that the blocks don't use FinalInstruction
Debug.Assert(TopologicalSort(deleteUnreachableBlocks: true).Count == Blocks.Count, "Container should not have any unreachable blocks"); Debug.Assert(TopologicalSort(deleteUnreachableBlocks: true).Count == Blocks.Count, "Container should not have any unreachable blocks");
Block bodyStartBlock; Block? bodyStartBlock;
switch (Kind) switch (Kind)
{ {
case ContainerKind.Normal: case ContainerKind.Normal:
@ -319,7 +325,7 @@ namespace ICSharpCode.Decompiler.IL
Blocks.ReplaceList(newOrder); Blocks.ReplaceList(newOrder);
} }
public static BlockContainer FindClosestContainer(ILInstruction inst) public static BlockContainer? FindClosestContainer(ILInstruction? inst)
{ {
while (inst != null) while (inst != null)
{ {
@ -330,18 +336,18 @@ namespace ICSharpCode.Decompiler.IL
return null; return null;
} }
public static BlockContainer FindClosestSwitchContainer(ILInstruction inst) public static BlockContainer? FindClosestSwitchContainer(ILInstruction? inst)
{ {
while (inst != null) while (inst != null)
{ {
if (inst is BlockContainer bc && bc.entryPoint.Instructions.FirstOrDefault() is SwitchInstruction) if (inst is BlockContainer { Kind: ContainerKind.Switch } bc)
return bc; return bc;
inst = inst.Parent; inst = inst.Parent;
} }
return null; return null;
} }
public bool MatchConditionBlock(Block block, out ILInstruction condition, out Block bodyStartBlock) public bool MatchConditionBlock(Block block, [NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out Block? bodyStartBlock)
{ {
condition = null; condition = null;
bodyStartBlock = null; bodyStartBlock = null;

25
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -30,7 +31,7 @@ namespace ICSharpCode.Decompiler.IL
partial class Branch : SimpleInstruction, IBranchOrLeaveInstruction partial class Branch : SimpleInstruction, IBranchOrLeaveInstruction
{ {
readonly int targetILOffset; readonly int targetILOffset;
Block targetBlock; Block? targetBlock;
public Branch(int targetILOffset) : base(OpCode.Branch) public Branch(int targetILOffset) : base(OpCode.Branch)
{ {
@ -48,7 +49,11 @@ namespace ICSharpCode.Decompiler.IL
} }
public Block TargetBlock { public Block TargetBlock {
get { return targetBlock; } get {
// HACK: We treat TargetBlock as non-nullable publicly, because it's only null inside
// the ILReader, and becomes non-null once the BlockBuilder has run.
return targetBlock!;
}
set { set {
if (targetBlock != null && IsConnected) if (targetBlock != null && IsConnected)
targetBlock.IncomingEdgeCount--; targetBlock.IncomingEdgeCount--;
@ -62,7 +67,7 @@ namespace ICSharpCode.Decompiler.IL
/// Gets the BlockContainer that contains the target block. /// Gets the BlockContainer that contains the target block.
/// </summary> /// </summary>
public BlockContainer TargetContainer { public BlockContainer TargetContainer {
get { return (BlockContainer)targetBlock?.Parent; } get { return (BlockContainer)targetBlock?.Parent!; }
} }
protected override void Connected() protected override void Connected()
@ -92,9 +97,9 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal static bool GetExecutesFinallyBlock(ILInstruction inst, BlockContainer container) internal static bool GetExecutesFinallyBlock(ILInstruction? inst, BlockContainer? container)
{ {
for (; inst != container; inst = inst.Parent) for (; inst != container && inst != null; inst = inst.Parent)
{ {
if (inst.Parent is TryFinally && inst.SlotInfo == TryFinally.TryBlockSlot) if (inst.Parent is TryFinally && inst.SlotInfo == TryFinally.TryBlockSlot)
return true; return true;
@ -107,9 +112,9 @@ namespace ICSharpCode.Decompiler.IL
base.CheckInvariant(phase); base.CheckInvariant(phase);
if (phase > ILPhase.InILReader) if (phase > ILPhase.InILReader)
{ {
Debug.Assert(targetBlock.Parent is BlockContainer); Debug.Assert(targetBlock?.Parent is BlockContainer);
Debug.Assert(this.IsDescendantOf(targetBlock.Parent)); Debug.Assert(this.IsDescendantOf(targetBlock!.Parent!));
Debug.Assert(targetBlock.Parent.Children[targetBlock.ChildIndex] == targetBlock); Debug.Assert(targetBlock!.Parent!.Children[targetBlock.ChildIndex] == targetBlock);
} }
} }
@ -118,7 +123,7 @@ namespace ICSharpCode.Decompiler.IL
WriteILRange(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
output.WriteLocalReference(TargetLabel, (object)targetBlock ?? TargetILOffset); output.WriteLocalReference(TargetLabel, (object?)targetBlock ?? TargetILOffset);
} }
} }

5
ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Daniel Grunwald #nullable enable
// Copyright (c) 2017 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -31,7 +32,7 @@ namespace ICSharpCode.Decompiler.IL
public static readonly SlotInfo FunctionPointerSlot = new SlotInfo("FunctionPointer", canInlineInto: true); public static readonly SlotInfo FunctionPointerSlot = new SlotInfo("FunctionPointer", canInlineInto: true);
public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true, isCollection: true); public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true, isCollection: true);
ILInstruction functionPointer; ILInstruction functionPointer = null!;
public readonly InstructionCollection<ILInstruction> Arguments; public readonly InstructionCollection<ILInstruction> Arguments;
public bool IsInstance { get; } public bool IsInstance { get; }
public bool HasExplicitThis { get; } public bool HasExplicitThis { get; }

15
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -19,7 +20,6 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -52,7 +52,7 @@ namespace ICSharpCode.Decompiler.IL
/// Gets/Sets the type specified in the 'constrained.' prefix. /// Gets/Sets the type specified in the 'constrained.' prefix.
/// Returns null if no 'constrained.' prefix exists for this call. /// Returns null if no 'constrained.' prefix exists for this call.
/// </summary> /// </summary>
public IType ConstrainedTo; public IType? ConstrainedTo;
/// <summary> /// <summary>
/// Gets whether the IL stack was empty at the point of this call. /// Gets whether the IL stack was empty at the point of this call.
@ -62,8 +62,7 @@ namespace ICSharpCode.Decompiler.IL
protected CallInstruction(OpCode opCode, IMethod method) : base(opCode) protected CallInstruction(OpCode opCode, IMethod method) : base(opCode)
{ {
Debug.Assert(method != null); this.Method = method ?? throw new ArgumentNullException(nameof(method));
this.Method = method;
this.Arguments = new InstructionCollection<ILInstruction>(this, 0); this.Arguments = new InstructionCollection<ILInstruction>(this, 0);
} }
@ -78,7 +77,7 @@ namespace ICSharpCode.Decompiler.IL
/// Gets the parameter for the argument with the specified index. /// Gets the parameter for the argument with the specified index.
/// Returns null for the <c>this</c> parameter. /// Returns null for the <c>this</c> parameter.
/// </summary> /// </summary>
public IParameter GetParameter(int argumentIndex) public IParameter? GetParameter(int argumentIndex)
{ {
int firstParamIndex = (Method.IsStatic || OpCode == OpCode.NewObj) ? 0 : 1; int firstParamIndex = (Method.IsStatic || OpCode == OpCode.NewObj) ? 0 : 1;
if (argumentIndex < firstParamIndex) if (argumentIndex < firstParamIndex)
@ -160,9 +159,9 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')'); output.Write(')');
} }
protected internal sealed override bool PerformMatch(ILInstruction other, ref Patterns.Match match) protected internal sealed override bool PerformMatch(ILInstruction? other, ref Patterns.Match match)
{ {
CallInstruction o = other as CallInstruction; CallInstruction? o = other as CallInstruction;
return o != null && this.OpCode == o.OpCode && this.Method.Equals(o.Method) && this.IsTail == o.IsTail return o != null && this.OpCode == o.OpCode && this.Method.Equals(o.Method) && this.IsTail == o.IsTail
&& object.Equals(this.ConstrainedTo, o.ConstrainedTo) && object.Equals(this.ConstrainedTo, o.ConstrainedTo)
&& Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match); && Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match);

6
ICSharpCode.Decompiler/IL/Instructions/Comp.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -21,7 +22,6 @@ using System.Diagnostics;
using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
@ -231,5 +231,3 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
} }

5
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2016 Siegfried Pammer #nullable enable
// Copyright (c) 2016 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -172,7 +173,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Gets whether the specific binary instruction is compatible with a compound operation on the specified type. /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type.
/// </summary> /// </summary>
internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, DecompilerSettings settings) internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, DecompilerSettings? settings)
{ {
if (binary.IsLifted) if (binary.IsLifted)
{ {

3
ICSharpCode.Decompiler/IL/Instructions/Conv.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

13
ICSharpCode.Decompiler/IL/Instructions/DeconstructResultInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2020 Siegfried Pammer #nullable enable
// Copyright (c) 2020 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -47,9 +48,9 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')'); output.Write(')');
} }
MatchInstruction FindMatch() MatchInstruction? FindMatch()
{ {
for (ILInstruction inst = this; inst != null; inst = inst.Parent) for (ILInstruction? inst = this; inst != null; inst = inst.Parent)
{ {
if (inst.Parent is MatchInstruction match && inst != match.TestedOperand) if (inst.Parent is MatchInstruction match && inst != match.TestedOperand)
return match; return match;
@ -60,10 +61,10 @@ namespace ICSharpCode.Decompiler.IL
void AdditionalInvariants() void AdditionalInvariants()
{ {
var matchInst = FindMatch(); var matchInst = FindMatch();
Debug.Assert(matchInst != null && (matchInst.IsDeconstructCall || matchInst.IsDeconstructTuple)); DebugAssert(matchInst != null && (matchInst.IsDeconstructCall || matchInst.IsDeconstructTuple));
Debug.Assert(Argument.MatchLdLoc(matchInst.Variable)); DebugAssert(Argument.MatchLdLoc(matchInst.Variable));
var outParamType = matchInst.GetDeconstructResultType(this.Index); var outParamType = matchInst.GetDeconstructResultType(this.Index);
Debug.Assert(outParamType.GetStackType() == ResultType); DebugAssert(outParamType.GetStackType() == ResultType);
} }
} }
} }

3
ICSharpCode.Decompiler/IL/Instructions/DefaultValue.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Siegfried Pammer #nullable enable
// Copyright (c) 2017 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

43
ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs

@ -1,4 +1,5 @@
// Copyright (c) 2018 Siegfried Pammer #nullable enable
// Copyright (c) 2018 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -56,7 +57,7 @@ namespace ICSharpCode.Decompiler.IL
public struct CSharpArgumentInfo public struct CSharpArgumentInfo
{ {
public string Name { get; set; } public string? Name { get; set; }
public CSharpArgumentInfoFlags Flags { get; set; } public CSharpArgumentInfoFlags Flags { get; set; }
public IType CompileTimeType { get; set; } public IType CompileTimeType { get; set; }
@ -66,9 +67,9 @@ namespace ICSharpCode.Decompiler.IL
partial class DynamicInstruction partial class DynamicInstruction
{ {
public CSharpBinderFlags BinderFlags { get; } public CSharpBinderFlags BinderFlags { get; }
public IType CallingContext { get; } public IType? CallingContext { get; }
protected DynamicInstruction(OpCode opCode, CSharpBinderFlags binderFlags, IType context) protected DynamicInstruction(OpCode opCode, CSharpBinderFlags binderFlags, IType? context)
: base(opCode) : base(opCode)
{ {
BinderFlags = binderFlags; BinderFlags = binderFlags;
@ -141,10 +142,10 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')'); output.Write(')');
} }
public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType context, ILInstruction argument) public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType? context, ILInstruction argument)
: base(OpCode.DynamicConvertInstruction, binderFlags, context) : base(OpCode.DynamicConvertInstruction, binderFlags, context)
{ {
Type = type; this.type = type;
Argument = argument; Argument = argument;
} }
@ -171,7 +172,7 @@ namespace ICSharpCode.Decompiler.IL
public IReadOnlyList<IType> TypeArguments { get; } public IReadOnlyList<IType> TypeArguments { get; }
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; } public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeMemberInstruction(CSharpBinderFlags binderFlags, string name, IType[] typeArguments, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) public DynamicInvokeMemberInstruction(CSharpBinderFlags binderFlags, string name, IType[]? typeArguments, IType? context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeMemberInstruction, binderFlags, context) : base(OpCode.DynamicInvokeMemberInstruction, binderFlags, context)
{ {
Name = name; Name = name;
@ -216,10 +217,10 @@ namespace ICSharpCode.Decompiler.IL
partial class DynamicGetMemberInstruction partial class DynamicGetMemberInstruction
{ {
public string Name { get; } public string? Name { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; } public CSharpArgumentInfo TargetArgumentInfo { get; }
public DynamicGetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target) public DynamicGetMemberInstruction(CSharpBinderFlags binderFlags, string? name, IType? context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target)
: base(OpCode.DynamicGetMemberInstruction, binderFlags, context) : base(OpCode.DynamicGetMemberInstruction, binderFlags, context)
{ {
Name = name; Name = name;
@ -249,11 +250,11 @@ namespace ICSharpCode.Decompiler.IL
partial class DynamicSetMemberInstruction partial class DynamicSetMemberInstruction
{ {
public string Name { get; } public string? Name { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; } public CSharpArgumentInfo TargetArgumentInfo { get; }
public CSharpArgumentInfo ValueArgumentInfo { get; } public CSharpArgumentInfo ValueArgumentInfo { get; }
public DynamicSetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target, CSharpArgumentInfo valueArgumentInfo, ILInstruction value) public DynamicSetMemberInstruction(CSharpBinderFlags binderFlags, string? name, IType? context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target, CSharpArgumentInfo valueArgumentInfo, ILInstruction value)
: base(OpCode.DynamicSetMemberInstruction, binderFlags, context) : base(OpCode.DynamicSetMemberInstruction, binderFlags, context)
{ {
Name = name; Name = name;
@ -293,7 +294,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; } public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicGetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) public DynamicGetIndexInstruction(CSharpBinderFlags binderFlags, IType? context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicGetIndexInstruction, binderFlags, context) : base(OpCode.DynamicGetIndexInstruction, binderFlags, context)
{ {
ArgumentInfo = argumentInfo; ArgumentInfo = argumentInfo;
@ -325,7 +326,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; } public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicSetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) public DynamicSetIndexInstruction(CSharpBinderFlags binderFlags, IType? context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicSetIndexInstruction, binderFlags, context) : base(OpCode.DynamicSetIndexInstruction, binderFlags, context)
{ {
ArgumentInfo = argumentInfo; ArgumentInfo = argumentInfo;
@ -355,11 +356,11 @@ namespace ICSharpCode.Decompiler.IL
partial class DynamicInvokeConstructorInstruction partial class DynamicInvokeConstructorInstruction
{ {
readonly IType resultType; readonly IType? resultType;
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; } public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeConstructorInstruction(CSharpBinderFlags binderFlags, IType type, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) public DynamicInvokeConstructorInstruction(CSharpBinderFlags binderFlags, IType? type, IType? context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeConstructorInstruction, binderFlags, context) : base(OpCode.DynamicInvokeConstructorInstruction, binderFlags, context)
{ {
ArgumentInfo = argumentInfo; ArgumentInfo = argumentInfo;
@ -395,7 +396,7 @@ namespace ICSharpCode.Decompiler.IL
public CSharpArgumentInfo RightArgumentInfo { get; } public CSharpArgumentInfo RightArgumentInfo { get; }
public ExpressionType Operation { get; } public ExpressionType Operation { get; }
public DynamicBinaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right) public DynamicBinaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType? context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right)
: base(OpCode.DynamicBinaryOperatorInstruction, binderFlags, context) : base(OpCode.DynamicBinaryOperatorInstruction, binderFlags, context)
{ {
Operation = operation; Operation = operation;
@ -437,7 +438,7 @@ namespace ICSharpCode.Decompiler.IL
public CSharpArgumentInfo RightArgumentInfo { get; } public CSharpArgumentInfo RightArgumentInfo { get; }
public ExpressionType Operation { get; } public ExpressionType Operation { get; }
public DynamicLogicOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right) public DynamicLogicOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType? context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right)
: base(OpCode.DynamicLogicOperatorInstruction, binderFlags, context) : base(OpCode.DynamicLogicOperatorInstruction, binderFlags, context)
{ {
Operation = operation; Operation = operation;
@ -486,7 +487,7 @@ namespace ICSharpCode.Decompiler.IL
public CSharpArgumentInfo OperandArgumentInfo { get; } public CSharpArgumentInfo OperandArgumentInfo { get; }
public ExpressionType Operation { get; } public ExpressionType Operation { get; }
public DynamicUnaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo operandArgumentInfo, ILInstruction operand) public DynamicUnaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType? context, CSharpArgumentInfo operandArgumentInfo, ILInstruction operand)
: base(OpCode.DynamicUnaryOperatorInstruction, binderFlags, context) : base(OpCode.DynamicUnaryOperatorInstruction, binderFlags, context)
{ {
Operation = operation; Operation = operation;
@ -533,7 +534,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; } public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) public DynamicInvokeInstruction(CSharpBinderFlags binderFlags, IType? context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeInstruction, binderFlags, context) : base(OpCode.DynamicInvokeInstruction, binderFlags, context)
{ {
ArgumentInfo = argumentInfo; ArgumentInfo = argumentInfo;
@ -562,9 +563,9 @@ namespace ICSharpCode.Decompiler.IL
partial class DynamicIsEventInstruction partial class DynamicIsEventInstruction
{ {
public string Name { get; } public string? Name { get; }
public DynamicIsEventInstruction(CSharpBinderFlags binderFlags, string name, IType context, ILInstruction argument) public DynamicIsEventInstruction(CSharpBinderFlags binderFlags, string? name, IType? context, ILInstruction argument)
: base(OpCode.DynamicIsEventInstruction, binderFlags, context) : base(OpCode.DynamicIsEventInstruction, binderFlags, context)
{ {
Name = name; Name = name;

7
ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs

@ -1,7 +1,4 @@
using System; #nullable enable
using System.Collections.Generic;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -13,7 +10,7 @@ namespace ICSharpCode.Decompiler.IL
public ExpressionTreeCast(IType type, ILInstruction argument, bool isChecked) public ExpressionTreeCast(IType type, ILInstruction argument, bool isChecked)
: base(OpCode.ExpressionTreeCast, argument) : base(OpCode.ExpressionTreeCast, argument)
{ {
this.Type = type; this.type = type;
this.IsChecked = isChecked; this.IsChecked = isChecked;
} }

39
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -18,7 +19,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.IL
/// May be null for functions that were not constructed from metadata, /// May be null for functions that were not constructed from metadata,
/// e.g., expression trees. /// e.g., expression trees.
/// </summary> /// </summary>
public readonly IMethod Method; public readonly IMethod? Method;
/// <summary> /// <summary>
/// Gets the generic context of this function. /// Gets the generic context of this function.
@ -54,7 +54,7 @@ namespace ICSharpCode.Decompiler.IL
/// has no effect, as the name should not be used in the final AST construction. /// has no effect, as the name should not be used in the final AST construction.
/// </para> /// </para>
/// </summary> /// </summary>
public string Name; public string? Name;
/// <summary> /// <summary>
/// Size of the IL code in this function. /// Size of the IL code in this function.
@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.IL
/// Gets the scope in which the local function is declared. /// Gets the scope in which the local function is declared.
/// Returns null, if this is not a local function. /// Returns null, if this is not a local function.
/// </summary> /// </summary>
public BlockContainer DeclarationScope { get; internal set; } public BlockContainer? DeclarationScope { get; internal set; }
/// <summary> /// <summary>
/// Gets the set of captured variables by this ILFunction. /// Gets the set of captured variables by this ILFunction.
@ -108,17 +108,17 @@ namespace ICSharpCode.Decompiler.IL
/// Return element type -- if the async method returns Task{T}, this field stores T. /// Return element type -- if the async method returns Task{T}, this field stores T.
/// If the async method returns Task or void, this field stores void. /// If the async method returns Task or void, this field stores void.
/// </summary> /// </summary>
public IType AsyncReturnType; public IType? AsyncReturnType;
/// <summary> /// <summary>
/// If this function is an iterator/async, this field stores the compiler-generated MoveNext() method. /// If this function is an iterator/async, this field stores the compiler-generated MoveNext() method.
/// </summary> /// </summary>
public IMethod MoveNextMethod; public IMethod? MoveNextMethod;
/// <summary> /// <summary>
/// If this function is a local function, this field stores the reduced version of the function. /// If this function is a local function, this field stores the reduced version of the function.
/// </summary> /// </summary>
internal TypeSystem.Implementation.LocalFunctionMethod ReducedMethod; internal TypeSystem.Implementation.LocalFunctionMethod? ReducedMethod;
public DebugInfo.AsyncDebugInfo AsyncDebugInfo; public DebugInfo.AsyncDebugInfo AsyncDebugInfo;
@ -131,8 +131,10 @@ namespace ICSharpCode.Decompiler.IL
get { get {
if (ctorCallStart == int.MinValue) if (ctorCallStart == int.MinValue)
{ {
if (!this.Method.IsConstructor || this.Method.IsStatic) if (this.Method == null || !this.Method.IsConstructor || this.Method.IsStatic)
{
ctorCallStart = -1; ctorCallStart = -1;
}
else else
{ {
ctorCallStart = this.Descendants.FirstOrDefault(d => d is CallInstruction call && !(call is NewObj) ctorCallStart = this.Descendants.FirstOrDefault(d => d is CallInstruction call && !(call is NewObj)
@ -150,7 +152,7 @@ namespace ICSharpCode.Decompiler.IL
/// T is the delegate type that matches the signature of this method. /// T is the delegate type that matches the signature of this method.
/// Otherwise this must be null. /// Otherwise this must be null.
/// </summary> /// </summary>
public IType DelegateType; public IType? DelegateType;
ILFunctionKind kind; ILFunctionKind kind;
@ -181,7 +183,7 @@ namespace ICSharpCode.Decompiler.IL
/// where the stack is empty, nop instructions, and the instruction following /// where the stack is empty, nop instructions, and the instruction following
/// a call instruction /// a call instruction
/// </summary> /// </summary>
public List<int> SequencePointCandidates { get; set; } public List<int>? SequencePointCandidates { get; set; }
/// <summary> /// <summary>
/// Constructs a new ILFunction from the given metadata and with the given ILAst body. /// Constructs a new ILFunction from the given metadata and with the given ILAst body.
@ -408,20 +410,9 @@ namespace ICSharpCode.Decompiler.IL
int helperVariableCount; int helperVariableCount;
public ILVariable RegisterVariable(VariableKind kind, IType type, string name = null) public ILVariable RegisterVariable(VariableKind kind, IType type, string? name = null)
{
return RegisterVariable(kind, type, type.GetStackType(), name);
}
public ILVariable RegisterVariable(VariableKind kind, StackType stackType, string name = null)
{
var type = Method.Compilation.FindType(stackType.ToKnownTypeCode());
return RegisterVariable(kind, type, stackType, name);
}
ILVariable RegisterVariable(VariableKind kind, IType type, StackType stackType, string name = null)
{ {
var variable = new ILVariable(kind, type, stackType); var variable = new ILVariable(kind, type);
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
{ {
name = "I_" + (helperVariableCount++); name = "I_" + (helperVariableCount++);

22
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -21,9 +21,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.IL.Patterns; using ICSharpCode.Decompiler.IL.Patterns;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -60,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL
this.OpCode = opCode; this.OpCode = opCode;
} }
protected void ValidateChild(ILInstruction inst) protected void ValidateChild(ILInstruction? inst)
{ {
if (inst == null) if (inst == null)
throw new ArgumentNullException(nameof(inst)); throw new ArgumentNullException(nameof(inst));
@ -69,6 +71,16 @@ namespace ICSharpCode.Decompiler.IL
// make sure to read the remarks on the ReplaceWith() method. // make sure to read the remarks on the ReplaceWith() method.
} }
internal static void DebugAssert([DoesNotReturnIf(false)] bool b)
{
Debug.Assert(b);
}
internal static void DebugAssert([DoesNotReturnIf(false)] bool b, string msg)
{
Debug.Assert(b, msg);
}
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal virtual void CheckInvariant(ILPhase phase) internal virtual void CheckInvariant(ILPhase phase)
{ {
@ -493,7 +505,7 @@ namespace ICSharpCode.Decompiler.IL
internal ChildrenEnumerator(ILInstruction inst) internal ChildrenEnumerator(ILInstruction inst)
{ {
Debug.Assert(inst != null); DebugAssert(inst != null);
this.inst = inst; this.inst = inst;
this.pos = -1; this.pos = -1;
this.end = inst!.GetChildCount(); this.end = inst!.GetChildCount();
@ -899,9 +911,9 @@ namespace ICSharpCode.Decompiler.IL
/// If extraction is not possible, the ILAst is left unmodified and the function returns null. /// If extraction is not possible, the ILAst is left unmodified and the function returns null.
/// May return null if extraction is not possible. /// May return null if extraction is not possible.
/// </summary> /// </summary>
public ILVariable Extract() public ILVariable Extract(ILTransformContext context)
{ {
return Transforms.ExtractionContext.Extract(this); return Transforms.ExtractionContext.Extract(this, context);
} }
/// <summary> /// <summary>
@ -950,7 +962,7 @@ namespace ICSharpCode.Decompiler.IL
public interface IInstructionWithMethodOperand public interface IInstructionWithMethodOperand
{ {
IMethod Method { get; } IMethod? Method { get; }
} }
public interface ILiftableInstruction public interface ILiftableInstruction

5
ICSharpCode.Decompiler/IL/Instructions/ILVariableCollection.cs

@ -1,4 +1,5 @@
// Copyright (c) 2016 Daniel Grunwald #nullable enable
// Copyright (c) 2016 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -128,7 +129,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
// However, remove unused this-parameters of delegates, expression trees, etc. // However, remove unused this-parameters of delegates, expression trees, etc.
// These will be replaced with the top-level function's this-parameter. // These will be replaced with the top-level function's this-parameter.
if (v.Index == -1 && v.Function.Kind != ILFunctionKind.TopLevelFunction) if (v.Index == -1 && v.Function!.Kind != ILFunctionKind.TopLevelFunction)
return true; return true;
return false; return false;
} }

9
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -35,7 +36,7 @@ namespace ICSharpCode.Decompiler.IL
/// </remarks> /// </remarks>
partial class IfInstruction : ILInstruction partial class IfInstruction : ILInstruction
{ {
public IfInstruction(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst = null) : base(OpCode.IfInstruction) public IfInstruction(ILInstruction condition, ILInstruction trueInst, ILInstruction? falseInst = null) : base(OpCode.IfInstruction)
{ {
this.Condition = condition; this.Condition = condition;
this.TrueInst = trueInst; this.TrueInst = trueInst;
@ -47,7 +48,7 @@ namespace ICSharpCode.Decompiler.IL
return new IfInstruction(lhs, rhs, new LdcI4(0)); return new IfInstruction(lhs, rhs, new LdcI4(0));
} }
public static IfInstruction LogicOr(ILInstruction lhs, ILInstruction rhs) public static IfInstruction LogicOr(ILInstruction lhs, ILInstruction? rhs)
{ {
return new IfInstruction(lhs, new LdcI4(1), rhs); return new IfInstruction(lhs, new LdcI4(1), rhs);
} }
@ -126,7 +127,7 @@ namespace ICSharpCode.Decompiler.IL
if (slot == IfInstruction.ConditionSlot) if (slot == IfInstruction.ConditionSlot)
return true; return true;
if (slot == IfInstruction.TrueInstSlot || slot == IfInstruction.FalseInstSlot || slot == NullCoalescingInstruction.FallbackInstSlot) if (slot == IfInstruction.TrueInstSlot || slot == IfInstruction.FalseInstSlot || slot == NullCoalescingInstruction.FallbackInstSlot)
return IsInConditionSlot(inst.Parent); return IsInConditionSlot(inst.Parent!);
if (inst.Parent is Comp comp) if (inst.Parent is Comp comp)
{ {
if (comp.Left == inst && comp.Right.MatchLdcI4(0)) if (comp.Left == inst && comp.Right.MatchLdcI4(0))

3
ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

3
ICSharpCode.Decompiler/IL/Instructions/LdLen.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

13
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -32,9 +33,9 @@ namespace ICSharpCode.Decompiler.IL
/// </remarks> /// </remarks>
partial class Leave : ILInstruction, IBranchOrLeaveInstruction partial class Leave : ILInstruction, IBranchOrLeaveInstruction
{ {
BlockContainer targetContainer; BlockContainer? targetContainer;
public Leave(BlockContainer targetContainer, ILInstruction value = null) : base(OpCode.Leave) public Leave(BlockContainer? targetContainer, ILInstruction? value = null) : base(OpCode.Leave)
{ {
// Note: ILReader will create Leave instructions with targetContainer==null to represent 'endfinally', // Note: ILReader will create Leave instructions with targetContainer==null to represent 'endfinally',
// the targetContainer will then be filled in by BlockBuilder // the targetContainer will then be filled in by BlockBuilder
@ -54,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public BlockContainer TargetContainer { public BlockContainer TargetContainer {
get { return targetContainer; } get { return targetContainer!; }
set { set {
if (targetContainer != null && IsConnected) if (targetContainer != null && IsConnected)
targetContainer.LeaveCount--; targetContainer.LeaveCount--;
@ -109,8 +110,8 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(targetContainer)); Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(targetContainer!));
Debug.Assert(phase <= ILPhase.InILReader || phase == ILPhase.InAsyncAwait || value.ResultType == targetContainer.ResultType); Debug.Assert(phase <= ILPhase.InILReader || phase == ILPhase.InAsyncAwait || value.ResultType == targetContainer!.ResultType);
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)

3
ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Siegfried Pammer #nullable enable
// Copyright (c) 2017 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

3
ICSharpCode.Decompiler/IL/Instructions/LogicInstructions.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Daniel Grunwald #nullable enable
// Copyright (c) 2017 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

30
ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2020 Siegfried Pammer #nullable enable
// Copyright (c) 2020 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -18,10 +19,9 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Diagnostics.CodeAnalysis;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
partial class MatchInstruction : ILInstruction partial class MatchInstruction : ILInstruction
@ -96,7 +96,7 @@ namespace ICSharpCode.Decompiler.IL
public int NumPositionalPatterns { public int NumPositionalPatterns {
get { get {
if (IsDeconstructCall) if (IsDeconstructCall)
return method.Parameters.Count - (method.IsStatic ? 1 : 0); return method!.Parameters.Count - (method.IsStatic ? 1 : 0);
else if (IsDeconstructTuple) else if (IsDeconstructTuple)
return TupleType.GetTupleElementTypes(variable.Type).Length; return TupleType.GetTupleElementTypes(variable.Type).Length;
else else
@ -118,7 +118,7 @@ namespace ICSharpCode.Decompiler.IL
/// (even if the pattern fails to match!). /// (even if the pattern fails to match!).
/// The pattern matching instruction evaluates to 1 (as I4) if the pattern matches, or 0 otherwise. /// The pattern matching instruction evaluates to 1 (as I4) if the pattern matches, or 0 otherwise.
/// </summary> /// </summary>
public static bool IsPatternMatch(ILInstruction inst, out ILInstruction testedOperand) public static bool IsPatternMatch(ILInstruction? inst, [NotNullWhen(true)] out ILInstruction? testedOperand)
{ {
switch (inst) switch (inst)
{ {
@ -153,9 +153,9 @@ namespace ICSharpCode.Decompiler.IL
{ {
if (this.IsDeconstructCall) if (this.IsDeconstructCall)
{ {
int firstOutParam = (method.IsStatic ? 1 : 0); int firstOutParam = (method!.IsStatic ? 1 : 0);
var outParamType = this.Method.Parameters[firstOutParam + index].Type; var outParamType = method.Parameters[firstOutParam + index].Type;
if (!(outParamType is ByReferenceType brt)) if (outParamType is not ByReferenceType brt)
throw new InvalidOperationException("deconstruct out param must be by reference"); throw new InvalidOperationException("deconstruct out param must be by reference");
return brt.ElementType; return brt.ElementType;
} }
@ -185,8 +185,8 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(SubPatterns.Count >= NumPositionalPatterns); Debug.Assert(SubPatterns.Count >= NumPositionalPatterns);
foreach (var subPattern in SubPatterns) foreach (var subPattern in SubPatterns)
{ {
if (!IsPatternMatch(subPattern, out ILInstruction operand)) if (!IsPatternMatch(subPattern, out ILInstruction? operand))
Debug.Fail("Sub-Pattern must be a valid pattern"); throw new InvalidOperationException("Sub-Pattern must be a valid pattern");
// the first child is TestedOperand // the first child is TestedOperand
int subPatternIndex = subPattern.ChildIndex - 1; int subPatternIndex = subPattern.ChildIndex - 1;
if (subPatternIndex < NumPositionalPatterns) if (subPatternIndex < NumPositionalPatterns)
@ -210,8 +210,11 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal static bool IsDeconstructMethod(IMethod method) internal static bool IsDeconstructMethod(IMethod? method)
{ {
if (method == null
)
return false;
if (method.Name != "Deconstruct") if (method.Name != "Deconstruct")
return false; return false;
if (method.ReturnType.Kind != TypeKind.Void) if (method.ReturnType.Kind != TypeKind.Void)
@ -260,7 +263,10 @@ namespace ICSharpCode.Decompiler.IL
if (IsDeconstructCall) if (IsDeconstructCall)
{ {
output.Write(".deconstruct["); output.Write(".deconstruct[");
method.WriteTo(output); if (method == null)
output.Write("<null>");
else
method.WriteTo(output);
output.Write(']'); output.Write(']');
} }
if (IsDeconstructTuple) if (IsDeconstructTuple)

3
ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

3
ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Siegfried Pammer #nullable enable
// Copyright (c) 2017 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

3
ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs

@ -1,4 +1,5 @@
// Copyright (c) 2018 Daniel Grunwald #nullable enable
// Copyright (c) 2018 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

75
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -16,8 +17,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using ICSharpCode.Decompiler.TypeSystem; using System.Diagnostics.CodeAnalysis;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
partial class ILInstruction partial class ILInstruction
@ -73,13 +75,13 @@ namespace ICSharpCode.Decompiler.IL
return MatchLdcI(out long v) && v == val; return MatchLdcI(out long v) && v == val;
} }
public bool MatchLdLoc(ILVariable variable) public bool MatchLdLoc(ILVariable? variable)
{ {
var inst = this as LdLoc; var inst = this as LdLoc;
return inst != null && inst.Variable == variable; return inst != null && inst.Variable == variable;
} }
public bool MatchLdLoca(ILVariable variable) public bool MatchLdLoca(ILVariable? variable)
{ {
var inst = this as LdLoca; var inst = this as LdLoca;
return inst != null && inst.Variable == variable; return inst != null && inst.Variable == variable;
@ -88,7 +90,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches either ldloc (if the variable is a reference type), or ldloca (otherwise). /// Matches either ldloc (if the variable is a reference type), or ldloca (otherwise).
/// </summary> /// </summary>
public bool MatchLdLocRef(ILVariable variable) public bool MatchLdLocRef(ILVariable? variable)
{ {
return MatchLdLocRef(out var v) && v == variable; return MatchLdLocRef(out var v) && v == variable;
} }
@ -96,7 +98,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches either ldloc (if the variable is a reference type), or ldloca (otherwise). /// Matches either ldloc (if the variable is a reference type), or ldloca (otherwise).
/// </summary> /// </summary>
public bool MatchLdLocRef(out ILVariable variable) public bool MatchLdLocRef([NotNullWhen(true)] out ILVariable? variable)
{ {
switch (this) switch (this)
{ {
@ -118,7 +120,7 @@ namespace ICSharpCode.Decompiler.IL
return inst != null && inst.Variable.Kind == VariableKind.Parameter && inst.Variable.Index < 0; return inst != null && inst.Variable.Kind == VariableKind.Parameter && inst.Variable.Index < 0;
} }
public bool MatchStLoc(out ILVariable variable) public bool MatchStLoc([NotNullWhen(true)] out ILVariable? variable)
{ {
var inst = this as StLoc; var inst = this as StLoc;
if (inst != null) if (inst != null)
@ -130,7 +132,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchStLoc(ILVariable variable, out ILInstruction value) public bool MatchStLoc(ILVariable? variable, [NotNullWhen(true)] out ILInstruction? value)
{ {
var inst = this as StLoc; var inst = this as StLoc;
if (inst != null && inst.Variable == variable) if (inst != null && inst.Variable == variable)
@ -142,7 +144,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchLdLen(StackType type, out ILInstruction array) public bool MatchLdLen(StackType type, [NotNullWhen(true)] out ILInstruction? array)
{ {
var inst = this as LdLen; var inst = this as LdLen;
if (inst != null && inst.ResultType == type) if (inst != null && inst.ResultType == type)
@ -154,7 +156,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchReturn(out ILInstruction value) public bool MatchReturn([NotNullWhen(true)] out ILInstruction? value)
{ {
var inst = this as Leave; var inst = this as Leave;
if (inst != null && inst.IsLeavingFunction) if (inst != null && inst.IsLeavingFunction)
@ -166,7 +168,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchBranch(out Block targetBlock) public bool MatchBranch([NotNullWhen(true)] out Block? targetBlock)
{ {
var inst = this as Branch; var inst = this as Branch;
if (inst != null) if (inst != null)
@ -178,13 +180,13 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchBranch(Block targetBlock) public bool MatchBranch(Block? targetBlock)
{ {
var inst = this as Branch; var inst = this as Branch;
return inst != null && inst.TargetBlock == targetBlock; return inst != null && inst.TargetBlock == targetBlock;
} }
public bool MatchLeave(out BlockContainer targetContainer, out ILInstruction value) public bool MatchLeave([NotNullWhen(true)] out BlockContainer? targetContainer, [NotNullWhen(true)] out ILInstruction? value)
{ {
var inst = this as Leave; var inst = this as Leave;
if (inst != null) if (inst != null)
@ -198,7 +200,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchLeave(BlockContainer targetContainer, out ILInstruction value) public bool MatchLeave(BlockContainer? targetContainer, [NotNullWhen(true)] out ILInstruction? value)
{ {
var inst = this as Leave; var inst = this as Leave;
if (inst != null && targetContainer == inst.TargetContainer) if (inst != null && targetContainer == inst.TargetContainer)
@ -210,7 +212,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchLeave(out BlockContainer targetContainer) public bool MatchLeave([NotNullWhen(true)] out BlockContainer? targetContainer)
{ {
var inst = this as Leave; var inst = this as Leave;
if (inst != null && inst.Value.MatchNop()) if (inst != null && inst.Value.MatchNop())
@ -222,16 +224,15 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchLeave(BlockContainer targetContainer) public bool MatchLeave(BlockContainer? targetContainer)
{ {
var inst = this as Leave; var inst = this as Leave;
return inst != null && inst.TargetContainer == targetContainer && inst.Value.MatchNop(); return inst != null && inst.TargetContainer == targetContainer && inst.Value.MatchNop();
} }
public bool MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst) public bool MatchIfInstruction([NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out ILInstruction? trueInst, [NotNullWhen(true)] out ILInstruction? falseInst)
{ {
var inst = this as IfInstruction; if (this is IfInstruction inst)
if (inst != null)
{ {
condition = inst.Condition; condition = inst.Condition;
trueInst = inst.TrueInst; trueInst = inst.TrueInst;
@ -244,7 +245,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchIfInstructionPositiveCondition(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst) public bool MatchIfInstructionPositiveCondition([NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out ILInstruction? trueInst, [NotNullWhen(true)] out ILInstruction? falseInst)
{ {
if (MatchIfInstruction(out condition, out trueInst, out falseInst)) if (MatchIfInstruction(out condition, out trueInst, out falseInst))
{ {
@ -252,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL
while (condition.MatchLogicNot(out var arg)) while (condition.MatchLogicNot(out var arg))
{ {
condition = arg; condition = arg;
ILInstruction tmp = trueInst; ILInstruction? tmp = trueInst;
trueInst = falseInst; trueInst = falseInst;
falseInst = tmp; falseInst = tmp;
} }
@ -264,7 +265,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches an if instruction where the false instruction is a nop. /// Matches an if instruction where the false instruction is a nop.
/// </summary> /// </summary>
public bool MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst) public bool MatchIfInstruction([NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out ILInstruction? trueInst)
{ {
var inst = this as IfInstruction; var inst = this as IfInstruction;
if (inst != null && inst.FalseInst.MatchNop()) if (inst != null && inst.FalseInst.MatchNop())
@ -283,7 +284,7 @@ namespace ICSharpCode.Decompiler.IL
/// Note: unlike C# '&amp;&amp;', this instruction is not limited to booleans, /// Note: unlike C# '&amp;&amp;', this instruction is not limited to booleans,
/// but allows passing through arbitrary I4 values on the rhs (but not on the lhs). /// but allows passing through arbitrary I4 values on the rhs (but not on the lhs).
/// </summary> /// </summary>
public bool MatchLogicAnd(out ILInstruction lhs, out ILInstruction rhs) public bool MatchLogicAnd([NotNullWhen(true)] out ILInstruction? lhs, [NotNullWhen(true)] out ILInstruction? rhs)
{ {
var inst = this as IfInstruction; var inst = this as IfInstruction;
if (inst != null && inst.FalseInst.MatchLdcI4(0)) if (inst != null && inst.FalseInst.MatchLdcI4(0))
@ -302,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL
/// Note: unlike C# '||', this instruction is not limited to booleans, /// Note: unlike C# '||', this instruction is not limited to booleans,
/// but allows passing through arbitrary I4 values on the rhs (but not on the lhs). /// but allows passing through arbitrary I4 values on the rhs (but not on the lhs).
/// </summary> /// </summary>
public bool MatchLogicOr(out ILInstruction lhs, out ILInstruction rhs) public bool MatchLogicOr([NotNullWhen(true)] out ILInstruction? lhs, [NotNullWhen(true)] out ILInstruction? rhs)
{ {
var inst = this as IfInstruction; var inst = this as IfInstruction;
if (inst != null && inst.TrueInst.MatchLdcI4(1)) if (inst != null && inst.TrueInst.MatchLdcI4(1))
@ -319,7 +320,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches an logical negation. /// Matches an logical negation.
/// </summary> /// </summary>
public bool MatchLogicNot(out ILInstruction arg) public bool MatchLogicNot([NotNullWhen(true)] out ILInstruction? arg)
{ {
if (this is Comp comp && comp.Kind == ComparisonKind.Equality if (this is Comp comp && comp.Kind == ComparisonKind.Equality
&& comp.LiftingKind == ComparisonLiftingKind.None && comp.LiftingKind == ComparisonLiftingKind.None
@ -332,7 +333,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchTryCatchHandler(out ILVariable variable) public bool MatchTryCatchHandler([NotNullWhen(true)] out ILVariable? variable)
{ {
var inst = this as TryCatchHandler; var inst = this as TryCatchHandler;
if (inst != null) if (inst != null)
@ -347,7 +348,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches comp(left == right) or logic.not(comp(left != right)). /// Matches comp(left == right) or logic.not(comp(left != right)).
/// </summary> /// </summary>
public bool MatchCompEquals(out ILInstruction left, out ILInstruction right) public bool MatchCompEquals([NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right)
{ {
ILInstruction thisInst = this; ILInstruction thisInst = this;
var compKind = ComparisonKind.Equality; var compKind = ComparisonKind.Equality;
@ -376,7 +377,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches 'comp(arg == ldnull)' /// Matches 'comp(arg == ldnull)'
/// </summary> /// </summary>
public bool MatchCompEqualsNull(out ILInstruction arg) public bool MatchCompEqualsNull([NotNullWhen(true)] out ILInstruction? arg)
{ {
if (!MatchCompEquals(out var left, out var right)) if (!MatchCompEquals(out var left, out var right))
{ {
@ -403,7 +404,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches 'comp(arg != ldnull)' /// Matches 'comp(arg != ldnull)'
/// </summary> /// </summary>
public bool MatchCompNotEqualsNull(out ILInstruction arg) public bool MatchCompNotEqualsNull([NotNullWhen(true)] out ILInstruction? arg)
{ {
if (!MatchCompNotEquals(out var left, out var right)) if (!MatchCompNotEquals(out var left, out var right))
{ {
@ -430,7 +431,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Matches comp(left != right) or logic.not(comp(left == right)). /// Matches comp(left != right) or logic.not(comp(left == right)).
/// </summary> /// </summary>
public bool MatchCompNotEquals(out ILInstruction left, out ILInstruction right) public bool MatchCompNotEquals([NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right)
{ {
ILInstruction thisInst = this; ILInstruction thisInst = this;
var compKind = ComparisonKind.Inequality; var compKind = ComparisonKind.Inequality;
@ -456,7 +457,7 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
public bool MatchLdFld(out ILInstruction target, out IField field) public bool MatchLdFld([NotNullWhen(true)] out ILInstruction? target, [NotNullWhen(true)] out IField? field)
{ {
if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile)
{ {
@ -472,7 +473,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchLdsFld(out IField field) public bool MatchLdsFld([NotNullWhen(true)] out IField? field)
{ {
if (this is LdObj ldobj && ldobj.Target is LdsFlda ldsflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) if (this is LdObj ldobj && ldobj.Target is LdsFlda ldsflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile)
{ {
@ -483,12 +484,12 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchLdsFld(IField field) public bool MatchLdsFld(IField? field)
{ {
return MatchLdsFld(out var f) && f.Equals(field); return MatchLdsFld(out var f) && f.Equals(field);
} }
public bool MatchStsFld(out IField field, out ILInstruction value) public bool MatchStsFld([NotNullWhen(true)] out IField? field, [NotNullWhen(true)] out ILInstruction? value)
{ {
if (this is StObj stobj && stobj.Target is LdsFlda ldsflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile) if (this is StObj stobj && stobj.Target is LdsFlda ldsflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile)
{ {
@ -501,7 +502,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchStFld(out ILInstruction target, out IField field, out ILInstruction value) public bool MatchStFld([NotNullWhen(true)] out ILInstruction? target, [NotNullWhen(true)] out IField? field, [NotNullWhen(true)] out ILInstruction? value)
{ {
if (this is StObj stobj && stobj.Target is LdFlda ldflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile) if (this is StObj stobj && stobj.Target is LdFlda ldflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile)
{ {
@ -522,7 +523,7 @@ namespace ICSharpCode.Decompiler.IL
return op != null && op.Operator == @operator; return op != null && op.Operator == @operator;
} }
public bool MatchBinaryNumericInstruction(BinaryNumericOperator @operator, out ILInstruction left, out ILInstruction right) public bool MatchBinaryNumericInstruction(BinaryNumericOperator @operator, [NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right)
{ {
var op = this as BinaryNumericInstruction; var op = this as BinaryNumericInstruction;
if (op != null && op.Operator == @operator) if (op != null && op.Operator == @operator)
@ -536,7 +537,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
public bool MatchBinaryNumericInstruction(out BinaryNumericOperator @operator, out ILInstruction left, out ILInstruction right) public bool MatchBinaryNumericInstruction(out BinaryNumericOperator @operator, [NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right)
{ {
var op = this as BinaryNumericInstruction; var op = this as BinaryNumericInstruction;
if (op != null) if (op != null)

13
ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -40,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL
partial class Nop partial class Nop
{ {
public string Comment; public string? Comment;
public NopKind Kind; public NopKind Kind;
@ -61,10 +62,10 @@ namespace ICSharpCode.Decompiler.IL
partial class InvalidBranch : SimpleInstruction partial class InvalidBranch : SimpleInstruction
{ {
public string Message; public string? Message;
public StackType ExpectedResultType = StackType.Void; public StackType ExpectedResultType = StackType.Void;
public InvalidBranch(string message) : this() public InvalidBranch(string? message) : this()
{ {
this.Message = message; this.Message = message;
} }
@ -88,10 +89,10 @@ namespace ICSharpCode.Decompiler.IL
partial class InvalidExpression : SimpleInstruction partial class InvalidExpression : SimpleInstruction
{ {
public string Message; public string? Message;
public StackType ExpectedResultType = StackType.Unknown; public StackType ExpectedResultType = StackType.Unknown;
public InvalidExpression(string message) : this() public InvalidExpression(string? message) : this()
{ {
this.Message = message; this.Message = message;
} }

7
ICSharpCode.Decompiler/IL/Instructions/StLoc.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -38,8 +39,8 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function)); Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));
Debug.Assert(phase <= ILPhase.InILReader || variable.Function.Variables[variable.IndexInFunction] == variable); Debug.Assert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);
Debug.Assert(value.ResultType == variable.StackType); Debug.Assert(value.ResultType == variable.StackType);
} }
} }

13
ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Siegfried Pammer #nullable enable
// Copyright (c) 2017 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -23,23 +24,23 @@ namespace ICSharpCode.Decompiler.IL
{ {
partial class StringToInt partial class StringToInt
{ {
public List<(string Key, int Value)> Map { get; } public List<(string? Key, int Value)> Map { get; }
public StringToInt(ILInstruction argument, List<(string Key, int Value)> map) public StringToInt(ILInstruction argument, List<(string? Key, int Value)> map)
: base(OpCode.StringToInt) : base(OpCode.StringToInt)
{ {
this.Argument = argument; this.Argument = argument;
this.Map = map; this.Map = map;
} }
public StringToInt(ILInstruction argument, string[] map) public StringToInt(ILInstruction argument, string?[] map)
: this(argument, ArrayToDictionary(map)) : this(argument, ArrayToDictionary(map))
{ {
} }
static List<(string Key, int Value)> ArrayToDictionary(string[] map) static List<(string? Key, int Value)> ArrayToDictionary(string?[] map)
{ {
var dict = new List<(string Key, int Value)>(); var dict = new List<(string? Key, int Value)>();
for (int i = 0; i < map.Length; i++) for (int i = 0; i < map.Length; i++)
{ {
dict.Add((map[i], i)); dict.Add((map[i], i));

4
ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs

@ -1,3 +1,4 @@
#nullable enable
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team // Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // Permission is hereby granted, free of charge, to any person obtaining a copy of this
@ -16,7 +17,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.IL
this.Sections = new InstructionCollection<SwitchSection>(this, 1); this.Sections = new InstructionCollection<SwitchSection>(this, 1);
} }
ILInstruction value; ILInstruction value = null!;
public ILInstruction Value { public ILInstruction Value {
get { return this.value; } get { return this.value; }
set { set {

11
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -33,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL
this.TryBlock = tryBlock; this.TryBlock = tryBlock;
} }
ILInstruction tryBlock; ILInstruction tryBlock = null!;
public ILInstruction TryBlock { public ILInstruction TryBlock {
get { return this.tryBlock; } get { return this.tryBlock; }
set { set {
@ -144,7 +145,7 @@ namespace ICSharpCode.Decompiler.IL
base.CheckInvariant(phase); base.CheckInvariant(phase);
Debug.Assert(Parent is TryCatch); Debug.Assert(Parent is TryCatch);
Debug.Assert(filter.ResultType == StackType.I4); Debug.Assert(filter.ResultType == StackType.I4);
Debug.Assert(this.IsDescendantOf(variable.Function)); Debug.Assert(this.IsDescendantOf(variable.Function!));
} }
public override StackType ResultType { public override StackType ResultType {
@ -202,7 +203,7 @@ namespace ICSharpCode.Decompiler.IL
this.FinallyBlock = finallyBlock; this.FinallyBlock = finallyBlock;
} }
ILInstruction finallyBlock; ILInstruction finallyBlock = null!;
public ILInstruction FinallyBlock { public ILInstruction FinallyBlock {
get { return this.finallyBlock; } get { return this.finallyBlock; }
set { set {
@ -299,7 +300,7 @@ namespace ICSharpCode.Decompiler.IL
this.FaultBlock = faultBlock; this.FaultBlock = faultBlock;
} }
ILInstruction faultBlock; ILInstruction faultBlock = null!;
public ILInstruction FaultBlock { public ILInstruction FaultBlock {
get { return this.faultBlock; } get { return this.faultBlock; }
set { set {

3
ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

3
ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs

@ -1,4 +1,5 @@
// Copyright (c) 2017 Siegfried Pammer #nullable enable
// Copyright (c) 2017 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

16
ICSharpCode.Decompiler/IL/Patterns/AnyNode.cs

@ -1,8 +1,5 @@
using System; #nullable enable
using System.Collections.Generic; using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL.Patterns namespace ICSharpCode.Decompiler.IL.Patterns
{ {
@ -37,19 +34,20 @@ namespace ICSharpCode.Decompiler.IL.Patterns
partial class AnyNode : PatternInstruction partial class AnyNode : PatternInstruction
{ {
CaptureGroup group; CaptureGroup? group;
public AnyNode(CaptureGroup group = null) public AnyNode(CaptureGroup? group = null)
: base(OpCode.AnyNode) : base(OpCode.AnyNode)
{ {
this.group = group; this.group = group;
} }
protected internal override bool PerformMatch(ILInstruction other, ref Match match) protected internal override bool PerformMatch(ILInstruction? other, ref Match match)
{ {
if (other == null) if (other == null)
return false; return false;
match.Add(group, other); if (group != null)
match.Add(group, other);
return true; return true;
} }
} }

13
ICSharpCode.Decompiler/IL/Patterns/ListMatch.cs

@ -1,4 +1,5 @@
// Copyright (c) 2016 Daniel Grunwald #nullable enable
// Copyright (c) 2016 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -44,7 +45,7 @@ namespace ICSharpCode.Decompiler.IL.Patterns
/// If the method returns true, it adds the capture groups (if any) to the match. /// If the method returns true, it adds the capture groups (if any) to the match.
/// If the method returns false, the match object remains in a partially-updated state and needs to be restored /// If the method returns false, the match object remains in a partially-updated state and needs to be restored
/// before it can be reused.</returns> /// before it can be reused.</returns>
internal static bool DoMatch(IReadOnlyList<ILInstruction> patterns, IReadOnlyList<ILInstruction> syntaxList, ref Match match) internal static bool DoMatch(IReadOnlyList<ILInstruction> patterns, IReadOnlyList<ILInstruction?> syntaxList, ref Match match)
{ {
ListMatch listMatch = new ListMatch(syntaxList); ListMatch listMatch = new ListMatch(syntaxList);
do do
@ -107,14 +108,14 @@ namespace ICSharpCode.Decompiler.IL.Patterns
/// <summary> /// <summary>
/// The syntax list we are matching against. /// The syntax list we are matching against.
/// </summary> /// </summary>
internal readonly IReadOnlyList<ILInstruction> SyntaxList; internal readonly IReadOnlyList<ILInstruction?> SyntaxList;
/// <summary> /// <summary>
/// The current index in the syntax list. /// The current index in the syntax list.
/// </summary> /// </summary>
internal int SyntaxIndex; internal int SyntaxIndex;
ListMatch(IReadOnlyList<ILInstruction> syntaxList) ListMatch(IReadOnlyList<ILInstruction?> syntaxList)
{ {
this.SyntaxList = syntaxList; this.SyntaxList = syntaxList;
this.SyntaxIndex = 0; this.SyntaxIndex = 0;
@ -122,8 +123,8 @@ namespace ICSharpCode.Decompiler.IL.Patterns
this.restoreStack = null; this.restoreStack = null;
} }
List<SavePoint> backtrackingStack; List<SavePoint>? backtrackingStack;
Stack<int> restoreStack; Stack<int>? restoreStack;
void AddSavePoint(SavePoint savepoint) void AddSavePoint(SavePoint savepoint)
{ {

5
ICSharpCode.Decompiler/IL/Patterns/Match.cs

@ -1,4 +1,5 @@
// Copyright (c) 2016 Daniel Grunwald #nullable enable
// Copyright (c) 2016 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -33,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL.Patterns
{ {
static readonly List<KeyValuePair<CaptureGroup, ILInstruction>> emptyResults = new List<KeyValuePair<CaptureGroup, ILInstruction>>(); static readonly List<KeyValuePair<CaptureGroup, ILInstruction>> emptyResults = new List<KeyValuePair<CaptureGroup, ILInstruction>>();
List<KeyValuePair<CaptureGroup, ILInstruction>> results; List<KeyValuePair<CaptureGroup, ILInstruction>>? results;
/// <summary> /// <summary>
/// Gets whether the match was successful. /// Gets whether the match was successful.

3
ICSharpCode.Decompiler/IL/PrimitiveType.cs

@ -1,4 +1,5 @@
// Copyright (c) 2014 Daniel Grunwald #nullable enable
// Copyright (c) 2014 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

4
ICSharpCode.Decompiler/IL/SemanticHelper.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -89,4 +91,4 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
} }
} }
} }

1
ICSharpCode.Decompiler/IL/SlotInfo.cs

@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {

1
ICSharpCode.Decompiler/IL/StackType.cs

@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {

3
ICSharpCode.Decompiler/IL/Transforms/FixLoneIsInst.cs

@ -16,7 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -63,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
// Use extraction to turn isInst.Argument into a pure instruction, thus making the emulation possible // Use extraction to turn isInst.Argument into a pure instruction, thus making the emulation possible
context.Step("FixLoneIsInst", isInst); context.Step("FixLoneIsInst", isInst);
isInst.Argument.Extract(); isInst.Argument.Extract(context);
} }
} }
} }

3
ICSharpCode.Decompiler/IL/Transforms/FixRemainingIncrements.cs

@ -16,7 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -73,7 +72,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
else else
{ {
context.Step($"Fix {call.Method.Name} call at 0x{call.StartILOffset:x4} using new local", call); context.Step($"Fix {call.Method.Name} call at 0x{call.StartILOffset:x4} using new local", call);
var newVariable = call.Arguments[0].Extract(); var newVariable = call.Arguments[0].Extract(context);
if (newVariable == null) if (newVariable == null)
{ {
Debug.Fail("Failed to extract argument of remaining increment/decrement"); Debug.Fail("Failed to extract argument of remaining increment/decrement");

17
ICSharpCode.Decompiler/IL/Transforms/ILExtraction.cs

@ -21,6 +21,8 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms namespace ICSharpCode.Decompiler.IL.Transforms
{ {
/// <summary> /// <summary>
@ -33,6 +35,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
readonly ILFunction Function; readonly ILFunction Function;
readonly ILTransformContext context;
/// <summary> /// <summary>
/// Combined flags of all instructions being moved. /// Combined flags of all instructions being moved.
/// </summary> /// </summary>
@ -47,17 +51,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
readonly List<Func<ILInstruction>> MoveActions = new List<Func<ILInstruction>>(); readonly List<Func<ILInstruction>> MoveActions = new List<Func<ILInstruction>>();
ExtractionContext(ILFunction function) ExtractionContext(ILFunction function, ILTransformContext context)
{ {
Debug.Assert(function != null); Debug.Assert(function != null);
this.Function = function; this.Function = function;
this.context = context;
} }
internal void RegisterMove(ILInstruction predecessor) internal void RegisterMove(ILInstruction predecessor)
{ {
FlagsBeingMoved |= predecessor.Flags; FlagsBeingMoved |= predecessor.Flags;
MoveActions.Add(delegate { MoveActions.Add(delegate {
var v = Function.RegisterVariable(VariableKind.StackSlot, predecessor.ResultType); var type = context.TypeSystem.FindType(predecessor.ResultType.ToKnownTypeCode());
var v = Function.RegisterVariable(VariableKind.StackSlot, type);
predecessor.ReplaceWith(new LdLoc(v)); predecessor.ReplaceWith(new LdLoc(v));
return new StLoc(v, predecessor); return new StLoc(v, predecessor);
}); });
@ -91,10 +97,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// ///
/// May return null if extraction is not possible. /// May return null if extraction is not possible.
/// </summary> /// </summary>
public static ILVariable Extract(ILInstruction instToExtract) public static ILVariable Extract(ILInstruction instToExtract, ILTransformContext context)
{ {
var function = instToExtract.Ancestors.OfType<ILFunction>().First(); var function = instToExtract.Ancestors.OfType<ILFunction>().First();
ExtractionContext ctx = new ExtractionContext(function); ExtractionContext ctx = new ExtractionContext(function, context);
ctx.FlagsBeingMoved = instToExtract.Flags; ctx.FlagsBeingMoved = instToExtract.Flags;
ILInstruction inst = instToExtract; ILInstruction inst = instToExtract;
while (inst != null) while (inst != null)
@ -113,8 +119,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
// We've reached the target block, and extraction is possible all the way. // We've reached the target block, and extraction is possible all the way.
int insertIndex = inst.ChildIndex; int insertIndex = inst.ChildIndex;
var type = context.TypeSystem.FindType(instToExtract.ResultType.ToKnownTypeCode());
// Move instToExtract itself: // Move instToExtract itself:
var v = function.RegisterVariable(VariableKind.StackSlot, instToExtract.ResultType); var v = function.RegisterVariable(VariableKind.StackSlot, type);
instToExtract.ReplaceWith(new LdLoc(v)); instToExtract.ReplaceWith(new LdLoc(v));
block.Instructions.Insert(insertIndex, new StLoc(v, instToExtract)); block.Instructions.Insert(insertIndex, new StLoc(v, instToExtract));
// Apply the other move actions: // Apply the other move actions:

8
ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs

@ -1,8 +1,5 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -90,7 +87,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
var call = (CallInstruction)arg.Parent; var call = (CallInstruction)arg.Parent;
Debug.Assert(context.Function == call.Ancestors.OfType<ILFunction>().First()); Debug.Assert(context.Function == call.Ancestors.OfType<ILFunction>().First());
var v = context.Function.RegisterVariable(VariableKind.NamedArgument, arg.ResultType); var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode());
var v = context.Function.RegisterVariable(VariableKind.NamedArgument, type);
context.Step($"Introduce named argument '{v.Name}'", arg); context.Step($"Introduce named argument '{v.Name}'", arg);
if (!(call.Parent is Block namedArgBlock) || namedArgBlock.Kind != BlockKind.CallWithNamedArgs) if (!(call.Parent is Block namedArgBlock) || namedArgBlock.Kind != BlockKind.CallWithNamedArgs)
{ {

2
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -257,7 +257,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var otherLoadOfV = v.LoadInstructions.FirstOrDefault(l => !(l.Parent is Cpblk)); var otherLoadOfV = v.LoadInstructions.FirstOrDefault(l => !(l.Parent is Cpblk));
if (otherLoadOfV == null) if (otherLoadOfV == null)
return false; return false;
finalStore = otherLoadOfV.Parent.Extract(); finalStore = otherLoadOfV.Parent.Extract(context);
if (finalStore == null) if (finalStore == null)
return false; return false;
value = ((StLoc)finalStore.StoreInstructions[0]).Value; value = ((StLoc)finalStore.StoreInstructions[0]).Value;

6
ICSharpCode.Decompiler/TypeSystem/IMember.cs

@ -62,6 +62,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary> /// </summary>
IType ReturnType { get; } IType ReturnType { get; }
/// <summary>
/// Gets/Sets the declaring type (incl. type arguments, if any).
/// If this is not a specialized member, the value returned is equal to <see cref="IEntity.DeclaringTypeDefinition"/>.
/// </summary>
new IType DeclaringType { get; }
/// <summary> /// <summary>
/// Gets the interface members explicitly implemented by this member. /// Gets the interface members explicitly implemented by this member.
/// </summary> /// </summary>

2
ICSharpCode.Decompiler/TypeSystem/Implementation/SyntheticRangeIndexer.cs

@ -92,7 +92,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
TypeParameterSubstitution IMember.Substitution => underlyingMethod.Substitution; TypeParameterSubstitution IMember.Substitution => underlyingMethod.Substitution;
EntityHandle IEntity.MetadataToken => underlyingMethod.MetadataToken; EntityHandle IEntity.MetadataToken => underlyingMethod.MetadataToken;
public string Name => underlyingMethod.Name; public string Name => underlyingMethod.Name;
IType IEntity.DeclaringType => underlyingMethod.DeclaringType; public IType DeclaringType => underlyingMethod.DeclaringType;
ITypeDefinition IEntity.DeclaringTypeDefinition => underlyingMethod.DeclaringTypeDefinition; ITypeDefinition IEntity.DeclaringTypeDefinition => underlyingMethod.DeclaringTypeDefinition;
IModule IEntity.ParentModule => underlyingMethod.ParentModule; IModule IEntity.ParentModule => underlyingMethod.ParentModule;
Accessibility IEntity.Accessibility => underlyingMethod.Accessibility; Accessibility IEntity.Accessibility => underlyingMethod.Accessibility;

1
ICSharpCode.Decompiler/Util/BitSet.cs

@ -15,6 +15,7 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // 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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Diagnostics; using System.Diagnostics;

13
ICSharpCode.Decompiler/Util/BusyManager.cs

@ -15,6 +15,7 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // 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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -36,9 +37,9 @@ namespace ICSharpCode.Decompiler.Util
{ {
public static readonly BusyLock Failed = new BusyLock(null); public static readonly BusyLock Failed = new BusyLock(null);
readonly List<object> objectList; readonly List<object?>? objectList;
internal BusyLock(List<object> objectList) internal BusyLock(List<object?>? objectList)
{ {
this.objectList = objectList; this.objectList = objectList;
} }
@ -56,13 +57,13 @@ namespace ICSharpCode.Decompiler.Util
} }
} }
[ThreadStatic] static List<object> _activeObjects; [ThreadStatic] static List<object?>? _activeObjects;
public static BusyLock Enter(object obj) public static BusyLock Enter(object? obj)
{ {
List<object> activeObjects = _activeObjects; List<object?>? activeObjects = _activeObjects;
if (activeObjects == null) if (activeObjects == null)
activeObjects = _activeObjects = new List<object>(); activeObjects = _activeObjects = new List<object?>();
for (int i = 0; i < activeObjects.Count; i++) for (int i = 0; i < activeObjects.Count; i++)
{ {
if (activeObjects[i] == obj) if (activeObjects[i] == obj)

2
ICSharpCode.Decompiler/Util/CacheManager.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;

6
ICSharpCode.Decompiler/Util/CallbackOnDispose.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Threading; using System.Threading;
@ -30,7 +32,7 @@ namespace ICSharpCode.Decompiler.Util
/// </remarks> /// </remarks>
public sealed class CallbackOnDispose : IDisposable public sealed class CallbackOnDispose : IDisposable
{ {
Action action; Action? action;
public CallbackOnDispose(Action action) public CallbackOnDispose(Action action)
{ {
@ -41,7 +43,7 @@ namespace ICSharpCode.Decompiler.Util
public void Dispose() public void Dispose()
{ {
Action a = Interlocked.Exchange(ref action, null); Action? a = Interlocked.Exchange(ref action, null);
if (a != null) if (a != null)
{ {
a(); a();

35
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
@ -14,13 +15,13 @@ namespace ICSharpCode.Decompiler.Util
} }
#if !NETCORE #if !NETCORE
public static IEnumerable<(A, B)> Zip<A, B>(this IEnumerable<A> input1, IEnumerable<B> input2) public static IEnumerable<(A, B)> Zip<A, B>(this IEnumerable<A>? input1, IEnumerable<B>? input2)
{ {
return input1.Zip(input2, (a, b) => (a, b)); return input1.Zip(input2, (a, b) => (a, b));
} }
#endif #endif
public static IEnumerable<(A, B)> ZipLongest<A, B>(this IEnumerable<A> input1, IEnumerable<B> input2) public static IEnumerable<(A?, B?)> ZipLongest<A, B>(this IEnumerable<A> input1, IEnumerable<B> input2)
{ {
using (var it1 = input1.GetEnumerator()) using (var it1 = input1.GetEnumerator())
{ {
@ -60,7 +61,7 @@ namespace ICSharpCode.Decompiler.Util
} }
#if !NETCORE #if !NETCORE
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> input) public static HashSet<T> ToHashSet<T>(this IEnumerable<T>? input)
{ {
return new HashSet<T>(input); return new HashSet<T>(input);
} }
@ -76,14 +77,14 @@ namespace ICSharpCode.Decompiler.Util
return input.Skip(input.Count - count); return input.Skip(input.Count - count);
} }
public static T PopOrDefault<T>(this Stack<T> stack) public static T? PopOrDefault<T>(this Stack<T> stack)
{ {
if (stack.Count == 0) if (stack.Count == 0)
return default(T); return default(T);
return stack.Pop(); return stack.Pop();
} }
public static T PeekOrDefault<T>(this Stack<T> stack) public static T? PeekOrDefault<T>(this Stack<T> stack)
{ {
if (stack.Count == 0) if (stack.Count == 0)
return default(T); return default(T);
@ -277,7 +278,7 @@ namespace ICSharpCode.Decompiler.Util
/// Returns the minimum element. /// Returns the minimum element.
/// </summary> /// </summary>
/// <exception cref="InvalidOperationException">The input sequence is empty</exception> /// <exception cref="InvalidOperationException">The input sequence is empty</exception>
public static T MinBy<T, K>(this IEnumerable<T> source, Func<T, K> keySelector, IComparer<K> keyComparer) public static T MinBy<T, K>(this IEnumerable<T> source, Func<T, K> keySelector, IComparer<K>? keyComparer)
{ {
if (source == null) if (source == null)
throw new ArgumentNullException(nameof(source)); throw new ArgumentNullException(nameof(source));
@ -318,7 +319,7 @@ namespace ICSharpCode.Decompiler.Util
/// Returns the maximum element. /// Returns the maximum element.
/// </summary> /// </summary>
/// <exception cref="InvalidOperationException">The input sequence is empty</exception> /// <exception cref="InvalidOperationException">The input sequence is empty</exception>
public static T MaxBy<T, K>(this IEnumerable<T> source, Func<T, K> keySelector, IComparer<K> keyComparer) public static T MaxBy<T, K>(this IEnumerable<T> source, Func<T, K> keySelector, IComparer<K>? keyComparer)
{ {
if (source == null) if (source == null)
throw new ArgumentNullException(nameof(source)); throw new ArgumentNullException(nameof(source));
@ -353,12 +354,12 @@ namespace ICSharpCode.Decompiler.Util
list.RemoveAt(list.Count - 1); list.RemoveAt(list.Count - 1);
} }
public static T OnlyOrDefault<T>(this IEnumerable<T> source, Func<T, bool> predicate) => OnlyOrDefault(source.Where(predicate)); public static T? OnlyOrDefault<T>(this IEnumerable<T>? source, Func<T, bool>? predicate) => OnlyOrDefault(source.Where(predicate));
public static T OnlyOrDefault<T>(this IEnumerable<T> source) public static T? OnlyOrDefault<T>(this IEnumerable<T> source)
{ {
bool any = false; bool any = false;
T first = default; T? first = default;
foreach (var t in source) foreach (var t in source)
{ {
if (any) if (any)
@ -372,14 +373,14 @@ namespace ICSharpCode.Decompiler.Util
#region Aliases/shortcuts for Enumerable extension methods #region Aliases/shortcuts for Enumerable extension methods
public static bool Any<T>(this ICollection<T> list) => list.Count > 0; public static bool Any<T>(this ICollection<T> list) => list.Count > 0;
public static bool Any<T>(this T[] array, Predicate<T> match) => Array.Exists(array, match); public static bool Any<T>(this T[]? array, Predicate<T>? match) => Array.Exists(array, match);
public static bool Any<T>(this List<T> list, Predicate<T> match) => list.Exists(match); public static bool Any<T>(this List<T> list, Predicate<T>? match) => list.Exists(match);
public static bool All<T>(this T[] array, Predicate<T> match) => Array.TrueForAll(array, match); public static bool All<T>(this T[]? array, Predicate<T>? match) => Array.TrueForAll(array, match);
public static bool All<T>(this List<T> list, Predicate<T> match) => list.TrueForAll(match); public static bool All<T>(this List<T> list, Predicate<T>? match) => list.TrueForAll(match);
public static T FirstOrDefault<T>(this T[] array, Predicate<T> predicate) => Array.Find(array, predicate); public static T FirstOrDefault<T>(this T[]? array, Predicate<T>? predicate) => Array.Find(array, predicate);
public static T FirstOrDefault<T>(this List<T> list, Predicate<T> predicate) => list.Find(predicate); public static T FirstOrDefault<T>(this List<T> list, Predicate<T>? predicate) => list.Find(predicate);
public static T Last<T>(this IList<T> list) => list[list.Count - 1]; public static T Last<T>(this IList<T> list) => list[list.Count - 1];
#endregion #endregion

5
ICSharpCode.Decompiler/Util/EmptyList.cs

@ -15,6 +15,7 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // 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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Collections; using System.Collections;
@ -91,11 +92,11 @@ namespace ICSharpCode.Decompiler.Util
} }
T IEnumerator<T>.Current { T IEnumerator<T>.Current {
get { return default(T); } get { throw new NotSupportedException(); }
} }
object IEnumerator.Current { object IEnumerator.Current {
get { return default(T); } get { throw new NotSupportedException(); }
} }
void IDisposable.Dispose() void IDisposable.Dispose()

5
ICSharpCode.Decompiler/Util/ExtensionMethods.cs

@ -1,4 +1,5 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team #nullable enable
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -26,7 +27,7 @@ namespace ICSharpCode.Decompiler.Util
/// </summary> /// </summary>
static class ExtensionMethods static class ExtensionMethods
{ {
public static Predicate<T> And<T>(this Predicate<T> filter1, Predicate<T> filter2) public static Predicate<T>? And<T>(this Predicate<T>? filter1, Predicate<T>? filter2)
{ {
if (filter1 == null) if (filter1 == null)
return filter2; return filter2;

24
ICSharpCode.Decompiler/Util/FileUtility.cs

@ -16,7 +16,10 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -28,9 +31,10 @@ namespace ICSharpCode.Decompiler.Util
/// Gets the normalized version of fileName. /// Gets the normalized version of fileName.
/// Slashes are replaced with backslashes, backreferences "." and ".." are 'evaluated'. /// Slashes are replaced with backslashes, backreferences "." and ".." are 'evaluated'.
/// </summary> /// </summary>
public static string NormalizePath(string fileName) [return: NotNullIfNotNull("fileName")]
public static string? NormalizePath(string? fileName)
{ {
if (string.IsNullOrEmpty(fileName)) if (fileName == null || fileName.Length == 0)
return fileName; return fileName;
int i; int i;
@ -169,14 +173,14 @@ namespace ICSharpCode.Decompiler.Util
&& (fileName[1] == '\\' || fileName[1] == '/'); && (fileName[1] == '\\' || fileName[1] == '/');
} }
public static bool IsEqualFileName(string fileName1, string fileName2) public static bool IsEqualFileName(string? fileName1, string? fileName2)
{ {
return string.Equals(NormalizePath(fileName1), return string.Equals(NormalizePath(fileName1),
NormalizePath(fileName2), NormalizePath(fileName2),
StringComparison.OrdinalIgnoreCase); StringComparison.OrdinalIgnoreCase);
} }
public static bool IsBaseDirectory(string baseDirectory, string testDirectory) public static bool IsBaseDirectory(string? baseDirectory, string? testDirectory)
{ {
if (baseDirectory == null || testDirectory == null) if (baseDirectory == null || testDirectory == null)
return false; return false;
@ -189,9 +193,10 @@ namespace ICSharpCode.Decompiler.Util
return testDirectory.StartsWith(baseDirectory, StringComparison.OrdinalIgnoreCase); return testDirectory.StartsWith(baseDirectory, StringComparison.OrdinalIgnoreCase);
} }
static string AddTrailingSeparator(string input) [return: NotNullIfNotNull("input")]
static string? AddTrailingSeparator(string? input)
{ {
if (string.IsNullOrEmpty(input)) if (input == null || input.Length == 0)
return input; return input;
if (input[input.Length - 1] == Path.DirectorySeparatorChar || input[input.Length - 1] == Path.AltDirectorySeparatorChar) if (input[input.Length - 1] == Path.DirectorySeparatorChar || input[input.Length - 1] == Path.AltDirectorySeparatorChar)
return input; return input;
@ -212,9 +217,9 @@ namespace ICSharpCode.Decompiler.Util
/// Converts a given absolute path and a given base path to a path that leads /// Converts a given absolute path and a given base path to a path that leads
/// from the base path to the absoulte path. (as a relative path) /// from the base path to the absoulte path. (as a relative path)
/// </summary> /// </summary>
public static string GetRelativePath(string baseDirectoryPath, string absPath) public static string GetRelativePath(string? baseDirectoryPath, string absPath)
{ {
if (string.IsNullOrEmpty(baseDirectoryPath)) if (baseDirectoryPath == null || baseDirectoryPath.Length == 0)
{ {
return absPath; return absPath;
} }
@ -252,7 +257,8 @@ namespace ICSharpCode.Decompiler.Util
return erg.ToString(); return erg.ToString();
} }
public static string TrimPath(string path, int max_chars) [return: NotNullIfNotNull("path")]
public static string? TrimPath(string? path, int max_chars)
{ {
const char ellipsis = '\u2026'; // HORIZONTAL ELLIPSIS const char ellipsis = '\u2026'; // HORIZONTAL ELLIPSIS
const int ellipsisLength = 2; const int ellipsisLength = 2;

26
ICSharpCode.Decompiler/Util/GraphVizGraph.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -34,8 +36,8 @@ namespace ICSharpCode.Decompiler.Util
List<GraphVizNode> nodes = new List<GraphVizNode>(); List<GraphVizNode> nodes = new List<GraphVizNode>();
List<GraphVizEdge> edges = new List<GraphVizEdge>(); List<GraphVizEdge> edges = new List<GraphVizEdge>();
public string rankdir; public string? rankdir;
public string Title; public string? Title;
public void AddEdge(GraphVizEdge edge) public void AddEdge(GraphVizEdge edge)
{ {
@ -58,7 +60,7 @@ namespace ICSharpCode.Decompiler.Util
Show(null); Show(null);
} }
public void Show(string name) public void Show(string? name)
{ {
if (name == null) if (name == null)
name = Title; name = Title;
@ -83,7 +85,7 @@ namespace ICSharpCode.Decompiler.Util
} }
} }
static void WriteGraphAttribute(TextWriter writer, string name, string value) static void WriteGraphAttribute(TextWriter writer, string name, string? value)
{ {
if (value != null) if (value != null)
writer.WriteLine("{0}={1};", name, Escape(value)); writer.WriteLine("{0}={1};", name, Escape(value));
@ -105,7 +107,7 @@ namespace ICSharpCode.Decompiler.Util
} }
} }
internal static void WriteAttribute(TextWriter writer, string name, string value, ref bool isFirst) internal static void WriteAttribute(TextWriter writer, string name, string? value, ref bool isFirst)
{ {
if (value != null) if (value != null)
{ {
@ -141,13 +143,13 @@ namespace ICSharpCode.Decompiler.Util
public readonly string Source, Target; public readonly string Source, Target;
/// <summary>edge stroke color</summary> /// <summary>edge stroke color</summary>
public string color; public string? color;
/// <summary>use edge to affect node ranking</summary> /// <summary>use edge to affect node ranking</summary>
public bool? constraint; public bool? constraint;
public string label; public string? label;
public string style; public string? style;
/// <summary>point size of label</summary> /// <summary>point size of label</summary>
public int? fontsize; public int? fontsize;
@ -184,9 +186,9 @@ namespace ICSharpCode.Decompiler.Util
sealed class GraphVizNode sealed class GraphVizNode
{ {
public readonly string ID; public readonly string ID;
public string label; public string? label;
public string labelloc; public string? labelloc;
/// <summary>point size of label</summary> /// <summary>point size of label</summary>
public int? fontsize; public int? fontsize;
@ -195,10 +197,10 @@ namespace ICSharpCode.Decompiler.Util
public double? height; public double? height;
/// <summary>space around label</summary> /// <summary>space around label</summary>
public string margin; public string? margin;
/// <summary>node shape</summary> /// <summary>node shape</summary>
public string shape; public string? shape;
public GraphVizNode(string id) public GraphVizNode(string id)
{ {

7
ICSharpCode.Decompiler/Util/Interval.cs

@ -1,4 +1,5 @@
// Copyright (c) 2016 Daniel Grunwald #nullable enable
// Copyright (c) 2016 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -111,7 +112,7 @@ namespace ICSharpCode.Decompiler.Util
} }
#region Equals and GetHashCode implementation #region Equals and GetHashCode implementation
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
return (obj is Interval) && Equals((Interval)obj); return (obj is Interval) && Equals((Interval)obj);
} }
@ -281,7 +282,7 @@ namespace ICSharpCode.Decompiler.Util
} }
#region Equals and GetHashCode implementation #region Equals and GetHashCode implementation
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
return (obj is LongInterval) && Equals((LongInterval)obj); return (obj is LongInterval) && Equals((LongInterval)obj);
} }

3
ICSharpCode.Decompiler/Util/KeyComparer.cs

@ -1,4 +1,5 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team #nullable enable
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

7
ICSharpCode.Decompiler/Util/LongSet.cs

@ -1,4 +1,5 @@
// Copyright (c) 2016 Daniel Grunwald #nullable enable
// Copyright (c) 2016 Daniel Grunwald
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -82,7 +83,7 @@ namespace ICSharpCode.Decompiler.Util
/// <summary> /// <summary>
/// Creates a new LongSet the contains the values from the specified intervals. /// Creates a new LongSet the contains the values from the specified intervals.
/// </summary> /// </summary>
public LongSet(IEnumerable<LongInterval> intervals) public LongSet(IEnumerable<LongInterval>? intervals)
: this(MergeOverlapping(intervals.Where(i => !i.IsEmpty).OrderBy(i => i.Start)).ToImmutableArray()) : this(MergeOverlapping(intervals.Where(i => !i.IsEmpty).OrderBy(i => i.Start)).ToImmutableArray())
{ {
} }
@ -350,7 +351,7 @@ namespace ICSharpCode.Decompiler.Util
} }
#region Equals and GetHashCode implementation #region Equals and GetHashCode implementation
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
return obj is LongSet && SetEquals((LongSet)obj); return obj is LongSet && SetEquals((LongSet)obj);
} }

5
ICSharpCode.Decompiler/Util/MultiDictionary.cs

@ -1,4 +1,5 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team #nullable enable
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -33,7 +34,7 @@ namespace ICSharpCode.Decompiler.Util
dict = new Dictionary<TKey, List<TValue>>(); dict = new Dictionary<TKey, List<TValue>>();
} }
public MultiDictionary(IEqualityComparer<TKey> comparer) public MultiDictionary(IEqualityComparer<TKey>? comparer)
{ {
dict = new Dictionary<TKey, List<TValue>>(comparer); dict = new Dictionary<TKey, List<TValue>>(comparer);
} }

8
ICSharpCode.Decompiler/Util/NullAttributes.cs

@ -25,5 +25,13 @@ namespace System.Diagnostics.CodeAnalysis
public bool ReturnValue { get; } public bool ReturnValue { get; }
} }
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class DoesNotReturnIfAttribute : Attribute
{
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
public bool ParameterValue { get; }
}
} }
#endif #endif

3
ICSharpCode.Decompiler/Util/Platform.cs

@ -1,4 +1,5 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team #nullable enable
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software

15
ICSharpCode.Decompiler/Util/ProjectedList.cs

@ -1,4 +1,5 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team #nullable enable
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -25,7 +26,7 @@ namespace ICSharpCode.Decompiler.Util
{ {
readonly IList<TInput> input; readonly IList<TInput> input;
readonly Func<TInput, TOutput> projection; readonly Func<TInput, TOutput> projection;
readonly TOutput[] items; readonly TOutput?[] items;
public ProjectedList(IList<TInput> input, Func<TInput, TOutput> projection) public ProjectedList(IList<TInput> input, Func<TInput, TOutput> projection)
{ {
@ -35,12 +36,12 @@ namespace ICSharpCode.Decompiler.Util
throw new ArgumentNullException(nameof(projection)); throw new ArgumentNullException(nameof(projection));
this.input = input; this.input = input;
this.projection = projection; this.projection = projection;
this.items = new TOutput[input.Count]; this.items = new TOutput?[input.Count];
} }
public TOutput this[int index] { public TOutput this[int index] {
get { get {
TOutput output = LazyInit.VolatileRead(ref items[index]); TOutput? output = LazyInit.VolatileRead(ref items[index]);
if (output != null) if (output != null)
{ {
return output; return output;
@ -72,7 +73,7 @@ namespace ICSharpCode.Decompiler.Util
readonly IList<TInput> input; readonly IList<TInput> input;
readonly TContext context; readonly TContext context;
readonly Func<TContext, TInput, TOutput> projection; readonly Func<TContext, TInput, TOutput> projection;
readonly TOutput[] items; readonly TOutput?[] items;
public ProjectedList(TContext context, IList<TInput> input, Func<TContext, TInput, TOutput> projection) public ProjectedList(TContext context, IList<TInput> input, Func<TContext, TInput, TOutput> projection)
{ {
@ -83,12 +84,12 @@ namespace ICSharpCode.Decompiler.Util
this.input = input; this.input = input;
this.context = context; this.context = context;
this.projection = projection; this.projection = projection;
this.items = new TOutput[input.Count]; this.items = new TOutput?[input.Count];
} }
public TOutput this[int index] { public TOutput this[int index] {
get { get {
TOutput output = LazyInit.VolatileRead(ref items[index]); TOutput? output = LazyInit.VolatileRead(ref items[index]);
if (output != null) if (output != null)
{ {
return output; return output;

7
ICSharpCode.Decompiler/Util/ReferenceComparer.cs

@ -15,22 +15,23 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // 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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace ICSharpCode.Decompiler.Util namespace ICSharpCode.Decompiler.Util
{ {
public sealed class ReferenceComparer : IEqualityComparer<object> public sealed class ReferenceComparer : IEqualityComparer<object?>
{ {
public readonly static ReferenceComparer Instance = new ReferenceComparer(); public readonly static ReferenceComparer Instance = new ReferenceComparer();
public new bool Equals(object x, object y) public new bool Equals(object? x, object? y)
{ {
return x == y; return x == y;
} }
public int GetHashCode(object obj) public int GetHashCode(object? obj)
{ {
return RuntimeHelpers.GetHashCode(obj); return RuntimeHelpers.GetHashCode(obj);
} }

27
ICSharpCode.Decompiler/Util/ResourcesFile.cs

@ -1,4 +1,5 @@
// Copyright (c) 2018 Daniel Grunwald #nullable enable
// Copyright (c) 2018 Daniel Grunwald
// Based on the .NET Core ResourceReader; make available under the MIT license // Based on the .NET Core ResourceReader; make available under the MIT license
// by the .NET Foundation. // by the .NET Foundation.
// //
@ -30,7 +31,7 @@ namespace ICSharpCode.Decompiler.Util
/// <summary> /// <summary>
/// .resources file. /// .resources file.
/// </summary> /// </summary>
public class ResourcesFile : IEnumerable<KeyValuePair<string, object>>, IDisposable public class ResourcesFile : IEnumerable<KeyValuePair<string, object?>>, IDisposable
{ {
sealed class MyBinaryReader : BinaryReader sealed class MyBinaryReader : BinaryReader
{ {
@ -87,7 +88,7 @@ namespace ICSharpCode.Decompiler.Util
readonly long fileStartPosition; readonly long fileStartPosition;
readonly long nameSectionPosition; readonly long nameSectionPosition;
readonly long dataSectionPosition; readonly long dataSectionPosition;
long[] startPositions; long[]? startPositions;
/// <summary> /// <summary>
/// Creates a new ResourcesFile. /// Creates a new ResourcesFile.
@ -285,7 +286,7 @@ namespace ICSharpCode.Decompiler.Util
return true; return true;
} }
object LoadObject(int dataOffset) object? LoadObject(int dataOffset)
{ {
try try
{ {
@ -318,7 +319,7 @@ namespace ICSharpCode.Decompiler.Util
// from that location. // from that location.
// Anyone who calls LoadObject should make sure they take a lock so // Anyone who calls LoadObject should make sure they take a lock so
// no one can cause us to do a seek in here. // no one can cause us to do a seek in here.
private object LoadObjectV1(int dataOffset) private object? LoadObjectV1(int dataOffset)
{ {
Debug.Assert(System.Threading.Monitor.IsEntered(reader)); Debug.Assert(System.Threading.Monitor.IsEntered(reader));
reader.Seek(dataSectionPosition + dataOffset, SeekOrigin.Begin); reader.Seek(dataSectionPosition + dataOffset, SeekOrigin.Begin);
@ -372,7 +373,7 @@ namespace ICSharpCode.Decompiler.Util
} }
} }
private object LoadObjectV2(int dataOffset) private object? LoadObjectV2(int dataOffset)
{ {
Debug.Assert(System.Threading.Monitor.IsEntered(reader)); Debug.Assert(System.Threading.Monitor.IsEntered(reader));
reader.Seek(dataSectionPosition + dataOffset, SeekOrigin.Begin); reader.Seek(dataSectionPosition + dataOffset, SeekOrigin.Begin);
@ -464,19 +465,19 @@ namespace ICSharpCode.Decompiler.Util
} }
} }
public object GetResourceValue(int index) public object? GetResourceValue(int index)
{ {
GetResourceName(index, out int dataOffset); GetResourceName(index, out int dataOffset);
return LoadObject(dataOffset); return LoadObject(dataOffset);
} }
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() public IEnumerator<KeyValuePair<string, object?>> GetEnumerator()
{ {
for (int i = 0; i < numResources; i++) for (int i = 0; i < numResources; i++)
{ {
string name = GetResourceName(i, out int dataOffset); string name = GetResourceName(i, out int dataOffset);
object val = LoadObject(dataOffset); object? val = LoadObject(dataOffset);
yield return new KeyValuePair<string, object>(name, val); yield return new KeyValuePair<string, object?>(name, val);
} }
} }
@ -487,7 +488,7 @@ namespace ICSharpCode.Decompiler.Util
long[] GetStartPositions() long[] GetStartPositions()
{ {
long[] positions = LazyInit.VolatileRead(ref startPositions); long[]? positions = LazyInit.VolatileRead(ref startPositions);
if (positions != null) if (positions != null)
return positions; return positions;
lock (reader) lock (reader)
@ -541,11 +542,11 @@ namespace ICSharpCode.Decompiler.Util
public class ResourceSerializedObject public class ResourceSerializedObject
{ {
public string TypeName { get; } public string? TypeName { get; }
readonly ResourcesFile file; readonly ResourcesFile file;
readonly long position; readonly long position;
internal ResourceSerializedObject(string typeName, ResourcesFile file, long position) internal ResourceSerializedObject(string? typeName, ResourcesFile file, long position)
{ {
this.TypeName = typeName; this.TypeName = typeName;
this.file = file; this.file = file;

15
ICSharpCode.Decompiler/Util/TreeTraversal.cs

@ -1,4 +1,5 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team #nullable enable
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -32,7 +33,7 @@ namespace ICSharpCode.Decompiler.Util
/// <param name="root">The root element of the tree.</param> /// <param name="root">The root element of the tree.</param>
/// <param name="recursion">The function that gets the children of an element.</param> /// <param name="recursion">The function that gets the children of an element.</param>
/// <returns>Iterator that enumerates the tree structure in pre-order.</returns> /// <returns>Iterator that enumerates the tree structure in pre-order.</returns>
public static IEnumerable<T> PreOrder<T>(T root, Func<T, IEnumerable<T>> recursion) public static IEnumerable<T> PreOrder<T>(T root, Func<T, IEnumerable<T>?> recursion)
{ {
return PreOrder(new T[] { root }, recursion); return PreOrder(new T[] { root }, recursion);
} }
@ -43,7 +44,7 @@ namespace ICSharpCode.Decompiler.Util
/// <param name="input">The root elements of the forest.</param> /// <param name="input">The root elements of the forest.</param>
/// <param name="recursion">The function that gets the children of an element.</param> /// <param name="recursion">The function that gets the children of an element.</param>
/// <returns>Iterator that enumerates the tree structure in pre-order.</returns> /// <returns>Iterator that enumerates the tree structure in pre-order.</returns>
public static IEnumerable<T> PreOrder<T>(IEnumerable<T> input, Func<T, IEnumerable<T>> recursion) public static IEnumerable<T> PreOrder<T>(IEnumerable<T> input, Func<T, IEnumerable<T>?> recursion)
{ {
Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>(); Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>();
try try
@ -55,7 +56,7 @@ namespace ICSharpCode.Decompiler.Util
{ {
T element = stack.Peek().Current; T element = stack.Peek().Current;
yield return element; yield return element;
IEnumerable<T> children = recursion(element); IEnumerable<T>? children = recursion(element);
if (children != null) if (children != null)
{ {
stack.Push(children.GetEnumerator()); stack.Push(children.GetEnumerator());
@ -79,7 +80,7 @@ namespace ICSharpCode.Decompiler.Util
/// <param name="root">The root element of the tree.</param> /// <param name="root">The root element of the tree.</param>
/// <param name="recursion">The function that gets the children of an element.</param> /// <param name="recursion">The function that gets the children of an element.</param>
/// <returns>Iterator that enumerates the tree structure in post-order.</returns> /// <returns>Iterator that enumerates the tree structure in post-order.</returns>
public static IEnumerable<T> PostOrder<T>(T root, Func<T, IEnumerable<T>> recursion) public static IEnumerable<T> PostOrder<T>(T root, Func<T, IEnumerable<T>?> recursion)
{ {
return PostOrder(new T[] { root }, recursion); return PostOrder(new T[] { root }, recursion);
} }
@ -90,7 +91,7 @@ namespace ICSharpCode.Decompiler.Util
/// <param name="input">The root elements of the forest.</param> /// <param name="input">The root elements of the forest.</param>
/// <param name="recursion">The function that gets the children of an element.</param> /// <param name="recursion">The function that gets the children of an element.</param>
/// <returns>Iterator that enumerates the tree structure in post-order.</returns> /// <returns>Iterator that enumerates the tree structure in post-order.</returns>
public static IEnumerable<T> PostOrder<T>(IEnumerable<T> input, Func<T, IEnumerable<T>> recursion) public static IEnumerable<T> PostOrder<T>(IEnumerable<T> input, Func<T, IEnumerable<T>?> recursion)
{ {
Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>(); Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>();
try try
@ -101,7 +102,7 @@ namespace ICSharpCode.Decompiler.Util
while (stack.Peek().MoveNext()) while (stack.Peek().MoveNext())
{ {
T element = stack.Peek().Current; T element = stack.Peek().Current;
IEnumerable<T> children = recursion(element); IEnumerable<T>? children = recursion(element);
if (children != null) if (children != null)
{ {
stack.Push(children.GetEnumerator()); stack.Push(children.GetEnumerator());

7
ICSharpCode.Decompiler/Util/UnicodeNewline.cs

@ -1,3 +1,4 @@
#nullable enable
// //
// UnicodeNewline.cs // UnicodeNewline.cs
// //
@ -118,7 +119,7 @@ namespace ICSharpCode.Decompiler.Util
/// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns> /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
/// <param name="curChar">The current character.</param> /// <param name="curChar">The current character.</param>
/// <param name="nextChar">A callback getting the next character (may be null).</param> /// <param name="nextChar">A callback getting the next character (may be null).</param>
public static int GetDelimiterLength(char curChar, Func<char> nextChar = null) public static int GetDelimiterLength(char curChar, Func<char>? nextChar = null)
{ {
if (curChar == CR) if (curChar == CR)
{ {
@ -161,7 +162,7 @@ namespace ICSharpCode.Decompiler.Util
/// <param name = "length">The length of the delimiter</param> /// <param name = "length">The length of the delimiter</param>
/// <param name = "type">The type of the delimiter</param> /// <param name = "type">The type of the delimiter</param>
/// <param name="nextChar">A callback getting the next character (may be null).</param> /// <param name="nextChar">A callback getting the next character (may be null).</param>
public static bool TryGetDelimiterLengthAndType(char curChar, out int length, out UnicodeNewline type, Func<char> nextChar = null) public static bool TryGetDelimiterLengthAndType(char curChar, out int length, out UnicodeNewline type, Func<char>? nextChar = null)
{ {
if (curChar == CR) if (curChar == CR)
{ {
@ -275,7 +276,7 @@ namespace ICSharpCode.Decompiler.Util
/// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns> /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
/// <param name="curChar">The current character.</param> /// <param name="curChar">The current character.</param>
/// <param name="nextChar">A callback getting the next character (may be null).</param> /// <param name="nextChar">A callback getting the next character (may be null).</param>
public static UnicodeNewline GetDelimiterType(char curChar, Func<char> nextChar = null) public static UnicodeNewline GetDelimiterType(char curChar, Func<char>? nextChar = null)
{ {
switch (curChar) switch (curChar)
{ {

14
ICSharpCode.Decompiler/Util/UnionFind.cs

@ -15,6 +15,7 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // 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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Generic; using System.Collections.Generic;
@ -32,6 +33,12 @@ namespace ICSharpCode.Decompiler.Util
public int rank; public int rank;
public Node parent; public Node parent;
public T value; public T value;
internal Node(T value)
{
this.value = value;
this.parent = this;
}
} }
public UnionFind() public UnionFind()
@ -44,10 +51,7 @@ namespace ICSharpCode.Decompiler.Util
Node node; Node node;
if (!mapping.TryGetValue(element, out node)) if (!mapping.TryGetValue(element, out node))
{ {
node = new Node { node = new Node(element);
value = element,
rank = 0
};
node.parent = node; node.parent = node;
mapping.Add(element, node); mapping.Add(element, node);
} }
@ -84,5 +88,3 @@ namespace ICSharpCode.Decompiler.Util
} }
} }
} }

23
ICSharpCode.Decompiler/Util/Win32Resources.cs

@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
@ -15,21 +16,21 @@ namespace ICSharpCode.Decompiler.Util
/// </summary> /// </summary>
/// <param name="pe"></param> /// <param name="pe"></param>
/// <returns></returns> /// <returns></returns>
public static unsafe Win32ResourceDirectory ReadWin32Resources(this PEReader pe) public static unsafe Win32ResourceDirectory? ReadWin32Resources(this PEReader pe)
{ {
if (pe == null) if (pe == null)
{ {
throw new ArgumentNullException(nameof(pe)); throw new ArgumentNullException(nameof(pe));
} }
int rva = pe.PEHeaders.PEHeader.ResourceTableDirectory.RelativeVirtualAddress; int rva = pe.PEHeaders.PEHeader?.ResourceTableDirectory.RelativeVirtualAddress ?? 0;
if (rva == 0) if (rva == 0)
return null; return null;
byte* pRoot = pe.GetSectionData(rva).Pointer; byte* pRoot = pe.GetSectionData(rva).Pointer;
return new Win32ResourceDirectory(pe, pRoot, 0, new Win32ResourceName("Root")); return new Win32ResourceDirectory(pe, pRoot, 0, new Win32ResourceName("Root"));
} }
public static Win32ResourceDirectory Find(this Win32ResourceDirectory root, Win32ResourceName type) public static Win32ResourceDirectory? Find(this Win32ResourceDirectory root, Win32ResourceName type)
{ {
if (root is null) if (root is null)
throw new ArgumentNullException(nameof(root)); throw new ArgumentNullException(nameof(root));
@ -41,7 +42,7 @@ namespace ICSharpCode.Decompiler.Util
return root.FindDirectory(type); return root.FindDirectory(type);
} }
public static Win32ResourceDirectory Find(this Win32ResourceDirectory root, Win32ResourceName type, Win32ResourceName name) public static Win32ResourceDirectory? Find(this Win32ResourceDirectory root, Win32ResourceName type, Win32ResourceName name)
{ {
if (root is null) if (root is null)
throw new ArgumentNullException(nameof(root)); throw new ArgumentNullException(nameof(root));
@ -55,7 +56,7 @@ namespace ICSharpCode.Decompiler.Util
return root.FindDirectory(type)?.FindDirectory(name); return root.FindDirectory(type)?.FindDirectory(name);
} }
public static Win32ResourceData Find(this Win32ResourceDirectory root, Win32ResourceName type, Win32ResourceName name, Win32ResourceName langId) public static Win32ResourceData? Find(this Win32ResourceDirectory root, Win32ResourceName type, Win32ResourceName name, Win32ResourceName langId)
{ {
if (root is null) if (root is null)
throw new ArgumentNullException(nameof(root)); throw new ArgumentNullException(nameof(root));
@ -122,7 +123,7 @@ namespace ICSharpCode.Decompiler.Util
return new string(pString->NameString, 0, pString->Length); return new string(pString->NameString, 0, pString->Length);
} }
public Win32ResourceDirectory FindDirectory(Win32ResourceName name) public Win32ResourceDirectory? FindDirectory(Win32ResourceName name)
{ {
foreach (var directory in Directories) foreach (var directory in Directories)
{ {
@ -132,7 +133,7 @@ namespace ICSharpCode.Decompiler.Util
return null; return null;
} }
public Win32ResourceData FindData(Win32ResourceName name) public Win32ResourceData? FindData(Win32ResourceName name)
{ {
foreach (var data in Datas) foreach (var data in Datas)
{ {
@ -142,12 +143,12 @@ namespace ICSharpCode.Decompiler.Util
return null; return null;
} }
public Win32ResourceDirectory FirstDirectory() public Win32ResourceDirectory? FirstDirectory()
{ {
return Directories.Count != 0 ? Directories[0] : null; return Directories.Count != 0 ? Directories[0] : null;
} }
public Win32ResourceData FirstData() public Win32ResourceData? FirstData()
{ {
return Datas.Count != 0 ? Datas[0] : null; return Datas.Count != 0 ? Datas[0] : null;
} }
@ -248,7 +249,7 @@ namespace ICSharpCode.Decompiler.Util
return _name.GetHashCode(); return _name.GetHashCode();
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
if (!(obj is Win32ResourceName name)) if (!(obj is Win32ResourceName name))
return false; return false;

4
ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net472</TargetFramework> <TargetFramework>net472</TargetFramework>
@ -112,4 +112,4 @@
<Page Include="Cases\Issue445.xaml" /> <Page Include="Cases\Issue445.xaml" />
</ItemGroup> </ItemGroup>
</Project> </Project>

Loading…
Cancel
Save