Merge pull request #2896 from asger-semmle/typescript-3.8

TS: Support Typescript 3.8
This commit is contained in:
Asger F 2020-02-25 08:19:01 +00:00 коммит произвёл GitHub
Родитель aadb148c1c 01309d7c2e
Коммит 160fc48803
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
36 изменённых файлов: 2926 добавлений и 28 удалений

Просмотреть файл

@ -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,

Просмотреть файл

@ -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",

Просмотреть файл

@ -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"

Просмотреть файл

@ -15,13 +15,21 @@ public class ExportNamedDeclaration extends ExportDeclaration {
private final Statement declaration;
private final List<ExportSpecifier> specifiers;
private final Literal source;
private final boolean hasTypeKeyword;
public ExportNamedDeclaration(
SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source) {
this(loc, declaration, specifiers, source, false);
}
public ExportNamedDeclaration(
SourceLocation loc, Statement declaration, List<ExportSpecifier> 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 <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
/** Returns true if this is an <code>export type</code> declaration. */
public boolean hasTypeKeyword() {
return hasTypeKeyword;
}
}

Просмотреть файл

@ -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<ImportSpecifier> specifiers, Literal source) {
this(loc, specifiers, source, false);
}
public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> 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 <code>import type</code> declaration. */
public boolean hasTypeKeyword() {
return hasTypeKeyword;
}
}

Просмотреть файл

@ -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}.
*
* <p>Does not hold for {@link #varAndTypeDecl}.
* <p>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
@ -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;
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;
@ -34,6 +42,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;
@ -144,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 <a
@ -334,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":
@ -441,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);
@ -507,6 +514,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 +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")) {
return new ExportNamedDeclaration(
loc,
null,
convertChildren(node.get("exportClause").getAsJsonObject(), "elements"),
source);
boolean hasTypeKeyword = node.get("isTypeOnly").getAsBoolean();
List<ExportSpecifier> specifiers =
hasKind(node.get("exportClause"), "NamespaceExport")
? Collections.singletonList(convertChild(node, "exportClause"))
: convertChildren(node.get("exportClause").getAsJsonObject(), "elements");
return new ExportNamedDeclaration(loc, null, specifiers, source, hasTypeKeyword);
} else {
return new ExportAllDeclaration(loc, source);
}
@ -1187,6 +1197,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);
@ -1354,6 +1369,7 @@ public class TypeScriptASTConverter {
private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throws ParseError {
Literal src = tryConvertChild(node, "moduleSpecifier", Literal.class);
List<ImportSpecifier> specifiers = new ArrayList<>();
boolean hasTypeKeyword = false;
if (hasChild(node, "importClause")) {
JsonObject importClause = node.get("importClause").getAsJsonObject();
if (hasChild(importClause, "name")) {
@ -1367,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;
}

Просмотреть файл

@ -0,0 +1,6 @@
class C {
#foo;
constructor() {
this.#foo = 5;
}
}

Просмотреть файл

@ -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")

Просмотреть файл

@ -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.

Просмотреть файл

@ -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.
*

Просмотреть файл

@ -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())
}
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -7984,6 +7984,17 @@
<dependencies/>
</relation>
<relation>
<name>hasTypeKeyword</name>
<cardinality>1000</cardinality>
<columnsizes>
<e>
<k>id</k>
<v>1000</v>
</e>
</columnsizes>
<dependencies/>
</relation>
<relation>
<name>isOptionalMember</name>
<cardinality>3668</cardinality>
<columnsizes>

Просмотреть файл

@ -0,0 +1,3 @@
import { ns } from "./reexport";
ns.foo();

Просмотреть файл

@ -0,0 +1 @@
export function foo() {}

Просмотреть файл

@ -0,0 +1 @@
export * as ns from "./lib";

Просмотреть файл

@ -0,0 +1 @@
| reexport.ts:1:8:1:14 | * as ns |

Просмотреть файл

@ -0,0 +1,3 @@
import javascript
query ExportNamespaceSpecifier test_ExportNamespaceSpecifier() { any() }

Просмотреть файл

@ -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; |

Просмотреть файл

@ -0,0 +1,9 @@
import javascript
query PropAccess propAccess(string name) {
result.getPropertyName() = name
}
query FieldDeclaration fieldDecl(string name) {
result.getName() = name
}

Просмотреть файл

@ -0,0 +1,8 @@
class C {
#privateField: any;
constructor(x: any) {
this.#privateField = x;
this.#privateField(y);
}
}

Просмотреть файл

@ -0,0 +1 @@
export class C {}

Просмотреть файл

@ -0,0 +1 @@
export function f() {}

Просмотреть файл

@ -0,0 +1,3 @@
import { ns } from "./importType";
ns.f(); // Calls local method in 'importType'

Просмотреть файл

@ -0,0 +1,3 @@
import type { C } from "./namedReexport";
let c: C;

Просмотреть файл

@ -0,0 +1,3 @@
export type * as ns from "./exportFunction";
export var ns = { f() {} };

Просмотреть файл

@ -0,0 +1 @@
export type { C } from "./exportClass";

Просмотреть файл

@ -0,0 +1,26 @@
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 |
| ns | importType.ts:3:12:3:13 | ns |
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 |

Просмотреть файл

@ -0,0 +1,22 @@
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()
}
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()
}

Просмотреть файл

@ -0,0 +1,9 @@
import type { Foo } from "foo";
export type { Foo };
var Foo = 45;
import type * as types from "types";
export type * as blah from "blah";

Просмотреть файл

@ -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 {}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,2 @@
description: add support for TypeScript 3.8
compatibility: backwards