Skip to content

Commit 13cb10d

Browse files
authored
Revert "JS: Split module exports into a local and global variant"
1 parent e52f819 commit 13cb10d

File tree

1 file changed

+56
-76
lines changed

1 file changed

+56
-76
lines changed

javascript/ql/lib/semmle/javascript/ES2015Modules.qll

Lines changed: 56 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -345,17 +345,7 @@ abstract class ExportDeclaration extends Stmt, @export_declaration {
345345

346346
/** Holds if this export declaration exports variable `v` under the name `name`. */
347347
overlay[global]
348-
final predicate exportsAs(LexicalName v, string name) {
349-
this.exportsDirectlyAs(v, name)
350-
or
351-
this.(ReExportDeclaration).reExportsAs(v, name)
352-
}
353-
354-
/**
355-
* Holds if this export declaration exports variable `v` under the name `name`,
356-
* not counting re-exports.
357-
*/
358-
predicate exportsDirectlyAs(LexicalName v, string name) { none() }
348+
abstract predicate exportsAs(LexicalName v, string name);
359349

360350
/**
361351
* Gets the data flow node corresponding to the value this declaration exports
@@ -379,17 +369,7 @@ abstract class ExportDeclaration extends Stmt, @export_declaration {
379369
* to module `a` or possibly to some other module from which `a` re-exports.
380370
*/
381371
overlay[global]
382-
final DataFlow::Node getSourceNode(string name) {
383-
result = this.getDirectSourceNode(name)
384-
or
385-
result = this.(ReExportDeclaration).getReExportedSourceNode(name)
386-
}
387-
388-
/**
389-
* Gets the data flow node corresponding to the value this declaration exports
390-
* under the name `name`, not including sources that come from a re-export.
391-
*/
392-
DataFlow::Node getDirectSourceNode(string name) { none() }
372+
abstract DataFlow::Node getSourceNode(string name);
393373

394374
/** Holds if is declared with the `type` keyword, so only types are exported. */
395375
predicate isTypeOnly() { has_type_keyword(this) }
@@ -441,20 +421,20 @@ class BulkReExportDeclaration extends ReExportDeclaration, @export_all_declarati
441421
override ConstantString getImportedPath() { result = this.getChildExpr(0) }
442422

443423
overlay[global]
444-
override predicate reExportsAs(LexicalName v, string name) {
424+
override predicate exportsAs(LexicalName v, string name) {
445425
this.getReExportedES2015Module().exportsAs(v, name) and
446-
not isShadowedFromBulkExport(this.getEnclosingModule(), name)
426+
not isShadowedFromBulkExport(this, name)
447427
}
448428

449429
overlay[global]
450-
override DataFlow::Node getReExportedSourceNode(string name) {
430+
override DataFlow::Node getSourceNode(string name) {
451431
result = this.getReExportedES2015Module().getAnExport().getSourceNode(name)
452432
}
453433
}
454434

455435
/**
456-
* Holds if bulk re-exports in `mod` should not re-export `name` because there is an explicit export
457-
* of that name in `mod`.
436+
* Holds if the given bulk export `reExport` should not re-export `name` because there is an explicit export
437+
* of that name in the same module.
458438
*
459439
* At compile time, shadowing works across declaration spaces.
460440
* For instance, directly exporting an interface `X` will block a variable `X` from being re-exported:
@@ -466,8 +446,8 @@ class BulkReExportDeclaration extends ReExportDeclaration, @export_all_declarati
466446
* but we ignore this subtlety.
467447
*/
468448
overlay[global]
469-
private predicate isShadowedFromBulkExport(Module mod, string name) {
470-
exists(ExportNamedDeclaration other | other.getTopLevel() = mod |
449+
private predicate isShadowedFromBulkExport(BulkReExportDeclaration reExport, string name) {
450+
exists(ExportNamedDeclaration other | other.getTopLevel() = reExport.getEnclosingModule() |
471451
other.getAnExportedDecl().getName() = name
472452
or
473453
other.getASpecifier().getExportedName() = name
@@ -488,7 +468,8 @@ class ExportDefaultDeclaration extends ExportDeclaration, @export_default_declar
488468
/** Gets the operand statement or expression that is exported by this declaration. */
489469
ExprOrStmt getOperand() { result = this.getChild(0) }
490470

491-
override predicate exportsDirectlyAs(LexicalName v, string name) {
471+
overlay[global]
472+
override predicate exportsAs(LexicalName v, string name) {
492473
name = "default" and v = this.getADecl().getVariable()
493474
}
494475

@@ -500,7 +481,8 @@ class ExportDefaultDeclaration extends ExportDeclaration, @export_default_declar
500481
)
501482
}
502483

503-
override DataFlow::Node getDirectSourceNode(string name) {
484+
overlay[global]
485+
override DataFlow::Node getSourceNode(string name) {
504486
name = "default" and result = DataFlow::valueNode(this.getOperand())
505487
}
506488
}
@@ -542,20 +524,21 @@ class ExportNamedDeclaration extends ExportDeclaration, @export_named_declaratio
542524
/** Gets the variable declaration, if any, exported by this named export. */
543525
VarDecl getADecl() { result = this.getAnExportedDecl() }
544526

545-
override predicate exportsDirectlyAs(LexicalName v, string name) {
546-
(
547-
exists(LexicalDecl vd | vd = this.getAnExportedDecl() |
548-
name = vd.getName() and v = vd.getALexicalName()
549-
)
527+
overlay[global]
528+
override predicate exportsAs(LexicalName v, string name) {
529+
exists(LexicalDecl vd | vd = this.getAnExportedDecl() |
530+
name = vd.getName() and v = vd.getALexicalName()
531+
)
532+
or
533+
exists(ExportSpecifier spec | spec = this.getASpecifier() and name = spec.getExportedName() |
534+
v = spec.getLocal().(LexicalAccess).getALexicalName()
550535
or
551-
exists(ExportSpecifier spec | spec = this.getASpecifier() and name = spec.getExportedName() |
552-
v = spec.getLocal().(LexicalAccess).getALexicalName()
553-
)
554-
) and
555-
not (this.isTypeOnly() and v instanceof Variable)
536+
this.(ReExportDeclaration).getReExportedES2015Module().exportsAs(v, spec.getLocalName())
537+
)
556538
}
557539

558-
override DataFlow::Node getDirectSourceNode(string name) {
540+
overlay[global]
541+
override DataFlow::Node getSourceNode(string name) {
559542
exists(VarDef d | d.getTarget() = this.getADecl() |
560543
name = d.getTarget().(VarDecl).getName() and
561544
result = DataFlow::valueNode(d.getSource())
@@ -571,11 +554,12 @@ class ExportNamedDeclaration extends ExportDeclaration, @export_named_declaratio
571554
exists(ExportSpecifier spec | spec = this.getASpecifier() and name = spec.getExportedName() |
572555
not exists(this.getImportedPath()) and result = DataFlow::valueNode(spec.getLocal())
573556
or
574-
// For `export * as B from ".."`, we use the ExportNamespaceSpecifier as a representative for the
575-
// object that gets exposed as `B`.
576-
this instanceof ReExportDeclaration and
577-
spec instanceof ExportNamespaceSpecifier and
578-
result = DataFlow::valueNode(spec)
557+
exists(ReExportDeclaration red | red = this |
558+
result = red.getReExportedES2015Module().getAnExport().getSourceNode(spec.getLocalName())
559+
or
560+
spec instanceof ExportNamespaceSpecifier and
561+
result = DataFlow::valueNode(spec)
562+
)
579563
)
580564
}
581565

@@ -603,6 +587,19 @@ private class ExportNamespaceStep extends PreCallGraphStep {
603587
}
604588
}
605589

590+
/**
591+
* An export declaration with the `type` modifier.
592+
*/
593+
private class TypeOnlyExportDeclaration extends ExportNamedDeclaration {
594+
TypeOnlyExportDeclaration() { this.isTypeOnly() }
595+
596+
overlay[global]
597+
override predicate exportsAs(LexicalName v, string name) {
598+
super.exportsAs(v, name) and
599+
not v instanceof Variable
600+
}
601+
}
602+
606603
/**
607604
* An export specifier in an export declaration.
608605
*
@@ -780,20 +777,6 @@ abstract class ReExportDeclaration extends ExportDeclaration {
780777
Stages::Imports::ref() and
781778
result.getFile() = ImportPathResolver::resolveExpr(this.getImportedPath())
782779
}
783-
784-
/**
785-
* Holds if this re-export declaration ultimately re-exports `v` (from another module)
786-
* under the given `name`.
787-
*/
788-
overlay[global]
789-
abstract predicate reExportsAs(LexicalName v, string name);
790-
791-
/**
792-
* Gets the data flow node (from another module) corresponding to the value that is re-exported
793-
* under the name `name`.
794-
*/
795-
overlay[global]
796-
abstract DataFlow::Node getReExportedSourceNode(string name);
797780
}
798781

799782
/** A literal path expression appearing in a re-export declaration. */
@@ -820,21 +803,6 @@ class SelectiveReExportDeclaration extends ReExportDeclaration, ExportNamedDecla
820803
override ConstantString getImportedPath() {
821804
result = ExportNamedDeclaration.super.getImportedPath()
822805
}
823-
824-
overlay[global]
825-
override predicate reExportsAs(LexicalName v, string name) {
826-
exists(ExportSpecifier spec | spec = this.getASpecifier() and name = spec.getExportedName() |
827-
this.getReExportedES2015Module().exportsAs(v, spec.getLocalName())
828-
) and
829-
not (this.isTypeOnly() and v instanceof Variable)
830-
}
831-
832-
overlay[global]
833-
override DataFlow::Node getReExportedSourceNode(string name) {
834-
exists(ExportSpecifier spec | spec = this.getASpecifier() and name = spec.getExportedName() |
835-
result = this.getReExportedES2015Module().getAnExport().getSourceNode(spec.getLocalName())
836-
)
837-
}
838806
}
839807

840808
/**
@@ -851,4 +819,16 @@ class SelectiveReExportDeclaration extends ReExportDeclaration, ExportNamedDecla
851819
*/
852820
class OriginalExportDeclaration extends ExportDeclaration {
853821
OriginalExportDeclaration() { not this instanceof ReExportDeclaration }
822+
823+
overlay[global]
824+
override predicate exportsAs(LexicalName v, string name) {
825+
this.(ExportDefaultDeclaration).exportsAs(v, name) or
826+
this.(ExportNamedDeclaration).exportsAs(v, name)
827+
}
828+
829+
overlay[global]
830+
override DataFlow::Node getSourceNode(string name) {
831+
result = this.(ExportDefaultDeclaration).getSourceNode(name) or
832+
result = this.(ExportNamedDeclaration).getSourceNode(name)
833+
}
854834
}

0 commit comments

Comments
 (0)