Merge pull request #19078 from asgerf/js/name-resolution

JS: QL-side type/name resolution for TypeScript and JSDoc
This commit is contained in:
Asger F
2025-06-11 14:17:11 +02:00
committed by GitHub
79 changed files with 3729 additions and 2180 deletions

View File

@@ -426,7 +426,6 @@ public class ScopeManager {
// cases where we turn on the 'declKind' flags
@Override
public Void visit(FunctionDeclaration nd, Void v) {
if (nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile()) return null;
// strict mode functions are block-scoped, non-strict mode ones aren't
if (blockscope == isStrict) visit(nd.getId(), DeclKind.var);
return null;
@@ -434,7 +433,6 @@ public class ScopeManager {
@Override
public Void visit(ClassDeclaration nd, Void c) {
if (nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile()) return null;
if (blockscope) visit(nd.getClassDef().getId(), DeclKind.varAndType);
return null;
}
@@ -483,7 +481,6 @@ public class ScopeManager {
@Override
public Void visit(VariableDeclaration nd, Void v) {
if (nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile()) return null;
// in block scoping mode, only process 'let'; in non-block scoping
// mode, only process non-'let'
if (blockscope == nd.isBlockScoped(ecmaVersion)) visit(nd.getDeclarations());
@@ -518,8 +515,7 @@ public class ScopeManager {
@Override
public Void visit(NamespaceDeclaration nd, Void c) {
if (blockscope) return null;
boolean isAmbientOutsideDtsFile = nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile();
boolean hasVariable = nd.isInstantiated() && !isAmbientOutsideDtsFile;
boolean hasVariable = nd.isInstantiated();
visit(nd.getName(), hasVariable ? DeclKind.varAndNamespace : DeclKind.namespace);
return null;
}

View File

@@ -50,61 +50,64 @@ toplevels(#20001,0)
#20016=@"loc,{#10000},1,1,2,0"
locations_default(#20016,#10000,1,1,2,0)
hasLocation(#20001,#20016)
#20017=*
stmts(#20017,26,#20001,0,"declare class C {}")
hasLocation(#20017,#20003)
stmt_containers(#20017,#20001)
has_declare_keyword(#20017)
#20018=*
exprs(#20018,78,#20017,0,"C")
hasLocation(#20018,#20009)
enclosing_stmt(#20018,#20017)
expr_containers(#20018,#20001)
literals("C","C",#20018)
#20019=@"var;{C};{#20000}"
variables(#20019,"C",#20000)
decl(#20018,#20019)
#20017=@"var;{C};{#20000}"
variables(#20017,"C",#20000)
#20018=@"local_type_name;{C};{#20000}"
local_type_names(#20018,"C",#20000)
#20019=*
stmts(#20019,26,#20001,0,"declare class C {}")
hasLocation(#20019,#20003)
stmt_containers(#20019,#20001)
has_declare_keyword(#20019)
#20020=*
scopes(#20020,10)
scopenodes(#20017,#20020)
scopenesting(#20020,#20000)
exprs(#20020,78,#20019,0,"C")
hasLocation(#20020,#20009)
enclosing_stmt(#20020,#20019)
expr_containers(#20020,#20001)
literals("C","C",#20020)
decl(#20020,#20017)
typedecl(#20020,#20018)
#20021=*
properties(#20021,#20017,2,0,"constructor() {}")
#20022=@"loc,{#10000},1,17,1,16"
locations_default(#20022,#10000,1,17,1,16)
hasLocation(#20021,#20022)
#20023=*
exprs(#20023,0,#20021,0,"constructor")
hasLocation(#20023,#20022)
enclosing_stmt(#20023,#20017)
expr_containers(#20023,#20001)
literals("constructor","constructor",#20023)
scopes(#20021,10)
scopenodes(#20019,#20021)
scopenesting(#20021,#20000)
#20022=*
properties(#20022,#20019,2,0,"constructor() {}")
#20023=@"loc,{#10000},1,17,1,16"
locations_default(#20023,#10000,1,17,1,16)
hasLocation(#20022,#20023)
#20024=*
exprs(#20024,9,#20021,1,"() {}")
hasLocation(#20024,#20022)
enclosing_stmt(#20024,#20017)
exprs(#20024,0,#20022,0,"constructor")
hasLocation(#20024,#20023)
enclosing_stmt(#20024,#20019)
expr_containers(#20024,#20001)
literals("constructor","constructor",#20024)
#20025=*
scopes(#20025,1)
scopenodes(#20024,#20025)
scopenesting(#20025,#20020)
#20026=@"var;{arguments};{#20025}"
variables(#20026,"arguments",#20025)
is_arguments_object(#20026)
#20027=*
stmts(#20027,1,#20024,-2,"{}")
hasLocation(#20027,#20022)
stmt_containers(#20027,#20024)
is_method(#20021)
exprs(#20025,9,#20022,1,"() {}")
hasLocation(#20025,#20023)
enclosing_stmt(#20025,#20019)
expr_containers(#20025,#20001)
#20026=*
scopes(#20026,1)
scopenodes(#20025,#20026)
scopenesting(#20026,#20021)
#20027=@"var;{arguments};{#20026}"
variables(#20027,"arguments",#20026)
is_arguments_object(#20027)
#20028=*
entry_cfg_node(#20028,#20001)
#20029=@"loc,{#10000},1,1,1,0"
locations_default(#20029,#10000,1,1,1,0)
hasLocation(#20028,#20029)
#20030=*
exit_cfg_node(#20030,#20001)
hasLocation(#20030,#20015)
successor(#20017,#20030)
successor(#20028,#20017)
stmts(#20028,1,#20025,-2,"{}")
hasLocation(#20028,#20023)
stmt_containers(#20028,#20025)
is_method(#20022)
#20029=*
entry_cfg_node(#20029,#20001)
#20030=@"loc,{#10000},1,1,1,0"
locations_default(#20030,#10000,1,1,1,0)
hasLocation(#20029,#20030)
#20031=*
exit_cfg_node(#20031,#20001)
hasLocation(#20031,#20015)
successor(#20019,#20031)
successor(#20029,#20019)
numlines(#10000,1,1,0)
filetype(#10000,"typescript")

View File

@@ -584,62 +584,63 @@ toplevels(#20001,0)
#20221=@"loc,{#10000},1,1,16,0"
locations_default(#20221,#10000,1,1,16,0)
hasLocation(#20001,#20221)
#20222=@"var;{C};{#20000}"
variables(#20222,"C",#20000)
#20223=@"local_type_name;{C};{#20000}"
local_type_names(#20223,"C",#20000)
#20224=*
stmts(#20224,18,#20001,0,"declare var A : any;")
hasLocation(#20224,#20003)
stmt_containers(#20224,#20001)
has_declare_keyword(#20224)
#20225=*
exprs(#20225,64,#20224,0,"A : any")
#20226=@"loc,{#10000},1,13,1,19"
locations_default(#20226,#10000,1,13,1,19)
hasLocation(#20225,#20226)
enclosing_stmt(#20225,#20224)
expr_containers(#20225,#20001)
#20222=@"var;{A};{#20000}"
variables(#20222,"A",#20000)
#20223=@"var;{B};{#20000}"
variables(#20223,"B",#20000)
#20224=@"var;{C};{#20000}"
variables(#20224,"C",#20000)
variables(#20224,"C",#20000)
#20225=@"local_type_name;{C};{#20000}"
local_type_names(#20225,"C",#20000)
#20226=*
stmts(#20226,18,#20001,0,"declare var A : any;")
hasLocation(#20226,#20003)
stmt_containers(#20226,#20001)
has_declare_keyword(#20226)
#20227=*
exprs(#20227,78,#20225,0,"A")
hasLocation(#20227,#20037)
enclosing_stmt(#20227,#20224)
exprs(#20227,64,#20226,0,"A : any")
#20228=@"loc,{#10000},1,13,1,19"
locations_default(#20228,#10000,1,13,1,19)
hasLocation(#20227,#20228)
enclosing_stmt(#20227,#20226)
expr_containers(#20227,#20001)
literals("A","A",#20227)
#20228=@"var;{A};{#20000}"
variables(#20228,"A",#20000)
decl(#20227,#20228)
#20229=*
typeexprs(#20229,2,#20225,2,"any")
hasLocation(#20229,#20041)
enclosing_stmt(#20229,#20224)
exprs(#20229,78,#20227,0,"A")
hasLocation(#20229,#20037)
enclosing_stmt(#20229,#20226)
expr_containers(#20229,#20001)
literals("any","any",#20229)
literals("A","A",#20229)
decl(#20229,#20222)
#20230=*
stmts(#20230,18,#20001,1,"declare var B : any;")
hasLocation(#20230,#20005)
stmt_containers(#20230,#20001)
has_declare_keyword(#20230)
typeexprs(#20230,2,#20227,2,"any")
hasLocation(#20230,#20041)
enclosing_stmt(#20230,#20226)
expr_containers(#20230,#20001)
literals("any","any",#20230)
#20231=*
exprs(#20231,64,#20230,0,"B : any")
#20232=@"loc,{#10000},2,13,2,19"
locations_default(#20232,#10000,2,13,2,19)
hasLocation(#20231,#20232)
enclosing_stmt(#20231,#20230)
expr_containers(#20231,#20001)
#20233=*
exprs(#20233,78,#20231,0,"B")
hasLocation(#20233,#20049)
enclosing_stmt(#20233,#20230)
expr_containers(#20233,#20001)
literals("B","B",#20233)
#20234=@"var;{B};{#20000}"
variables(#20234,"B",#20000)
decl(#20233,#20234)
stmts(#20231,18,#20001,1,"declare var B : any;")
hasLocation(#20231,#20005)
stmt_containers(#20231,#20001)
has_declare_keyword(#20231)
#20232=*
exprs(#20232,64,#20231,0,"B : any")
#20233=@"loc,{#10000},2,13,2,19"
locations_default(#20233,#10000,2,13,2,19)
hasLocation(#20232,#20233)
enclosing_stmt(#20232,#20231)
expr_containers(#20232,#20001)
#20234=*
exprs(#20234,78,#20232,0,"B")
hasLocation(#20234,#20049)
enclosing_stmt(#20234,#20231)
expr_containers(#20234,#20001)
literals("B","B",#20234)
decl(#20234,#20223)
#20235=*
typeexprs(#20235,2,#20231,2,"any")
typeexprs(#20235,2,#20232,2,"any")
hasLocation(#20235,#20053)
enclosing_stmt(#20235,#20230)
enclosing_stmt(#20235,#20231)
expr_containers(#20235,#20001)
literals("any","any",#20235)
#20236=*
@@ -660,7 +661,7 @@ hasLocation(#20239,#20061)
enclosing_stmt(#20239,#20236)
expr_containers(#20239,#20001)
literals("C","C",#20239)
decl(#20239,#20222)
decl(#20239,#20224)
#20240=*
typeexprs(#20240,2,#20237,2,"any")
hasLocation(#20240,#20065)
@@ -679,8 +680,8 @@ hasLocation(#20243,#20071)
enclosing_stmt(#20243,#20241)
expr_containers(#20243,#20001)
literals("C","C",#20243)
decl(#20243,#20222)
typedecl(#20243,#20223)
decl(#20243,#20224)
typedecl(#20243,#20225)
#20244=*
scopes(#20244,10)
scopenodes(#20241,#20244)
@@ -769,7 +770,7 @@ exprs(#20266,79,#20265,0,"A")
hasLocation(#20266,#20093)
expr_containers(#20266,#20258)
literals("A","A",#20266)
bind(#20266,#20228)
bind(#20266,#20222)
#20267=*
stmts(#20267,1,#20258,-2,"{}")
#20268=@"loc,{#10000},7,12,7,13"
@@ -825,7 +826,7 @@ exprs(#20281,79,#20279,0,"A")
hasLocation(#20281,#20109)
expr_containers(#20281,#20272)
literals("A","A",#20281)
bind(#20281,#20228)
bind(#20281,#20222)
#20282=*
exprs(#20282,94,#20277,1,"@B")
#20283=@"loc,{#10000},8,9,8,10"
@@ -837,7 +838,7 @@ exprs(#20284,79,#20282,0,"B")
hasLocation(#20284,#20113)
expr_containers(#20284,#20272)
literals("B","B",#20284)
bind(#20284,#20234)
bind(#20284,#20223)
#20285=*
stmts(#20285,1,#20272,-2,"{}")
#20286=@"loc,{#10000},8,16,8,17"
@@ -899,7 +900,7 @@ exprs(#20300,79,#20299,0,"A")
hasLocation(#20300,#20133)
expr_containers(#20300,#20290)
literals("A","A",#20300)
bind(#20300,#20228)
bind(#20300,#20222)
#20301=*
stmts(#20301,1,#20290,-2,"{}")
#20302=@"loc,{#10000},10,18,10,19"
@@ -963,7 +964,7 @@ exprs(#20317,79,#20315,0,"A")
hasLocation(#20317,#20153)
expr_containers(#20317,#20306)
literals("A","A",#20317)
bind(#20317,#20228)
bind(#20317,#20222)
#20318=*
exprs(#20318,94,#20313,1,"@B")
#20319=@"loc,{#10000},11,15,11,16"
@@ -975,7 +976,7 @@ exprs(#20320,79,#20318,0,"B")
hasLocation(#20320,#20157)
expr_containers(#20320,#20306)
literals("B","B",#20320)
bind(#20320,#20234)
bind(#20320,#20223)
#20321=*
stmts(#20321,1,#20306,-2,"{}")
#20322=@"loc,{#10000},11,22,11,23"
@@ -1037,7 +1038,7 @@ exprs(#20336,79,#20335,0,"A")
hasLocation(#20336,#20173)
expr_containers(#20336,#20326)
literals("A","A",#20336)
bind(#20336,#20228)
bind(#20336,#20222)
#20337=*
exprs(#20337,104,#20326,-12,"@B")
#20338=@"loc,{#10000},13,12,13,13"
@@ -1053,7 +1054,7 @@ exprs(#20340,79,#20339,0,"B")
hasLocation(#20340,#20181)
expr_containers(#20340,#20326)
literals("B","B",#20340)
bind(#20340,#20234)
bind(#20340,#20223)
#20341=*
stmts(#20341,1,#20326,-2,"{}")
#20342=@"loc,{#10000},13,18,13,19"
@@ -1115,7 +1116,7 @@ exprs(#20356,79,#20355,0,"A")
hasLocation(#20356,#20197)
expr_containers(#20356,#20346)
literals("A","A",#20356)
bind(#20356,#20228)
bind(#20356,#20222)
#20357=*
exprs(#20357,104,#20346,-12,"@B @C")
#20358=@"loc,{#10000},14,12,14,16"
@@ -1133,7 +1134,7 @@ exprs(#20361,79,#20359,0,"B")
hasLocation(#20361,#20205)
expr_containers(#20361,#20346)
literals("B","B",#20361)
bind(#20361,#20234)
bind(#20361,#20223)
#20362=*
exprs(#20362,94,#20357,1,"@C")
#20363=@"loc,{#10000},14,15,14,16"
@@ -1145,7 +1146,7 @@ exprs(#20364,79,#20362,0,"C")
hasLocation(#20364,#20209)
expr_containers(#20364,#20346)
literals("C","C",#20364)
bind(#20364,#20222)
bind(#20364,#20224)
#20365=*
stmts(#20365,1,#20346,-2,"{}")
#20366=@"loc,{#10000},14,22,14,23"
@@ -1349,8 +1350,8 @@ successor(#20265,#20263)
successor(#20263,#20281)
successor(#20241,#20266)
successor(#20236,#20243)
successor(#20230,#20236)
successor(#20224,#20230)
successor(#20374,#20224)
successor(#20231,#20236)
successor(#20226,#20231)
successor(#20374,#20226)
numlines(#10000,15,12,0)
filetype(#10000,"typescript")

View File

@@ -694,506 +694,509 @@ toplevels(#20001,0)
#20252=@"loc,{#10000},2,1,30,0"
locations_default(#20252,#10000,2,1,30,0)
hasLocation(#20001,#20252)
#20253=@"var;{C};{#20000}"
variables(#20253,"C",#20000)
#20254=@"local_type_name;{C};{#20000}"
local_type_names(#20254,"C",#20000)
#20255=*
stmts(#20255,17,#20001,0,"declare ... on f();")
hasLocation(#20255,#20020)
stmt_containers(#20255,#20001)
has_declare_keyword(#20255)
#20256=*
exprs(#20256,78,#20255,-1,"f")
hasLocation(#20256,#20079)
expr_containers(#20256,#20255)
literals("f","f",#20256)
#20257=@"var;{f};{#20000}"
variables(#20257,"f",#20000)
decl(#20256,#20257)
#20253=@"var;{f};{#20000}"
variables(#20253,"f",#20000)
#20254=@"var;{C};{#20000}"
variables(#20254,"C",#20000)
#20255=@"var;{D};{#20000}"
variables(#20255,"D",#20000)
#20256=@"local_type_name;{C};{#20000}"
local_type_names(#20256,"C",#20000)
#20257=@"local_type_name;{D};{#20000}"
local_type_names(#20257,"D",#20000)
#20258=*
scopes(#20258,1)
scopenodes(#20255,#20258)
scopenesting(#20258,#20000)
#20259=@"var;{arguments};{#20258}"
variables(#20259,"arguments",#20258)
is_arguments_object(#20259)
stmts(#20258,17,#20001,0,"declare ... on f();")
hasLocation(#20258,#20020)
stmt_containers(#20258,#20001)
has_declare_keyword(#20258)
#20259=*
exprs(#20259,78,#20258,-1,"f")
hasLocation(#20259,#20079)
expr_containers(#20259,#20258)
literals("f","f",#20259)
decl(#20259,#20253)
#20260=*
stmts(#20260,26,#20001,1,"abstrac ... mber;\n}")
#20261=@"loc,{#10000},4,1,15,1"
locations_default(#20261,#10000,4,1,15,1)
hasLocation(#20260,#20261)
stmt_containers(#20260,#20001)
is_abstract_class(#20260)
scopes(#20260,1)
scopenodes(#20258,#20260)
scopenesting(#20260,#20000)
#20261=@"var;{arguments};{#20260}"
variables(#20261,"arguments",#20260)
is_arguments_object(#20261)
#20262=*
exprs(#20262,78,#20260,0,"C")
hasLocation(#20262,#20091)
enclosing_stmt(#20262,#20260)
expr_containers(#20262,#20001)
literals("C","C",#20262)
decl(#20262,#20253)
typedecl(#20262,#20254)
#20263=*
scopes(#20263,10)
scopenodes(#20260,#20263)
scopenesting(#20263,#20000)
stmts(#20262,26,#20001,1,"abstrac ... mber;\n}")
#20263=@"loc,{#10000},4,1,15,1"
locations_default(#20263,#10000,4,1,15,1)
hasLocation(#20262,#20263)
stmt_containers(#20262,#20001)
is_abstract_class(#20262)
#20264=*
properties(#20264,#20260,2,0,"abstract h();")
#20265=@"loc,{#10000},6,3,6,15"
locations_default(#20265,#10000,6,3,6,15)
hasLocation(#20264,#20265)
exprs(#20264,78,#20262,0,"C")
hasLocation(#20264,#20091)
enclosing_stmt(#20264,#20262)
expr_containers(#20264,#20001)
literals("C","C",#20264)
decl(#20264,#20254)
typedecl(#20264,#20256)
#20265=*
scopes(#20265,10)
scopenodes(#20262,#20265)
scopenesting(#20265,#20000)
#20266=*
exprs(#20266,0,#20264,0,"h")
hasLocation(#20266,#20097)
enclosing_stmt(#20266,#20260)
expr_containers(#20266,#20001)
literals("h","h",#20266)
#20267=*
exprs(#20267,9,#20264,1,"abstract h();")
hasLocation(#20267,#20265)
enclosing_stmt(#20267,#20260)
expr_containers(#20267,#20001)
properties(#20266,#20262,2,0,"abstract h();")
#20267=@"loc,{#10000},6,3,6,15"
locations_default(#20267,#10000,6,3,6,15)
hasLocation(#20266,#20267)
#20268=*
scopes(#20268,1)
scopenodes(#20267,#20268)
scopenesting(#20268,#20263)
#20269=@"var;{arguments};{#20268}"
variables(#20269,"arguments",#20268)
is_arguments_object(#20269)
is_method(#20264)
is_abstract_member(#20264)
exprs(#20268,0,#20266,0,"h")
hasLocation(#20268,#20097)
enclosing_stmt(#20268,#20262)
expr_containers(#20268,#20001)
literals("h","h",#20268)
#20269=*
exprs(#20269,9,#20266,1,"abstract h();")
hasLocation(#20269,#20267)
enclosing_stmt(#20269,#20262)
expr_containers(#20269,#20001)
#20270=*
properties(#20270,#20260,3,0,"g(x: nu ... number;")
#20271=@"loc,{#10000},9,3,9,23"
locations_default(#20271,#10000,9,3,9,23)
hasLocation(#20270,#20271)
scopes(#20270,1)
scopenodes(#20269,#20270)
scopenesting(#20270,#20265)
#20271=@"var;{arguments};{#20270}"
variables(#20271,"arguments",#20270)
is_arguments_object(#20271)
is_method(#20266)
is_abstract_member(#20266)
#20272=*
exprs(#20272,0,#20270,0,"g")
hasLocation(#20272,#20105)
enclosing_stmt(#20272,#20260)
expr_containers(#20272,#20001)
literals("g","g",#20272)
#20273=*
exprs(#20273,9,#20270,1,"g(x: nu ... number;")
hasLocation(#20273,#20271)
enclosing_stmt(#20273,#20260)
expr_containers(#20273,#20001)
properties(#20272,#20262,3,0,"g(x: nu ... number;")
#20273=@"loc,{#10000},9,3,9,23"
locations_default(#20273,#10000,9,3,9,23)
hasLocation(#20272,#20273)
#20274=*
scopes(#20274,1)
scopenodes(#20273,#20274)
scopenesting(#20274,#20263)
#20275=@"var;{x};{#20274}"
variables(#20275,"x",#20274)
exprs(#20274,0,#20272,0,"g")
hasLocation(#20274,#20105)
enclosing_stmt(#20274,#20262)
expr_containers(#20274,#20001)
literals("g","g",#20274)
#20275=*
exprs(#20275,9,#20272,1,"g(x: nu ... number;")
hasLocation(#20275,#20273)
enclosing_stmt(#20275,#20262)
expr_containers(#20275,#20001)
#20276=*
exprs(#20276,78,#20273,0,"x")
hasLocation(#20276,#20109)
expr_containers(#20276,#20273)
literals("x","x",#20276)
decl(#20276,#20275)
#20277=@"var;{arguments};{#20274}"
variables(#20277,"arguments",#20274)
is_arguments_object(#20277)
scopes(#20276,1)
scopenodes(#20275,#20276)
scopenesting(#20276,#20265)
#20277=@"var;{x};{#20276}"
variables(#20277,"x",#20276)
#20278=*
typeexprs(#20278,2,#20273,-3,"number")
hasLocation(#20278,#20119)
expr_containers(#20278,#20273)
literals("number","number",#20278)
#20279=*
typeexprs(#20279,2,#20273,-6,"number")
hasLocation(#20279,#20113)
expr_containers(#20279,#20273)
literals("number","number",#20279)
is_method(#20270)
exprs(#20278,78,#20275,0,"x")
hasLocation(#20278,#20109)
expr_containers(#20278,#20275)
literals("x","x",#20278)
decl(#20278,#20277)
#20279=@"var;{arguments};{#20276}"
variables(#20279,"arguments",#20276)
is_arguments_object(#20279)
#20280=*
properties(#20280,#20260,4,0,"g(x: st ... string;")
#20281=@"loc,{#10000},10,3,10,23"
locations_default(#20281,#10000,10,3,10,23)
hasLocation(#20280,#20281)
typeexprs(#20280,2,#20275,-3,"number")
hasLocation(#20280,#20119)
expr_containers(#20280,#20275)
literals("number","number",#20280)
#20281=*
typeexprs(#20281,2,#20275,-6,"number")
hasLocation(#20281,#20113)
expr_containers(#20281,#20275)
literals("number","number",#20281)
is_method(#20272)
#20282=*
exprs(#20282,0,#20280,0,"g")
hasLocation(#20282,#20123)
enclosing_stmt(#20282,#20260)
expr_containers(#20282,#20001)
literals("g","g",#20282)
#20283=*
exprs(#20283,9,#20280,1,"g(x: st ... string;")
hasLocation(#20283,#20281)
enclosing_stmt(#20283,#20260)
expr_containers(#20283,#20001)
properties(#20282,#20262,4,0,"g(x: st ... string;")
#20283=@"loc,{#10000},10,3,10,23"
locations_default(#20283,#10000,10,3,10,23)
hasLocation(#20282,#20283)
#20284=*
scopes(#20284,1)
scopenodes(#20283,#20284)
scopenesting(#20284,#20263)
#20285=@"var;{x};{#20284}"
variables(#20285,"x",#20284)
exprs(#20284,0,#20282,0,"g")
hasLocation(#20284,#20123)
enclosing_stmt(#20284,#20262)
expr_containers(#20284,#20001)
literals("g","g",#20284)
#20285=*
exprs(#20285,9,#20282,1,"g(x: st ... string;")
hasLocation(#20285,#20283)
enclosing_stmt(#20285,#20262)
expr_containers(#20285,#20001)
#20286=*
exprs(#20286,78,#20283,0,"x")
hasLocation(#20286,#20127)
expr_containers(#20286,#20283)
literals("x","x",#20286)
decl(#20286,#20285)
#20287=@"var;{arguments};{#20284}"
variables(#20287,"arguments",#20284)
is_arguments_object(#20287)
scopes(#20286,1)
scopenodes(#20285,#20286)
scopenesting(#20286,#20265)
#20287=@"var;{x};{#20286}"
variables(#20287,"x",#20286)
#20288=*
typeexprs(#20288,2,#20283,-3,"string")
hasLocation(#20288,#20137)
expr_containers(#20288,#20283)
literals("string","string",#20288)
#20289=*
typeexprs(#20289,2,#20283,-6,"string")
hasLocation(#20289,#20131)
expr_containers(#20289,#20283)
literals("string","string",#20289)
is_method(#20280)
exprs(#20288,78,#20285,0,"x")
hasLocation(#20288,#20127)
expr_containers(#20288,#20285)
literals("x","x",#20288)
decl(#20288,#20287)
#20289=@"var;{arguments};{#20286}"
variables(#20289,"arguments",#20286)
is_arguments_object(#20289)
#20290=*
properties(#20290,#20260,5,0,"g(x: any) {}")
#20291=@"loc,{#10000},11,3,11,14"
locations_default(#20291,#10000,11,3,11,14)
hasLocation(#20290,#20291)
typeexprs(#20290,2,#20285,-3,"string")
hasLocation(#20290,#20137)
expr_containers(#20290,#20285)
literals("string","string",#20290)
#20291=*
typeexprs(#20291,2,#20285,-6,"string")
hasLocation(#20291,#20131)
expr_containers(#20291,#20285)
literals("string","string",#20291)
is_method(#20282)
#20292=*
exprs(#20292,0,#20290,0,"g")
hasLocation(#20292,#20141)
enclosing_stmt(#20292,#20260)
expr_containers(#20292,#20001)
literals("g","g",#20292)
#20293=*
exprs(#20293,9,#20290,1,"g(x: any) {}")
hasLocation(#20293,#20291)
enclosing_stmt(#20293,#20260)
expr_containers(#20293,#20001)
properties(#20292,#20262,5,0,"g(x: any) {}")
#20293=@"loc,{#10000},11,3,11,14"
locations_default(#20293,#10000,11,3,11,14)
hasLocation(#20292,#20293)
#20294=*
scopes(#20294,1)
scopenodes(#20293,#20294)
scopenesting(#20294,#20263)
#20295=@"var;{x};{#20294}"
variables(#20295,"x",#20294)
exprs(#20294,0,#20292,0,"g")
hasLocation(#20294,#20141)
enclosing_stmt(#20294,#20262)
expr_containers(#20294,#20001)
literals("g","g",#20294)
#20295=*
exprs(#20295,9,#20292,1,"g(x: any) {}")
hasLocation(#20295,#20293)
enclosing_stmt(#20295,#20262)
expr_containers(#20295,#20001)
#20296=*
exprs(#20296,78,#20293,0,"x")
hasLocation(#20296,#20145)
expr_containers(#20296,#20293)
literals("x","x",#20296)
decl(#20296,#20295)
#20297=@"var;{arguments};{#20294}"
variables(#20297,"arguments",#20294)
is_arguments_object(#20297)
scopes(#20296,1)
scopenodes(#20295,#20296)
scopenesting(#20296,#20265)
#20297=@"var;{x};{#20296}"
variables(#20297,"x",#20296)
#20298=*
typeexprs(#20298,2,#20293,-6,"any")
hasLocation(#20298,#20149)
expr_containers(#20298,#20293)
literals("any","any",#20298)
#20299=*
stmts(#20299,1,#20293,-2,"{}")
#20300=@"loc,{#10000},11,13,11,14"
locations_default(#20300,#10000,11,13,11,14)
hasLocation(#20299,#20300)
stmt_containers(#20299,#20293)
is_method(#20290)
exprs(#20298,78,#20295,0,"x")
hasLocation(#20298,#20145)
expr_containers(#20298,#20295)
literals("x","x",#20298)
decl(#20298,#20297)
#20299=@"var;{arguments};{#20296}"
variables(#20299,"arguments",#20296)
is_arguments_object(#20299)
#20300=*
typeexprs(#20300,2,#20295,-6,"any")
hasLocation(#20300,#20149)
expr_containers(#20300,#20295)
literals("any","any",#20300)
#20301=*
properties(#20301,#20260,6,8,"abstract x: number;")
#20302=@"loc,{#10000},14,3,14,21"
locations_default(#20302,#10000,14,3,14,21)
stmts(#20301,1,#20295,-2,"{}")
#20302=@"loc,{#10000},11,13,11,14"
locations_default(#20302,#10000,11,13,11,14)
hasLocation(#20301,#20302)
stmt_containers(#20301,#20295)
is_method(#20292)
#20303=*
#20304=*
exprs(#20304,0,#20301,0,"x")
hasLocation(#20304,#20159)
expr_containers(#20304,#20303)
literals("x","x",#20304)
is_abstract_member(#20301)
properties(#20303,#20262,6,8,"abstract x: number;")
#20304=@"loc,{#10000},14,3,14,21"
locations_default(#20304,#10000,14,3,14,21)
hasLocation(#20303,#20304)
#20305=*
typeexprs(#20305,2,#20301,2,"number")
hasLocation(#20305,#20163)
enclosing_stmt(#20305,#20260)
expr_containers(#20305,#20001)
literals("number","number",#20305)
#20306=*
properties(#20306,#20260,7,0,"constructor() {}")
#20307=@"loc,{#10000},4,18,4,17"
locations_default(#20307,#10000,4,18,4,17)
hasLocation(#20306,#20307)
exprs(#20306,0,#20303,0,"x")
hasLocation(#20306,#20159)
expr_containers(#20306,#20305)
literals("x","x",#20306)
is_abstract_member(#20303)
#20307=*
typeexprs(#20307,2,#20303,2,"number")
hasLocation(#20307,#20163)
enclosing_stmt(#20307,#20262)
expr_containers(#20307,#20001)
literals("number","number",#20307)
#20308=*
exprs(#20308,0,#20306,0,"constructor")
hasLocation(#20308,#20307)
enclosing_stmt(#20308,#20260)
expr_containers(#20308,#20001)
literals("constructor","constructor",#20308)
exprs(#20303,9,#20306,1,"() {}")
hasLocation(#20303,#20307)
enclosing_stmt(#20303,#20260)
expr_containers(#20303,#20001)
#20309=*
scopes(#20309,1)
scopenodes(#20303,#20309)
scopenesting(#20309,#20263)
#20310=@"var;{arguments};{#20309}"
variables(#20310,"arguments",#20309)
is_arguments_object(#20310)
properties(#20308,#20262,7,0,"constructor() {}")
#20309=@"loc,{#10000},4,18,4,17"
locations_default(#20309,#10000,4,18,4,17)
hasLocation(#20308,#20309)
#20310=*
exprs(#20310,0,#20308,0,"constructor")
hasLocation(#20310,#20309)
enclosing_stmt(#20310,#20262)
expr_containers(#20310,#20001)
literals("constructor","constructor",#20310)
exprs(#20305,9,#20308,1,"() {}")
hasLocation(#20305,#20309)
enclosing_stmt(#20305,#20262)
expr_containers(#20305,#20001)
#20311=*
stmts(#20311,1,#20303,-2,"{}")
hasLocation(#20311,#20307)
stmt_containers(#20311,#20303)
is_method(#20306)
#20312=*
stmts(#20312,26,#20001,2,"declare ... mber;\n}")
#20313=@"loc,{#10000},18,1,29,1"
locations_default(#20313,#10000,18,1,29,1)
hasLocation(#20312,#20313)
stmt_containers(#20312,#20001)
has_declare_keyword(#20312)
is_abstract_class(#20312)
scopes(#20311,1)
scopenodes(#20305,#20311)
scopenesting(#20311,#20265)
#20312=@"var;{arguments};{#20311}"
variables(#20312,"arguments",#20311)
is_arguments_object(#20312)
#20313=*
stmts(#20313,1,#20305,-2,"{}")
hasLocation(#20313,#20309)
stmt_containers(#20313,#20305)
is_method(#20308)
#20314=*
exprs(#20314,78,#20312,0,"D")
hasLocation(#20314,#20174)
enclosing_stmt(#20314,#20312)
expr_containers(#20314,#20001)
literals("D","D",#20314)
#20315=@"var;{D};{#20000}"
variables(#20315,"D",#20000)
decl(#20314,#20315)
stmts(#20314,26,#20001,2,"declare ... mber;\n}")
#20315=@"loc,{#10000},18,1,29,1"
locations_default(#20315,#10000,18,1,29,1)
hasLocation(#20314,#20315)
stmt_containers(#20314,#20001)
has_declare_keyword(#20314)
is_abstract_class(#20314)
#20316=*
scopes(#20316,10)
scopenodes(#20312,#20316)
scopenesting(#20316,#20000)
exprs(#20316,78,#20314,0,"D")
hasLocation(#20316,#20174)
enclosing_stmt(#20316,#20314)
expr_containers(#20316,#20001)
literals("D","D",#20316)
decl(#20316,#20255)
typedecl(#20316,#20257)
#20317=*
properties(#20317,#20312,2,0,"abstract h();")
#20318=@"loc,{#10000},20,3,20,15"
locations_default(#20318,#10000,20,3,20,15)
hasLocation(#20317,#20318)
#20319=*
exprs(#20319,0,#20317,0,"h")
hasLocation(#20319,#20180)
enclosing_stmt(#20319,#20312)
expr_containers(#20319,#20001)
literals("h","h",#20319)
scopes(#20317,10)
scopenodes(#20314,#20317)
scopenesting(#20317,#20000)
#20318=*
properties(#20318,#20314,2,0,"abstract h();")
#20319=@"loc,{#10000},20,3,20,15"
locations_default(#20319,#10000,20,3,20,15)
hasLocation(#20318,#20319)
#20320=*
exprs(#20320,9,#20317,1,"abstract h();")
hasLocation(#20320,#20318)
enclosing_stmt(#20320,#20312)
exprs(#20320,0,#20318,0,"h")
hasLocation(#20320,#20180)
enclosing_stmt(#20320,#20314)
expr_containers(#20320,#20001)
literals("h","h",#20320)
#20321=*
scopes(#20321,1)
scopenodes(#20320,#20321)
scopenesting(#20321,#20316)
#20322=@"var;{arguments};{#20321}"
variables(#20322,"arguments",#20321)
is_arguments_object(#20322)
is_method(#20317)
is_abstract_member(#20317)
#20323=*
properties(#20323,#20312,3,0,"g(x: nu ... number;")
#20324=@"loc,{#10000},23,3,23,23"
locations_default(#20324,#10000,23,3,23,23)
hasLocation(#20323,#20324)
#20325=*
exprs(#20325,0,#20323,0,"g")
hasLocation(#20325,#20188)
enclosing_stmt(#20325,#20312)
expr_containers(#20325,#20001)
literals("g","g",#20325)
exprs(#20321,9,#20318,1,"abstract h();")
hasLocation(#20321,#20319)
enclosing_stmt(#20321,#20314)
expr_containers(#20321,#20001)
#20322=*
scopes(#20322,1)
scopenodes(#20321,#20322)
scopenesting(#20322,#20317)
#20323=@"var;{arguments};{#20322}"
variables(#20323,"arguments",#20322)
is_arguments_object(#20323)
is_method(#20318)
is_abstract_member(#20318)
#20324=*
properties(#20324,#20314,3,0,"g(x: nu ... number;")
#20325=@"loc,{#10000},23,3,23,23"
locations_default(#20325,#10000,23,3,23,23)
hasLocation(#20324,#20325)
#20326=*
exprs(#20326,9,#20323,1,"g(x: nu ... number;")
hasLocation(#20326,#20324)
enclosing_stmt(#20326,#20312)
exprs(#20326,0,#20324,0,"g")
hasLocation(#20326,#20188)
enclosing_stmt(#20326,#20314)
expr_containers(#20326,#20001)
literals("g","g",#20326)
#20327=*
scopes(#20327,1)
scopenodes(#20326,#20327)
scopenesting(#20327,#20316)
#20328=@"var;{x};{#20327}"
variables(#20328,"x",#20327)
#20329=*
exprs(#20329,78,#20326,0,"x")
hasLocation(#20329,#20192)
expr_containers(#20329,#20326)
literals("x","x",#20329)
decl(#20329,#20328)
#20330=@"var;{arguments};{#20327}"
variables(#20330,"arguments",#20327)
is_arguments_object(#20330)
#20331=*
typeexprs(#20331,2,#20326,-3,"number")
hasLocation(#20331,#20202)
expr_containers(#20331,#20326)
literals("number","number",#20331)
exprs(#20327,9,#20324,1,"g(x: nu ... number;")
hasLocation(#20327,#20325)
enclosing_stmt(#20327,#20314)
expr_containers(#20327,#20001)
#20328=*
scopes(#20328,1)
scopenodes(#20327,#20328)
scopenesting(#20328,#20317)
#20329=@"var;{x};{#20328}"
variables(#20329,"x",#20328)
#20330=*
exprs(#20330,78,#20327,0,"x")
hasLocation(#20330,#20192)
expr_containers(#20330,#20327)
literals("x","x",#20330)
decl(#20330,#20329)
#20331=@"var;{arguments};{#20328}"
variables(#20331,"arguments",#20328)
is_arguments_object(#20331)
#20332=*
typeexprs(#20332,2,#20326,-6,"number")
hasLocation(#20332,#20196)
expr_containers(#20332,#20326)
typeexprs(#20332,2,#20327,-3,"number")
hasLocation(#20332,#20202)
expr_containers(#20332,#20327)
literals("number","number",#20332)
is_method(#20323)
#20333=*
properties(#20333,#20312,4,0,"g(x: st ... string;")
#20334=@"loc,{#10000},24,3,24,23"
locations_default(#20334,#10000,24,3,24,23)
hasLocation(#20333,#20334)
#20335=*
exprs(#20335,0,#20333,0,"g")
hasLocation(#20335,#20206)
enclosing_stmt(#20335,#20312)
expr_containers(#20335,#20001)
literals("g","g",#20335)
typeexprs(#20333,2,#20327,-6,"number")
hasLocation(#20333,#20196)
expr_containers(#20333,#20327)
literals("number","number",#20333)
is_method(#20324)
#20334=*
properties(#20334,#20314,4,0,"g(x: st ... string;")
#20335=@"loc,{#10000},24,3,24,23"
locations_default(#20335,#10000,24,3,24,23)
hasLocation(#20334,#20335)
#20336=*
exprs(#20336,9,#20333,1,"g(x: st ... string;")
hasLocation(#20336,#20334)
enclosing_stmt(#20336,#20312)
exprs(#20336,0,#20334,0,"g")
hasLocation(#20336,#20206)
enclosing_stmt(#20336,#20314)
expr_containers(#20336,#20001)
literals("g","g",#20336)
#20337=*
scopes(#20337,1)
scopenodes(#20336,#20337)
scopenesting(#20337,#20316)
#20338=@"var;{x};{#20337}"
variables(#20338,"x",#20337)
#20339=*
exprs(#20339,78,#20336,0,"x")
hasLocation(#20339,#20210)
expr_containers(#20339,#20336)
literals("x","x",#20339)
decl(#20339,#20338)
#20340=@"var;{arguments};{#20337}"
variables(#20340,"arguments",#20337)
is_arguments_object(#20340)
#20341=*
typeexprs(#20341,2,#20336,-3,"string")
hasLocation(#20341,#20220)
expr_containers(#20341,#20336)
literals("string","string",#20341)
exprs(#20337,9,#20334,1,"g(x: st ... string;")
hasLocation(#20337,#20335)
enclosing_stmt(#20337,#20314)
expr_containers(#20337,#20001)
#20338=*
scopes(#20338,1)
scopenodes(#20337,#20338)
scopenesting(#20338,#20317)
#20339=@"var;{x};{#20338}"
variables(#20339,"x",#20338)
#20340=*
exprs(#20340,78,#20337,0,"x")
hasLocation(#20340,#20210)
expr_containers(#20340,#20337)
literals("x","x",#20340)
decl(#20340,#20339)
#20341=@"var;{arguments};{#20338}"
variables(#20341,"arguments",#20338)
is_arguments_object(#20341)
#20342=*
typeexprs(#20342,2,#20336,-6,"string")
hasLocation(#20342,#20214)
expr_containers(#20342,#20336)
typeexprs(#20342,2,#20337,-3,"string")
hasLocation(#20342,#20220)
expr_containers(#20342,#20337)
literals("string","string",#20342)
is_method(#20333)
#20343=*
properties(#20343,#20312,5,0,"g(x: any) {}")
#20344=@"loc,{#10000},25,3,25,14"
locations_default(#20344,#10000,25,3,25,14)
hasLocation(#20343,#20344)
#20345=*
exprs(#20345,0,#20343,0,"g")
hasLocation(#20345,#20224)
enclosing_stmt(#20345,#20312)
expr_containers(#20345,#20001)
literals("g","g",#20345)
typeexprs(#20343,2,#20337,-6,"string")
hasLocation(#20343,#20214)
expr_containers(#20343,#20337)
literals("string","string",#20343)
is_method(#20334)
#20344=*
properties(#20344,#20314,5,0,"g(x: any) {}")
#20345=@"loc,{#10000},25,3,25,14"
locations_default(#20345,#10000,25,3,25,14)
hasLocation(#20344,#20345)
#20346=*
exprs(#20346,9,#20343,1,"g(x: any) {}")
hasLocation(#20346,#20344)
enclosing_stmt(#20346,#20312)
exprs(#20346,0,#20344,0,"g")
hasLocation(#20346,#20224)
enclosing_stmt(#20346,#20314)
expr_containers(#20346,#20001)
literals("g","g",#20346)
#20347=*
scopes(#20347,1)
scopenodes(#20346,#20347)
scopenesting(#20347,#20316)
#20348=@"var;{x};{#20347}"
variables(#20348,"x",#20347)
#20349=*
exprs(#20349,78,#20346,0,"x")
hasLocation(#20349,#20228)
expr_containers(#20349,#20346)
literals("x","x",#20349)
decl(#20349,#20348)
#20350=@"var;{arguments};{#20347}"
variables(#20350,"arguments",#20347)
is_arguments_object(#20350)
#20351=*
typeexprs(#20351,2,#20346,-6,"any")
hasLocation(#20351,#20232)
expr_containers(#20351,#20346)
literals("any","any",#20351)
exprs(#20347,9,#20344,1,"g(x: any) {}")
hasLocation(#20347,#20345)
enclosing_stmt(#20347,#20314)
expr_containers(#20347,#20001)
#20348=*
scopes(#20348,1)
scopenodes(#20347,#20348)
scopenesting(#20348,#20317)
#20349=@"var;{x};{#20348}"
variables(#20349,"x",#20348)
#20350=*
exprs(#20350,78,#20347,0,"x")
hasLocation(#20350,#20228)
expr_containers(#20350,#20347)
literals("x","x",#20350)
decl(#20350,#20349)
#20351=@"var;{arguments};{#20348}"
variables(#20351,"arguments",#20348)
is_arguments_object(#20351)
#20352=*
stmts(#20352,1,#20346,-2,"{}")
#20353=@"loc,{#10000},25,13,25,14"
locations_default(#20353,#10000,25,13,25,14)
hasLocation(#20352,#20353)
stmt_containers(#20352,#20346)
is_method(#20343)
#20354=*
properties(#20354,#20312,6,8,"abstract x: number;")
#20355=@"loc,{#10000},28,3,28,21"
locations_default(#20355,#10000,28,3,28,21)
hasLocation(#20354,#20355)
#20356=*
typeexprs(#20352,2,#20347,-6,"any")
hasLocation(#20352,#20232)
expr_containers(#20352,#20347)
literals("any","any",#20352)
#20353=*
stmts(#20353,1,#20347,-2,"{}")
#20354=@"loc,{#10000},25,13,25,14"
locations_default(#20354,#10000,25,13,25,14)
hasLocation(#20353,#20354)
stmt_containers(#20353,#20347)
is_method(#20344)
#20355=*
properties(#20355,#20314,6,8,"abstract x: number;")
#20356=@"loc,{#10000},28,3,28,21"
locations_default(#20356,#10000,28,3,28,21)
hasLocation(#20355,#20356)
#20357=*
exprs(#20357,0,#20354,0,"x")
hasLocation(#20357,#20242)
expr_containers(#20357,#20356)
literals("x","x",#20357)
is_abstract_member(#20354)
#20358=*
typeexprs(#20358,2,#20354,2,"number")
hasLocation(#20358,#20246)
enclosing_stmt(#20358,#20312)
expr_containers(#20358,#20001)
literals("number","number",#20358)
exprs(#20358,0,#20355,0,"x")
hasLocation(#20358,#20242)
expr_containers(#20358,#20357)
literals("x","x",#20358)
is_abstract_member(#20355)
#20359=*
properties(#20359,#20312,7,0,"constructor() {}")
#20360=@"loc,{#10000},18,26,18,25"
locations_default(#20360,#10000,18,26,18,25)
hasLocation(#20359,#20360)
#20361=*
exprs(#20361,0,#20359,0,"constructor")
hasLocation(#20361,#20360)
enclosing_stmt(#20361,#20312)
expr_containers(#20361,#20001)
literals("constructor","constructor",#20361)
exprs(#20356,9,#20359,1,"() {}")
hasLocation(#20356,#20360)
enclosing_stmt(#20356,#20312)
expr_containers(#20356,#20001)
typeexprs(#20359,2,#20355,2,"number")
hasLocation(#20359,#20246)
enclosing_stmt(#20359,#20314)
expr_containers(#20359,#20001)
literals("number","number",#20359)
#20360=*
properties(#20360,#20314,7,0,"constructor() {}")
#20361=@"loc,{#10000},18,26,18,25"
locations_default(#20361,#10000,18,26,18,25)
hasLocation(#20360,#20361)
#20362=*
scopes(#20362,1)
scopenodes(#20356,#20362)
scopenesting(#20362,#20316)
#20363=@"var;{arguments};{#20362}"
variables(#20363,"arguments",#20362)
is_arguments_object(#20363)
#20364=*
stmts(#20364,1,#20356,-2,"{}")
hasLocation(#20364,#20360)
stmt_containers(#20364,#20356)
is_method(#20359)
exprs(#20362,0,#20360,0,"constructor")
hasLocation(#20362,#20361)
enclosing_stmt(#20362,#20314)
expr_containers(#20362,#20001)
literals("constructor","constructor",#20362)
exprs(#20357,9,#20360,1,"() {}")
hasLocation(#20357,#20361)
enclosing_stmt(#20357,#20314)
expr_containers(#20357,#20001)
#20363=*
scopes(#20363,1)
scopenodes(#20357,#20363)
scopenesting(#20363,#20317)
#20364=@"var;{arguments};{#20363}"
variables(#20364,"arguments",#20363)
is_arguments_object(#20364)
#20365=*
entry_cfg_node(#20365,#20001)
#20366=@"loc,{#10000},2,1,2,0"
locations_default(#20366,#10000,2,1,2,0)
hasLocation(#20365,#20366)
#20367=*
exit_cfg_node(#20367,#20001)
hasLocation(#20367,#20251)
successor(#20312,#20367)
successor(#20303,#20306)
stmts(#20365,1,#20357,-2,"{}")
hasLocation(#20365,#20361)
stmt_containers(#20365,#20357)
is_method(#20360)
#20366=*
entry_cfg_node(#20366,#20001)
#20367=@"loc,{#10000},2,1,2,0"
locations_default(#20367,#10000,2,1,2,0)
hasLocation(#20366,#20367)
#20368=*
entry_cfg_node(#20368,#20303)
hasLocation(#20368,#20307)
exit_cfg_node(#20368,#20001)
hasLocation(#20368,#20251)
successor(#20314,#20368)
successor(#20305,#20308)
#20369=*
exit_cfg_node(#20369,#20303)
hasLocation(#20369,#20307)
successor(#20311,#20369)
successor(#20368,#20311)
successor(#20308,#20303)
successor(#20306,#20260)
successor(#20293,#20290)
entry_cfg_node(#20369,#20305)
hasLocation(#20369,#20309)
#20370=*
entry_cfg_node(#20370,#20293)
#20371=@"loc,{#10000},11,3,11,2"
locations_default(#20371,#10000,11,3,11,2)
hasLocation(#20370,#20371)
#20372=*
exit_cfg_node(#20372,#20293)
#20373=@"loc,{#10000},11,15,11,14"
locations_default(#20373,#10000,11,15,11,14)
hasLocation(#20372,#20373)
successor(#20299,#20372)
successor(#20296,#20299)
successor(#20370,#20296)
successor(#20292,#20293)
successor(#20290,#20308)
successor(#20280,#20292)
successor(#20270,#20280)
successor(#20264,#20270)
successor(#20262,#20264)
successor(#20260,#20312)
successor(#20255,#20262)
successor(#20365,#20255)
exit_cfg_node(#20370,#20305)
hasLocation(#20370,#20309)
successor(#20313,#20370)
successor(#20369,#20313)
successor(#20310,#20305)
successor(#20308,#20262)
successor(#20295,#20292)
#20371=*
entry_cfg_node(#20371,#20295)
#20372=@"loc,{#10000},11,3,11,2"
locations_default(#20372,#10000,11,3,11,2)
hasLocation(#20371,#20372)
#20373=*
exit_cfg_node(#20373,#20295)
#20374=@"loc,{#10000},11,15,11,14"
locations_default(#20374,#10000,11,15,11,14)
hasLocation(#20373,#20374)
successor(#20301,#20373)
successor(#20298,#20301)
successor(#20371,#20298)
successor(#20294,#20295)
successor(#20292,#20310)
successor(#20282,#20294)
successor(#20272,#20282)
successor(#20266,#20272)
successor(#20264,#20266)
successor(#20262,#20314)
successor(#20258,#20264)
successor(#20366,#20258)
numlines(#10000,29,15,8)
filetype(#10000,"typescript")

View File

@@ -425,146 +425,146 @@ hasLocation(#20001,#20158)
variables(#20159,"declaration",#20000)
#20160=@"var;{f};{#20000}"
variables(#20160,"f",#20000)
#20161=@"var;{C};{#20000}"
variables(#20161,"C",#20000)
#20162=@"local_type_name;{C};{#20000}"
local_type_names(#20162,"C",#20000)
#20163=@"local_type_name;{I};{#20000}"
local_type_names(#20163,"I",#20000)
#20164=*
stmts(#20164,17,#20001,0,"functio ... ber) {}")
hasLocation(#20164,#20003)
stmt_containers(#20164,#20001)
#20161=@"var;{ambient};{#20000}"
variables(#20161,"ambient",#20000)
#20162=@"var;{C};{#20000}"
variables(#20162,"C",#20000)
#20163=@"local_type_name;{C};{#20000}"
local_type_names(#20163,"C",#20000)
#20164=@"local_type_name;{I};{#20000}"
local_type_names(#20164,"I",#20000)
#20165=*
exprs(#20165,78,#20164,-1,"declaration")
hasLocation(#20165,#20033)
expr_containers(#20165,#20164)
literals("declaration","declaration",#20165)
decl(#20165,#20159)
stmts(#20165,17,#20001,0,"functio ... ber) {}")
hasLocation(#20165,#20003)
stmt_containers(#20165,#20001)
#20166=*
scopes(#20166,1)
scopenodes(#20164,#20166)
scopenesting(#20166,#20000)
#20167=@"var;{x};{#20166}"
variables(#20167,"x",#20166)
#20168=*
exprs(#20168,78,#20164,0,"x")
hasLocation(#20168,#20045)
expr_containers(#20168,#20164)
literals("x","x",#20168)
decl(#20168,#20167)
#20169=@"var;{arguments};{#20166}"
variables(#20169,"arguments",#20166)
is_arguments_object(#20169)
#20170=*
typeexprs(#20170,2,#20164,-4,"void")
hasLocation(#20170,#20041)
expr_containers(#20170,#20164)
literals("void","void",#20170)
exprs(#20166,78,#20165,-1,"declaration")
hasLocation(#20166,#20033)
expr_containers(#20166,#20165)
literals("declaration","declaration",#20166)
decl(#20166,#20159)
#20167=*
scopes(#20167,1)
scopenodes(#20165,#20167)
scopenesting(#20167,#20000)
#20168=@"var;{x};{#20167}"
variables(#20168,"x",#20167)
#20169=*
exprs(#20169,78,#20165,0,"x")
hasLocation(#20169,#20045)
expr_containers(#20169,#20165)
literals("x","x",#20169)
decl(#20169,#20168)
#20170=@"var;{arguments};{#20167}"
variables(#20170,"arguments",#20167)
is_arguments_object(#20170)
#20171=*
typeexprs(#20171,2,#20164,-6,"number")
hasLocation(#20171,#20049)
expr_containers(#20171,#20164)
literals("number","number",#20171)
typeexprs(#20171,2,#20165,-4,"void")
hasLocation(#20171,#20041)
expr_containers(#20171,#20165)
literals("void","void",#20171)
#20172=*
stmts(#20172,1,#20164,-2,"{}")
#20173=@"loc,{#10000},1,45,1,46"
locations_default(#20173,#10000,1,45,1,46)
hasLocation(#20172,#20173)
stmt_containers(#20172,#20164)
#20174=*
stmts(#20174,18,#20001,1,"var f = ... ber) {}")
hasLocation(#20174,#20007)
stmt_containers(#20174,#20001)
typeexprs(#20172,2,#20165,-6,"number")
hasLocation(#20172,#20049)
expr_containers(#20172,#20165)
literals("number","number",#20172)
#20173=*
stmts(#20173,1,#20165,-2,"{}")
#20174=@"loc,{#10000},1,45,1,46"
locations_default(#20174,#10000,1,45,1,46)
hasLocation(#20173,#20174)
stmt_containers(#20173,#20165)
#20175=*
exprs(#20175,64,#20174,0,"f = fun ... ber) {}")
#20176=@"loc,{#10000},3,5,3,44"
locations_default(#20176,#10000,3,5,3,44)
hasLocation(#20175,#20176)
enclosing_stmt(#20175,#20174)
expr_containers(#20175,#20001)
#20177=*
exprs(#20177,78,#20175,0,"f")
hasLocation(#20177,#20059)
enclosing_stmt(#20177,#20174)
expr_containers(#20177,#20001)
literals("f","f",#20177)
decl(#20177,#20160)
stmts(#20175,18,#20001,1,"var f = ... ber) {}")
hasLocation(#20175,#20007)
stmt_containers(#20175,#20001)
#20176=*
exprs(#20176,64,#20175,0,"f = fun ... ber) {}")
#20177=@"loc,{#10000},3,5,3,44"
locations_default(#20177,#10000,3,5,3,44)
hasLocation(#20176,#20177)
enclosing_stmt(#20176,#20175)
expr_containers(#20176,#20001)
#20178=*
exprs(#20178,9,#20175,1,"functio ... ber) {}")
#20179=@"loc,{#10000},3,9,3,44"
locations_default(#20179,#10000,3,9,3,44)
hasLocation(#20178,#20179)
enclosing_stmt(#20178,#20174)
exprs(#20178,78,#20176,0,"f")
hasLocation(#20178,#20059)
enclosing_stmt(#20178,#20175)
expr_containers(#20178,#20001)
#20180=*
scopes(#20180,1)
scopenodes(#20178,#20180)
scopenesting(#20180,#20000)
#20181=@"var;{x};{#20180}"
variables(#20181,"x",#20180)
#20182=*
exprs(#20182,78,#20178,0,"x")
hasLocation(#20182,#20075)
expr_containers(#20182,#20178)
literals("x","x",#20182)
decl(#20182,#20181)
#20183=@"var;{arguments};{#20180}"
variables(#20183,"arguments",#20180)
is_arguments_object(#20183)
#20184=*
typeexprs(#20184,2,#20178,-4,"string")
hasLocation(#20184,#20071)
expr_containers(#20184,#20178)
literals("string","string",#20184)
literals("f","f",#20178)
decl(#20178,#20160)
#20179=*
exprs(#20179,9,#20176,1,"functio ... ber) {}")
#20180=@"loc,{#10000},3,9,3,44"
locations_default(#20180,#10000,3,9,3,44)
hasLocation(#20179,#20180)
enclosing_stmt(#20179,#20175)
expr_containers(#20179,#20001)
#20181=*
scopes(#20181,1)
scopenodes(#20179,#20181)
scopenesting(#20181,#20000)
#20182=@"var;{x};{#20181}"
variables(#20182,"x",#20181)
#20183=*
exprs(#20183,78,#20179,0,"x")
hasLocation(#20183,#20075)
expr_containers(#20183,#20179)
literals("x","x",#20183)
decl(#20183,#20182)
#20184=@"var;{arguments};{#20181}"
variables(#20184,"arguments",#20181)
is_arguments_object(#20184)
#20185=*
typeexprs(#20185,2,#20178,-6,"number")
hasLocation(#20185,#20079)
expr_containers(#20185,#20178)
literals("number","number",#20185)
typeexprs(#20185,2,#20179,-4,"string")
hasLocation(#20185,#20071)
expr_containers(#20185,#20179)
literals("string","string",#20185)
#20186=*
stmts(#20186,1,#20178,-2,"{}")
#20187=@"loc,{#10000},3,43,3,44"
locations_default(#20187,#10000,3,43,3,44)
hasLocation(#20186,#20187)
stmt_containers(#20186,#20178)
#20188=*
stmts(#20188,17,#20001,2,"declare ... umber);")
hasLocation(#20188,#20011)
stmt_containers(#20188,#20001)
has_declare_keyword(#20188)
typeexprs(#20186,2,#20179,-6,"number")
hasLocation(#20186,#20079)
expr_containers(#20186,#20179)
literals("number","number",#20186)
#20187=*
stmts(#20187,1,#20179,-2,"{}")
#20188=@"loc,{#10000},3,43,3,44"
locations_default(#20188,#10000,3,43,3,44)
hasLocation(#20187,#20188)
stmt_containers(#20187,#20179)
#20189=*
exprs(#20189,78,#20188,-1,"ambient")
hasLocation(#20189,#20091)
expr_containers(#20189,#20188)
literals("ambient","ambient",#20189)
#20190=@"var;{ambient};{#20000}"
variables(#20190,"ambient",#20000)
decl(#20189,#20190)
stmts(#20189,17,#20001,2,"declare ... umber);")
hasLocation(#20189,#20011)
stmt_containers(#20189,#20001)
has_declare_keyword(#20189)
#20190=*
exprs(#20190,78,#20189,-1,"ambient")
hasLocation(#20190,#20091)
expr_containers(#20190,#20189)
literals("ambient","ambient",#20190)
decl(#20190,#20161)
#20191=*
scopes(#20191,1)
scopenodes(#20188,#20191)
scopenodes(#20189,#20191)
scopenesting(#20191,#20000)
#20192=@"var;{x};{#20191}"
variables(#20192,"x",#20191)
#20193=*
exprs(#20193,78,#20188,0,"x")
exprs(#20193,78,#20189,0,"x")
hasLocation(#20193,#20103)
expr_containers(#20193,#20188)
expr_containers(#20193,#20189)
literals("x","x",#20193)
decl(#20193,#20192)
#20194=@"var;{arguments};{#20191}"
variables(#20194,"arguments",#20191)
is_arguments_object(#20194)
#20195=*
typeexprs(#20195,2,#20188,-4,"string")
typeexprs(#20195,2,#20189,-4,"string")
hasLocation(#20195,#20099)
expr_containers(#20195,#20188)
expr_containers(#20195,#20189)
literals("string","string",#20195)
#20196=*
typeexprs(#20196,2,#20188,-6,"number")
typeexprs(#20196,2,#20189,-6,"number")
hasLocation(#20196,#20107)
expr_containers(#20196,#20188)
expr_containers(#20196,#20189)
literals("number","number",#20196)
#20197=*
stmts(#20197,26,#20001,3,"class C ... C) {}\n}")
@@ -578,8 +578,8 @@ hasLocation(#20199,#20115)
enclosing_stmt(#20199,#20197)
expr_containers(#20199,#20001)
literals("C","C",#20199)
decl(#20199,#20161)
typedecl(#20199,#20162)
decl(#20199,#20162)
typedecl(#20199,#20163)
#20200=*
scopes(#20200,10)
scopenodes(#20197,#20200)
@@ -612,7 +612,7 @@ typeexprs(#20207,0,#20204,-4,"C")
hasLocation(#20207,#20127)
expr_containers(#20207,#20204)
literals("C","C",#20207)
typebind(#20207,#20162)
typebind(#20207,#20163)
#20208=*
stmts(#20208,1,#20204,-2,"{}")
#20209=@"loc,{#10000},8,19,8,20"
@@ -660,7 +660,7 @@ hasLocation(#20219,#20138)
enclosing_stmt(#20219,#20217)
expr_containers(#20219,#20001)
literals("I","I",#20219)
typedecl(#20219,#20163)
typedecl(#20219,#20164)
#20220=*
properties(#20220,#20217,2,0,"method(this: I);")
#20221=@"loc,{#10000},12,3,12,18"
@@ -689,7 +689,7 @@ typeexprs(#20226,0,#20223,-4,"I")
hasLocation(#20226,#20150)
expr_containers(#20226,#20223)
literals("I","I",#20226)
typebind(#20226,#20163)
typebind(#20226,#20164)
is_method(#20220)
is_abstract_member(#20220)
#20227=*
@@ -729,37 +729,37 @@ successor(#20203,#20204)
successor(#20201,#20212)
successor(#20199,#20203)
successor(#20197,#20217)
successor(#20188,#20199)
successor(#20174,#20177)
successor(#20178,#20175)
successor(#20189,#20199)
successor(#20175,#20178)
successor(#20179,#20176)
#20236=*
entry_cfg_node(#20236,#20178)
entry_cfg_node(#20236,#20179)
#20237=@"loc,{#10000},3,9,3,8"
locations_default(#20237,#10000,3,9,3,8)
hasLocation(#20236,#20237)
#20238=*
exit_cfg_node(#20238,#20178)
exit_cfg_node(#20238,#20179)
#20239=@"loc,{#10000},3,45,3,44"
locations_default(#20239,#10000,3,45,3,44)
hasLocation(#20238,#20239)
successor(#20186,#20238)
successor(#20182,#20186)
successor(#20236,#20182)
successor(#20177,#20178)
successor(#20175,#20188)
successor(#20164,#20174)
successor(#20187,#20238)
successor(#20183,#20187)
successor(#20236,#20183)
successor(#20178,#20179)
successor(#20176,#20189)
successor(#20165,#20175)
#20240=*
entry_cfg_node(#20240,#20164)
entry_cfg_node(#20240,#20165)
hasLocation(#20240,#20228)
#20241=*
exit_cfg_node(#20241,#20164)
exit_cfg_node(#20241,#20165)
#20242=@"loc,{#10000},1,47,1,46"
locations_default(#20242,#10000,1,47,1,46)
hasLocation(#20241,#20242)
successor(#20172,#20241)
successor(#20168,#20172)
successor(#20240,#20168)
successor(#20165,#20164)
successor(#20227,#20165)
successor(#20173,#20241)
successor(#20169,#20173)
successor(#20240,#20169)
successor(#20166,#20165)
successor(#20227,#20166)
numlines(#10000,14,9,0)
filetype(#10000,"typescript")

View File

@@ -147,4 +147,3 @@ ql/javascript/ql/src/meta/extraction-metrics/FileData.ql
ql/javascript/ql/src/meta/extraction-metrics/MissingMetrics.ql
ql/javascript/ql/src/meta/extraction-metrics/PhaseTimings.ql
ql/javascript/ql/src/meta/types/TypedExprs.ql
ql/javascript/ql/src/meta/types/TypesWithQualifiedName.ql

View File

@@ -153,17 +153,7 @@ private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, AstNode decl, string k
kind = "T"
}
/**
* Gets an element, of kind `kind`, that element `e` uses, if any.
*
* The `kind` is a string representing what kind of use it is:
* - `"M"` for function and method calls
* - `"T"` for uses of types
* - `"V"` for variable accesses
* - `"I"` for imports
*/
cached
AstNode definitionOf(Locatable e, string kind) {
private AstNode definitionOfRaw(Locatable e, string kind) {
variableDefLookup(e, result, kind)
or
// prefer definitions over declarations
@@ -179,3 +169,46 @@ AstNode definitionOf(Locatable e, string kind) {
or
jsdocTypeLookup(e, result, kind)
}
/** Gets a more useful node to show for something that resolves to `node`. */
private AstNode redirectOnce(AstNode node) {
exists(ConstructorDeclaration ctor |
ctor.isSynthetic() and
node = ctor.getBody() and
result = ctor.getDeclaringClass()
)
or
exists(ClassDefinition cls |
node = cls and
result = cls.getIdentifier()
)
or
exists(FunctionDeclStmt decl |
node = decl and
result = decl.getIdentifier()
)
or
exists(MethodDeclaration member |
not member instanceof ConstructorDeclaration and
node = member.getBody() and
result = member.getNameExpr()
)
}
private AstNode redirect(AstNode node) {
node = definitionOfRaw(_, _) and
result = redirectOnce*(node) and
not exists(redirectOnce(result))
}
/**
* Gets an element, of kind `kind`, that element `e` uses, if any.
*
* The `kind` is a string representing what kind of use it is:
* - `"M"` for function and method calls
* - `"T"` for uses of types
* - `"V"` for variable accesses
* - `"I"` for imports
*/
cached
AstNode definitionOf(Locatable e, string kind) { result = redirect(definitionOfRaw(e, kind)) }

View File

@@ -649,11 +649,13 @@ module API {
/** Gets a node corresponding to an import of module `m` without taking into account types from models. */
Node getAModuleImportRaw(string m) {
result = Impl::MkModuleImport(m) or
result = Impl::MkModuleImport(m).(Node).getMember("default")
result = Impl::MkModuleImport(m).(Node).getMember("default") or
result = Impl::MkTypeUse(m, "")
}
/** Gets a node whose type has the given qualified name, not including types from models. */
Node getANodeOfTypeRaw(string moduleName, string exportedName) {
exportedName != "" and
result = Impl::MkTypeUse(moduleName, exportedName).(Node).getInstance()
or
exportedName = "" and
@@ -749,18 +751,14 @@ module API {
MkModuleImport(string m) {
imports(_, m)
or
any(TypeAnnotation n).hasQualifiedName(m, _)
or
any(Type t).hasUnderlyingType(m, _)
any(TypeAnnotation n).hasUnderlyingType(m, _)
} or
MkClassInstance(DataFlow::ClassNode cls) { needsDefNode(cls) } or
MkDef(DataFlow::Node nd) { rhs(_, _, nd) } or
MkUse(DataFlow::Node nd) { use(_, _, nd) } or
/** A use of a TypeScript type. */
MkTypeUse(string moduleName, string exportName) {
any(TypeAnnotation n).hasQualifiedName(moduleName, exportName)
or
any(Type t).hasUnderlyingType(moduleName, exportName)
any(TypeAnnotation n).hasUnderlyingType(moduleName, exportName)
} or
MkSyntheticCallbackArg(DataFlow::Node src, int bound, DataFlow::InvokeNode nd) {
trackUseNode(src, true, bound, "").flowsTo(nd.getCalleeNode())

View File

@@ -5,17 +5,49 @@
import javascript
module Closure {
/** A call to `goog.require` */
class RequireCallExpr extends CallExpr {
RequireCallExpr() { this.getCallee().(PropAccess).getQualifiedName() = "goog.require" }
/** Gets the imported namespace name. */
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
}
/** A call to `goog.provide` */
class ProvideCallExpr extends CallExpr {
ProvideCallExpr() { this.getCallee().(PropAccess).getQualifiedName() = "goog.provide" }
/** Gets the imported namespace name. */
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
}
/** A call to `goog.module` or `goog.declareModuleId`. */
private class ModuleDeclarationCall extends CallExpr {
private string kind;
ModuleDeclarationCall() {
this.getCallee().(PropAccess).getQualifiedName() = kind and
kind = ["goog.module", "goog.declareModuleId"]
}
/** Gets the declared namespace. */
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
/** Gets the string `goog.module` or `goog.declareModuleId` depending on which method is being called. */
string getModuleKind() { result = kind }
}
/**
* A reference to a Closure namespace.
*/
class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
deprecated class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
/**
* Gets the namespace being referenced.
*/
string getClosureNamespace() { result = super.getClosureNamespace() }
}
module ClosureNamespaceRef {
deprecated module ClosureNamespaceRef {
/**
* A reference to a Closure namespace.
*
@@ -32,10 +64,10 @@ module Closure {
/**
* A data flow node that returns the value of a closure namespace.
*/
class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range {
}
deprecated class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range
{ }
module ClosureNamespaceAccess {
deprecated module ClosureNamespaceAccess {
/**
* A data flow node that returns the value of a closure namespace.
*
@@ -47,7 +79,7 @@ module Closure {
/**
* A call to a method on the `goog.` namespace, as a closure reference.
*/
abstract private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
abstract deprecated private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
ClosureNamespaceRef::Range
{
DefaultNamespaceRef() { this = DataFlow::globalVarRef("goog").getAMethodCall() }
@@ -59,14 +91,14 @@ module Closure {
* Holds if `node` is the data flow node corresponding to the expression in
* a top-level expression statement.
*/
private predicate isTopLevelExpr(DataFlow::Node node) {
deprecated private predicate isTopLevelExpr(DataFlow::Node node) {
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
}
/**
* A top-level call to `goog.provide`.
*/
private class DefaultClosureProvideCall extends DefaultNamespaceRef {
deprecated private class DefaultClosureProvideCall extends DefaultNamespaceRef {
DefaultClosureProvideCall() {
this.getMethodName() = "provide" and
isTopLevelExpr(this)
@@ -76,13 +108,14 @@ module Closure {
/**
* A top-level call to `goog.provide`.
*/
class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
deprecated class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
{ }
/**
* A call to `goog.require`.
*/
private class DefaultClosureRequireCall extends DefaultNamespaceRef, ClosureNamespaceAccess::Range
deprecated private class DefaultClosureRequireCall extends DefaultNamespaceRef,
ClosureNamespaceAccess::Range
{
DefaultClosureRequireCall() { this.getMethodName() = "require" }
}
@@ -90,13 +123,13 @@ module Closure {
/**
* A call to `goog.require`.
*/
class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
deprecated class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
{ }
/**
* A top-level call to `goog.module` or `goog.declareModuleId`.
*/
private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
deprecated private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
DefaultClosureModuleDeclaration() {
(this.getMethodName() = "module" or this.getMethodName() = "declareModuleId") and
isTopLevelExpr(this)
@@ -106,41 +139,29 @@ module Closure {
/**
* A top-level call to `goog.module` or `goog.declareModuleId`.
*/
class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
deprecated class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
{ }
private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) }
pragma[nomagic]
private MethodCallExpr googModuleDeclExpr() {
result.getReceiver() = googVariable().getAnAccess() and
result.getMethodName() = ["module", "declareModuleId"]
}
pragma[nomagic]
private MethodCallExpr googModuleDeclExprInContainer(StmtContainer container) {
result = googModuleDeclExpr() and
container = result.getContainer()
}
pragma[noinline]
private ClosureRequireCall getARequireInTopLevel(ClosureModule m) { result.getTopLevel() = m }
private RequireCallExpr getARequireInTopLevel(ClosureModule m) { result.getTopLevel() = m }
/**
* A module using the Closure module system, declared using `goog.module()` or `goog.declareModuleId()`.
*/
class ClosureModule extends Module {
ClosureModule() { exists(googModuleDeclExprInContainer(this)) }
private ModuleDeclarationCall decl;
ClosureModule() { decl.getTopLevel() = this }
/**
* Gets the call to `goog.module` or `goog.declareModuleId` in this module.
*/
ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
deprecated ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
/**
* Gets the namespace of this module.
*/
string getClosureNamespace() { result = this.getModuleDeclaration().getClosureNamespace() }
string getClosureNamespace() { result = decl.getClosureNamespace() }
override Module getAnImportedModule() {
result.(ClosureModule).getClosureNamespace() =
@@ -156,7 +177,7 @@ module Closure {
* Has no result for ES6 modules using `goog.declareModuleId`.
*/
Variable getExportsVariable() {
this.getModuleDeclaration().getMethodName() = "module" and
decl.getModuleKind() = "goog.module" and
result = this.getScope().getVariable("exports")
}
@@ -185,15 +206,15 @@ module Closure {
ClosureScript() {
not this instanceof ClosureModule and
(
any(ClosureProvideCall provide).getTopLevel() = this
any(ProvideCallExpr provide).getTopLevel() = this
or
any(ClosureRequireCall require).getTopLevel() = this
any(RequireCallExpr require).getTopLevel() = this
)
}
/** Gets the identifier of a namespace required by this module. */
string getARequiredNamespace() {
exists(ClosureRequireCall require |
exists(RequireCallExpr require |
require.getTopLevel() = this and
result = require.getClosureNamespace()
)
@@ -201,7 +222,7 @@ module Closure {
/** Gets the identifer of a namespace provided by this module. */
string getAProvidedNamespace() {
exists(ClosureProvideCall require |
exists(ProvideCallExpr require |
require.getTopLevel() = this and
result = require.getClosureNamespace()
)
@@ -213,7 +234,13 @@ module Closure {
*/
pragma[noinline]
predicate isClosureNamespace(string name) {
exists(string namespace | namespace = any(ClosureNamespaceRef ref).getClosureNamespace() |
exists(string namespace |
namespace =
[
any(RequireCallExpr ref).getClosureNamespace(),
any(ModuleDeclarationCall c).getClosureNamespace()
]
|
name = namespace.substring(0, namespace.indexOf("."))
or
name = namespace

View File

@@ -180,6 +180,9 @@ deprecated private class LiteralImportPath extends PathExpr, ConstantString {
* ```
*/
class ImportSpecifier extends Expr, @import_specifier {
/** Gets the import declaration in which this specifier appears. */
ImportDeclaration getImportDeclaration() { result.getASpecifier() = this }
/** Gets the imported symbol; undefined for default and namespace import specifiers. */
Identifier getImported() { result = this.getChildExpr(0) }

View File

@@ -4,6 +4,7 @@
import javascript
private import semmle.javascript.internal.CachedStages
private import semmle.javascript.internal.TypeResolution
/**
* A program element that is either an expression or a type annotation.
@@ -1017,7 +1018,11 @@ class InvokeExpr extends @invokeexpr, Expr {
* Note that the resolved function may be overridden in a subclass and thus is not
* necessarily the actual target of this invocation at runtime.
*/
Function getResolvedCallee() { result = this.getResolvedCalleeName().getImplementation() }
Function getResolvedCallee() {
TypeResolution::callTarget(this, result)
or
result = this.getResolvedCalleeName().getImplementation()
}
}
/**

View File

@@ -34,7 +34,7 @@ module AccessPath {
not this.accessesGlobal(_) and
not this instanceof DataFlow::PropRead and
not this instanceof PropertyProjection and
not this instanceof Closure::ClosureNamespaceAccess and
not this.asExpr() instanceof Closure::RequireCallExpr and
not this = DataFlow::parameterNode(any(ImmediatelyInvokedFunctionExpr iife).getAParameter()) and
not FlowSteps::identityFunctionStep(_, this)
}
@@ -139,8 +139,8 @@ module AccessPath {
result = join(fromReference(prop.getBase(), root), "[number]")
)
or
exists(Closure::ClosureNamespaceAccess acc | node = acc |
result = acc.getClosureNamespace() and
exists(Closure::RequireCallExpr req | node = req.flow() |
result = req.getClosureNamespace() and
root.isGlobal()
)
or

View File

@@ -33,6 +33,9 @@ class JSDoc extends @jsdoc, Locatable {
result.getTitle() = title
}
/** Gets the element to which this JSDoc comment is attached */
Documentable getDocumentedElement() { result.getDocumentation() = this }
override string toString() { result = this.getComment().toString() }
}
@@ -299,6 +302,41 @@ class JSDocIdentifierTypeExpr extends @jsdoc_identifier_type_expr, JSDocTypeExpr
override predicate isRawFunction() { this.getName() = "Function" }
}
private AstNode getAncestorInScope(Documentable doc) {
any(JSDocLocalTypeAccess t).getJSDocComment() = doc.getDocumentation() and // restrict to cases where we need this
result = doc.getParent()
or
exists(AstNode mid |
mid = getAncestorInScope(doc) and
not mid = any(Scope s).getScopeElement() and
result = mid.getParent()
)
}
private Scope getScope(Documentable doc) { result.getScopeElement() = getAncestorInScope(doc) }
pragma[nomagic]
private predicate shouldResolveName(TopLevel top, string name) {
exists(JSDocLocalTypeAccess access |
access.getName() = name and
access.getTopLevel() = top
)
}
private LexicalName getOwnLocal(Scope scope, string name, DeclarationSpace space) {
scope = result.getScope() and
name = result.getName() and
space = result.getDeclarationSpace() and
shouldResolveName(scope.getScopeElement().getTopLevel(), name) // restrict size of predicate
}
private LexicalName resolveLocal(Scope scope, string name, DeclarationSpace space) {
result = getOwnLocal(scope, name, space)
or
result = resolveLocal(scope.getOuterScope(), name, space) and
not exists(getOwnLocal(scope, name, space))
}
/**
* An unqualified identifier in a JSDoc type expression.
*
@@ -311,6 +349,12 @@ class JSDocIdentifierTypeExpr extends @jsdoc_identifier_type_expr, JSDocTypeExpr
*/
class JSDocLocalTypeAccess extends JSDocIdentifierTypeExpr {
JSDocLocalTypeAccess() { not this = any(JSDocQualifiedTypeAccess a).getNameNode() }
/** Gets a variable, type-name, or namespace that this expression may resolve to. */
LexicalName getALexicalName() {
result =
resolveLocal(getScope(this.getJSDocComment().getDocumentedElement()), this.getName(), _)
}
}
/**
@@ -371,7 +415,7 @@ class JSDocNamedTypeExpr extends JSDocTypeExpr {
* - `foo.bar.Baz` has prefix `foo` and suffix `.bar.Baz`.
* - `Baz` has prefix `Baz` and an empty suffix.
*/
predicate hasNameParts(string prefix, string suffix) {
deprecated predicate hasNameParts(string prefix, string suffix) {
not this = any(JSDocQualifiedTypeAccess a).getBase() and // restrict size of predicate
exists(string regex, string name | regex = "([^.]+)(.*)" |
name = this.getRawName() and
@@ -379,46 +423,6 @@ class JSDocNamedTypeExpr extends JSDocTypeExpr {
suffix = name.regexpCapture(regex, 2)
)
}
pragma[noinline]
pragma[nomagic]
private predicate hasNamePartsAndEnv(string prefix, string suffix, JSDoc::Environment env) {
// Force join ordering
this.hasNameParts(prefix, suffix) and
env.isContainerInScope(this.getContainer())
}
/**
* Gets the qualified name of this name by resolving its prefix, if any.
*/
cached
private string resolvedName() {
exists(string prefix, string suffix, JSDoc::Environment env |
this.hasNamePartsAndEnv(prefix, suffix, env) and
result = env.resolveAlias(prefix) + suffix
)
}
override predicate hasQualifiedName(string globalName) {
globalName = this.resolvedName()
or
not exists(this.resolvedName()) and
globalName = this.getRawName()
}
override DataFlow::ClassNode getClass() {
exists(string name |
this.hasQualifiedName(name) and
result.hasQualifiedName(name)
)
or
// Handle case where a local variable has a reference to the class,
// but the class doesn't have a globally qualified name.
exists(string alias, JSDoc::Environment env |
this.hasNamePartsAndEnv(alias, "", env) and
result.getAClassReference().flowsTo(env.getNodeFromAlias(alias))
)
}
}
/**
@@ -447,12 +451,6 @@ class JSDocAppliedTypeExpr extends @jsdoc_applied_type_expr, JSDocTypeExpr {
* For example, in `Array<string>`, `string` is the only argument type.
*/
JSDocTypeExpr getAnArgument() { result = this.getArgument(_) }
override predicate hasQualifiedName(string globalName) {
this.getHead().hasQualifiedName(globalName)
}
override DataFlow::ClassNode getClass() { result = this.getHead().getClass() }
}
/**
@@ -472,8 +470,6 @@ class JSDocNullableTypeExpr extends @jsdoc_nullable_type_expr, JSDocTypeExpr {
predicate isPrefix() { jsdoc_prefix_qualifier(this) }
override JSDocTypeExpr getAnUnderlyingType() { result = this.getTypeExpr().getAnUnderlyingType() }
override DataFlow::ClassNode getClass() { result = this.getTypeExpr().getClass() }
}
/**
@@ -493,8 +489,6 @@ class JSDocNonNullableTypeExpr extends @jsdoc_non_nullable_type_expr, JSDocTypeE
predicate isPrefix() { jsdoc_prefix_qualifier(this) }
override JSDocTypeExpr getAnUnderlyingType() { result = this.getTypeExpr().getAnUnderlyingType() }
override DataFlow::ClassNode getClass() { result = this.getTypeExpr().getClass() }
}
/**
@@ -599,8 +593,6 @@ class JSDocOptionalParameterTypeExpr extends @jsdoc_optional_type_expr, JSDocTyp
override JSDocTypeExpr getAnUnderlyingType() {
result = this.getUnderlyingType().getAnUnderlyingType()
}
override DataFlow::ClassNode getClass() { result = this.getUnderlyingType().getClass() }
}
/**
@@ -635,7 +627,7 @@ module JSDoc {
/**
* A statement container which may declare JSDoc name aliases.
*/
class Environment extends StmtContainer {
deprecated class Environment extends StmtContainer {
/**
* Gets the fully qualified name aliased by the given unqualified name
* within this container.
@@ -685,7 +677,7 @@ module JSDoc {
}
pragma[noinline]
private predicate isTypenamePrefix(string name) {
deprecated private predicate isTypenamePrefix(string name) {
any(JSDocNamedTypeExpr expr).hasNameParts(name, _)
}
}

View File

@@ -4,6 +4,8 @@
import javascript
private import internal.StmtContainers
private import internal.NameResolution
private import internal.UnderlyingTypes
/**
* A type annotation, either in the form of a TypeScript type or a JSDoc comment.
@@ -75,14 +77,38 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
TypeAnnotation getAnUnderlyingType() { result = this }
/**
* DEPRECATED. Use `hasUnderlyingType` instead.
*
* Holds if this is a reference to the type with qualified name `globalName` relative to the global scope.
*/
predicate hasQualifiedName(string globalName) { none() }
deprecated predicate hasQualifiedName(string globalName) {
UnderlyingTypes::nodeHasUnderlyingType(this, globalName)
}
/**
* DEPRECATED. Use `hasUnderlyingType` instead.
*
* Holds if this is a reference to the type exported from `moduleName` under the name `exportedName`.
*/
predicate hasQualifiedName(string moduleName, string exportedName) { none() }
deprecated predicate hasQualifiedName(string moduleName, string exportedName) {
UnderlyingTypes::nodeHasUnderlyingType(this, moduleName, exportedName)
}
/**
* Holds if this is a reference to the type with qualified name `globalName` relative to the global scope,
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
*/
final predicate hasUnderlyingType(string globalName) {
UnderlyingTypes::nodeHasUnderlyingType(this, globalName)
}
/**
* Holds if this is a reference to the type exported from `moduleName` under the name `exportedName`,
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
*/
final predicate hasUnderlyingType(string moduleName, string exportedName) {
UnderlyingTypes::nodeHasUnderlyingType(this, moduleName, exportedName)
}
/** Gets the statement in which this type appears. */
Stmt getEnclosingStmt() { none() }
@@ -107,5 +133,5 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
*
* This unfolds nullability modifiers and generic type applications.
*/
DataFlow::ClassNode getClass() { none() }
final DataFlow::ClassNode getClass() { UnderlyingTypes::nodeHasUnderlyingClassType(this, result) }
}

View File

@@ -1,4 +1,5 @@
import javascript
private import semmle.javascript.internal.UnderlyingTypes
/**
* A statement that defines a namespace, that is, a namespace declaration or enum declaration.
@@ -575,10 +576,6 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
override Function getEnclosingFunction() { result = ExprOrType.super.getEnclosingFunction() }
override TopLevel getTopLevel() { result = ExprOrType.super.getTopLevel() }
override DataFlow::ClassNode getClass() {
result.getAstNode() = this.getType().(ClassType).getClass()
}
}
/**
@@ -698,58 +695,9 @@ class TypeAccess extends @typeaccess, TypeExpr, TypeRef {
*/
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 `imprt`.
*
* 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.getImportedPathString() |
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" }
@@ -822,14 +770,6 @@ class GenericTypeExpr extends @generic_typeexpr, TypeExpr {
/** 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" }
}

View File

@@ -27,6 +27,12 @@ class Scope extends @scope {
result = this.getAVariable() and
result.getName() = name
}
/** Gets the local type name with the given name declared in this scope. */
LocalTypeName getLocalTypeName(string name) {
result.getScope() = this and
result.getName() = name
}
}
/**
@@ -128,8 +134,26 @@ class Variable extends @variable, LexicalName {
/** Gets the scope this variable is declared in. */
override Scope getScope() { variables(this, _, result) }
/**
* Holds if this variable is declared in the top-level of a module using a `declare` statement.
*
* For example:
* ```js
* declare var $: any;
* ```
*
* Such variables are generally treated as a global variables, except for type-checking related purposes.
*/
pragma[nomagic]
predicate isTopLevelWithAmbientDeclaration() {
this.getScope() instanceof ModuleScope and
forex(VarDecl decl | decl = this.getADeclaration() | decl.isAmbient())
}
/** Holds if this is a global variable. */
predicate isGlobal() { this.getScope() instanceof GlobalScope }
predicate isGlobal() {
this.getScope() instanceof GlobalScope or this.isTopLevelWithAmbientDeclaration()
}
/**
* Holds if this is a variable exported from a TypeScript namespace.

View File

@@ -3,6 +3,7 @@
*/
private import javascript
private import semmle.javascript.internal.TypeResolution
/**
* An input to a view component, such as React props.
@@ -14,34 +15,11 @@ abstract class ViewComponentInput extends DataFlow::Node {
private class ViewComponentInputAsThreatModelSource extends ThreatModelSource::Range instanceof ViewComponentInput
{
ViewComponentInputAsThreatModelSource() { not isSafeType(this.asExpr().getType()) }
ViewComponentInputAsThreatModelSource() {
not TypeResolution::valueHasSanitizingPrimitiveType(this.asExpr())
}
final override string getThreatModel() { result = "view-component-input" }
final override string getSourceType() { result = ViewComponentInput.super.getSourceType() }
}
private predicate isSafeType(Type t) {
t instanceof NumberLikeType
or
t instanceof BooleanLikeType
or
t instanceof UndefinedType
or
t instanceof NullType
or
t instanceof VoidType
or
hasSafeTypes(t, t.(UnionType).getNumElementType())
or
isSafeType(t.(IntersectionType).getAnElementType())
}
/** Hold if the first `n` components of `t` are safe types. */
private predicate hasSafeTypes(UnionType t, int n) {
isSafeType(t.getElementType(0)) and
n = 1
or
isSafeType(t.getElementType(n - 1)) and
hasSafeTypes(t, n - 1)
}

View File

@@ -27,6 +27,9 @@ private import internal.PreCallGraphStep
private import semmle.javascript.internal.CachedStages
private import semmle.javascript.dataflow.internal.DataFlowPrivate as Private
private import semmle.javascript.dataflow.internal.VariableOrThis
private import semmle.javascript.internal.NameResolution
private import semmle.javascript.internal.UnderlyingTypes
private import semmle.javascript.internal.TypeResolution
module DataFlow {
/**
@@ -189,26 +192,6 @@ module DataFlow {
FlowSteps::identityFunctionStep(result, this)
}
/**
* Gets the static type of this node as determined by the TypeScript type system.
*/
private Type getType() {
exists(AST::ValueNode node |
this = TValueNode(node) and
ast_node_type(node, result)
)
or
exists(BindingPattern pattern |
this = lvalueNode(pattern) and
ast_node_type(pattern, result)
)
or
exists(MethodDefinition def |
this = TThisNode(def.getInit()) and
ast_node_type(def.getDeclaringClass(), result)
)
}
/**
* Gets the type annotation describing the type of this node,
* provided that a static type could not be found.
@@ -229,6 +212,15 @@ module DataFlow {
)
}
private NameResolution::Node getNameResolutionNode() {
this = valueNode(result)
or
exists(PropertyPattern pattern |
result = pattern.getValuePattern() and
this = TPropNode(pattern)
)
}
/**
* Holds if this node is annotated with the given named type,
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
@@ -236,9 +228,10 @@ module DataFlow {
cached
predicate hasUnderlyingType(string globalName) {
Stages::TypeTracking::ref() and
this.getType().hasUnderlyingType(globalName)
or
this.getFallbackTypeAnnotation().getAnUnderlyingType().hasQualifiedName(globalName)
exists(NameResolution::Node type |
TypeResolution::valueHasType(this.getNameResolutionNode(), type) and
UnderlyingTypes::nodeHasUnderlyingType(type, globalName)
)
}
/**
@@ -248,9 +241,11 @@ module DataFlow {
cached
predicate hasUnderlyingType(string moduleName, string typeName) {
Stages::TypeTracking::ref() and
this.getType().hasUnderlyingType(moduleName, typeName)
or
this.getFallbackTypeAnnotation().getAnUnderlyingType().hasQualifiedName(moduleName, typeName)
moduleName != "global" and
exists(NameResolution::Node type |
TypeResolution::valueHasType(this.getNameResolutionNode(), type) and
UnderlyingTypes::nodeHasUnderlyingType(type, moduleName, typeName)
)
}
/**

View File

@@ -333,7 +333,14 @@ module SourceNode {
astNode instanceof TaggedTemplateExpr or
astNode instanceof Templating::PipeRefExpr or
astNode instanceof Templating::TemplateVarRefExpr or
astNode instanceof StringLiteral
astNode instanceof StringLiteral or
astNode instanceof TypeAssertion or
astNode instanceof SatisfiesExpr
)
or
exists(VariableDeclarator decl |
exists(decl.getTypeAnnotation()) and
this = DataFlow::valueNode(decl.getBindingPattern())
)
or
DataFlow::parameterNode(this, _)

View File

@@ -179,6 +179,9 @@ module Public {
/** Holds if this represents values stored at an unknown array index. */
predicate isUnknownArrayElement() { this = MkArrayElementUnknown() }
/** Holds if this represents the value of a resolved promise. */
predicate isPromiseValue() { this = MkPromiseValue() }
/** Holds if this represents values stored in a `Map` at an unknown key. */
predicate isMapValueWithUnknownKey() { this = MkMapValueWithUnknownKey() }
@@ -266,6 +269,11 @@ module Public {
or
this = ContentSet::anyCapturedContent() and
result instanceof Private::MkCapturedContent
or
// Although data flow will never use the special `Awaited` ContentSet in a read or store step,
// it may appear in type-tracking and type resolution, and here it helps to treat is as `Awaited[value]`.
this = MkAwaited() and
result = MkPromiseValue()
}
/** Gets the singleton content to be accessed. */

View File

@@ -5,6 +5,8 @@
import javascript
private import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomizations
private import semmle.javascript.dataflow.internal.PreCallGraphStep
private import semmle.javascript.internal.NameResolution
private import semmle.javascript.internal.TypeResolution
/**
* Provides classes and predicates for reasoning about [Nest](https://nestjs.com/).
@@ -133,7 +135,9 @@ module NestJS {
hasSanitizingPipe(this, false)
or
hasSanitizingPipe(this, true) and
isSanitizingType(this.getParameter().getType().unfold())
// Note: we could consider types with class-validator decorators to be sanitized here, but instead we consider the root
// object to be tainted, but omit taint steps for the individual properties names that have sanitizing decorators. See ClassValidator.qll.
TypeResolution::isSanitizingPrimitiveType(this.getParameter().getTypeAnnotation())
}
}
@@ -209,19 +213,6 @@ module NestJS {
dependsOnType = true
}
/**
* Holds if a parameter of type `t` is considered sanitized, provided it has been checked by `ValidationPipe`
* (which relies on metadata emitted by the TypeScript compiler).
*/
private predicate isSanitizingType(Type t) {
t instanceof NumberType
or
t instanceof BooleanType
//
// Note: we could consider types with class-validator decorators to be sanitized here, but instead we consider the root
// object to be tainted, but omit taint steps for the individual properties names that have sanitizing decorators. See ClassValidator.qll.
}
/**
* A user-defined pipe class, for example:
* ```js
@@ -237,7 +228,7 @@ module NestJS {
CustomPipeClass() {
exists(ClassDefinition cls |
this = cls.flow() and
cls.getASuperInterface().hasQualifiedName("@nestjs/common", "PipeTransform")
cls.getASuperInterface().hasUnderlyingType("@nestjs/common", "PipeTransform")
)
}
@@ -327,14 +318,6 @@ module NestJS {
}
}
private predicate isStringType(Type type) {
type instanceof StringType
or
type instanceof AnyType
or
isStringType(type.(PromiseType).getElementType().unfold())
}
/**
* A return value from a route handler, seen as an argument to `res.send()`.
*
@@ -353,10 +336,10 @@ module NestJS {
ReturnValueAsResponseSend() {
handler.isReturnValueReflected() and
this = handler.getAReturn() and
// Only returned strings are sinks
not exists(Type type |
type = this.asExpr().getType() and
not isStringType(type.unfold())
// Only returned strings are sinks. If we can find a type for the return value, it must be string-like.
not exists(NameResolution::Node type |
TypeResolution::valueHasType(this.asExpr(), type) and
not TypeResolution::hasUnderlyingStringOrAnyType(type)
)
}

View File

@@ -60,9 +60,7 @@ predicate isPackageUsed(string package) {
or
package = any(JS::Import imp).getImportedPathString()
or
any(JS::TypeName t).hasQualifiedName(package, _)
or
any(JS::TypeAnnotation t).hasQualifiedName(package, _)
any(JS::TypeAnnotation t).hasUnderlyingType(package, _)
or
exists(JS::PackageJson json | json.getPackageName() = package)
}
@@ -138,7 +136,7 @@ API::Node getExtraNodeFromType(string type) {
parseRelevantTypeString(type, package, qualifiedName)
|
qualifiedName = "" and
result = [API::moduleImport(package), API::moduleExport(package)]
result = [API::Internal::getAModuleImportRaw(package), API::moduleExport(package)]
or
// Access instance of a type based on type annotations
result = API::Internal::getANodeOfTypeRaw(package, qualifiedName)

View File

@@ -60,11 +60,7 @@ private predicate neverReturnsJQuery(string name) {
decl.getBaseName() = "jQuery" and
decl.getName() = name
|
not decl.getDocumentation()
.getATagByTitle("return")
.getType()
.getAnUnderlyingType()
.hasQualifiedName("jQuery")
not decl.getDocumentation().getATagByTitle("return").getType().hasUnderlyingType("jQuery")
)
}
@@ -414,6 +410,8 @@ module JQuery {
this = DataFlow::moduleImport(["jquery", "zepto", "cash-dom"])
or
this.hasUnderlyingType("JQueryStatic")
or
this.hasUnderlyingType("jquery", "")
}
}
}

View File

@@ -0,0 +1,512 @@
/**
* Provides name resolution and propagates type information.
*/
private import javascript
/**
* Provides name resolution and propagates type information.
*/
module NameResolution {
private class NodeBase =
@expr or @typeexpr or @lexical_name or @toplevel or @function_decl_stmt or @class_decl_stmt or
@namespace_declaration or @enum_declaration or @interface_declaration or
@type_alias_declaration or @jsdoc_type_expr;
/**
* A node in a graph which we use to perform name and type resolution.
*/
class Node extends NodeBase {
string toString() {
result = this.(AstNode).toString()
or
result = this.(LexicalName).toString()
or
result = this.(JSDocTypeExpr).toString()
}
Location getLocation() {
result = this.(AstNode).getLocation()
or
result = this.(LocalVariableLike).getLocation()
or
result = this.(JSDocTypeExpr).getLocation()
}
}
private signature predicate nodeSig(Node node);
/**
* A module top-level, or a `module {}` or `enum {}` statement.
*/
private class ModuleLike extends AstNode {
ModuleLike() {
this instanceof Module
or
this instanceof NamespaceDefinition // `module {}` or `enum {}` statement
}
}
/**
* A local variable, or a top-level variable that acts as a global variable due to an ambient declaration.
*/
class LocalVariableLike extends Variable {
LocalVariableLike() { this.isLocal() or this.isTopLevelWithAmbientDeclaration() }
Location getLocation() {
result =
min(Location loc |
loc = this.getADeclaration().getLocation()
|
loc order by loc.getStartLine(), loc.getStartColumn()
)
}
}
/**
* Holds if values/namespaces/types in `node1` can flow to values/namespaces/types in `node2`.
*
* May also include some type-specific steps in cases where this is harmless when tracking values.
*/
private predicate commonStep(Node node1, Node node2) {
// Import paths are part of the graph and has an incoming edge from the imported module, if found.
// This ensures we can also use the PathExpr as a source when working with external (unresolved) modules.
exists(Import imprt |
node1 = imprt.getImportedModule() and
node2 = imprt.getImportedPathExpr()
)
or
exists(ImportNamespaceSpecifier spec |
node1 = spec.getImportDeclaration().getImportedPathExpr() and
node2 = spec.getLocal()
)
or
exists(ExportNamespaceSpecifier spec |
node1 = spec.getExportDeclaration().(ReExportDeclaration).getImportedPath() and
node2 = spec
)
or
exists(ExportAssignDeclaration assign |
node1 = assign.getExpression() and
node2 = assign.getContainer()
)
or
exists(ImportEqualsDeclaration imprt |
node1 = imprt.getImportedEntity() and
node2 = imprt.getIdentifier()
)
or
exists(ExternalModuleReference ref |
node1 = ref.getImportedPathExpr() and
node2 = ref
)
or
exists(ImportTypeExpr imprt |
node1 = imprt.getPathExpr() and // TODO: ImportTypeExpr does not seem to be resolved to a Module
node2 = imprt
)
or
exists(ClassOrInterface cls |
node1 = cls and
node2 = cls.getIdentifier()
)
or
exists(NamespaceDefinition def |
node1 = def and
node2 = def.getIdentifier()
)
or
exists(Function fun |
node1 = fun and
node2 = fun.getIdentifier()
)
or
exists(EnumMember def |
node1 = def.getInitializer() and
node2 = def.getIdentifier()
)
or
exists(TypeAliasDeclaration alias |
node1 = alias.getDefinition() and
node2 = alias.getIdentifier()
)
or
exists(VariableDeclarator decl |
node1 = decl.getInit() and
node2 = decl.getBindingPattern()
)
or
exists(ParenthesizedTypeExpr type |
node1 = type.getElementType() and
node2 = type
)
or
exists(ParenthesisExpr expr |
node1 = expr.getExpression() and
node2 = expr
)
or
exists(NonNullAssertion assertion |
// For the time being we don't use this for nullness analysis, so just
// propagate through these assertions.
node1 = assertion.getExpression() and
node2 = assertion
)
or
exists(FunctionTypeExpr fun |
node1 = fun.getFunction() and
node2 = fun
)
or
exists(TypeofTypeExpr type |
node1 = type.getExpressionName() and
node2 = type
)
or
exists(Closure::RequireCallExpr req |
node1.(Closure::ClosureModule).getClosureNamespace() = req.getClosureNamespace() and
node2 = req
)
or
exists(Closure::ClosureModule mod |
node1 = mod.getExportsVariable() and
node2 = mod
)
or
exists(ImmediatelyInvokedFunctionExpr fun, int i |
node1 = fun.getArgument(i) and
node2 = fun.getParameter(i)
)
}
/**
* Holds if there is a read from `node1` to `node2` that accesses the member `name`.
*/
predicate readStep(Node node1, string name, Node node2) {
exists(QualifiedTypeAccess access |
node1 = access.getQualifier() and
name = access.getIdentifier().getName() and
node2 = access
)
or
exists(QualifiedNamespaceAccess access |
node1 = access.getQualifier() and
name = access.getIdentifier().getName() and
node2 = access
)
or
exists(QualifiedVarTypeAccess access |
node1 = access.getQualifier() and
name = access.getIdentifier().getName() and
node2 = access
)
or
exists(PropAccess access |
node1 = access.getBase() and
name = access.getPropertyName() and
node2 = access
)
or
exists(ObjectPattern pattern |
node1 = pattern and
node2 = pattern.getPropertyPatternByName(name).getValuePattern()
)
or
exists(ImportSpecifier spec |
node1 = spec.getImportDeclaration().getImportedPathExpr() and
name = spec.getImportedName() and
node2 = spec.getLocal()
)
or
exists(SelectiveReExportDeclaration exprt, ExportSpecifier spec |
spec = exprt.getASpecifier() and
node1 = exprt.getImportedPath() and
name = spec.getLocalName() and
node2 = spec.getLocal()
)
or
exists(JSDocQualifiedTypeAccess expr |
node1 = expr.getBase() and
name = expr.getName() and
node2 = expr
)
}
private signature module TypeResolutionInputSig {
/**
* Holds if flow is permitted through the given variable.
*/
predicate isRelevantVariable(LexicalName var);
}
/**
* A local variable with exactly one definition, not counting implicit initialization.
*/
private class EffectivelyConstantVariable extends LocalVariableLike {
EffectivelyConstantVariable() {
count(SsaExplicitDefinition ssa | ssa.getSourceVariable() = this) <= 1 // count may be zero if ambient
}
}
/** Configuration for propagating values and namespaces */
private module ValueConfig implements TypeResolutionInputSig {
predicate isRelevantVariable(LexicalName var) {
var instanceof EffectivelyConstantVariable
or
// We merge the namespace and value declaration spaces as it seems there is
// no need to distinguish them in practice.
var instanceof LocalNamespaceName
}
}
/**
* Associates information about values, such as references to a class, module, or namespace.
*/
module ValueFlow = FlowImpl<ValueConfig>;
private module TypeConfig implements TypeResolutionInputSig {
predicate isRelevantVariable(LexicalName var) { var instanceof LocalTypeName }
}
/**
* Associates nodes with information about types.
*/
module TypeFlow = FlowImpl<TypeConfig>;
/**
* Generates a directed graph for tracking type names or value names back toward their definition.
* The ultimate definition might not be in the database, but the graph lets us track as far as we can.
*
* The module parameter determines whether types or values should be tracked.
*
* The example below illustrates the need for two separate instantiations of this module.
* When tracking through the nodes corresponding to `X`, we need to remember whether a type or value was tracked.
*
* ```ts
* // lib.ts
* class C1 {}
* class C2 {}
*
* const X = C1;
* type X = C2;
*
* export { X }
*
* // use.ts
* import { X } from "./lib"
*
* var x1 = X // should refer to C1
* var x2: X; // should refer to C2
* ```
*/
private module FlowImpl<TypeResolutionInputSig S> {
/**
* Gets the exported member of `mod` named `name`.
*/
Node getModuleExport(ModuleLike mod, string name) {
exists(ExportDeclaration exprt |
mod = exprt.getContainer() and
exprt.exportsAs(result, name) and
S::isRelevantVariable(result)
)
or
exists(ExportNamespaceSpecifier spec |
result = spec and
mod = spec.getContainer() and
name = spec.getExportedName()
)
or
exists(SelectiveReExportDeclaration exprt, ExportSpecifier spec |
// `export { A as B } from 'blah'`
// This is not covered by `exportsAs` above because neither A or B is a LexicalName
// (both are property names) so it doesn't fit the interface of `exportsAs`.
spec = exprt.getASpecifier() and
mod = exprt.getContainer() and
name = spec.getExportedName() and
result = spec.getLocal()
)
or
exists(EnumDeclaration enum |
mod = enum and
result = enum.getMemberByName(name).getIdentifier()
)
or
storeToVariable(result, name, mod.(Closure::ClosureModule).getExportsVariable())
}
/**
* Holds if `value` is stored in `target.prop`. Only needs to recognise assignments
* that are also recognised by JSDoc tooling such as the Closure compiler.
*/
private predicate storeToVariable(Expr value, string prop, LocalVariableLike target) {
exists(AssignExpr assign |
// target.name = value
assign.getLhs().(PropAccess).accesses(target.getAnAccess(), prop) and
value = assign.getRhs()
)
or
// target = { name: value }
value = target.getAnAssignedExpr().(ObjectExpr).getPropertyByName(prop).getInit()
}
/** Steps that only apply for this configuration. */
private predicate specificStep(Node node1, Node node2) {
exists(LexicalName var | S::isRelevantVariable(var) |
node1.(LexicalDecl).getALexicalName() = var and
node2 = var
or
node1 = var and
node2.(LexicalAccess).getALexicalName() = var
or
node1 = var and
node2.(JSDocLocalTypeAccess).getALexicalName() = var
)
or
exists(Node base, string name, ModuleLike mod |
readStep(base, name, node2) and
base = trackModule(mod) and
node1 = getModuleExport(mod, name)
)
}
/**
* Holds if data should propagate from `node1` to `node2`.
*/
pragma[inline]
predicate step(Node node1, Node node2) {
commonStep(node1, node2)
or
specificStep(node1, node2)
}
/** Helps track flow from a particular set of source nodes. */
module Track<nodeSig/1 isSource> {
/** Gets the set of nodes reachable from `source`. */
Node track(Node source) {
isSource(source) and
result = source
or
step(track(source), result)
}
}
signature class AstNodeSig extends AstNode;
/** Helps track flow from a particular set of source nodes. */
module TrackNode<AstNodeSig Source> {
/** Gets the set of nodes reachable from `source`. */
Node track(Source source) {
result = source
or
step(track(source), result)
}
}
}
/**
* Gets a node to which the given module flows.
*/
predicate trackModule = ValueFlow::TrackNode<ModuleLike>::track/1;
/**
* Holds if `moduleName` appears to start with a package name, as opposed to a relative file import.
*/
bindingset[moduleName]
private predicate isExternalModuleName(string moduleName) {
not moduleName.regexpMatch("^(\\.|/).*")
}
bindingset[name]
private string normalizeModuleName(string name) {
result =
name.regexpReplaceAll("^node:", "")
.regexpReplaceAll("\\.[cm]?[jt]sx?$", "")
.regexpReplaceAll("/(index)?$", "")
}
/** Appends a name onto a qualified name */
bindingset[a, b]
string append(string a, string b) {
if b = "default"
then result = a
else (
(if a = "" or b = "" then result = a + b else result = a + "." + b) and
result.length() < 100
)
}
private predicate needsQualifiedName(Node node) {
node = any(JSDocLocalTypeAccess t).getALexicalName().(Variable)
or
exists(Node prev | needsQualifiedName(prev) |
ValueFlow::step(node, prev)
or
readStep(node, _, prev)
)
}
/**
* Holds if `node` is a reference to the given module, or a qualified name rooted in that module.
*
* If `qualifiedName` is empty, `node` refers to the module itself.
*
* If `mod` is the string `"global"`, `node` refers to a global access path.
*
* Unlike `trackModule`, this is intended to track uses of external packages.
*/
predicate nodeRefersToModule(Node node, string mod, string qualifiedName) {
exists(Expr path |
path = any(Import imprt).getImportedPathExpr() or
path = any(ReExportDeclaration e).getImportedPath()
|
node = path and
mod = normalizeModuleName(path.getStringValue()) and
isExternalModuleName(mod) and
qualifiedName = ""
)
or
mod = "global" and
exists(LocalNamespaceAccess access |
node = access and
not exists(access.getLocalNamespaceName()) and
access.getName() = qualifiedName
)
or
mod = "global" and
exists(JSDocLocalTypeAccess access |
node = access and
not exists(access.getALexicalName()) and
access.getName() = qualifiedName
)
or
mod = "global" and
exists(GlobalVarAccess access |
node = access and
needsQualifiedName(access) and // restrict number of qualified names we generate
access.getName() = qualifiedName
)
or
mod = "global" and
qualifiedName = node.(Closure::RequireCallExpr).getClosureNamespace()
or
// Additionally track through bulk re-exports (`export * from 'mod`).
// These are normally handled by 'exportAs' which supports various shadowing rules,
// but has no effect when the ultimate re-exported module is not resolved to a Module.
// We propagate external module refs through bulk re-exports and ignore shadowing rules.
exists(BulkReExportDeclaration reExport |
nodeRefersToModule(reExport.getImportedPath(), mod, qualifiedName) and
node = reExport.getContainer()
)
or
exists(Node mid |
nodeRefersToModule(mid, mod, qualifiedName) and
ValueFlow::step(mid, node)
)
or
exists(Node mid, string prefix, string step |
nodeRefersToModule(mid, mod, prefix) and
readStep(mid, step, node) and
qualifiedName = append(prefix, step)
)
}
}

View File

@@ -0,0 +1,422 @@
private import javascript
private import semmle.javascript.internal.NameResolution::NameResolution
private import semmle.javascript.internal.UnderlyingTypes
private import semmle.javascript.dataflow.internal.sharedlib.SummaryTypeTracker as SummaryTypeTracker
module TypeResolution {
predicate trackClassValue = ValueFlow::TrackNode<ClassDefinition>::track/1;
predicate trackType = TypeFlow::TrackNode<TypeDefinition>::track/1;
/**
* Gets a node that has `fun` as an underlying type.
*
* We track through underlying types as an approximate way to handle calls to a type
* that is a union/intersection involving functions.
*/
Node trackUnderlyingFunctionType(Function fun) {
result = fun
or
exists(Node mid | mid = trackUnderlyingFunctionType(fun) |
TypeFlow::step(mid, result)
or
UnderlyingTypes::underlyingTypeStep(mid, result)
)
}
predicate trackFunctionValue = ValueFlow::TrackNode<Function>::track/1;
/**
* Gets the representative for the type containing the given member.
*
* For non-static members this is simply the enclosing type declaration.
*
* For static members we use the class's `Variable` as representative for the type of the class object.
*/
private Node getMemberBase(MemberDeclaration member) {
if member.isStatic()
then result = member.getDeclaringClass().getVariable()
else result = member.getDeclaringType()
}
/**
* Holds if `host` is a type with a `content` of type `memberType`, not counting inherited members.
*/
private predicate typeOwnMember(Node host, DataFlow::Content content, Node memberType) {
exists(MemberDeclaration decl | host = getMemberBase(decl) |
exists(FieldDeclaration field |
decl = field and
content.asPropertyName() = field.getName() and
memberType = field.getTypeAnnotation()
)
or
exists(MethodDeclaration method |
decl = method and
content.asPropertyName() = method.getName()
|
not method instanceof AccessorMethodDeclaration and
memberType = method.getBody() // use the Function as representative for the function type
or
method instanceof GetterMethodDeclaration and
memberType = method.getBody().getReturnTypeAnnotation()
)
or
decl instanceof IndexSignature and
memberType = decl.(IndexSignature).getBody().getReturnTypeAnnotation() and
content.isUnknownArrayElement()
)
or
// Ad-hoc support for array types. We don't support generics in general currently, we just special-case arrays and promises.
content.isUnknownArrayElement() and
(
memberType = host.(ArrayTypeExpr).getElementType()
or
exists(GenericTypeExpr type |
host = type and
type.getTypeAccess().(LocalTypeAccess).getName() = ["Array", "ReadonlyArray"] and
memberType = type.getTypeArgument(0)
)
or
exists(JSDocAppliedTypeExpr type |
host = type and
type.getHead().(JSDocLocalTypeAccess).getName() = "Array" and
memberType = type.getArgument(0)
)
)
or
content.isPromiseValue() and
memberType = unwrapPromiseType(host)
}
/**
* Holds if `host` is a type with a `content` of type `memberType`, possible due to inheritance.
*/
private predicate typeMember(Node host, DataFlow::Content content, Node memberType) {
typeOwnMember(host, content, memberType)
or
// Inherit members from base types
not typeOwnMember(host, content, _) and
exists(ClassOrInterface baseType | typeMember(baseType, content, memberType) |
host.(ClassDefinition).getSuperClass() = trackClassValue(baseType)
or
host.(ClassOrInterface).getASuperInterface() = trackType(baseType)
)
}
/**
* Holds `use` refers to `host`, and `host` has type members.
*
* Currently steps through unions and intersections, which acts as a basic
* approximation to the unions/intersection of objects.
*/
private predicate typeMemberHostReaches(Node host, Node use) {
typeMember(host, _, _) and
use = host
or
exists(Node mid | typeMemberHostReaches(host, mid) |
TypeFlow::step(mid, use)
or
UnderlyingTypes::underlyingTypeStep(mid, use)
)
}
/**
* Holds if there is a read from from `object` to `member` that reads `contents`.
*/
private predicate valueReadStep(Node object, DataFlow::ContentSet contents, Node member) {
member.(PropAccess).accesses(object, contents.asPropertyName())
or
object.(ObjectPattern).getPropertyPatternByName(contents.asPropertyName()).getValuePattern() =
member
or
member.(AwaitExpr).getOperand() = object and
contents = DataFlow::ContentSet::promiseValue()
or
SummaryTypeTracker::basicLoadStep(object.(AST::ValueNode).flow(),
member.(AST::ValueNode).flow(), contents)
}
predicate callTarget(InvokeExpr call, Function target) {
exists(ClassDefinition cls |
valueHasType(call.(NewExpr).getCallee(), trackClassValue(cls)) and
target = cls.getConstructor().getBody()
)
or
valueHasType(call.getCallee(), trackFunctionValue(target))
or
valueHasType(call.getCallee(), trackUnderlyingFunctionType(target)) and
(
call instanceof NewExpr and
target = any(ConstructorTypeExpr t).getFunction()
or
call instanceof CallExpr and
target = any(PlainFunctionTypeExpr t).getFunction()
)
or
exists(InterfaceDefinition interface, CallSignature sig |
valueHasType(call.getCallee(), trackType(interface)) and
sig = interface.getACallSignature() and
target = sig.getBody()
|
call instanceof NewExpr and
sig instanceof ConstructorCallSignature
or
call instanceof CallExpr and
sig instanceof FunctionCallSignature
)
}
private predicate functionReturnType(Function func, Node returnType) {
returnType = func.getReturnTypeAnnotation()
or
not exists(func.getReturnTypeAnnotation()) and
exists(Function functionType |
contextualType(func, trackUnderlyingFunctionType(functionType)) and
returnType = functionType.getReturnTypeAnnotation()
)
}
bindingset[name]
private predicate isPromiseTypeName(string name) {
name.regexpMatch(".?(Promise|Thenable)(Like)?")
}
private Node unwrapPromiseType(Node promiseType) {
exists(GenericTypeExpr type |
promiseType = type and
isPromiseTypeName(type.getTypeAccess().(LocalTypeAccess).getName()) and
result = type.getTypeArgument(0)
)
or
exists(JSDocAppliedTypeExpr type |
promiseType = type and
isPromiseTypeName(type.getHead().(JSDocLocalTypeAccess).getName()) and
result = type.getArgument(0)
)
}
predicate contextualType(Node value, Node type) {
exists(LocalVariableLike v |
type = v.getADeclaration().getTypeAnnotation() and
value = v.getAnAssignedExpr()
)
or
exists(InvokeExpr call, Function target, int i |
callTarget(call, target) and
value = call.getArgument(i) and
type = target.getParameter(i).getTypeAnnotation()
)
or
exists(Function lambda, Node returnType |
value = lambda.getAReturnedExpr() and
functionReturnType(lambda, returnType)
|
not lambda.isAsyncOrGenerator() and
type = returnType
or
lambda.isAsync() and
type = unwrapPromiseType(returnType)
)
or
exists(ObjectExpr object, Node objectType, Node host, string name |
contextualType(object, objectType) and
typeMemberHostReaches(host, objectType) and
typeMember(host, any(DataFlow::Content c | c.asPropertyName() = name), type) and
value = object.getPropertyByName(name).getInit()
)
or
exists(ArrayExpr array, Node arrayType, Node host |
contextualType(array, arrayType) and
typeMemberHostReaches(host, arrayType) and
typeMember(host, any(DataFlow::Content c | c.isUnknownArrayElement()), type) and
value = array.getAnElement()
)
}
/**
* Holds if `value` has the given `type`.
*/
predicate valueHasType(Node value, Node type) {
value.(BindingPattern).getTypeAnnotation() = type
or
value.(TypeAssertion).getTypeAnnotation() = type
or
value.(SatisfiesExpr).getTypeAnnotation() = type
or
exists(VarDecl decl |
// ValueFlow::step is restricted to variables with at most one assignment. Allow the type annotation
// of a variable to propagate to its uses, even if the variable has multiple assignments.
type = decl.getTypeAnnotation() and
value = decl.getVariable().(LocalVariableLike).getAnAccess()
)
or
exists(MemberDeclaration member |
value.(ThisExpr).getBindingContainer() = member.getInit() and
type = getMemberBase(member)
)
or
exists(ClassDefinition cls |
value = cls and
type = cls.getVariable()
)
or
exists(FunctionDeclStmt fun |
value = fun and
type = fun.getVariable()
)
or
exists(Function target | callTarget(value, target) |
type = target.getReturnTypeAnnotation()
or
exists(ClassDefinition cls |
target = cls.getConstructor().getBody() and
type = cls
)
)
or
// Contextual typing for parameters
exists(Function lambda, Function functionType, int i |
contextualType(lambda, trackUnderlyingFunctionType(functionType))
or
exists(InterfaceDefinition interface |
contextualType(lambda, trackType(interface)) and
functionType = interface.getACallSignature().getBody()
)
|
value = lambda.getParameter(i) and
not exists(value.(Parameter).getTypeAnnotation()) and
type = functionType.getParameter(i).getTypeAnnotation()
)
or
exists(Node mid | valueHasType(mid, type) | ValueFlow::step(mid, value))
or
exists(Node mid, Node midType, DataFlow::ContentSet contents, Node host |
valueReadStep(mid, contents, value) and
valueHasType(mid, midType) and
typeMemberHostReaches(host, midType) and
typeMember(host, contents.getAReadContent(), type)
)
}
signature predicate nodeSig(Node node);
/**
* Tracks types that have a certain property, in the sense that:
* - an intersection type has the property if any member has the property
* - a union type has the property if all its members have the property
*/
module TrackMustProp<nodeSig/1 directlyHasProperty> {
predicate hasProperty(Node node) {
directlyHasProperty(node)
or
exists(Node mid |
hasProperty(mid) and
TypeFlow::step(mid, node)
)
or
unionHasProp(node)
or
hasProperty(node.(IntersectionTypeExpr).getAnElementType())
or
exists(ConditionalTypeExpr cond |
node = cond and
hasProperty(cond.getTrueType()) and
hasProperty(cond.getFalseType())
)
}
private predicate unionHasProp(UnionTypeExpr node, int n) {
hasProperty(node.getElementType(0)) and n = 1
or
unionHasProp(node, n - 1) and
hasProperty(node.getElementType(n - 1))
}
private predicate unionHasProp(UnionTypeExpr node) {
unionHasProp(node, node.getNumElementType())
}
}
module ValueHasProperty<nodeSig/1 typeHasProperty> {
predicate valueHasProperty(Node value) {
exists(Node type |
valueHasType(value, type) and
typeHasProperty(type)
)
}
}
private predicate isSanitizingPrimitiveTypeBase(Node node) {
node.(TypeExpr).isNumbery()
or
node.(TypeExpr).isBooleany()
or
node.(TypeExpr).isNull()
or
node.(TypeExpr).isUndefined()
or
node.(TypeExpr).isVoid()
or
node.(TypeExpr).isNever()
or
node.(TypeExpr).isBigInt()
or
node.(TypeExpr).isSymbol()
or
node instanceof LiteralTypeExpr
or
node = any(EnumMember m).getIdentifier() // enum members are constant
or
node instanceof EnumDeclaration // enums are unions of constants
}
/**
* Holds if `node` refers to a type that is considered untaintable (if actually enforced at runtime).
*
* Specifically, the types `number`, `boolean`, `null`, `undefined`, `void`, `never`, as well as literal types (`"foo"`)
* and enums and enum members have this property.
*/
predicate isSanitizingPrimitiveType =
TrackMustProp<isSanitizingPrimitiveTypeBase/1>::hasProperty/1;
/**
* Holds if `value` has a type that is considered untaintable (if actually enforced at runtime).
*
* See `isSanitizingPrimitiveType`.
*/
predicate valueHasSanitizingPrimitiveType =
ValueHasProperty<isSanitizingPrimitiveType/1>::valueHasProperty/1;
private predicate isPromiseBase(Node node) { exists(unwrapPromiseType(node)) }
/**
* Holds if the given type is a Promise object. Does not hold for unions unless all parts of the union are promises.
*/
predicate isPromiseType = TrackMustProp<isPromiseBase/1>::hasProperty/1;
/**
* Holds if the given value has a type that implied it is a Promise object. Does not hold for unions unless all parts of the union are promises.
*/
predicate valueHasPromiseType = ValueHasProperty<isPromiseType/1>::valueHasProperty/1;
/**
* Holds if `type` contains `string` or `any`, possibly wrapped in a promise.
*/
predicate hasUnderlyingStringOrAnyType(Node type) {
type.(TypeAnnotation).isStringy()
or
type.(TypeAnnotation).isAny()
or
type instanceof StringLiteralTypeExpr
or
type instanceof TemplateLiteralTypeExpr
or
exists(Node mid | hasUnderlyingStringOrAnyType(mid) |
TypeFlow::step(mid, type)
or
UnderlyingTypes::underlyingTypeStep(mid, type)
or
type = unwrapPromiseType(mid)
)
}
}

View File

@@ -0,0 +1,128 @@
/**
* Provides name resolution and propagates type information.
*/
private import javascript
private import semmle.javascript.internal.NameResolution::NameResolution
/**
* Provides name resolution and propagates type information.
*/
module UnderlyingTypes {
private predicate subtypeStep(Node node1, Node node2) {
exists(ClassOrInterface cls |
(
node1 = cls.getSuperClass() or
node1 = cls.getASuperInterface()
) and
node2 = cls
)
}
predicate underlyingTypeStep(Node node1, Node node2) {
exists(UnionOrIntersectionTypeExpr type |
node1 = type.getAnElementType() and
node2 = type
)
or
exists(ReadonlyTypeExpr type |
node1 = type.getElementType() and
node2 = type
)
or
exists(OptionalTypeExpr type |
node1 = type.getElementType() and
node2 = type
)
or
exists(GenericTypeExpr type |
node1 = type.getTypeAccess() and
node2 = type
)
or
exists(ExpressionWithTypeArguments e |
node1 = e.getExpression() and
node2 = e
)
or
exists(JSDocUnionTypeExpr type |
node1 = type.getAnAlternative() and
node2 = type
)
or
exists(JSDocNonNullableTypeExpr type |
node1 = type.getTypeExpr() and
node2 = type
)
or
exists(JSDocNullableTypeExpr type |
node1 = type.getTypeExpr() and
node2 = type
)
or
exists(JSDocAppliedTypeExpr type |
node1 = type.getHead() and
node2 = type
)
or
exists(JSDocOptionalParameterTypeExpr type |
node1 = type.getUnderlyingType() and
node2 = type
)
}
predicate nodeHasUnderlyingType(Node node, string mod, string name) {
nodeRefersToModule(node, mod, name)
or
exists(JSDocLocalTypeAccess type |
node = type and
not exists(type.getALexicalName()) and
not type = any(JSDocQualifiedTypeAccess t).getBase() and
name = type.getName() and
mod = "global"
)
or
exists(LocalTypeAccess type |
node = type and
not exists(type.getLocalTypeName()) and
name = type.getName() and
mod = "global"
)
or
exists(Node mid | nodeHasUnderlyingType(mid, mod, name) |
TypeFlow::step(mid, node)
or
underlyingTypeStep(mid, node)
or
subtypeStep(mid, node)
)
}
pragma[nomagic]
predicate nodeHasUnderlyingType(Node node, string name) {
nodeHasUnderlyingType(node, "global", name)
}
predicate nodeHasUnderlyingClassType(Node node, DataFlow::ClassNode cls) {
node = cls.getAstNode()
or
exists(string name |
classHasGlobalName(cls, name) and
nodeHasUnderlyingType(node, name)
)
or
exists(Node mid | nodeHasUnderlyingClassType(mid, cls) |
TypeFlow::step(mid, node)
or
underlyingTypeStep(mid, node)
// Note: unlike for external types, we do not use subtype steps here.
// The caller is responsible for handling the class hierarchy.
)
}
pragma[nomagic]
private predicate classHasGlobalName(DataFlow::ClassNode cls, string name) {
cls.flowsTo(AccessPath::getAnAssignmentTo(name)) and
not cls.getTopLevel().isExterns() // don't propagate externs classes
}
}

View File

@@ -10,6 +10,7 @@
*/
import javascript
private import semmle.javascript.internal.TypeResolution
/**
* Holds if `call` is a call to an `async` function.
@@ -28,7 +29,7 @@ predicate isPromise(DataFlow::SourceNode node, boolean nullable) {
isAsyncCall(node, nullable)
or
not isAsyncCall(node, _) and
node.asExpr().getType() instanceof PromiseType and
TypeResolution::valueHasPromiseType(node.asExpr()) and
nullable = true
}

View File

@@ -12,7 +12,10 @@ import javascript
from DataFlow::Node invoke, Function f, string kind
where
invoke.(DataFlow::InvokeNode).getACallee() = f and kind = "Call"
or
invoke.(DataFlow::PropRef).getAnAccessorCallee().getFunction() = f and kind = "Accessor call"
(
invoke.(DataFlow::InvokeNode).getACallee() = f and kind = "Call"
or
invoke.(DataFlow::PropRef).getAnAccessorCallee().getFunction() = f and kind = "Accessor call"
) and
not f.getTopLevel().isExterns()
select invoke, kind + " to $@", f, f.describe()

View File

@@ -1,14 +0,0 @@
/**
* @name Types with qualified name
* @description The number of type annotations with a qualified name
* @kind metric
* @metricType project
* @metricAggregate sum
* @tags meta
* @id js/meta/types-with-qualified-name
*/
import javascript
import meta.MetaMetrics
select projectRoot(), count(TypeAnnotation t | t.hasQualifiedName(_) or t.hasQualifiedName(_, _))

View File

@@ -0,0 +1,27 @@
namespace NS {
export class C {
/** name:NS.C.m */
m() { }
}
export class D extends C { }
}
function t1(c: NS.C, d: NS.D) {
/** calls:NS.C.m */
c.m();
/** calls:NS.C.m */
d.m();
}
async function t2(cp: Promise<NS.C>) {
const c = await cp;
/** calls:NS.C.m */
c.m();
cp.then(c2 => {
/** calls:NS.C.m */
c2.m();
})
}

View File

@@ -1514,6 +1514,7 @@ sources
| tst2.ts:7:1:9:1 | return of function setX |
| tst2.ts:8:3:8:5 | A.x |
| tst2.ts:11:11:11:13 | A.x |
| tst2.ts:11:11:11:23 | A.x as number |
| tst2.ts:13:1:13:40 | class S ... ing> {} |
| tst2.ts:13:26:13:29 | List |
| tst2.ts:13:39:13:38 | (...arg ... rgs); } |
@@ -1522,6 +1523,7 @@ sources
| tst2.ts:13:39:13:38 | super(...args) |
| tst2.ts:13:39:13:38 | this |
| tst2.ts:15:11:15:13 | A.x |
| tst2.ts:15:11:15:30 | A.x satisfies number |
| tst.js:1:1:1:0 | this |
| tst.js:1:1:1:24 | import ... m 'fs'; |
| tst.js:1:10:1:11 | fs |

View File

@@ -1,10 +1,10 @@
| bar.js:5:14:5:14 | x | x |
| bar.js:5:14:5:14 | x | ns.very.long.namespace |
| bar.js:5:14:5:18 | x.Foo | ns.very.long.namespace.Foo |
| bar.js:12:14:12:17 | iife | iife |
| bar.js:12:14:12:17 | iife | IIFE |
| bar.js:12:14:12:21 | iife.Foo | IIFE.Foo |
| closure.js:8:12:8:15 | goog | goog |
| closure.js:8:12:8:19 | goog.net | goog.net |
| closure.js:8:12:8:28 | goog.net.SomeType | goog.net.SomeType |
| closure.js:9:12:9:14 | net | net |
| closure.js:9:12:9:14 | net | goog.net |
| closure.js:9:12:9:23 | net.SomeType | goog.net.SomeType |
| closure.js:10:12:10:19 | SomeType | goog.net.SomeType |

View File

@@ -1,3 +1,3 @@
import javascript
query string test_hasQualifiedName(JSDocNamedTypeExpr expr) { expr.hasQualifiedName(result) }
query string test_hasUnderlyingType(JSDocNamedTypeExpr expr) { expr.hasUnderlyingType(result) }

View File

@@ -2,13 +2,14 @@ test_isString
| tst.js:2:12:2:17 | string |
test_isNumber
| tst.js:3:12:3:17 | number |
test_QualifiedName
test_hasUnderlyingType
| VarType | tst.js:9:13:9:19 | VarType |
| boolean | tst.js:5:14:5:20 | boolean |
| foo | tst.js:4:12:4:14 | foo |
| foo.bar | tst.js:4:12:4:18 | foo.bar |
| foo.bar.baz | tst.js:4:12:4:22 | foo.bar.baz |
| number | tst.js:3:12:3:17 | number |
| number | tst.js:3:12:3:18 | number? |
| string | tst.js:2:12:2:17 | string |
test_ParameterType
| tst.js:7:12:7:12 | x | tst.js:2:12:2:17 | string |

View File

@@ -4,7 +4,7 @@ query TypeAnnotation test_isString() { result.isString() }
query TypeAnnotation test_isNumber() { result.isNumber() }
query TypeAnnotation test_QualifiedName(string name) { result.hasQualifiedName(name) }
query TypeAnnotation test_hasUnderlyingType(string name) { result.hasUnderlyingType(name) }
query TypeAnnotation test_ParameterType(Parameter p) { result = p.getTypeAnnotation() }

View File

@@ -1,5 +1,5 @@
import javascript
from TypeAnnotation type, string mod, string name
where type.hasQualifiedName(mod, name)
where type.hasUnderlyingType(mod, name)
select type, mod, name

View File

@@ -1 +1,7 @@
| tst.ts:38:3:38:19 | resolveAmbient(x) | x should not resolve to a global |
| tst.ts:22:3:22:18 | resolveGlobal(x) | x should resolve to a global variable |
| tst.ts:23:3:23:18 | resolveGlobal(y) | y should resolve to a global variable |
| tst.ts:24:3:24:18 | resolveGlobal(z) | z should resolve to a global variable |
| tst.ts:25:3:25:18 | resolveGlobal(w) | w should resolve to a global variable |
| tst.ts:39:3:39:18 | resolveGlobal(y) | y should resolve to a global variable |
| tst.ts:40:3:40:18 | resolveGlobal(z) | z should resolve to a global variable |
| tst.ts:41:3:41:18 | resolveGlobal(w) | w should resolve to a global variable |

View File

@@ -1,16 +1,36 @@
| tst.ts:52:3:52:23 | obj.sim ... od(str) | TestInterface.simpleMethod in global scope | no concrete target |
| tst.ts:53:3:53:24 | obj.gen ... od(str) | TestInterface.genericMethod in global scope | no concrete target |
| tst.ts:54:3:54:24 | obj.gen ... od(num) | TestInterface.genericMethod in global scope | no concrete target |
| tst.ts:55:3:55:27 | obj.ove ... od(num) | TestInterface.overloadedMethod in global scope | no concrete target |
| tst.ts:56:3:56:27 | obj.ove ... od(str) | TestInterface.overloadedMethod in global scope | no concrete target |
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | TestInterface.overloadedMethod in global scope | no concrete target |
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | TestInterface.genericOverloadedMethod in global scope | no concrete target |
| tst.ts:59:3:59:39 | obj.gen ... : str}) | TestInterface.genericOverloadedMethod in global scope | no concrete target |
| tst.ts:60:3:60:34 | obj.gen ... od(num) | TestInterface.genericOverloadedMethod in global scope | no concrete target |
| tst.ts:52:3:52:23 | obj.sim ... od(str) | TestInterface.simpleMethod in global scope | simpleM ... number; |
| tst.ts:53:3:53:24 | obj.gen ... od(str) | TestInterface.genericMethod in global scope | generic ... T): T; |
| tst.ts:54:3:54:24 | obj.gen ... od(num) | TestInterface.genericMethod in global scope | generic ... T): T; |
| tst.ts:55:3:55:27 | obj.ove ... od(num) | TestInterface.overloadedMethod in global scope | overloa ... ): any; |
| tst.ts:55:3:55:27 | obj.ove ... od(num) | TestInterface.overloadedMethod in global scope | overloa ... number; |
| tst.ts:55:3:55:27 | obj.ove ... od(num) | TestInterface.overloadedMethod in global scope | overloa ... string; |
| tst.ts:56:3:56:27 | obj.ove ... od(str) | TestInterface.overloadedMethod in global scope | overloa ... ): any; |
| tst.ts:56:3:56:27 | obj.ove ... od(str) | TestInterface.overloadedMethod in global scope | overloa ... number; |
| tst.ts:56:3:56:27 | obj.ove ... od(str) | TestInterface.overloadedMethod in global scope | overloa ... string; |
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | TestInterface.overloadedMethod in global scope | overloa ... ): any; |
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | TestInterface.overloadedMethod in global scope | overloa ... number; |
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | TestInterface.overloadedMethod in global scope | overloa ... string; |
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | TestInterface.genericOverloadedMethod in global scope | generic ... ): any; |
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | TestInterface.genericOverloadedMethod in global scope | generic ... T>): T; |
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | TestInterface.genericOverloadedMethod in global scope | generic ... []): T; |
| tst.ts:59:3:59:39 | obj.gen ... : str}) | TestInterface.genericOverloadedMethod in global scope | generic ... ): any; |
| tst.ts:59:3:59:39 | obj.gen ... : str}) | TestInterface.genericOverloadedMethod in global scope | generic ... T>): T; |
| tst.ts:59:3:59:39 | obj.gen ... : str}) | TestInterface.genericOverloadedMethod in global scope | generic ... []): T; |
| tst.ts:60:3:60:34 | obj.gen ... od(num) | TestInterface.genericOverloadedMethod in global scope | generic ... ): any; |
| tst.ts:60:3:60:34 | obj.gen ... od(num) | TestInterface.genericOverloadedMethod in global scope | generic ... T>): T; |
| tst.ts:60:3:60:34 | obj.gen ... od(num) | TestInterface.genericOverloadedMethod in global scope | generic ... []): T; |
| tst.ts:64:3:64:23 | obj.sim ... od(str) | TestClass.simpleMethod in global scope | simpleM ... ength } |
| tst.ts:65:3:65:24 | obj.gen ... od(str) | TestClass.genericMethod in global scope | generic ... rn x; } |
| tst.ts:66:3:66:24 | obj.gen ... od(num) | TestClass.genericMethod in global scope | generic ... rn x; } |
| tst.ts:67:3:67:27 | obj.ove ... od(num) | TestClass.overloadedMethod in global scope | overloa ... number; |
| tst.ts:67:3:67:27 | obj.ove ... od(num) | TestClass.overloadedMethod in global scope | overloa ... rn x; } |
| tst.ts:67:3:67:27 | obj.ove ... od(num) | TestClass.overloadedMethod in global scope | overloa ... string; |
| tst.ts:68:3:68:27 | obj.ove ... od(str) | TestClass.overloadedMethod in global scope | overloa ... number; |
| tst.ts:68:3:68:27 | obj.ove ... od(str) | TestClass.overloadedMethod in global scope | overloa ... rn x; } |
| tst.ts:68:3:68:27 | obj.ove ... od(str) | TestClass.overloadedMethod in global scope | overloa ... string; |
| tst.ts:69:3:69:36 | obj.gen ... ([num]) | TestClass.genericOverloadedMethod in global scope | generic ... T>): T; |
| tst.ts:69:3:69:36 | obj.gen ... ([num]) | TestClass.genericOverloadedMethod in global scope | generic ... []): T; |
| tst.ts:69:3:69:36 | obj.gen ... ([num]) | TestClass.genericOverloadedMethod in global scope | generic ... null; } |
| tst.ts:70:3:70:39 | obj.gen ... : str}) | TestClass.genericOverloadedMethod in global scope | generic ... T>): T; |
| tst.ts:70:3:70:39 | obj.gen ... : str}) | TestClass.genericOverloadedMethod in global scope | generic ... []): T; |
| tst.ts:70:3:70:39 | obj.gen ... : str}) | TestClass.genericOverloadedMethod in global scope | generic ... null; } |

View File

@@ -1,13 +1,15 @@
hasQualifiedNameModule
| default-import | default | tst.ts:11:9:11:21 | DefaultImport |
hasUnderlyingTypeModule
| default-import | | tst.ts:11:9:11:21 | DefaultImport |
| global | UnresolvedName | tst.ts:12:9:12:22 | UnresolvedName |
| import-assign | | tst.ts:10:9:10:11 | asn |
| import-assign | Foo | tst.ts:10:9:10:15 | asn.Foo |
| named-import | Name1 | tst.ts:7:9:7:13 | Name1 |
| named-import | Name1 | tst.ts:13:9:13:13 | Name1 |
| named-import | Name1 | tst.ts:13:9:13:21 | Name1<number> |
| named-import | Name2 | tst.ts:8:9:8:13 | Name2 |
| namespace-import | | tst.ts:9:9:9:17 | namespace |
| namespace-import | Foo | tst.ts:9:9:9:21 | namespace.Foo |
| tst.ts | ExportedClass | relative.ts:4:8:4:20 | ExportedClass |
hasQualifiedNameGlobal
hasUnderlyingTypeGlobal
| UnresolvedName | tst.ts:12:9:12:22 | UnresolvedName |
paramExample
| tst.ts:7:5:7:6 | x1 |

View File

@@ -1,13 +1,13 @@
import javascript
query TypeAnnotation hasQualifiedNameModule(string moduleName, string member) {
result.hasQualifiedName(moduleName, member)
query TypeAnnotation hasUnderlyingTypeModule(string moduleName, string member) {
result.hasUnderlyingType(moduleName, member)
}
query TypeAnnotation hasQualifiedNameGlobal(string globalName) {
result.hasQualifiedName(globalName)
query TypeAnnotation hasUnderlyingTypeGlobal(string globalName) {
result.hasUnderlyingType(globalName)
}
query Parameter paramExample() {
result.getTypeAnnotation().hasQualifiedName("named-import", "Name1")
result.getTypeAnnotation().hasUnderlyingType("named-import", "Name1")
}

View File

@@ -5,6 +5,6 @@
| tst.ts:8:14:8:16 | arg | Sub in global scope |
underlyingTypeNode
| foo | | file://:0:0:0:0 | use moduleImport("foo").getMember("exports") |
| foo | | file://:0:0:0:0 | use moduleImport("foo").getMember("exports").getMember("") |
| foo | | foo.ts:1:8:1:10 | use moduleImport("foo").getMember("exports").getMember("default") |
| foo | Bar | foo.ts:3:1:5:1 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |
| foo | Bar | foo.ts:3:12:3:12 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |

View File

@@ -0,0 +1,32 @@
import * as express from 'express';
function getRequest(): express.Request { }
function t1() {
getRequest(); // $ hasUnderlyingType='express'.Request
}
declare function getRequestAmbient(): express.Request;
function t2() {
getRequestAmbient(); // $ hasUnderlyingType='express'.Request
}
class C {
method(): express.Request { }
}
function t3(c: C) {
c.method(); // $ hasUnderlyingType='express'.Request
new C().method(); // $ hasUnderlyingType='express'.Request
}
function callback(fn: (req: express.Request) => void) { // $ SPURIOUS: hasUnderlyingType='express'.Request // req seems to be a SourceNode
}
function t4() {
callback(function (
req // $ hasUnderlyingType='express'.Request
) { }
);
}

View File

@@ -0,0 +1,5 @@
goog.declareModuleId("closure.es")
const Bar = goog.require('closure.reexported.Bar');
export { Bar }

View File

@@ -0,0 +1,3 @@
goog.module("closure.lib")
exports.Foo = goog.require('closure.reexported.Foo');

View File

@@ -0,0 +1,16 @@
goog.module("closure.use")
const lib = goog.require("closure.lib");
const es = goog.require("closure.es");
/**
* @param {lib.Foo} x
*/
function t1(x) { // $ hasUnderlyingType=closure.reexported.Foo hasUnderlyingType=closure.lib.Foo
}
/**
* @param {es.Bar} x
*/
function t2(x) { // $ hasUnderlyingType=closure.reexported.Bar hasUnderlyingType=closure.es.Bar
}

View File

@@ -0,0 +1,45 @@
import * as express from 'express';
interface Options {
handle(req: express.Request): void; // $ hasUnderlyingType='express'.Request
}
declare function doSomething(options: Options);
function t1() {
doSomething({
handle(req) { // $ hasUnderlyingType='express'.Request
}
});
}
function t2(callback: ((opts: Options) => void) | undefined) {
callback({
handle(req) { } // $ hasUnderlyingType='express'.Request
})
callback!({
handle(req) { } // $ hasUnderlyingType='express'.Request
})
}
function t3(): Options {
return {
handle(req) { } // $ hasUnderlyingType='express'.Request
}
}
function t4(): Options[] {
return [
{
handle(req) { } // $ hasUnderlyingType='express'.Request
}
]
}
async function t5(): Promise<Options> {
return {
handle(req) { // $ hasUnderlyingType='express'.Request
}
}
}

View File

@@ -0,0 +1 @@
export * from 'express';

View File

@@ -0,0 +1,7 @@
import { Request, Response } from './expressBulkExport';
function t1(req: Request) { // $ hasUnderlyingType='express'.Request
}
function t2(res: Response) { // $ hasUnderlyingType='express'.Response
}

View File

@@ -0,0 +1,2 @@
import E = require('express');
export = E;

View File

@@ -0,0 +1,4 @@
import { Request } from "./expressExportAssign";
function t1(req: Request) { // $ hasUnderlyingType='express'.Request
}

View File

@@ -0,0 +1,5 @@
import Express = require('express');
namespace Wrapper {
export import E = Express;
}
export = Wrapper;

View File

@@ -0,0 +1,4 @@
import { E } from "./expressExportAssignWrapper";
function t1(req: E.Request) { // $ hasUnderlyingType='express'.Request
}

View File

@@ -0,0 +1,2 @@
export { Request } from 'express';
export { Response as R } from 'express';

View File

@@ -0,0 +1,10 @@
import { Request, Response, R } from './expressSelectiveExport';
function t1(req: Request) { // $ hasUnderlyingType='express'.Request
}
function t2(res: Response) { // none, not exported
}
function t3(res: R) { // $ hasUnderlyingType='express'.Response
}

View File

@@ -0,0 +1 @@
export * as wrapper from 'express';

View File

@@ -0,0 +1,29 @@
import { Request, Response, wrapper } from './expressWrapperExport';
import * as w from './expressWrapperExport';
function t1(req: Request) { // none
}
function t2(res: Response) { // none
}
function t3(req: wrapper.Request) { // $ hasUnderlyingType='express'.Request
}
function t4(res: wrapper.Response) { // $ hasUnderlyingType='express'.Response
}
function t5(req: w.wrapper.Request) { // $ hasUnderlyingType='express'.Request
}
function t6(res: w.wrapper.Response) { // $ hasUnderlyingType='express'.Response
}
function t7(req: w.Request) { // none
}
function t8(res: w.Response) { // none
}
function t9(e: typeof w.wrapper) { // $ hasUnderlyingType='express'
}

View File

@@ -0,0 +1,46 @@
import * as express from 'express';
type Box1<T> = {
value: T;
other: string;
};
function t1(b: Box1<express.Request>) {
b.value; // $ MISSING: hasUnderlyingType='express'.Request
b.other;
}
interface Box2<T> {
value: T;
other: string;
}
function t2(b: Box2<express.Request>) {
b.value; // $ MISSING: hasUnderlyingType='express'.Request
b.other;
}
class Box3<T> {
value: T;
other: string;
}
function t3(b: Box3<express.Request>) {
b.value; // $ MISSING: hasUnderlyingType='express'.Request
b.other;
}
abstract class Box4<T> {
abstract getValue(): T;
abstract getOther(): string;
}
function t4(b: Box4<express.Request>) {
b.getValue(); // $ MISSING: hasUnderlyingType='express'.Request
b.getOther();
}
type Box5<T> = {
value: T & { blah: string };
other: string;
};
function t5(b: Box5<express.Request>) {
b.value; // $ MISSING: hasUnderlyingType='express'.Request
b.other;
}

View File

@@ -0,0 +1,10 @@
function t1(el: HTMLElement) { } // $ hasUnderlyingType=HTMLElement
/**
* @param {HTMLInputElement} el
*/
function t2(el) { // $ hasUnderlyingType=HTMLInputElement
}
function t3(req: Express.Request) { // $ hasUnderlyingType=Express.Request
}

View File

@@ -0,0 +1,14 @@
import * as e from 'express';
import { Response } from 'express';
/**
* @param {e.Request} req
*/
function t1(req) { // $ hasUnderlyingType='express'.Request
}
/**
* @param {Response} res
*/
function t2(res) { // $ hasUnderlyingType='express'.Response
}

View File

@@ -0,0 +1,4 @@
import { Request } from 'express';
function t1(req: Request) { // $ hasUnderlyingType='express'.Request
}

View File

@@ -0,0 +1,27 @@
import Express = require('express');
namespace A {
export import E = Express;
}
namespace B {
export import Q = A
}
namespace C {
import E = Express;
export const A = E;
}
function t1(x: A.E.Request) { // $ hasUnderlyingType='express'.Request
}
function t2(x: B.Q.E.Request) { // $ hasUnderlyingType='express'.Request
}
function t3(x: typeof Express) { // $ hasUnderlyingType='express'
}
function t4(x: typeof A.E) { // $ hasUnderlyingType='express'
}
function t5(x: typeof C.A) { // $ hasUnderlyingType='express'
}

View File

@@ -0,0 +1,15 @@
import * as express from 'express';
function t1(e: typeof express) { // $ hasUnderlyingType='express'
}
function t2(req: express.Request) { // $ hasUnderlyingType='express'.Request
}
function t3(req: Request) { // $ hasUnderlyingType=Request // not in scope, refers to a global
}
type E = typeof express;
function t4(e: E) { // $ hasUnderlyingType='express'
}

View File

@@ -0,0 +1,16 @@
import * as express from 'express';
interface Foo {
req: express.Request;
e: typeof express;
}
function t1(f: Foo) {
f.req; // $ hasUnderlyingType='express'.Request
f.e; // $ hasUnderlyingType='express'
const {
req, // $ hasUnderlyingType='express'.Request
e // $ hasUnderlyingType='express'
} = f;
}

View File

@@ -0,0 +1,20 @@
import * as express from 'express';
interface MyRequest extends express.Request {
}
function t1(req: MyRequest) { // $ hasUnderlyingType='express'.Request
}
class MyRequestClass extends express.Request {
}
function t2(req: MyRequestClass) { // $ hasUnderlyingType='express'.Request
}
class MyRequestClass2 implements express.Request {
}
function t3(req: MyRequestClass2) { // $ hasUnderlyingType='express'.Request
}

View File

@@ -0,0 +1,54 @@
| calls.ts:6:5:6:16 | getRequest() | 'express'.Request |
| calls.ts:12:5:12:23 | getRequestAmbient() | 'express'.Request |
| calls.ts:20:5:20:14 | c.method() | 'express'.Request |
| calls.ts:21:5:21:20 | new C().method() | 'express'.Request |
| calls.ts:24:24:24:26 | req | 'express'.Request |
| calls.ts:29:9:29:11 | req | 'express'.Request |
| closure.use.js:9:13:9:13 | x | closure.lib.Foo |
| closure.use.js:9:13:9:13 | x | closure.reexported.Foo |
| closure.use.js:15:13:15:13 | x | closure.es.Bar |
| closure.use.js:15:13:15:13 | x | closure.reexported.Bar |
| contextualTypes.ts:4:12:4:14 | req | 'express'.Request |
| contextualTypes.ts:11:16:11:18 | req | 'express'.Request |
| contextualTypes.ts:18:16:18:18 | req | 'express'.Request |
| contextualTypes.ts:21:16:21:18 | req | 'express'.Request |
| contextualTypes.ts:27:16:27:18 | req | 'express'.Request |
| contextualTypes.ts:34:20:34:22 | req | 'express'.Request |
| contextualTypes.ts:41:16:41:18 | req | 'express'.Request |
| expressBulkExport.use.ts:3:13:3:15 | req | 'express'.Request |
| expressBulkExport.use.ts:6:13:6:15 | res | 'express'.Response |
| expressExportAssign.use.ts:3:13:3:15 | req | 'express'.Request |
| expressExportAssignWrapper.use.ts:3:13:3:15 | req | 'express'.Request |
| expressSelectiveExport.use.ts:3:13:3:15 | req | 'express'.Request |
| expressSelectiveExport.use.ts:9:13:9:15 | res | 'express'.Response |
| expressWrapperExport.use.ts:10:13:10:15 | req | 'express'.Request |
| expressWrapperExport.use.ts:13:13:13:15 | res | 'express'.Response |
| expressWrapperExport.use.ts:16:13:16:15 | req | 'express'.Request |
| expressWrapperExport.use.ts:19:13:19:15 | res | 'express'.Response |
| expressWrapperExport.use.ts:28:13:28:13 | e | 'express' |
| globals.ts:1:13:1:14 | el | HTMLElement |
| globals.ts:6:13:6:14 | el | HTMLInputElement |
| globals.ts:9:13:9:15 | req | Express.Request |
| jsdoc.js:7:13:7:15 | req | 'express'.Request |
| jsdoc.js:13:13:13:15 | res | 'express'.Response |
| namedImport.ts:3:13:3:15 | req | 'express'.Request |
| namespaceDecls.ts:14:13:14:13 | x | 'express'.Request |
| namespaceDecls.ts:17:13:17:13 | x | 'express'.Request |
| namespaceDecls.ts:20:13:20:13 | x | 'express' |
| namespaceDecls.ts:23:13:23:13 | x | 'express' |
| namespaceDecls.ts:26:13:26:13 | x | 'express' |
| namespaceImport.ts:3:13:3:13 | e | 'express' |
| namespaceImport.ts:6:13:6:15 | req | 'express'.Request |
| namespaceImport.ts:9:13:9:15 | req | Request |
| namespaceImport.ts:14:13:14:13 | e | 'express' |
| props.ts:9:5:9:9 | f.req | 'express'.Request |
| props.ts:10:5:10:7 | f.e | 'express' |
| props.ts:13:9:13:11 | req | 'express'.Request |
| props.ts:14:9:14:9 | e | 'express' |
| subtype.ts:7:13:7:15 | req | 'express'.Request |
| subtype.ts:13:13:13:15 | req | 'express'.Request |
| subtype.ts:19:13:19:15 | req | 'express'.Request |
| typeCast.ts:4:16:4:35 | e as express.Request | 'express'.Request |
| typeCast.ts:5:16:5:33 | <express.Request>e | 'express'.Request |
| typeCast.ts:6:16:6:42 | e satis ... Request | 'express'.Request |
| varAssignment.ts:4:9:4:11 | req | 'express'.Request |

View File

@@ -0,0 +1,15 @@
import javascript
bindingset[x, y]
private string join(string x, string y) {
if x = "" or y = "" then result = x + y else result = x + "." + y
}
query predicate hasUnderlyingType(DataFlow::SourceNode node, string value) {
node.hasUnderlyingType(value)
or
exists(string mod, string name |
node.hasUnderlyingType(mod, name) and
value = join("'" + mod + "'", name)
)
}

View File

@@ -0,0 +1,2 @@
query: test.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,3 @@
{
"include": ["."]
}

View File

@@ -0,0 +1,7 @@
import * as express from 'express';
function t1(e) {
var req1 = e as express.Request; // $ hasUnderlyingType='express'.Request
var req2 = <express.Request>e; // $ hasUnderlyingType='express'.Request
var req3 = e satisfies express.Request; // $ hasUnderlyingType='express'.Request
}

View File

@@ -0,0 +1,5 @@
import * as express from 'express';
function t1(e) {
var req: express.Request = e; // $ hasUnderlyingType='express'.Request
}

View File

@@ -71,6 +71,9 @@ responseSendArgument
| local/customPipe.ts:37:16:37:31 | '' + unsanitized |
| local/customPipe.ts:42:16:42:31 | '' + unsanitized |
| local/customPipe.ts:48:16:48:31 | '' + unsanitized |
| local/routes.ts:7:12:7:16 | 'foo' |
| local/routes.ts:12:12:12:16 | 'foo' |
| local/routes.ts:17:12:17:16 | 'foo' |
| local/routes.ts:32:31:32:31 | x |
| local/routes.ts:33:31:33:38 | queryObj |
| local/routes.ts:34:31:34:34 | name |

View File

@@ -62,6 +62,8 @@
| dragAndDrop.ts:73:29:73:39 | droppedHtml | dragAndDrop.ts:71:27:71:61 | e.dataT ... /html') | dragAndDrop.ts:73:29:73:39 | droppedHtml | Cross-site scripting vulnerability due to $@. | dragAndDrop.ts:71:27:71:61 | e.dataT ... /html') | user-provided value |
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | Cross-site scripting vulnerability due to $@. | event-handler-receiver.js:2:49:2:61 | location.href | user-provided value |
| express.js:6:15:6:33 | req.param("wobble") | express.js:6:15:6:33 | req.param("wobble") | express.js:6:15:6:33 | req.param("wobble") | Cross-site scripting vulnerability due to $@. | express.js:6:15:6:33 | req.param("wobble") | user-provided value |
| jquery-declare-any.ts:6:7:6:17 | window.name | jquery-declare-any.ts:6:7:6:17 | window.name | jquery-declare-any.ts:6:7:6:17 | window.name | Cross-site scripting vulnerability due to $@. | jquery-declare-any.ts:6:7:6:17 | window.name | user-provided value |
| jquery-declare-type.ts:6:7:6:17 | window.name | jquery-declare-type.ts:6:7:6:17 | window.name | jquery-declare-type.ts:6:7:6:17 | window.name | Cross-site scripting vulnerability due to $@. | jquery-declare-type.ts:6:7:6:17 | window.name | user-provided value |
| jquery.js:7:5:7:34 | "<div i ... + "\\">" | jquery.js:2:17:2:40 | documen ... .search | jquery.js:7:5:7:34 | "<div i ... + "\\">" | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:40 | documen ... .search | user-provided value |
| jquery.js:8:18:8:34 | "XSS: " + tainted | jquery.js:2:17:2:40 | documen ... .search | jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:40 | documen ... .search | user-provided value |
| jquery.js:10:5:10:40 | "<b>" + ... "</b>" | jquery.js:10:13:10:20 | location | jquery.js:10:5:10:40 | "<b>" + ... "</b>" | Cross-site scripting vulnerability due to $@. | jquery.js:10:13:10:20 | location | user-provided value |
@@ -954,6 +956,8 @@ nodes
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | semmle.label | '<h2><a ... ></h2>' |
| event-handler-receiver.js:2:49:2:61 | location.href | semmle.label | location.href |
| express.js:6:15:6:33 | req.param("wobble") | semmle.label | req.param("wobble") |
| jquery-declare-any.ts:6:7:6:17 | window.name | semmle.label | window.name |
| jquery-declare-type.ts:6:7:6:17 | window.name | semmle.label | window.name |
| jquery.js:2:7:2:40 | tainted | semmle.label | tainted |
| jquery.js:2:17:2:40 | documen ... .search | semmle.label | documen ... .search |
| jquery.js:4:5:4:11 | tainted | semmle.label | tainted |

View File

@@ -182,6 +182,8 @@ nodes
| hana.js:85:35:85:54 | tableRows[0].comment | semmle.label | tableRows[0].comment |
| hana.js:90:33:90:34 | rs | semmle.label | rs |
| hana.js:90:33:90:45 | rs[0].comment | semmle.label | rs[0].comment |
| jquery-declare-any.ts:6:7:6:17 | window.name | semmle.label | window.name |
| jquery-declare-type.ts:6:7:6:17 | window.name | semmle.label | window.name |
| jquery.js:2:7:2:40 | tainted | semmle.label | tainted |
| jquery.js:2:17:2:40 | documen ... .search | semmle.label | documen ... .search |
| jquery.js:4:5:4:11 | tainted | semmle.label | tainted |

View File

@@ -0,0 +1,7 @@
import 'dummy';
declare var $: any;
function t() {
$(window.name); // $ Alert
}

View File

@@ -0,0 +1,7 @@
import 'dummy';
declare var $: JQueryStatic;
function t() {
$(window.name); // $ Alert
}

View File

@@ -22,7 +22,6 @@
| main.js:111:37:111:37 | x | main.js:98:43:98:43 | x | main.js:111:37:111:37 | x | This markdown rendering which depends on $@ might later allow $@. | main.js:98:43:98:43 | x | library input | main.js:112:24:112:26 | svg | cross-site scripting |
| main.js:117:34:117:34 | s | main.js:116:47:116:47 | s | main.js:117:34:117:34 | s | This markdown rendering which depends on $@ might later allow $@. | main.js:116:47:116:47 | s | library input | main.js:118:53:118:56 | html | cross-site scripting |
| typed.ts:2:29:2:29 | s | typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | typed.ts:1:39:1:39 | s | library input | typed.ts:3:31:3:34 | html | cross-site scripting |
| typed.ts:8:40:8:40 | s | typed.ts:6:43:6:43 | s | typed.ts:8:40:8:40 | s | This HTML construction which depends on $@ might later allow $@. | typed.ts:6:43:6:43 | s | library input | typed.ts:8:29:8:52 | "<span> ... /span>" | cross-site scripting |
edges
| jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff | provenance | |
| jquery-plugin.js:11:34:11:40 | options | jquery-plugin.js:12:31:12:37 | options | provenance | |
@@ -69,7 +68,6 @@ edges
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x | provenance | |
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s | provenance | |
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s | provenance | |
| typed.ts:6:43:6:43 | s | typed.ts:8:40:8:40 | s | provenance | |
nodes
| jquery-plugin.js:11:27:11:31 | stuff | semmle.label | stuff |
| jquery-plugin.js:11:34:11:40 | options | semmle.label | options |
@@ -128,6 +126,4 @@ nodes
| main.js:117:34:117:34 | s | semmle.label | s |
| typed.ts:1:39:1:39 | s | semmle.label | s |
| typed.ts:2:29:2:29 | s | semmle.label | s |
| typed.ts:6:43:6:43 | s | semmle.label | s |
| typed.ts:8:40:8:40 | s | semmle.label | s |
subpaths

View File

@@ -3,9 +3,9 @@ export function basicHtmlConstruction(s: string) { // $ Source
document.body.innerHTML = html;
}
export function insertIntoCreatedDocument(s: string) { // $ Source
export function insertIntoCreatedDocument(s: string) {
const newDoc = document.implementation.createHTMLDocument("");
newDoc.body.innerHTML = "<span>" + s + "</span>"; // $ SPURIOUS: Alert - inserted into document disconnected from the main DOM.
newDoc.body.innerHTML = "<span>" + s + "</span>"; // OK - inserted into document disconnected from the main DOM.
}
export function id(s: string) {
@@ -17,4 +17,3 @@ export function notVulnerable() {
const html = "<span>" + s + "</span>";
document.body.innerHTML = html;
}

View File

@@ -1,36 +1,36 @@
| b.js:3:3:3:3 | x | b.js:2:7:2:7 | x | V |
| b.js:7:1:7:1 | f | b.js:1:1:5:1 | functio ... ar x;\\n} | M |
| b.js:8:1:8:1 | g | a.js:2:1:2:15 | function g() {} | M |
| b.js:7:1:7:1 | f | b.js:1:10:1:10 | f | M |
| b.js:8:1:8:1 | g | a.js:2:10:2:10 | g | M |
| client.ts:1:22:1:30 | "./tslib" | tslib.ts:1:1:10:0 | <toplevel> | I |
| client.ts:7:19:7:19 | C | tslib.ts:1:8:3:1 | class C {\\n m() {}\\n} | T |
| client.ts:8:10:8:10 | C | client.ts:3:1:5:1 | class C {\\n m() {}\\n} | T |
| client.ts:9:16:9:16 | C | client.ts:3:1:5:1 | class C {\\n m() {}\\n} | T |
| client.ts:10:16:10:16 | C | tslib.ts:6:10:8:3 | class C ... {}\\n } | T |
| client.ts:13:25:13:25 | C | client.ts:3:1:5:1 | class C {\\n m() {}\\n} | T |
| client.ts:13:35:13:35 | C | tslib.ts:1:8:3:1 | class C {\\n m() {}\\n} | T |
| client.ts:13:47:13:47 | C | tslib.ts:6:10:8:3 | class C ... {}\\n } | T |
| client.ts:7:19:7:19 | C | tslib.ts:1:14:1:14 | C | T |
| client.ts:8:10:8:10 | C | client.ts:3:7:3:7 | C | T |
| client.ts:9:16:9:16 | C | client.ts:3:7:3:7 | C | T |
| client.ts:10:16:10:16 | C | tslib.ts:6:16:6:16 | C | T |
| client.ts:13:25:13:25 | C | client.ts:3:7:3:7 | C | T |
| client.ts:13:35:13:35 | C | tslib.ts:1:14:1:14 | C | T |
| client.ts:13:47:13:47 | C | tslib.ts:6:16:6:16 | C | T |
| client.ts:14:3:14:3 | x | client.ts:13:22:13:22 | x | V |
| client.ts:14:5:14:5 | m | client.ts:4:3:4:8 | m() {} | M |
| client.ts:14:5:14:5 | m | client.ts:4:3:4:3 | m | M |
| client.ts:15:3:15:3 | y | client.ts:13:28:13:28 | y | V |
| client.ts:15:5:15:5 | m | tslib.ts:2:3:2:8 | m() {} | M |
| client.ts:15:5:15:5 | m | tslib.ts:2:3:2:3 | m | M |
| client.ts:16:3:16:3 | z | client.ts:13:38:13:38 | z | V |
| client.ts:16:5:16:5 | m | tslib.ts:7:5:7:10 | m() {} | M |
| client.ts:16:5:16:5 | m | tslib.ts:7:5:7:5 | m | M |
| d.js:1:17:1:21 | './c' | c.js:1:1:1:20 | <toplevel> | I |
| d.js:10:1:10:1 | A | d.js:7:1:9:1 | functio ... = 42;\\n} | V |
| d.js:16:19:16:23 | Super | d.js:12:1:14:1 | class S ... () {}\\n} | V |
| d.js:10:1:10:1 | A | d.js:7:10:7:10 | A | V |
| d.js:16:19:16:23 | Super | d.js:12:7:12:11 | Super | V |
| d.js:16:25:16:24 | args | d.js:16:25:16:24 | args | V |
| d.js:20:1:20:1 | o | d.js:3:9:5:1 | {\\n f: ... () {}\\n} | V |
| d.js:20:3:20:3 | f | d.js:4:3:4:18 | f: function() {} | M |
| d.js:22:13:22:13 | A | d.js:7:1:9:1 | functio ... = 42;\\n} | M |
| d.js:22:13:22:13 | A | d.js:7:10:7:10 | A | M |
| d.js:23:1:23:1 | a | d.js:22:5:22:5 | a | V |
| d.js:23:3:23:3 | x | d.js:8:3:8:8 | this.x | M |
| d.js:24:1:24:1 | a | d.js:22:5:22:5 | a | V |
| d.js:24:3:24:3 | g | d.js:10:1:10:13 | A.prototype.g | M |
| d.js:26:13:26:15 | Sub | d.js:16:1:18:1 | class S ... () {}\\n} | M |
| d.js:26:13:26:15 | Sub | d.js:16:7:16:9 | Sub | M |
| d.js:27:1:27:1 | x | d.js:26:5:26:5 | x | V |
| d.js:27:3:27:3 | m | d.js:13:3:13:3 | m | M |
| d.js:28:1:28:1 | x | d.js:26:5:26:5 | x | V |
| d.js:28:3:28:3 | n | d.js:17:3:17:3 | n | M |
| tst.js:1:19:1:23 | './m' | m.js:1:1:2:0 | <toplevel> | I |
| tst.js:3:5:3:5 | A | m.js:1:8:1:17 | class A {} | M |
| tst.js:3:5:3:5 | A | m.js:1:14:1:14 | A | M |
| tst.js:5:15:5:19 | './m' | m.js:1:1:2:0 | <toplevel> | I |