Skip to content

Commit c8e5be7

Browse files
authored
Merge pull request github#2093 from asger-semmle/ts-unused-var-fix
Approved by erik-krogh
2 parents 24a5301 + ea35b84 commit c8e5be7

File tree

10 files changed

+47
-13
lines changed

10 files changed

+47
-13
lines changed

change-notes/1.23/extractor-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
* Recognition of CommonJS modules has improved. As a result, some files that were previously extracted as
99
global scripts are now extracted as modules.
1010
* Top-level `await` is now supported.
11+
* A bug was fixed in how the TypeScript extractor handles default-exported anonymous classes.

javascript/extractor/src/com/semmle/js/extractor/Main.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
package com.semmle.js.extractor;
22

3-
import java.io.File;
4-
import java.io.IOException;
5-
import java.util.ArrayList;
6-
import java.util.LinkedHashSet;
7-
import java.util.List;
8-
import java.util.Set;
9-
import java.util.regex.Pattern;
10-
113
import com.semmle.js.extractor.ExtractorConfig.HTMLHandling;
124
import com.semmle.js.extractor.ExtractorConfig.Platform;
135
import com.semmle.js.extractor.ExtractorConfig.SourceType;
@@ -31,14 +23,21 @@
3123
import com.semmle.util.process.ArgsParser;
3224
import com.semmle.util.process.ArgsParser.FileMode;
3325
import com.semmle.util.trap.TrapWriter;
26+
import java.io.File;
27+
import java.io.IOException;
28+
import java.util.ArrayList;
29+
import java.util.LinkedHashSet;
30+
import java.util.List;
31+
import java.util.Set;
32+
import java.util.regex.Pattern;
3433

3534
/** The main entry point of the JavaScript extractor. */
3635
public class Main {
3736
/**
3837
* A version identifier that should be updated every time the extractor changes in such a way that
3938
* it may produce different tuples for the same file under the same {@link ExtractorConfig}.
4039
*/
41-
public static final String EXTRACTOR_VERSION = "2019-09-18";
40+
public static final String EXTRACTOR_VERSION = "2019-10-07";
4241

4342
public static final Pattern NEWLINE = Pattern.compile("\n");
4443

javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -942,11 +942,13 @@ private Node convertClass(JsonObject node, String kind, SourceLocation loc) thro
942942
SourceLocation bodyLoc = new SourceLocation(loc.getSource(), loc.getStart(), loc.getEnd());
943943
advance(bodyLoc, skip);
944944
ClassBody body = new ClassBody(bodyLoc, convertChildren(node, "members"));
945-
if ("ClassExpression".equals(kind)) {
945+
if ("ClassExpression".equals(kind) || id == null) {
946+
// Note that `export default class {}` is represented as a ClassDeclaration
947+
// in TypeScript but we treat this as a ClassExpression.
946948
ClassExpression classExpr =
947949
new ClassExpression(loc, id, typeParameters, superClass, superInterfaces, body);
948950
attachSymbolInformation(classExpr.getClassDef(), node);
949-
return classExpr;
951+
return fixExports(loc, classExpr);
950952
}
951953
boolean hasDeclareKeyword = hasModifier(node, "DeclareKeyword");
952954
boolean hasAbstractKeyword = hasModifier(node, "AbstractKeyword");
@@ -1225,6 +1227,11 @@ private Node convertForOfStatement(JsonObject node, SourceLocation loc) throws P
12251227
private Node convertFunctionDeclaration(JsonObject node, SourceLocation loc) throws ParseError {
12261228
List<Expression> params = convertParameters(node);
12271229
Identifier fnId = convertChild(node, "name", "Identifier");
1230+
if (fnId == null) {
1231+
// Anonymous function declarations may occur as part of default exported functions.
1232+
// We represent these as function expressions.
1233+
return fixExports(loc, convertFunctionExpression(node, loc));
1234+
}
12281235
BlockStatement fnbody = convertChild(node, "body");
12291236
boolean generator = hasChild(node, "asteriskToken");
12301237
boolean async = hasModifier(node, "AsyncKeyword");
@@ -2305,15 +2312,15 @@ private IJSXName convertJSXName(Expression e) {
23052312
* <p>If the declared statement has decorators, the {@code loc} should first be advanced past
23062313
* these using {@link #advanceUntilAfter}.
23072314
*/
2308-
private Node fixExports(SourceLocation loc, Statement decl) {
2315+
private Node fixExports(SourceLocation loc, Node decl) {
23092316
Matcher m = EXPORT_DECL_START.matcher(loc.getSource());
23102317
if (m.find()) {
23112318
String skipped = m.group(0);
23122319
SourceLocation outerLoc = new SourceLocation(loc.getSource(), loc.getStart(), loc.getEnd());
23132320
advance(loc, skipped);
23142321
// capture group 1 is `default`, if present
23152322
if (m.group(1) == null)
2316-
return new ExportNamedDeclaration(outerLoc, decl, new ArrayList<>(), null);
2323+
return new ExportNamedDeclaration(outerLoc, (Statement) decl, new ArrayList<>(), null);
23172324
return new ExportDefaultDeclaration(outerLoc, decl);
23182325
}
23192326
return decl;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Foo } from "somwhere";
2+
3+
export default class extends Foo {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Foo } from "somwhere";
2+
3+
export default function(x=Foo) {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
classExprs
2+
| exportClass.ts:3:16:3:35 | class extends Foo {} |
3+
functionExprs
4+
| exportClass.ts:3:34:3:33 | (...arg ... rgs); } |
5+
| exportFunction.ts:3:16:3:33 | function(x=Foo) {} |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import javascript
2+
3+
query ClassExpr classExprs() { any() }
4+
5+
query FunctionExpr functionExprs() { any() }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Foo } from "./node_modules/somwhere";
2+
3+
export default function(x=Foo) {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var C1 = global.C1; // OK
2+
var C2 = global.C2; // OK
3+
4+
class C extends C1 {}
5+
export default class extends C2 {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var C1 = global.C1; // OK
2+
3+
export default function(x=C1) {}

0 commit comments

Comments
 (0)