diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index de9042b6d36..7d18dbd4228 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.TypeofTypeExpr; 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 @@ public class TypeScriptASTConverter { *

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 @@ public class TypeScriptASTConverter { 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 00000000000..c8de02deadf --- /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 00000000000..30c2c5ef190 --- /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 00000000000..6818c85c6d2 --- /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 00000000000..c4e321bb419 --- /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 00000000000..1fd441ff040 --- /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 00000000000..6481a749c40 --- /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 00000000000..5c6b48f8796 --- /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) {}