@@ -46,4 +46,86 @@ module Internal {
4646 }
4747 }
4848
49+ /**
50+ * Gets the inner expression of `e`, with any surrounding parentheses and boolean nots removed.
51+ * `polarity` is true iff the inner expression is nested in an even number of negations.
52+ */
53+ private Expr stripNotsAndParens ( Expr e , boolean polarity ) {
54+ exists ( Expr inner |
55+ inner = e .stripParens ( ) |
56+ if inner instanceof LogNotExpr then
57+ ( result = stripNotsAndParens ( inner .( LogNotExpr ) .getOperand ( ) , polarity .booleanNot ( ) ) )
58+ else
59+ ( result = inner and polarity = true )
60+ )
61+ }
62+
63+ /**
64+ * An equality test for `null` and `undefined`.
65+ */
66+ private abstract class UndefinedNullTest extends EqualityTest {
67+ /** Gets the unique Boolean value that this test evaluates to, if any. */
68+ abstract boolean getTheTestResult ( ) ;
69+
70+ /**
71+ * Gets the expression that is tested for being `null` or `undefined`.
72+ */
73+ abstract Expr getOperand ( ) ;
74+ }
75+
76+ /**
77+ * A dis- or conjunction that tests if an expression is `null` or `undefined` in either branch.
78+ */
79+ private class CompositeUndefinedNullTestPart extends DefensiveExpression {
80+
81+ UndefinedNullTest test ;
82+
83+ boolean polarity ;
84+
85+ CompositeUndefinedNullTestPart ( ) {
86+ exists ( BinaryExpr composite , Variable v , Expr op , Expr opOther , UndefinedNullTest testOther |
87+ composite instanceof LogAndExpr or
88+ composite instanceof LogOrExpr |
89+ composite .hasOperands ( op , opOther ) and
90+ this = op .flow ( ) and
91+ test = stripNotsAndParens ( op , polarity ) and
92+ testOther = stripNotsAndParens ( opOther , _) and
93+ test .getOperand ( ) .( VarRef ) .getVariable ( ) = v and
94+ testOther .getOperand ( ) .( VarRef ) .getVariable ( ) = v
95+ )
96+ }
97+
98+ override boolean getTheTestResult ( ) {
99+ polarity = true and result = test .getTheTestResult ( )
100+ or
101+ polarity = false and result = test .getTheTestResult ( ) .booleanNot ( )
102+ }
103+
104+ }
105+
106+ /**
107+ * A test for `undefined` or `null` in an if-statement.
108+ */
109+ private class SanityCheckingUndefinedNullGuard extends DefensiveExpression {
110+
111+ UndefinedNullTest test ;
112+
113+ boolean polarity ;
114+
115+ SanityCheckingUndefinedNullGuard ( ) {
116+ exists ( IfStmt c |
117+ this = c .getCondition ( ) .flow ( ) and
118+ test = stripNotsAndParens ( c .getCondition ( ) , polarity ) and
119+ test .getOperand ( ) instanceof VarRef
120+ )
121+ }
122+
123+ override boolean getTheTestResult ( ) {
124+ polarity = true and result = test .getTheTestResult ( )
125+ or
126+ polarity = false and result = test .getTheTestResult ( ) .booleanNot ( )
127+ }
128+
129+ }
130+
49131}
0 commit comments