@@ -6,100 +6,77 @@ import javascript
66
77module Closure {
88 /**
9- * A call to a function in the `goog` namespace such as `goog.provide` or `goog.load` .
9+ * A reference to a Closure namespace.
1010 */
11- class GoogFunctionCall extends CallExpr {
12- GoogFunctionCall ( ) {
13- exists ( GlobalVariable gv | gv .getName ( ) = "goog" |
14- this .getCallee ( ) .( DotExpr ) .getBase ( ) = gv .getAnAccess ( )
15- )
16- }
17-
18- /** Gets the name of the invoked function. */
19- string getFunctionName ( ) { result = getCallee ( ) .( DotExpr ) .getPropertyName ( ) }
11+ abstract class ClosureNamespaceRef extends DataFlow:: Node {
12+ /**
13+ * Gets the namespace being referenced.
14+ */
15+ abstract string getClosureNamespace ( ) ;
2016 }
2117
2218 /**
23- * An expression statement consisting of a call to a function
24- * in the `goog` namespace.
19+ * A call to a method on the `goog.` namespace, as a closure reference.
2520 */
26- class GoogFunctionCallStmt extends ExprStmt {
27- GoogFunctionCallStmt ( ) { super .getExpr ( ) instanceof GoogFunctionCall }
28-
29- override GoogFunctionCall getExpr ( ) { result = super .getExpr ( ) }
21+ abstract private class DefaultNamespaceRef extends DataFlow:: MethodCallNode , ClosureNamespaceRef {
22+ DefaultNamespaceRef ( ) { this = DataFlow:: globalVarRef ( "goog" ) .getAMethodCall ( ) }
3023
31- /** Gets the name of the invoked function. */
32- string getFunctionName ( ) { result = getExpr ( ) .getFunctionName ( ) }
33-
34- /** Gets the `i`th argument to the invoked function. */
35- Expr getArgument ( int i ) { result = getExpr ( ) .getArgument ( i ) }
36-
37- /** Gets an argument to the invoked function. */
38- Expr getAnArgument ( ) { result = getArgument ( _) }
24+ override string getClosureNamespace ( ) { result = getArgument ( 0 ) .asExpr ( ) .getStringValue ( ) }
3925 }
4026
41- abstract private class GoogNamespaceRef extends ExprOrStmt { abstract string getClosureNamespace ( ) ; }
42-
4327 /**
44- * A call to `goog.provide` .
28+ * Holds if `node` is the dataflow node for a top-level expression .
4529 */
46- class GoogProvide extends GoogFunctionCallStmt , GoogNamespaceRef {
47- GoogProvide ( ) { getFunctionName ( ) = "provide" }
48-
49- /** Gets the identifier of the namespace created by this call. */
50- override string getClosureNamespace ( ) { result = getArgument ( 0 ) .getStringValue ( ) }
30+ private predicate isTopLevelExpr ( DataFlow:: Node node ) {
31+ node .getTopLevel ( ) .getAChildStmt ( ) .( ExprStmt ) .getExpr ( ) .flow ( ) = node
5132 }
5233
5334 /**
54- * A call to `goog.require `.
35+ * A top-level call to `goog.provide `.
5536 */
56- class GoogRequire extends GoogFunctionCall , GoogNamespaceRef {
57- GoogRequire ( ) { getFunctionName ( ) = "require" }
58-
59- /** Gets the identifier of the namespace imported by this call. */
60- override string getClosureNamespace ( ) { result = getArgument ( 0 ) . getStringValue ( ) }
37+ class ClosureProvideCall extends DefaultNamespaceRef {
38+ ClosureProvideCall ( ) {
39+ getMethodName ( ) = "provide" and
40+ isTopLevelExpr ( this )
41+ }
6142 }
6243
63- private class GoogRequireImport extends GoogRequire , Import {
64- /** Gets the module in which this import appears. */
65- override Module getEnclosingModule ( ) { result = getTopLevel ( ) }
66-
67- /** Gets the (unresolved) path that this import refers to. */
68- override PathExpr getImportedPath ( ) { result = getArgument ( 0 ) }
44+ /**
45+ * A call to `goog.require`.
46+ */
47+ class ClosureRequireCall extends DefaultNamespaceRef {
48+ ClosureRequireCall ( ) { getMethodName ( ) = "require" }
6949 }
7050
7151 /**
72- * A call to `goog.module` or `goog.declareModuleId`.
52+ * A top-level call to `goog.module` or `goog.declareModuleId`.
7353 */
74- class GoogModuleDeclaration extends GoogFunctionCallStmt , GoogNamespaceRef {
75- GoogModuleDeclaration ( ) {
76- getFunctionName ( ) = "module" or
77- getFunctionName ( ) = "declareModuleId"
54+ class ClosureModuleDeclaration extends DefaultNamespaceRef {
55+ ClosureModuleDeclaration ( ) {
56+ ( getMethodName ( ) = "module" or getMethodName ( ) = "declareModuleId" ) and
57+ isTopLevelExpr ( this )
7858 }
79-
80- /** Gets the identifier of the namespace imported by this call. */
81- override string getClosureNamespace ( ) { result = getArgument ( 0 ) .getStringValue ( ) }
8259 }
8360
8461 /**
8562 * A module using the Closure module system, declared using `goog.module()` or `goog.declareModuleId()`.
8663 */
8764 class ClosureModule extends Module {
88- ClosureModule ( ) { getAChildStmt ( ) instanceof GoogModuleDeclaration }
65+ ClosureModule ( ) { any ( ClosureModuleDeclaration decl ) . getTopLevel ( ) = this }
8966
9067 /**
9168 * Gets the call to `goog.module` or `goog.declareModuleId` in this module.
9269 */
93- GoogModuleDeclaration getModuleDeclaration ( ) { result = getAChildStmt ( ) }
70+ ClosureModuleDeclaration getModuleDeclaration ( ) { result . getTopLevel ( ) = this }
9471
9572 /**
9673 * Gets the namespace of this module.
9774 */
9875 string getClosureNamespace ( ) { result = getModuleDeclaration ( ) .getClosureNamespace ( ) }
9976
10077 override Module getAnImportedModule ( ) {
101- exists ( GoogRequireImport imprt |
102- imprt .getEnclosingModule ( ) = this and
78+ exists ( ClosureRequireCall imprt |
79+ imprt .getTopLevel ( ) = this and
10380 result .( ClosureModule ) .getClosureNamespace ( ) = imprt .getClosureNamespace ( )
10481 )
10582 }
@@ -113,7 +90,7 @@ module Closure {
11390 * Has no result for ES6 modules using `goog.declareModuleId`.
11491 */
11592 Variable getExportsVariable ( ) {
116- getModuleDeclaration ( ) .getFunctionName ( ) = "module" and
93+ getModuleDeclaration ( ) .getMethodName ( ) = "module" and
11794 result = getScope ( ) .getVariable ( "exports" )
11895 }
11996
@@ -137,26 +114,36 @@ module Closure {
137114 class ClosureScript extends TopLevel {
138115 ClosureScript ( ) {
139116 not this instanceof ClosureModule and
140- getAChildStmt ( ) instanceof GoogProvide
141- or
142- getAChildStmt ( ) .( ExprStmt ) .getExpr ( ) instanceof GoogRequire
117+ (
118+ any ( ClosureProvideCall provide ) .getTopLevel ( ) = this
119+ or
120+ any ( ClosureRequireCall require ) .getTopLevel ( ) = this
121+ )
143122 }
144123
145124 /** Gets the identifier of a namespace required by this module. */
146125 string getARequiredNamespace ( ) {
147- result = getAChildStmt ( ) .( ExprStmt ) .getExpr ( ) .( GoogRequire ) .getClosureNamespace ( )
126+ exists ( ClosureRequireCall require |
127+ require .getTopLevel ( ) = this and
128+ result = require .getClosureNamespace ( )
129+ )
148130 }
149131
150132 /** Gets the identifer of a namespace provided by this module. */
151- string getAProvidedNamespace ( ) { result = getAChildStmt ( ) .( GoogProvide ) .getClosureNamespace ( ) }
133+ string getAProvidedNamespace ( ) {
134+ exists ( ClosureProvideCall require |
135+ require .getTopLevel ( ) = this and
136+ result = require .getClosureNamespace ( )
137+ )
138+ }
152139 }
153140
154141 /**
155142 * Holds if `name` is a closure namespace, including proper namespace prefixes.
156143 */
157144 pragma [ noinline]
158145 predicate isLibraryNamespacePath ( string name ) {
159- exists ( string namespace | namespace = any ( GoogNamespaceRef provide ) .getClosureNamespace ( ) |
146+ exists ( string namespace | namespace = any ( ClosureNamespaceRef ref ) .getClosureNamespace ( ) |
160147 name = namespace .substring ( 0 , namespace .indexOf ( "." ) )
161148 or
162149 name = namespace
@@ -185,7 +172,7 @@ module Closure {
185172 result = getWrittenLibraryAccessPath ( write )
186173 )
187174 or
188- result = node .asExpr ( ) . ( GoogRequire ) .getClosureNamespace ( )
175+ result = node .( ClosureRequireCall ) .getClosureNamespace ( )
189176 }
190177
191178 /**
0 commit comments