Browse Source

Add support for unsigned right shift.

Only for user-defined operators so far; builtin right shifts still cast to the appropriate type.
pull/2994/head
Daniel Grunwald 2 years ago
parent
commit
3c46271a11
  1. 32
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
  2. 10
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Operators.cs
  3. 1
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  4. 7
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  5. 1
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
  6. 1
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  7. 3
      ICSharpCode.Decompiler/CSharp/OutputVisitor/GenericGrammarAmbiguityVisitor.cs
  8. 1
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  9. 21
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
  10. 7
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
  11. 9
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs
  12. 5
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/BinaryOperatorExpression.cs
  13. 5
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs
  14. 7
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  15. 6
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  16. 21
      ICSharpCode.Decompiler/DecompilerSettings.cs
  17. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  18. 4
      ICSharpCode.Decompiler/Output/IAmbience.cs
  19. 4
      ILSpy/Languages/CSharpLanguage.cs
  20. 9
      ILSpy/Properties/Resources.Designer.cs
  21. 3
      ILSpy/Properties/Resources.resx

32
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs

@ -201,6 +201,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
#if CS110
public static CustomStruct operator >>>(CustomStruct lhs, int rhs)
{
throw new NotImplementedException();
}
#endif
public static CustomStruct operator &(CustomStruct lhs, CustomStruct rhs) public static CustomStruct operator &(CustomStruct lhs, CustomStruct rhs)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -4219,6 +4225,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
#endif #endif
} }
#if CS110
public static void CustomStructUnsignedRightShiftTest(CustomStruct p, CustomClass c, CustomStruct2 s)
{
//CustomStruct l = default(CustomStruct);
//p >>>= 5;
//l >>>= 5;
customStructField >>>= 5;
CustomStructProp >>>= 5;
c.CustomStructField >>>= 5;
c.CustomStructProp >>>= 5;
s.CustomStructField >>>= 5;
s.CustomStructProp >>>= 5;
customClassField.CustomStructField >>>= 5;
customClassField.CustomStructProp >>>= 5;
otherCustomStructField.CustomStructField >>>= 5;
otherCustomStructField.CustomStructProp >>>= 5;
CustomClassProp.CustomStructField >>>= 5;
CustomClassProp.CustomStructProp >>>= 5;
GetClass().CustomStructField >>>= 5;
GetClass().CustomStructProp >>>= 5;
GetRefStruct().CustomStructField >>>= 5;
GetRefStruct().CustomStructProp >>>= 5;
GetRefCustomStruct() >>>= 5;
}
#endif
public static void CustomStructBitAndTest(CustomStruct p, CustomClass c, CustomStruct2 s) public static void CustomStructBitAndTest(CustomStruct p, CustomClass c, CustomStruct2 s)
{ {
//CustomStruct l = default(CustomStruct); //CustomStruct l = default(CustomStruct);

10
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Operators.cs

@ -72,6 +72,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return null; return null;
} }
#if CS110
public static AllOperators operator >>>(AllOperators a, int b)
{
return null;
}
#endif
public static AllOperators operator ~(AllOperators a) public static AllOperators operator ~(AllOperators a)
{ {
return null; return null;
@ -170,6 +177,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
c = a ^ b; c = a ^ b;
c = a << 5; c = a << 5;
c = a >> 5; c = a >> 5;
#if CS110
c = a >>> 5;
#endif
c = ~a; c = ~a;
c = !a; c = !a;
c = -a; c = -a;

1
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -530,6 +530,7 @@ namespace ICSharpCode.Decompiler.CSharp
typeSystemAstBuilder.SupportInitAccessors = settings.InitAccessors; typeSystemAstBuilder.SupportInitAccessors = settings.InitAccessors;
typeSystemAstBuilder.SupportRecordClasses = settings.RecordClasses; typeSystemAstBuilder.SupportRecordClasses = settings.RecordClasses;
typeSystemAstBuilder.SupportRecordStructs = settings.RecordStructs; typeSystemAstBuilder.SupportRecordStructs = settings.RecordStructs;
typeSystemAstBuilder.SupportUnsignedRightShift = settings.UnsignedRightShift;
typeSystemAstBuilder.AlwaysUseGlobal = settings.AlwaysUseGlobal; typeSystemAstBuilder.AlwaysUseGlobal = settings.AlwaysUseGlobal;
return typeSystemAstBuilder; return typeSystemAstBuilder;
} }

7
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1729,6 +1729,7 @@ namespace ICSharpCode.Decompiler.CSharp
case BinaryOperatorType.ExclusiveOr: case BinaryOperatorType.ExclusiveOr:
case BinaryOperatorType.ShiftLeft: case BinaryOperatorType.ShiftLeft:
case BinaryOperatorType.ShiftRight: case BinaryOperatorType.ShiftRight:
case BinaryOperatorType.UnsignedShiftRight:
return false; return false;
default: default:
return true; return true;
@ -1804,7 +1805,7 @@ namespace ICSharpCode.Decompiler.CSharp
else if (inst.Method.Parameters.Count == 2) else if (inst.Method.Parameters.Count == 2)
{ {
var value = Translate(inst.Value).ConvertTo(inst.Method.Parameters[1].Type, this); var value = Translate(inst.Value).ConvertTo(inst.Method.Parameters[1].Type, this);
AssignmentOperatorType? op = GetAssignmentOperatorTypeFromMetadataName(inst.Method.Name); AssignmentOperatorType? op = GetAssignmentOperatorTypeFromMetadataName(inst.Method.Name, settings);
Debug.Assert(op != null); Debug.Assert(op != null);
return new AssignmentExpression(target, op.Value, value) return new AssignmentExpression(target, op.Value, value)
@ -1822,7 +1823,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
internal static AssignmentOperatorType? GetAssignmentOperatorTypeFromMetadataName(string name) internal static AssignmentOperatorType? GetAssignmentOperatorTypeFromMetadataName(string name, DecompilerSettings settings)
{ {
switch (name) switch (name)
{ {
@ -1846,6 +1847,8 @@ namespace ICSharpCode.Decompiler.CSharp
return AssignmentOperatorType.ShiftLeft; return AssignmentOperatorType.ShiftLeft;
case "op_RightShift": case "op_RightShift":
return AssignmentOperatorType.ShiftRight; return AssignmentOperatorType.ShiftRight;
case "op_UnsignedRightShift" when settings.UnsignedRightShift:
return AssignmentOperatorType.UnsignedShiftRight;
default: default:
return null; return null;
} }

1
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs

@ -237,6 +237,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
astBuilder.SupportInitAccessors = (ConversionFlags & ConversionFlags.SupportInitAccessors) != 0; astBuilder.SupportInitAccessors = (ConversionFlags & ConversionFlags.SupportInitAccessors) != 0;
astBuilder.SupportRecordClasses = (ConversionFlags & ConversionFlags.SupportRecordClasses) != 0; astBuilder.SupportRecordClasses = (ConversionFlags & ConversionFlags.SupportRecordClasses) != 0;
astBuilder.SupportRecordStructs = (ConversionFlags & ConversionFlags.SupportRecordStructs) != 0; astBuilder.SupportRecordStructs = (ConversionFlags & ConversionFlags.SupportRecordStructs) != 0;
astBuilder.SupportUnsignedRightShift = (ConversionFlags & ConversionFlags.SupportUnsignedRightShift) != 0;
return astBuilder; return astBuilder;
} }

1
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -826,6 +826,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
break; break;
case BinaryOperatorType.ShiftLeft: case BinaryOperatorType.ShiftLeft:
case BinaryOperatorType.ShiftRight: case BinaryOperatorType.ShiftRight:
case BinaryOperatorType.UnsignedShiftRight:
spacePolicy = policy.SpaceAroundShiftOperator; spacePolicy = policy.SpaceAroundShiftOperator;
break; break;
case BinaryOperatorType.NullCoalescing: case BinaryOperatorType.NullCoalescing:

3
ICSharpCode.Decompiler/CSharp/OutputVisitor/GenericGrammarAmbiguityVisitor.cs

@ -92,6 +92,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case BinaryOperatorType.ShiftRight when genericNestingLevel >= 2: case BinaryOperatorType.ShiftRight when genericNestingLevel >= 2:
genericNestingLevel -= 2; genericNestingLevel -= 2;
break; break;
case BinaryOperatorType.UnsignedShiftRight when genericNestingLevel >= 3:
genericNestingLevel -= 3;
break;
default: default:
return true; // stop visiting, no ambiguity found return true; // stop visiting, no ambiguity found
} }

1
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -122,6 +122,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return PrecedenceLevel.Additive; return PrecedenceLevel.Additive;
case BinaryOperatorType.ShiftLeft: case BinaryOperatorType.ShiftLeft:
case BinaryOperatorType.ShiftRight: case BinaryOperatorType.ShiftRight:
case BinaryOperatorType.UnsignedShiftRight:
return PrecedenceLevel.Shift; return PrecedenceLevel.Shift;
case BinaryOperatorType.GreaterThan: case BinaryOperatorType.GreaterThan:
case BinaryOperatorType.GreaterThanOrEqual: case BinaryOperatorType.GreaterThanOrEqual:

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

@ -674,6 +674,27 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
} }
} }
} }
OperatorMethod[]? unsignedShiftRightOperators;
public OperatorMethod[] UnsignedShiftRightOperators {
get {
OperatorMethod[]? ops = LazyInit.VolatileRead(ref unsignedShiftRightOperators);
if (ops != null)
{
return ops;
}
else
{
return LazyInit.GetOrSet(ref unsignedShiftRightOperators, Lift(
new LambdaBinaryOperatorMethod<int, int>(this, (a, b) => (int)((uint)a >> b)),
new LambdaBinaryOperatorMethod<uint, int>(this, (a, b) => a >> b),
new LambdaBinaryOperatorMethod<long, int>(this, (a, b) => (long)((ulong)a >> b)),
new LambdaBinaryOperatorMethod<ulong, int>(this, (a, b) => a >> b)
));
}
}
}
#endregion #endregion
#region Equality operators #region Equality operators

7
ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

@ -685,7 +685,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{ {
isNullable = true; isNullable = true;
} }
if (op == BinaryOperatorType.ShiftLeft || op == BinaryOperatorType.ShiftRight) if (op == BinaryOperatorType.ShiftLeft || op == BinaryOperatorType.ShiftRight || op == BinaryOperatorType.UnsignedShiftRight)
{ {
// special case: the shift operators allow "var x = null << null", producing int?. // special case: the shift operators allow "var x = null << null", producing int?.
if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null) if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
@ -805,6 +805,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
case BinaryOperatorType.ShiftRight: case BinaryOperatorType.ShiftRight:
methodGroup = operators.ShiftRightOperators; methodGroup = operators.ShiftRightOperators;
break; break;
case BinaryOperatorType.UnsignedShiftRight:
methodGroup = operators.UnsignedShiftRightOperators;
break;
case BinaryOperatorType.Equality: case BinaryOperatorType.Equality:
case BinaryOperatorType.InEquality: case BinaryOperatorType.InEquality:
case BinaryOperatorType.LessThan: case BinaryOperatorType.LessThan:
@ -1256,6 +1259,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return "op_LeftShift"; return "op_LeftShift";
case BinaryOperatorType.ShiftRight: case BinaryOperatorType.ShiftRight:
return "op_RightShift"; return "op_RightShift";
case BinaryOperatorType.UnsignedShiftRight:
return "op_UnsignedRightShift";
case BinaryOperatorType.Equality: case BinaryOperatorType.Equality:
return "op_Equality"; return "op_Equality";
case BinaryOperatorType.InEquality: case BinaryOperatorType.InEquality:

9
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs

@ -47,6 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public readonly static TokenRole ModulusRole = new TokenRole("%="); public readonly static TokenRole ModulusRole = new TokenRole("%=");
public readonly static TokenRole ShiftLeftRole = new TokenRole("<<="); public readonly static TokenRole ShiftLeftRole = new TokenRole("<<=");
public readonly static TokenRole ShiftRightRole = new TokenRole(">>="); public readonly static TokenRole ShiftRightRole = new TokenRole(">>=");
public readonly static TokenRole UnsignedShiftRightRole = new TokenRole(">>>=");
public readonly static TokenRole BitwiseAndRole = new TokenRole("&="); public readonly static TokenRole BitwiseAndRole = new TokenRole("&=");
public readonly static TokenRole BitwiseOrRole = new TokenRole("|="); public readonly static TokenRole BitwiseOrRole = new TokenRole("|=");
public readonly static TokenRole ExclusiveOrRole = new TokenRole("^="); public readonly static TokenRole ExclusiveOrRole = new TokenRole("^=");
@ -129,6 +130,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return ShiftLeftRole; return ShiftLeftRole;
case AssignmentOperatorType.ShiftRight: case AssignmentOperatorType.ShiftRight:
return ShiftRightRole; return ShiftRightRole;
case AssignmentOperatorType.UnsignedShiftRight:
return UnsignedShiftRightRole;
case AssignmentOperatorType.BitwiseAnd: case AssignmentOperatorType.BitwiseAnd:
return BitwiseAndRole; return BitwiseAndRole;
case AssignmentOperatorType.BitwiseOr: case AssignmentOperatorType.BitwiseOr:
@ -164,6 +167,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return BinaryOperatorType.ShiftLeft; return BinaryOperatorType.ShiftLeft;
case AssignmentOperatorType.ShiftRight: case AssignmentOperatorType.ShiftRight:
return BinaryOperatorType.ShiftRight; return BinaryOperatorType.ShiftRight;
case AssignmentOperatorType.UnsignedShiftRight:
return BinaryOperatorType.UnsignedShiftRight;
case AssignmentOperatorType.BitwiseAnd: case AssignmentOperatorType.BitwiseAnd:
return BinaryOperatorType.BitwiseAnd; return BinaryOperatorType.BitwiseAnd;
case AssignmentOperatorType.BitwiseOr: case AssignmentOperatorType.BitwiseOr:
@ -195,6 +200,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return ExpressionType.LeftShiftAssign; return ExpressionType.LeftShiftAssign;
case AssignmentOperatorType.ShiftRight: case AssignmentOperatorType.ShiftRight:
return ExpressionType.RightShiftAssign; return ExpressionType.RightShiftAssign;
case AssignmentOperatorType.UnsignedShiftRight:
return ExpressionType.Extension;
case AssignmentOperatorType.BitwiseAnd: case AssignmentOperatorType.BitwiseAnd:
return ExpressionType.AndAssign; return ExpressionType.AndAssign;
case AssignmentOperatorType.BitwiseOr: case AssignmentOperatorType.BitwiseOr:
@ -259,6 +266,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
ShiftLeft, ShiftLeft,
/// <summary>left >>= right</summary> /// <summary>left >>= right</summary>
ShiftRight, ShiftRight,
/// <summary>left >>>= right</summary>
UnsignedShiftRight,
/// <summary>left &amp;= right</summary> /// <summary>left &amp;= right</summary>
BitwiseAnd, BitwiseAnd,

5
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/BinaryOperatorExpression.cs

@ -52,6 +52,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public readonly static TokenRole ModulusRole = new TokenRole("%"); public readonly static TokenRole ModulusRole = new TokenRole("%");
public readonly static TokenRole ShiftLeftRole = new TokenRole("<<"); public readonly static TokenRole ShiftLeftRole = new TokenRole("<<");
public readonly static TokenRole ShiftRightRole = new TokenRole(">>"); public readonly static TokenRole ShiftRightRole = new TokenRole(">>");
public readonly static TokenRole UnsignedShiftRightRole = new TokenRole(">>>");
public readonly static TokenRole NullCoalescingRole = new TokenRole("??"); public readonly static TokenRole NullCoalescingRole = new TokenRole("??");
public readonly static TokenRole RangeRole = new TokenRole(".."); public readonly static TokenRole RangeRole = new TokenRole("..");
public readonly static TokenRole IsKeywordRole = IsExpression.IsKeywordRole; public readonly static TokenRole IsKeywordRole = IsExpression.IsKeywordRole;
@ -151,6 +152,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return ShiftLeftRole; return ShiftLeftRole;
case BinaryOperatorType.ShiftRight: case BinaryOperatorType.ShiftRight:
return ShiftRightRole; return ShiftRightRole;
case BinaryOperatorType.UnsignedShiftRight:
return UnsignedShiftRightRole;
case BinaryOperatorType.NullCoalescing: case BinaryOperatorType.NullCoalescing:
return NullCoalescingRole; return NullCoalescingRole;
case BinaryOperatorType.Range: case BinaryOperatorType.Range:
@ -262,6 +265,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
ShiftLeft, ShiftLeft,
/// <summary>left &gt;&gt; right</summary> /// <summary>left &gt;&gt; right</summary>
ShiftRight, ShiftRight,
/// <summary>left &gt;&gt;&gt; right</summary>
UnsignedShiftRight,
/// <summary>left ?? right</summary> /// <summary>left ?? right</summary>
NullCoalescing, NullCoalescing,

5
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs

@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
ExclusiveOr, ExclusiveOr,
LeftShift, LeftShift,
RightShift, RightShift,
UnsignedRightShift,
Equality, Equality,
Inequality, Inequality,
GreaterThan, GreaterThan,
@ -94,6 +95,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole ExclusiveOrRole = new TokenRole("^"); public static readonly TokenRole ExclusiveOrRole = new TokenRole("^");
public static readonly TokenRole LeftShiftRole = new TokenRole("<<"); public static readonly TokenRole LeftShiftRole = new TokenRole("<<");
public static readonly TokenRole RightShiftRole = new TokenRole(">>"); public static readonly TokenRole RightShiftRole = new TokenRole(">>");
public static readonly TokenRole UnsignedRightShiftRole = new TokenRole(">>>");
public static readonly TokenRole EqualityRole = new TokenRole("=="); public static readonly TokenRole EqualityRole = new TokenRole("==");
public static readonly TokenRole InequalityRole = new TokenRole("!="); public static readonly TokenRole InequalityRole = new TokenRole("!=");
public static readonly TokenRole GreaterThanRole = new TokenRole(">"); public static readonly TokenRole GreaterThanRole = new TokenRole(">");
@ -127,6 +129,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
names[(int)OperatorType.ExclusiveOr] = new string[] { "^", "op_ExclusiveOr" }; names[(int)OperatorType.ExclusiveOr] = new string[] { "^", "op_ExclusiveOr" };
names[(int)OperatorType.LeftShift] = new string[] { "<<", "op_LeftShift" }; names[(int)OperatorType.LeftShift] = new string[] { "<<", "op_LeftShift" };
names[(int)OperatorType.RightShift] = new string[] { ">>", "op_RightShift" }; names[(int)OperatorType.RightShift] = new string[] { ">>", "op_RightShift" };
names[(int)OperatorType.UnsignedRightShift] = new string[] { ">>>", "op_UnsignedRightShift" };
names[(int)OperatorType.Equality] = new string[] { "==", "op_Equality" }; names[(int)OperatorType.Equality] = new string[] { "==", "op_Equality" };
names[(int)OperatorType.Inequality] = new string[] { "!=", "op_Inequality" }; names[(int)OperatorType.Inequality] = new string[] { "!=", "op_Inequality" };
names[(int)OperatorType.GreaterThan] = new string[] { ">", "op_GreaterThan" }; names[(int)OperatorType.GreaterThan] = new string[] { ">", "op_GreaterThan" };
@ -230,6 +233,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return LeftShiftRole; return LeftShiftRole;
case OperatorType.RightShift: case OperatorType.RightShift:
return RightShiftRole; return RightShiftRole;
case OperatorType.UnsignedRightShift:
return UnsignedRightShiftRole;
case OperatorType.Equality: case OperatorType.Equality:
return EqualityRole; return EqualityRole;
case OperatorType.Inequality: case OperatorType.Inequality:

7
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -225,6 +225,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary> /// </summary>
public bool SupportRecordStructs { get; set; } public bool SupportRecordStructs { get; set; }
/// <summary>
/// Controls whether C# 11 "operator >>>" is supported.
/// </summary>
public bool SupportUnsignedRightShift { get; set; }
/// <summary> /// <summary>
/// Controls whether all fully qualified type names should be prefixed with "global::". /// Controls whether all fully qualified type names should be prefixed with "global::".
/// </summary> /// </summary>
@ -2217,6 +2222,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name); OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name);
if (opType == null) if (opType == null)
return ConvertMethod(op); return ConvertMethod(op);
if (opType == OperatorType.UnsignedRightShift && !SupportUnsignedRightShift)
return ConvertMethod(op);
OperatorDeclaration decl = new OperatorDeclaration(); OperatorDeclaration decl = new OperatorDeclaration();
decl.Modifiers = GetMemberModifiers(op); decl.Modifiers = GetMemberModifiers(op);

6
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -142,7 +142,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
break; break;
} }
BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(method.Name); BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(method.Name, context.Settings);
if (bop != null && arguments.Length == 2) if (bop != null && arguments.Length == 2)
{ {
invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression
@ -350,7 +350,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
} }
static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name) static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name, DecompilerSettings settings)
{ {
switch (name) switch (name)
{ {
@ -374,6 +374,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return BinaryOperatorType.ShiftLeft; return BinaryOperatorType.ShiftLeft;
case "op_RightShift": case "op_RightShift":
return BinaryOperatorType.ShiftRight; return BinaryOperatorType.ShiftRight;
case "op_UnsignedRightShift" when settings.UnsignedRightShift:
return BinaryOperatorType.UnsignedShiftRight;
case "op_Equality": case "op_Equality":
return BinaryOperatorType.Equality; return BinaryOperatorType.Equality;
case "op_Inequality": case "op_Inequality":

21
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -154,12 +154,13 @@ namespace ICSharpCode.Decompiler
requiredMembers = false; requiredMembers = false;
numericIntPtr = false; numericIntPtr = false;
utf8StringLiterals = false; utf8StringLiterals = false;
unsignedRightShift = false;
} }
} }
public CSharp.LanguageVersion GetMinimumRequiredVersion() public CSharp.LanguageVersion GetMinimumRequiredVersion()
{ {
if (parameterNullCheck || scopedRef || requiredMembers || numericIntPtr || utf8StringLiterals) if (parameterNullCheck || scopedRef || requiredMembers || numericIntPtr || utf8StringLiterals || unsignedRightShift)
return CSharp.LanguageVersion.CSharp11_0; return CSharp.LanguageVersion.CSharp11_0;
if (fileScopedNamespaces || recordStructs) if (fileScopedNamespaces || recordStructs)
return CSharp.LanguageVersion.CSharp10_0; return CSharp.LanguageVersion.CSharp10_0;
@ -1199,6 +1200,24 @@ namespace ICSharpCode.Decompiler
} }
} }
bool unsignedRightShift = true;
/// <summary>
/// Gets/Sets whether to use C# 11.0 unsigned right shift operator.
/// </summary>
[Category("C# 11.0 / VS 2022.4")]
[Description("DecompilerSettings.UnsignedRightShift")]
public bool UnsignedRightShift {
get { return unsignedRightShift; }
set {
if (unsignedRightShift != value)
{
unsignedRightShift = value;
OnPropertyChanged();
}
}
}
bool showXmlDocumentation = true; bool showXmlDocumentation = true;
/// <summary> /// <summary>

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

@ -386,7 +386,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction rhs; ILInstruction rhs;
if (operatorCall.Arguments.Count == 2) if (operatorCall.Arguments.Count == 2)
{ {
if (CSharp.ExpressionBuilder.GetAssignmentOperatorTypeFromMetadataName(operatorCall.Method.Name) == null) if (CSharp.ExpressionBuilder.GetAssignmentOperatorTypeFromMetadataName(operatorCall.Method.Name, context.Settings) == null)
return false; return false;
rhs = operatorCall.Arguments[1]; rhs = operatorCall.Arguments[1];
} }

4
ICSharpCode.Decompiler/Output/IAmbience.cs

@ -109,6 +109,10 @@ namespace ICSharpCode.Decompiler.Output
/// Support <c>record</c> structs. /// Support <c>record</c> structs.
/// </summary> /// </summary>
SupportRecordStructs = 0x40000, SupportRecordStructs = 0x40000,
/// <summary>
/// Support <c>&gt;&gt;&gt;</c> as unsigned right shift operator.
/// </summary>
SupportUnsignedRightShift = 0x80000,
StandardConversionFlags = ShowParameterNames | StandardConversionFlags = ShowParameterNames |
ShowAccessibility | ShowAccessibility |

4
ILSpy/Languages/CSharpLanguage.cs

@ -749,6 +749,10 @@ namespace ICSharpCode.ILSpy
{ {
flags |= ConversionFlags.SupportRecordStructs; flags |= ConversionFlags.SupportRecordStructs;
} }
if (settings.UnsignedRightShift)
{
flags |= ConversionFlags.SupportUnsignedRightShift;
}
if (settings.InitAccessors) if (settings.InitAccessors)
{ {
flags |= ConversionFlags.SupportInitAccessors; flags |= ConversionFlags.SupportInitAccessors;

9
ILSpy/Properties/Resources.Designer.cs generated

@ -1280,6 +1280,15 @@ namespace ICSharpCode.ILSpy.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Unsigned right shift (&gt;&gt;&gt;).
/// </summary>
public static string DecompilerSettings_UnsignedRightShift {
get {
return ResourceManager.GetString("DecompilerSettings.UnsignedRightShift", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Use discards. /// Looks up a localized string similar to Use discards.
/// </summary> /// </summary>

3
ILSpy/Properties/Resources.resx

@ -450,6 +450,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.SwitchExpressions" xml:space="preserve"> <data name="DecompilerSettings.SwitchExpressions" xml:space="preserve">
<value>Switch expressions</value> <value>Switch expressions</value>
</data> </data>
<data name="DecompilerSettings.UnsignedRightShift" xml:space="preserve">
<value>Unsigned right shift (&gt;&gt;&gt;)</value>
</data>
<data name="DecompilerSettings.UseDiscards" xml:space="preserve"> <data name="DecompilerSettings.UseDiscards" xml:space="preserve">
<value>Use discards</value> <value>Use discards</value>
</data> </data>

Loading…
Cancel
Save