From a6e23d1f98052f127f07234a66678d53a6269b71 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 23 Jun 2020 23:29:25 +0200 Subject: [PATCH] Fix "case null" handling in switch(string) with current Roslyn version (3.7.0-2.final). --- .../IL/Transforms/SwitchOnStringTransform.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs index 216c1c79f..a25588629 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs +++ b/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 } } + /// + /// Matches: + /// Block oldDefaultBlock (incoming: 1) { + /// if (comp.o(ldloc switchVar == ldnull)) br nullValueCaseBlock + /// br newDefaultBlock + /// } + /// + 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; + } + /// /// Matches (and the negated version): /// if (call op_Equality(ldloc switchValueVar, stringValue)) br body