Skip to content

Commit 2f960ae

Browse files
committed
Breaking long, multi-term if statement conditions onto separate lines
1 parent c43ffcf commit 2f960ae

File tree

5 files changed

+105
-24
lines changed

5 files changed

+105
-24
lines changed

ReadableExpressions.UnitTests/WhenTranslatingConditionals.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
{
33
using System;
44
using System.Linq.Expressions;
5-
using System.Reflection;
6-
using System.Reflection.Emit;
75
using Microsoft.VisualStudio.TestTools.UnitTesting;
86

97
[TestClass]
@@ -409,6 +407,31 @@ public void ShouldIncludeReturnKeywordsForConstantsAndCasts()
409407

410408
Assert.AreEqual(EXPECTED.TrimStart(), translated);
411409
}
410+
411+
[TestMethod]
412+
public void ShouldBreakLongMultipleConditionsOntoMultipleLines()
413+
{
414+
var intVariable1 = Expression.Variable(typeof(int), "thisVariableHasALongName");
415+
var intVariable2 = Expression.Variable(typeof(int), "thisOtherVariableHasALongNameToo");
416+
var int1IsGreaterThanInt2 = Expression.GreaterThan(intVariable1, intVariable2);
417+
var int1IsNotEqualToInt2 = Expression.NotEqual(intVariable1, intVariable2);
418+
419+
var intIsInRange = Expression.AndAlso(int1IsGreaterThanInt2, int1IsNotEqualToInt2);
420+
Expression<Action> writeYo = () => Console.WriteLine("Yo!");
421+
var ifInRangeWriteYo = Expression.IfThen(intIsInRange, writeYo.Body);
422+
423+
424+
var translated = ifInRangeWriteYo.ToReadableString();
425+
426+
const string EXPECTED = @"
427+
if ((thisVariableHasALongName > thisOtherVariableHasALongNameToo) &&
428+
(thisVariableHasALongName != thisOtherVariableHasALongNameToo))
429+
{
430+
Console.WriteLine(""Yo!"");
431+
}";
432+
433+
Assert.AreEqual(EXPECTED.TrimStart(), translated);
434+
}
412435
}
413436

414437
#region Helpers

ReadableExpressions/Translators/BinaryExpressionTranslator.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ internal BinaryExpressionTranslator(NegationExpressionTranslator negationTransla
5656
};
5757
}
5858

59+
public static string GetOperator(Expression expression) => _operatorsByNodeType[expression.NodeType];
60+
5961
public override string Translate(Expression expression, TranslationContext context)
6062
{
6163
var binary = (BinaryExpression)expression;
@@ -70,7 +72,7 @@ public override string Translate(Expression expression, TranslationContext conte
7072
private static string Translate(BinaryExpression binary, TranslationContext context)
7173
{
7274
var left = TranslateOperand(binary.Left, context);
73-
var @operator = _operatorsByNodeType[binary.NodeType];
75+
var @operator = GetOperator(binary);
7476
var right = TranslateOperand(binary.Right, context);
7577

7678
var operation = $"{left} {@operator} {right}";
@@ -115,7 +117,7 @@ private static string AdjustForCheckedOperatorIfAppropriate(
115117
return $"checked({operation})";
116118
}
117119

118-
private string TranslateAddition(BinaryExpression binary, TranslationContext context)
120+
private static string TranslateAddition(BinaryExpression binary, TranslationContext context)
119121
{
120122
if ((binary.Left.Type != typeof(string)) && (binary.Right.Type != typeof(string)))
121123
{

ReadableExpressions/Translators/ConditionalExpressionTranslator.cs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public override string Translate(Expression expression, TranslationContext conte
2828

2929
if (IsTernary(conditional))
3030
{
31-
return new TernaryFormatter(conditional.Test, ifTrueBlock, ifFalseBlock, context);
31+
return new FormattedTernary(conditional.Test, ifTrueBlock, ifFalseBlock, context);
3232
}
3333

3434
var test = GetTest(conditional, context);
@@ -43,14 +43,7 @@ public override string Translate(Expression expression, TranslationContext conte
4343

4444
private static string GetTest(ConditionalExpression conditional, TranslationContext context)
4545
{
46-
var test = context.TranslateAsCodeBlock(conditional.Test);
47-
48-
if (test.IsMultiLine())
49-
{
50-
test = test.Indented().TrimStart();
51-
}
52-
53-
return test.WithSurroundingParentheses(checkExisting: true);
46+
return new FormattedCondition(conditional.Test, context);
5447
}
5548

5649
private static bool HasNoElseCondition(ConditionalExpression conditional)
@@ -59,15 +52,9 @@ private static bool HasNoElseCondition(ConditionalExpression conditional)
5952
(conditional.Type == typeof(void));
6053
}
6154

62-
private static string IfStatement(string test, string body)
63-
{
64-
return $"if {test}{body}";
65-
}
55+
private static string IfStatement(string test, string body) => $"if {test}{body}";
6656

67-
private static bool IsTernary(Expression conditional)
68-
{
69-
return conditional.Type != typeof(void);
70-
}
57+
private static bool IsTernary(Expression conditional) => conditional.Type != typeof(void);
7158

7259
private static string ShortCircuitingIf(string test, CodeBlock ifTrue, CodeBlock ifFalse)
7360
{
@@ -94,7 +81,7 @@ private static string IfElse(
9481
? " " + ifFalse.WithoutCurlyBraces()
9582
: ifFalse.WithCurlyBraces();
9683

97-
string ifElseBlock = $@"
84+
var ifElseBlock = $@"
9885
if {test}{ifTrue.WithCurlyBraces()}
9986
else{ifFalseBlock}";
10087

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
namespace AgileObjects.ReadableExpressions.Translators.Formatting
2+
{
3+
using System;
4+
using System.Linq.Expressions;
5+
6+
internal class FormattedCondition : FormattableExpressionBase
7+
{
8+
private readonly Expression _condition;
9+
private readonly TranslationContext _context;
10+
private readonly string _singleLineTest;
11+
12+
public FormattedCondition(
13+
Expression condition,
14+
TranslationContext context)
15+
{
16+
_condition = condition;
17+
_context = context;
18+
19+
var test = context.TranslateAsCodeBlock(condition);
20+
21+
if (test.IsMultiLine())
22+
{
23+
test = test.Indented().TrimStart();
24+
}
25+
26+
_singleLineTest = test.WithSurroundingParentheses(checkExisting: true);
27+
28+
MultipleLineTranslationFactory = GetMultipleLineTranslation;
29+
}
30+
31+
protected override Func<string> SingleLineTranslationFactory => () => _singleLineTest;
32+
33+
protected override Func<string> MultipleLineTranslationFactory { get; }
34+
35+
private string GetMultipleLineTranslation()
36+
{
37+
if (IsNotRelevantBinary(_condition, out BinaryExpression conditionBinary))
38+
{
39+
return _singleLineTest;
40+
}
41+
42+
var conditionLeft = new FormattedCondition(conditionBinary.Left, _context);
43+
var conditionOperator = BinaryExpressionTranslator.GetOperator(conditionBinary);
44+
var conditionRight = new FormattedCondition(conditionBinary.Right, _context);
45+
46+
var condition = $@"
47+
{conditionLeft} {conditionOperator}
48+
{conditionRight.ToString().Indented()}".TrimStart().WithSurroundingParentheses();
49+
50+
return condition;
51+
}
52+
53+
private static bool IsNotRelevantBinary(Expression condition, out BinaryExpression binary)
54+
{
55+
switch (condition.NodeType)
56+
{
57+
case ExpressionType.And:
58+
case ExpressionType.AndAlso:
59+
case ExpressionType.Or:
60+
case ExpressionType.OrElse:
61+
binary = (BinaryExpression)condition;
62+
return false;
63+
}
64+
65+
binary = null;
66+
return true;
67+
}
68+
}
69+
}

ReadableExpressions/Translators/Formatting/TernaryFormatter.cs renamed to ReadableExpressions/Translators/Formatting/FormattedTernary.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ namespace AgileObjects.ReadableExpressions.Translators.Formatting
33
using System;
44
using System.Linq.Expressions;
55

6-
internal class TernaryFormatter : FormattableExpressionBase
6+
internal class FormattedTernary : FormattableExpressionBase
77
{
8-
public TernaryFormatter(
8+
public FormattedTernary(
99
Expression condition,
1010
CodeBlock ifTrue,
1111
CodeBlock ifFalse,

0 commit comments

Comments
 (0)