JavaScript: Open-source extractor.

This commit is contained in:
Max Schaefer
2018-11-06 08:25:02 +00:00
parent e03b4f0cb6
commit 4c4920c3a9
992 changed files with 134506 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An array type, such as <tt>number[]</tt>, or in general <tt>T[]</tt> where
* <tt>T</tt> is a type.
*/
public class ArrayTypeExpr extends TypeExpression {
private final ITypeExpression elementType;
public ArrayTypeExpr(SourceLocation loc, ITypeExpression elementType) {
super("ArrayTypeExpr", loc);
this.elementType = elementType;
}
public ITypeExpression getElementType() {
return elementType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,44 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A conditional type annotation, such as <tt>T extends any[] ? A : B</tt>.
*/
public class ConditionalTypeExpr extends TypeExpression {
private ITypeExpression checkType;
private ITypeExpression extendsType;
private ITypeExpression trueType;
private ITypeExpression falseType;
public ConditionalTypeExpr(SourceLocation loc, ITypeExpression checkType, ITypeExpression extendsType,
ITypeExpression trueType, ITypeExpression falseType) {
super("ConditionalTypeExpr", loc);
this.checkType = checkType;
this.extendsType = extendsType;
this.trueType = trueType;
this.falseType = falseType;
}
public ITypeExpression getCheckType() {
return checkType;
}
public ITypeExpression getExtendsType() {
return extendsType;
}
public ITypeExpression getTrueType() {
return trueType;
}
public ITypeExpression getFalseType() {
return falseType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.Decorator;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
public class DecoratorList extends Expression {
private final List<Decorator> decorators;
public DecoratorList(SourceLocation loc, List<Decorator> decorators) {
super("DecoratorList", loc);
this.decorators = decorators;
}
public List<Decorator> getDecorators() {
return decorators;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,63 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.Decorator;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
public class EnumDeclaration extends Statement implements INodeWithSymbol {
private final boolean isConst;
private final boolean hasDeclareKeyword;
private final List<Decorator> decorators;
private final Identifier id;
private List<EnumMember> members;
private int typeSymbol = -1;
public EnumDeclaration(SourceLocation loc, boolean isConst, boolean hasDeclareKeyword, List<Decorator> decorators, Identifier id,
List<EnumMember> members) {
super("EnumDeclaration", loc);
this.isConst = isConst;
this.hasDeclareKeyword = hasDeclareKeyword;
this.decorators = decorators;
this.id = id;
this.members = members;
}
public boolean isConst() {
return isConst;
}
public boolean hasDeclareKeyword() {
return hasDeclareKeyword;
}
public List<Decorator> getDecorators() {
return decorators;
}
public Identifier getId() {
return id;
}
public List<EnumMember> getMembers() {
return members;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
@Override
public int getSymbol() {
return typeSymbol;
}
@Override
public void setSymbol(int symbol) {
this.typeSymbol = symbol;
}
}

View File

@@ -0,0 +1,46 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.Node;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
public class EnumMember extends Node implements INodeWithSymbol {
private final Identifier id;
private final Expression initializer;
private int typeSymbol = -1;
public EnumMember(SourceLocation loc, Identifier id, Expression initializer) {
super("EnumMember", loc);
this.id = id;
this.initializer = initializer;
}
public Identifier getId() {
return id;
}
/**
* Returns the initializer expression, or {@code null} if this enum member has
* no explicit initializer.
*/
public Expression getInitializer() {
return initializer;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
@Override
public int getSymbol() {
return typeSymbol;
}
@Override
public void setSymbol(int symbol) {
this.typeSymbol = symbol;
}
}

View File

@@ -0,0 +1,28 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
/**
* A statement of form <tt>export as namespace X</tt> where <tt>X</tt> is an
* identifier.
*/
public class ExportAsNamespaceDeclaration extends Statement {
private Identifier id;
public ExportAsNamespaceDeclaration(SourceLocation loc, Identifier id) {
super("ExportAsNamespaceDeclaration", loc);
this.id = id;
}
public Identifier getId() {
return id;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,24 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
public class ExportWholeDeclaration extends Statement {
private final Expression rhs;
public ExportWholeDeclaration(SourceLocation loc, Expression rhs) {
super("ExportWholeDeclaration", loc);
this.rhs = rhs;
}
public Expression getRhs() {
return rhs;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,42 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An expression with type arguments, occurring as the super-class expression of
* a class. For example:
*
* <pre>
* class StringList extends List&lt;string&gt; {}
* </pre>
*
* Above, <tt>List</tt> is a concrete expression whereas its type argument is a
* type.
*/
public class ExpressionWithTypeArguments extends Expression {
private final Expression expression;
private final List<ITypeExpression> typeArguments;
public ExpressionWithTypeArguments(SourceLocation loc, Expression expression, List<ITypeExpression> typeArguments) {
super("ExpressionWithTypeArguments", loc);
this.expression = expression;
this.typeArguments = typeArguments;
}
public Expression getExpression() {
return expression;
}
public List<ITypeExpression> getTypeArguments() {
return typeArguments;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,35 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.Literal;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
/**
* A statement of form <tt>declare module "X" {...}</tt>.
*/
public class ExternalModuleDeclaration extends Statement {
private final Literal name;
private final List<Statement> body;
public ExternalModuleDeclaration(SourceLocation loc, Literal name, List<Statement> body) {
super("ExternalModuleDeclaration", loc);
this.name = name;
this.body = body;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
public Literal getName() {
return name;
}
public List<Statement> getBody() {
return body;
}
}

View File

@@ -0,0 +1,24 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
public class ExternalModuleReference extends Expression {
private final Expression expression;
public ExternalModuleReference(SourceLocation loc, Expression expression) {
super("ExternalModuleReference", loc);
this.expression = expression;
}
public Expression getExpression() {
return expression;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,29 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.FunctionExpression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
public class FunctionTypeExpr extends TypeExpression {
private final FunctionExpression function;
private final boolean isConstructor;
public FunctionTypeExpr(SourceLocation loc, FunctionExpression function, boolean isConstructor) {
super("FunctionTypeExpr", loc);
this.function = function;
this.isConstructor = isConstructor;
}
public FunctionExpression getFunction() {
return function;
}
public boolean isConstructor() {
return isConstructor;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,33 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An instantiation of a named type, such as <tt>Array&lt;number&gt;</tt>
*/
public class GenericTypeExpr extends TypeExpression {
final private ITypeExpression typeName; // Always Identifier or MemberExpression
final private List<ITypeExpression> typeArguments;
public GenericTypeExpr(SourceLocation loc, ITypeExpression typeName, List<ITypeExpression> typeArguments) {
super("GenericTypeExpr", loc);
this.typeName = typeName;
this.typeArguments = typeArguments;
}
public ITypeExpression getTypeName() {
return typeName;
}
public List<ITypeExpression> getTypeArguments() {
return typeArguments;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,28 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
/**
* A statement of form: <tt>declare global { ... }</tt>
*/
public class GlobalAugmentationDeclaration extends Statement {
private final List<Statement> body;
public GlobalAugmentationDeclaration(SourceLocation loc, List<Statement> body) {
super("GlobalAugmentationDeclaration", loc);
this.body = body;
}
public List<Statement> getBody() {
return body;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,17 @@
package com.semmle.ts.ast;
/**
* An AST node that is associated with a TypeScript compiler symbol.
*
* This can be the symbol for the type defined by this node, of it this is a
* module top-level, the symbol for that module.
*/
public interface INodeWithSymbol {
/**
* Gets a number identifying the symbol associated with this AST node, or
* <tt>-1</tt> if there is no such symbol.
*/
int getSymbol();
void setSymbol(int symbol);
}

View File

@@ -0,0 +1,15 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.INode;
import com.semmle.js.ast.Literal;
/**
* An AST node that may occur as part of a TypeScript type annotation.
* <p>
* At the QL level, expressions and type annotations are completely separate. In
* the extractor, however, some expressions such as {@link Literal} type may
* occur in a type annotation because the TypeScript AST does not distinguish
* <tt>null</tt> literals from the <tt>null</tt> type.
*/
public interface ITypeExpression extends INode, ITypedAstNode {
}

View File

@@ -0,0 +1,17 @@
package com.semmle.ts.ast;
/**
* An AST node with an associated static type.
*/
public interface ITypedAstNode {
/**
* Gets the static type of this node as determined by the TypeScript compiler,
* or -1 if no type was determined.
* <p>
* The ID refers to a type in a table that is extracted on a per-project basis,
* and the meaning of this type ID is not available at the AST level.
*/
int getStaticTypeId();
void setStaticTypeId(int id);
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An import type such as in <tt>import("http").ServerRequest</tt>.
*/
public class ImportTypeExpr extends Expression implements ITypeExpression {
private final ITypeExpression path;
public ImportTypeExpr(SourceLocation loc, ITypeExpression path) {
super("ImportTypeExpr", loc);
this.path = path;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
public ITypeExpression getPath() {
return path;
}
}

View File

@@ -0,0 +1,34 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
/**
* An import of form <tt>import a = E</tt>.
*/
public class ImportWholeDeclaration extends Statement {
private final Identifier lhs;
private final Expression rhs;
public ImportWholeDeclaration(SourceLocation loc, Identifier lhs, Expression rhs) {
super("ImportWholeDeclaration", loc);
this.lhs = lhs;
this.rhs = rhs;
}
public Identifier getLhs() {
return lhs;
}
public Expression getRhs() {
return rhs;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,31 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type of form <tt>T[K]</tt> where <tt>T</tt> and <tt>K</tt> are types.
*/
public class IndexedAccessTypeExpr extends TypeExpression {
private final ITypeExpression objectType;
private final ITypeExpression indexType;
public IndexedAccessTypeExpr(SourceLocation loc, ITypeExpression objectType, ITypeExpression indexType) {
super("IndexedAccessTypeExpr", loc);
this.objectType = objectType;
this.indexType = indexType;
}
public ITypeExpression getObjectType() {
return objectType;
}
public ITypeExpression getIndexType() {
return indexType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,25 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type annotation of form <tt>infer R</tt>
*/
public class InferTypeExpr extends TypeExpression {
private TypeParameter typeParameter;
public InferTypeExpr(SourceLocation loc, TypeParameter typeParameter) {
super("InferTypeExpr", loc);
this.typeParameter = typeParameter;
}
public TypeParameter getTypeParameter() {
return typeParameter;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,65 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.MemberDefinition;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
/**
* A TypeScript interface declaration.
*/
public class InterfaceDeclaration extends Statement implements INodeWithSymbol {
private final Identifier name;
private final List<TypeParameter> typeParameters;
private final List<ITypeExpression> superInterfaces;
private final List<MemberDefinition<?>> body;
private int typeSymbol = -1;
public InterfaceDeclaration(SourceLocation loc, Identifier name, List<TypeParameter> typeParameters,
List<ITypeExpression> superInterfaces,
List<MemberDefinition<?>> body) {
super("InterfaceDeclaration", loc);
this.name = name;
this.typeParameters = typeParameters;
this.superInterfaces = superInterfaces;
this.body = body;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
public Identifier getName() {
return name;
}
public List<TypeParameter> getTypeParameters() {
return typeParameters;
}
public boolean hasTypeParameters() {
return !typeParameters.isEmpty();
}
public List<MemberDefinition<?>> getBody() {
return body;
}
public List<ITypeExpression> getSuperInterfaces() {
return superInterfaces;
}
@Override
public int getSymbol() {
return typeSymbol;
}
@Override
public void setSymbol(int symbol) {
this.typeSymbol = symbol;
}
}

View File

@@ -0,0 +1,28 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.MemberDefinition;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An inline interface type, such as <tt>{x: number; y: number}</tt>.
*/
public class InterfaceTypeExpr extends TypeExpression {
private final List<MemberDefinition<?>> body;
public InterfaceTypeExpr(SourceLocation loc, List<MemberDefinition<?>> body) {
super("InterfaceTypeExpr", loc);
this.body = body;
}
public List<MemberDefinition<?>> getBody() {
return body;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,29 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An intersection type such as <tt>T&amp;S</tt>, denoting the intersection of
* type <tt>T</tt> and type <tt>S</tt>.
*/
public class IntersectionTypeExpr extends TypeExpression {
private final List<ITypeExpression> elementTypes;
public IntersectionTypeExpr(SourceLocation loc, List<ITypeExpression> elementTypes) {
super("IntersectionTypeExpr", loc);
this.elementTypes = elementTypes;
}
/** The members of the intersection type; always contains at least two types. */
public List<ITypeExpression> getElementTypes() {
return elementTypes;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,32 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type of form <tt>E is T</tt> where <tt>E</tt> is a parameter name or
* <tt>this</tt> and <tt>T</tt> is a type.
*/
public class IsTypeExpr extends TypeExpression {
private final ITypeExpression left; // Always Identifier or KeywordTypeExpr (in case of 'this')
private final ITypeExpression right;
public IsTypeExpr(SourceLocation loc, ITypeExpression left, ITypeExpression right) {
super("IsTypeExpr", loc);
this.left = left;
this.right = right;
}
public ITypeExpression getLeft() {
return left;
}
public ITypeExpression getRight() {
return right;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,25 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type of form <tt>keyof T</tt> where <tt>T</tt> is a type.
*/
public class KeyofTypeExpr extends TypeExpression {
private final ITypeExpression elementType;
public KeyofTypeExpr(SourceLocation loc, ITypeExpression elementType) {
super("KeyofTypeExpr", loc);
this.elementType = elementType;
}
public ITypeExpression getElementType() {
return elementType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,32 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* One of the TypeScript keyword types, such as <tt>string</tt> or <tt>any</tt>.
* <p>
* This includes the type <tt>unique symbol</tt> which consists of two keywords
* but is represented as a keyword single type expression.
* <p>
* At the QL level, the <tt>null</tt> type is also a keyword type. In the
* extractor, however, this is represented by a Literal, because the TypeScript
* AST does not distinguish those two uses of <tt>null</tt>.
*/
public class KeywordTypeExpr extends TypeExpression {
private final String keyword;
public KeywordTypeExpr(SourceLocation loc, String keyword) {
super("KeywordTypeExpr", loc);
this.keyword = keyword;
}
public String getKeyword() {
return keyword;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,35 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type of form <tt>{ [K in C]: T }</tt>, where <tt>T</tt> is a type that may
* refer to <tt>K</tt>.
* <p>
* As with the TypeScript AST, the <tt>K in C</tt> part is represented as a type
* parameter with <tt>C</tt> as its upper bound.
*/
public class MappedTypeExpr extends TypeExpression {
private final TypeParameter typeParameter;
private final ITypeExpression elementType;
public MappedTypeExpr(SourceLocation loc, TypeParameter typeParameter, ITypeExpression elementType) {
super("MappedTypeExpr", loc);
this.typeParameter = typeParameter;
this.elementType = elementType;
}
public TypeParameter getTypeParameter() {
return typeParameter;
}
public ITypeExpression getElementType() {
return elementType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,62 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
public class NamespaceDeclaration extends Statement implements INodeWithSymbol {
private final Identifier name;
private final List<Statement> body;
private final boolean isInstantiated;
private final boolean hasDeclareKeyword;
private int symbol = -1;
public NamespaceDeclaration(SourceLocation loc, Identifier name, List<Statement> body, boolean isInstantiated, boolean hasDeclareKeyword) {
super("NamespaceDeclaration", loc);
this.name = name;
this.body = body;
this.isInstantiated = isInstantiated;
this.hasDeclareKeyword = hasDeclareKeyword;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
public Identifier getName() {
return name;
}
public List<Statement> getBody() {
return body;
}
/**
* Returns whether this is an instantiated namespace.
*
* Non-instantiated namespaces only contain interface types, type aliases, and
* other non-instantiated namespaces. The TypeScript compiler does not emit
* code for non-instantiated namespaces.
*/
public boolean isInstantiated() {
return isInstantiated;
}
public boolean hasDeclareKeyword() {
return hasDeclareKeyword;
}
@Override
public int getSymbol() {
return this.symbol;
}
@Override
public void setSymbol(int symbol) {
this.symbol = symbol;
}
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A TypeScript expression of form <tt>E!</tt>, asserting that <tt>E</tt> is not null.
*/
public class NonNullAssertion extends Expression {
private final Expression expression;
public NonNullAssertion(SourceLocation loc, Expression expression) {
super("NonNullAssertion", loc);
this.expression = expression;
}
public Expression getExpression() {
return expression;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An optional type in a tuple type, such as <tt>number?</tt> in
* <tt>[string, number?]</tt>.
*/
public class OptionalTypeExpr extends TypeExpression {
private final ITypeExpression elementType;
public OptionalTypeExpr(SourceLocation loc, ITypeExpression elementType) {
super("OptionalTypeExpr", loc);
this.elementType = elementType;
}
public ITypeExpression getElementType() {
return elementType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,25 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type expression in parentheses, such as <tt>("foo" | "bar")</tt>.
*/
public class ParenthesizedTypeExpr extends TypeExpression {
private final ITypeExpression elementType;
public ParenthesizedTypeExpr(SourceLocation loc, ITypeExpression elementType) {
super("ParenthesizedTypeExpr", loc);
this.elementType = elementType;
}
public ITypeExpression getElementType() {
return elementType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A rest type in a tuple type, such as <tt>number[]</tt> in
* <tt>[string, ...number[]]</tt>.
*/
public class RestTypeExpr extends TypeExpression {
private final ITypeExpression arrayType;
public RestTypeExpr(SourceLocation loc, ITypeExpression arrayType) {
super("RestTypeExpr", loc);
this.arrayType = arrayType;
}
public ITypeExpression getArrayType() {
return arrayType;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,27 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A tuple type, such as <tt>[number, string]</tt>.
*/
public class TupleTypeExpr extends TypeExpression {
private final List<ITypeExpression> elementTypes;
public TupleTypeExpr(SourceLocation loc, List<ITypeExpression> elementTypes) {
super("TupleTypeExpr", loc);
this.elementTypes = elementTypes;
}
public List<ITypeExpression> getElementTypes() {
return elementTypes;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,53 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Visitor;
public class TypeAliasDeclaration extends Statement implements INodeWithSymbol {
private final Identifier name;
private final List<TypeParameter> typeParameters;
private final ITypeExpression definition;
private int typeSymbol = -1;
public TypeAliasDeclaration(SourceLocation loc, Identifier name, List<TypeParameter> typeParameters, ITypeExpression definition) {
super("TypeAliasDeclaration", loc);
this.name = name;
this.typeParameters = typeParameters;
this.definition = definition;
}
public Identifier getId() {
return name;
}
public List<TypeParameter> getTypeParameters() {
return typeParameters;
}
public boolean hasTypeParameters() {
return !typeParameters.isEmpty();
}
public ITypeExpression getDefinition() {
return definition;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
@Override
public int getSymbol() {
return typeSymbol;
}
@Override
public void setSymbol(int symbol) {
this.typeSymbol = symbol;
}
}

View File

@@ -0,0 +1,42 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Expression;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* An expression of form <code>E as T</code> or <code>&lt;T&gt; E</code>.
*/
public class TypeAssertion extends Expression {
private final Expression expression;
private final ITypeExpression typeAnnotation;
private final boolean isAsExpression;
public TypeAssertion(SourceLocation loc, Expression expression, ITypeExpression typeAnnotation, boolean isAsExpression) {
super("TypeAssertion", loc);
this.expression = expression;
this.typeAnnotation = typeAnnotation;
this.isAsExpression = isAsExpression;
}
public Expression getExpression() {
return expression;
}
public ITypeExpression getTypeAnnotation() {
return typeAnnotation;
}
/**
* True if this is an assertion of form <tt>E as T</tt>, as opposed to the old
* syntax <code>&lt;T&gt; E</code>.
*/
public boolean isAsExpression() {
return isAsExpression;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Node;
import com.semmle.js.ast.SourceLocation;
/**
* An AST node that may occur as part of a TypeScript type annotation and is not
* also an expression.
*/
public abstract class TypeExpression extends Node implements ITypeExpression {
private int staticTypeId = -1;
public TypeExpression(String type, SourceLocation loc) {
super(type, loc);
}
@Override
public int getStaticTypeId() {
return staticTypeId;
}
@Override
public void setStaticTypeId(int staticTypeId) {
this.staticTypeId = staticTypeId;
}
}

View File

@@ -0,0 +1,53 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type parameter declared on a class, interface, function, or type alias.
* <p>
* The general form of a type parameter is: <tt>S extends T = U</tt>.
*/
public class TypeParameter extends TypeExpression {
private final Identifier id;
private final ITypeExpression bound;
private final ITypeExpression default_;
public TypeParameter(SourceLocation loc, Identifier id, ITypeExpression bound, ITypeExpression default_) {
super("TypeParameter", loc);
this.id = id;
this.bound = bound;
this.default_ = default_;
}
public Identifier getId() {
return id;
}
/**
* Returns the bound on the type parameter, or {@code null} if there is no
* bound.
* <p>
* For example, in <tt>T extends Array = number[]</tt> the bound is
* <tt>Array</tt>.
*/
public ITypeExpression getBound() {
return bound;
}
/**
* Returns the type parameter default, or {@code null} if there is no default,
* <p>
* For example, in <tt>T extends Array = number[]</tt> the default is
* <tt>number[]</tt>.
*/
public ITypeExpression getDefault() {
return default_;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/**
* A type of form <tt>typeof E</tt> where <tt>E</tt> is an expression that takes
* the form of a qualified name.
*/
public class TypeofTypeExpr extends TypeExpression {
private final ITypeExpression expression; // Always Identifier or MemberExpression.
public TypeofTypeExpr(SourceLocation loc, ITypeExpression expression) {
super("TypeofTypeExpr", loc);
this.expression = expression;
}
public ITypeExpression getExpression() {
return expression;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,26 @@
package com.semmle.ts.ast;
import java.util.List;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Visitor;
/** A union type such as <tt>number | string | boolean</tt>. */
public class UnionTypeExpr extends TypeExpression {
private final List<ITypeExpression> elementTypes;
public UnionTypeExpr(SourceLocation loc, List<ITypeExpression> elementTypes) {
super("UnionTypeExpr", loc);
this.elementTypes = elementTypes;
}
/** The members of the union; always contains at least two types. */
public List<ITypeExpression> getElementTypes() {
return elementTypes;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
}

View File

@@ -0,0 +1,247 @@
package com.semmle.ts.extractor;
import java.util.LinkedHashMap;
import java.util.Map;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.semmle.util.trap.TrapWriter;
import com.semmle.util.trap.TrapWriter.Label;
/**
* Extracts type and symbol information into TRAP files.
* <p>
* This is closely coupled with the <tt>type_table.ts</tt> file in the
* parser-wrapper. Type strings and symbol strings generated in that file are
* parsed here. See that file for reference and documentation.
*/
public class TypeExtractor {
private final TrapWriter trapWriter;
private final TypeTable table;
private static final Map<String, Integer> tagToKind = new LinkedHashMap<String, Integer>();
private static final int referenceKind = 6;
private static final int objectKind = 7;
private static final int typevarKind = 8;
private static final int typeofKind = 9;
private static final int uniqueSymbolKind = 15;
private static final int tupleKind = 18;
private static final int lexicalTypevarKind = 19;
private static final int thisKind = 20;
private static final int numberLiteralTypeKind = 21;
private static final int stringLiteralTypeKind = 22;
static {
tagToKind.put("any", 0);
tagToKind.put("string", 1);
tagToKind.put("number", 2);
tagToKind.put("union", 3);
tagToKind.put("true", 4);
tagToKind.put("false", 5);
tagToKind.put("reference", referenceKind);
tagToKind.put("object", objectKind);
tagToKind.put("typevar", typevarKind);
tagToKind.put("typeof", typeofKind);
tagToKind.put("void", 10);
tagToKind.put("undefined", 11);
tagToKind.put("null", 12);
tagToKind.put("never", 13);
tagToKind.put("plainsymbol", 14);
tagToKind.put("uniquesymbol", uniqueSymbolKind);
tagToKind.put("objectkeyword", 16);
tagToKind.put("intersection", 17);
tagToKind.put("tuple", tupleKind);
tagToKind.put("lextypevar", lexicalTypevarKind);
tagToKind.put("this", thisKind);
tagToKind.put("numlit", numberLiteralTypeKind);
tagToKind.put("strlit", stringLiteralTypeKind);
tagToKind.put("unknown", 23);
}
private static final Map<String, Integer> symbolKind = new LinkedHashMap<String, Integer>();
static {
symbolKind.put("root", 0);
symbolKind.put("member", 1);
symbolKind.put("other", 2);
}
public TypeExtractor(TrapWriter trapWriter, TypeTable table) {
this.trapWriter = trapWriter;
this.table = table;
}
public void extract() {
for (int i = 0; i < table.getNumberOfTypes(); ++i) {
extractType(i);
}
extractPropertyLookups(table.getPropertyLookups());
for (int i = 0; i < table.getNumberOfSymbols(); ++i) {
extractSymbol(i);
}
extractSymbolNameMapping("symbol_module", table.getModuleMappings());
extractSymbolNameMapping("symbol_global", table.getGlobalMappings());
extractSignatureMappings(table.getSignatureMappings());
for (int i = 0; i < table.getNumberOfSignatures(); ++i) {
extractSignature(i);
}
extractIndexTypeTable(table.getNumberIndexTypes(), "number_index_type");
extractIndexTypeTable(table.getStringIndexTypes(), "string_index_type");
extractBaseTypes(table.getBaseTypes());
extractSelfTypes(table.getSelfTypes());
}
private void extractType(int id) {
Label lbl = trapWriter.globalID("type;" + id);
String contents = table.getTypeString(id);
String[] parts = contents.split(";");
int kind = tagToKind.get(parts[0]);
trapWriter.addTuple("types", lbl, kind, table.getTypeToStringValue(id));
int firstChild = 1;
switch (kind) {
case referenceKind:
case typevarKind:
case typeofKind:
case uniqueSymbolKind: {
// The first part of a reference is the symbol for name binding.
Label symbol = trapWriter.globalID("symbol;" + parts[1]);
trapWriter.addTuple("type_symbol", lbl, symbol);
++firstChild;
break;
}
case tupleKind: {
// The first two parts denote minimum length and presence of rest element.
trapWriter.addTuple("tuple_type_min_length", lbl, Integer.parseInt(parts[1]));
if (parts[2].equals("t")) {
trapWriter.addTuple("tuple_type_rest", lbl);
}
firstChild += 2;
break;
}
case objectKind:
case lexicalTypevarKind:
firstChild = parts.length; // No children.
break;
case numberLiteralTypeKind:
case stringLiteralTypeKind:
firstChild = parts.length; // No children.
// The string value may contain `;` so don't use the split().
String value = contents.substring(parts[0].length() + 1);
trapWriter.addTuple("type_literal_value", lbl, value);
break;
}
for (int i = firstChild; i < parts.length; ++i) {
Label childLabel = trapWriter.globalID("type;" + parts[i]);
trapWriter.addTuple("type_child", childLabel, lbl, i - firstChild);
}
}
private void extractPropertyLookups(JsonObject lookups) {
JsonArray baseTypes = lookups.get("baseTypes").getAsJsonArray();
JsonArray names = lookups.get("names").getAsJsonArray();
JsonArray propertyTypes = lookups.get("propertyTypes").getAsJsonArray();
for (int i = 0; i < baseTypes.size(); ++i) {
int baseType = baseTypes.get(i).getAsInt();
String name = names.get(i).getAsString();
int propertyType = propertyTypes.get(i).getAsInt();
trapWriter.addTuple("type_property", trapWriter.globalID("type;" + baseType), name,
trapWriter.globalID("type;" + propertyType));
}
}
private void extractSymbol(int index) {
// Format is: kind;decl;name[;parent]
String[] parts = table.getSymbolString(index).split(";");
int kind = symbolKind.get(parts[0]);
String name = parts[2];
Label label = trapWriter.globalID("symbol;" + index);
trapWriter.addTuple("symbols", label, kind, name);
if (parts.length == 4) {
Label parentLabel = trapWriter.globalID("symbol;" + parts[3]);
trapWriter.addTuple("symbol_parent", label, parentLabel);
}
}
private void extractSymbolNameMapping(String relationName, JsonObject mappings) {
JsonArray symbols = mappings.get("symbols").getAsJsonArray();
JsonArray names = mappings.get("names").getAsJsonArray();
for (int i = 0; i < symbols.size(); ++i) {
Label symbol = trapWriter.globalID("symbol;" + symbols.get(i).getAsInt());
String moduleName = names.get(i).getAsString();
trapWriter.addTuple(relationName, symbol, moduleName);
}
}
private void extractSignature(int index) {
// Format is:
// kind;numTypeParams;requiredParams;returnType(;paramName;paramType)*
String[] parts = table.getSignatureString(index).split(";");
Label label = trapWriter.globalID("signature;" + index);
int kind = Integer.parseInt(parts[0]);
int numberOfTypeParameters = Integer.parseInt(parts[1]);
int requiredParameters = Integer.parseInt(parts[2]);
Label returnType = trapWriter.globalID("type;" + parts[3]);
trapWriter.addTuple("signature_types", label, kind, table.getSignatureToStringValue(index), numberOfTypeParameters,
requiredParameters);
trapWriter.addTuple("signature_contains_type", returnType, label, -1);
int numberOfParameters = (parts.length - 4) / 2; // includes type parameters
for (int i = 0; i < numberOfParameters; ++i) {
int partIndex = 4 + (2 * i);
String paramName = parts[partIndex];
String paramTypeId = parts[partIndex + 1];
if (paramTypeId.length() > 0) { // Unconstrained type parameters have an empty type ID.
Label paramType = trapWriter.globalID("type;" + parts[partIndex + 1]);
trapWriter.addTuple("signature_contains_type", paramType, label, i);
}
trapWriter.addTuple("signature_parameter_name", label, i, paramName);
}
}
private void extractSignatureMappings(JsonObject mappings) {
JsonArray baseTypes = mappings.get("baseTypes").getAsJsonArray();
JsonArray kinds = mappings.get("kinds").getAsJsonArray();
JsonArray indices = mappings.get("indices").getAsJsonArray();
JsonArray signatures = mappings.get("signatures").getAsJsonArray();
for (int i = 0; i < baseTypes.size(); ++i) {
int baseType = baseTypes.get(i).getAsInt();
int kind = kinds.get(i).getAsInt();
int index = indices.get(i).getAsInt();
int signatureId = signatures.get(i).getAsInt();
trapWriter.addTuple("type_contains_signature", trapWriter.globalID("type;" + baseType), kind, index,
trapWriter.globalID("signature;" + signatureId));
}
}
private void extractIndexTypeTable(JsonObject table, String relationName) {
JsonArray baseTypes = table.get("baseTypes").getAsJsonArray();
JsonArray propertyTypes = table.get("propertyTypes").getAsJsonArray();
for (int i = 0; i < baseTypes.size(); ++i) {
int baseType = baseTypes.get(i).getAsInt();
int propertyType = propertyTypes.get(i).getAsInt();
trapWriter.addTuple(relationName, trapWriter.globalID("type;" + baseType), trapWriter.globalID("type;" + propertyType));
}
}
private void extractBaseTypes(JsonObject table) {
JsonArray symbols = table.get("symbols").getAsJsonArray();
JsonArray baseTypeSymbols = table.get("baseTypeSymbols").getAsJsonArray();
for (int i = 0; i < symbols.size(); ++i) {
int symbolId = symbols.get(i).getAsInt();
int baseTypeSymbolId = baseTypeSymbols.get(i).getAsInt();
trapWriter.addTuple("base_type_names", trapWriter.globalID("symbol;" + symbolId),
trapWriter.globalID("symbol;" + baseTypeSymbolId));
}
}
private void extractSelfTypes(JsonObject table) {
JsonArray symbols = table.get("symbols").getAsJsonArray();
JsonArray selfTypes = table.get("selfTypes").getAsJsonArray();
for (int i = 0; i < symbols.size(); ++i) {
int symbolId = symbols.get(i).getAsInt();
int typeId = selfTypes.get(i).getAsInt();
trapWriter.addTuple("self_types", trapWriter.globalID("symbol;" + symbolId), trapWriter.globalID("type;" + typeId));
}
}
}

View File

@@ -0,0 +1,113 @@
package com.semmle.ts.extractor;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* Holds the output of the <tt>get-type-table</tt> command.
* <p>
* See documentation in <tt>parser-wrapper/src/type_table.ts</tt>.
*/
public class TypeTable {
private final JsonArray typeStrings;
private final JsonArray typeToStringValues;
private final JsonObject propertyLookups;
private final JsonArray symbolStrings;
private final JsonObject moduleMappings;
private final JsonObject globalMappings;
private final JsonArray signatureStrings;
private final JsonObject signatureMappings;
private final JsonArray signatureToStringValues;
private final JsonObject stringIndexTypes;
private final JsonObject numberIndexTypes;
private final JsonObject baseTypes;
private final JsonObject selfTypes;
public TypeTable(JsonObject typeTable) {
this.typeStrings = typeTable.get("typeStrings").getAsJsonArray();
this.typeToStringValues = typeTable.get("typeToStringValues").getAsJsonArray();
this.propertyLookups = typeTable.get("propertyLookups").getAsJsonObject();
this.symbolStrings = typeTable.get("symbolStrings").getAsJsonArray();
this.moduleMappings = typeTable.get("moduleMappings").getAsJsonObject();
this.globalMappings = typeTable.get("globalMappings").getAsJsonObject();
this.signatureStrings = typeTable.get("signatureStrings").getAsJsonArray();
this.signatureMappings = typeTable.get("signatureMappings").getAsJsonObject();
this.signatureToStringValues = typeTable.get("signatureToStringValues").getAsJsonArray();
this.numberIndexTypes = typeTable.get("numberIndexTypes").getAsJsonObject();
this.stringIndexTypes = typeTable.get("stringIndexTypes").getAsJsonObject();
this.baseTypes = typeTable.get("baseTypes").getAsJsonObject();
this.selfTypes = typeTable.get("selfTypes").getAsJsonObject();
}
public String getTypeString(int index) {
return typeStrings.get(index).getAsString();
}
public String getTypeToStringValue(int index) {
return typeToStringValues.get(index).getAsString();
}
public JsonObject getPropertyLookups() {
return propertyLookups;
}
public int getNumberOfTypes() {
return typeStrings.size();
}
public String getSymbolString(int index) {
return symbolStrings.get(index).getAsString();
}
public int getNumberOfSymbols() {
return symbolStrings.size();
}
public JsonObject getModuleMappings() {
return moduleMappings;
}
public JsonObject getGlobalMappings() {
return globalMappings;
}
public JsonArray getSignatureStrings() {
return signatureStrings;
}
public int getNumberOfSignatures() {
return signatureStrings.size();
}
public String getSignatureString(int i) {
return signatureStrings.get(i).getAsString();
}
public JsonObject getSignatureMappings() {
return signatureMappings;
}
public JsonArray getSignatureToStringValues() {
return signatureToStringValues;
}
public String getSignatureToStringValue(int i) {
return signatureToStringValues.get(i).getAsString();
}
public JsonObject getNumberIndexTypes() {
return numberIndexTypes;
}
public JsonObject getStringIndexTypes() {
return stringIndexTypes;
}
public JsonObject getBaseTypes() {
return baseTypes;
}
public JsonObject getSelfTypes() {
return selfTypes;
}
}