Browse Source

Improve use of dynamic expressions in conditional context:

Let "operator true" be invoked implicitly where possible.
pull/1165/head
Daniel Grunwald 7 years ago
parent
commit
02dde92bcb
  1. 14
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  3. 14
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  4. 5
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs

14
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2527,12 +2527,16 @@ namespace ICSharpCode.Decompiler.CSharp
return CreateUnaryOperator(UnaryOperatorType.Plus); return CreateUnaryOperator(UnaryOperatorType.Plus);
case ExpressionType.IsTrue: case ExpressionType.IsTrue:
var operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo); var operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo);
if (IfInstruction.IsInConditionSlot(inst)) { Expression expr;
// TODO if (inst.SlotInfo == IfInstruction.ConditionSlot) {
// We rely on the context implicitly invoking "operator true".
expr = new UnaryOperatorExpression(UnaryOperatorType.IsTrue, operand);
} else {
// Create a dummy conditional to ensure "operator true" will be invoked.
expr = new ConditionalExpression(operand, new PrimitiveExpression(true), new PrimitiveExpression(false));
} }
return new ConditionalExpression(operand.Expression, new PrimitiveExpression(true), new PrimitiveExpression(false)) return expr.WithILInstruction(inst)
.WithILInstruction(inst) .WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Boolean)));
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Boolean)));
default: default:
return base.VisitDynamicUnaryOperatorInstruction(inst, context); return base.VisitDynamicUnaryOperatorInstruction(inst, context);
} }

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

@ -1102,7 +1102,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType); var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType);
if (opType == UnaryOperatorType.Await) { if (opType == UnaryOperatorType.Await) {
WriteKeyword(opSymbol); WriteKeyword(opSymbol);
} else if (!IsPostfixOperator(opType) && opType != UnaryOperatorType.NullConditionalRewrap) { } else if (!IsPostfixOperator(opType) && opSymbol != null) {
WriteToken(opSymbol); WriteToken(opSymbol);
} }
unaryOperatorExpression.Expression.AcceptVisitor(this); unaryOperatorExpression.Expression.AcceptVisitor(this);

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

@ -64,6 +64,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return Primary; return Primary;
case UnaryOperatorType.NullConditionalRewrap: case UnaryOperatorType.NullConditionalRewrap:
return NullableRewrap; return NullableRewrap;
case UnaryOperatorType.IsTrue:
return Conditional;
default: default:
return Unary; return Unary;
} }
@ -264,12 +266,13 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
if (InsertParenthesesForReadability && precedence < Equality) { if (InsertParenthesesForReadability && precedence < Equality) {
// In readable mode, boost the priority of the left-hand side if the operator // In readable mode, boost the priority of the left-hand side if the operator
// there isn't the same as the operator on this expression. // there isn't the same as the operator on this expression.
int boostTo = IsBitwise(binaryOperatorExpression.Operator) ? Unary : Equality;
if (GetBinaryOperatorType(binaryOperatorExpression.Left) == binaryOperatorExpression.Operator) { if (GetBinaryOperatorType(binaryOperatorExpression.Left) == binaryOperatorExpression.Operator) {
ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence); ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence);
} else { } else {
ParenthesizeIfRequired(binaryOperatorExpression.Left, Equality); ParenthesizeIfRequired(binaryOperatorExpression.Left, boostTo);
} }
ParenthesizeIfRequired(binaryOperatorExpression.Right, Equality); ParenthesizeIfRequired(binaryOperatorExpression.Right, boostTo);
} else { } else {
// all other binary operators are left-associative // all other binary operators are left-associative
ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence); ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence);
@ -279,6 +282,13 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
base.VisitBinaryOperatorExpression(binaryOperatorExpression); base.VisitBinaryOperatorExpression(binaryOperatorExpression);
} }
static bool IsBitwise(BinaryOperatorType op)
{
return op == BinaryOperatorType.BitwiseAnd
|| op == BinaryOperatorType.BitwiseOr
|| op == BinaryOperatorType.ExclusiveOr;
}
BinaryOperatorType? GetBinaryOperatorType(Expression expr) BinaryOperatorType? GetBinaryOperatorType(Expression expr)
{ {
BinaryOperatorExpression boe = expr as BinaryOperatorExpression; BinaryOperatorExpression boe = expr as BinaryOperatorExpression;

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

@ -117,6 +117,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
case UnaryOperatorType.NullConditional: case UnaryOperatorType.NullConditional:
return NullConditionalRole; return NullConditionalRole;
case UnaryOperatorType.NullConditionalRewrap: case UnaryOperatorType.NullConditionalRewrap:
case UnaryOperatorType.IsTrue:
return null; // no syntax return null; // no syntax
default: default:
throw new NotSupportedException("Invalid value for UnaryOperatorType"); throw new NotSupportedException("Invalid value for UnaryOperatorType");
@ -193,5 +194,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// This has no syntax in C#, but the node is used to ensure parentheses are inserted where necessary. /// This has no syntax in C#, but the node is used to ensure parentheses are inserted where necessary.
/// </summary> /// </summary>
NullConditionalRewrap, NullConditionalRewrap,
/// <summary>
/// Implicit call of "operator true".
/// </summary>
IsTrue,
} }
} }

Loading…
Cancel
Save