Browse Source

Fix "case null" handling in switch(string) with current Roslyn version (3.7.0-2.final).

pull/2045/head
Daniel Grunwald 5 years ago
parent
commit
a6e23d1f98
  1. 31
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

31
ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

@ -889,8 +889,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (nullValueCaseBlock != null && exitOrDefaultBlock != nullValueCaseBlock) {
stringValues.Add((null, nullValueCaseBlock));
}
// In newer Roslyn versions (>=3.7) the null check appears in the default case, not prior to the switch.
if (!stringValues.Any(pair => pair.Value == null) && IsNullCheckInDefaultBlock(ref exitOrDefaultBlock, switchValueLoad.Variable, out nullValueCaseBlock)) {
stringValues.Add((null, nullValueCaseBlock));
}
context.Step(nameof(MatchRoslynSwitchOnString), switchValueLoad);
((Branch)defaultSection.Body).TargetBlock = exitOrDefaultBlock;
ILInstruction switchValueInst = switchValueLoad;
if (instructions == switchBlockInstructions) {
// stloc switchValueLoadVariable(switchValue)
@ -959,6 +964,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
/// <summary>
/// Matches:
/// Block oldDefaultBlock (incoming: 1) {
/// if (comp.o(ldloc switchVar == ldnull)) br nullValueCaseBlock
/// br newDefaultBlock
/// }
/// </summary>
private bool IsNullCheckInDefaultBlock(ref Block exitOrDefaultBlock, ILVariable switchVar, out Block nullValueCaseBlock)
{
nullValueCaseBlock = null;
if (!exitOrDefaultBlock.Instructions[0].MatchIfInstruction(out var condition, out var thenBranch))
return false;
if (!(condition.MatchCompEqualsNull(out var arg) && arg.MatchLdLoc(switchVar)))
return false;
if (!thenBranch.MatchBranch(out nullValueCaseBlock))
return false;
if (nullValueCaseBlock.Parent != exitOrDefaultBlock.Parent)
return false;
if (!exitOrDefaultBlock.Instructions[1].MatchBranch(out var elseBlock))
return false;
if (elseBlock.Parent != exitOrDefaultBlock.Parent)
return false;
exitOrDefaultBlock = elseBlock;
return true;
}
/// <summary>
/// Matches (and the negated version):
/// if (call op_Equality(ldloc switchValueVar, stringValue)) br body

Loading…
Cancel
Save