forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTypeScript.qll
More file actions
2875 lines (2401 loc) · 91.8 KB
/
Copy pathTypeScript.qll
File metadata and controls
2875 lines (2401 loc) · 91.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import javascript
/**
* A statement that defines a namespace, that is, a namespace declaration or enum declaration.
*
* Declarations that declare an alias for a namespace (i.e. an import) are not
* considered to be namespace definitions.
*/
class NamespaceDefinition extends Stmt, @namespace_definition, AST::ValueNode {
/**
* DEPRECATED: Use `getIdentifier()` instead.
*
* Gets the identifier naming the namespace.
*/
deprecated Identifier getId() { result = this.getIdentifier() }
/**
* Gets the identifier naming the namespace.
*/
Identifier getIdentifier() { none() } // Overridden in subtypes.
/**
* Gets unqualified name of the namespace being defined.
*/
string getName() {
result = this.(NamespaceDeclaration).getName()
or
result = this.(EnumDeclaration).getName()
}
/**
* Gets the local namespace name induced by this namespace.
*/
LocalNamespaceName getLocalNamespaceName() {
result = this.getIdentifier().(LocalNamespaceDecl).getLocalNamespaceName()
}
/**
* Gets the canonical name of the namespace being defined.
*/
Namespace getNamespace() { result.getADefinition() = this }
}
/**
* A TypeScript namespace declaration.
*
* This is also known as an "internal module" and can be declared
* using the `module` or `namespace` keyword. For example:
* ```
* namespace util { ... }
* module util { ... } // equivalent
* ```
*
* Note that modules whose name is a string literal, called "external modules",
* and are not namespace declarations.
* For example, `declare module "X" {...}` is an external module declaration.
* These are represented by `ExternalModuleDeclaration`.
*/
class NamespaceDeclaration extends NamespaceDefinition, StmtContainer, @namespace_declaration {
/** Gets the name of this namespace. */
override Identifier getIdentifier() { result = this.getChildExpr(-1) }
/** Gets the name of this namespace as a string. */
override string getName() { result = this.getIdentifier().getName() }
/** Gets the `i`th statement in this namespace. */
Stmt getStmt(int i) {
i >= 0 and
result = this.getChildStmt(i)
}
/** Gets a statement in this namespace. */
override Stmt getAStmt() { result = this.getStmt(_) }
/** Gets the number of statements in this namespace. */
int getNumStmt() { result = count(this.getAStmt()) }
override StmtContainer getEnclosingContainer() { result = this.getContainer() }
/**
* Holds if this declaration implies the existence of a concrete namespace object at runtime.
*
* A namespace that is empty or only contains interfaces and type aliases is not instantiated,
* and thus has no namespace object at runtime and is not associated with a variable.
*/
predicate isInstantiated() { is_instantiated(this) }
override ControlFlowNode getFirstControlFlowNode() {
if has_declare_keyword(this) then result = this else result = this.getIdentifier()
}
override string getAPrimaryQlClass() { result = "NamespaceDeclaration" }
}
/**
* A statement that defines a named type, that is, a class, interface, type alias, or enum declaration.
*
* Note that imports and type parameters are not type definitions. Consider using `TypeDecl` to capture
* a wider class of type declarations.
*/
class TypeDefinition extends ASTNode, @type_definition {
/**
* Gets the identifier naming the type.
*/
Identifier getIdentifier() {
result = this.(ClassDefinition).getIdentifier() or
result = this.(InterfaceDeclaration).getIdentifier() or
result = this.(TypeAliasDeclaration).getIdentifier() or
result = this.(EnumDeclaration).getIdentifier() or
result = this.(EnumMember).getIdentifier()
}
/**
* Gets the unqualified name of the type being defined.
*/
string getName() { result = this.getIdentifier().getName() }
/**
* Gets the canonical name of the type being defined.
*/
TypeName getTypeName() { result.getADefinition() = this }
/**
* Gets the type defined by this declaration.
*/
Type getType() { ast_node_type(this.getIdentifier(), result) }
override string getAPrimaryQlClass() { result = "TypeDefinition" }
}
/**
* A TypeScript declaration of form `declare module "X" {...}` where `X`
* is the name of an external module.
*/
class ExternalModuleDeclaration extends Stmt, StmtContainer, @external_module_declaration {
/**
* Gets the string literal denoting the module name, such as `"fs"` in:
* ```
* declare module "fs" {...}
* ```
*/
StringLiteral getNameLiteral() { result = this.getChildExpr(-1) }
/**
* Gets the module name, such as `fs` in:
* ```
* declare module "fs" {...}
* ```
*/
string getName() { result = this.getNameLiteral().getStringValue() }
/** Gets the `i`th statement in this namespace. */
Stmt getStmt(int i) {
i >= 0 and
result = this.getChildStmt(i)
}
/** Gets a statement in this namespace. */
override Stmt getAStmt() { result = this.getStmt(_) }
/** Gets the number of statements in this namespace. */
int getNumStmt() { result = count(this.getAStmt()) }
override StmtContainer getEnclosingContainer() { result = this.getContainer() }
override string getAPrimaryQlClass() { result = "ExternalModuleDeclaration" }
}
/**
* A TypeScript declaration of form `declare global {...}`.
*/
class GlobalAugmentationDeclaration extends Stmt, StmtContainer, @global_augmentation_declaration {
/** Gets the `i`th statement in this namespace. */
Stmt getStmt(int i) {
i >= 0 and
result = this.getChildStmt(i)
}
/** Gets a statement in this namespace. */
override Stmt getAStmt() { result = this.getStmt(_) }
/** Gets the number of statements in this namespace. */
int getNumStmt() { result = count(this.getAStmt()) }
override StmtContainer getEnclosingContainer() { result = this.getContainer() }
override string getAPrimaryQlClass() { result = "GlobalAugmentationDeclaration" }
}
/** A TypeScript "import-equals" declaration. */
class ImportEqualsDeclaration extends Stmt, @import_equals_declaration {
/**
* DEPRECATED: Use `getIdentifier()` instead.
*
* Gets the name under which the imported entity is imported.
*/
deprecated Identifier getId() { result = this.getIdentifier() }
/** Gets the name under which the imported entity is imported. */
Identifier getIdentifier() { result = this.getChildExpr(0) }
/** Gets the expression specifying the imported module or entity. */
Expr getImportedEntity() { result = this.getChildExpr(1) }
override ControlFlowNode getFirstControlFlowNode() { result = this.getIdentifier() }
override string getAPrimaryQlClass() { result = "ImportEqualsDeclaration" }
}
/**
* A `require()` call in a TypeScript import-equals declaration, such as `require("foo")` in:
* ```
* import foo = require("foo");
* ```
*
* These are special in that they may only occur in an import-equals declaration,
* and the compiled output depends on the `--module` flag passed to the
* TypeScript compiler.
*/
class ExternalModuleReference extends Expr, Import, @external_module_reference {
/** Gets the expression specifying the module. */
Expr getExpression() { result = this.getChildExpr(0) }
override PathExpr getImportedPath() { result = this.getExpression() }
override Module getEnclosingModule() { result = this.getTopLevel() }
override ControlFlowNode getFirstControlFlowNode() {
result = this.getExpression().getFirstControlFlowNode()
}
override DataFlow::Node getImportedModuleNode() { result = DataFlow::valueNode(this) }
override string getAPrimaryQlClass() { result = "ExternalModuleReference" }
}
/** A literal path expression appearing in an external module reference. */
private class LiteralExternalModulePath extends PathExpr, ConstantString {
LiteralExternalModulePath() {
exists(ExternalModuleReference emr | this.getParentExpr*() = emr.getExpression())
}
override string getValue() { result = this.getStringValue() }
}
/** A TypeScript "export-assign" declaration. */
class ExportAssignDeclaration extends Stmt, @export_assign_declaration {
/** Gets the expression exported by this declaration. */
Expr getExpression() { result = this.getChildExpr(0) }
override string getAPrimaryQlClass() { result = "ExportAssignDeclaration" }
}
/** A TypeScript export of form `export as namespace X` where `X` is an identifier. */
class ExportAsNamespaceDeclaration extends Stmt, @export_as_namespace_declaration {
/**
* Gets the `X` in `export as namespace X`.
*/
Identifier getIdentifier() { result = this.getChildExpr(0) }
override string getAPrimaryQlClass() { result = "ExportAsNamespaceDeclaration" }
}
/**
* A type alias declaration, that is, a statement of form `type A = T`.
*/
class TypeAliasDeclaration extends @type_alias_declaration, TypeParameterized, Stmt {
/** Gets the name of this type alias as a string. */
string getName() { result = this.getIdentifier().getName() }
Identifier getIdentifier() { result = this.getChildTypeExpr(0) }
override TypeParameter getTypeParameter(int n) { result = this.getChildTypeExpr(n + 2) }
/**
* Gets the `T` in `type A = T`.
*/
TypeExpr getDefinition() { result = this.getChildTypeExpr(1) }
override string describe() { result = "type alias " + this.getName() }
/**
* Gets the canonical name of the type being defined.
*/
TypeName getTypeName() { result.getADefinition() = this }
override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" }
}
/**
* A TypeScript interface declaration, inline interface type, or function type.
*/
class InterfaceDefinition extends @interface_definition, ClassOrInterface {
override predicate isAbstract() { any() }
override string getAPrimaryQlClass() { result = "InterfaceDefinition" }
}
/** A TypeScript interface declaration. */
class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interface_declaration {
override Identifier getIdentifier() { result = this.getChildTypeExpr(0) }
override TypeParameter getTypeParameter(int n) {
exists(int astIndex | typeexprs(result, _, this, astIndex, _) |
astIndex <= -2 and astIndex % 2 = 0 and n = -(astIndex + 2) / 2
)
}
override string describe() { result = "interface " + this.getName() }
/**
* Gets the `n`th type from the `extends` clause of this interface, starting at 0.
*/
override TypeExpr getSuperInterface(int n) {
exists(int astIndex | typeexprs(result, _, this, astIndex, _) |
astIndex <= -1 and astIndex % 2 = -1 and n = -(astIndex + 1) / 2
)
}
/**
* Gets any type from the `extends` clause of this interface.
*/
override TypeExpr getASuperInterface() { result = InterfaceDefinition.super.getASuperInterface() }
override string getAPrimaryQlClass() { result = "InterfaceDeclaration" }
}
/** An inline TypeScript interface type, such as `{x: number; y: number}`. */
class InterfaceTypeExpr extends TypeExpr, InterfaceDefinition, @interface_typeexpr {
override Identifier getIdentifier() { none() }
override string describe() { result = "anonymous interface" }
override string getAPrimaryQlClass() { result = "InterfaceTypeExpr" }
}
/**
* A TypeScript function type, such as `(x: string) => number` or a
* constructor type such as `new (x: string) => Object`.
*/
class FunctionTypeExpr extends TypeExpr, @function_typeexpr {
/** Holds if this is a constructor type, such as `new (x: string) => Object`. */
predicate isConstructor() { this instanceof ConstructorTypeExpr }
/** Gets the function AST node that holds the parameters and return type. */
FunctionExpr getFunction() { result = this.getChildExpr(0) }
/** Gets the `n`th parameter of this function type. */
Parameter getParameter(int n) { result = this.getFunction().getParameter(n) }
/** Gets any of the parameters of this function type. */
Parameter getAParameter() { result = this.getFunction().getAParameter() }
/** Gets the number of parameters of this function type. */
int getNumParameter() { result = this.getFunction().getNumParameter() }
/** Gets the `n`th type parameter of this function type. */
TypeParameter getTypeParameter(int n) { result = this.getFunction().getTypeParameter(n) }
/** Gets any of the type parameters of this function type. */
TypeParameter getATypeParameter() { result = this.getFunction().getATypeParameter() }
/** Gets the number of type parameters of this function type. */
int getNumTypeParameter() { result = this.getFunction().getNumTypeParameter() }
/** Gets the return type of this function type, if any. */
TypeExpr getReturnTypeAnnotation() { result = this.getFunction().getReturnTypeAnnotation() }
override string getAPrimaryQlClass() { result = "FunctionTypeExpr" }
}
/** A constructor type, such as `new (x: string) => Object`. */
class ConstructorTypeExpr extends FunctionTypeExpr, @constructor_typeexpr { }
/** A function type that is not a constructor type, such as `(x: string) => number`. */
class PlainFunctionTypeExpr extends FunctionTypeExpr, @plain_function_typeexpr { }
/** A possibly qualified identifier that declares or refers to a type. */
abstract class TypeRef extends ASTNode { }
/** An identifier declaring a type name, that is, the name of a class, interface, type parameter, or import. */
class TypeDecl extends Identifier, TypeRef, LexicalDecl {
TypeDecl() {
this = any(ClassOrInterface ci).getIdentifier() or
this = any(TypeParameter tp).getIdentifier() or
this = any(ImportSpecifier im).getLocal() or
this = any(ImportEqualsDeclaration im).getIdentifier() or
this = any(TypeAliasDeclaration td).getIdentifier() or
this = any(EnumDeclaration ed).getIdentifier() or
this = any(EnumMember member).getIdentifier()
}
/**
* Gets the local type name being declared.
*
* If this is an import or type alias, the local type name represents the local alias.
*/
LocalTypeName getLocalTypeName() { result.getADeclaration() = this }
/**
* Gets a string describing the type being declared, consisting of the declaration kind and
* the name being declared, such as `class C` for a class declaration `C`.
*/
string describe() {
exists(ClassOrInterface ci | this = ci.getIdentifier() | result = ci.describe())
or
exists(TypeParameter tp | this = tp.getIdentifier() |
result = "type parameter " + this.getName()
)
or
exists(TypeAliasDeclaration td | this = td.getIdentifier() |
result = "type alias " + this.getName()
)
or
exists(EnumDeclaration enum | this = enum.getIdentifier() | result = "enum " + this.getName())
or
exists(EnumMember member | this = member.getIdentifier() |
result = "enum member " + member.getPrefixedName()
)
or
exists(ImportSpecifier im | this = im.getLocal() | result = "imported type " + this.getName())
}
}
/**
* The local name for a type in a particular scope.
*
* It is possible for two distinct local type names to refer to the same underlying
* type through imports or type aliases. For example:
* ```
* namespace A {
* export class C {}
* }
* namespace B {
* import C = A.C;
* }
* ```
* In the above example, two distinct local type names exist for the type `C`:
* one in `A` and one in `B`.
* Since a local type name is always specific to one scope, it is not possible
* for the two namespaces to share a single local type name for `C`.
*
* There may be multiple declarations of a given local type name, for example:
* ```
* interface Point { x: number; }
* interface Point { y: number; }
* ```
* In the above example, the two declarations of `Point` refer to the same
* local type name.
*/
class LocalTypeName extends @local_type_name, LexicalName {
/** Gets the local name of this type. */
override string getName() { local_type_names(this, result, _) }
/** Gets the scope this type name is declared in. */
override Scope getScope() { local_type_names(this, _, result) }
/** Gets a textual representation of this element. */
override string toString() { result = this.getName() }
/**
* Gets a declaration of this type name.
*
* All local type names have at least one declaration and may have
* multiple declarations in case these are interface declarations.
*/
TypeDecl getADeclaration() { typedecl(result, this) }
/**
* Gets the first declaration of this type name.
*/
TypeDecl getFirstDeclaration() {
result =
min(this.getADeclaration() as decl
order by
decl.getLocation().getStartLine(), decl.getLocation().getStartColumn()
)
}
/** Gets a use of this type name in a type annotation. */
LocalTypeAccess getATypeAccess() { typebind(result, this) }
/** Gets a use of this type name in an export. */
ExportVarAccess getAnExportAccess() { typebind(result, this) }
/** Gets an identifier that refers to this type name. */
Identifier getAnAccess() { typebind(result, this) }
override DeclarationSpace getDeclarationSpace() { result = "type" }
}
/**
* The local name for a namespace in a particular scope.
*
* Namespace declarations and imports can give rise to local namespace names.
* For example, the following declarations declare two local namespace names,
* `A` and `B`:
* ```
* import A from './A';
* namespace B {}
* ```
*
* It is possible for a namespace to have multiple aliases; each alias corresponds
* to a distinct local namespace name. For example, there are three distinct local
* namespace names for `A` in this example:
* ```
* namespace A {}
* namespace Q {
* import B = A;
* import C = A;
* }
* ```
* There is one local namespace name for the declaration of `A` and one for each import.
*/
class LocalNamespaceName extends @local_namespace_name, LexicalName {
/** Gets the local name of this namespace. */
override string getName() { local_namespace_names(this, result, _) }
/** Gets the scope this namespace name is declared in. */
override Scope getScope() { local_namespace_names(this, _, result) }
/** Gets a textual representation of this element. */
override string toString() { result = this.getName() }
/**
* Gets a declaration of this namespace name.
*
* All local namespace names have at least one declaration and may have
* multiple declarations unless it comes from an import.
*/
LocalNamespaceDecl getADeclaration() { namespacedecl(result, this) }
/**
* Gets the first declaration of this namespace name.
*/
LocalNamespaceDecl getFirstDeclaration() {
result =
min(this.getADeclaration() as decl
order by
decl.getLocation().getStartLine(), decl.getLocation().getStartColumn()
)
}
/** Gets a use of this namespace name in a type annotation. */
LocalNamespaceAccess getATypeAccess() { namespacebind(result, this) }
/** Gets a use of this namespace in an export. */
ExportVarAccess getAnExportAccess() { namespacebind(result, this) }
/**
* Gets an access to a type member of this namespace alias,
* such as `http.ServerRequest` where `http` is a reference to this namespace.
*/
QualifiedTypeAccess getAMemberAccess(string member) {
result.getIdentifier().getName() = member and
result.getQualifier() = this.getAnAccess()
}
/** Gets an identifier that refers to this namespace name. */
Identifier getAnAccess() { namespacebind(result, this) }
/**
* Gets the canonical name of the namespace referenced by this name.
*/
Namespace getNamespace() { result = this.getADeclaration().getNamespace() }
override DeclarationSpace getDeclarationSpace() { result = "namespace" }
}
/**
* A type expression, that is, an AST node that is part of a TypeScript type annotation.
*
* This class includes only explicit type annotations -
* types inferred by the TypeScript compiler are not type expressions.
*/
class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
override string toString() { typeexprs(this, _, _, _, result) }
/**
* Gets the static type expressed by this type annotation.
*
* Has no result if this occurs in a TypeScript file that was extracted
* without type information.
*/
override Type getType() { ast_node_type(this, result) }
override Stmt getEnclosingStmt() { result = ExprOrType.super.getEnclosingStmt() }
override Function getEnclosingFunction() { result = ExprOrType.super.getEnclosingFunction() }
override TopLevel getTopLevel() { result = ExprOrType.super.getTopLevel() }
override DataFlow::ClassNode getClass() {
result.getAstNode() = this.getType().(ClassType).getClass()
}
}
/**
* Classes that are internally represented as a keyword type.
*/
private class KeywordTypeExpr extends @keyword_typeexpr, TypeExpr {
string getName() { literals(result, _, this) }
override predicate isAny() { this.getName() = "any" }
override predicate isString() { this.getName() = "string" }
override predicate isStringy() { this.getName() = "string" }
override predicate isNumber() { this.getName() = "number" }
override predicate isNumbery() { this.getName() = "number" }
override predicate isBoolean() { this.getName() = "boolean" }
override predicate isBooleany() { this.getName() = "boolean" }
override predicate isUndefined() { this.getName() = "undefined" }
override predicate isNull() { this.getName() = "null" }
override predicate isVoid() { this.getName() = "void" }
override predicate isNever() { this.getName() = "never" }
override predicate isThis() { this.getName() = "this" }
override predicate isSymbol() { this.getName() = "symbol" }
override predicate isUniqueSymbol() { this.getName() = "unique symbol" }
override predicate isObjectKeyword() { this.getName() = "object" }
override predicate isUnknownKeyword() { this.getName() = "unknown" }
override predicate isBigInt() { this.getName() = "bigint" }
override predicate isConstKeyword() { this.getName() = "const" }
override string getAPrimaryQlClass() { result = "KeywordTypeExpr" }
}
/**
* A use of the predefined type `any`, `string`, `number`, `boolean`, `null`, `undefined`, `void`, `never`, `symbol`, or `object`.
*/
class PredefinedTypeExpr extends KeywordTypeExpr {
PredefinedTypeExpr() {
not this.isThis() // The only keyword type that we don't consider a "predefined" type
}
}
/**
* A use of the `this` type.
*/
class ThisTypeExpr extends KeywordTypeExpr {
ThisTypeExpr() { this.isThis() }
}
/**
* A possibly qualified name that is used as part of a type, such as `Date` or `http.ServerRequest`.
*
* Type arguments are not part of a type access but there are convenience methods in this class
* for accessing them.
*/
class TypeAccess extends @typeaccess, TypeExpr, TypeRef {
/** Gets the identifier naming the type without any qualifier, such as `ServerRequest` in `http.ServerRequest`. */
Identifier getIdentifier() { none() }
/**
* Gets the enclosing generic type expression providing type arguments to this type, if any.
*
* For example, in `Array<number>`, the `Array` part is a type access with `Array<number>`
* being its enclosing generic type.
*/
GenericTypeExpr getAsGenericType() { result.getTypeAccess() = this }
/**
* Holds if there are type arguments provided to this type by an enclosing generic type expression.
*
* For example, in `Array<number>`, the `Array` part is a type access having type arguments.
*/
predicate hasTypeArguments() { exists(this.getAsGenericType()) }
/**
* Gets the `n`th type argument provided to this type by the enclosing generic type expression, if any.
*
* For example, in `Array<number>`, the `Array` part is a type access having the type argument `number`.
*/
TypeExpr getTypeArgument(int n) { result = this.getAsGenericType().getTypeArgument(n) }
/**
* Gets a type argument provided to this type by the enclosing generic type expression, if any.
*
* For example, in `Array<number>`, the `Array` part is a type access having the type argument `number`.
*/
TypeExpr getATypeArgument() { result = this.getAsGenericType().getATypeArgument() }
/**
* Gets the number of type arguments provided to this type by the enclosing generic type expression,
* if any, or 0 otherwise.
*
* For example, in `Array<number>`, the `Array` part is a type access having 1 type argument.
*/
int getNumTypeArgument() {
if exists(this.getAsGenericType())
then result = this.getAsGenericType().getNumTypeArgument()
else result = 0
}
/**
* Gets the canonical name of the type being accessed.
*/
TypeName getTypeName() { ast_node_symbol(this, result) }
override predicate hasQualifiedName(string globalName) {
this.getTypeName().hasQualifiedName(globalName)
or
exists(LocalTypeAccess local | local = this |
not exists(local.getLocalTypeName()) and // Without a local type name, the type is looked up in the global scope.
globalName = local.getName()
)
}
override predicate hasQualifiedName(string moduleName, string exportedName) {
this.getTypeName().hasQualifiedName(moduleName, exportedName)
or
exists(ImportDeclaration imprt, ImportSpecifier spec |
moduleName = getImportName(imprt) and
spec = imprt.getASpecifier()
|
spec.getImportedName() = exportedName and
this = spec.getLocal().(TypeDecl).getLocalTypeName().getAnAccess()
or
(spec instanceof ImportNamespaceSpecifier or spec instanceof ImportDefaultSpecifier) and
this =
spec.getLocal().(LocalNamespaceDecl).getLocalNamespaceName().getAMemberAccess(exportedName)
)
or
exists(ImportEqualsDeclaration imprt |
moduleName = getImportName(imprt.getImportedEntity()) and
this =
imprt
.getIdentifier()
.(LocalNamespaceDecl)
.getLocalNamespaceName()
.getAMemberAccess(exportedName)
)
}
override string getAPrimaryQlClass() { result = "TypeAccess" }
}
/**
* Gets a suitable name for the library imported by `import`.
*
* For relative imports, this is the snapshot-relative path to the imported module.
* For non-relative imports, it is the import path itself.
*/
private string getImportName(Import imprt) {
exists(string path | path = imprt.getImportedPath().getValue() |
if path.regexpMatch("[./].*")
then result = imprt.getImportedModule().getFile().getRelativePath()
else result = path
)
}
/** An identifier that is used as part of a type, such as `Date`. */
class LocalTypeAccess extends @local_type_access, TypeAccess, Identifier, LexicalAccess {
override predicate isStringy() { this.getName() = "String" }
override predicate isNumbery() { this.getName() = "Number" }
override predicate isBooleany() { this.getName() = "Boolean" }
override predicate isRawFunction() { this.getName() = "Function" }
override Identifier getIdentifier() { result = this }
/**
* Gets the local type name being referenced by this identifier, if any.
*
* Names that refer to a declaration in an external `d.ts` file, such as in
* the built-in `lib.d.ts` prelude, do not have a local typename.
*
* For example, in `Array<number>`, the `Array` name will usually not have
* a local type name as it is declared in `lib.d.ts`.
*/
LocalTypeName getLocalTypeName() { result.getAnAccess() = this }
override string getAPrimaryQlClass() { result = "LocalTypeAccess" }
}
/**
* A qualified name that is used as part of a type, such as `http.ServerRequest`.
*/
class QualifiedTypeAccess extends @qualified_type_access, TypeAccess {
/**
* Gets the qualifier in front of the name, such as `http` in `http.ServerRequest`.
*
* If the prefix consists of multiple identifiers, the qualifier is itself a qualified namespace access.
* For example, the qualifier of `lib.util.List` is `lib.util`.
*/
NamespaceAccess getQualifier() { result = this.getChildTypeExpr(0) }
/** Gets the last identifier in the name, such as `ServerRequest` in `http.ServerRequest`. */
override Identifier getIdentifier() { result = this.getChildTypeExpr(1) }
}
/**
* A type consisting of a name and at least one type argument, such as `Array<number>`.
*
* For convenience, the methods for accessing type arguments are also made available
* on the `TypeAccess` class.
*/
class GenericTypeExpr extends @generic_typeexpr, TypeExpr {
/** Gets the name of the type, such as `Array` in `Array<number>`. */
TypeAccess getTypeAccess() { result = this.getChildTypeExpr(-1) }
/** Gets the `n`th type argument, starting at 0. */
TypeExpr getTypeArgument(int n) { result = this.getChildTypeExpr(n) and n >= 0 }
/** Gets any of the type arguments. */
TypeExpr getATypeArgument() { result = this.getTypeArgument(_) }
/** Gets the number of type arguments. This is always at least one. */
int getNumTypeArgument() { result = count(this.getATypeArgument()) }
override predicate hasQualifiedName(string globalName) {
this.getTypeAccess().hasQualifiedName(globalName)
}
override predicate hasQualifiedName(string moduleName, string exportedName) {
this.getTypeAccess().hasQualifiedName(moduleName, exportedName)
}
override string getAPrimaryQlClass() { result = "GenericTypeExpr" }
}
/**
* A string, number, or boolean literal used as a type.
*
* Note that the `null` and `undefined` types are considered predefined types, not literal types.
*/
class LiteralTypeExpr extends @literal_typeexpr, TypeExpr {
/** Gets the value of this literal, as a string. */
string getValue() { literals(result, _, this) }
/**
* Gets the raw source text of this literal, including quotes for
* string literals.
*/
string getRawValue() { literals(_, result, this) }
override string getAPrimaryQlClass() { result = "LiteralTypeExpr" }
}
/** A string literal used as a type. */
class StringLiteralTypeExpr extends @string_literal_typeexpr, LiteralTypeExpr { }
/** A number literal used as a type. */
class NumberLiteralTypeExpr extends @number_literal_typeexpr, LiteralTypeExpr {
/** Gets the integer value of this literal type. */
int getIntValue() { result = this.getValue().toInt() }
}
/** A boolean literal used as a type. */
class BooleanLiteralTypeExpr extends @boolean_literal_typeexpr, LiteralTypeExpr {
predicate isTrue() { this.getValue() = "true" }
predicate isFalse() { this.getValue() = "false" }
}
/** A bigint literal used as a TypeScript type annotation. */
class BigIntLiteralTypeExpr extends @bigint_literal_typeexpr, LiteralTypeExpr {
/** Gets the integer value of the bigint literal, if it can be represented as a QL integer. */
int getIntValue() { result = this.getValue().toInt() }
/**
* Gets the floating point value of this literal if it can be represented
* as a QL floating point value.
*/
float getFloatValue() { result = this.getValue().toFloat() }
}
/**
* An array type, such as `number[]`, or in general `T[]` where `T` is a type.
*
* This class includes only type expressions that use the notation `T[]`.
* Named types such as `Array<number>` and tuple types such as `[number, string]`
* are not array type expressions.
*/
class ArrayTypeExpr extends @array_typeexpr, TypeExpr {
/** Gets the type of the array elements. */
TypeExpr getElementType() { result = this.getChildTypeExpr(0) }
override string getAPrimaryQlClass() { result = "ArrayTypeExpr" }
}
/**
* A union type, such as `string|number|boolean`.
*/
class UnionTypeExpr extends @union_typeexpr, TypeExpr {
/** Gets the `n`th type in the union, starting at 0. */
TypeExpr getElementType(int n) { result = this.getChildTypeExpr(n) }
/** Gets any of the types in the union. */
TypeExpr getAnElementType() { result = this.getElementType(_) }
/** Gets the number of types in the union. This is always at least two. */
int getNumElementType() { result = count(this.getAnElementType()) }
override TypeExpr getAnUnderlyingType() { result = this.getAnElementType().getAnUnderlyingType() }
override string getAPrimaryQlClass() { result = "UnionTypeExpr" }
}
/**
* A type of form `T[K]` where `T` and `K` are types.
*/
class IndexedAccessTypeExpr extends @indexed_access_typeexpr, TypeExpr {
/** Gets the type `T` in `T[K]`, denoting the object type whose properties are to be extracted. */
TypeExpr getObjectType() { result = this.getChildTypeExpr(0) }
/** Gets the type `K` in `T[K]`, denoting the property names to extract from the object type. */
TypeExpr getIndexType() { result = this.getChildTypeExpr(1) }
override string getAPrimaryQlClass() { result = "IndexedAccessTypeExpr" }
}
/**
* A type of form `S&T`, denoting the intersection of type `S` and type `T`.
*
* In general, there are can more than two operands to an intersection type.
*/
class IntersectionTypeExpr extends @intersection_typeexpr, TypeExpr {
/** Gets the `n`th operand of the intersection type, starting at 0. */
TypeExpr getElementType(int n) { result = this.getChildTypeExpr(n) }
/** Gets any of the operands to the intersection type. */
TypeExpr getAnElementType() { result = this.getElementType(_) }
/** Gets the number of operands to the intersection type. This is always at least two. */
int getNumElementType() { result = count(this.getAnElementType()) }
override TypeExpr getAnUnderlyingType() { result = this.getAnElementType().getAnUnderlyingType() }
override string getAPrimaryQlClass() { result = "IntersectionTypeExpr" }
}
/**
* A type expression enclosed in parentheses.
*/
class ParenthesizedTypeExpr extends @parenthesized_typeexpr, TypeExpr {
/** Gets the type inside the parentheses. */
TypeExpr getElementType() { result = this.getChildTypeExpr(0) }
override TypeExpr stripParens() { result = this.getElementType().stripParens() }
override TypeExpr getAnUnderlyingType() { result = this.getElementType().getAnUnderlyingType() }
override string getAPrimaryQlClass() { result = "ParenthesizedTypeExpr" }
}
/**
* A tuple type such as `[number, string]`.
*/
class TupleTypeExpr extends @tuple_typeexpr, TypeExpr {
/** Gets the `n`th element type in the tuple, starting at 0. */
TypeExpr getElementType(int n) { result = this.getChildTypeExpr(n) and n >= 0 }
/** Gets any of the element types in the tuple. */
TypeExpr getAnElementType() { result = this.getElementType(_) }
/** Gets the number of elements in the tuple type. */
int getNumElementType() { result = count(this.getAnElementType()) }
/**
* Gets the name of the `n`th tuple member, starting at 0.
* Only has a result if the tuple members are named.
*/
Identifier getElementName(int n) {
// Type element names are at indices -1, -2, -3, ...
result = this.getChild(-(n + 1)) and n >= 0
}
override string getAPrimaryQlClass() { result = "TupleTypeExpr" }
}
/**
* A type of form `keyof T` where `T` is a type.
*/
class KeyofTypeExpr extends @keyof_typeexpr, TypeExpr {
/** Gets the type `T` in `keyof T`, denoting the object type whose property names are to be extracted. */
TypeExpr getElementType() { result = this.getChildTypeExpr(0) }
override string getAPrimaryQlClass() { result = "KeyofTypeExpr" }
}
/**
* A type of form `{ [K in C]: T }` where `K in C` declares a type parameter with `C`