Skip to content

Commit 1e696df

Browse files
committed
Added Eqv and Imp operator support
1 parent 92e15e2 commit 1e696df

File tree

8 files changed

+138
-39
lines changed

8 files changed

+138
-39
lines changed

Rubberduck.Inspections/Concrete/UnreachableCaseInspection/ContextWrapperBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ public abstract class ContextWrapperBase
1313
public ContextWrapperBase(ParserRuleContext context, IParseTreeVisitorResults inspValues, IUnreachableCaseInspectionFactoryProvider factoryFactory)
1414
{
1515
_context = context;
16-
_rangeFilterFactory = factoryFactory.CreateIUCIRangeClauseFilterFactory();
17-
_valueFactory = factoryFactory.CreateIUCIValueFactory();
16+
_rangeFilterFactory = factoryFactory.CreateIRangeClauseFilterFactory();
17+
_valueFactory = factoryFactory.CreateIParseTreeValueFactory();
1818
_inspValues = inspValues;
1919
}
2020

Rubberduck.Inspections/Concrete/UnreachableCaseInspection/ParseTreeExpressionEvaluator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public class ParseTreeExpressionEvaluator : IParseTreeExpressionEvaluator
3636
[LogicSymbols.AND] = delegate (double LHS, double RHS) { return Convert.ToBoolean(LHS) && Convert.ToBoolean(RHS); },
3737
[LogicSymbols.OR] = delegate (double LHS, double RHS) { return Convert.ToBoolean(LHS) || Convert.ToBoolean(RHS); },
3838
[LogicSymbols.XOR] = delegate (double LHS, double RHS) { return Convert.ToBoolean(LHS) ^ Convert.ToBoolean(RHS); },
39+
[LogicSymbols.EQV] = delegate (double LHS, double RHS) { return Convert.ToBoolean(LHS).Equals(Convert.ToBoolean(RHS)); },
40+
[LogicSymbols.IMP] = delegate (double LHS, double RHS) { return Convert.ToBoolean(LHS).Equals(Convert.ToBoolean(RHS)) || Convert.ToBoolean(RHS); },
3941
};
4042

4143
private static Dictionary<string, Func<double, double>> MathOpsUnary = new Dictionary<string, Func<double, double>>()

Rubberduck.Inspections/Concrete/UnreachableCaseInspection/RangeClauseContextWrapper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public RangeClauseContextWrapper(VBAParser.RangeClauseContext context, IParseTre
3030
{
3131
_isValueRange = !(context.TO() is null);
3232
_isLTorGT = !(context.IS() is null);
33-
_isRelationalOp = Context.TryGetChildContext<VBAParser.RelationalOpContext>(out _);
33+
_isRelationalOp = Context.children.Any(ch => ch is ParserRuleContext && ParseTreeValueVisitor.IsLogicalContext(ch));
3434
_isSingleValue = !(_isValueRange || _isLTorGT || _isRelationalOp);
3535
_evalTypeName = string.Empty;
3636
IsUnreachable = false;
@@ -42,7 +42,8 @@ public RangeClauseContextWrapper(VBAParser.RangeClauseContext context, string ev
4242
{
4343
_isValueRange = !(context.TO() is null);
4444
_isLTorGT = !(context.IS() is null);
45-
_isRelationalOp = Context.TryGetChildContext<VBAParser.RelationalOpContext>(out _);
45+
_isRelationalOp = Context.children.Any(ch => ch is ParserRuleContext && ParseTreeValueVisitor.IsLogicalContext(ch));
46+
4647
_isSingleValue = !(_isValueRange || _isLTorGT || _isRelationalOp);
4748
IsUnreachable = false;
4849
AsFilter = FilterFactory.Create(evalTypeName, ValueFactory);

Rubberduck.Inspections/Concrete/UnreachableCaseInspection/RangeClauseFilter.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class RangeClauseFilter<T> : IRangeClauseFilter, IRangeClauseFilterTestSu
3030
{
3131
private readonly IParseTreeValueFactory _valueFactory;
3232
private readonly IRangeClauseFilterFactory _filterFactory;
33-
private readonly TryConvertParseTreeValue<T> _tNewConverter;
33+
private readonly TryConvertParseTreeValue<T> _valueConverter;
3434
private readonly T _trueValue;
3535
private readonly T _falseValue;
3636

@@ -49,7 +49,7 @@ public RangeClauseFilter(string typeName, IParseTreeValueFactory valueFactory, I
4949
{
5050
_valueFactory = valueFactory;
5151
_filterFactory = filterFactory;
52-
_tNewConverter = tConverter;
52+
_valueConverter = tConverter;
5353

5454
_ranges = new List<Tuple<T, T>>();
5555
_singleValues = new HashSet<T>();
@@ -158,7 +158,7 @@ public void AddIsClause(IParseTreeValue value, string opSymbol)
158158
{
159159
if (value.ParsesToConstantValue)
160160
{
161-
if (!_tNewConverter(value, out T result))
161+
if (!_valueConverter(value, out T result))
162162
{
163163
throw new ArgumentException();
164164
}
@@ -174,7 +174,7 @@ public void AddRelationalOp(IParseTreeValue value)
174174
{
175175
if (value.ParsesToConstantValue)
176176
{
177-
if (!_tNewConverter(value, out T result))
177+
if (!_valueConverter(value, out T result))
178178
{
179179
throw new ArgumentException();
180180
}
@@ -190,7 +190,7 @@ public void AddSingleValue(IParseTreeValue value)
190190
{
191191
if (value.ParsesToConstantValue)
192192
{
193-
if (!_tNewConverter(value, out T result))
193+
if (!_valueConverter(value, out T result))
194194
{
195195
throw new ArgumentException();
196196
}
@@ -215,7 +215,7 @@ public void AddValueRange(IParseTreeValue inputStartVal, IParseTreeValue inputEn
215215

216216
if (inputStartVal.ParsesToConstantValue && inputEndVal.ParsesToConstantValue)
217217
{
218-
if (!(_tNewConverter(inputStartVal, out T startVal) && _tNewConverter(inputEndVal, out T endVal)))
218+
if (!(_valueConverter(inputStartVal, out T startVal) && _valueConverter(inputEndVal, out T endVal)))
219219
{
220220
throw new ArgumentException();
221221
}
@@ -340,12 +340,12 @@ public override int GetHashCode()
340340
public void AddExtents(IParseTreeValue min, IParseTreeValue max)
341341
{
342342
_hasExtents = true;
343-
if (_tNewConverter(min, out _minExtent))
343+
if (_valueConverter(min, out _minExtent))
344344
{
345345
AddIsClauseImpl(_minExtent, LogicSymbols.LT);
346346
}
347347

348-
if (_tNewConverter(max, out _maxExtent))
348+
if (_valueConverter(max, out _maxExtent))
349349
{
350350
AddIsClauseImpl(_maxExtent, LogicSymbols.GT);
351351
}
@@ -357,8 +357,8 @@ private bool FiltersAllRelationalOps
357357
{
358358
if (ContainsBooleans)
359359
{
360-
return _singleValues.Contains(_trueValue)
361-
|| RangesFilterValue(_trueValue);
360+
return _singleValues.Contains(_trueValue) && _singleValues.Contains(_falseValue)
361+
|| RangesFilterValue(_trueValue) && RangesFilterValue(_falseValue);
362362
}
363363
return _singleValues.Contains(_trueValue) && _singleValues.Contains(_falseValue)
364364
|| RangesFilterValue(_trueValue) && RangesFilterValue(_falseValue)
@@ -846,7 +846,7 @@ private int RangesValuesCount()
846846
private T ConvertToContainedGeneric<K>(K value)
847847
{
848848
var parseTreeValue = _valueFactory.Create(value.ToString(), TypeName);
849-
if(_tNewConverter(parseTreeValue, out T tValue))
849+
if(_valueConverter(parseTreeValue, out T tValue))
850850
{
851851
return tValue;
852852
}

Rubberduck.Inspections/Concrete/UnreachableCaseInspection/SelectCaseStmtContextWrapper.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public SelectCaseStmtContextWrapper(VBAParser.SelectCaseStmtContext selectCaseCo
3232
_mismatchResults = new List<ParserRuleContext>();
3333
_caseElseResults = new List<ParserRuleContext>();
3434
_evalTypeName = null;
35-
_inspectionRangeFactory = factoryFactory.CreateUnreachableCaseInspectionRangeFactory();
35+
_inspectionRangeFactory = factoryFactory.CreateIRangeClauseContextWrapperFactory();
3636
}
3737

3838
public string EvaluationTypeName => _evalTypeName
@@ -194,6 +194,8 @@ internal static class LogicSymbols
194194
public static string OR => Tokens.Or;
195195
public static string XOR => Tokens.XOr;
196196
public static string NOT => Tokens.Not;
197+
public static string EQV => "Eqv";
198+
public static string IMP => "Imp";
197199

198200
private static string LoadSymbols(int target)
199201
{

Rubberduck.Inspections/Concrete/UnreachableCaseInspection/UnreachableCaseInspection.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ public UnreachableCaseInspection(RubberduckParserState state) : base(state)
3333
//TODO_Question: IUnreachableCaseInspectionFactoryFactory - candidate for IoCInstaller?
3434
var factoriesFactory = new UnreachableCaseInspectionFactoryProvider();
3535

36-
_selectStmtFactory = factoriesFactory.CreateUnreachableCaseInspectionSelectStmtFactory();
37-
_valueFactory = factoriesFactory.CreateIUCIValueFactory();
38-
_parseTreeVisitorFactory = factoriesFactory.CreateIUCIParseTreeValueVisitorFactory();
36+
_selectStmtFactory = factoriesFactory.CreateISelectStmtContextWrapperFactory();
37+
_valueFactory = factoriesFactory.CreateIParseTreeValueFactory();
38+
_parseTreeVisitorFactory = factoriesFactory.CreateIParseTreeValueVisitorFactory();
3939

4040
_parseTreeValueVisitor = _parseTreeVisitorFactory.Create(State, _valueFactory);
4141
}

Rubberduck.Inspections/Concrete/UnreachableCaseInspection/UnreachableCaseInspectionFactoryProvider.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,39 @@ namespace Rubberduck.Inspections.Concrete.UnreachableCaseInspection
33
{
44
public interface IUnreachableCaseInspectionFactoryProvider
55
{
6-
IParseTreeValueVisitorFactory CreateIUCIParseTreeValueVisitorFactory();
7-
IParseTreeValueFactory CreateIUCIValueFactory();
8-
IRangeClauseFilterFactory CreateIUCIRangeClauseFilterFactory();
9-
ISelectCaseStmtContextWrapperFactory CreateUnreachableCaseInspectionSelectStmtFactory();
10-
IRangeClauseContextWrapperFactory CreateUnreachableCaseInspectionRangeFactory();
6+
IParseTreeValueVisitorFactory CreateIParseTreeValueVisitorFactory();
7+
IParseTreeValueFactory CreateIParseTreeValueFactory();
8+
IRangeClauseFilterFactory CreateIRangeClauseFilterFactory();
9+
ISelectCaseStmtContextWrapperFactory CreateISelectStmtContextWrapperFactory();
10+
IRangeClauseContextWrapperFactory CreateIRangeClauseContextWrapperFactory();
1111
}
1212

1313
public class UnreachableCaseInspectionFactoryProvider : IUnreachableCaseInspectionFactoryProvider
1414
{
15-
public IParseTreeValueVisitorFactory CreateIUCIParseTreeValueVisitorFactory()
15+
public IParseTreeValueVisitorFactory CreateIParseTreeValueVisitorFactory()
1616
{
1717
return new ParseTreeValueVisitorFactory();
1818
}
1919

20-
public IParseTreeValueFactory CreateIUCIValueFactory()
20+
public IParseTreeValueFactory CreateIParseTreeValueFactory()
2121
{
2222
return new ParseTreeValueFactory();
2323
}
2424

25-
public IRangeClauseFilterFactory CreateIUCIRangeClauseFilterFactory()
25+
public IRangeClauseFilterFactory CreateIRangeClauseFilterFactory()
2626
{
2727
return new RangeClauseFilterFactory();
2828
}
2929

30-
public ISelectCaseStmtContextWrapperFactory CreateUnreachableCaseInspectionSelectStmtFactory()
30+
public ISelectCaseStmtContextWrapperFactory CreateISelectStmtContextWrapperFactory()
3131
{
3232
return new SelectCaseStmtContextWrapperFactory()
3333
{
3434
FactoryProvider = this
3535
};
3636
}
3737

38-
public IRangeClauseContextWrapperFactory CreateUnreachableCaseInspectionRangeFactory()
38+
public IRangeClauseContextWrapperFactory CreateIRangeClauseContextWrapperFactory()
3939
{
4040
return new RangeClauseContextWrapperFactory()
4141
{

RubberduckTests/Inspections/UnreachableCaseInspectionTests.cs

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ public class UnreachableCaseInspectionTests
1818
private const string VALUE_TYPE_SEPARATOR = "?";
1919
private const string OPERAND_SEPARATOR = "_";
2020

21-
private IUnreachableCaseInspectionFactoryProvider _factoriesFactory;
21+
private IUnreachableCaseInspectionFactoryProvider _factoryProvider;
2222
private IParseTreeValueFactory _valueFactory;
2323
private IParseTreeExpressionEvaluator _calculator;
2424
private IParseTreeValueVisitorFactory _visitorFactory;
2525
private IRangeClauseFilterFactory _rangeClauseFilterFactory;
2626
private IRangeClauseContextWrapperFactory _rangeFactory;
2727
private ISelectCaseStmtContextWrapperFactory _selectStmtFactory;
2828

29-
private IUnreachableCaseInspectionFactoryProvider FactoriesFactory
29+
private IUnreachableCaseInspectionFactoryProvider FactoryProvider
3030
{
3131
get
3232
{
33-
if (_factoriesFactory is null)
33+
if (_factoryProvider is null)
3434
{
35-
_factoriesFactory = new UnreachableCaseInspectionFactoryProvider();
35+
_factoryProvider = new UnreachableCaseInspectionFactoryProvider();
3636
}
37-
return _factoriesFactory;
37+
return _factoryProvider;
3838
}
3939
}
4040

@@ -44,7 +44,7 @@ private IParseTreeValueFactory ValueFactory
4444
{
4545
if (_valueFactory is null)
4646
{
47-
_valueFactory = FactoriesFactory.CreateIUCIValueFactory();
47+
_valueFactory = FactoryProvider.CreateIParseTreeValueFactory();
4848
}
4949
return _valueFactory;
5050
}
@@ -68,7 +68,7 @@ private IParseTreeValueVisitorFactory ValueVisitorFactory
6868
{
6969
if (_visitorFactory is null)
7070
{
71-
_visitorFactory = FactoriesFactory.CreateIUCIParseTreeValueVisitorFactory();
71+
_visitorFactory = FactoryProvider.CreateIParseTreeValueVisitorFactory();
7272
}
7373
return _visitorFactory;
7474
}
@@ -80,7 +80,7 @@ private IRangeClauseFilterFactory RangeClauseFilterFactory
8080
{
8181
if (_rangeClauseFilterFactory is null)
8282
{
83-
_rangeClauseFilterFactory = FactoriesFactory.CreateIUCIRangeClauseFilterFactory();
83+
_rangeClauseFilterFactory = FactoryProvider.CreateIRangeClauseFilterFactory();
8484
}
8585
return _rangeClauseFilterFactory;
8686
}
@@ -92,7 +92,7 @@ private IRangeClauseContextWrapperFactory InspectionRangeFactory
9292
{
9393
if (_rangeFactory is null)
9494
{
95-
_rangeFactory = FactoriesFactory.CreateUnreachableCaseInspectionRangeFactory();
95+
_rangeFactory = FactoryProvider.CreateIRangeClauseContextWrapperFactory();
9696
}
9797
return _rangeFactory;
9898
}
@@ -104,7 +104,7 @@ private ISelectCaseStmtContextWrapperFactory InspectionSelectStmtFactory
104104
{
105105
if (_selectStmtFactory is null)
106106
{
107-
_selectStmtFactory = FactoriesFactory.CreateUnreachableCaseInspectionSelectStmtFactory();
107+
_selectStmtFactory = FactoryProvider.CreateISelectStmtContextWrapperFactory();
108108
}
109109
return _selectStmtFactory;
110110
}
@@ -353,6 +353,42 @@ public void UciUnit_LogicBinaryConstants(string operands, string expected)
353353
Assert.IsTrue(result.ParsesToConstantValue);
354354
}
355355

356+
// Dim A, B, C, D, MyCheck
357+
//A = 10: B = 8: C = 6: D = Null ' Initialize variables.
358+
//MyCheck = A > B Eqv B > C ' Returns True.
359+
//MyCheck = B > A Eqv B > C ' Returns False.
360+
//MyCheck = A > B Eqv B > D ' Returns Null.
361+
//MyCheck = A Eqv B ' Returns -3 (bitwise comparison).
362+
[TestCase("True_Eqv_True", "True")]
363+
[TestCase("False_Eqv_True", "False")]
364+
[TestCase("True_Eqv_False", "False")]
365+
[TestCase("False_Eqv_False", "True")]
366+
[Category("Inspections")]
367+
public void UciUnit_LogicEqvOperator(string operands, string expected)
368+
{
369+
GetBinaryOpValues(operands, out IParseTreeValue LHS, out IParseTreeValue RHS, out string opSymbol);
370+
371+
var result = Calculator.Evaluate(LHS, RHS, opSymbol);
372+
373+
Assert.AreEqual(expected, result.ValueText);
374+
Assert.IsTrue(result.ParsesToConstantValue);
375+
}
376+
377+
[TestCase("True_Imp_True", "True")]
378+
[TestCase("False_Imp_True", "True")]
379+
[TestCase("True_Imp_False", "False")]
380+
[TestCase("False_Imp_False", "True")]
381+
[Category("Inspections")]
382+
public void UciUnit_LogicImpOperator(string operands, string expected)
383+
{
384+
GetBinaryOpValues(operands, out IParseTreeValue LHS, out IParseTreeValue RHS, out string opSymbol);
385+
386+
var result = Calculator.Evaluate(LHS, RHS, opSymbol);
387+
388+
Assert.AreEqual(expected, result.ValueText);
389+
Assert.IsTrue(result.ParsesToConstantValue);
390+
}
391+
356392
[TestCase("Not_False", "True")]
357393
[TestCase("Not_True", "False")]
358394
[Category("Inspections")]
@@ -2094,6 +2130,64 @@ End Select
20942130
CheckActualResultsEqualsExpected(inputCode, unreachable: 1);
20952131
}
20962132

2133+
[TestCase("START Eqv FINISH", "True")]
2134+
[TestCase("START * 0 Eqv FINISH * 0", "True")]
2135+
[TestCase("START Eqv FINISH * 0", "False")]
2136+
[TestCase("START * 0 Eqv FINISH", "False")]
2137+
[Category("Inspections")]
2138+
public void UciFunctional_EqvOperator( string secondCase, string thirdCase)
2139+
{
2140+
string inputCode =
2141+
@"
2142+
private const START As Long = 3
2143+
private const FINISH As Long = 10
2144+
2145+
Sub Foo(x As Long, y As Long, z As Long)
2146+
Select Case z
2147+
Case Is < x
2148+
'OK
2149+
Case <secondCase>
2150+
'OK
2151+
Case <thirdCase>
2152+
'Unreachable
2153+
End Select
2154+
2155+
End Sub";
2156+
2157+
inputCode = inputCode.Replace("<secondCase>", secondCase);
2158+
inputCode = inputCode.Replace("<thirdCase>", thirdCase);
2159+
CheckActualResultsEqualsExpected(inputCode, unreachable: 1);
2160+
}
2161+
2162+
[TestCase("START Imp FINISH", "True")]
2163+
[TestCase("START * 0 Imp FINISH * 0", "True")]
2164+
[TestCase("START Imp FINISH * 0", "False")]
2165+
[TestCase("START * 0 Imp FINISH", "True")]
2166+
[Category("Inspections")]
2167+
public void UciFunctional_ImpOperator(string secondCase, string thirdCase)
2168+
{
2169+
string inputCode =
2170+
@"
2171+
private const START As Long = 3
2172+
private const FINISH As Long = 10
2173+
2174+
Sub Foo(x As Long, y As Long, z As Long)
2175+
Select Case z
2176+
Case Is < x
2177+
'OK
2178+
Case <secondCase>
2179+
'OK
2180+
Case <thirdCase>
2181+
'Unreachable
2182+
End Select
2183+
2184+
End Sub";
2185+
2186+
inputCode = inputCode.Replace("<secondCase>", secondCase);
2187+
inputCode = inputCode.Replace("<thirdCase>", thirdCase);
2188+
CheckActualResultsEqualsExpected(inputCode, unreachable: 1);
2189+
}
2190+
20972191
private static void CheckActualResultsEqualsExpected(string inputCode, int unreachable = 0, int mismatch = 0, int caseElse = 0)
20982192
{
20992193
var expected = new Dictionary<string, int>

0 commit comments

Comments
 (0)