From 316580334a736b3dfb3cbd2c5d4375f8aa3b8ff9 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 7 Oct 2019 15:58:57 +0100 Subject: [PATCH 1/4] TS: Fix extraction of default-exported class --- .../js/parser/TypeScriptASTConverter.java | 30 ++++++++++++------- .../DefaultExports/exportClass.ts | 3 ++ .../DefaultExports/exportFunction.ts | 3 ++ .../DefaultExports/test.expected | 5 ++++ .../RegressionTests/DefaultExports/test.ql | 5 ++++ .../ExportedClassExpr/exportFunction.ts | 3 ++ .../DeadStoreOfLocal/exportDefaultClass.ts | 5 ++++ .../DeadStoreOfLocal/exportDefaultFunction.ts | 3 ++ 8 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportClass.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportFunction.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportedClassExpr/exportFunction.ts create mode 100644 javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultClass.ts create mode 100644 javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultFunction.ts diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index de9042b6d366..7d18dbd42288 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; @@ -142,13 +150,6 @@ import com.semmle.ts.ast.UnaryTypeExpr; import com.semmle.ts.ast.UnionTypeExpr; import com.semmle.util.collections.CollectionUtil; -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 params = convertParameters(node); Identifier fnId = convertChild(node, "name", "Identifier"); + if (fnId == null) { + // Anonymous function declarations may occur as part of default exported functions. + // We represent these as function expressions. + return fixExports(loc, convertFunctionExpression(node, loc)); + } BlockStatement fnbody = convertChild(node, "body"); boolean generator = hasChild(node, "asteriskToken"); boolean async = hasModifier(node, "AsyncKeyword"); @@ -2305,7 +2313,7 @@ private IJSXName convertJSXName(Expression e) { *

If the declared statement has decorators, the {@code loc} should first be advanced past * these using {@link #advanceUntilAfter}. */ - private Node fixExports(SourceLocation loc, Statement decl) { + private Node fixExports(SourceLocation loc, Node decl) { Matcher m = EXPORT_DECL_START.matcher(loc.getSource()); if (m.find()) { String skipped = m.group(0); @@ -2313,7 +2321,7 @@ private Node fixExports(SourceLocation loc, Statement decl) { advance(loc, skipped); // capture group 1 is `default`, if present if (m.group(1) == null) - return new ExportNamedDeclaration(outerLoc, decl, new ArrayList<>(), null); + return new ExportNamedDeclaration(outerLoc, (Statement) decl, new ArrayList<>(), null); return new ExportDefaultDeclaration(outerLoc, decl); } return decl; diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportClass.ts b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportClass.ts new file mode 100644 index 000000000000..c8de02deadf4 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportClass.ts @@ -0,0 +1,3 @@ +import { Foo } from "somwhere"; + +export default class extends Foo {} diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportFunction.ts b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportFunction.ts new file mode 100644 index 000000000000..30c2c5ef190a --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/exportFunction.ts @@ -0,0 +1,3 @@ +import { Foo } from "somwhere"; + +export default function(x=Foo) {} diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.expected b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.expected new file mode 100644 index 000000000000..6818c85c6d24 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.expected @@ -0,0 +1,5 @@ +classExprs +| exportClass.ts:3:16:3:35 | class extends Foo {} | +functionExprs +| exportClass.ts:3:34:3:33 | (...arg ... rgs); } | +| exportFunction.ts:3:16:3:33 | function(x=Foo) {} | diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.ql b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.ql new file mode 100644 index 000000000000..c4e321bb4192 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/DefaultExports/test.ql @@ -0,0 +1,5 @@ +import javascript + +query ClassExpr classExprs() { any() } + +query FunctionExpr functionExprs() { any() } diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportedClassExpr/exportFunction.ts b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportedClassExpr/exportFunction.ts new file mode 100644 index 000000000000..1fd441ff0408 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportedClassExpr/exportFunction.ts @@ -0,0 +1,3 @@ +import { Foo } from "./node_modules/somwhere"; + +export default function(x=Foo) {} diff --git a/javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultClass.ts b/javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultClass.ts new file mode 100644 index 000000000000..6481a749c40c --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultClass.ts @@ -0,0 +1,5 @@ +var C1 = global.C1; // OK +var C2 = global.C2; // OK + +class C extends C1 {} +export default class extends C2 {} diff --git a/javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultFunction.ts b/javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultFunction.ts new file mode 100644 index 000000000000..5c6b48f8796c --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/DeadStoreOfLocal/exportDefaultFunction.ts @@ -0,0 +1,3 @@ +var C1 = global.C1; // OK + +export default function(x=C1) {} From 52bd19b951ec573ea336e094799eaab0325e02fa Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 7 Oct 2019 16:13:30 +0100 Subject: [PATCH 2/4] JS: Run Java formatter --- .../src/com/semmle/js/extractor/Main.java | 15 +++++++------ .../js/parser/TypeScriptASTConverter.java | 21 +++++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 466e93639eb1..a10d689c97ab 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -1,13 +1,5 @@ package com.semmle.js.extractor; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; - import com.semmle.js.extractor.ExtractorConfig.HTMLHandling; import com.semmle.js.extractor.ExtractorConfig.Platform; import com.semmle.js.extractor.ExtractorConfig.SourceType; @@ -31,6 +23,13 @@ import com.semmle.util.process.ArgsParser; import com.semmle.util.process.ArgsParser.FileMode; import com.semmle.util.trap.TrapWriter; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; /** The main entry point of the JavaScript extractor. */ public class Main { diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 7d18dbd42288..55a36130efec 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -1,13 +1,5 @@ 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; @@ -150,6 +142,13 @@ import com.semmle.ts.ast.UnaryTypeExpr; import com.semmle.ts.ast.UnionTypeExpr; import com.semmle.util.collections.CollectionUtil; +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 params = convertParameters(node); Identifier fnId = convertChild(node, "name", "Identifier"); if (fnId == null) { - // Anonymous function declarations may occur as part of default exported functions. - // We represent these as function expressions. - return fixExports(loc, convertFunctionExpression(node, loc)); + // Anonymous function declarations may occur as part of default exported functions. + // We represent these as function expressions. + return fixExports(loc, convertFunctionExpression(node, loc)); } BlockStatement fnbody = convertChild(node, "body"); boolean generator = hasChild(node, "asteriskToken"); From d0cce12db935488417b58ed3d33b43556657fc2b Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 7 Oct 2019 16:15:24 +0100 Subject: [PATCH 3/4] JS: Bump extractor version --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index a10d689c97ab..4b77c9ab22ee 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -37,7 +37,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2019-09-18"; + public static final String EXTRACTOR_VERSION = "2019-10-07"; public static final Pattern NEWLINE = Pattern.compile("\n"); From ea35b8418a22d8fac0960e1daf571ff7c9f4a442 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 8 Oct 2019 12:05:31 +0100 Subject: [PATCH 4/4] JS: Add change note --- change-notes/1.23/extractor-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.23/extractor-javascript.md b/change-notes/1.23/extractor-javascript.md index 5c61ce675416..557c9ccda24d 100644 --- a/change-notes/1.23/extractor-javascript.md +++ b/change-notes/1.23/extractor-javascript.md @@ -8,3 +8,4 @@ * Recognition of CommonJS modules has improved. As a result, some files that were previously extracted as global scripts are now extracted as modules. * Top-level `await` is now supported. +* A bug was fixed in how the TypeScript extractor handles default-exported anonymous classes.