mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
JS: Extract types and signatures for functions
This commit is contained in:
@@ -22,6 +22,7 @@ export interface AugmentedNode extends ts.Node {
|
||||
$symbol?: number;
|
||||
$resolvedSignature?: number;
|
||||
$overloadIndex?: number;
|
||||
$declaredSignature?: number;
|
||||
}
|
||||
|
||||
export type AugmentedPos = number;
|
||||
@@ -263,6 +264,17 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj
|
||||
namePart.$symbol = typeTable.getSymbolId(symbol);
|
||||
}
|
||||
}
|
||||
if (ts.isFunctionLike(node)) {
|
||||
let signature = typeChecker.getSignatureFromDeclaration(node);
|
||||
if (signature != null) {
|
||||
let kind = ts.isConstructSignatureDeclaration(node) || ts.isConstructorDeclaration(node)
|
||||
? ts.SignatureKind.Construct : ts.SignatureKind.Call;
|
||||
let id = typeTable.getSignatureId(kind, signature);
|
||||
if (id != null) {
|
||||
(node as AugmentedNode).$declaredSignature = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,8 +314,10 @@ function isTypedNode(node: ts.Node): boolean {
|
||||
case ts.SyntaxKind.BinaryExpression:
|
||||
case ts.SyntaxKind.CallExpression:
|
||||
case ts.SyntaxKind.ClassExpression:
|
||||
case ts.SyntaxKind.ClassDeclaration:
|
||||
case ts.SyntaxKind.CommaListExpression:
|
||||
case ts.SyntaxKind.ConditionalExpression:
|
||||
case ts.SyntaxKind.Constructor:
|
||||
case ts.SyntaxKind.DeleteExpression:
|
||||
case ts.SyntaxKind.ElementAccessExpression:
|
||||
case ts.SyntaxKind.ExpressionStatement:
|
||||
@@ -311,9 +325,13 @@ function isTypedNode(node: ts.Node): boolean {
|
||||
case ts.SyntaxKind.FalseKeyword:
|
||||
case ts.SyntaxKind.FunctionDeclaration:
|
||||
case ts.SyntaxKind.FunctionExpression:
|
||||
case ts.SyntaxKind.GetAccessor:
|
||||
case ts.SyntaxKind.Identifier:
|
||||
case ts.SyntaxKind.IndexSignature:
|
||||
case ts.SyntaxKind.JsxExpression:
|
||||
case ts.SyntaxKind.LiteralType:
|
||||
case ts.SyntaxKind.MethodDeclaration:
|
||||
case ts.SyntaxKind.MethodSignature:
|
||||
case ts.SyntaxKind.NewExpression:
|
||||
case ts.SyntaxKind.NonNullExpression:
|
||||
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
@@ -327,6 +345,7 @@ function isTypedNode(node: ts.Node): boolean {
|
||||
case ts.SyntaxKind.PrefixUnaryExpression:
|
||||
case ts.SyntaxKind.PropertyAccessExpression:
|
||||
case ts.SyntaxKind.RegularExpressionLiteral:
|
||||
case ts.SyntaxKind.SetAccessor:
|
||||
case ts.SyntaxKind.StringLiteral:
|
||||
case ts.SyntaxKind.TaggedTemplateExpression:
|
||||
case ts.SyntaxKind.TemplateExpression:
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.List;
|
||||
public abstract class AFunctionExpression extends Expression implements IFunction {
|
||||
private final AFunction<? extends Node> fn;
|
||||
private int symbol = -1;
|
||||
private int declaredSignature = -1;
|
||||
|
||||
public AFunctionExpression(
|
||||
String type,
|
||||
@@ -144,4 +145,14 @@ public abstract class AFunctionExpression extends Expression implements IFunctio
|
||||
public void setSymbol(int symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeclaredSignatureId() {
|
||||
return declaredSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeclaredSignatureId(int id) {
|
||||
declaredSignature = id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ public class FunctionDeclaration extends Statement implements IFunction {
|
||||
private final AFunction<? extends Node> fn;
|
||||
private final boolean hasDeclareKeyword;
|
||||
private int symbol = -1;
|
||||
private int staticType = -1;
|
||||
private int declaredSignature = -1;
|
||||
|
||||
public FunctionDeclaration(
|
||||
SourceLocation loc,
|
||||
@@ -185,4 +187,24 @@ public class FunctionDeclaration extends Statement implements IFunction {
|
||||
public void setSymbol(int symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStaticTypeId() {
|
||||
return staticType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStaticTypeId(int id) {
|
||||
staticType = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeclaredSignatureId() {
|
||||
return declaredSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeclaredSignatureId(int id) {
|
||||
declaredSignature = id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ package com.semmle.js.ast;
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.INodeWithSymbol;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.ITypedAstNode;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
import java.util.List;
|
||||
|
||||
/** A function declaration or expression. */
|
||||
public interface IFunction extends IStatementContainer, INodeWithSymbol {
|
||||
public interface IFunction extends IStatementContainer, INodeWithSymbol, ITypedAstNode {
|
||||
/** The function name; may be null for function expressions. */
|
||||
public Identifier getId();
|
||||
|
||||
@@ -63,4 +64,15 @@ public interface IFunction extends IStatementContainer, INodeWithSymbol {
|
||||
public List<DecoratorList> getParameterDecorators();
|
||||
|
||||
public boolean hasDeclareKeyword();
|
||||
|
||||
/**
|
||||
* Gets the type signature of this function as determined by the TypeScript compiler, or -1 if no
|
||||
* call signature was extracted.
|
||||
*
|
||||
* <p>The ID refers to a signature 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.
|
||||
*/
|
||||
public int getDeclaredSignatureId();
|
||||
|
||||
public void setDeclaredSignatureId(int id);
|
||||
}
|
||||
|
||||
@@ -762,6 +762,7 @@ public class ASTExtractor {
|
||||
trapwriter.addTuple("hasDeclareKeyword", key);
|
||||
}
|
||||
extractFunction(nd, key);
|
||||
emitStaticType(nd, key);
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -833,7 +834,13 @@ public class ASTExtractor {
|
||||
extractParameterDefaultsAndTypes(nd, key, i);
|
||||
|
||||
extractFunctionAttributes(nd, key);
|
||||
|
||||
// Extract associated symbol and signature
|
||||
emitNodeSymbol(nd, key);
|
||||
if (nd.getDeclaredSignatureId() != -1) {
|
||||
Label signatureKey = trapwriter.globalID("signature;" + nd.getDeclaredSignatureId());
|
||||
trapwriter.addTuple("declared_function_signature", key, signatureKey);
|
||||
}
|
||||
|
||||
boolean oldIsStrict = isStrict;
|
||||
isStrict = bodyIsStrict;
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.semmle.js.ast.ForOfStatement;
|
||||
import com.semmle.js.ast.ForStatement;
|
||||
import com.semmle.js.ast.FunctionDeclaration;
|
||||
import com.semmle.js.ast.FunctionExpression;
|
||||
import com.semmle.js.ast.IFunction;
|
||||
import com.semmle.js.ast.INode;
|
||||
import com.semmle.js.ast.IPattern;
|
||||
import com.semmle.js.ast.Identifier;
|
||||
@@ -670,6 +671,13 @@ public class TypeScriptASTConverter {
|
||||
attachSymbolInformation(node, json);
|
||||
}
|
||||
|
||||
/** Attached the declared call signature to a function. */
|
||||
private void attachDeclaredSignature(IFunction node, JsonObject json) {
|
||||
if (json.has("$declaredSignature")) {
|
||||
node.setDeclaredSignatureId(json.get("$declaredSignature").getAsInt());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given array of TypeScript AST nodes into a list of JavaScript AST nodes, skipping
|
||||
* any {@code null} elements.
|
||||
@@ -786,15 +794,18 @@ public class TypeScriptASTConverter {
|
||||
}
|
||||
|
||||
private Node convertArrowFunction(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
return new ArrowFunctionExpression(
|
||||
loc,
|
||||
convertParameters(node),
|
||||
convertChild(node, "body"),
|
||||
false,
|
||||
hasModifier(node, "AsyncKeyword"),
|
||||
convertChildrenNotNull(node, "typeParameters"),
|
||||
convertParameterTypes(node),
|
||||
convertChildAsType(node, "type"));
|
||||
ArrowFunctionExpression function =
|
||||
new ArrowFunctionExpression(
|
||||
loc,
|
||||
convertParameters(node),
|
||||
convertChild(node, "body"),
|
||||
false,
|
||||
hasModifier(node, "AsyncKeyword"),
|
||||
convertChildrenNotNull(node, "typeParameters"),
|
||||
convertParameterTypes(node),
|
||||
convertChildAsType(node, "type"));
|
||||
attachDeclaredSignature(function, node);
|
||||
return function;
|
||||
}
|
||||
|
||||
private Node convertAwaitExpression(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
@@ -1044,6 +1055,8 @@ public class TypeScriptASTConverter {
|
||||
null,
|
||||
null);
|
||||
attachSymbolInformation(value, node);
|
||||
attachStaticType(value, node);
|
||||
attachDeclaredSignature(value, node);
|
||||
List<FieldDefinition> parameterFields = convertParameterFields(node);
|
||||
return new MethodDefinition(loc, flags, methodKind, key, value, parameterFields);
|
||||
}
|
||||
@@ -1234,6 +1247,8 @@ public class TypeScriptASTConverter {
|
||||
returnType,
|
||||
thisParam);
|
||||
attachSymbolInformation(function, node);
|
||||
attachStaticType(function, node);
|
||||
attachDeclaredSignature(function, node);
|
||||
return fixExports(loc, function);
|
||||
}
|
||||
|
||||
@@ -1247,18 +1262,22 @@ public class TypeScriptASTConverter {
|
||||
List<DecoratorList> paramDecorators = convertParameterDecorators(node);
|
||||
ITypeExpression returnType = convertChildAsType(node, "type");
|
||||
ITypeExpression thisParam = convertThisParameterType(node);
|
||||
return new FunctionExpression(
|
||||
loc,
|
||||
fnId,
|
||||
params,
|
||||
fnbody,
|
||||
generator,
|
||||
async,
|
||||
convertChildrenNotNull(node, "typeParameters"),
|
||||
paramTypes,
|
||||
paramDecorators,
|
||||
returnType,
|
||||
thisParam);
|
||||
FunctionExpression function =
|
||||
new FunctionExpression(
|
||||
loc,
|
||||
fnId,
|
||||
params,
|
||||
fnbody,
|
||||
generator,
|
||||
async,
|
||||
convertChildrenNotNull(node, "typeParameters"),
|
||||
paramTypes,
|
||||
paramDecorators,
|
||||
returnType,
|
||||
thisParam);
|
||||
attachStaticType(function, node);
|
||||
attachDeclaredSignature(function, node);
|
||||
return function;
|
||||
}
|
||||
|
||||
private Node convertFunctionType(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
@@ -1591,7 +1610,7 @@ public class TypeScriptASTConverter {
|
||||
List<DecoratorList> paramDecorators = convertParameterDecorators(node);
|
||||
List<TypeParameter> typeParameters = convertChildrenNotNull(node, "typeParameters");
|
||||
ITypeExpression thisType = convertThisParameterType(node);
|
||||
FunctionExpression method =
|
||||
FunctionExpression function =
|
||||
new FunctionExpression(
|
||||
loc,
|
||||
null,
|
||||
@@ -1604,8 +1623,10 @@ public class TypeScriptASTConverter {
|
||||
paramDecorators,
|
||||
returnType,
|
||||
thisType);
|
||||
attachSymbolInformation(method, node);
|
||||
return method;
|
||||
attachSymbolInformation(function, node);
|
||||
attachStaticType(function, node);
|
||||
attachDeclaredSignature(function, node);
|
||||
return function;
|
||||
}
|
||||
|
||||
private Node convertNamespaceDeclaration(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
|
||||
@@ -416,6 +416,13 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||
*/
|
||||
CanonicalFunctionName getCanonicalName() { ast_node_symbol(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the call signature of this function, as determined by the TypeScript compiler, if any.
|
||||
*/
|
||||
CallSignatureType getCallSignature() {
|
||||
declared_function_signature(this, result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -641,6 +641,11 @@ ast_node_type(
|
||||
unique int node: @typed_ast_node ref,
|
||||
int typ: @type ref);
|
||||
|
||||
declared_function_signature(
|
||||
unique int node: @function ref,
|
||||
int sig: @signature_type ref
|
||||
);
|
||||
|
||||
invoke_expr_signature(
|
||||
unique int node: @invokeexpr ref,
|
||||
int sig: @signature_type ref
|
||||
|
||||
@@ -6,9 +6,19 @@ test_ExprSignature
|
||||
| tst.ts:12:8:12:8 | x | number |
|
||||
| tst.ts:16:8:16:8 | x | number |
|
||||
| tst.ts:17:8:17:8 | x | any |
|
||||
| tst.ts:21:3:21:28 | method( ... string; | (x: number): string |
|
||||
| tst.ts:21:10:21:10 | x | number |
|
||||
| tst.ts:23:3:23:38 | overloa ... number; | (x: any): any |
|
||||
| tst.ts:23:3:23:38 | overloa ... number; | (x: number): number |
|
||||
| tst.ts:23:3:23:38 | overloa ... number; | (x: string): string |
|
||||
| tst.ts:23:20:23:20 | x | number |
|
||||
| tst.ts:24:3:24:38 | overloa ... string; | (x: any): any |
|
||||
| tst.ts:24:3:24:38 | overloa ... string; | (x: number): number |
|
||||
| tst.ts:24:3:24:38 | overloa ... string; | (x: string): string |
|
||||
| tst.ts:24:20:24:20 | x | string |
|
||||
| tst.ts:25:3:25:32 | overloa ... ): any; | (x: any): any |
|
||||
| tst.ts:25:3:25:32 | overloa ... ): any; | (x: number): number |
|
||||
| tst.ts:25:3:25:32 | overloa ... ): any; | (x: string): string |
|
||||
| tst.ts:25:20:25:20 | x | any |
|
||||
| tst.ts:28:5:28:5 | m | Method |
|
||||
| tst.ts:29:1:29:1 | m | Method |
|
||||
@@ -22,7 +32,9 @@ test_ExprSignature
|
||||
| tst.ts:30:1:30:25 | m.overl ... ("foo") | string |
|
||||
| tst.ts:30:20:30:24 | "foo" | "foo" |
|
||||
| tst.ts:33:3:33:10 | callback | (x: number): string |
|
||||
| tst.ts:33:13:33:33 | (x: num ... string | (x: number): string |
|
||||
| tst.ts:33:14:33:14 | x | number |
|
||||
| tst.ts:37:3:37:18 | method(x: T): T; | (x: T): T |
|
||||
| tst.ts:37:10:37:10 | x | T |
|
||||
| tst.ts:40:10:40:12 | foo | (g: Generic<string>): string |
|
||||
| tst.ts:40:14:40:14 | g | Generic<string> |
|
||||
@@ -30,6 +42,11 @@ test_ExprSignature
|
||||
| tst.ts:41:10:41:17 | g.method | (x: string): string |
|
||||
| tst.ts:41:10:41:24 | g.method("foo") | string |
|
||||
| tst.ts:41:19:41:23 | "foo" | "foo" |
|
||||
| tst.ts:44:15:44:15 | C | C |
|
||||
| tst.ts:45:3:45:25 | constru ... tring); | any |
|
||||
| tst.ts:45:15:45:15 | x | string |
|
||||
| tst.ts:46:3:46:25 | constru ... umber); | any |
|
||||
| tst.ts:46:15:46:15 | x | number |
|
||||
test_TypeReferenceSig
|
||||
| Callable | function | 0 | (x: number): string |
|
||||
| Newable | constructor | 0 | new (x: number): any |
|
||||
@@ -38,3 +55,20 @@ test_TypeReferenceSig
|
||||
| OverloadedCallable | function | 2 | (x: any): any |
|
||||
| OverloadedNewable | constructor | 0 | new (x: number): OverloadedNewable |
|
||||
| OverloadedNewable | constructor | 1 | new (x: any): any |
|
||||
test_FunctionCallSig
|
||||
| tst.ts:2:3:2:22 | (x: number): string; | (x: number): string |
|
||||
| tst.ts:6:3:6:22 | (x: number): number; | (x: number): number |
|
||||
| tst.ts:7:3:7:22 | (x: string): string; | (x: string): string |
|
||||
| tst.ts:8:3:8:16 | (x: any): any; | (x: any): any |
|
||||
| tst.ts:12:3:12:23 | new (x: ... ): any; | new (x: number): any |
|
||||
| tst.ts:16:3:16:37 | new (x: ... ewable; | new (x: number): OverloadedNewable |
|
||||
| tst.ts:17:3:17:20 | new (x: any): any; | new (x: any): any |
|
||||
| tst.ts:21:3:21:28 | method( ... string; | (x: number): string |
|
||||
| tst.ts:23:3:23:38 | overloa ... number; | (x: number): number |
|
||||
| tst.ts:24:3:24:38 | overloa ... string; | (x: string): string |
|
||||
| tst.ts:25:3:25:32 | overloa ... ): any; | (x: any): any |
|
||||
| tst.ts:33:13:33:33 | (x: num ... string | (x: number): string |
|
||||
| tst.ts:37:3:37:18 | method(x: T): T; | (x: T): T |
|
||||
| tst.ts:40:1:42:1 | functio ... oo");\\n} | (g: Generic<string>): string |
|
||||
| tst.ts:45:3:45:25 | constru ... tring); | new (x: string): C |
|
||||
| tst.ts:46:3:46:25 | constru ... umber); | new (x: number): C |
|
||||
|
||||
@@ -16,3 +16,7 @@ query predicate test_ExprSignature(Expr expr, string type) {
|
||||
query predicate test_TypeReferenceSig(TypeReference type, SignatureKind kind, int n, CallSignatureType sig) {
|
||||
sig = type.getSignature(kind, n)
|
||||
}
|
||||
|
||||
query predicate test_FunctionCallSig(Function f, CallSignatureType sig) {
|
||||
sig = f.getCallSignature()
|
||||
}
|
||||
|
||||
@@ -40,3 +40,8 @@ interface Generic<T> {
|
||||
function foo(g: Generic<string>) {
|
||||
return g.method("foo");
|
||||
}
|
||||
|
||||
declare class C {
|
||||
constructor(x: string);
|
||||
constructor(x: number);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user