Skip to content

Commit 2cddb82

Browse files
authored
Merge pull request #2210 from max-schaefer/js/better-destructuring-type-inference
Approved by asger-semmle, esbena
2 parents 0b2c262 + 89f68f4 commit 2cddb82

File tree

5 files changed

+36
-14
lines changed

5 files changed

+36
-14
lines changed

javascript/ql/src/semmle/javascript/dataflow/internal/PropertyTypeInference.qll

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,17 @@ abstract class AnalyzedPropertyRead extends DataFlow::AnalyzedNode {
5050
}
5151

5252
/**
53-
* Flow analysis for (non-numeric) property read accesses.
53+
* Flow analysis for non-numeric property read accesses.
5454
*/
55-
private class AnalyzedPropertyAccess extends AnalyzedPropertyRead, DataFlow::ValueNode {
56-
override PropAccess astNode;
55+
private class AnalyzedNonNumericPropertyRead extends AnalyzedPropertyRead {
56+
DataFlow::PropRead self;
5757
DataFlow::AnalyzedNode baseNode;
5858
string propName;
5959

60-
AnalyzedPropertyAccess() {
61-
astNode.accesses(baseNode.asExpr(), propName) and
62-
isNonNumericPropertyName(propName) and
63-
astNode instanceof RValue
60+
AnalyzedNonNumericPropertyRead() {
61+
this = self and
62+
self.accesses(baseNode, propName) and
63+
isNonNumericPropertyName(propName)
6464
}
6565

6666
override predicate reads(AbstractValue base, string prop) {
@@ -148,26 +148,26 @@ private predicate explicitPropertyWrite(
148148
* Flow analysis for `arguments.callee`. We assume it is never redefined,
149149
* which is unsound in practice, but pragmatically useful.
150150
*/
151-
private class AnalyzedArgumentsCallee extends AnalyzedPropertyAccess {
151+
private class AnalyzedArgumentsCallee extends AnalyzedNonNumericPropertyRead {
152152
AnalyzedArgumentsCallee() { propName = "callee" }
153153

154154
override AbstractValue getALocalValue() {
155155
exists(AbstractArguments baseVal | reads(baseVal, _) |
156156
result = TAbstractFunction(baseVal.getFunction())
157157
)
158158
or
159-
hasNonArgumentsBase(astNode) and result = super.getALocalValue()
159+
hasNonArgumentsBase(self) and result = super.getALocalValue()
160160
}
161161
}
162162

163163
/**
164-
* Holds if `pacc` is of the form `e.callee` where `e` could evaluate to some
164+
* Holds if `pr` is of the form `e.callee` where `e` could evaluate to some
165165
* value that is not an arguments object.
166166
*/
167-
private predicate hasNonArgumentsBase(PropAccess pacc) {
168-
pacc.getPropertyName() = "callee" and
167+
private predicate hasNonArgumentsBase(DataFlow::PropRead pr) {
168+
pr.getPropertyName() = "callee" and
169169
exists(AbstractValue baseVal |
170-
baseVal = pacc.getBase().analyze().getALocalValue() and
170+
baseVal = pr.getBase().analyze().getALocalValue() and
171171
not baseVal instanceof AbstractArguments
172172
)
173173
}

javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,11 @@ abstract class AnalyzedSsaDefinition extends SsaDefinition {
223223
* Flow analysis for SSA definitions corresponding to `VarDef`s.
224224
*/
225225
private class AnalyzedExplicitDefinition extends AnalyzedSsaDefinition, SsaExplicitDefinition {
226-
override AbstractValue getAnRhsValue() { result = getDef().(AnalyzedVarDef).getAnAssignedValue() }
226+
override AbstractValue getAnRhsValue() {
227+
result = getDef().(AnalyzedVarDef).getAnAssignedValue()
228+
or
229+
result = getRhsNode().analyze().getALocalValue()
230+
}
227231
}
228232

229233
/**
@@ -241,6 +245,8 @@ private class AnalyzedVariableCapture extends AnalyzedSsaDefinition, SsaVariable
241245
exists(LocalVariable v | v = getSourceVariable() |
242246
result = v.(AnalyzedCapturedVariable).getALocalValue()
243247
or
248+
result = any(AnalyzedExplicitDefinition def | def.getSourceVariable() = v).getAnRhsValue()
249+
or
244250
not guaranteedToBeInitialized(v) and result = getImplicitInitValue(v)
245251
)
246252
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const lib = require("./lib"),
2+
{ f } = require("./lib");
3+
4+
/** calls:lib.f */
5+
lib.f();
6+
/** calls:lib.f */
7+
f();
8+
9+
(function() {
10+
/** calls:lib.f */
11+
f();
12+
})();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports.f =
2+
/** name:lib.f */
3+
function() {};

javascript/ql/test/library-tests/Flow/abseval.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
| classAccessors.js:12:9:12:11 | myZ | classAccessors.js:12:15:12:20 | this.z | file://:0:0:0:0 | indefinite value (call) |
8181
| classAccessors.js:12:9:12:11 | myZ | classAccessors.js:12:15:12:20 | this.z | file://:0:0:0:0 | indefinite value (heap) |
8282
| destructuring.js:2:7:2:24 | { x, y = (z = x) } | destructuring.js:2:28:2:28 | o | file://:0:0:0:0 | indefinite value (call) |
83+
| destructuring.js:3:7:3:8 | z1 | destructuring.js:3:12:3:12 | z | file://:0:0:0:0 | indefinite value (call) |
8384
| destructuring.js:3:7:3:8 | z1 | destructuring.js:3:12:3:12 | z | file://:0:0:0:0 | indefinite value (heap) |
8485
| es2015.js:1:5:1:7 | Sup | es2015.js:1:11:6:1 | class { ... ;\\n }\\n} | es2015.js:1:11:6:1 | class Sup |
8586
| es2015.js:4:9:4:12 | ctor | es2015.js:4:16:4:25 | new.target | file://:0:0:0:0 | indefinite value (call) |

0 commit comments

Comments
 (0)