Skip to content

Commit 5676891

Browse files
committed
JS: Add TemplateLiteralTypeExpr
1 parent 9da5c5c commit 5676891

File tree

14 files changed

+210
-7
lines changed

14 files changed

+210
-7
lines changed

javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.semmle.ts.ast.ParenthesizedTypeExpr;
4444
import com.semmle.ts.ast.PredicateTypeExpr;
4545
import com.semmle.ts.ast.RestTypeExpr;
46+
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
4647
import com.semmle.ts.ast.TupleTypeExpr;
4748
import com.semmle.ts.ast.TypeAliasDeclaration;
4849
import com.semmle.ts.ast.TypeAssertion;
@@ -368,6 +369,11 @@ public R visit(TemplateLiteral nd, C c) {
368369
return visit((Expression) nd, c);
369370
}
370371

372+
@Override
373+
public R visit(TemplateLiteralTypeExpr nd, C c) {
374+
return visit((TypeExpression) nd, c);
375+
}
376+
371377
@Override
372378
public R visit(TaggedTemplateExpression nd, C c) {
373379
return visit((Expression) nd, c);

javascript/extractor/src/com/semmle/js/ast/NodeCopier.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.semmle.ts.ast.ParenthesizedTypeExpr;
4040
import com.semmle.ts.ast.PredicateTypeExpr;
4141
import com.semmle.ts.ast.RestTypeExpr;
42+
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
4243
import com.semmle.ts.ast.TupleTypeExpr;
4344
import com.semmle.ts.ast.TypeAliasDeclaration;
4445
import com.semmle.ts.ast.TypeAssertion;
@@ -419,6 +420,11 @@ public TemplateLiteral visit(TemplateLiteral nd, Void q) {
419420
return new TemplateLiteral(visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
420421
}
421422

423+
@Override
424+
public TemplateLiteralTypeExpr visit(TemplateLiteralTypeExpr nd, Void q) {
425+
return new TemplateLiteralTypeExpr(visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
426+
}
427+
422428
@Override
423429
public TaggedTemplateExpression visit(TaggedTemplateExpression nd, Void q) {
424430
return new TaggedTemplateExpression(

javascript/extractor/src/com/semmle/js/ast/TemplateLiteral.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,23 @@ public TemplateLiteral(
2121
super("TemplateLiteral", loc);
2222
this.expressions = expressions;
2323
this.quasis = quasis;
24-
this.children = mergeChildren(expressions, quasis);
24+
this.children = TemplateLiteral.<Expression>mergeChildren(expressions, quasis);
2525
}
2626

2727
/*
2828
* Merge quasis and expressions into a single array in textual order.
2929
* Also filter out the empty constant strings that the parser likes to generate.
3030
*/
31-
private List<Expression> mergeChildren(
32-
List<Expression> expressions, List<TemplateElement> quasis) {
33-
List<Expression> children = new ArrayList<Expression>();
31+
@SuppressWarnings("unchecked")
32+
public static <E extends INode> List<E> mergeChildren(
33+
List<? extends INode> expressions,
34+
List<TemplateElement> quasis) {
35+
36+
List<INode> children = new ArrayList<INode>();
3437
int j = 0, n = quasis.size();
3538

3639
for (int i = 0, m = expressions.size(); i < m; ++i) {
37-
Expression expr = expressions.get(i);
40+
INode expr = expressions.get(i);
3841
for (; j < n; ++j) {
3942
TemplateElement quasi = quasis.get(j);
4043
if (quasi.getLoc().getStart().compareTo(expr.getLoc().getStart()) > 0) break;
@@ -48,7 +51,7 @@ private List<Expression> mergeChildren(
4851
if (!quasi.getRaw().isEmpty()) children.add(quasi);
4952
}
5053

51-
return children;
54+
return (List<E>)children;
5255
}
5356

5457
@Override

javascript/extractor/src/com/semmle/js/ast/Visitor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.semmle.ts.ast.ParenthesizedTypeExpr;
4040
import com.semmle.ts.ast.PredicateTypeExpr;
4141
import com.semmle.ts.ast.RestTypeExpr;
42+
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
4243
import com.semmle.ts.ast.TupleTypeExpr;
4344
import com.semmle.ts.ast.TypeAliasDeclaration;
4445
import com.semmle.ts.ast.TypeAssertion;
@@ -157,6 +158,8 @@ public interface Visitor<C, R> {
157158

158159
public R visit(TemplateLiteral nd, C q);
159160

161+
public R visit(TemplateLiteralTypeExpr nd, C q);
162+
160163
public R visit(TaggedTemplateExpression nd, C q);
161164

162165
public R visit(ArrowFunctionExpression nd, C q);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
import com.semmle.ts.ast.ParenthesizedTypeExpr;
144144
import com.semmle.ts.ast.PredicateTypeExpr;
145145
import com.semmle.ts.ast.RestTypeExpr;
146+
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
146147
import com.semmle.ts.ast.TupleTypeExpr;
147148
import com.semmle.ts.ast.TypeAliasDeclaration;
148149
import com.semmle.ts.ast.TypeAssertion;
@@ -1270,6 +1271,13 @@ public Label visit(TemplateLiteral nd, Context c) {
12701271
return key;
12711272
}
12721273

1274+
@Override
1275+
public Label visit(TemplateLiteralTypeExpr nd, Context c) {
1276+
Label key = super.visit(nd, c);
1277+
visitAll(nd.getChildren(), key, IdContext.typeBind, 0);
1278+
return key;
1279+
}
1280+
12731281
@Override
12741282
public Label visit(TemplateElement nd, Context c) {
12751283
Label key = super.visit(nd, c);

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.semmle.js.ast.Identifier;
77
import com.semmle.js.ast.Literal;
88
import com.semmle.js.ast.MemberExpression;
9+
import com.semmle.js.ast.TemplateElement;
910
import com.semmle.js.extractor.ASTExtractor.IdContext;
1011
import com.semmle.ts.ast.ArrayTypeExpr;
1112
import com.semmle.ts.ast.ConditionalTypeExpr;
@@ -22,6 +23,7 @@
2223
import com.semmle.ts.ast.ParenthesizedTypeExpr;
2324
import com.semmle.ts.ast.PredicateTypeExpr;
2425
import com.semmle.ts.ast.RestTypeExpr;
26+
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
2527
import com.semmle.ts.ast.TupleTypeExpr;
2628
import com.semmle.ts.ast.TypeParameter;
2729
import com.semmle.ts.ast.TypeofTypeExpr;
@@ -67,6 +69,7 @@ public class TypeExprKinds {
6769
private static final int restTypeExpr = 34;
6870
private static final int bigintLiteralTypeExpr = 35;
6971
private static final int readonlyTypeExpr = 36;
72+
private static final int templateLiteralTypeExpr = 37;
7073

7174
public static int getTypeExprKind(final INode type, final IdContext idcontext) {
7275
Integer kind =
@@ -241,6 +244,16 @@ public Integer visit(OptionalTypeExpr nd, Void c) {
241244
public Integer visit(RestTypeExpr nd, Void c) {
242245
return restTypeExpr;
243246
}
247+
248+
@Override
249+
public Integer visit(TemplateLiteralTypeExpr nd, Void c) {
250+
return templateLiteralTypeExpr;
251+
}
252+
253+
@Override
254+
public Integer visit(TemplateElement nd, Void c) {
255+
return stringLiteralTypeExpr;
256+
}
244257
},
245258
null);
246259
if (kind == null)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.semmle.ts.ast;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import com.semmle.js.ast.Expression;
7+
import com.semmle.js.ast.INode;
8+
import com.semmle.js.ast.Node;
9+
import com.semmle.js.ast.SourceLocation;
10+
import com.semmle.js.ast.TemplateElement;
11+
import com.semmle.js.ast.TemplateLiteral;
12+
import com.semmle.js.ast.Visitor;
13+
14+
/**
15+
* A template literal used in a type, such as in <code>type T = `Hello, ${name}!`</code>.
16+
*/
17+
public class TemplateLiteralTypeExpr extends TypeExpression {
18+
private final List<ITypeExpression> expressions;
19+
private final List<TemplateElement> quasis;
20+
private final List<Node> children;
21+
22+
public TemplateLiteralTypeExpr(
23+
SourceLocation loc, List<ITypeExpression> expressions, List<TemplateElement> quasis) {
24+
super("TemplateLiteralTypeExpr", loc);
25+
this.expressions = expressions;
26+
this.quasis = quasis;
27+
this.children = TemplateLiteral.<Node>mergeChildren(expressions, quasis);
28+
}
29+
30+
@Override
31+
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
32+
return v.visit(this, q);
33+
}
34+
35+
/** The type expressions in this template. */
36+
public List<ITypeExpression> getExpressions() {
37+
return expressions;
38+
}
39+
40+
/** The template elements in this template. */
41+
public List<TemplateElement> getQuasis() {
42+
return quasis;
43+
}
44+
45+
/** All type expressions and template elements in this template, in lexical order. */
46+
public List<Node> getChildren() {
47+
return children;
48+
}
49+
}

javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
import com.semmle.ts.ast.ParenthesizedTypeExpr;
146146
import com.semmle.ts.ast.PredicateTypeExpr;
147147
import com.semmle.ts.ast.RestTypeExpr;
148+
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
148149
import com.semmle.ts.ast.TupleTypeExpr;
149150
import com.semmle.ts.ast.TypeAliasDeclaration;
150151
import com.semmle.ts.ast.TypeAssertion;
@@ -576,6 +577,8 @@ private Node convertNodeUntyped(JsonObject node, String defaultKind) throws Pars
576577
case "TemplateMiddle":
577578
case "TemplateTail":
578579
return convertTemplateElement(node, kind, loc);
580+
case "TemplateLiteralType":
581+
return convertTemplateLiteralType(node, loc);
579582
case "ThisKeyword":
580583
return convertThisKeyword(loc);
581584
case "ThisType":
@@ -2152,6 +2155,19 @@ private Node convertTemplateExpression(JsonObject node, SourceLocation loc) thro
21522155
return new TemplateLiteral(loc, expressions, quasis);
21532156
}
21542157

2158+
private Node convertTemplateLiteralType(JsonObject node, SourceLocation loc) throws ParseError {
2159+
List<TemplateElement> quasis;
2160+
List<ITypeExpression> expressions = new ArrayList<>();
2161+
quasis = new ArrayList<>();
2162+
quasis.add(convertChild(node, "head"));
2163+
for (JsonElement elt : node.get("templateSpans").getAsJsonArray()) {
2164+
JsonObject templateSpan = (JsonObject) elt;
2165+
expressions.add(convertChildAsType(templateSpan, "type"));
2166+
quasis.add(convertChild(templateSpan, "literal"));
2167+
}
2168+
return new TemplateLiteralTypeExpr(loc, expressions, quasis);
2169+
}
2170+
21552171
private Node convertTemplateElement(JsonObject node, String kind, SourceLocation loc) {
21562172
boolean tail = "TemplateTail".equals(kind);
21572173
if (loc.getSource().startsWith("`") || loc.getSource().startsWith("}")) {

javascript/ql/src/semmle/javascript/TypeScript.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,29 @@ class InferTypeExpr extends @infer_typeexpr, TypeParameterized, TypeExpr {
12131213
override string getAPrimaryQlClass() { result = "InferTypeExpr" }
12141214
}
12151215

1216+
/**
1217+
* A template literal used as a type.
1218+
*/
1219+
class TemplateLiteralTypeExpr extends @template_literal_typeexpr, TypeExpr {
1220+
/**
1221+
* Gets the `i`th element of this template literal, which may either
1222+
* be a type expression or a constant template element.
1223+
*/
1224+
ExprOrType getElement(int i) { result = getChild(i) }
1225+
1226+
/**
1227+
* Gets an element of this template literal.
1228+
*/
1229+
ExprOrType getAnElement() { result = getElement(_) }
1230+
1231+
/**
1232+
* Gets the number of elements of this template literal.
1233+
*/
1234+
int getNumElement() { result = count(getAnElement()) }
1235+
1236+
override string getAPrimaryQlClass() { result = "TemplateLiteralTypeExpr" }
1237+
}
1238+
12161239
/**
12171240
* A scope induced by a conditional type expression whose `extends` type
12181241
* contains `infer` types.

javascript/ql/src/semmlecode.javascript.dbscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ case @typeexpr.kind of
584584
| 34 = @rest_typeexpr
585585
| 35 = @bigint_literal_typeexpr
586586
| 36 = @readonly_typeexpr
587+
| 37 = @template_literal_typeexpr
587588
;
588589

589590
@typeref = @typeaccess | @type_decl;

0 commit comments

Comments
 (0)