Skip to content

Commit a9f1e21

Browse files
author
Max Schaefer
committed
JavaScript: Fix exported name of default re-exports.
A default re-export (not part of the standard yet) looks like this: ``` export f from 'mod'; ``` What this means is that the default export of `mod` is re-exported under the name `f`. Default re-export specifiers (like `f` in this example) are modelled as a kind of default export specifier in our library, but unlike normal default export specifiers they do not export the name `default`. This was previously not modelled correctly, leading to surprising errors down the line, for example in type inference where we suddenly would no longer be able to resolve an import that otherwise looked resolvable.
1 parent 44e4b25 commit a9f1e21

File tree

19 files changed

+79
-8
lines changed

19 files changed

+79
-8
lines changed

change-notes/1.18/analysis-javascript.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
* Modelling of global variables has been improved. This may give more true-positive results and fewer false-positive results for a variety of queries.
1010

11+
* Modelling of re-export declarations has been improved. This may result in fewer false-positive results for a variety of queries.
12+
1113
* Modelling of taint flow through the array operations `map` and `join` has been improved. This may give additional results for the security queries.
1214

1315
* Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following libraries:

javascript/ql/src/semmle/javascript/ES2015Modules.qll

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -428,22 +428,39 @@ class ExportSpecifier extends Expr, @exportspecifier {
428428
string getExportedName() { result = getExported().getName() }
429429
}
430430

431-
/** A named export specifier. */
431+
/**
432+
* A named export specifier, for example `v` in `export { v }`.
433+
*/
432434
class NamedExportSpecifier extends ExportSpecifier, @namedexportspecifier {
433435
}
434436

435-
/** A default export specifier. */
437+
/**
438+
* A default export specifier, for example `default` in `export default 42`,
439+
* or `v` in `export v from "mod"`.
440+
*/
436441
class ExportDefaultSpecifier extends ExportSpecifier, @exportdefaultspecifier {
437-
override string getLocalName() {
438-
getExportDeclaration() instanceof ReExportDeclaration and result = "default"
439-
}
440-
441442
override string getExportedName() {
442443
result = "default"
443444
}
444445
}
445446

446-
/** A namespace export specifier. */
447+
/**
448+
* A default export specifier in a re-export declaration, for example `v` in
449+
* `export v from "mod"`.
450+
*/
451+
class ReExportDefaultSpecifier extends ExportDefaultSpecifier {
452+
ReExportDefaultSpecifier() {
453+
getExportDeclaration() instanceof ReExportDeclaration
454+
}
455+
456+
override string getLocalName() { result = "default" }
457+
458+
override string getExportedName() { result = getExported().getName() }
459+
}
460+
461+
/**
462+
* A namespace export specifier, for example `*` in `export * from "mod"`.
463+
*/
447464
class ExportNamespaceSpecifier extends ExportSpecifier, @exportnamespacespecifier {
448465
}
449466

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@
217217
| reexport-mixins.js:1:1:4:0 | module object of module reexport-mixins |
218218
| reexport-unknown.js:1:1:2:0 | exports object of module reexport-unknown |
219219
| reexport-unknown.js:1:1:2:0 | module object of module reexport-unknown |
220+
| reexport/client/src/index.js:1:1:3:0 | exports object of module index |
221+
| reexport/client/src/index.js:1:1:3:0 | module object of module index |
222+
| reexport/lib/index.js:1:1:4:0 | exports object of module index |
223+
| reexport/lib/index.js:1:1:4:0 | module object of module index |
224+
| reexport/lib/src/utils/util.js:1:1:3:0 | exports object of module util |
225+
| reexport/lib/src/utils/util.js:1:1:3:0 | module object of module util |
220226
| refinements.js:1:1:8:1 | function f1 |
221227
| refinements.js:1:1:8:1 | instance of function f1 |
222228
| refinements.js:10:1:24:1 | function f2 |

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@
221221
| objlit.js:38:11:38:12 | x6 | objlit.js:38:16:38:21 | this.h | file://:0:0:0:0 | indefinite value (heap) |
222222
| objlit.js:38:11:38:12 | x6 | objlit.js:38:16:38:21 | this.h | objlit.js:41:10:41:22 | anonymous function |
223223
| objlit.js:43:7:43:8 | o3 | objlit.js:43:12:45:3 | {\\n _ ... o2\\n } | objlit.js:43:12:45:3 | object literal |
224+
| reexport/client/src/index.js:2:5:2:8 | test | reexport/client/src/index.js:2:12:2:15 | data | file://:0:0:0:0 | non-empty, non-numeric string |
224225
| refinements.js:3:7:3:8 | x1 | refinements.js:3:12:3:12 | g | file://:0:0:0:0 | undefined |
225226
| refinements.js:7:7:7:8 | x3 | refinements.js:7:12:7:12 | g | file://:0:0:0:0 | undefined |
226227
| refinements.js:11:7:11:7 | a | refinements.js:11:11:11:72 | Math.ra ... ' : 42) | file://:0:0:0:0 | non-empty, non-numeric string |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { data } from '../../lib';
2+
var test = data;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export data from './src/utils/util'
2+
3+
// semmle-extractor-options: --experimental
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default "data";
2+

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
| objlit.js:37:11:37:12 | x5 | objlit.js:37:16:37:21 | this.f | boolean, class, date, function, null, number, object, regular expression,string or undefined |
122122
| objlit.js:38:11:38:12 | x6 | objlit.js:38:16:38:21 | this.h | boolean, class, date, function, null, number, object, regular expression,string or undefined |
123123
| objlit.js:43:7:43:8 | o3 | objlit.js:43:12:45:3 | {\\n _ ... o2\\n } | object |
124+
| reexport/client/src/index.js:2:5:2:8 | test | reexport/client/src/index.js:2:12:2:15 | data | string |
124125
| refinements.js:3:7:3:8 | x1 | refinements.js:3:12:3:12 | g | undefined |
125126
| refinements.js:5:9:5:10 | x2 | refinements.js:5:14:5:14 | g | |
126127
| refinements.js:7:7:7:8 | x3 | refinements.js:7:12:7:12 | g | undefined |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
| a.js:1:1:3:1 | export ... n 23;\\n} |
22
| a.js:5:1:5:32 | export ... } = o; |
33
| b.js:5:1:5:18 | export { f as g }; |
4+
| b.js:7:1:7:21 | export ... './a'; |
45
| d.js:4:1:4:20 | export * from 'm/c'; |
56
| e.js:2:1:2:16 | export { x, y }; |
67
| e.js:3:1:3:35 | export ... './a'; |
78
| es2015_require.js:3:1:3:25 | export ... ss C {} |
89
| export-in-mjs.mjs:1:1:1:34 | export ... s = 42; |
910
| f.ts:5:1:5:24 | export ... oo() {} |
11+
| m/c.js:5:1:5:30 | export ... '../b'; |
1012
| tst.html:7:3:7:22 | export const y = 42; |

javascript/ql/test/library-tests/Modules/ExportSpecifiers.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
| e.js:2:10:2:10 | x | e.js:2:10:2:10 | x | e.js:2:10:2:10 | x |
33
| e.js:2:13:2:13 | y | e.js:2:13:2:13 | y | e.js:2:13:2:13 | y |
44
| e.js:3:10:3:21 | default as g | e.js:3:10:3:16 | default | e.js:3:21:3:21 | g |
5+
| m/c.js:5:10:5:15 | g as h | m/c.js:5:10:5:10 | g | m/c.js:5:15:5:15 | h |

0 commit comments

Comments
 (0)