Browse Source

Pattern Matching: Ensure that we always return a non-null instruction after successfully matching a pattern.

pull/3049/head
Siegfried Pammer 2 years ago
parent
commit
800067e488
  1. 72
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/PatternMatching.cs
  2. 21
      ICSharpCode.Decompiler/IL/Transforms/PatternMatchingTransform.cs

72
ICSharpCode.Decompiler.Tests/TestCases/Pretty/PatternMatching.cs

@ -503,6 +503,66 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
public void RecursivePattern_NullableIntField_Var(object obj)
{
if (obj is X { NullableIntField: var nullableIntField })
{
Console.WriteLine("Test " + nullableIntField.Value);
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePattern_NullableIntProp_Const(object obj)
{
if (obj is X { NullableIntProp: 42 } x)
{
Console.WriteLine("Test " + x);
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePattern_NullableIntProp_Var(object obj)
{
if (obj is X { NullableIntProp: var nullableIntProp })
{
Console.WriteLine("Test " + nullableIntProp.Value);
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePattern_NullableCustomStructField_Const(object obj)
{
if (obj is X { NullableCustomStructField: { I: 42, Obj: not null } nullableCustomStructField })
{
Console.WriteLine("Test " + nullableCustomStructField.I);
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePattern_NullableCustomStructField_Var(object obj)
{
if (obj is X { NullableCustomStructField: var nullableCustomStructField, Obj: null })
{
Console.WriteLine("Test " + nullableCustomStructField.Value);
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePattern_NullableCustomStructProp_Const(object obj) public void RecursivePattern_NullableCustomStructProp_Const(object obj)
{ {
if (obj is X { NullableCustomStructProp: { I: 42, Obj: not null } nullableCustomStructProp }) if (obj is X { NullableCustomStructProp: { I: 42, Obj: not null } nullableCustomStructProp })
@ -514,6 +574,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine("not Test"); Console.WriteLine("not Test");
} }
} }
public void RecursivePattern_NullableCustomStructProp_Var(object obj)
{
if (obj is X { NullableCustomStructProp: var nullableCustomStructProp, Obj: null })
{
Console.WriteLine("Test " + nullableCustomStructProp.Value);
}
else
{
Console.WriteLine("not Test");
}
}
#endif #endif
private bool F() private bool F()
{ {

21
ICSharpCode.Decompiler/IL/Transforms/PatternMatchingTransform.cs

@ -186,11 +186,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; return true;
} }
private static ILInstruction? DetectPropertySubPatterns(MatchInstruction parentPattern, ILInstruction? trueInst, private static ILInstruction DetectPropertySubPatterns(MatchInstruction parentPattern, ILInstruction trueInst,
ILInstruction parentFalseInst, BlockContainer container, ILTransformContext context, ref ControlFlowGraph? cfg) ILInstruction parentFalseInst, BlockContainer container, ILTransformContext context, ref ControlFlowGraph? cfg)
{ {
ILInstruction? prevTrueInst = trueInst; while (true)
while (trueInst != null)
{ {
Block? trueBlock = trueInst as Block; Block? trueBlock = trueInst as Block;
if (!(trueBlock != null || trueInst.MatchBranch(out trueBlock))) if (!(trueBlock != null || trueInst.MatchBranch(out trueBlock)))
@ -201,13 +200,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
break; break;
} }
trueInst = DetectPropertySubPattern(parentPattern, trueBlock, parentFalseInst, context, ref cfg); var nextTrueInst = DetectPropertySubPattern(parentPattern, trueBlock, parentFalseInst, context, ref cfg);
if (trueInst != null) if (nextTrueInst != null)
{ {
prevTrueInst = trueInst; trueInst = nextTrueInst;
} }
else
{
break;
} }
return prevTrueInst; }
return trueInst;
} }
private static ILInstruction? DetectPropertySubPattern(MatchInstruction parentPattern, Block block, private static ILInstruction? DetectPropertySubPattern(MatchInstruction parentPattern, Block block,
@ -288,7 +291,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (targetVariable.Type.IsKnownType(KnownTypeCode.NullableOfT)) if (targetVariable.Type.IsKnownType(KnownTypeCode.NullableOfT))
{ {
return MatchNullableHasValueCheckPattern(block, varPattern, parentFalseInst, context, ref cfg); return MatchNullableHasValueCheckPattern(block, varPattern, parentFalseInst, context, ref cfg)
?? block;
} }
var instructionAfterNullCheck = MatchNullCheckPattern(block, varPattern, parentFalseInst, context); var instructionAfterNullCheck = MatchNullCheckPattern(block, varPattern, parentFalseInst, context);
@ -339,6 +343,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
block.Instructions.Add(trueInst); block.Instructions.Add(trueInst);
return trueInst; return trueInst;
} }
private static ILInstruction? MatchNullableHasValueCheckPattern(Block block, MatchInstruction varPattern, private static ILInstruction? MatchNullableHasValueCheckPattern(Block block, MatchInstruction varPattern,
ILInstruction parentFalseInst, ILTransformContext context, ref ControlFlowGraph? cfg) ILInstruction parentFalseInst, ILTransformContext context, ref ControlFlowGraph? cfg)
{ {

Loading…
Cancel
Save