Browse Source

Add missing DecompilerSettings for new language features

pull/3049/head
Siegfried Pammer 2 years ago
parent
commit
688474facd
  1. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 62
      ICSharpCode.Decompiler/DecompilerSettings.cs
  3. 18
      ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs
  4. 2
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  5. 29
      ICSharpCode.Decompiler/IL/Transforms/PatternMatchingTransform.cs
  6. 27
      ILSpy/Properties/Resources.Designer.cs
  7. 9
      ILSpy/Properties/Resources.resx

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -4575,7 +4575,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -4575,7 +4575,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
foreach (var subPattern in matchInstruction.SubPatterns)
{
if (!MatchInstruction.IsPatternMatch(subPattern, out var testedOperand))
if (!MatchInstruction.IsPatternMatch(subPattern, out var testedOperand, settings))
{
Debug.Fail("Invalid sub pattern");
continue;

62
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -130,6 +130,7 @@ namespace ICSharpCode.Decompiler @@ -130,6 +130,7 @@ namespace ICSharpCode.Decompiler
staticLocalFunctions = false;
ranges = false;
switchExpressions = false;
recursivePatternMatching = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp9_0)
{
@ -141,6 +142,8 @@ namespace ICSharpCode.Decompiler @@ -141,6 +142,8 @@ namespace ICSharpCode.Decompiler
withExpressions = false;
usePrimaryConstructorSyntax = false;
covariantReturns = false;
relationalPatterns = false;
patternCombinators = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp10_0)
{
@ -166,10 +169,11 @@ namespace ICSharpCode.Decompiler @@ -166,10 +169,11 @@ namespace ICSharpCode.Decompiler
if (fileScopedNamespaces || recordStructs)
return CSharp.LanguageVersion.CSharp10_0;
if (nativeIntegers || initAccessors || functionPointers || forEachWithGetEnumeratorExtension
|| recordClasses || withExpressions || usePrimaryConstructorSyntax || covariantReturns)
|| recordClasses || withExpressions || usePrimaryConstructorSyntax || covariantReturns
|| relationalPatterns || patternCombinators)
return CSharp.LanguageVersion.CSharp9_0;
if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement
|| staticLocalFunctions || ranges || switchExpressions)
|| staticLocalFunctions || ranges || switchExpressions || recursivePatternMatching)
return CSharp.LanguageVersion.CSharp8_0;
if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers
|| patternBasedFixedStatement)
@ -1678,6 +1682,60 @@ namespace ICSharpCode.Decompiler @@ -1678,6 +1682,60 @@ namespace ICSharpCode.Decompiler
}
}
bool recursivePatternMatching = true;
/// <summary>
/// Gets/Sets whether C# 8.0 recursive patterns should be detected.
/// </summary>
[Category("C# 8.0 / VS 2019")]
[Description("DecompilerSettings.RecursivePatternMatching")]
public bool RecursivePatternMatching {
get { return recursivePatternMatching; }
set {
if (recursivePatternMatching != value)
{
recursivePatternMatching = value;
OnPropertyChanged();
}
}
}
bool patternCombinators = true;
/// <summary>
/// Gets/Sets whether C# 9.0 and, or, not patterns should be detected.
/// </summary>
[Category("C# 9.0 / VS 2019.8")]
[Description("DecompilerSettings.PatternCombinators")]
public bool PatternCombinators {
get { return patternCombinators; }
set {
if (patternCombinators != value)
{
patternCombinators = value;
OnPropertyChanged();
}
}
}
bool relationalPatterns = true;
/// <summary>
/// Gets/Sets whether C# 9.0 relational patterns should be detected.
/// </summary>
[Category("C# 9.0 / VS 2019.8")]
[Description("DecompilerSettings.RelationalPatterns")]
public bool RelationalPatterns {
get { return relationalPatterns; }
set {
if (relationalPatterns != value)
{
relationalPatterns = value;
OnPropertyChanged();
}
}
}
bool staticLocalFunctions = true;
/// <summary>

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

@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.IL @@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.IL
/// (even if the pattern fails to match!).
/// The pattern matching instruction evaluates to 1 (as I4) if the pattern matches, or 0 otherwise.
/// </summary>
public static bool IsPatternMatch(ILInstruction? inst, [NotNullWhen(true)] out ILInstruction? testedOperand)
public static bool IsPatternMatch(ILInstruction? inst, [NotNullWhen(true)] out ILInstruction? testedOperand, DecompilerSettings? settings)
{
switch (inst)
{
@ -127,13 +127,23 @@ namespace ICSharpCode.Decompiler.IL @@ -127,13 +127,23 @@ namespace ICSharpCode.Decompiler.IL
testedOperand = m.testedOperand;
return true;
case Comp comp:
if (comp.MatchLogicNot(out var operand) && IsPatternMatch(operand, out testedOperand))
if (comp.MatchLogicNot(out var operand) && IsPatternMatch(operand, out testedOperand, settings))
{
return true;
return settings?.PatternCombinators ?? true;
}
else
{
testedOperand = comp.Left;
if (!(settings?.RelationalPatterns ?? true))
{
if (comp.Kind is not (ComparisonKind.Equality or ComparisonKind.Inequality))
return false;
}
if (!(settings?.PatternCombinators ?? true))
{
if (comp.Kind is ComparisonKind.Inequality)
return false;
}
return IsConstant(comp.Right);
}
case Call call when IsCallToString_op_Equality(call):
@ -201,7 +211,7 @@ namespace ICSharpCode.Decompiler.IL @@ -201,7 +211,7 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(SubPatterns.Count >= NumPositionalPatterns);
foreach (var subPattern in SubPatterns)
{
if (!IsPatternMatch(subPattern, out ILInstruction? operand))
if (!IsPatternMatch(subPattern, out ILInstruction? operand, null))
throw new InvalidOperationException("Sub-Pattern must be a valid pattern");
// the first child is TestedOperand
int subPatternIndex = subPattern.ChildIndex - 1;

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

@ -557,7 +557,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -557,7 +557,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
}
}
if (MatchInstruction.IsPatternMatch(inst.Condition, out _)
if (MatchInstruction.IsPatternMatch(inst.Condition, out _, context.Settings)
&& inst.TrueInst.MatchLdcI4(1) && inst.FalseInst.MatchLdcI4(0))
{
context.Step("match(x) ? true : false -> match(x)", inst);

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

@ -189,6 +189,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -189,6 +189,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
private static ILInstruction DetectPropertySubPatterns(MatchInstruction parentPattern, ILInstruction trueInst,
ILInstruction parentFalseInst, BlockContainer container, ILTransformContext context, ref ControlFlowGraph? cfg)
{
if (!context.Settings.RecursivePatternMatching)
{
return trueInst;
}
while (true)
{
Block? trueBlock = trueInst as Block;
@ -230,7 +234,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -230,7 +234,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ExtensionMethods.Swap(ref trueInst, ref falseInst);
negate = true;
}
if (MatchInstruction.IsPatternMatch(condition, out var operand))
if (MatchInstruction.IsPatternMatch(condition, out var operand, context.Settings))
{
if (!PropertyOrFieldAccess(operand, out var target, out _))
{
@ -240,6 +244,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -240,6 +244,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
return null;
}
if (negate && !context.Settings.PatternCombinators)
{
return null;
}
context.Step("Move property sub pattern", condition);
if (negate)
{
@ -253,8 +261,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -253,8 +261,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
return null;
}
context.Step("Move property sub pattern", condition);
parentPattern.SubPatterns.Add(new Comp(negate ? ComparisonKind.Equality : ComparisonKind.Inequality, Sign.None, condition, new LdcI4(0)));
if (!negate && !context.Settings.PatternCombinators)
{
return null;
}
context.Step("Sub pattern: implicit != 0", condition);
parentPattern.SubPatterns.Add(new Comp(negate ? ComparisonKind.Equality : ComparisonKind.Inequality,
Sign.None, condition, new LdcI4(0)));
}
else
{
@ -376,7 +389,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -376,7 +389,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return null;
}
if (varPattern.Variable.AddressCount == 1)
if (varPattern.Variable.AddressCount == 1 && context.Settings.PatternCombinators)
{
context.Step("Nullable.HasValue check -> not null pattern", block);
varPattern.ReplaceWith(new Comp(ComparisonKind.Inequality, ComparisonLiftingKind.CSharp, StackType.O, Sign.None, varPattern.TestedOperand, new LdNull()));
@ -412,6 +425,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -412,6 +425,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
return null;
}
if (!(context.Settings.RelationalPatterns || comp.Kind is ComparisonKind.Equality or ComparisonKind.Inequality))
{
return null;
}
bool negated = false;
if (!DetectExitPoints.CompatibleExitInstruction(falseInst, parentFalseInst))
{
@ -426,6 +443,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -426,6 +443,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
return null;
}
if (negated && !context.Settings.PatternCombinators)
{
return null;
}
context.Step("Nullable.HasValue check + Nullable.GetValueOrDefault pattern", block);
// varPattern: match (v = testedOperand)
// comp: comp.i4(call GetValueOrDefault(ldloca v) != ldc.i4 42)

27
ILSpy/Properties/Resources.Designer.cs generated

@ -1145,6 +1145,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1145,6 +1145,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Pattern combinators (and, or, not).
/// </summary>
public static string DecompilerSettings_PatternCombinators {
get {
return ResourceManager.GetString("DecompilerSettings.PatternCombinators", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use pattern matching expressions.
/// </summary>
@ -1199,6 +1208,24 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1199,6 +1208,24 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Recursive pattern matching.
/// </summary>
public static string DecompilerSettings_RecursivePatternMatching {
get {
return ResourceManager.GetString("DecompilerSettings.RecursivePatternMatching", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Relational patterns.
/// </summary>
public static string DecompilerSettings_RelationalPatterns {
get {
return ResourceManager.GetString("DecompilerSettings.RelationalPatterns", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Remove dead and side effect free code (use with caution!).
/// </summary>

9
ILSpy/Properties/Resources.resx

@ -405,6 +405,9 @@ Are you sure you want to continue?</value> @@ -405,6 +405,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.ParameterNullCheck" xml:space="preserve">
<value>Use parameter null checking</value>
</data>
<data name="DecompilerSettings.PatternCombinators" xml:space="preserve">
<value>Pattern combinators (and, or, not)</value>
</data>
<data name="DecompilerSettings.PatternMatching" xml:space="preserve">
<value>Use pattern matching expressions</value>
</data>
@ -423,6 +426,12 @@ Are you sure you want to continue?</value> @@ -423,6 +426,12 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.RecordStructs" xml:space="preserve">
<value>Record structs</value>
</data>
<data name="DecompilerSettings.RecursivePatternMatching" xml:space="preserve">
<value>Recursive pattern matching</value>
</data>
<data name="DecompilerSettings.RelationalPatterns" xml:space="preserve">
<value>Relational patterns</value>
</data>
<data name="DecompilerSettings.RemoveDeadAndSideEffectFreeCodeUseWithCaution" xml:space="preserve">
<value>Remove dead and side effect free code (use with caution!)</value>
</data>

Loading…
Cancel
Save