From 7f939fe1e41ff8d191ed2dbbd873457b2c69a9b4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 6 Feb 2020 11:32:10 +0000 Subject: [PATCH 01/13] TS: Update to TypeScript 3.8.2 --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index f1f82f91f25..55994647a94 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "3.7.5" + "typescript": "3.8.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 4562b05a011..5afdf469e36 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -225,9 +225,9 @@ tsutils@^2.12.1: dependencies: tslib "^1.8.1" -typescript@3.7.5: - version "3.7.5" - resolved "typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" +typescript@3.8.2: + version "3.8.2" + resolved typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a wrappy@1: version "1.0.2" From 9b52acc62ac167d606ac96055d8201548458792a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 6 Feb 2020 16:26:16 +0000 Subject: [PATCH 02/13] TS: Handle export * as ns --- .../js/parser/TypeScriptASTConverter.java | 18 +++++++++++++----- .../ExportNamespaceSpecifier/client.ts | 3 +++ .../TypeScript/ExportNamespaceSpecifier/lib.ts | 1 + .../ExportNamespaceSpecifier/reexport.ts | 1 + .../ExportNamespaceSpecifier/test.expected | 1 + .../ExportNamespaceSpecifier/test.ql | 3 +++ 6 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 1b0e5421497..c4dbf02aa3a 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -34,6 +34,7 @@ import com.semmle.js.ast.ExportAllDeclaration; import com.semmle.js.ast.ExportDeclaration; import com.semmle.js.ast.ExportDefaultDeclaration; import com.semmle.js.ast.ExportNamedDeclaration; +import com.semmle.js.ast.ExportNamespaceSpecifier; import com.semmle.js.ast.ExportSpecifier; import com.semmle.js.ast.Expression; import com.semmle.js.ast.ExpressionStatement; @@ -507,6 +508,8 @@ public class TypeScriptASTConverter { return convertNamespaceDeclaration(node, loc); case "ModuleBlock": return convertModuleBlock(node, loc); + case "NamespaceExport": + return convertNamespaceExport(node, loc); case "NamespaceExportDeclaration": return convertNamespaceExportDeclaration(node, loc); case "NamespaceImport": @@ -1170,11 +1173,11 @@ public class TypeScriptASTConverter { private Node convertExportDeclaration(JsonObject node, SourceLocation loc) throws ParseError { Literal source = tryConvertChild(node, "moduleSpecifier", Literal.class); if (hasChild(node, "exportClause")) { - return new ExportNamedDeclaration( - loc, - null, - convertChildren(node.get("exportClause").getAsJsonObject(), "elements"), - source); + List specifiers = + hasKind(node.get("exportClause"), "NamespaceExport") + ? Collections.singletonList(convertChild(node, "exportClause")) + : convertChildren(node.get("exportClause").getAsJsonObject(), "elements"); + return new ExportNamedDeclaration(loc, null, specifiers, source); } else { return new ExportAllDeclaration(loc, source); } @@ -1187,6 +1190,11 @@ public class TypeScriptASTConverter { convertChild(node, "name")); } + private Node convertNamespaceExport(JsonObject node, SourceLocation loc) throws ParseError { + // Convert the "* as ns" from an export declaration. + return new ExportNamespaceSpecifier(loc, convertChild(node, "name")); + } + private Node convertExpressionStatement(JsonObject node, SourceLocation loc) throws ParseError { Expression expression = convertChild(node, "expression"); return new ExpressionStatement(loc, expression); diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts new file mode 100644 index 00000000000..b4004f7005b --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts @@ -0,0 +1,3 @@ +import { ns } from "./reexport"; + +ns.foo(); diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts new file mode 100644 index 00000000000..f99d4277774 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts @@ -0,0 +1 @@ +export function foo() {} diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts new file mode 100644 index 00000000000..19c4b621498 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts @@ -0,0 +1 @@ +export * as ns from "./lib"; diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected new file mode 100644 index 00000000000..6403f1793a4 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected @@ -0,0 +1 @@ +| reexport.ts:1:13:1:14 | ns | diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql new file mode 100644 index 00000000000..44f3f9d7fd4 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql @@ -0,0 +1,3 @@ +import javascript + +query ExportNamespaceSpecifier test_ExportNamespaceSpecifier() { any() } From 8531c113a1982d245e23b2f2eca0065e37152e12 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 6 Feb 2020 16:48:19 +0000 Subject: [PATCH 03/13] TS: Fix imports --- .../semmle/js/parser/TypeScriptASTConverter.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index c4dbf02aa3a..b6bd5041a48 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -1,5 +1,13 @@ package com.semmle.js.parser; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -145,13 +153,6 @@ import com.semmle.ts.ast.UnaryTypeExpr; import com.semmle.ts.ast.UnionTypeExpr; import com.semmle.util.collections.CollectionUtil; import com.semmle.util.data.IntList; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Utility class for converting a Date: Thu, 6 Feb 2020 16:49:40 +0000 Subject: [PATCH 04/13] TS: Add test and documentation for private fields --- .../js/parser/TypeScriptASTConverter.java | 7 +- .../extractor/tests/ts/input/privateField.ts | 6 + .../tests/ts/output/trap/privateField.ts.trap | 273 ++++++++++++++++++ .../TypeScript/PrivateFields/test.expected | 5 + .../TypeScript/PrivateFields/test.ql | 9 + .../TypeScript/PrivateFields/tst.ts | 8 + 6 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 javascript/extractor/tests/ts/input/privateField.ts create mode 100644 javascript/extractor/tests/ts/output/trap/privateField.ts.trap create mode 100644 javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index b6bd5041a48..8299abebe8b 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -336,7 +336,11 @@ public class TypeScriptASTConverter { private Node convertNodeUntyped(JsonObject node, String defaultKind) throws ParseError { String kind = getKind(node); if (kind == null) kind = defaultKind; - if (kind == null) kind = "Identifier"; + if (kind == null) { + // Identifiers and PrivateIdentifiers do not have a "kind" property like other nodes. + // Since we encode identifiers and private identifiers the same, default to Identifier. + kind = "Identifier"; + } SourceLocation loc = getSourceLocation(node); switch (kind) { case "AnyKeyword": @@ -443,6 +447,7 @@ public class TypeScriptASTConverter { case "FunctionType": return convertFunctionType(node, loc); case "Identifier": + case "PrivateIdentifier": return convertIdentifier(node, loc); case "IfStatement": return convertIfStatement(node, loc); diff --git a/javascript/extractor/tests/ts/input/privateField.ts b/javascript/extractor/tests/ts/input/privateField.ts new file mode 100644 index 00000000000..a6cd745260c --- /dev/null +++ b/javascript/extractor/tests/ts/input/privateField.ts @@ -0,0 +1,6 @@ +class C { + #foo; + constructor() { + this.#foo = 5; + } +} diff --git a/javascript/extractor/tests/ts/output/trap/privateField.ts.trap b/javascript/extractor/tests/ts/output/trap/privateField.ts.trap new file mode 100644 index 00000000000..97567d63457 --- /dev/null +++ b/javascript/extractor/tests/ts/output/trap/privateField.ts.trap @@ -0,0 +1,273 @@ +#10000=@"/privateField.ts;sourcefile" +files(#10000,"/privateField.ts","privateField","ts",0) +#10001=@"/;folder" +folders(#10001,"/","") +containerparent(#10001,#10000) +#10002=@"loc,{#10000},0,0,0,0" +locations_default(#10002,#10000,0,0,0,0) +hasLocation(#10000,#10002) +#20000=@"global_scope" +scopes(#20000,0) +#20001=@"script;{#10000},1,1" +#20002=* +lines(#20002,#20001,"class C {"," +") +#20003=@"loc,{#10000},1,1,1,9" +locations_default(#20003,#10000,1,1,1,9) +hasLocation(#20002,#20003) +#20004=* +lines(#20004,#20001," #foo;"," +") +#20005=@"loc,{#10000},2,1,2,6" +locations_default(#20005,#10000,2,1,2,6) +hasLocation(#20004,#20005) +indentation(#10000,2," ",1) +#20006=* +lines(#20006,#20001," constructor() {"," +") +#20007=@"loc,{#10000},3,1,3,16" +locations_default(#20007,#10000,3,1,3,16) +hasLocation(#20006,#20007) +indentation(#10000,3," ",1) +#20008=* +lines(#20008,#20001," this.#foo = 5;"," +") +#20009=@"loc,{#10000},4,1,4,17" +locations_default(#20009,#10000,4,1,4,17) +hasLocation(#20008,#20009) +indentation(#10000,4," ",3) +#20010=* +lines(#20010,#20001," }"," +") +#20011=@"loc,{#10000},5,1,5,2" +locations_default(#20011,#10000,5,1,5,2) +hasLocation(#20010,#20011) +indentation(#10000,5," ",1) +#20012=* +lines(#20012,#20001,"}"," +") +#20013=@"loc,{#10000},6,1,6,1" +locations_default(#20013,#10000,6,1,6,1) +hasLocation(#20012,#20013) +numlines(#20001,6,6,0) +#20014=* +tokeninfo(#20014,7,#20001,0,"class") +#20015=@"loc,{#10000},1,1,1,5" +locations_default(#20015,#10000,1,1,1,5) +hasLocation(#20014,#20015) +#20016=* +tokeninfo(#20016,6,#20001,1,"C") +#20017=@"loc,{#10000},1,7,1,7" +locations_default(#20017,#10000,1,7,1,7) +hasLocation(#20016,#20017) +#20018=* +tokeninfo(#20018,8,#20001,2,"{") +#20019=@"loc,{#10000},1,9,1,9" +locations_default(#20019,#10000,1,9,1,9) +hasLocation(#20018,#20019) +#20020=* +tokeninfo(#20020,8,#20001,3,";") +#20021=@"loc,{#10000},2,6,2,6" +locations_default(#20021,#10000,2,6,2,6) +hasLocation(#20020,#20021) +#20022=* +tokeninfo(#20022,7,#20001,4,"constructor") +#20023=@"loc,{#10000},3,2,3,12" +locations_default(#20023,#10000,3,2,3,12) +hasLocation(#20022,#20023) +#20024=* +tokeninfo(#20024,8,#20001,5,"(") +#20025=@"loc,{#10000},3,13,3,13" +locations_default(#20025,#10000,3,13,3,13) +hasLocation(#20024,#20025) +#20026=* +tokeninfo(#20026,8,#20001,6,")") +#20027=@"loc,{#10000},3,14,3,14" +locations_default(#20027,#10000,3,14,3,14) +hasLocation(#20026,#20027) +#20028=* +tokeninfo(#20028,8,#20001,7,"{") +#20029=@"loc,{#10000},3,16,3,16" +locations_default(#20029,#10000,3,16,3,16) +hasLocation(#20028,#20029) +#20030=* +tokeninfo(#20030,7,#20001,8,"this") +#20031=@"loc,{#10000},4,4,4,7" +locations_default(#20031,#10000,4,4,4,7) +hasLocation(#20030,#20031) +#20032=* +tokeninfo(#20032,8,#20001,9,".") +#20033=@"loc,{#10000},4,8,4,8" +locations_default(#20033,#10000,4,8,4,8) +hasLocation(#20032,#20033) +#20034=* +tokeninfo(#20034,8,#20001,10,"=") +#20035=@"loc,{#10000},4,14,4,14" +locations_default(#20035,#10000,4,14,4,14) +hasLocation(#20034,#20035) +#20036=* +tokeninfo(#20036,3,#20001,11,"5") +#20037=@"loc,{#10000},4,16,4,16" +locations_default(#20037,#10000,4,16,4,16) +hasLocation(#20036,#20037) +#20038=* +tokeninfo(#20038,8,#20001,12,";") +#20039=@"loc,{#10000},4,17,4,17" +locations_default(#20039,#10000,4,17,4,17) +hasLocation(#20038,#20039) +#20040=* +tokeninfo(#20040,8,#20001,13,"}") +#20041=@"loc,{#10000},5,2,5,2" +locations_default(#20041,#10000,5,2,5,2) +hasLocation(#20040,#20041) +#20042=* +tokeninfo(#20042,8,#20001,14,"}") +hasLocation(#20042,#20013) +#20043=* +tokeninfo(#20043,0,#20001,15,"") +#20044=@"loc,{#10000},7,1,7,0" +locations_default(#20044,#10000,7,1,7,0) +hasLocation(#20043,#20044) +toplevels(#20001,0) +#20045=@"loc,{#10000},1,1,7,0" +locations_default(#20045,#10000,1,1,7,0) +hasLocation(#20001,#20045) +#20046=@"var;{C};{#20000}" +variables(#20046,"C",#20000) +#20047=@"local_type_name;{C};{#20000}" +local_type_names(#20047,"C",#20000) +#20048=* +stmts(#20048,26,#20001,0,"class C ... 5;\n }\n}") +#20049=@"loc,{#10000},1,1,6,1" +locations_default(#20049,#10000,1,1,6,1) +hasLocation(#20048,#20049) +stmtContainers(#20048,#20001) +#20050=* +exprs(#20050,78,#20048,0,"C") +hasLocation(#20050,#20017) +enclosingStmt(#20050,#20048) +exprContainers(#20050,#20001) +literals("C","C",#20050) +decl(#20050,#20046) +typedecl(#20050,#20047) +#20051=* +scopes(#20051,10) +scopenodes(#20048,#20051) +scopenesting(#20051,#20000) +#20052=* +properties(#20052,#20048,2,8,"#foo;") +#20053=@"loc,{#10000},2,2,2,6" +locations_default(#20053,#10000,2,2,2,6) +hasLocation(#20052,#20053) +#20054=* +#20055=* +exprs(#20055,0,#20052,0,"#foo") +#20056=@"loc,{#10000},2,2,2,5" +locations_default(#20056,#10000,2,2,2,5) +hasLocation(#20055,#20056) +exprContainers(#20055,#20054) +literals("#foo","#foo",#20055) +#20057=* +properties(#20057,#20048,3,0,"constru ... = 5;\n }") +#20058=@"loc,{#10000},3,2,5,2" +locations_default(#20058,#10000,3,2,5,2) +hasLocation(#20057,#20058) +#20059=* +exprs(#20059,0,#20057,0,"constru ... = 5;\n }") +hasLocation(#20059,#20058) +enclosingStmt(#20059,#20048) +exprContainers(#20059,#20001) +literals("constructor","constructor",#20059) +exprs(#20054,9,#20057,1,"constru ... = 5;\n }") +hasLocation(#20054,#20058) +enclosingStmt(#20054,#20048) +exprContainers(#20054,#20001) +#20060=* +scopes(#20060,1) +scopenodes(#20054,#20060) +scopenesting(#20060,#20051) +#20061=@"var;{arguments};{#20060}" +variables(#20061,"arguments",#20060) +isArgumentsObject(#20061) +#20062=* +stmts(#20062,1,#20054,-2,"{\n th ... = 5;\n }") +#20063=@"loc,{#10000},3,16,5,2" +locations_default(#20063,#10000,3,16,5,2) +hasLocation(#20062,#20063) +stmtContainers(#20062,#20054) +#20064=* +stmts(#20064,2,#20062,0,"this.#foo = 5;") +#20065=@"loc,{#10000},4,4,4,17" +locations_default(#20065,#10000,4,4,4,17) +hasLocation(#20064,#20065) +stmtContainers(#20064,#20054) +#20066=* +exprs(#20066,47,#20064,0,"this.#foo = 5") +#20067=@"loc,{#10000},4,4,4,16" +locations_default(#20067,#10000,4,4,4,16) +hasLocation(#20066,#20067) +enclosingStmt(#20066,#20064) +exprContainers(#20066,#20054) +#20068=* +exprs(#20068,14,#20066,0,"this.#foo") +#20069=@"loc,{#10000},4,4,4,12" +locations_default(#20069,#10000,4,4,4,12) +hasLocation(#20068,#20069) +enclosingStmt(#20068,#20064) +exprContainers(#20068,#20054) +#20070=* +exprs(#20070,6,#20068,0,"this") +hasLocation(#20070,#20031) +enclosingStmt(#20070,#20064) +exprContainers(#20070,#20054) +#20071=* +exprs(#20071,0,#20068,1,"#foo") +#20072=@"loc,{#10000},4,9,4,12" +locations_default(#20072,#10000,4,9,4,12) +hasLocation(#20071,#20072) +enclosingStmt(#20071,#20064) +exprContainers(#20071,#20054) +literals("#foo","#foo",#20071) +#20073=* +exprs(#20073,3,#20066,1,"5") +hasLocation(#20073,#20037) +enclosingStmt(#20073,#20064) +exprContainers(#20073,#20054) +literals("5","5",#20073) +isMethod(#20057) +#20074=* +entry_cfg_node(#20074,#20001) +#20075=@"loc,{#10000},1,1,1,0" +locations_default(#20075,#10000,1,1,1,0) +hasLocation(#20074,#20075) +#20076=* +exit_cfg_node(#20076,#20001) +hasLocation(#20076,#20044) +successor(#20055,#20052) +successor(#20054,#20057) +#20077=* +entry_cfg_node(#20077,#20054) +#20078=@"loc,{#10000},3,2,3,1" +locations_default(#20078,#10000,3,2,3,1) +hasLocation(#20077,#20078) +successor(#20052,#20062) +#20079=* +exit_cfg_node(#20079,#20054) +#20080=@"loc,{#10000},5,3,5,2" +locations_default(#20080,#10000,5,3,5,2) +hasLocation(#20079,#20080) +successor(#20062,#20064) +successor(#20064,#20070) +successor(#20073,#20066) +successor(#20071,#20068) +successor(#20070,#20071) +successor(#20068,#20073) +successor(#20066,#20079) +successor(#20077,#20055) +successor(#20059,#20054) +successor(#20057,#20048) +successor(#20050,#20059) +successor(#20048,#20076) +successor(#20074,#20050) +numlines(#10000,6,6,0) +filetype(#10000,"typescript") diff --git a/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected new file mode 100644 index 00000000000..fc28ada4ff9 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected @@ -0,0 +1,5 @@ +propAccess +| #privateField | tst.ts:5:9:5:26 | this.#privateField | +| #privateField | tst.ts:6:9:6:26 | this.#privateField | +fieldDecl +| #privateField | tst.ts:2:5:2:23 | #privateField: any; | diff --git a/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql new file mode 100644 index 00000000000..27147fcb461 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql @@ -0,0 +1,9 @@ +import javascript + +query PropAccess propAccess(string name) { + result.getPropertyName() = name +} + +query FieldDeclaration fieldDecl(string name) { + result.getName() = name +} diff --git a/javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts b/javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts new file mode 100644 index 00000000000..9e2dbdca644 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts @@ -0,0 +1,8 @@ +class C { + #privateField: any; + + constructor(x: any) { + this.#privateField = x; + this.#privateField(y); + } +} From 8d58aad0f2b389f6e3e6be20e7013ea2e20d3dbc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 16:25:49 +0000 Subject: [PATCH 05/13] TS: Support type-only import/export --- .../semmle/js/ast/ExportNamedDeclaration.java | 13 ++++++ .../com/semmle/js/ast/ImportDeclaration.java | 15 ++++++- .../com/semmle/js/extractor/ASTExtractor.java | 44 +++++++++++++++++-- .../com/semmle/js/extractor/ExprKinds.java | 9 ++-- .../js/parser/TypeScriptASTConverter.java | 7 ++- javascript/ql/src/semmle/javascript/AST.qll | 2 +- .../src/semmle/javascript/ES2015Modules.qll | 32 ++++++++++++++ .../ql/src/semmlecode.javascript.dbscheme | 3 ++ .../TypeOnlyImportExport/test.expected | 6 +++ .../TypeScript/TypeOnlyImportExport/test.ql | 13 ++++++ .../TypeScript/TypeOnlyImportExport/tst.ts | 5 +++ 11 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts diff --git a/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java b/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java index c70ed56b30a..d4d19b8d1ab 100644 --- a/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java +++ b/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java @@ -15,13 +15,21 @@ public class ExportNamedDeclaration extends ExportDeclaration { private final Statement declaration; private final List specifiers; private final Literal source; + private final boolean hasTypeKeyword; public ExportNamedDeclaration( SourceLocation loc, Statement declaration, List specifiers, Literal source) { + this(loc, declaration, specifiers, source, false); + } + + public ExportNamedDeclaration( + SourceLocation loc, Statement declaration, List specifiers, Literal source, + boolean hasTypeKeyword) { super("ExportNamedDeclaration", loc); this.declaration = declaration; this.specifiers = specifiers; this.source = source; + this.hasTypeKeyword = hasTypeKeyword; } public Statement getDeclaration() { @@ -48,4 +56,9 @@ public class ExportNamedDeclaration extends ExportDeclaration { public R accept(Visitor v, C c) { return v.visit(this, c); } + + /** Returns true if this is an export type declaration. */ + public boolean hasTypeKeyword() { + return hasTypeKeyword; + } } diff --git a/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java b/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java index 1e538c1bb74..8a291000f2f 100644 --- a/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java +++ b/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java @@ -1,8 +1,9 @@ package com.semmle.js.ast; -import com.semmle.ts.ast.INodeWithSymbol; import java.util.List; +import com.semmle.ts.ast.INodeWithSymbol; + /** * An import declaration, which can be of one of the following forms: * @@ -24,10 +25,17 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol { private int symbol = -1; + private boolean hasTypeKeyword; + public ImportDeclaration(SourceLocation loc, List specifiers, Literal source) { + this(loc, specifiers, source, false); + } + + public ImportDeclaration(SourceLocation loc, List specifiers, Literal source, boolean hasTypeKeyword) { super("ImportDeclaration", loc); this.specifiers = specifiers; this.source = source; + this.hasTypeKeyword = hasTypeKeyword; } public Literal getSource() { @@ -52,4 +60,9 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol { public void setSymbol(int symbol) { this.symbol = symbol; } + + /** Returns true if this is an import type declaration. */ + public boolean hasTypeKeyword() { + return hasTypeKeyword; + } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 6af90d562d8..19b3283121d 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -250,6 +250,22 @@ public class ASTExtractor { /** An identifier that declares a variable and a namespace. */ varAndNamespaceDecl, + /** + * An identifier that occurs in a type-only import. + * + * These may declare a type and/or a namespace, but for compatibility with our AST, + * must be emitted as a VarDecl (with no variable binding). + */ + typeOnlyImport, + + /** + * An identifier that occurs in a type-only export. + * + * These may refer to a type and/or a namespace, but for compatibility with our AST, + * must be emitted as an ExportVarAccess (with no variable binding). + */ + typeOnlyExport, + /** An identifier that declares a variable, type, and namepsace. */ varAndTypeAndNamespaceDecl, @@ -278,7 +294,8 @@ public class ASTExtractor { * True if this occurs as part of a type annotation, i.e. it is {@link #typeBind} or {@link * #typeDecl}, {@link #typeLabel}, {@link #varInTypeBind}, or {@link #namespaceBind}. * - *

Does not hold for {@link #varAndTypeDecl}. + *

Does not hold for {@link #varAndTypeDecl} or {@link #typeOnlyImportExport} as these + * do not occur in type annotations. */ public boolean isInsideType() { return this == typeBind @@ -488,6 +505,14 @@ public class ASTExtractor { addVariableBinding("decl", key, name); addNamespaceBinding("namespacedecl", key, name); break; + case typeOnlyImport: + addTypeBinding("typedecl", key, name); + addNamespaceBinding("namespacedecl", key, name); + break; + case typeOnlyExport: + addTypeBinding("typebind", key, name); + addNamespaceBinding("namespacebind", key, name); + break; case varAndTypeAndNamespaceDecl: addVariableBinding("decl", key, name); addTypeBinding("typedecl", key, name); @@ -1538,7 +1563,14 @@ public class ASTExtractor { Label lbl = super.visit(nd, c); visit(nd.getDeclaration(), lbl, -1); visit(nd.getSource(), lbl, -2); - visitAll(nd.getSpecifiers(), lbl, nd.hasSource() ? IdContext.label : IdContext.export, 0); + IdContext childContext = + nd.hasSource() ? IdContext.label : + nd.hasTypeKeyword() ? IdContext.typeOnlyExport : + IdContext.export; + visitAll(nd.getSpecifiers(), lbl, childContext, 0); + if (nd.hasTypeKeyword()) { + trapwriter.addTuple("hasTypeKeyword", lbl); + } return lbl; } @@ -1554,8 +1586,12 @@ public class ASTExtractor { public Label visit(ImportDeclaration nd, Context c) { Label lbl = super.visit(nd, c); visit(nd.getSource(), lbl, -1); - visitAll(nd.getSpecifiers(), lbl); + IdContext childContext = nd.hasTypeKeyword() ? IdContext.typeOnlyImport : IdContext.varAndTypeAndNamespaceDecl; + visitAll(nd.getSpecifiers(), lbl, childContext, 0); emitNodeSymbol(nd, lbl); + if (nd.hasTypeKeyword()) { + trapwriter.addTuple("hasTypeKeyword", lbl); + } return lbl; } @@ -1563,7 +1599,7 @@ public class ASTExtractor { public Label visit(ImportSpecifier nd, Context c) { Label lbl = super.visit(nd, c); visit(nd.getImported(), lbl, 0, IdContext.label); - visit(nd.getLocal(), lbl, 1, IdContext.varAndTypeAndNamespaceDecl); + visit(nd.getLocal(), lbl, 1, c.idcontext); return lbl; } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java b/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java index 122ccda028e..d88f341bc0e 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java @@ -1,5 +1,9 @@ package com.semmle.js.extractor; +import java.util.EnumMap; +import java.util.LinkedHashMap; +import java.util.Map; + import com.semmle.jcorn.TokenType; import com.semmle.jcorn.jsx.JSXParser; import com.semmle.js.ast.AssignmentExpression; @@ -29,9 +33,6 @@ import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.ExpressionWithTypeArguments; import com.semmle.ts.ast.TypeAssertion; import com.semmle.util.exception.CatastrophicError; -import java.util.EnumMap; -import java.util.LinkedHashMap; -import java.util.Map; /** Map from SpiderMonkey expression types to the numeric kinds used in the DB scheme. */ public class ExprKinds { @@ -154,6 +155,8 @@ public class ExprKinds { idKinds.put(IdContext.namespaceDecl, 78); idKinds.put(IdContext.varAndNamespaceDecl, 78); idKinds.put(IdContext.varAndTypeAndNamespaceDecl, 78); + idKinds.put(IdContext.typeOnlyImport, 78); + idKinds.put(IdContext.typeOnlyExport, 103); idKinds.put(IdContext.varBind, 79); idKinds.put(IdContext.export, 103); idKinds.put(IdContext.exportBase, 103); diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 8299abebe8b..0643cc15ef5 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -1179,11 +1179,12 @@ public class TypeScriptASTConverter { private Node convertExportDeclaration(JsonObject node, SourceLocation loc) throws ParseError { Literal source = tryConvertChild(node, "moduleSpecifier", Literal.class); if (hasChild(node, "exportClause")) { + boolean hasTypeKeyword = node.get("isTypeOnly").getAsBoolean(); List specifiers = hasKind(node.get("exportClause"), "NamespaceExport") ? Collections.singletonList(convertChild(node, "exportClause")) : convertChildren(node.get("exportClause").getAsJsonObject(), "elements"); - return new ExportNamedDeclaration(loc, null, specifiers, source); + return new ExportNamedDeclaration(loc, null, specifiers, source, hasTypeKeyword); } else { return new ExportAllDeclaration(loc, source); } @@ -1368,6 +1369,7 @@ public class TypeScriptASTConverter { private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throws ParseError { Literal src = tryConvertChild(node, "moduleSpecifier", Literal.class); List specifiers = new ArrayList<>(); + boolean hasTypeKeyword = false; if (hasChild(node, "importClause")) { JsonObject importClause = node.get("importClause").getAsJsonObject(); if (hasChild(importClause, "name")) { @@ -1381,8 +1383,9 @@ public class TypeScriptASTConverter { specifiers.addAll(convertChildren(namedBindings, "elements")); } } + hasTypeKeyword = importClause.get("isTypeOnly").getAsBoolean(); } - ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src); + ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src, hasTypeKeyword); attachSymbolInformation(importDecl, node); return importDecl; } diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index 66a5155458c..b1cbe224764 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -125,7 +125,7 @@ class ASTNode extends @ast_node, Locatable { * Holds if this is part of an ambient declaration or type annotation in a TypeScript file. * * A declaration is ambient if it occurs under a `declare` modifier or is - * an interface declaration, type alias, or type annotation. + * an interface declaration, type alias, type annotation, or type-only import/export declaration. * * The TypeScript compiler emits no code for ambient declarations, but they * can affect name resolution and type checking at compile-time. diff --git a/javascript/ql/src/semmle/javascript/ES2015Modules.qll b/javascript/ql/src/semmle/javascript/ES2015Modules.qll index f75f582d851..ca50b3cdcc6 100644 --- a/javascript/ql/src/semmle/javascript/ES2015Modules.qll +++ b/javascript/ql/src/semmle/javascript/ES2015Modules.qll @@ -76,6 +76,16 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration { // `import { createServer } from 'http'` result = DataFlow::destructuredModuleImportNode(this) } + + /** Holds if this is declared with the `type` keyword, so it only imports types. */ + predicate isTypeOnly() { + hasTypeKeyword(this) + } + + override predicate isAmbient() { + Stmt.super.isAmbient() or + isTypeOnly() + } } /** A literal path expression appearing in an `import` declaration. */ @@ -256,6 +266,16 @@ abstract class ExportDeclaration extends Stmt, @exportdeclaration { * to module `a` or possibly to some other module from which `a` re-exports. */ abstract DataFlow::Node getSourceNode(string name); + + /** Holds if is declared with the `type` keyword, so only types are exported. */ + predicate isTypeOnly() { + hasTypeKeyword(this) + } + + override predicate isAmbient() { + Stmt.super.isAmbient() or + isTypeOnly() + } } /** @@ -413,6 +433,18 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration } } +/** + * An export declaration with the `type` modifier. + */ +private class TypeOnlyExportDeclaration extends ExportNamedDeclaration { + TypeOnlyExportDeclaration() { isTypeOnly() } + + override predicate exportsAs(LexicalName v, string name) { + super.exportsAs(v, name) and + not v instanceof Variable + } +} + /** * An export specifier in an export declaration. * diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index dad09eeeff5..03c078a7e6e 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -385,6 +385,8 @@ case @expr.kind of @exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + @typeassertion = @astypeassertion | @prefixtypeassertion; @classdefinition = @classdeclstmt | @classexpr; @@ -518,6 +520,7 @@ hasPublicKeyword (int id: @property ref); hasPrivateKeyword (int id: @property ref); hasProtectedKeyword (int id: @property ref); hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); isOptionalMember (int id: @property ref); hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); isOptionalParameterDeclaration (unique int parameter: @pattern ref); diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected new file mode 100644 index 00000000000..1127959be64 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -0,0 +1,6 @@ +getAVarReference +| Foo | tst.ts:5:5:5:7 | Foo | +getAnExportAccess +| Foo | tst.ts:3:15:3:17 | Foo | +getATypeDecl +| Foo | tst.ts:1:15:1:17 | Foo | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql new file mode 100644 index 00000000000..42d0acf7495 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql @@ -0,0 +1,13 @@ +import javascript + +query VarRef getAVarReference(Variable v) { + result = v.getAReference() +} + +query VarRef getAnExportAccess(LocalTypeName t) { + result = t.getAnExportAccess() +} + +query TypeDecl getATypeDecl(LocalTypeName t) { + result = t.getADeclaration() +} diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts new file mode 100644 index 00000000000..cb80e400923 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts @@ -0,0 +1,5 @@ +import type { Foo } from "foo"; + +export type { Foo }; + +var Foo = 45; From 260b243c2830db4fa416ef8fdbcde8f11e3915a4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 16:32:11 +0000 Subject: [PATCH 06/13] TS: Add test case to DeclBeforeUse --- .../query-tests/Declarations/DeclBeforeUse/typescript.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts b/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts index 18862ea5f5e..0de18d48a48 100644 --- a/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts +++ b/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts @@ -3,3 +3,9 @@ class Foo {} declare class Bar extends Baz {} // OK declare class Baz {} + +export type { I }; // OK - does not refer to the constant 'I' + +const I = 45; + +interface I {} From 16c909b433ae15b37dacecbb18b03c354a0eddd4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 16:48:16 +0000 Subject: [PATCH 07/13] TS: Add test case for import type * as ns --- .../TypeScript/TypeOnlyImportExport/test.expected | 1 + .../test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected index 1127959be64..9ff9937769f 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -4,3 +4,4 @@ getAnExportAccess | Foo | tst.ts:3:15:3:17 | Foo | getATypeDecl | Foo | tst.ts:1:15:1:17 | Foo | +| types | tst.ts:7:18:7:22 | types | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts index cb80e400923..440e77b9dbc 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts @@ -3,3 +3,7 @@ import type { Foo } from "foo"; export type { Foo }; var Foo = 45; + +import type * as types from "types"; + +export type * as blah from "blah"; From 47673c6e21c895012d6c76b65174ec1df129f1d8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 17:13:47 +0000 Subject: [PATCH 08/13] TS: Disable export analysis for type-only exports --- .../dataflow/internal/InterModuleTypeInference.qll | 8 +++++++- .../TypeScript/TypeOnlyImportExport/exportFunction.ts | 1 + .../TypeScript/TypeOnlyImportExport/importFunction.ts | 3 +++ .../TypeScript/TypeOnlyImportExport/importType.ts | 3 +++ .../TypeScript/TypeOnlyImportExport/test.expected | 7 +++++++ .../library-tests/TypeScript/TypeOnlyImportExport/test.ql | 4 ++++ 6 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll index 6bc0eac95bc..4d60fdebcfd 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll @@ -405,10 +405,16 @@ private class AnalyzedClosureGlobalAccessPath extends AnalyzedNode, AnalyzedProp */ private class AnalyzedExportNamespaceSpecifier extends AnalyzedPropertyWrite, DataFlow::ValueNode { override ExportNamespaceSpecifier astNode; + ReExportDeclaration decl; + + AnalyzedExportNamespaceSpecifier() { + decl = astNode.getExportDeclaration() and + not decl.isTypeOnly() + } override predicate writesValue(AbstractValue baseVal, string propName, AbstractValue value) { baseVal = TAbstractExportsObject(getTopLevel()) and propName = astNode.getExportedName() and - value = TAbstractExportsObject(astNode.getExportDeclaration().(ReExportDeclaration).getReExportedModule()) + value = TAbstractExportsObject(decl.getReExportedModule()) } } diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts new file mode 100644 index 00000000000..8b38a11158b --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts @@ -0,0 +1 @@ +export function f() {} diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts new file mode 100644 index 00000000000..1034558749c --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts @@ -0,0 +1,3 @@ +import { ns } from "./importType"; + +ns.f(); // Calls local method in 'importType' diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts new file mode 100644 index 00000000000..090e94bc597 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts @@ -0,0 +1,3 @@ +export type * as ns from "./exportFunction"; + +export var ns = { f() {} }; diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected index 9ff9937769f..f4861fcc5ce 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -1,7 +1,14 @@ getAVarReference | Foo | tst.ts:5:5:5:7 | Foo | +| f | exportFunction.ts:1:17:1:17 | f | +| ns | importFunction.ts:1:10:1:11 | ns | +| ns | importFunction.ts:3:1:3:2 | ns | +| ns | importType.ts:3:12:3:13 | ns | getAnExportAccess | Foo | tst.ts:3:15:3:17 | Foo | getATypeDecl | Foo | tst.ts:1:15:1:17 | Foo | +| ns | importFunction.ts:1:10:1:11 | ns | | types | tst.ts:7:18:7:22 | types | +calls +| importFunction.ts:3:1:3:6 | ns.f() | importType.ts:3:19:3:24 | f() {} | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql index 42d0acf7495..3c3b9bf2320 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql @@ -11,3 +11,7 @@ query VarRef getAnExportAccess(LocalTypeName t) { query TypeDecl getATypeDecl(LocalTypeName t) { result = t.getADeclaration() } + +query Function calls(DataFlow::InvokeNode invoke) { + result = invoke.getACallee() +} From 18974bad1c0c6209e30f413509aae5d7e14bda6e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 10:28:59 +0000 Subject: [PATCH 09/13] TS: Add upgrade script and stats --- .../src/semmlecode.javascript.dbscheme.stats | 11 + .../old.dbscheme | 1186 ++++++++++++++++ .../semmlecode.javascript.dbscheme | 1189 +++++++++++++++++ .../upgrade.properties | 2 + 4 files changed, 2388 insertions(+) create mode 100644 javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme create mode 100644 javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme.stats b/javascript/ql/src/semmlecode.javascript.dbscheme.stats index 1bc81f76f9b..7e352454e59 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/src/semmlecode.javascript.dbscheme.stats @@ -7984,6 +7984,17 @@ +hasTypeKeyword +1000 + + +id +1000 + + + + + isOptionalMember 3668 diff --git a/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme new file mode 100644 index 00000000000..dad09eeeff5 --- /dev/null +++ b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme @@ -0,0 +1,1186 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..03c078a7e6e --- /dev/null +++ b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme @@ -0,0 +1,1189 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties new file mode 100644 index 00000000000..d0a417d20a6 --- /dev/null +++ b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties @@ -0,0 +1,2 @@ +description: add support for TypeScript 3.8 +compatibility: backwards From 05d9e64dab5081a939d7b25f6fa2f9d11e8146c0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 11:59:29 +0000 Subject: [PATCH 10/13] TS: Add change note --- change-notes/1.24/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 58c1698d799..50197d6f5a1 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -2,6 +2,8 @@ ## General improvements +* TypeScript 3.8 is now supported. + * Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). * Imports with the `.js` extension can now be resolved to a TypeScript file, From 4e1bd9056ce100741b080b89ffd5bd9f48b66dac Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 12:41:35 +0000 Subject: [PATCH 11/13] TS: Fix javadoc --- .../extractor/src/com/semmle/js/extractor/ASTExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 19b3283121d..8dcc6d3a5c5 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -294,8 +294,8 @@ public class ASTExtractor { * True if this occurs as part of a type annotation, i.e. it is {@link #typeBind} or {@link * #typeDecl}, {@link #typeLabel}, {@link #varInTypeBind}, or {@link #namespaceBind}. * - *

Does not hold for {@link #varAndTypeDecl} or {@link #typeOnlyImportExport} as these - * do not occur in type annotations. + *

Does not hold for {@link #varAndTypeDecl}, {@link #typeOnlyImport}, or @{link {@link #typeOnlyExport} + * as these do not occur in type annotations. */ public boolean isInsideType() { return this == typeBind From 78954489fbf532b3c71b5c1ab519c00448286b65 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 15:03:06 +0000 Subject: [PATCH 12/13] TS: Fix expected output --- .../TypeScript/ExportNamespaceSpecifier/test.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected index 6403f1793a4..ca8914da44f 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected @@ -1 +1 @@ -| reexport.ts:1:13:1:14 | ns | +| reexport.ts:1:8:1:14 | * as ns | From 01309d7c2ee8ceb399744cb4ed08ab1c488af759 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 11:38:05 +0000 Subject: [PATCH 13/13] TS: Add test for named re-export and exportsAs --- .../TypeScript/TypeOnlyImportExport/exportClass.ts | 1 + .../TypeOnlyImportExport/importRexportedClass.ts | 3 +++ .../TypeScript/TypeOnlyImportExport/namedReexport.ts | 1 + .../TypeScript/TypeOnlyImportExport/test.expected | 12 ++++++++++++ .../TypeScript/TypeOnlyImportExport/test.ql | 5 +++++ 5 files changed, 22 insertions(+) create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts new file mode 100644 index 00000000000..1ec0ebf40c5 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts @@ -0,0 +1 @@ +export class C {} diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts new file mode 100644 index 00000000000..92b60b44ccf --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts @@ -0,0 +1,3 @@ +import type { C } from "./namedReexport"; + +let c: C; diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts new file mode 100644 index 00000000000..6fd9a22c067 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts @@ -0,0 +1 @@ +export type { C } from "./exportClass"; diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected index f4861fcc5ce..083b5a90be6 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -1,5 +1,7 @@ getAVarReference +| C | exportClass.ts:1:14:1:14 | C | | Foo | tst.ts:5:5:5:7 | Foo | +| c | importRexportedClass.ts:3:5:3:5 | c | | f | exportFunction.ts:1:17:1:17 | f | | ns | importFunction.ts:1:10:1:11 | ns | | ns | importFunction.ts:3:1:3:2 | ns | @@ -7,8 +9,18 @@ getAVarReference getAnExportAccess | Foo | tst.ts:3:15:3:17 | Foo | getATypeDecl +| C | exportClass.ts:1:14:1:14 | C | +| C | importRexportedClass.ts:1:15:1:15 | C | | Foo | tst.ts:1:15:1:17 | Foo | | ns | importFunction.ts:1:10:1:11 | ns | | types | tst.ts:7:18:7:22 | types | calls | importFunction.ts:3:1:3:6 | ns.f() | importType.ts:3:19:3:24 | f() {} | +exportsAs +| exportClass.ts:1:1:1:17 | export class C {} | C | C | type | +| exportClass.ts:1:1:1:17 | export class C {} | C | C | variable | +| exportFunction.ts:1:1:1:22 | export ... f() {} | f | f | variable | +| importType.ts:3:1:3:27 | export ... ) {} }; | ns | ns | variable | +| namedReexport.ts:1:1:1:39 | export ... Class"; | C | C | type | +| tst.ts:3:1:3:20 | export type { Foo }; | Foo | Foo | namespace | +| tst.ts:3:1:3:20 | export type { Foo }; | Foo | Foo | type | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql index 3c3b9bf2320..17939b3b380 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql @@ -15,3 +15,8 @@ query TypeDecl getATypeDecl(LocalTypeName t) { query Function calls(DataFlow::InvokeNode invoke) { result = invoke.getACallee() } + +query predicate exportsAs(ExportDeclaration exprt, LexicalName v, string name, string kind) { + exprt.exportsAs(v, name) and + kind = v.getDeclarationSpace() +}