mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #19640 from asgerf/js/no-type-extraction
JS: Disable type extraction
This commit is contained in:
@@ -10,7 +10,6 @@ export interface AugmentedSourceFile extends ts.SourceFile {
|
||||
/** Internal property that we expose as a workaround. */
|
||||
redirectInfo?: object | null;
|
||||
$tokens?: Token[];
|
||||
$symbol?: number;
|
||||
$lineStarts?: ReadonlyArray<number>;
|
||||
}
|
||||
|
||||
@@ -18,11 +17,6 @@ export interface AugmentedNode extends ts.Node {
|
||||
$pos?: any;
|
||||
$end?: any;
|
||||
$declarationKind?: string;
|
||||
$type?: number;
|
||||
$symbol?: number;
|
||||
$resolvedSignature?: number;
|
||||
$overloadIndex?: number;
|
||||
$declaredSignature?: number;
|
||||
}
|
||||
|
||||
export type AugmentedPos = number;
|
||||
@@ -73,7 +67,7 @@ function tryGetTypeOfNode(typeChecker: ts.TypeChecker, node: AugmentedNode): ts.
|
||||
} catch (e) {
|
||||
let sourceFile = node.getSourceFile();
|
||||
let { line, character } = sourceFile.getLineAndCharacterOfPosition(node.pos);
|
||||
console.warn(`Could not compute type of ${ts.SyntaxKind[node.kind]} at ${sourceFile.fileName}:${line+1}:${character+1}`);
|
||||
console.warn(`Could not compute type of ${ts.SyntaxKind[node.kind]} at ${sourceFile.fileName}:${line + 1}:${character + 1}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -157,17 +151,6 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj
|
||||
});
|
||||
}
|
||||
|
||||
let typeChecker = project && project.program.getTypeChecker();
|
||||
let typeTable = project && project.typeTable;
|
||||
|
||||
// Associate a symbol with the AST node root, in case it is a module.
|
||||
if (typeTable != null) {
|
||||
let symbol = typeChecker.getSymbolAtLocation(ast);
|
||||
if (symbol != null) {
|
||||
ast.$symbol = typeTable.getSymbolId(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
visitAstNode(ast);
|
||||
function visitAstNode(node: AugmentedNode) {
|
||||
ts.forEachChild(node, visitAstNode);
|
||||
@@ -190,192 +173,5 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj
|
||||
node.$declarationKind = "var";
|
||||
}
|
||||
}
|
||||
|
||||
if (typeChecker != null) {
|
||||
if (isTypedNode(node) && !typeTable.skipExtractingTypes) {
|
||||
let contextualType = isContextuallyTypedNode(node)
|
||||
? typeChecker.getContextualType(node)
|
||||
: null;
|
||||
let type = contextualType || tryGetTypeOfNode(typeChecker, node);
|
||||
if (type != null) {
|
||||
let parent = node.parent;
|
||||
let unfoldAlias = ts.isTypeAliasDeclaration(parent) && node === parent.type;
|
||||
let id = typeTable.buildType(type, unfoldAlias);
|
||||
if (id != null) {
|
||||
node.$type = id;
|
||||
}
|
||||
}
|
||||
// Extract the target call signature of a function call.
|
||||
// In case the callee is overloaded or generic, this is not something we can
|
||||
// derive from the callee type in QL.
|
||||
if (ts.isCallOrNewExpression(node)) {
|
||||
let kind = ts.isCallExpression(node) ? ts.SignatureKind.Call : ts.SignatureKind.Construct;
|
||||
let resolvedSignature = typeChecker.getResolvedSignature(node);
|
||||
if (resolvedSignature != null) {
|
||||
let resolvedId = typeTable.getSignatureId(kind, resolvedSignature);
|
||||
if (resolvedId != null) {
|
||||
(node as AugmentedNode).$resolvedSignature = resolvedId;
|
||||
}
|
||||
let declaration = resolvedSignature.declaration;
|
||||
if (declaration != null) {
|
||||
// Find the generic signature, i.e. without call-site type arguments substituted,
|
||||
// but with overloading resolved.
|
||||
let calleeType = typeChecker.getTypeAtLocation(node.expression);
|
||||
if (calleeType != null && declaration != null) {
|
||||
let calleeSignatures = typeChecker.getSignaturesOfType(calleeType, kind);
|
||||
for (let i = 0; i < calleeSignatures.length; ++i) {
|
||||
if (calleeSignatures[i].declaration === declaration) {
|
||||
(node as AugmentedNode).$overloadIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Extract the symbol so the declaration can be found from QL.
|
||||
let name = (declaration as any).name;
|
||||
let symbol = name && typeChecker.getSymbolAtLocation(name);
|
||||
if (symbol != null) {
|
||||
(node as AugmentedNode).$symbol = typeTable.getSymbolId(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let symbolNode =
|
||||
isNamedNodeWithSymbol(node) ? node.name :
|
||||
ts.isImportDeclaration(node) ? node.moduleSpecifier :
|
||||
ts.isExternalModuleReference(node) ? node.expression :
|
||||
null;
|
||||
if (symbolNode != null) {
|
||||
let symbol = typeChecker.getSymbolAtLocation(symbolNode);
|
||||
if (symbol != null) {
|
||||
node.$symbol = typeTable.getSymbolId(symbol);
|
||||
}
|
||||
}
|
||||
if (ts.isTypeReferenceNode(node)) {
|
||||
// For type references we inject a symbol on each part of the name.
|
||||
// We traverse each node in the name here since we know these are part of
|
||||
// a type annotation. This means we don't have to do it for all identifiers
|
||||
// and qualified names, which would extract more information than we need.
|
||||
let namePart: (ts.EntityName & AugmentedNode) = node.typeName;
|
||||
while (ts.isQualifiedName(namePart)) {
|
||||
let symbol = typeChecker.getSymbolAtLocation(namePart.right);
|
||||
if (symbol != null) {
|
||||
namePart.$symbol = typeTable.getSymbolId(symbol);
|
||||
}
|
||||
|
||||
// Traverse into the prefix.
|
||||
namePart = namePart.left;
|
||||
}
|
||||
let symbol = typeChecker.getSymbolAtLocation(namePart);
|
||||
if (symbol != null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type NamedNodeWithSymbol = AugmentedNode & (ts.ClassDeclaration | ts.InterfaceDeclaration
|
||||
| ts.TypeAliasDeclaration | ts.EnumDeclaration | ts.EnumMember | ts.ModuleDeclaration | ts.FunctionDeclaration
|
||||
| ts.MethodDeclaration | ts.MethodSignature);
|
||||
|
||||
/**
|
||||
* True if the given AST node has a name, and should be associated with a symbol.
|
||||
*/
|
||||
function isNamedNodeWithSymbol(node: ts.Node): node is NamedNodeWithSymbol {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.ClassDeclaration:
|
||||
case ts.SyntaxKind.InterfaceDeclaration:
|
||||
case ts.SyntaxKind.TypeAliasDeclaration:
|
||||
case ts.SyntaxKind.EnumDeclaration:
|
||||
case ts.SyntaxKind.EnumMember:
|
||||
case ts.SyntaxKind.ModuleDeclaration:
|
||||
case ts.SyntaxKind.FunctionDeclaration:
|
||||
case ts.SyntaxKind.MethodDeclaration:
|
||||
case ts.SyntaxKind.MethodSignature:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the given AST node has a type.
|
||||
*/
|
||||
function isTypedNode(node: ts.Node): boolean {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.ArrayLiteralExpression:
|
||||
case ts.SyntaxKind.ArrowFunction:
|
||||
case ts.SyntaxKind.AsExpression:
|
||||
case ts.SyntaxKind.SatisfiesExpression:
|
||||
case ts.SyntaxKind.AwaitExpression:
|
||||
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:
|
||||
case ts.SyntaxKind.ExpressionWithTypeArguments:
|
||||
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:
|
||||
case ts.SyntaxKind.NumericLiteral:
|
||||
case ts.SyntaxKind.ObjectKeyword:
|
||||
case ts.SyntaxKind.ObjectLiteralExpression:
|
||||
case ts.SyntaxKind.OmittedExpression:
|
||||
case ts.SyntaxKind.ParenthesizedExpression:
|
||||
case ts.SyntaxKind.PartiallyEmittedExpression:
|
||||
case ts.SyntaxKind.PostfixUnaryExpression:
|
||||
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:
|
||||
case ts.SyntaxKind.TemplateHead:
|
||||
case ts.SyntaxKind.TemplateMiddle:
|
||||
case ts.SyntaxKind.TemplateSpan:
|
||||
case ts.SyntaxKind.TemplateTail:
|
||||
case ts.SyntaxKind.TrueKeyword:
|
||||
case ts.SyntaxKind.TypeAssertionExpression:
|
||||
case ts.SyntaxKind.TypeLiteral:
|
||||
case ts.SyntaxKind.TypeOfExpression:
|
||||
case ts.SyntaxKind.VoidExpression:
|
||||
case ts.SyntaxKind.YieldExpression:
|
||||
return true;
|
||||
default:
|
||||
return ts.isTypeNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
type ContextuallyTypedNode = (ts.ArrayLiteralExpression | ts.ObjectLiteralExpression) & AugmentedNode;
|
||||
|
||||
function isContextuallyTypedNode(node: ts.Node): node is ContextuallyTypedNode {
|
||||
let kind = node.kind;
|
||||
return kind === ts.SyntaxKind.ArrayLiteralExpression || kind === ts.SyntaxKind.ObjectLiteralExpression;
|
||||
}
|
||||
|
||||
@@ -1,54 +1,26 @@
|
||||
import * as ts from "./typescript";
|
||||
import { TypeTable } from "./type_table";
|
||||
import * as pathlib from "path";
|
||||
import { VirtualSourceRoot } from "./virtual_source_root";
|
||||
|
||||
/**
|
||||
* Extracts the package name from the prefix of an import string.
|
||||
*/
|
||||
const packageNameRex = /^(?:@[\w.-]+[/\\]+)?\w[\w.-]*(?=[/\\]|$)/;
|
||||
const extensions = ['.ts', '.tsx', '.d.ts', '.js', '.jsx'];
|
||||
|
||||
function getPackageName(importString: string) {
|
||||
let packageNameMatch = packageNameRex.exec(importString);
|
||||
if (packageNameMatch == null) return null;
|
||||
let packageName = packageNameMatch[0];
|
||||
if (packageName.charAt(0) === '@') {
|
||||
packageName = packageName.replace(/[/\\]+/g, '/'); // Normalize slash after the scope.
|
||||
}
|
||||
return packageName;
|
||||
}
|
||||
|
||||
export class Project {
|
||||
public program: ts.Program = null;
|
||||
private host: ts.CompilerHost;
|
||||
private resolutionCache: ts.ModuleResolutionCache;
|
||||
|
||||
constructor(
|
||||
public tsConfig: string,
|
||||
public config: ts.ParsedCommandLine,
|
||||
public typeTable: TypeTable,
|
||||
public packageEntryPoints: Map<string, string>,
|
||||
public virtualSourceRoot: VirtualSourceRoot) {
|
||||
public tsConfig: string,
|
||||
public config: ts.ParsedCommandLine,
|
||||
public packageEntryPoints: Map<string, string>) {
|
||||
|
||||
this.resolveModuleNames = this.resolveModuleNames.bind(this);
|
||||
|
||||
this.resolutionCache = ts.createModuleResolutionCache(pathlib.dirname(tsConfig), ts.sys.realpath, config.options);
|
||||
let host = ts.createCompilerHost(config.options, true);
|
||||
host.resolveModuleNames = this.resolveModuleNames;
|
||||
host.trace = undefined; // Disable tracing which would otherwise go to standard out
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public unload(): void {
|
||||
this.typeTable.releaseProgram();
|
||||
this.program = null;
|
||||
}
|
||||
|
||||
public load(): void {
|
||||
const { config, host } = this;
|
||||
this.program = ts.createProgram(config.fileNames, config.options, host);
|
||||
this.typeTable.setProgram(this.program, this.virtualSourceRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,74 +32,4 @@ export class Project {
|
||||
this.unload();
|
||||
this.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override for module resolution in the TypeScript compiler host.
|
||||
*/
|
||||
private resolveModuleNames(
|
||||
moduleNames: string[],
|
||||
containingFile: string,
|
||||
reusedNames: string[],
|
||||
redirectedReference: ts.ResolvedProjectReference,
|
||||
options: ts.CompilerOptions) {
|
||||
|
||||
let oppositePath =
|
||||
this.virtualSourceRoot.toVirtualPath(containingFile) ||
|
||||
this.virtualSourceRoot.fromVirtualPath(containingFile);
|
||||
|
||||
const { host, resolutionCache } = this;
|
||||
return moduleNames.map((moduleName) => {
|
||||
let redirected = this.redirectModuleName(moduleName, containingFile, options);
|
||||
if (redirected != null) return redirected;
|
||||
if (oppositePath != null) {
|
||||
// If the containing file is in the virtual source root, try resolving from the real source root, and vice versa.
|
||||
redirected = ts.resolveModuleName(moduleName, oppositePath, options, host, resolutionCache).resolvedModule;
|
||||
if (redirected != null) return redirected;
|
||||
}
|
||||
return ts.resolveModuleName(moduleName, containingFile, options, host, resolutionCache).resolvedModule;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path that the given import string should be redirected to, or null if it should
|
||||
* fall back to standard module resolution.
|
||||
*/
|
||||
private redirectModuleName(moduleName: string, containingFile: string, options: ts.CompilerOptions): ts.ResolvedModule {
|
||||
// Get a package name from the leading part of the module name, e.g. '@scope/foo' from '@scope/foo/bar'.
|
||||
let packageName = getPackageName(moduleName);
|
||||
if (packageName == null) return null;
|
||||
|
||||
// Get the overridden location of this package, if one exists.
|
||||
let packageEntryPoint = this.packageEntryPoints.get(packageName);
|
||||
if (packageEntryPoint == null) return null;
|
||||
|
||||
// If the requested module name is exactly the overridden package name,
|
||||
// return the entry point file (it is not necessarily called `index.ts`).
|
||||
if (moduleName === packageName) {
|
||||
return { resolvedFileName: packageEntryPoint, isExternalLibraryImport: true };
|
||||
}
|
||||
|
||||
// Get the suffix after the package name, e.g. the '/bar' in '@scope/foo/bar'.
|
||||
let suffix = moduleName.substring(packageName.length);
|
||||
|
||||
// Resolve the suffix relative to the package directory.
|
||||
let packageDir = pathlib.dirname(packageEntryPoint);
|
||||
let joinedPath = pathlib.join(packageDir, suffix);
|
||||
|
||||
// Add implicit '/index'
|
||||
if (ts.sys.directoryExists(joinedPath)) {
|
||||
joinedPath = pathlib.join(joinedPath, 'index');
|
||||
}
|
||||
|
||||
// Try each recognized extension. We must not return a file whose extension is not
|
||||
// recognized by TypeScript.
|
||||
for (let ext of extensions) {
|
||||
let candidate = joinedPath.endsWith(ext) ? joinedPath : (joinedPath + ext);
|
||||
if (ts.sys.fileExists(candidate)) {
|
||||
return { resolvedFileName: candidate, isExternalLibraryImport: true };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,14 +31,12 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as pathlib from "path";
|
||||
import * as readline from "readline";
|
||||
import * as ts from "./typescript";
|
||||
import * as ast_extractor from "./ast_extractor";
|
||||
|
||||
import { Project } from "./common";
|
||||
import { TypeTable } from "./type_table";
|
||||
import { VirtualSourceRoot } from "./virtual_source_root";
|
||||
|
||||
// Remove limit on stack trace depth.
|
||||
@@ -55,19 +53,6 @@ interface LoadCommand {
|
||||
packageEntryPoints: [string, string][];
|
||||
packageJsonFiles: [string, string][];
|
||||
}
|
||||
interface OpenProjectCommand extends LoadCommand {
|
||||
command: "open-project";
|
||||
}
|
||||
interface GetOwnFilesCommand extends LoadCommand {
|
||||
command: "get-own-files";
|
||||
}
|
||||
interface CloseProjectCommand {
|
||||
command: "close-project";
|
||||
tsConfig: string;
|
||||
}
|
||||
interface GetTypeTableCommand {
|
||||
command: "get-type-table";
|
||||
}
|
||||
interface ResetCommand {
|
||||
command: "reset";
|
||||
}
|
||||
@@ -81,13 +66,11 @@ interface PrepareFilesCommand {
|
||||
interface GetMetadataCommand {
|
||||
command: "get-metadata";
|
||||
}
|
||||
type Command = ParseCommand | OpenProjectCommand | GetOwnFilesCommand | CloseProjectCommand
|
||||
| GetTypeTableCommand | ResetCommand | QuitCommand | PrepareFilesCommand | GetMetadataCommand;
|
||||
type Command = ParseCommand | ResetCommand | QuitCommand | PrepareFilesCommand | GetMetadataCommand;
|
||||
|
||||
/** The state to be shared between commands. */
|
||||
class State {
|
||||
public project: Project = null;
|
||||
public typeTable = new TypeTable();
|
||||
|
||||
/** List of files that have been requested. */
|
||||
public pendingFiles: string[] = [];
|
||||
@@ -205,22 +188,18 @@ function checkCycle(root: any) {
|
||||
visit(root);
|
||||
if (path.length > 0) {
|
||||
path.reverse();
|
||||
console.log(JSON.stringify({type: "error", message: "Cycle = " + path.join(".")}));
|
||||
console.log(JSON.stringify({ type: "error", message: "Cycle = " + path.join(".") }));
|
||||
}
|
||||
}
|
||||
|
||||
/** Property names to extract from the TypeScript AST. */
|
||||
const astProperties: string[] = [
|
||||
"$declarationKind",
|
||||
"$declaredSignature",
|
||||
"$end",
|
||||
"$lineStarts",
|
||||
"$overloadIndex",
|
||||
"$pos",
|
||||
"$resolvedSignature",
|
||||
"$symbol",
|
||||
"$tokens",
|
||||
"$type",
|
||||
"argument",
|
||||
"argumentExpression",
|
||||
"arguments",
|
||||
@@ -392,20 +371,14 @@ function isExtractableSourceFile(ast: ast_extractor.AugmentedSourceFile): boolea
|
||||
* an already-open project, or by parsing the file.
|
||||
*/
|
||||
function getAstForFile(filename: string): ts.SourceFile {
|
||||
if (state.project != null) {
|
||||
let ast = state.project.program.getSourceFile(filename);
|
||||
if (ast != null && isExtractableSourceFile(ast)) {
|
||||
ast_extractor.augmentAst(ast, ast.text, state.project);
|
||||
return ast;
|
||||
}
|
||||
let { ast, code } = parseSingleFile(filename);
|
||||
if (ast != null && isExtractableSourceFile(ast)) {
|
||||
ast_extractor.augmentAst(ast, code, null);
|
||||
}
|
||||
// Fall back to extracting without a project.
|
||||
let {ast, code} = parseSingleFile(filename);
|
||||
ast_extractor.augmentAst(ast, code, null);
|
||||
return ast;
|
||||
}
|
||||
|
||||
function parseSingleFile(filename: string): {ast: ts.SourceFile, code: string} {
|
||||
function parseSingleFile(filename: string): { ast: ts.SourceFile, code: string } {
|
||||
let code = ts.sys.readFile(filename);
|
||||
|
||||
// create a compiler host that only allows access to `filename`
|
||||
@@ -436,7 +409,7 @@ function parseSingleFile(filename: string): {ast: ts.SourceFile, code: string} {
|
||||
|
||||
let ast = program.getSourceFile(filename);
|
||||
|
||||
return {ast, code};
|
||||
return { ast, code };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -507,7 +480,7 @@ function loadTsConfig(command: LoadCommand): LoadedConfig {
|
||||
let virtualExclusions = excludes == null ? [] : [...excludes];
|
||||
virtualExclusions.push('**/node_modules/**/*');
|
||||
let virtualResults = ts.sys.readDirectory(virtualDir, extensions, virtualExclusions, includes, depth)
|
||||
return [ ...originalResults, ...virtualResults ];
|
||||
return [...originalResults, ...virtualResults];
|
||||
},
|
||||
fileExists: (path: string) => {
|
||||
return ts.sys.fileExists(path)
|
||||
@@ -531,256 +504,6 @@ function loadTsConfig(command: LoadCommand): LoadedConfig {
|
||||
return { config, basePath, packageJsonFiles, packageEntryPoints, virtualSourceRoot, ownFiles };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of files included in the given tsconfig.json file's include pattern,
|
||||
* (not including those only references through imports).
|
||||
*/
|
||||
function handleGetFileListCommand(command: GetOwnFilesCommand) {
|
||||
let { config, ownFiles } = loadTsConfig(command);
|
||||
|
||||
console.log(JSON.stringify({
|
||||
type: "file-list",
|
||||
ownFiles,
|
||||
}));
|
||||
}
|
||||
|
||||
function handleOpenProjectCommand(command: OpenProjectCommand) {
|
||||
let { config, packageEntryPoints, virtualSourceRoot, basePath, ownFiles } = loadTsConfig(command);
|
||||
|
||||
let project = new Project(command.tsConfig, config, state.typeTable, packageEntryPoints, virtualSourceRoot);
|
||||
project.load();
|
||||
|
||||
state.project = project;
|
||||
let program = project.program;
|
||||
let typeChecker = program.getTypeChecker();
|
||||
|
||||
let shouldReportDiagnostics = getEnvironmentVariable("SEMMLE_TYPESCRIPT_REPORT_DIAGNOSTICS", v => v.trim().toLowerCase() === "true", false);
|
||||
let diagnostics = shouldReportDiagnostics
|
||||
? program.getSemanticDiagnostics().filter(d => d.category === ts.DiagnosticCategory.Error)
|
||||
: [];
|
||||
if (diagnostics.length > 0) {
|
||||
console.warn('TypeScript: reported ' + diagnostics.length + ' semantic errors.');
|
||||
}
|
||||
for (let diagnostic of diagnostics) {
|
||||
let text = diagnostic.messageText;
|
||||
if (text && typeof text !== 'string') {
|
||||
text = text.messageText;
|
||||
}
|
||||
let locationStr = '';
|
||||
let { file } = diagnostic;
|
||||
if (file != null) {
|
||||
let { line, character } = file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||
locationStr = `${file.fileName}:${line}:${character}`;
|
||||
}
|
||||
console.warn(`TypeScript: ${locationStr} ${text}`);
|
||||
}
|
||||
|
||||
// Associate external module names with the corresponding file symbols.
|
||||
// We need these mappings to identify which module a given external type comes from.
|
||||
// The TypeScript API lets us resolve a module name to a source file, but there is no
|
||||
// inverse mapping, nor a way to enumerate all known module names. So we discover all
|
||||
// modules on the type roots (usually "node_modules/@types" but this is configurable).
|
||||
let typeRoots = ts.getEffectiveTypeRoots(config.options, {
|
||||
getCurrentDirectory: () => basePath,
|
||||
});
|
||||
|
||||
for (let typeRoot of typeRoots || []) {
|
||||
if (ts.sys.directoryExists(typeRoot)) {
|
||||
traverseTypeRoot(typeRoot, "");
|
||||
}
|
||||
let virtualTypeRoot = virtualSourceRoot.toVirtualPathIfDirectoryExists(typeRoot);
|
||||
if (virtualTypeRoot != null) {
|
||||
traverseTypeRoot(virtualTypeRoot, "");
|
||||
}
|
||||
}
|
||||
|
||||
for (let sourceFile of program.getSourceFiles()) {
|
||||
addModuleBindingsFromModuleDeclarations(sourceFile);
|
||||
addModuleBindingsFromFilePath(sourceFile);
|
||||
}
|
||||
|
||||
/** Concatenates two imports paths. These always use `/` as path separator. */
|
||||
function joinModulePath(prefix: string, suffix: string) {
|
||||
if (prefix.length === 0) return suffix;
|
||||
if (suffix.length === 0) return prefix;
|
||||
return prefix + "/" + suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses a directory that is a type root or contained in a type root, and associates
|
||||
* module names (i.e. import strings) with files in this directory.
|
||||
*
|
||||
* `importPrefix` denotes an import string that resolves to this directory,
|
||||
* or an empty string if the file itself is a type root.
|
||||
*
|
||||
* The `filePath` is a system file path, possibly absolute, whereas `importPrefix`
|
||||
* is generally short and system-independent, typically just the name of a module.
|
||||
*/
|
||||
function traverseTypeRoot(filePath: string, importPrefix: string) {
|
||||
for (let child of fs.readdirSync(filePath)) {
|
||||
if (child[0] === ".") continue;
|
||||
let childPath = pathlib.join(filePath, child);
|
||||
if (fs.statSync(childPath).isDirectory()) {
|
||||
traverseTypeRoot(childPath, joinModulePath(importPrefix, child));
|
||||
continue;
|
||||
}
|
||||
let sourceFile = program.getSourceFile(childPath);
|
||||
if (sourceFile == null) {
|
||||
continue;
|
||||
}
|
||||
let importPath = getImportPathFromFileInFolder(importPrefix, child);
|
||||
addModuleBindingFromImportPath(sourceFile, importPath);
|
||||
}
|
||||
}
|
||||
|
||||
function getImportPathFromFileInFolder(folder: string, baseName: string) {
|
||||
let stem = getStem(baseName);
|
||||
return (stem === "index")
|
||||
? folder
|
||||
: joinModulePath(folder, stem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits module bindings for a module with relative path `folder/baseName`.
|
||||
*/
|
||||
function addModuleBindingFromImportPath(sourceFile: ts.SourceFile, importPath: string) {
|
||||
let symbol = typeChecker.getSymbolAtLocation(sourceFile);
|
||||
if (symbol == null) return; // Happens if the source file is not a module.
|
||||
|
||||
let canonicalSymbol = getEffectiveExportTarget(symbol); // Follow `export = X` declarations.
|
||||
let symbolId = state.typeTable.getSymbolId(canonicalSymbol);
|
||||
|
||||
// Associate the module name with this symbol.
|
||||
state.typeTable.addModuleMapping(symbolId, importPath);
|
||||
|
||||
// Associate global variable names with this module.
|
||||
// For each `export as X` declaration, the global X refers to this module.
|
||||
// Note: the `globalExports` map is stored on the original symbol, not the target of `export=`.
|
||||
if (symbol.globalExports != null) {
|
||||
symbol.globalExports.forEach((global: ts.Symbol) => {
|
||||
state.typeTable.addGlobalMapping(symbolId, global.name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the basename of `file` without its extension, while treating `.d.ts` as a
|
||||
* single extension.
|
||||
*/
|
||||
function getStem(file: string) {
|
||||
if (file.endsWith(".d.ts")) {
|
||||
return pathlib.basename(file, ".d.ts");
|
||||
}
|
||||
if (file.endsWith(".d.mts") || file.endsWith(".d.cts")) {
|
||||
// We don't extract d.mts or d.cts files, but their symbol can coincide with that of a d.ts file,
|
||||
// which means any module bindings we generate for it will ultimately be visible in QL.
|
||||
let base = pathlib.basename(file);
|
||||
return base.substring(0, base.length - '.d.mts'.length);
|
||||
}
|
||||
let base = pathlib.basename(file);
|
||||
let dot = base.lastIndexOf('.');
|
||||
return dot === -1 || dot === 0 ? base : base.substring(0, dot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits module bindings for a module based on its file path.
|
||||
*
|
||||
* This looks for enclosing `node_modules` folders to determine the module name.
|
||||
* This is needed for modules that ship their own type definitions as opposed to having
|
||||
* type definitions loaded from a type root (conventionally named `@types/xxx`).
|
||||
*/
|
||||
function addModuleBindingsFromFilePath(sourceFile: ts.SourceFile) {
|
||||
let fullPath = sourceFile.fileName;
|
||||
let index = fullPath.lastIndexOf('/node_modules/');
|
||||
if (index === -1) return;
|
||||
|
||||
let relativePath = fullPath.substring(index + '/node_modules/'.length);
|
||||
|
||||
// Ignore node_modules/@types folders here as they are typically handled as type roots.
|
||||
if (relativePath.startsWith("@types/")) return;
|
||||
|
||||
// If the enclosing package has a "typings" field, only add module bindings for that file.
|
||||
let packageJsonFile = getEnclosingPackageJson(fullPath);
|
||||
if (packageJsonFile != null) {
|
||||
let json = getPackageJson(packageJsonFile);
|
||||
let typings = getPackageTypings(packageJsonFile);
|
||||
if (json != null && typings != null) {
|
||||
let name = json.name;
|
||||
if (typings === fullPath && typeof name === 'string') {
|
||||
addModuleBindingFromImportPath(sourceFile, name);
|
||||
} else if (typings != null) {
|
||||
return; // Typings field prevents access to other files in package.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add module bindings relative to package directory.
|
||||
let { dir, base } = pathlib.parse(relativePath);
|
||||
addModuleBindingFromImportPath(sourceFile, getImportPathFromFileInFolder(dir, base));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit module name bindings for external module declarations, i.e: `declare module 'X' {..}`
|
||||
* These can generally occur anywhere; they may or may not be on the type root path.
|
||||
*/
|
||||
function addModuleBindingsFromModuleDeclarations(sourceFile: ts.SourceFile) {
|
||||
for (let stmt of sourceFile.statements) {
|
||||
if (ts.isModuleDeclaration(stmt) && ts.isStringLiteral(stmt.name)) {
|
||||
let symbol = (stmt as any).symbol;
|
||||
if (symbol == null) continue;
|
||||
symbol = getEffectiveExportTarget(symbol);
|
||||
let symbolId = state.typeTable.getSymbolId(symbol);
|
||||
let moduleName = stmt.name.text;
|
||||
state.typeTable.addModuleMapping(symbolId, moduleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If `symbol` refers to a container with an `export = X` declaration, returns
|
||||
* the target of `X`, otherwise returns `symbol`.
|
||||
*/
|
||||
function getEffectiveExportTarget(symbol: ts.Symbol) {
|
||||
if (symbol.exports != null && symbol.exports.has(ts.InternalSymbolName.ExportEquals)) {
|
||||
let exportAlias = symbol.exports.get(ts.InternalSymbolName.ExportEquals);
|
||||
if (exportAlias.flags & ts.SymbolFlags.Alias) {
|
||||
return typeChecker.getAliasedSymbol(exportAlias);
|
||||
}
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// Unlike in the get-own-files command, this command gets all files we can possibly
|
||||
// extract type information for, including files referenced outside the tsconfig's inclusion pattern.
|
||||
let allFiles = program.getSourceFiles().map(sf => pathlib.resolve(sf.fileName));
|
||||
|
||||
console.log(JSON.stringify({
|
||||
type: "project-opened",
|
||||
ownFiles,
|
||||
allFiles,
|
||||
}));
|
||||
}
|
||||
|
||||
function handleCloseProjectCommand(command: CloseProjectCommand) {
|
||||
if (state.project == null) {
|
||||
console.log(JSON.stringify({
|
||||
type: "error",
|
||||
message: "No project is open",
|
||||
}));
|
||||
return;
|
||||
}
|
||||
state.project.unload();
|
||||
state.project = null;
|
||||
console.log(JSON.stringify({type: "project-closed"}));
|
||||
}
|
||||
|
||||
function handleGetTypeTableCommand(command: GetTypeTableCommand) {
|
||||
console.log(JSON.stringify({
|
||||
type: "type-table",
|
||||
typeTable: state.typeTable.getTypeTableJson(),
|
||||
}));
|
||||
}
|
||||
|
||||
function handleResetCommand(command: ResetCommand) {
|
||||
reset();
|
||||
console.log(JSON.stringify({
|
||||
@@ -807,8 +530,6 @@ function handleGetMetadataCommand(command: GetMetadataCommand) {
|
||||
|
||||
function reset() {
|
||||
state = new State();
|
||||
state.typeTable.restrictedExpansion = getEnvironmentVariable("SEMMLE_TYPESCRIPT_NO_EXPANSION", v => v.trim().toLowerCase() === "true", true);
|
||||
state.typeTable.skipExtractingTypes = getEnvironmentVariable("CODEQL_EXTRACTOR_JAVASCRIPT_OPTION_SKIP_TYPES", v => v.trim().toLowerCase() === "true", false);
|
||||
}
|
||||
|
||||
function getEnvironmentVariable<T>(name: string, parse: (x: string) => T, defaultValue: T) {
|
||||
@@ -848,35 +569,23 @@ function runReadLineInterface() {
|
||||
rl.on("line", (line: string) => {
|
||||
let req: Command = JSON.parse(line);
|
||||
switch (req.command) {
|
||||
case "parse":
|
||||
handleParseCommand(req);
|
||||
break;
|
||||
case "open-project":
|
||||
handleOpenProjectCommand(req);
|
||||
break;
|
||||
case "get-own-files":
|
||||
handleGetFileListCommand(req);
|
||||
break;
|
||||
case "close-project":
|
||||
handleCloseProjectCommand(req);
|
||||
break;
|
||||
case "get-type-table":
|
||||
handleGetTypeTableCommand(req);
|
||||
break;
|
||||
case "prepare-files":
|
||||
handlePrepareFilesCommand(req);
|
||||
break;
|
||||
case "reset":
|
||||
handleResetCommand(req);
|
||||
break;
|
||||
case "get-metadata":
|
||||
handleGetMetadataCommand(req);
|
||||
break;
|
||||
case "quit":
|
||||
rl.close();
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown command " + (req as any).command + ".");
|
||||
case "parse":
|
||||
handleParseCommand(req);
|
||||
break;
|
||||
case "prepare-files":
|
||||
handlePrepareFilesCommand(req);
|
||||
break;
|
||||
case "reset":
|
||||
handleResetCommand(req);
|
||||
break;
|
||||
case "get-metadata":
|
||||
handleGetMetadataCommand(req);
|
||||
break;
|
||||
case "quit":
|
||||
rl.close();
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown command " + (req as any).command + ".");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -886,23 +595,6 @@ if (process.argv.length > 2) {
|
||||
let argument = process.argv[2];
|
||||
if (argument === "--version") {
|
||||
console.log("parser-wrapper with TypeScript " + ts.version);
|
||||
} else if (pathlib.basename(argument) === "tsconfig.json") {
|
||||
reset();
|
||||
handleOpenProjectCommand({
|
||||
command: "open-project",
|
||||
tsConfig: argument,
|
||||
packageEntryPoints: [],
|
||||
packageJsonFiles: [],
|
||||
sourceRoot: null,
|
||||
virtualSourceRoot: null,
|
||||
});
|
||||
for (let sf of state.project.program.getSourceFiles()) {
|
||||
if (/lib\..*\.d\.ts/.test(pathlib.basename(sf.fileName)) || pathlib.basename(sf.fileName) === "lib.d.ts") continue;
|
||||
handleParseCommand({
|
||||
command: "parse",
|
||||
filename: sf.fileName,
|
||||
}, false);
|
||||
}
|
||||
} else if (pathlib.extname(argument) === ".ts" || pathlib.extname(argument) === ".tsx") {
|
||||
handleParseCommand({
|
||||
command: "parse",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,10 +51,8 @@ import com.semmle.js.extractor.trapcache.DummyTrapCache;
|
||||
import com.semmle.js.extractor.trapcache.ITrapCache;
|
||||
import com.semmle.js.parser.ParseError;
|
||||
import com.semmle.js.parser.ParsedProject;
|
||||
import com.semmle.ts.extractor.TypeExtractor;
|
||||
import com.semmle.ts.extractor.TypeScriptParser;
|
||||
import com.semmle.ts.extractor.TypeScriptWrapperOOMError;
|
||||
import com.semmle.ts.extractor.TypeTable;
|
||||
import com.semmle.util.data.StringUtil;
|
||||
import com.semmle.util.diagnostic.DiagnosticLevel;
|
||||
import com.semmle.util.diagnostic.DiagnosticLocation;
|
||||
@@ -220,7 +218,6 @@ public class AutoBuild {
|
||||
private final Set<String> xmlExtensions = new LinkedHashSet<>();
|
||||
private ProjectLayout filters;
|
||||
private final Path LGTM_SRC, SEMMLE_DIST;
|
||||
private final TypeScriptMode typeScriptMode;
|
||||
private final String defaultEncoding;
|
||||
private ExecutorService threadPool;
|
||||
private volatile boolean seenCode = false;
|
||||
@@ -238,8 +235,6 @@ public class AutoBuild {
|
||||
this.SEMMLE_DIST = Paths.get(EnvironmentVariables.getExtractorRoot());
|
||||
this.outputConfig = new ExtractorOutputConfig(LegacyLanguage.JAVASCRIPT);
|
||||
this.trapCache = ITrapCache.fromExtractorOptions();
|
||||
this.typeScriptMode =
|
||||
getEnumFromEnvVar("LGTM_INDEX_TYPESCRIPT", TypeScriptMode.class, TypeScriptMode.FULL);
|
||||
this.defaultEncoding = getEnvVar("LGTM_INDEX_DEFAULT_ENCODING");
|
||||
this.installDependencies = Boolean.valueOf(getEnvVar("LGTM_INDEX_TYPESCRIPT_INSTALL_DEPS"));
|
||||
this.virtualSourceRoot = makeVirtualSourceRoot();
|
||||
@@ -395,7 +390,7 @@ public class AutoBuild {
|
||||
defaultExtract.add(FileType.HTML);
|
||||
defaultExtract.add(FileType.JS);
|
||||
defaultExtract.add(FileType.YAML);
|
||||
if (typeScriptMode != TypeScriptMode.NONE) defaultExtract.add(FileType.TYPESCRIPT);
|
||||
defaultExtract.add(FileType.TYPESCRIPT);
|
||||
for (FileType filetype : defaultExtract)
|
||||
for (String extension : filetype.getExtensions()) patterns.add("**/*" + extension);
|
||||
|
||||
@@ -785,7 +780,7 @@ public class AutoBuild {
|
||||
extractTypeScript(filesToExtract, extractedFiles,
|
||||
extractors, tsconfigFiles, dependencyInstallationResult);
|
||||
|
||||
boolean hasTypeScriptFiles = extractedFiles.size() > 0;
|
||||
boolean hasTypeScriptFiles = hasTypeScriptFiles(filesToExtract);
|
||||
|
||||
// extract remaining files
|
||||
return extractFiles(
|
||||
@@ -1044,7 +1039,6 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
|
||||
private ExtractorConfig mkExtractorConfig() {
|
||||
ExtractorConfig config = new ExtractorConfig(true);
|
||||
config = config.withSourceType(getSourceType());
|
||||
config = config.withTypeScriptMode(typeScriptMode);
|
||||
config = config.withVirtualSourceRoot(virtualSourceRoot);
|
||||
if (defaultEncoding != null) config = config.withDefaultEncoding(defaultEncoding);
|
||||
return config;
|
||||
@@ -1065,75 +1059,26 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
|
||||
FileExtractors extractors,
|
||||
List<Path> tsconfig,
|
||||
DependencyInstallationResult deps) {
|
||||
if (hasTypeScriptFiles(files) || !tsconfig.isEmpty()) {
|
||||
|
||||
List<Path> typeScriptFiles = new ArrayList<>();
|
||||
// Get all TypeScript files.
|
||||
for (Path f : files) {
|
||||
if (extractors.fileType(f) == FileType.TYPESCRIPT) {
|
||||
typeScriptFiles.add(f);
|
||||
}
|
||||
}
|
||||
// Also get TypeScript files from HTML file snippets.
|
||||
for (Map.Entry<Path, FileSnippet> entry : state.getSnippets().entrySet()) {
|
||||
if (!extractedFiles.contains(entry.getKey())
|
||||
&& FileType.forFileExtension(entry.getKey().toFile()) == FileType.TYPESCRIPT) {
|
||||
typeScriptFiles.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeScriptFiles.isEmpty()) {
|
||||
TypeScriptParser tsParser = state.getTypeScriptParser();
|
||||
verifyTypeScriptInstallation(state);
|
||||
|
||||
// Collect all files included in a tsconfig.json inclusion pattern.
|
||||
// If a given file is referenced by multiple tsconfig files, we prefer to extract it using
|
||||
// one that includes it rather than just references it.
|
||||
Set<File> explicitlyIncludedFiles = new LinkedHashSet<>();
|
||||
if (tsconfig.size() > 1) { // No prioritization needed if there's only one tsconfig.
|
||||
for (Path projectPath : tsconfig) {
|
||||
explicitlyIncludedFiles.addAll(tsParser.getOwnFiles(projectPath.toFile(), deps, virtualSourceRoot));
|
||||
}
|
||||
}
|
||||
|
||||
// Extract TypeScript projects
|
||||
for (Path projectPath : tsconfig) {
|
||||
File projectFile = projectPath.toFile();
|
||||
long start = logBeginProcess("Opening project " + projectFile);
|
||||
ParsedProject project = tsParser.openProject(projectFile, deps, virtualSourceRoot);
|
||||
logEndProcess(start, "Done opening project " + projectFile);
|
||||
// Extract all files belonging to this project which are also matched
|
||||
// by our include/exclude filters.
|
||||
List<Path> typeScriptFiles = new ArrayList<Path>();
|
||||
for (File sourceFile : project.getAllFiles()) {
|
||||
Path sourcePath = sourceFile.toPath();
|
||||
Path normalizedFile = normalizePath(sourcePath);
|
||||
if (!files.contains(normalizedFile) && !state.getSnippets().containsKey(normalizedFile)) {
|
||||
continue;
|
||||
}
|
||||
if (!project.getOwnFiles().contains(sourceFile) && explicitlyIncludedFiles.contains(sourceFile)) continue;
|
||||
if (extractors.fileType(sourcePath) != FileType.TYPESCRIPT) {
|
||||
// For the time being, skip non-TypeScript files, even if the TypeScript
|
||||
// compiler can parse them for us.
|
||||
continue;
|
||||
}
|
||||
if (extractedFiles.contains(sourcePath)) {
|
||||
continue;
|
||||
}
|
||||
typeScriptFiles.add(sourcePath);
|
||||
}
|
||||
typeScriptFiles.sort(PATH_ORDERING);
|
||||
extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors);
|
||||
tsParser.closeProject(projectFile);
|
||||
}
|
||||
|
||||
// Extract all the types discovered when extracting the ASTs.
|
||||
if (!tsconfig.isEmpty()) {
|
||||
TypeTable typeTable = tsParser.getTypeTable();
|
||||
extractTypeTable(tsconfig.iterator().next(), typeTable);
|
||||
}
|
||||
|
||||
// Extract remaining TypeScript files.
|
||||
List<Path> remainingTypeScriptFiles = new ArrayList<>();
|
||||
for (Path f : files) {
|
||||
if (!extractedFiles.contains(f)
|
||||
&& extractors.fileType(f) == FileType.TYPESCRIPT) {
|
||||
remainingTypeScriptFiles.add(f);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Path, FileSnippet> entry : state.getSnippets().entrySet()) {
|
||||
if (!extractedFiles.contains(entry.getKey())
|
||||
&& FileType.forFileExtension(entry.getKey().toFile()) == FileType.TYPESCRIPT) {
|
||||
remainingTypeScriptFiles.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
if (!remainingTypeScriptFiles.isEmpty()) {
|
||||
extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractors);
|
||||
}
|
||||
|
||||
extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors);
|
||||
// The TypeScript compiler instance is no longer needed.
|
||||
tsParser.killProcess();
|
||||
}
|
||||
@@ -1186,8 +1131,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
|
||||
}
|
||||
|
||||
// extract TypeScript projects from 'tsconfig.json'
|
||||
if (typeScriptMode != TypeScriptMode.NONE
|
||||
&& treatAsTSConfig(file.getFileName().toString())
|
||||
if (treatAsTSConfig(file.getFileName().toString())
|
||||
&& !excludes.contains(file)
|
||||
&& isFileIncluded(file)) {
|
||||
tsconfigFiles.add(file);
|
||||
@@ -1246,18 +1190,6 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
|
||||
return path.toAbsolutePath().normalize();
|
||||
}
|
||||
|
||||
private void extractTypeTable(Path fileHandle, TypeTable table) {
|
||||
TrapWriter trapWriter =
|
||||
outputConfig
|
||||
.getTrapWriterFactory()
|
||||
.mkTrapWriter(new File(fileHandle.toString() + ".codeql-typescript-typetable"));
|
||||
try {
|
||||
new TypeExtractor(trapWriter, table).extract();
|
||||
} finally {
|
||||
FileUtil.close(trapWriter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source type specified in <code>LGTM_INDEX_SOURCE_TYPE</code>, or the default of {@link
|
||||
* SourceType#AUTO}.
|
||||
|
||||
@@ -221,9 +221,6 @@ public class ExtractorConfig {
|
||||
/** Should textual information be extracted into the lines/4 relation? */
|
||||
private boolean extractLines;
|
||||
|
||||
/** Should TypeScript files be extracted? */
|
||||
private TypeScriptMode typescriptMode;
|
||||
|
||||
/** Override amount of RAM to allocate to the TypeScript compiler. */
|
||||
private int typescriptRam;
|
||||
|
||||
@@ -245,7 +242,6 @@ public class ExtractorConfig {
|
||||
this.esnext = true;
|
||||
this.v8Extensions = true;
|
||||
}
|
||||
this.typescriptMode = TypeScriptMode.NONE;
|
||||
this.e4x = experimental;
|
||||
this.defaultEncoding = StandardCharsets.UTF_8.name();
|
||||
this.virtualSourceRoot = VirtualSourceRoot.none;
|
||||
@@ -266,7 +262,6 @@ public class ExtractorConfig {
|
||||
this.sourceType = that.sourceType;
|
||||
this.htmlHandling = that.htmlHandling;
|
||||
this.extractLines = that.extractLines;
|
||||
this.typescriptMode = that.typescriptMode;
|
||||
this.typescriptRam = that.typescriptRam;
|
||||
this.defaultEncoding = that.defaultEncoding;
|
||||
this.virtualSourceRoot = that.virtualSourceRoot;
|
||||
@@ -416,20 +411,10 @@ public class ExtractorConfig {
|
||||
return res;
|
||||
}
|
||||
|
||||
public TypeScriptMode getTypeScriptMode() {
|
||||
return typescriptMode;
|
||||
}
|
||||
|
||||
public int getTypeScriptRam() {
|
||||
return typescriptRam;
|
||||
}
|
||||
|
||||
public ExtractorConfig withTypeScriptMode(TypeScriptMode typescriptMode) {
|
||||
ExtractorConfig res = new ExtractorConfig(this);
|
||||
res.typescriptMode = typescriptMode;
|
||||
return res;
|
||||
}
|
||||
|
||||
public ExtractorConfig withTypeScriptRam(int ram) {
|
||||
ExtractorConfig res = new ExtractorConfig(this);
|
||||
res.typescriptRam = ram;
|
||||
@@ -490,8 +475,6 @@ public class ExtractorConfig {
|
||||
+ sourceType
|
||||
+ ", extractLines="
|
||||
+ extractLines
|
||||
+ ", typescriptMode="
|
||||
+ typescriptMode
|
||||
+ ", defaultEncoding="
|
||||
+ defaultEncoding
|
||||
+ ", virtualSourceRoot="
|
||||
|
||||
@@ -217,8 +217,6 @@ public class FileExtractor {
|
||||
TYPESCRIPT(".ts", ".tsx", ".mts", ".cts") {
|
||||
@Override
|
||||
protected boolean contains(File f, String lcExt, ExtractorConfig config) {
|
||||
if (config.getTypeScriptMode() == TypeScriptMode.NONE) return false;
|
||||
|
||||
// Read the beginning of the file to guess the file type.
|
||||
if (hasBadFileHeader(f, lcExt, config)) {
|
||||
return false;
|
||||
|
||||
@@ -18,9 +18,7 @@ import com.semmle.js.extractor.ExtractorConfig.SourceType;
|
||||
import com.semmle.js.extractor.FileExtractor.FileType;
|
||||
import com.semmle.js.extractor.trapcache.ITrapCache;
|
||||
import com.semmle.js.parser.ParsedProject;
|
||||
import com.semmle.ts.extractor.TypeExtractor;
|
||||
import com.semmle.ts.extractor.TypeScriptParser;
|
||||
import com.semmle.ts.extractor.TypeTable;
|
||||
import com.semmle.util.data.StringUtil;
|
||||
import com.semmle.util.data.UnitParser;
|
||||
import com.semmle.util.exception.ResourceError;
|
||||
@@ -79,7 +77,6 @@ public class Main {
|
||||
private PathMatcher includeMatcher, excludeMatcher;
|
||||
private FileExtractor fileExtractor;
|
||||
private ExtractorState extractorState;
|
||||
private Set<File> projectFiles = new LinkedHashSet<>();
|
||||
private Set<File> files = new LinkedHashSet<>();
|
||||
private final Set<File> extractedFiles = new LinkedHashSet<>();
|
||||
|
||||
@@ -121,10 +118,6 @@ public class Main {
|
||||
}
|
||||
|
||||
// Sort files for determinism
|
||||
projectFiles = projectFiles.stream()
|
||||
.sorted(AutoBuild.FILE_ORDERING)
|
||||
.collect(Collectors.toCollection(() -> new LinkedHashSet<>()));
|
||||
|
||||
files = files.stream()
|
||||
.sorted(AutoBuild.FILE_ORDERING)
|
||||
.collect(Collectors.toCollection(() -> new LinkedHashSet<>()));
|
||||
@@ -142,53 +135,22 @@ public class Main {
|
||||
tsParser.verifyInstallation(!ap.has(P_QUIET));
|
||||
}
|
||||
|
||||
for (File projectFile : projectFiles) {
|
||||
|
||||
long start = verboseLogStartTimer(ap, "Opening project " + projectFile);
|
||||
ParsedProject project = tsParser.openProject(projectFile, DependencyInstallationResult.empty, extractorConfig.getVirtualSourceRoot());
|
||||
verboseLogEndTimer(ap, start);
|
||||
// Extract all files belonging to this project which are also matched
|
||||
// by our include/exclude filters.
|
||||
List<File> filesToExtract = new ArrayList<>();
|
||||
for (File sourceFile : project.getOwnFiles()) {
|
||||
File normalizedFile = normalizeFile(sourceFile);
|
||||
if ((files.contains(normalizedFile) || extractorState.getSnippets().containsKey(normalizedFile.toPath()))
|
||||
&& !extractedFiles.contains(sourceFile.getAbsoluteFile())
|
||||
&& FileType.TYPESCRIPT.getExtensions().contains(FileUtil.extension(sourceFile))) {
|
||||
filesToExtract.add(sourceFile);
|
||||
}
|
||||
}
|
||||
tsParser.prepareFiles(filesToExtract);
|
||||
for (int i = 0; i < filesToExtract.size(); ++i) {
|
||||
ensureFileIsExtracted(filesToExtract.get(i), ap);
|
||||
}
|
||||
// Close the project to free memory. This does not need to be in a `finally` as
|
||||
// the project is not a system resource.
|
||||
tsParser.closeProject(projectFile);
|
||||
}
|
||||
|
||||
if (!projectFiles.isEmpty()) {
|
||||
// Extract all the types discovered when extracting the ASTs.
|
||||
TypeTable typeTable = tsParser.getTypeTable();
|
||||
extractTypeTable(projectFiles.iterator().next(), typeTable);
|
||||
}
|
||||
|
||||
List<File> remainingTypescriptFiles = new ArrayList<>();
|
||||
List<File> typeScriptFiles = new ArrayList<>();
|
||||
for (File f : files) {
|
||||
if (!extractedFiles.contains(f.getAbsoluteFile())
|
||||
&& FileType.forFileExtension(f) == FileType.TYPESCRIPT) {
|
||||
remainingTypescriptFiles.add(f);
|
||||
typeScriptFiles.add(f);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Path, FileSnippet> entry : extractorState.getSnippets().entrySet()) {
|
||||
if (!extractedFiles.contains(entry.getKey().toFile())
|
||||
&& FileType.forFileExtension(entry.getKey().toFile()) == FileType.TYPESCRIPT) {
|
||||
remainingTypescriptFiles.add(entry.getKey().toFile());
|
||||
typeScriptFiles.add(entry.getKey().toFile());
|
||||
}
|
||||
}
|
||||
if (!remainingTypescriptFiles.isEmpty()) {
|
||||
tsParser.prepareFiles(remainingTypescriptFiles);
|
||||
for (File f : remainingTypescriptFiles) {
|
||||
if (!typeScriptFiles.isEmpty()) {
|
||||
tsParser.prepareFiles(typeScriptFiles);
|
||||
for (File f : typeScriptFiles) {
|
||||
ensureFileIsExtracted(f, ap);
|
||||
}
|
||||
}
|
||||
@@ -225,21 +187,6 @@ public class Main {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void extractTypeTable(File fileHandle, TypeTable table) {
|
||||
TrapWriter trapWriter =
|
||||
extractorOutputConfig
|
||||
.getTrapWriterFactory()
|
||||
.mkTrapWriter(
|
||||
new File(
|
||||
fileHandle.getParentFile(),
|
||||
fileHandle.getName() + ".codeql-typescript-typetable"));
|
||||
try {
|
||||
new TypeExtractor(trapWriter, table).extract();
|
||||
} finally {
|
||||
FileUtil.close(trapWriter);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureFileIsExtracted(File f, ArgsParser ap) {
|
||||
if (!extractedFiles.add(f.getAbsoluteFile())) {
|
||||
// The file has already been extracted as part of a project.
|
||||
@@ -304,11 +251,8 @@ public class Main {
|
||||
includes.add("**/.babelrc*.json");
|
||||
|
||||
|
||||
// extract TypeScript if `--typescript` or `--typescript-full` was specified
|
||||
if (getTypeScriptMode(ap) != TypeScriptMode.NONE) {
|
||||
addIncludesFor(includes, FileType.TYPESCRIPT);
|
||||
includes.add("**/*tsconfig*.json");
|
||||
}
|
||||
addIncludesFor(includes, FileType.TYPESCRIPT);
|
||||
includes.add("**/*tsconfig*.json");
|
||||
|
||||
// add explicit include patterns
|
||||
for (String pattern : ap.getZeroOrMore(P_INCLUDE))
|
||||
@@ -442,12 +386,6 @@ public class Main {
|
||||
return ap.has(P_EXPERIMENTAL) || ap.has(P_JSCRIPT) || ap.has(P_MOZ_EXTENSIONS);
|
||||
}
|
||||
|
||||
private static TypeScriptMode getTypeScriptMode(ArgsParser ap) {
|
||||
if (ap.has(P_TYPESCRIPT_FULL)) return TypeScriptMode.FULL;
|
||||
if (ap.has(P_TYPESCRIPT)) return TypeScriptMode.BASIC;
|
||||
return TypeScriptMode.NONE;
|
||||
}
|
||||
|
||||
private Path inferSourceRoot(ArgsParser ap) {
|
||||
List<File> files = getFilesArg(ap);
|
||||
Path sourceRoot = files.iterator().next().toPath().toAbsolutePath().getParent();
|
||||
@@ -478,7 +416,6 @@ public class Main {
|
||||
.withFileType(getFileType(ap))
|
||||
.withSourceType(ap.getEnum(P_SOURCE_TYPE, SourceType.class, SourceType.AUTO))
|
||||
.withExtractLines(ap.has(P_EXTRACT_PROGRAM_TEXT))
|
||||
.withTypeScriptMode(getTypeScriptMode(ap))
|
||||
.withTypeScriptRam(
|
||||
ap.has(P_TYPESCRIPT_RAM)
|
||||
? UnitParser.parseOpt(ap.getString(P_TYPESCRIPT_RAM), UnitParser.MEGABYTES)
|
||||
@@ -542,12 +479,6 @@ public class Main {
|
||||
&& (explicit || includeMatcher.matches(path) && !excludeMatcher.matches(path))) {
|
||||
files.add(normalizeFile(root));
|
||||
}
|
||||
|
||||
if (extractorConfig.getTypeScriptMode() == TypeScriptMode.FULL
|
||||
&& AutoBuild.treatAsTSConfig(root.getName())
|
||||
&& !excludeMatcher.matches(path)) {
|
||||
projectFiles.add(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.semmle.js.extractor;
|
||||
|
||||
/** The amount of information to extract from TypeScript files. */
|
||||
public enum TypeScriptMode {
|
||||
/** TypeScript files will not be extracted. */
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Only syntactic information will be extracted from TypeScript files.
|
||||
*
|
||||
* <p>This requires Node.js and the TypeScript compiler to be installed if the project contains
|
||||
* any TypeScript files.
|
||||
*/
|
||||
BASIC,
|
||||
|
||||
/** Extract as much as possible from TypeScript files. */
|
||||
FULL;
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
package com.semmle.ts.extractor;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.semmle.util.trap.TrapWriter;
|
||||
import com.semmle.util.trap.TrapWriter.Label;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Extracts type and symbol information into TRAP files.
|
||||
*
|
||||
* <p>This is closely coupled with the <code>type_table.ts</code> 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;
|
||||
private static final int bigintLiteralTypeKind = 25;
|
||||
|
||||
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);
|
||||
tagToKind.put("bigint", 24);
|
||||
tagToKind.put("bigintlit", bigintLiteralTypeKind);
|
||||
}
|
||||
|
||||
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());
|
||||
extractTypeAliases(table.getTypeAliases());
|
||||
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 = split(contents);
|
||||
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 index of rest element (or -1 if no rest element).
|
||||
trapWriter.addTuple("tuple_type_min_length", lbl, Integer.parseInt(parts[1]));
|
||||
int restIndex = Integer.parseInt(parts[2]);
|
||||
if (restIndex != -1) {
|
||||
trapWriter.addTuple("tuple_type_rest_index", lbl, restIndex);
|
||||
}
|
||||
firstChild += 2;
|
||||
break;
|
||||
}
|
||||
case objectKind:
|
||||
case lexicalTypevarKind:
|
||||
firstChild = parts.length; // No children.
|
||||
break;
|
||||
|
||||
case numberLiteralTypeKind:
|
||||
case stringLiteralTypeKind:
|
||||
case bigintLiteralTypeKind:
|
||||
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 extractTypeAliases(JsonObject aliases) {
|
||||
JsonArray aliasTypes = aliases.get("aliasTypes").getAsJsonArray();
|
||||
JsonArray underlyingTypes = aliases.get("underlyingTypes").getAsJsonArray();
|
||||
for (int i = 0; i < aliasTypes.size(); ++i) {
|
||||
int aliasType = aliasTypes.get(i).getAsInt();
|
||||
int underlyingType = underlyingTypes.get(i).getAsInt();
|
||||
trapWriter.addTuple(
|
||||
"type_alias",
|
||||
trapWriter.globalID("type;" + aliasType),
|
||||
trapWriter.globalID("type;" + underlyingType));
|
||||
}
|
||||
}
|
||||
|
||||
private void extractSymbol(int index) {
|
||||
// Format is: kind;decl;parent;name
|
||||
String[] parts = split(table.getSymbolString(index), 4);
|
||||
int kind = symbolKind.get(parts[0]);
|
||||
String name = parts[3];
|
||||
Label label = trapWriter.globalID("symbol;" + index);
|
||||
trapWriter.addTuple("symbols", label, kind, name);
|
||||
String parentStr = parts[2];
|
||||
if (parentStr.length() > 0) {
|
||||
Label parentLabel = trapWriter.globalID("symbol;" + parentStr);
|
||||
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;isAbstract;numTypeParams;requiredParams;restParamType;returnType(;paramName;paramType)*
|
||||
String[] parts = split(table.getSignatureString(index));
|
||||
Label label = trapWriter.globalID("signature;" + index);
|
||||
int kind = Integer.parseInt(parts[0]);
|
||||
boolean isAbstract = parts[1].equals("t");
|
||||
if (isAbstract) {
|
||||
trapWriter.addTuple("is_abstract_signature", label);
|
||||
}
|
||||
int numberOfTypeParameters = Integer.parseInt(parts[2]);
|
||||
int requiredParameters = Integer.parseInt(parts[3]);
|
||||
String restParamTypeTag = parts[4];
|
||||
if (!restParamTypeTag.isEmpty()) {
|
||||
trapWriter.addTuple(
|
||||
"signature_rest_parameter", label, trapWriter.globalID("type;" + restParamTypeTag));
|
||||
}
|
||||
Label returnType = trapWriter.globalID("type;" + parts[5]);
|
||||
trapWriter.addTuple(
|
||||
"signature_types",
|
||||
label,
|
||||
kind,
|
||||
table.getSignatureToStringValue(index),
|
||||
numberOfTypeParameters,
|
||||
requiredParameters);
|
||||
trapWriter.addTuple("signature_contains_type", returnType, label, -1);
|
||||
int numberOfParameters = (parts.length - 6) / 2; // includes type parameters
|
||||
for (int i = 0; i < numberOfParameters; ++i) {
|
||||
int partIndex = 6 + (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));
|
||||
}
|
||||
}
|
||||
|
||||
/** Like {@link #split(String)} without a limit. */
|
||||
private static String[] split(String input) {
|
||||
return split(input, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the input around the semicolon (<code>;</code>) character, preserving all empty
|
||||
* substrings.
|
||||
*
|
||||
* <p>At most <code>limit</code> substrings will be extracted. If the limit is reached, the last
|
||||
* substring will extend to the end of the string, possibly itself containing semicolons.
|
||||
*
|
||||
* <p>Note that the {@link String#split(String)} method does not preserve empty substrings at the
|
||||
* end of the string in case the string ends with a semicolon.
|
||||
*/
|
||||
private static String[] split(String input, int limit) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
int lastPos = 0;
|
||||
for (int i = 0; i < input.length(); ++i) {
|
||||
if (input.charAt(i) == ';') {
|
||||
result.add(input.substring(lastPos, i));
|
||||
lastPos = i + 1;
|
||||
if (result.size() == limit - 1) break;
|
||||
}
|
||||
}
|
||||
result.add(input.substring(lastPos));
|
||||
return result.toArray(EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
}
|
||||
@@ -463,113 +463,6 @@ public class TypeScriptParser {
|
||||
checkResponseType(response, "ok");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a map to an array of [key, value] pairs.
|
||||
*/
|
||||
private JsonArray mapToArray(Map<String, Path> map) {
|
||||
JsonArray result = new JsonArray();
|
||||
map.forEach(
|
||||
(key, path) -> {
|
||||
JsonArray entry = new JsonArray();
|
||||
entry.add(key);
|
||||
entry.add(path.toString());
|
||||
result.add(entry);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Set<File> getFilesFromJsonArray(JsonArray array) {
|
||||
Set<File> files = new LinkedHashSet<>();
|
||||
for (JsonElement elm : array) {
|
||||
files.add(new File(elm.getAsString()));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of files included by the inclusion pattern in the given tsconfig.json file.
|
||||
*/
|
||||
public Set<File> getOwnFiles(File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) {
|
||||
JsonObject request = makeLoadCommand("get-own-files", tsConfigFile, deps, vroot);
|
||||
JsonObject response = talkToParserWrapper(request);
|
||||
try {
|
||||
checkResponseType(response, "file-list");
|
||||
return getFilesFromJsonArray(response.get("ownFiles").getAsJsonArray());
|
||||
} catch (IllegalStateException e) {
|
||||
throw new CatastrophicError(
|
||||
"TypeScript parser wrapper sent unexpected response: " + response, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new project based on a tsconfig.json file. The compiler will analyze all files in the
|
||||
* project.
|
||||
*
|
||||
* <p>Call {@link #parse} to access individual files in the project.
|
||||
*
|
||||
* <p>Only one project should be opened at once.
|
||||
*/
|
||||
public ParsedProject openProject(File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) {
|
||||
JsonObject request = makeLoadCommand("open-project", tsConfigFile, deps, vroot);
|
||||
JsonObject response = talkToParserWrapper(request);
|
||||
try {
|
||||
checkResponseType(response, "project-opened");
|
||||
ParsedProject project = new ParsedProject(tsConfigFile,
|
||||
getFilesFromJsonArray(response.get("ownFiles").getAsJsonArray()),
|
||||
getFilesFromJsonArray(response.get("allFiles").getAsJsonArray()));
|
||||
return project;
|
||||
} catch (IllegalStateException e) {
|
||||
throw new CatastrophicError(
|
||||
"TypeScript parser wrapper sent unexpected response: " + response, e);
|
||||
}
|
||||
}
|
||||
|
||||
private JsonObject makeLoadCommand(String command, File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) {
|
||||
JsonObject request = new JsonObject();
|
||||
request.add("command", new JsonPrimitive(command));
|
||||
request.add("tsConfig", new JsonPrimitive(tsConfigFile.getPath()));
|
||||
request.add("packageEntryPoints", mapToArray(deps.getPackageEntryPoints()));
|
||||
request.add("packageJsonFiles", mapToArray(deps.getPackageJsonFiles()));
|
||||
request.add("sourceRoot", vroot.getSourceRoot() == null
|
||||
? JsonNull.INSTANCE
|
||||
: new JsonPrimitive(vroot.getSourceRoot().toString()));
|
||||
request.add("virtualSourceRoot", vroot.getVirtualSourceRoot() == null
|
||||
? JsonNull.INSTANCE
|
||||
: new JsonPrimitive(vroot.getVirtualSourceRoot().toString()));
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a project previously opened.
|
||||
*
|
||||
* <p>This main purpose is to free heap space in the Node.js process.
|
||||
*/
|
||||
public void closeProject(File tsConfigFile) {
|
||||
JsonObject request = new JsonObject();
|
||||
request.add("command", new JsonPrimitive("close-project"));
|
||||
request.add("tsConfig", new JsonPrimitive(tsConfigFile.getPath()));
|
||||
JsonObject response = talkToParserWrapper(request);
|
||||
try {
|
||||
checkResponseType(response, "project-closed");
|
||||
} catch (IllegalStateException e) {
|
||||
throw new CatastrophicError(
|
||||
"TypeScript parser wrapper sent unexpected response: " + response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public TypeTable getTypeTable() {
|
||||
JsonObject request = new JsonObject();
|
||||
request.add("command", new JsonPrimitive("get-type-table"));
|
||||
JsonObject response = talkToParserWrapper(request);
|
||||
try {
|
||||
checkResponseType(response, "type-table");
|
||||
return new TypeTable(response.get("typeTable").getAsJsonObject());
|
||||
} catch (IllegalStateException e) {
|
||||
throw new CatastrophicError(
|
||||
"TypeScript parser wrapper sent unexpected response: " + response, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes any open project, and in general, brings the TypeScript wrapper to a fresh state as if
|
||||
* it had just been restarted.
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package com.semmle.ts.extractor;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Holds the output of the <code>get-type-table</code> command.
|
||||
*
|
||||
* <p>See documentation in <code>parser-wrapper/src/type_table.ts</code>.
|
||||
*/
|
||||
public class TypeTable {
|
||||
private final JsonArray typeStrings;
|
||||
private final JsonArray typeToStringValues;
|
||||
private final JsonObject propertyLookups;
|
||||
private final JsonObject typeAliases;
|
||||
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.typeAliases = typeTable.get("typeAliases").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 JsonObject getTypeAliases() {
|
||||
return typeAliases;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -111,12 +111,17 @@ public class AutoBuildTests {
|
||||
try {
|
||||
Set<String> actual = new LinkedHashSet<>();
|
||||
new AutoBuild() {
|
||||
private void markExtracted(Path file, FileExtractor extractor) {
|
||||
String extracted = file.toString();
|
||||
if (extractor.getConfig().hasFileType()) {
|
||||
extracted += ":" + extractor.getFileType(file.toFile());
|
||||
}
|
||||
actual.add(extracted);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<?> extract(FileExtractor extractor, Path file, boolean concurrent) {
|
||||
String extracted = file.toString();
|
||||
if (extractor.getConfig().hasFileType())
|
||||
extracted += ":" + extractor.getFileType(file.toFile());
|
||||
actual.add(extracted);
|
||||
markExtracted(file, extractor);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@@ -134,7 +139,7 @@ public class AutoBuildTests {
|
||||
java.util.Set<Path> extractedFiles,
|
||||
FileExtractors extractors) {
|
||||
for (Path f : files) {
|
||||
actual.add(f.toString());
|
||||
markExtracted(f, extractors.forFile(f));
|
||||
extractedFiles.add(f);
|
||||
}
|
||||
}
|
||||
@@ -190,15 +195,6 @@ public class AutoBuildTests {
|
||||
|
||||
@Test
|
||||
public void typescript() throws IOException {
|
||||
envVars.put("LGTM_INDEX_TYPESCRIPT", "basic");
|
||||
addFile(true, LGTM_SRC, "tst.ts");
|
||||
addFile(true, LGTM_SRC, "tst.tsx");
|
||||
runTest();
|
||||
}
|
||||
|
||||
@Test(expected = UserError.class)
|
||||
public void typescriptWrongConfig() throws IOException {
|
||||
envVars.put("LGTM_INDEX_TYPESCRIPT", "true");
|
||||
addFile(true, LGTM_SRC, "tst.ts");
|
||||
addFile(true, LGTM_SRC, "tst.tsx");
|
||||
runTest();
|
||||
@@ -207,7 +203,6 @@ public class AutoBuildTests {
|
||||
@Test
|
||||
public void skipJsFilesDerivedFromTypeScriptFiles() throws IOException {
|
||||
// JS-derived files (.js, .cjs, .mjs, .jsx, .cjsx, .mjsx) should be skipped when TS indexing
|
||||
envVars.put("LGTM_INDEX_TYPESCRIPT", "basic");
|
||||
// Add TypeScript sources
|
||||
addFile(true, LGTM_SRC, "foo.ts");
|
||||
addFile(true, LGTM_SRC, "bar.tsx");
|
||||
@@ -225,7 +220,6 @@ public class AutoBuildTests {
|
||||
|
||||
@Test
|
||||
public void skipFilesInTsconfigOutDir() throws IOException {
|
||||
envVars.put("LGTM_INDEX_TYPESCRIPT", "basic");
|
||||
// Files under outDir in tsconfig.json should be excluded
|
||||
// Create tsconfig.json with outDir set to "dist"
|
||||
addFile(true, LGTM_SRC, "tsconfig.json");
|
||||
@@ -506,15 +500,6 @@ public class AutoBuildTests {
|
||||
runTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noTypescriptExtraction() throws IOException {
|
||||
envVars.put("LGTM_INDEX_TYPESCRIPT", "none");
|
||||
addFile(false, LGTM_SRC, "tst.ts");
|
||||
addFile(false, LGTM_SRC, "sub.js", "tst.ts");
|
||||
addFile(false, LGTM_SRC, "tst.js.ts");
|
||||
runTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includeNonExistentFile() throws IOException {
|
||||
envVars.put("LGTM_INDEX_INCLUDE", "tst.js");
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export const foo: { bar: number } = { bar: 42};
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from Expr e, Type t
|
||||
where t = e.getType()
|
||||
select e, t
|
||||
@@ -1,2 +0,0 @@
|
||||
def test(codeql, javascript):
|
||||
codeql.database.create(extractor_option="skip_types=true")
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -145,4 +145,3 @@ ql/javascript/ql/src/meta/analysis-quality/UnresolvableImports.ql
|
||||
ql/javascript/ql/src/meta/extraction-metrics/FileData.ql
|
||||
ql/javascript/ql/src/meta/extraction-metrics/MissingMetrics.ql
|
||||
ql/javascript/ql/src/meta/extraction-metrics/PhaseTimings.ql
|
||||
ql/javascript/ql/src/meta/types/TypedExprs.ql
|
||||
|
||||
@@ -126,7 +126,7 @@ private predicate propertyLookup(Expr prop, AstNode write, string kind) {
|
||||
private predicate typeLookup(AstNode ref, AstNode decl, string kind) {
|
||||
exists(TypeAccess typeAccess |
|
||||
ref = typeAccess.getIdentifier() and
|
||||
decl = typeAccess.getTypeName().getADefinition() and
|
||||
decl = typeAccess.getTypeBinding().getTypeDefinition() and
|
||||
kind = "T"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ import semmle.javascript.NodeJS
|
||||
import semmle.javascript.NPM
|
||||
import semmle.javascript.Paths
|
||||
import semmle.javascript.Promises
|
||||
import semmle.javascript.CanonicalNames
|
||||
deprecated import semmle.javascript.CanonicalNames
|
||||
import semmle.javascript.RangeAnalysis
|
||||
import semmle.javascript.Regexp
|
||||
import semmle.javascript.Routing
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
import javascript
|
||||
private import internal.StmtContainers
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
private import semmle.javascript.internal.TypeResolution
|
||||
private import semmle.javascript.internal.BindingInfo
|
||||
|
||||
/**
|
||||
* A program element corresponding to JavaScript code, such as an expression
|
||||
@@ -472,5 +474,22 @@ module AST {
|
||||
|
||||
/** Gets the data flow node associated with this program element. */
|
||||
DataFlow::ValueNode flow() { result = DataFlow::valueNode(this) }
|
||||
|
||||
/**
|
||||
* Gets information about the results of name-resolution for this expression.
|
||||
*
|
||||
* This can be used to map an expression to the class it refers to, or
|
||||
* associate it with a named value coming from an dependency.
|
||||
*/
|
||||
ExprNameBindingNode getNameBinding() { result = this }
|
||||
|
||||
/**
|
||||
* Gets information about the type of this expression.
|
||||
*
|
||||
* This can be used to map an expression to the classes it may be an instance of
|
||||
* (according to the type system), or to associate it with a named type coming
|
||||
* from a dependency.
|
||||
*/
|
||||
TypeNameBindingNode getTypeBinding() { TypeResolution::valueHasType(this, result) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Provides classes for working with name resolution of namespaces and types.
|
||||
*/
|
||||
deprecated module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -18,7 +19,7 @@ import javascript
|
||||
*
|
||||
* This class is only populated when full TypeScript extraction is enabled.
|
||||
*/
|
||||
class CanonicalName extends @symbol {
|
||||
deprecated class CanonicalName extends @symbol {
|
||||
/**
|
||||
* Gets the parent of this canonical name, that is, the prefix of its qualified name.
|
||||
*/
|
||||
@@ -218,7 +219,7 @@ class CanonicalName extends @symbol {
|
||||
/**
|
||||
* The canonical name for a type.
|
||||
*/
|
||||
class TypeName extends CanonicalName {
|
||||
deprecated class TypeName extends CanonicalName {
|
||||
TypeName() {
|
||||
exists(TypeReference ref | type_symbol(ref, this)) or
|
||||
exists(TypeDefinition def | ast_node_symbol(def, this)) or
|
||||
@@ -261,7 +262,7 @@ class TypeName extends CanonicalName {
|
||||
/**
|
||||
* The canonical name for a namespace.
|
||||
*/
|
||||
class Namespace extends CanonicalName {
|
||||
deprecated class Namespace extends CanonicalName {
|
||||
Namespace() {
|
||||
this.getAChild().isExportedMember() or
|
||||
exists(NamespaceDefinition def | ast_node_symbol(def, this)) or
|
||||
@@ -309,7 +310,7 @@ class Namespace extends CanonicalName {
|
||||
/**
|
||||
* The canonical name for a function.
|
||||
*/
|
||||
class CanonicalFunctionName extends CanonicalName {
|
||||
deprecated class CanonicalFunctionName extends CanonicalName {
|
||||
CanonicalFunctionName() {
|
||||
exists(Function fun | ast_node_symbol(fun, this)) or
|
||||
exists(InvokeExpr invoke | ast_node_symbol(invoke, this))
|
||||
|
||||
@@ -119,7 +119,7 @@ class ClassOrInterface extends @class_or_interface, TypeParameterized {
|
||||
*
|
||||
* Anonymous classes and interfaces do not have a canonical name.
|
||||
*/
|
||||
TypeName getTypeName() { result.getADefinition() = this }
|
||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||
|
||||
/**
|
||||
* Gets the ClassOrInterface corresponding to either a super type or an implemented interface.
|
||||
|
||||
@@ -171,12 +171,14 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
|
||||
predicate mayReferToParameter(Parameter p) { DataFlow::parameterNode(p).flowsToExpr(this) }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `getTypeBinding()` instead.
|
||||
*
|
||||
* Gets the static type of this expression, as determined by the TypeScript type system.
|
||||
*
|
||||
* Has no result if the expression is in a JavaScript file or in a TypeScript
|
||||
* file that was extracted without type information.
|
||||
*/
|
||||
Type getType() { ast_node_type(this, result) }
|
||||
deprecated Type getType() { ast_node_type(this, result) }
|
||||
|
||||
/**
|
||||
* Holds if the syntactic context that the expression appears in relies on the expression
|
||||
@@ -988,12 +990,14 @@ class InvokeExpr extends @invokeexpr, Expr {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. No longer supported.
|
||||
*
|
||||
* Gets the call signature of the invoked function, as determined by the TypeScript
|
||||
* type system, with overloading resolved and type parameters substituted.
|
||||
*
|
||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||
*/
|
||||
CallSignatureType getResolvedSignature() { invoke_expr_signature(this, result) }
|
||||
deprecated CallSignatureType getResolvedSignature() { invoke_expr_signature(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the index of the targeted call signature among the overload signatures
|
||||
@@ -1004,25 +1008,21 @@ class InvokeExpr extends @invokeexpr, Expr {
|
||||
int getResolvedOverloadIndex() { invoke_expr_overload_index(this, result) }
|
||||
|
||||
/**
|
||||
* DEPRECATED. No longer directly supported, but `getResolvedCallee()` may be usable as an alternative.
|
||||
*
|
||||
* Gets the canonical name of the static call target, as determined by the TypeScript type system.
|
||||
*
|
||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||
*/
|
||||
CanonicalFunctionName getResolvedCalleeName() { ast_node_symbol(this, result) }
|
||||
deprecated CanonicalFunctionName getResolvedCalleeName() { ast_node_symbol(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the statically resolved target function, as determined by the TypeScript type system, if any.
|
||||
*
|
||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||
*
|
||||
* Note that the resolved function may be overridden in a subclass and thus is not
|
||||
* necessarily the actual target of this invocation at runtime.
|
||||
*/
|
||||
Function getResolvedCallee() {
|
||||
TypeResolution::callTarget(this, result)
|
||||
or
|
||||
result = this.getResolvedCalleeName().getImplementation()
|
||||
}
|
||||
Function getResolvedCallee() { TypeResolution::callTarget(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -434,12 +434,12 @@ 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) }
|
||||
deprecated 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) }
|
||||
deprecated CallSignatureType getCallSignature() { declared_function_signature(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,11 +6,20 @@ import javascript
|
||||
private import internal.StmtContainers
|
||||
private import internal.NameResolution
|
||||
private import internal.UnderlyingTypes
|
||||
private import internal.BindingInfo
|
||||
|
||||
/**
|
||||
* A type annotation, either in the form of a TypeScript type or a JSDoc comment.
|
||||
*/
|
||||
class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
/**
|
||||
* Gets information about the results of name-resolution for this type.
|
||||
*
|
||||
* This can be used to map a type name to the class/interface it refers to, or
|
||||
* associate it with a named type coming from an dependency.
|
||||
*/
|
||||
TypeNameBindingNode getTypeBinding() { result = this }
|
||||
|
||||
/** Holds if this is the `any` type. */
|
||||
predicate isAny() { none() }
|
||||
|
||||
@@ -126,7 +135,7 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
*
|
||||
* Note that this has no result for JSDoc type annotations.
|
||||
*/
|
||||
Type getType() { none() }
|
||||
deprecated Type getType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the class referenced by this type annotation, if any.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import javascript
|
||||
private import semmle.javascript.internal.UnderlyingTypes
|
||||
|
||||
/**
|
||||
* A statement that defines a namespace, that is, a namespace declaration or enum declaration.
|
||||
@@ -32,7 +31,7 @@ class NamespaceDefinition extends Stmt, @namespace_definition, AST::ValueNode {
|
||||
/**
|
||||
* Gets the canonical name of the namespace being defined.
|
||||
*/
|
||||
Namespace getNamespace() { result.getADefinition() = this }
|
||||
deprecated Namespace getNamespace() { result.getADefinition() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,12 +111,12 @@ class TypeDefinition extends AstNode, @type_definition {
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
TypeName getTypeName() { result.getADefinition() = this }
|
||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||
|
||||
/**
|
||||
* Gets the type defined by this declaration.
|
||||
*/
|
||||
Type getType() { ast_node_type(this.getIdentifier(), result) }
|
||||
deprecated Type getType() { ast_node_type(this.getIdentifier(), result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeDefinition" }
|
||||
}
|
||||
@@ -269,7 +268,7 @@ class TypeAliasDeclaration extends @type_alias_declaration, TypeParameterized, S
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
TypeName getTypeName() { result.getADefinition() = this }
|
||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" }
|
||||
}
|
||||
@@ -549,7 +548,7 @@ class LocalNamespaceName extends @local_namespace_name, LexicalName {
|
||||
/**
|
||||
* Gets the canonical name of the namespace referenced by this name.
|
||||
*/
|
||||
Namespace getNamespace() { result = this.getADeclaration().getNamespace() }
|
||||
deprecated Namespace getNamespace() { result = this.getADeclaration().getNamespace() }
|
||||
|
||||
override DeclarationSpace getDeclarationSpace() { result = "namespace" }
|
||||
}
|
||||
@@ -569,7 +568,7 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
|
||||
* Has no result if this occurs in a TypeScript file that was extracted
|
||||
* without type information.
|
||||
*/
|
||||
override Type getType() { ast_node_type(this, result) }
|
||||
deprecated override Type getType() { ast_node_type(this, result) }
|
||||
|
||||
override Stmt getEnclosingStmt() { result = ExprOrType.super.getEnclosingStmt() }
|
||||
|
||||
@@ -693,7 +692,7 @@ class TypeAccess extends @typeaccess, TypeExpr, TypeRef {
|
||||
/**
|
||||
* Gets the canonical name of the type being accessed.
|
||||
*/
|
||||
TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeAccess" }
|
||||
}
|
||||
@@ -1380,7 +1379,7 @@ class LocalNamespaceDecl extends VarDecl, NamespaceRef {
|
||||
/**
|
||||
* Gets the canonical name of the namespace being defined or aliased by this name.
|
||||
*/
|
||||
Namespace getNamespace() { ast_node_symbol(this, result) }
|
||||
deprecated Namespace getNamespace() { ast_node_symbol(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1398,7 +1397,7 @@ class NamespaceAccess extends TypeExpr, NamespaceRef, @namespace_access {
|
||||
/**
|
||||
* Gets the canonical name of the namespace being accessed.
|
||||
*/
|
||||
Namespace getNamespace() { ast_node_symbol(this, result) }
|
||||
deprecated Namespace getNamespace() { ast_node_symbol(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NamespaceAccess" }
|
||||
}
|
||||
@@ -1507,7 +1506,7 @@ class EnumDeclaration extends NamespaceDefinition, @enum_declaration, AST::Value
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the local namespace name introduced by the enumeration, for use in
|
||||
@@ -1595,7 +1594,7 @@ class EnumMember extends AstNode, @enum_member {
|
||||
/**
|
||||
* Gets the canonical name of the type defined by this enum member.
|
||||
*/
|
||||
TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "EnumMember" }
|
||||
}
|
||||
@@ -1770,13 +1769,18 @@ class TypeRootFolder extends Folder {
|
||||
|
||||
/// Types
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A static type in the TypeScript type system.
|
||||
*
|
||||
* Types are generally not associated with a specific location or AST node.
|
||||
* For instance, there may be many AST nodes representing different uses of the
|
||||
* `number` keyword, but there only exists one `number` type.
|
||||
*/
|
||||
class Type extends @type {
|
||||
deprecated class Type extends @type {
|
||||
/**
|
||||
* Gets a string representation of this type.
|
||||
*/
|
||||
@@ -1973,9 +1977,14 @@ class Type extends @type {
|
||||
}
|
||||
|
||||
/**
|
||||
* * DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A union type or intersection type, such as `string | number` or `T & U`.
|
||||
*/
|
||||
class UnionOrIntersectionType extends Type, @union_or_intersection_type {
|
||||
deprecated class UnionOrIntersectionType extends Type, @union_or_intersection_type {
|
||||
/**
|
||||
* Gets the `i`th member of this union or intersection, starting at 0.
|
||||
*/
|
||||
@@ -1993,19 +2002,34 @@ class UnionOrIntersectionType extends Type, @union_or_intersection_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A union type, such as `string | number`.
|
||||
*
|
||||
* Note that the `boolean` type is represented as the union `true | false`,
|
||||
* but is still displayed as `boolean` in string representations.
|
||||
*/
|
||||
class UnionType extends UnionOrIntersectionType, @union_type { }
|
||||
deprecated class UnionType extends UnionOrIntersectionType, @union_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* An intersection type, such as `T & {x: number}`.
|
||||
*/
|
||||
class IntersectionType extends UnionOrIntersectionType, @intersection_type { }
|
||||
deprecated class IntersectionType extends UnionOrIntersectionType, @intersection_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that describes a JavaScript `Array` object.
|
||||
*
|
||||
* Specifically, the following three kinds of types are considered array types:
|
||||
@@ -2016,7 +2040,7 @@ class IntersectionType extends UnionOrIntersectionType, @intersection_type { }
|
||||
* Foreign array-like objects such as `HTMLCollection` are not normal JavaScript arrays,
|
||||
* and their corresponding types are not considered array types either.
|
||||
*/
|
||||
class ArrayType extends Type {
|
||||
deprecated class ArrayType extends Type {
|
||||
ArrayType() {
|
||||
this instanceof @tuple_type or
|
||||
this.(TypeReference).hasQualifiedName("Array") or
|
||||
@@ -2030,25 +2054,40 @@ class ArrayType extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* An array type such as `Array<string>`, or equivalently, `string[]`.
|
||||
*/
|
||||
class PlainArrayType extends ArrayType, TypeReference {
|
||||
deprecated class PlainArrayType extends ArrayType, TypeReference {
|
||||
PlainArrayType() { this.hasQualifiedName("Array") }
|
||||
|
||||
override Type getNumberIndexType() { result = this.getTypeArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A read-only array type such as `ReadonlyArray<string>`.
|
||||
*/
|
||||
class ReadonlyArrayType extends ArrayType, TypeReference {
|
||||
deprecated class ReadonlyArrayType extends ArrayType, TypeReference {
|
||||
ReadonlyArrayType() { this.hasQualifiedName("ReadonlyArray") }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A tuple type, such as `[number, string]`.
|
||||
*/
|
||||
class TupleType extends ArrayType, @tuple_type {
|
||||
deprecated class TupleType extends ArrayType, @tuple_type {
|
||||
/**
|
||||
* Gets the `i`th member of this tuple type, starting at 0.
|
||||
*/
|
||||
@@ -2102,34 +2141,64 @@ class TupleType extends ArrayType, @tuple_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The predefined `any` type.
|
||||
*/
|
||||
class AnyType extends Type, @any_type { }
|
||||
deprecated class AnyType extends Type, @any_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The predefined `unknown` type.
|
||||
*/
|
||||
class UnknownType extends Type, @unknown_type { }
|
||||
deprecated class UnknownType extends Type, @unknown_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The predefined `string` type.
|
||||
*/
|
||||
class StringType extends Type, @string_type { }
|
||||
deprecated class StringType extends Type, @string_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The predefined `number` type.
|
||||
*/
|
||||
class NumberType extends Type, @number_type { }
|
||||
deprecated class NumberType extends Type, @number_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The predefined `bigint` type.
|
||||
*/
|
||||
class BigIntType extends Type, @bigint_type { }
|
||||
deprecated class BigIntType extends Type, @bigint_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A boolean, number, or string literal type.
|
||||
*/
|
||||
class LiteralType extends Type, @literal_type {
|
||||
deprecated class LiteralType extends Type, @literal_type {
|
||||
/**
|
||||
* Gets the string value of this literal.
|
||||
*/
|
||||
@@ -2137,9 +2206,14 @@ class LiteralType extends Type, @literal_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The boolean literal type `true` or `false`.
|
||||
*/
|
||||
class BooleanLiteralType extends LiteralType, @boolean_literal_type {
|
||||
deprecated class BooleanLiteralType extends LiteralType, @boolean_literal_type {
|
||||
/**
|
||||
* Gets the boolean value represented by this type.
|
||||
*/
|
||||
@@ -2153,7 +2227,7 @@ class BooleanLiteralType extends LiteralType, @boolean_literal_type {
|
||||
/**
|
||||
* A number literal as a static type.
|
||||
*/
|
||||
class NumberLiteralType extends LiteralType, @number_literal_type {
|
||||
deprecated class NumberLiteralType extends LiteralType, @number_literal_type {
|
||||
override string getStringValue() { type_literal_value(this, result) }
|
||||
|
||||
/**
|
||||
@@ -2168,16 +2242,26 @@ class NumberLiteralType extends LiteralType, @number_literal_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A string literal as a static type.
|
||||
*/
|
||||
class StringLiteralType extends LiteralType, @string_literal_type {
|
||||
deprecated class StringLiteralType extends LiteralType, @string_literal_type {
|
||||
override string getStringValue() { type_literal_value(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A bigint literal as a static type.
|
||||
*/
|
||||
class BigIntLiteralType extends LiteralType {
|
||||
deprecated class BigIntLiteralType extends LiteralType {
|
||||
override string getStringValue() { type_literal_value(this, result) }
|
||||
|
||||
/**
|
||||
@@ -2192,9 +2276,14 @@ class BigIntLiteralType extends LiteralType {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `boolean` type, internally represented as the union type `true | false`.
|
||||
*/
|
||||
class BooleanType extends UnionType {
|
||||
deprecated class BooleanType extends UnionType {
|
||||
BooleanType() {
|
||||
this.getAnElementType() instanceof @true_type and
|
||||
this.getAnElementType() instanceof @false_type and
|
||||
@@ -2203,9 +2292,14 @@ class BooleanType extends UnionType {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `string` type or a string literal type.
|
||||
*/
|
||||
class StringLikeType extends Type {
|
||||
deprecated class StringLikeType extends Type {
|
||||
StringLikeType() {
|
||||
this instanceof StringType or
|
||||
this instanceof StringLiteralType
|
||||
@@ -2213,9 +2307,14 @@ class StringLikeType extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `number` type or a number literal type.
|
||||
*/
|
||||
class NumberLikeType extends Type {
|
||||
deprecated class NumberLikeType extends Type {
|
||||
NumberLikeType() {
|
||||
this instanceof NumberType or
|
||||
this instanceof NumberLiteralType
|
||||
@@ -2223,9 +2322,14 @@ class NumberLikeType extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `boolean`, `true,` or `false` type.
|
||||
*/
|
||||
class BooleanLikeType extends Type {
|
||||
deprecated class BooleanLikeType extends Type {
|
||||
BooleanLikeType() {
|
||||
this instanceof BooleanType or
|
||||
this instanceof BooleanLiteralType
|
||||
@@ -2233,39 +2337,74 @@ class BooleanLikeType extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `void` type.
|
||||
*/
|
||||
class VoidType extends Type, @void_type { }
|
||||
deprecated class VoidType extends Type, @void_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `undefined` type.
|
||||
*/
|
||||
class UndefinedType extends Type, @undefined_type { }
|
||||
deprecated class UndefinedType extends Type, @undefined_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `null` type.
|
||||
*/
|
||||
class NullType extends Type, @null_type { }
|
||||
deprecated class NullType extends Type, @null_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `never` type.
|
||||
*/
|
||||
class NeverType extends Type, @never_type { }
|
||||
deprecated class NeverType extends Type, @never_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `symbol` type or a specific `unique symbol` type.
|
||||
*/
|
||||
class SymbolType extends Type, @symbol_type { }
|
||||
deprecated class SymbolType extends Type, @symbol_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `symbol` type.
|
||||
*/
|
||||
class PlainSymbolType extends SymbolType, @plain_symbol_type { }
|
||||
deprecated class PlainSymbolType extends SymbolType, @plain_symbol_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A `unique symbol` type.
|
||||
*/
|
||||
class UniqueSymbolType extends SymbolType, @unique_symbol_type {
|
||||
deprecated class UniqueSymbolType extends SymbolType, @unique_symbol_type {
|
||||
/**
|
||||
* Gets the canonical name of the variable exposing the symbol.
|
||||
*/
|
||||
@@ -2292,14 +2431,24 @@ class UniqueSymbolType extends SymbolType, @unique_symbol_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The `object` type.
|
||||
*/
|
||||
class ObjectKeywordType extends Type, @objectkeyword_type { }
|
||||
deprecated class ObjectKeywordType extends Type, @objectkeyword_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to a class, interface, enum, or enum member.
|
||||
*/
|
||||
class TypeReference extends Type, @type_reference {
|
||||
deprecated class TypeReference extends Type, @type_reference {
|
||||
/**
|
||||
* Gets the canonical name of the type being referenced.
|
||||
*/
|
||||
@@ -2350,9 +2499,14 @@ class TypeReference extends Type, @type_reference {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to a class, possibly with type arguments.
|
||||
*/
|
||||
class ClassType extends TypeReference {
|
||||
deprecated class ClassType extends TypeReference {
|
||||
ClassDefinition declaration;
|
||||
|
||||
ClassType() { declaration = this.getADefinition() }
|
||||
@@ -2364,9 +2518,14 @@ class ClassType extends TypeReference {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to an interface, possibly with type arguents.
|
||||
*/
|
||||
class InterfaceType extends TypeReference {
|
||||
deprecated class InterfaceType extends TypeReference {
|
||||
InterfaceDeclaration declaration;
|
||||
|
||||
InterfaceType() { declaration = this.getADefinition() }
|
||||
@@ -2378,9 +2537,14 @@ class InterfaceType extends TypeReference {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to an enum.
|
||||
*/
|
||||
class EnumType extends TypeReference {
|
||||
deprecated class EnumType extends TypeReference {
|
||||
EnumDeclaration declaration;
|
||||
|
||||
EnumType() { declaration = this.getADefinition() }
|
||||
@@ -2392,9 +2556,14 @@ class EnumType extends TypeReference {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to the value of an enum member.
|
||||
*/
|
||||
class EnumLiteralType extends TypeReference {
|
||||
deprecated class EnumLiteralType extends TypeReference {
|
||||
EnumMember declaration;
|
||||
|
||||
EnumLiteralType() { declaration = this.getADefinition() }
|
||||
@@ -2406,9 +2575,14 @@ class EnumLiteralType extends TypeReference {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to a type alias.
|
||||
*/
|
||||
class TypeAliasReference extends TypeReference {
|
||||
deprecated class TypeAliasReference extends TypeReference {
|
||||
TypeAliasReference() { type_alias(this, _) }
|
||||
|
||||
/**
|
||||
@@ -2420,14 +2594,24 @@ class TypeAliasReference extends TypeReference {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* An anonymous interface type, such as `{ x: number }`.
|
||||
*/
|
||||
class AnonymousInterfaceType extends Type, @object_type { }
|
||||
deprecated class AnonymousInterfaceType extends Type, @object_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to a type variable.
|
||||
*/
|
||||
class TypeVariableType extends Type, @typevariable_type {
|
||||
deprecated class TypeVariableType extends Type, @typevariable_type {
|
||||
/**
|
||||
* Gets a syntactic declaration of this type variable.
|
||||
*
|
||||
@@ -2465,9 +2649,14 @@ class TypeVariableType extends Type, @typevariable_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to a type variable declared on a class, interface or function.
|
||||
*/
|
||||
class CanonicalTypeVariableType extends TypeVariableType, @canonical_type_variable_type {
|
||||
deprecated class CanonicalTypeVariableType extends TypeVariableType, @canonical_type_variable_type {
|
||||
override TypeName getHostType() { result = this.getCanonicalName().getParent() }
|
||||
|
||||
override CanonicalName getCanonicalName() { type_symbol(this, result) }
|
||||
@@ -2476,6 +2665,11 @@ class CanonicalTypeVariableType extends TypeVariableType, @canonical_type_variab
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type that refers to a type variable without a canonical name.
|
||||
*
|
||||
* These arise in generic call signatures such as `<T>(x: T) => T`.
|
||||
@@ -2487,13 +2681,18 @@ class CanonicalTypeVariableType extends TypeVariableType, @canonical_type_variab
|
||||
* - `<T>(x: T) => T`
|
||||
* - `<S, T>(x: S, y: T) => T`.
|
||||
*/
|
||||
class LexicalTypeVariableType extends TypeVariableType, @lexical_type_variable_type {
|
||||
deprecated class LexicalTypeVariableType extends TypeVariableType, @lexical_type_variable_type {
|
||||
override string getName() {
|
||||
types(this, _, result) // The toString value contains the name.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A `this` type in a specific class or interface.
|
||||
*
|
||||
* For example, the return type of `span` below is a `this` type
|
||||
@@ -2504,7 +2703,7 @@ class LexicalTypeVariableType extends TypeVariableType, @lexical_type_variable_t
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class ThisType extends Type, @this_type {
|
||||
deprecated class ThisType extends Type, @this_type {
|
||||
/**
|
||||
* Gets the type containing the `this` type.
|
||||
*/
|
||||
@@ -2514,10 +2713,15 @@ class ThisType extends Type, @this_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* The type of a named value, `typeof X`, typically denoting the type of
|
||||
* a class constructor, namespace object, enum object, or module object.
|
||||
*/
|
||||
class TypeofType extends Type, @typeof_type {
|
||||
deprecated class TypeofType extends Type, @typeof_type {
|
||||
/**
|
||||
* Gets the canonical name of the named value.
|
||||
*/
|
||||
@@ -2590,9 +2794,14 @@ module SignatureKind {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A function or constructor signature in a TypeScript type.
|
||||
*/
|
||||
class CallSignatureType extends @signature_type {
|
||||
deprecated class CallSignatureType extends @signature_type {
|
||||
/**
|
||||
* Gets a value indicating if this is a function or constructor signature.
|
||||
*/
|
||||
@@ -2739,14 +2948,25 @@ class CallSignatureType extends @signature_type {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A function call signature in a type, that is, a signature without the `new` keyword.
|
||||
*/
|
||||
class FunctionCallSignatureType extends CallSignatureType, @function_signature_type { }
|
||||
deprecated class FunctionCallSignatureType extends CallSignatureType, @function_signature_type { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A constructor call signature in a type, that is, a signature with the `new` keyword.
|
||||
*/
|
||||
class ConstructorCallSignatureType extends CallSignatureType, @constructor_signature_type { }
|
||||
deprecated class ConstructorCallSignatureType extends CallSignatureType, @constructor_signature_type
|
||||
{ }
|
||||
|
||||
/**
|
||||
* A type name that defines a promise.
|
||||
@@ -2756,7 +2976,7 @@ class ConstructorCallSignatureType extends CallSignatureType, @constructor_signa
|
||||
* - It has one type parameter, say, `T`
|
||||
* - It has a `then` method whose first argument is a callback that takes a `T` as argument.
|
||||
*/
|
||||
private class PromiseTypeName extends TypeName {
|
||||
deprecated private class PromiseTypeName extends TypeName {
|
||||
PromiseTypeName() {
|
||||
// The name must suggest it is a promise.
|
||||
this.getName().matches(["%Promise", "%PromiseLike", "%Thenable", "%Deferred"]) and
|
||||
@@ -2775,12 +2995,17 @@ private class PromiseTypeName extends TypeName {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Static types from the TypeScript compiler are not longer available. Use one of the following alternatives instead:
|
||||
* - `Expr.getTypeBinding()`
|
||||
* - `Expr.getNameBinding()`
|
||||
* - `TypeAnnotation.getTypeBinding()`
|
||||
*
|
||||
* A type such as `Promise<T>`, describing a promise or promise-like object.
|
||||
*
|
||||
* This includes types whose name and `then` method signature suggest it is a promise,
|
||||
* such as `PromiseLike<T>` and `Thenable<T>`.
|
||||
*/
|
||||
class PromiseType extends TypeReference {
|
||||
deprecated class PromiseType extends TypeReference {
|
||||
PromiseType() {
|
||||
this.getNumTypeArgument() = 1 and
|
||||
this.getTypeName() instanceof PromiseTypeName
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.internal.TypeResolution
|
||||
|
||||
/**
|
||||
* An input to a view component, such as React props.
|
||||
@@ -16,7 +15,7 @@ abstract class ViewComponentInput extends DataFlow::Node {
|
||||
private class ViewComponentInputAsThreatModelSource extends ThreatModelSource::Range instanceof ViewComponentInput
|
||||
{
|
||||
ViewComponentInputAsThreatModelSource() {
|
||||
not TypeResolution::valueHasSanitizingPrimitiveType(this.asExpr())
|
||||
not this.asExpr().getTypeBinding().isSanitizingPrimitiveType()
|
||||
}
|
||||
|
||||
final override string getThreatModel() { result = "view-component-input" }
|
||||
|
||||
@@ -50,7 +50,7 @@ module ClassValidator {
|
||||
|
||||
pragma[noinline]
|
||||
private ClassDefinition getClassReferencedByPropRead(DataFlow::PropRead read) {
|
||||
read.getBase().asExpr().getType().unfold().(ClassType).getClass() = result
|
||||
read.getBase().asExpr().getTypeBinding().getAnUnderlyingClass().getAstNode() = result
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,18 +41,19 @@ module Electron {
|
||||
BrowserView() { this = DataFlow::moduleMember("electron", "BrowserView").getAnInstantiation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression of type `BrowserWindow` or `BrowserView`.
|
||||
*/
|
||||
private class BrowserObjectByType extends BrowserObject {
|
||||
BrowserObjectByType() {
|
||||
exists(string tp | tp = "BrowserWindow" or tp = "BrowserView" |
|
||||
this.asExpr().getType().hasUnderlyingType("electron", tp)
|
||||
)
|
||||
private class ElectronEntryPoint extends API::EntryPoint {
|
||||
ElectronEntryPoint() { this = "Electron.Browser" }
|
||||
|
||||
override DataFlow::SourceNode getASource() {
|
||||
result.hasUnderlyingType(["Electron.BrowserWindow", "Electron.BrowserView"])
|
||||
}
|
||||
}
|
||||
|
||||
private API::Node browserObject() { result.asSource() instanceof NewBrowserObject }
|
||||
private API::Node browserObject() {
|
||||
result.asSource() instanceof NewBrowserObject or
|
||||
result = API::Node::ofType("electron", ["BrowserWindow", "BrowserView"]) or
|
||||
result = any(ElectronEntryPoint e).getANode()
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node whose value may originate from a browser object instantiation.
|
||||
|
||||
@@ -48,7 +48,7 @@ module Express {
|
||||
private predicate isRouter(DataFlow::Node e) {
|
||||
isRouter(e, _)
|
||||
or
|
||||
e.asExpr().getType().hasUnderlyingType("express", "Router")
|
||||
e.(DataFlow::SourceNode).hasUnderlyingType("express", "Router")
|
||||
or
|
||||
// created by `webpack-dev-server`
|
||||
WebpackDevServer::webpackDevServerApp().flowsTo(e)
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
import javascript
|
||||
private import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomizations
|
||||
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
||||
private import semmle.javascript.internal.NameResolution
|
||||
private import semmle.javascript.internal.TypeResolution
|
||||
|
||||
/**
|
||||
* Provides classes and predicates for reasoning about [Nest](https://nestjs.com/).
|
||||
@@ -137,7 +135,7 @@ module NestJS {
|
||||
hasSanitizingPipe(this, true) and
|
||||
// Note: we could consider types with class-validator decorators to be sanitized here, but instead we consider the root
|
||||
// object to be tainted, but omit taint steps for the individual properties names that have sanitizing decorators. See ClassValidator.qll.
|
||||
TypeResolution::isSanitizingPrimitiveType(this.getParameter().getTypeAnnotation())
|
||||
this.getParameter().getTypeBinding().isSanitizingPrimitiveType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,9 +335,10 @@ module NestJS {
|
||||
handler.isReturnValueReflected() and
|
||||
this = handler.getAReturn() and
|
||||
// Only returned strings are sinks. If we can find a type for the return value, it must be string-like.
|
||||
not exists(NameResolution::Node type |
|
||||
TypeResolution::valueHasType(this.asExpr(), type) and
|
||||
not TypeResolution::hasUnderlyingStringOrAnyType(type)
|
||||
(
|
||||
this.asExpr().getTypeBinding().hasUnderlyingStringOrAnyType()
|
||||
or
|
||||
not exists(this.asExpr().getTypeBinding())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -540,46 +539,32 @@ module NestJS {
|
||||
)
|
||||
}
|
||||
|
||||
private DataFlow::Node getConcreteClassFromProviderTuple(DataFlow::SourceNode tuple) {
|
||||
result = tuple.getAPropertyWrite("useClass").getRhs()
|
||||
private DataFlow::ClassNode getConcreteClassFromProviderTuple(DataFlow::SourceNode tuple) {
|
||||
result = tuple.getAPropertyWrite("useClass").getRhs().asExpr().getNameBinding().getClassNode()
|
||||
or
|
||||
exists(DataFlow::FunctionNode f |
|
||||
f = tuple.getAPropertyWrite("useFactory").getRhs().getAFunctionValue() and
|
||||
result.getAstNode() = f.getFunction().getAReturnedExpr().getType().(ClassType).getClass()
|
||||
result = f.getFunction().getAReturnedExpr().getTypeBinding().getAnUnderlyingClass()
|
||||
)
|
||||
or
|
||||
result.getAstNode() =
|
||||
tuple.getAPropertyWrite("useValue").getRhs().asExpr().getType().(ClassType).getClass()
|
||||
result =
|
||||
tuple.getAPropertyWrite("useValue").getRhs().asExpr().getTypeBinding().getAnUnderlyingClass()
|
||||
}
|
||||
|
||||
private predicate providerPair(DataFlow::Node interface, DataFlow::Node concreteClass) {
|
||||
private predicate providerPair(DataFlow::ClassNode interface, DataFlow::ClassNode concreteClass) {
|
||||
exists(DataFlow::SourceNode tuple |
|
||||
tuple = providerTuple().getALocalSource() and
|
||||
interface = tuple.getAPropertyWrite("provide").getRhs() and
|
||||
interface =
|
||||
tuple.getAPropertyWrite("provide").getRhs().asExpr().getNameBinding().getClassNode() and
|
||||
concreteClass = getConcreteClassFromProviderTuple(tuple)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the class being referenced at `node` without relying on the call graph. */
|
||||
private DataFlow::ClassNode getClassFromNode(DataFlow::Node node) {
|
||||
result.getAstNode() = node.analyze().getAValue().(AbstractClass).getClass()
|
||||
}
|
||||
|
||||
private predicate providerClassPair(
|
||||
DataFlow::ClassNode interface, DataFlow::ClassNode concreteClass
|
||||
) {
|
||||
exists(DataFlow::Node interfaceNode, DataFlow::Node concreteClassNode |
|
||||
providerPair(interfaceNode, concreteClassNode) and
|
||||
interface = getClassFromNode(interfaceNode) and
|
||||
concreteClass = getClassFromNode(concreteClassNode)
|
||||
)
|
||||
}
|
||||
|
||||
private class DependencyInjectionStep extends PreCallGraphStep {
|
||||
override predicate classInstanceSource(DataFlow::ClassNode cls, DataFlow::Node node) {
|
||||
exists(DataFlow::ClassNode interfaceClass |
|
||||
node.asExpr().(Parameter).getType().(ClassType).getClass() = interfaceClass.getAstNode() and
|
||||
providerClassPair(interfaceClass, cls)
|
||||
node.asExpr().getTypeBinding().getTypeDefinition() = interfaceClass.getAstNode() and
|
||||
providerPair(interfaceClass, cls)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
177
javascript/ql/lib/semmle/javascript/internal/BindingInfo.qll
Normal file
177
javascript/ql/lib/semmle/javascript/internal/BindingInfo.qll
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* Provides a limited public interface to name/type resolution information.
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.internal.NameResolution
|
||||
private import semmle.javascript.internal.TypeResolution
|
||||
private import semmle.javascript.internal.UnderlyingTypes
|
||||
|
||||
/**
|
||||
* Interface for accessing name-resolution info about type names.
|
||||
*/
|
||||
class TypeNameBindingNode extends NameResolution::Node {
|
||||
/**
|
||||
* Holds if type refers to, or is an alias for, the given type name relative to the global scope.
|
||||
*
|
||||
* For example:
|
||||
* ```ts
|
||||
* var x: Document; // hasQualifiedName("Document")
|
||||
* var x: Electron; // hasQualifiedName("Electron")
|
||||
* var x: Electron.BrowserWindow; // hasQualifiedName("Electron.BrowserWindow")
|
||||
* ```
|
||||
*/
|
||||
predicate hasQualifiedName(string qualifiedName) {
|
||||
NameResolution::nodeRefersToModule(this, "global", qualifiedName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this refers to a value exported by the given module, with the given
|
||||
* qualified name. If the `qualifiedName` is empty, this refers to the module itself.
|
||||
*
|
||||
* For example, the type annotations below have the following name bindings:
|
||||
* ```ts
|
||||
* import { Request } from "express";
|
||||
*
|
||||
* var x: Request; // hasUnderlyingType("express", "Request")
|
||||
* var x: Request | null; // no result (see hasUnderlyingType)
|
||||
* var x: Request & { prop: string }; // no result (see hasUnderlyingType)
|
||||
*
|
||||
* interface CustomSubtype extends Request {}
|
||||
*
|
||||
* var x: CustomSubtype; // no result (see hasUnderlyingType)
|
||||
*
|
||||
* var x: typeof import("express"); // hasUnderlyingType("express", "")
|
||||
* ```
|
||||
*/
|
||||
predicate hasQualifiedName(string moduleName, string qualifiedName) {
|
||||
NameResolution::nodeRefersToModule(this, moduleName, qualifiedName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type refers to the given type exported from the given module, after
|
||||
* unfolding unions and intersections, and following subtype relations.
|
||||
*
|
||||
* For example:
|
||||
* ```ts
|
||||
* import { Request } from "express";
|
||||
*
|
||||
* var x: Request; // hasUnderlyingType("express", "Request")
|
||||
* var x: Request | null; // hasUnderlyingType("express", "Request")
|
||||
* var x: Request & { prop: string }; // hasUnderlyingType("express", "Request")
|
||||
*
|
||||
* interface CustomSubtype extends Request {}
|
||||
*
|
||||
* var x: CustomSubtype; // hasUnderlyingType("express", "Request")
|
||||
* ```
|
||||
*/
|
||||
predicate hasUnderlyingType(string moduleName, string qualifiedName) {
|
||||
UnderlyingTypes::nodeHasUnderlyingType(this, moduleName, qualifiedName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type refers to the given type from the global scope, after
|
||||
* unfolding unions and intersections, and following subtype relations.
|
||||
*
|
||||
* For example:
|
||||
* ```ts
|
||||
* var x: Document; // hasUnderlyingType("Document")
|
||||
* var x: Document | null; // hasUnderlyingType("Document")
|
||||
* var x: Document & { prop: string }; // hasUnderlyingType("Document")
|
||||
*
|
||||
* interface CustomSubtype extends Document {}
|
||||
*
|
||||
* var x: CustomSubtype; // hasUnderlyingType("Document")
|
||||
* ```
|
||||
*/
|
||||
predicate hasUnderlyingType(string qualifiedName) {
|
||||
UnderlyingTypes::nodeHasUnderlyingType(this, qualifiedName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the declaration of the type being referenced by this name.
|
||||
*
|
||||
* For example:
|
||||
* ```ts
|
||||
* class Foo {}
|
||||
*
|
||||
* type T = Foo;
|
||||
* var x: T; // getTypeDefinition() maps T to the class Foo above
|
||||
* ```
|
||||
*
|
||||
* Note that this has no result for function-style classes referenced from
|
||||
* a JSDoc comment.
|
||||
*/
|
||||
TypeDefinition getTypeDefinition() { TypeResolution::trackType(result) = this }
|
||||
|
||||
/**
|
||||
* Gets a class that this type refers to, after unfolding unions and intersections (but not subtyping).
|
||||
*
|
||||
* For example, the type of `x` maps to the class `C` in each example below:
|
||||
* ```ts
|
||||
* class C {}
|
||||
*
|
||||
* var x: C;
|
||||
* var x: C | null;
|
||||
* var x: C & { prop: string };
|
||||
* ```
|
||||
*/
|
||||
DataFlow::ClassNode getAnUnderlyingClass() {
|
||||
UnderlyingTypes::nodeHasUnderlyingClassType(this, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type contains `string` or `any`, possibly wrapped in a promise.
|
||||
*/
|
||||
predicate hasUnderlyingStringOrAnyType() { TypeResolution::hasUnderlyingStringOrAnyType(this) }
|
||||
|
||||
/**
|
||||
* Holds if this refers to a type that is considered untaintable (if actually enforced at runtime).
|
||||
*
|
||||
* Specifically, the types `number`, `boolean`, `null`, `undefined`, `void`, `never`, as well as literal types (`"foo"`)
|
||||
* and enums and enum members have this property.
|
||||
*/
|
||||
predicate isSanitizingPrimitiveType() { TypeResolution::isSanitizingPrimitiveType(this) }
|
||||
|
||||
/**
|
||||
* Holds if the given type is a Promise object. Does not hold for unions unless all parts of the union are promises.
|
||||
*/
|
||||
predicate isPromiseType() { TypeResolution::isPromiseType(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for accessing name-resolution info about expressions.
|
||||
*/
|
||||
class ExprNameBindingNode extends NameResolution::Node {
|
||||
/**
|
||||
* Holds if this refers a value exported by the given module, with the given
|
||||
* qualified name. If the `qualifiedName` is empty, this refers to the module itself.
|
||||
*
|
||||
* For example, the type annotations below have the following name bindings:
|
||||
* ```ts
|
||||
* import * as f from "foo";
|
||||
*
|
||||
* var x = f; // hasQualifiedName("f", "")
|
||||
* var x = f.x.y; // hasQualifiedName("f", "x.y")
|
||||
* ```
|
||||
*/
|
||||
predicate hasQualifiedName(string moduleName, string qualifiedName) {
|
||||
NameResolution::nodeRefersToModule(this, moduleName, qualifiedName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class, or function acting as a class, referenced by this name.
|
||||
*
|
||||
* ```ts
|
||||
* class Foo {}
|
||||
* const T = Foo;
|
||||
* var x = T; // getClassNode() maps T to the class Foo above
|
||||
*
|
||||
* function Bar() {}
|
||||
* Bar.prototype.blah = function() {};
|
||||
* const S = Bar;
|
||||
* var x = S; // getClassNode() maps S to the function Bar above
|
||||
* ```
|
||||
*/
|
||||
DataFlow::ClassNode getClassNode() { NameResolution::nodeRefersToClass(this, result) }
|
||||
}
|
||||
@@ -17,6 +17,7 @@ module NameResolution {
|
||||
* A node in a graph which we use to perform name and type resolution.
|
||||
*/
|
||||
class Node extends NodeBase {
|
||||
/** Gets a string representation of this node. */
|
||||
string toString() {
|
||||
result = this.(AstNode).toString()
|
||||
or
|
||||
@@ -25,6 +26,7 @@ module NameResolution {
|
||||
result = this.(JSDocTypeExpr).toString()
|
||||
}
|
||||
|
||||
/** Gets the location of this node. */
|
||||
Location getLocation() {
|
||||
result = this.(AstNode).getLocation()
|
||||
or
|
||||
@@ -44,6 +46,9 @@ module NameResolution {
|
||||
this instanceof Module
|
||||
or
|
||||
this instanceof NamespaceDefinition // `module {}` or `enum {}` statement
|
||||
or
|
||||
// A module wrapped in a promise. We model this as a module exporting the actual module in a property called `$$promise-content`.
|
||||
this instanceof DynamicImportExpr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,6 +235,19 @@ module NameResolution {
|
||||
name = expr.getName() and
|
||||
node2 = expr
|
||||
)
|
||||
or
|
||||
exists(AwaitExpr await |
|
||||
node1 = await.getOperand() and
|
||||
name = "$$promise-content" and
|
||||
node2 = await
|
||||
)
|
||||
or
|
||||
exists(MethodCallExpr call |
|
||||
call.getMethodName() = "then" and
|
||||
node1 = call.getReceiver() and
|
||||
name = "$$promise-content" and
|
||||
node2 = call.getArgument(0).(Function).getParameter(0)
|
||||
)
|
||||
}
|
||||
|
||||
private signature module TypeResolutionInputSig {
|
||||
@@ -332,6 +350,12 @@ module NameResolution {
|
||||
)
|
||||
or
|
||||
storeToVariable(result, name, mod.(Closure::ClosureModule).getExportsVariable())
|
||||
or
|
||||
exists(DynamicImportExpr imprt |
|
||||
mod = imprt and
|
||||
name = "$$promise-content" and
|
||||
result = imprt.getImportedPathExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,6 +432,10 @@ module NameResolution {
|
||||
*/
|
||||
predicate trackModule = ValueFlow::TrackNode<ModuleLike>::track/1;
|
||||
|
||||
predicate trackClassValue = ValueFlow::TrackNode<ClassDefinition>::track/1;
|
||||
|
||||
predicate trackFunctionValue = ValueFlow::TrackNode<Function>::track/1;
|
||||
|
||||
/**
|
||||
* Holds if `moduleName` appears to start with a package name, as opposed to a relative file import.
|
||||
*/
|
||||
@@ -509,4 +537,25 @@ module NameResolution {
|
||||
qualifiedName = append(prefix, step)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate classHasGlobalName(DataFlow::ClassNode cls, string name) {
|
||||
cls.flowsTo(AccessPath::getAnAssignmentTo(name)) and
|
||||
not cls.getTopLevel().isExterns() // don't propagate externs classes
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` refers to the given class.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate nodeRefersToClass(Node node, DataFlow::ClassNode cls) {
|
||||
exists(string name |
|
||||
classHasGlobalName(cls, name) and
|
||||
nodeRefersToModule(node, "global", name)
|
||||
)
|
||||
or
|
||||
trackClassValue(cls.getAstNode()) = node
|
||||
or
|
||||
trackFunctionValue(cls.getAstNode()) = node
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ private import semmle.javascript.internal.UnderlyingTypes
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.SummaryTypeTracker as SummaryTypeTracker
|
||||
|
||||
module TypeResolution {
|
||||
predicate trackClassValue = ValueFlow::TrackNode<ClassDefinition>::track/1;
|
||||
|
||||
predicate trackType = TypeFlow::TrackNode<TypeDefinition>::track/1;
|
||||
|
||||
/**
|
||||
@@ -24,8 +22,6 @@ module TypeResolution {
|
||||
)
|
||||
}
|
||||
|
||||
predicate trackFunctionValue = ValueFlow::TrackNode<Function>::track/1;
|
||||
|
||||
/**
|
||||
* Gets the representative for the type containing the given member.
|
||||
*
|
||||
@@ -134,6 +130,13 @@ module TypeResolution {
|
||||
or
|
||||
SummaryTypeTracker::basicLoadStep(object.(AST::ValueNode).flow(),
|
||||
member.(AST::ValueNode).flow(), contents)
|
||||
or
|
||||
exists(IndexExpr index |
|
||||
not exists(index.getPropertyName()) and
|
||||
object = index.getBase() and
|
||||
member = index and
|
||||
contents = DataFlow::ContentSet::arrayElement()
|
||||
)
|
||||
}
|
||||
|
||||
predicate callTarget(InvokeExpr call, Function target) {
|
||||
|
||||
@@ -119,10 +119,4 @@ module UnderlyingTypes {
|
||||
// The caller is responsible for handling the class hierarchy.
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate classHasGlobalName(DataFlow::ClassNode cls, string name) {
|
||||
cls.flowsTo(AccessPath::getAnAssignmentTo(name)) and
|
||||
not cls.getTopLevel().isExterns() // don't propagate externs classes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,20 +45,22 @@ string getKind(MemberDeclaration m) {
|
||||
/**
|
||||
* A call-signature that originates from a MethodSignature in the AST.
|
||||
*/
|
||||
private class MethodCallSig extends CallSignatureType {
|
||||
string name;
|
||||
private class MethodCallSig extends Function {
|
||||
private MethodSignature signature;
|
||||
|
||||
MethodCallSig() {
|
||||
exists(MethodSignature sig |
|
||||
this = sig.getBody().getCallSignature() and
|
||||
name = sig.getName()
|
||||
)
|
||||
MethodCallSig() { this = signature.getBody() }
|
||||
|
||||
int getNumOptionalParameter() {
|
||||
result = count(Parameter p | p = this.getParameter(_) and p.isDeclaredOptional())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of any member that has this signature.
|
||||
*/
|
||||
string getName() { result = name }
|
||||
int getNumRequiredParameter() {
|
||||
result = count(Parameter p | p = this.getParameter(_) and not p.isDeclaredOptional())
|
||||
}
|
||||
|
||||
SignatureKind getKind() { result = SignatureKind::function() }
|
||||
|
||||
TypeExpr getTypeParameterBound(int i) { result = this.getTypeParameter(i).getBound() }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -75,6 +77,7 @@ private MethodCallSig getMethodCallSigWithFingerprint(
|
||||
/**
|
||||
* Holds if the two call signatures could be overloads of each other and have the same parameter types.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate matchingCallSignature(MethodCallSig method, MethodCallSig other) {
|
||||
other =
|
||||
getMethodCallSigWithFingerprint(method.getName(), method.getNumOptionalParameter(),
|
||||
@@ -109,6 +112,16 @@ private MethodSignature getMethodSignatureWithFingerprint(
|
||||
result.getBody().getNumParameter() = numParameters
|
||||
}
|
||||
|
||||
bindingset[t1, t2]
|
||||
pragma[inline_late]
|
||||
private predicate sameType(TypeExpr t1, TypeExpr t2) {
|
||||
t1.(PredefinedTypeExpr).getName() = t2.(PredefinedTypeExpr).getName()
|
||||
or
|
||||
t1 instanceof ThisTypeExpr and t2 instanceof ThisTypeExpr
|
||||
or
|
||||
t1.(LocalTypeAccess).getLocalTypeName() = t2.(LocalTypeAccess).getLocalTypeName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the two method signatures are overloads of each other and have the same parameter types.
|
||||
*/
|
||||
@@ -122,14 +135,13 @@ predicate signaturesMatch(MethodSignature method, MethodSignature other) {
|
||||
not exists(method.getBody().getThisTypeAnnotation()) and
|
||||
not exists(other.getBody().getThisTypeAnnotation())
|
||||
or
|
||||
method.getBody().getThisTypeAnnotation().getType() =
|
||||
other.getBody().getThisTypeAnnotation().getType()
|
||||
sameType(method.getBody().getThisTypeAnnotation(), other.getBody().getThisTypeAnnotation())
|
||||
) and
|
||||
// The types are compared in matchingCallSignature. This is a consistency check that the textual representation of the type-annotations are somewhat similar.
|
||||
forall(int i | i in [0 .. -1 + method.getBody().getNumParameter()] |
|
||||
getParameterTypeAnnotation(method, i) = getParameterTypeAnnotation(other, i)
|
||||
) and
|
||||
matchingCallSignature(method.getBody().getCallSignature(), other.getBody().getCallSignature())
|
||||
matchingCallSignature(method.getBody(), other.getBody())
|
||||
}
|
||||
|
||||
from ClassOrInterface decl, string name, MethodSignature previous, MethodSignature unreachable
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.TypeResolution
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call to an `async` function.
|
||||
@@ -30,7 +29,7 @@ predicate isPromise(DataFlow::SourceNode node, boolean nullable) {
|
||||
isAsyncCall(node, nullable)
|
||||
or
|
||||
not isAsyncCall(node, _) and
|
||||
TypeResolution::valueHasPromiseType(node.asExpr()) and
|
||||
node.asExpr().getTypeBinding().isPromiseType() and
|
||||
nullable = true
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* The `Type` and `Symbol` classes have been deprecated and will be empty in newly extracted databases, since the TypeScript extractor no longer populates them.
|
||||
This is a breaking change for custom queries that explicitly relied on these classes.
|
||||
Such queries will still compile, but with deprecation warnings, and may have different query results due to type information no longer being available.
|
||||
We expect most custom queries will not be affected, however. If a custom query has no deprecation warnings, it should not be affected by this change.
|
||||
Uses of `getType()` should be rewritten to use the new `getTypeBinding()` or `getNameBinding()` APIs instead.
|
||||
If the new API is not sufficient, please consider opening an issue in `github/codeql` describing your use-case.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* The TypeScript extractor no longer relies on the TypeScript compiler for extracting type information.
|
||||
Instead, the information we need from types is now derived by an algorithm written in QL.
|
||||
This results in more robust extraction with faster extraction times, in some cases significantly faster.
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* @name Typed expressions
|
||||
* @description The number of expressions for which the TypeScript extractor could
|
||||
* extract a type other than 'any'.
|
||||
* @kind metric
|
||||
* @metricType project
|
||||
* @metricAggregate sum
|
||||
* @tags meta
|
||||
* @id js/meta/typed-expressions
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import meta.MetaMetrics
|
||||
|
||||
predicate isProperType(Type t) { not t instanceof AnyType }
|
||||
|
||||
select projectRoot(), count(Expr e | isProperType(e.getType()))
|
||||
@@ -1,17 +0,0 @@
|
||||
arrayTypes
|
||||
| [number, string] | `string \| number` |
|
||||
| number[] | `number` |
|
||||
| readonly T[] | `T` |
|
||||
| readonly number[] | `number` |
|
||||
| readonly number[][] | `number[]` |
|
||||
numberIndexTypes
|
||||
| NumberIndexable | object |
|
||||
| [number, string] | string \| number |
|
||||
| number[] | number |
|
||||
| readonly T[] | T |
|
||||
| readonly number[] | number |
|
||||
| readonly number[][] | number[] |
|
||||
| string | string |
|
||||
stringIndexTypes
|
||||
| StringIndexable | object |
|
||||
tupleTypes
|
||||
@@ -1,11 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate arrayTypes(ArrayType array, string elem) {
|
||||
elem = "`" + array.getArrayElementType() + "`"
|
||||
}
|
||||
|
||||
query predicate numberIndexTypes(Type type, Type numType) { type.getNumberIndexType() = numType }
|
||||
|
||||
query predicate stringIndexTypes(Type type, Type strType) { type.getStringIndexType() = strType }
|
||||
|
||||
query predicate tupleTypes(TupleType type, Type arrType) { arrType = type.getUnderlyingArrayType() }
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,19 +0,0 @@
|
||||
let plain: number[];
|
||||
let readonly: ReadonlyArray<number>;
|
||||
let tuple: [number, string];
|
||||
|
||||
interface NumberIndexable {
|
||||
length: number;
|
||||
[n: number]: object;
|
||||
}
|
||||
|
||||
interface StringIndexable {
|
||||
length: number;
|
||||
[n: string]: object;
|
||||
}
|
||||
|
||||
let numberIndexable: NumberIndexable;
|
||||
let stringIndexable: StringIndexable;
|
||||
|
||||
let readonlySyntax: readonly number[];
|
||||
let readonlySyntax2: readonly number[][];
|
||||
@@ -1,15 +0,0 @@
|
||||
| CEverything | CGenericBase |
|
||||
| CEverything | IBase |
|
||||
| CEverything | IGenericSub |
|
||||
| CGenericSub | CGenericBase |
|
||||
| CImplements | IBase |
|
||||
| CImplementsGeneric | IGenericBase |
|
||||
| CImplementsString | IGenericBase |
|
||||
| CStringSub | CGenericBase |
|
||||
| CSub | CBase |
|
||||
| IEmptySub | IEmpty |
|
||||
| IGenericSub | IGenericBase |
|
||||
| IMulti | IBase |
|
||||
| IMulti | IGenericBase |
|
||||
| IStringSub | IGenericBase |
|
||||
| ISub | IBase |
|
||||
@@ -1,4 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from TypeName typename
|
||||
select typename.getName(), typename.getABaseTypeName().getName()
|
||||
@@ -1,17 +0,0 @@
|
||||
| CBase | CBase |
|
||||
| CEverything | CEverything<S, T> |
|
||||
| CGenericBase | CGenericBase<T> |
|
||||
| CGenericSub | CGenericSub<Q> |
|
||||
| CImplements | CImplements |
|
||||
| CImplementsGeneric | CImplementsGeneric<Q> |
|
||||
| CImplementsString | CImplementsString |
|
||||
| CStringSub | CStringSub |
|
||||
| CSub | CSub |
|
||||
| IBase | IBase |
|
||||
| IEmpty | IEmpty |
|
||||
| IEmptySub | IEmptySub |
|
||||
| IGenericBase | IGenericBase<T> |
|
||||
| IGenericSub | IGenericSub<Q> |
|
||||
| IMulti | IMulti<T> |
|
||||
| IStringSub | IStringSub |
|
||||
| ISub | ISub |
|
||||
@@ -1,4 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from TypeName tn
|
||||
select tn.getName(), tn.getType()
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,39 +0,0 @@
|
||||
interface IBase {
|
||||
x: string;
|
||||
}
|
||||
interface ISub extends IBase {
|
||||
y: string;
|
||||
}
|
||||
|
||||
interface IGenericBase<T> {
|
||||
w: T;
|
||||
}
|
||||
interface IStringSub extends IGenericBase<string> {}
|
||||
interface IGenericSub<Q> extends IGenericBase<Q> {}
|
||||
|
||||
class CBase {}
|
||||
class CSub extends CBase {}
|
||||
|
||||
class CGenericBase<T> {}
|
||||
class CStringSub extends CGenericBase<string> {}
|
||||
class CGenericSub<Q> extends CGenericBase<Q> {}
|
||||
|
||||
interface IMulti<T> extends IBase, IGenericBase<T> {}
|
||||
|
||||
abstract class CImplements implements IBase {
|
||||
x: string;
|
||||
}
|
||||
abstract class CImplementsString implements IGenericBase<string> {
|
||||
w: string;
|
||||
}
|
||||
abstract class CImplementsGeneric<Q> implements IGenericBase<Q> {
|
||||
w: Q;
|
||||
}
|
||||
|
||||
abstract class CEverything<S,T> extends CGenericBase<S> implements IGenericSub<T>, IBase {
|
||||
x: string;
|
||||
w: T;
|
||||
}
|
||||
|
||||
interface IEmpty {}
|
||||
interface IEmptySub extends IEmpty {}
|
||||
@@ -4,14 +4,7 @@ exprFloatValue
|
||||
| tst.ts:3:25:3:56 | 1000000 ... 000000n | 1.0E30 |
|
||||
exprIntValue
|
||||
| tst.ts:1:25:1:28 | 100n | 100 |
|
||||
exprWithBigIntType
|
||||
| tst.ts:1:5:1:11 | hundred |
|
||||
| tst.ts:2:5:2:12 | bigValue |
|
||||
| tst.ts:3:5:3:20 | bigNegativeValue |
|
||||
| tst.ts:5:5:5:14 | bigintType |
|
||||
literalTypeExprIntValue
|
||||
| tst.ts:6:24:6:28 | 1000n | 1000 |
|
||||
typeExpr
|
||||
| tst.ts:5:24:5:29 | bigint |
|
||||
typeIntValue
|
||||
| 1000n | 1000 |
|
||||
|
||||
@@ -4,12 +4,8 @@ query predicate exprFloatValue(BigIntLiteral literal, float f) { f = literal.get
|
||||
|
||||
query predicate exprIntValue(BigIntLiteral literal, int i) { i = literal.getIntValue() }
|
||||
|
||||
query predicate exprWithBigIntType(Expr e) { e.getType() instanceof BigIntType }
|
||||
|
||||
query predicate literalTypeExprIntValue(BigIntLiteralTypeExpr type, int val) {
|
||||
val = type.getIntValue()
|
||||
}
|
||||
|
||||
query predicate typeExpr(TypeExpr type) { type.isBigInt() }
|
||||
|
||||
query predicate typeIntValue(BigIntLiteralType type, int i) { type.getIntValue() = i }
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
| tst.ts:52:3:52:23 | obj.sim ... od(str) | (x: string): number | 0 |
|
||||
| tst.ts:53:3:53:24 | obj.gen ... od(str) | (x: string): string | 0 |
|
||||
| tst.ts:54:3:54:24 | obj.gen ... od(num) | (x: number): number | 0 |
|
||||
| tst.ts:55:3:55:27 | obj.ove ... od(num) | (x: number): number | 0 |
|
||||
| tst.ts:56:3:56:27 | obj.ove ... od(str) | (x: string): string | 1 |
|
||||
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | (x: any): any | 2 |
|
||||
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | (x: number[]): number | 0 |
|
||||
| tst.ts:59:3:59:39 | obj.gen ... : str}) | (x: Box<string>): string | 1 |
|
||||
| tst.ts:60:3:60:34 | obj.gen ... od(num) | (x: any): any | 2 |
|
||||
| tst.ts:64:3:64:23 | obj.sim ... od(str) | (x: string): number | 0 |
|
||||
| tst.ts:65:3:65:24 | obj.gen ... od(str) | (x: string): string | 0 |
|
||||
| tst.ts:66:3:66:24 | obj.gen ... od(num) | (x: number): number | 0 |
|
||||
| tst.ts:67:3:67:27 | obj.ove ... od(num) | (x: number): number | 0 |
|
||||
| tst.ts:68:3:68:27 | obj.ove ... od(str) | (x: string): string | 1 |
|
||||
| tst.ts:69:3:69:36 | obj.gen ... ([num]) | (x: number[]): number | 0 |
|
||||
| tst.ts:70:3:70:39 | obj.gen ... : str}) | (x: Box<string>): string | 1 |
|
||||
| tst.ts:74:3:74:28 | new Sim ... or(str) | new (x: string): SimpleConstructor | 0 |
|
||||
| tst.ts:75:3:75:29 | new Gen ... or(str) | new (x: string): GenericConstructor<string> | 0 |
|
||||
| tst.ts:76:3:76:29 | new Gen ... or(num) | new (x: number): GenericConstructor<number> | 0 |
|
||||
| tst.ts:77:3:77:37 | new Ove ... m, num) | new (x: number, y: number): OverloadedConstructor | 0 |
|
||||
| tst.ts:78:3:78:37 | new Ove ... r, str) | new (x: string, y: string): OverloadedConstructor | 1 |
|
||||
| tst.ts:79:3:79:48 | new Gen ... [str]) | new (x: string[], y: string[]): GenericOverloadedConstructor<string> | 0 |
|
||||
| tst.ts:80:3:80:54 | new Gen ... : num}) | new (x: Box<number>, y: Box<number>): GenericOverloadedConstructor<nu... | 1 |
|
||||
| tst.ts:84:10:84:24 | callback("str") | (x: string): U | 0 |
|
||||
@@ -1,4 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from InvokeExpr invoke
|
||||
select invoke, invoke.getResolvedSignature(), invoke.getResolvedOverloadIndex()
|
||||
@@ -1,36 +0,0 @@
|
||||
| tst.ts:52:3:52:23 | obj.sim ... od(str) | TestInterface.simpleMethod in global scope | simpleM ... number; |
|
||||
| tst.ts:53:3:53:24 | obj.gen ... od(str) | TestInterface.genericMethod in global scope | generic ... T): T; |
|
||||
| tst.ts:54:3:54:24 | obj.gen ... od(num) | TestInterface.genericMethod in global scope | generic ... T): T; |
|
||||
| tst.ts:55:3:55:27 | obj.ove ... od(num) | TestInterface.overloadedMethod in global scope | overloa ... ): any; |
|
||||
| tst.ts:55:3:55:27 | obj.ove ... od(num) | TestInterface.overloadedMethod in global scope | overloa ... number; |
|
||||
| tst.ts:55:3:55:27 | obj.ove ... od(num) | TestInterface.overloadedMethod in global scope | overloa ... string; |
|
||||
| tst.ts:56:3:56:27 | obj.ove ... od(str) | TestInterface.overloadedMethod in global scope | overloa ... ): any; |
|
||||
| tst.ts:56:3:56:27 | obj.ove ... od(str) | TestInterface.overloadedMethod in global scope | overloa ... number; |
|
||||
| tst.ts:56:3:56:27 | obj.ove ... od(str) | TestInterface.overloadedMethod in global scope | overloa ... string; |
|
||||
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | TestInterface.overloadedMethod in global scope | overloa ... ): any; |
|
||||
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | TestInterface.overloadedMethod in global scope | overloa ... number; |
|
||||
| tst.ts:57:3:57:26 | obj.ove ... hod([]) | TestInterface.overloadedMethod in global scope | overloa ... string; |
|
||||
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | TestInterface.genericOverloadedMethod in global scope | generic ... ): any; |
|
||||
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | TestInterface.genericOverloadedMethod in global scope | generic ... T>): T; |
|
||||
| tst.ts:58:3:58:36 | obj.gen ... ([num]) | TestInterface.genericOverloadedMethod in global scope | generic ... []): T; |
|
||||
| tst.ts:59:3:59:39 | obj.gen ... : str}) | TestInterface.genericOverloadedMethod in global scope | generic ... ): any; |
|
||||
| tst.ts:59:3:59:39 | obj.gen ... : str}) | TestInterface.genericOverloadedMethod in global scope | generic ... T>): T; |
|
||||
| tst.ts:59:3:59:39 | obj.gen ... : str}) | TestInterface.genericOverloadedMethod in global scope | generic ... []): T; |
|
||||
| tst.ts:60:3:60:34 | obj.gen ... od(num) | TestInterface.genericOverloadedMethod in global scope | generic ... ): any; |
|
||||
| tst.ts:60:3:60:34 | obj.gen ... od(num) | TestInterface.genericOverloadedMethod in global scope | generic ... T>): T; |
|
||||
| tst.ts:60:3:60:34 | obj.gen ... od(num) | TestInterface.genericOverloadedMethod in global scope | generic ... []): T; |
|
||||
| tst.ts:64:3:64:23 | obj.sim ... od(str) | TestClass.simpleMethod in global scope | simpleM ... ength } |
|
||||
| tst.ts:65:3:65:24 | obj.gen ... od(str) | TestClass.genericMethod in global scope | generic ... rn x; } |
|
||||
| tst.ts:66:3:66:24 | obj.gen ... od(num) | TestClass.genericMethod in global scope | generic ... rn x; } |
|
||||
| tst.ts:67:3:67:27 | obj.ove ... od(num) | TestClass.overloadedMethod in global scope | overloa ... number; |
|
||||
| tst.ts:67:3:67:27 | obj.ove ... od(num) | TestClass.overloadedMethod in global scope | overloa ... rn x; } |
|
||||
| tst.ts:67:3:67:27 | obj.ove ... od(num) | TestClass.overloadedMethod in global scope | overloa ... string; |
|
||||
| tst.ts:68:3:68:27 | obj.ove ... od(str) | TestClass.overloadedMethod in global scope | overloa ... number; |
|
||||
| tst.ts:68:3:68:27 | obj.ove ... od(str) | TestClass.overloadedMethod in global scope | overloa ... rn x; } |
|
||||
| tst.ts:68:3:68:27 | obj.ove ... od(str) | TestClass.overloadedMethod in global scope | overloa ... string; |
|
||||
| tst.ts:69:3:69:36 | obj.gen ... ([num]) | TestClass.genericOverloadedMethod in global scope | generic ... T>): T; |
|
||||
| tst.ts:69:3:69:36 | obj.gen ... ([num]) | TestClass.genericOverloadedMethod in global scope | generic ... []): T; |
|
||||
| tst.ts:69:3:69:36 | obj.gen ... ([num]) | TestClass.genericOverloadedMethod in global scope | generic ... null; } |
|
||||
| tst.ts:70:3:70:39 | obj.gen ... : str}) | TestClass.genericOverloadedMethod in global scope | generic ... T>): T; |
|
||||
| tst.ts:70:3:70:39 | obj.gen ... : str}) | TestClass.genericOverloadedMethod in global scope | generic ... []): T; |
|
||||
| tst.ts:70:3:70:39 | obj.gen ... : str}) | TestClass.genericOverloadedMethod in global scope | generic ... null; } |
|
||||
@@ -1,11 +0,0 @@
|
||||
import javascript
|
||||
|
||||
string getTarget(InvokeExpr e) {
|
||||
result = e.getResolvedCallee().toString()
|
||||
or
|
||||
not exists(e.getResolvedCallee()) and
|
||||
result = "no concrete target"
|
||||
}
|
||||
|
||||
from InvokeExpr invoke
|
||||
select invoke, invoke.getResolvedCalleeName(), getTarget(invoke)
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,85 +0,0 @@
|
||||
interface Box<T> { x: T }
|
||||
|
||||
interface TestInterface {
|
||||
simpleMethod(x: string): number;
|
||||
|
||||
genericMethod<T>(x: T): T;
|
||||
|
||||
overloadedMethod(x: number): number;
|
||||
overloadedMethod(x: string): string;
|
||||
overloadedMethod(x: any): any;
|
||||
|
||||
genericOverloadedMethod<T>(x: T[]): T;
|
||||
genericOverloadedMethod<T>(x: Box<T>): T;
|
||||
genericOverloadedMethod(x: any): any;
|
||||
}
|
||||
|
||||
class TestClass {
|
||||
simpleMethod(x: string): number { return x.length }
|
||||
|
||||
genericMethod<T>(x: T): T { return x; }
|
||||
|
||||
overloadedMethod(x: number): number;
|
||||
overloadedMethod(x: string): string;
|
||||
overloadedMethod(x: any): any { return x; }
|
||||
|
||||
genericOverloadedMethod<T>(x: T[]): T;
|
||||
genericOverloadedMethod<T>(x: Box<T>): T;
|
||||
genericOverloadedMethod(x: any): any { return x.x || x[0] || null; }
|
||||
}
|
||||
|
||||
class SimpleConstructor {
|
||||
constructor(x: string) {}
|
||||
}
|
||||
|
||||
class GenericConstructor<T> {
|
||||
constructor(x: T) {}
|
||||
}
|
||||
|
||||
class OverloadedConstructor {
|
||||
constructor(x: number, y: number);
|
||||
constructor(x: string, y: string);
|
||||
constructor(x: any, y: any) {}
|
||||
}
|
||||
|
||||
class GenericOverloadedConstructor<T> {
|
||||
constructor(x: T[], y: T[]);
|
||||
constructor(x: Box<T>, y: Box<T>);
|
||||
constructor(x: any, y: any) {}
|
||||
}
|
||||
|
||||
function useTestInterface(obj: TestInterface, str: string, num: number) {
|
||||
obj.simpleMethod(str);
|
||||
obj.genericMethod(str);
|
||||
obj.genericMethod(num);
|
||||
obj.overloadedMethod(num);
|
||||
obj.overloadedMethod(str);
|
||||
obj.overloadedMethod([]);
|
||||
obj.genericOverloadedMethod([num]);
|
||||
obj.genericOverloadedMethod({x: str});
|
||||
obj.genericOverloadedMethod(num);
|
||||
}
|
||||
|
||||
function useTestClass(obj: TestClass, str: string, num: number) {
|
||||
obj.simpleMethod(str);
|
||||
obj.genericMethod(str);
|
||||
obj.genericMethod(num);
|
||||
obj.overloadedMethod(num);
|
||||
obj.overloadedMethod(str);
|
||||
obj.genericOverloadedMethod([num]);
|
||||
obj.genericOverloadedMethod({x: str});
|
||||
}
|
||||
|
||||
function testConstructors(str: string, num: number) {
|
||||
new SimpleConstructor(str);
|
||||
new GenericConstructor(str);
|
||||
new GenericConstructor(num);
|
||||
new OverloadedConstructor(num, num);
|
||||
new OverloadedConstructor(str, str);
|
||||
new GenericOverloadedConstructor([str], [str]);
|
||||
new GenericOverloadedConstructor({x: num}, {x: num});
|
||||
}
|
||||
|
||||
function testCallback<U>(callback: (x: string) => U): U {
|
||||
return callback("str");
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
test_ExprSignature
|
||||
| tst.ts:2:4:2:4 | x | number |
|
||||
| tst.ts:6:4:6:4 | x | number |
|
||||
| tst.ts:7:4:7:4 | x | string |
|
||||
| tst.ts:8:4:8:4 | x | any |
|
||||
| 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 |
|
||||
| tst.ts:29:1:29:8 | m.method | (x: number): string |
|
||||
| tst.ts:29:1:29:12 | m.method(42) | string |
|
||||
| tst.ts:29:10:29:11 | 42 | 42 |
|
||||
| tst.ts:30:1:30:1 | m | Method |
|
||||
| tst.ts:30:1:30:18 | m.overloadedMethod | (x: any): any |
|
||||
| tst.ts:30:1:30:18 | m.overloadedMethod | (x: number): number |
|
||||
| tst.ts:30:1:30:18 | m.overloadedMethod | (x: string): string |
|
||||
| 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> |
|
||||
| tst.ts:41:10:41:10 | g | Generic<string> |
|
||||
| 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 |
|
||||
| tst.ts:50:3:50:36 | method( ... ing[]); | (x: number, ...y: string[]): any |
|
||||
| tst.ts:50:10:50:10 | x | number |
|
||||
| tst.ts:50:24:50:24 | y | string[] |
|
||||
| tst.ts:51:4:51:4 | x | number |
|
||||
| tst.ts:51:18:51:18 | y | string[] |
|
||||
| tst.ts:52:7:52:7 | x | number |
|
||||
| tst.ts:52:21:52:21 | y | string[] |
|
||||
| tst.ts:54:3:54:34 | method2 ... ing[]); | (x: number, y: string[]): any |
|
||||
| tst.ts:54:11:54:11 | x | number |
|
||||
| tst.ts:54:22:54:22 | y | string[] |
|
||||
| tst.ts:55:3:55:32 | method3 ... tring); | (x: number, y: string): any |
|
||||
| tst.ts:55:11:55:11 | x | number |
|
||||
| tst.ts:55:22:55:22 | y | string |
|
||||
| tst.ts:59:3:59:25 | method( ... ing[]); | (...y: string[]): any |
|
||||
| tst.ts:59:13:59:13 | y | string[] |
|
||||
| tst.ts:60:7:60:7 | y | string[] |
|
||||
| tst.ts:61:10:61:10 | y | string[] |
|
||||
| tst.ts:63:3:63:23 | method2 ... ing[]); | (y: string[]): any |
|
||||
| tst.ts:63:11:63:11 | y | string[] |
|
||||
| tst.ts:64:3:64:21 | method3(y: string); | (y: string): any |
|
||||
| tst.ts:64:11:64:11 | y | string |
|
||||
test_TypeReferenceSig
|
||||
| Callable | function | 0 | (x: number): string |
|
||||
| Newable | constructor | 0 | new (x: number): any |
|
||||
| OnlyRestParams | constructor | 0 | new (...y: string[]): any |
|
||||
| OnlyRestParams | function | 0 | (...y: string[]): any |
|
||||
| OverloadedCallable | function | 0 | (x: number): number |
|
||||
| OverloadedCallable | function | 1 | (x: string): string |
|
||||
| OverloadedCallable | function | 2 | (x: any): any |
|
||||
| OverloadedNewable | constructor | 0 | new (x: number): OverloadedNewable |
|
||||
| OverloadedNewable | constructor | 1 | new (x: any): any |
|
||||
| WithRestParams | constructor | 0 | new (x: number, ...y: string[]): any |
|
||||
| WithRestParams | function | 0 | (x: number, ...y: string[]): 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 |
|
||||
| tst.ts:50:3:50:36 | method( ... ing[]); | (x: number, ...y: string[]): any |
|
||||
| tst.ts:51:3:51:30 | (x: num ... ing[]); | (x: number, ...y: string[]): any |
|
||||
| tst.ts:52:3:52:33 | new(x: ... ing[]); | new (x: number, ...y: string[]): any |
|
||||
| tst.ts:54:3:54:34 | method2 ... ing[]); | (x: number, y: string[]): any |
|
||||
| tst.ts:55:3:55:32 | method3 ... tring); | (x: number, y: string): any |
|
||||
| tst.ts:59:3:59:25 | method( ... ing[]); | (...y: string[]): any |
|
||||
| tst.ts:60:3:60:19 | (...y: string[]); | (...y: string[]): any |
|
||||
| tst.ts:61:3:61:22 | new(...y: string[]); | new (...y: string[]): any |
|
||||
| tst.ts:63:3:63:23 | method2 ... ing[]); | (y: string[]): any |
|
||||
| tst.ts:64:3:64:21 | method3(y: string); | (y: string): any |
|
||||
test_getRestParameterType
|
||||
| (...y: string[]): any | string |
|
||||
| (x: number, ...y: string[]): any | string |
|
||||
| new (...y: string[]): any | string |
|
||||
| new (x: number, ...y: string[]): any | string |
|
||||
test_getRestParameterArray
|
||||
| (...y: string[]): any | string[] |
|
||||
| (x: number, ...y: string[]): any | string[] |
|
||||
| new (...y: string[]): any | string[] |
|
||||
| new (x: number, ...y: string[]): any | string[] |
|
||||
test_RestSig_getParameter
|
||||
| (...y: string[]): any | 0 | y | string |
|
||||
| (x: number, ...y: string[]): any | 0 | x | number |
|
||||
| (x: number, ...y: string[]): any | 1 | y | string |
|
||||
| new (...y: string[]): any | 0 | y | string |
|
||||
| new (x: number, ...y: string[]): any | 0 | x | number |
|
||||
| new (x: number, ...y: string[]): any | 1 | y | string |
|
||||
test_RestSig_numRequiredParams
|
||||
| (...y: string[]): any | 0 |
|
||||
| (x: number, ...y: string[]): any | 1 |
|
||||
| new (...y: string[]): any | 0 |
|
||||
| new (x: number, ...y: string[]): any | 1 |
|
||||
@@ -1,41 +0,0 @@
|
||||
import javascript
|
||||
|
||||
string getASignatureOrElseType(Type t) {
|
||||
result = t.getASignature(_).toString()
|
||||
or
|
||||
not exists(t.getASignature(_)) and
|
||||
result = t.toString()
|
||||
}
|
||||
|
||||
query predicate test_ExprSignature(Expr expr, string type) {
|
||||
not exists(MethodDeclaration decl | decl.getNameExpr() = expr) and
|
||||
not exists(DotExpr dot | expr = dot.getPropertyNameExpr()) and
|
||||
type = getASignatureOrElseType(expr.getType())
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
query Type test_getRestParameterType(CallSignatureType sig) { result = sig.getRestParameterType() }
|
||||
|
||||
query Type test_getRestParameterArray(CallSignatureType sig) {
|
||||
result = sig.getRestParameterArrayType()
|
||||
}
|
||||
|
||||
query predicate test_RestSig_getParameter(CallSignatureType sig, int n, string name, Type type) {
|
||||
sig.hasRestParameter() and
|
||||
name = sig.getParameterName(n) and
|
||||
type = sig.getParameter(n)
|
||||
}
|
||||
|
||||
query int test_RestSig_numRequiredParams(CallSignatureType sig) {
|
||||
sig.hasRestParameter() and
|
||||
result = sig.getNumRequiredParameter()
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,65 +0,0 @@
|
||||
interface Callable {
|
||||
(x: number): string;
|
||||
}
|
||||
|
||||
interface OverloadedCallable {
|
||||
(x: number): number;
|
||||
(x: string): string;
|
||||
(x: any): any;
|
||||
}
|
||||
|
||||
interface Newable {
|
||||
new (x: number): any;
|
||||
}
|
||||
|
||||
interface OverloadedNewable {
|
||||
new (x: number): OverloadedNewable;
|
||||
new (x: any): any;
|
||||
}
|
||||
|
||||
interface Method {
|
||||
method(x: number): string;
|
||||
|
||||
overloadedMethod(x: number): number;
|
||||
overloadedMethod(x: string): string;
|
||||
overloadedMethod(x: any): any;
|
||||
}
|
||||
|
||||
let m: Method;
|
||||
m.method(42);
|
||||
m.overloadedMethod("foo");
|
||||
|
||||
interface FunctionTypeField {
|
||||
callback: (x: number) => string;
|
||||
}
|
||||
|
||||
interface Generic<T> {
|
||||
method(x: T): T;
|
||||
}
|
||||
|
||||
function foo(g: Generic<string>) {
|
||||
return g.method("foo");
|
||||
}
|
||||
|
||||
declare class C {
|
||||
constructor(x: string);
|
||||
constructor(x: number);
|
||||
}
|
||||
|
||||
interface WithRestParams {
|
||||
method(x: number, ...y: string[]);
|
||||
(x: number, ...y: string[]);
|
||||
new(x: number, ...y: string[]);
|
||||
|
||||
method2(x: number, y: string[]);
|
||||
method3(x: number, y: string);
|
||||
}
|
||||
|
||||
interface OnlyRestParams {
|
||||
method(...y: string[]);
|
||||
(...y: string[]);
|
||||
new(...y: string[]);
|
||||
|
||||
method2(y: string[]);
|
||||
method3(y: string);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
| client1.ts:4:9:4:19 | F.Component | Component in module 'framework1' |
|
||||
| client1.ts:5:9:5:29 | Util.De ... mponent | Util.DefaultComponent in global scope |
|
||||
| client2.ts:4:9:4:19 | F.Component | Component in module 'framework2' |
|
||||
| client2.ts:5:9:5:30 | Util2.D ... mponent | Util2.DefaultComponent in global scope |
|
||||
| client2_lazy.ts:4:9:4:19 | F.Component | Component in module 'framework2' |
|
||||
| client2_lazy.ts:5:9:5:30 | Util2.D ... mponent | Util2.DefaultComponent in global scope |
|
||||
| declare-module-client2.ts:5:8:5:8 | C | C in module 'foo' |
|
||||
| declare-module-client.ts:5:8:5:8 | C | C in module 'foo' |
|
||||
@@ -1,4 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from TypeAccess access
|
||||
select access, access.getTypeName()
|
||||
@@ -1,34 +1,6 @@
|
||||
classDeclaration
|
||||
| test.vue:3:18:5:3 | class M ... er;\\n } |
|
||||
| test_tsx.vue:3:18:5:3 | class M ... er;\\n } |
|
||||
exprType
|
||||
| htmlfile.html:4:22:4:24 | foo | () => void |
|
||||
| htmlfile.html:4:33:4:41 | "./other" | any |
|
||||
| htmlfile.html:5:17:5:22 | result | number[] |
|
||||
| htmlfile.html:5:26:5:28 | foo | () => void |
|
||||
| htmlfile.html:5:26:5:30 | foo() | void |
|
||||
| htmlfile.html:5:26:5:42 | foo() as number[] | number[] |
|
||||
| other.ts:1:8:1:16 | Component | typeof default in test.vue |
|
||||
| other.ts:1:23:1:34 | "./test.vue" | any |
|
||||
| other.ts:2:8:2:19 | ComponentTsx | typeof default in test_tsx.vue |
|
||||
| other.ts:2:26:2:41 | "./test_tsx.vue" | any |
|
||||
| other.ts:4:1:4:15 | new Component() | MyComponent |
|
||||
| other.ts:4:5:4:13 | Component | typeof default in test.vue |
|
||||
| other.ts:5:1:5:18 | new ComponentTsx() | MyComponentTsx |
|
||||
| other.ts:5:5:5:16 | ComponentTsx | typeof default in test_tsx.vue |
|
||||
| other.ts:7:17:7:19 | foo | () => void |
|
||||
| test.vue:2:15:2:19 | other | typeof other.ts |
|
||||
| test.vue:2:26:2:34 | "./other" | any |
|
||||
| test.vue:3:24:3:34 | MyComponent | MyComponent |
|
||||
| test.vue:4:7:4:7 | x | number |
|
||||
| test_tsx.vue:2:15:2:19 | other | typeof other.ts |
|
||||
| test_tsx.vue:2:26:2:34 | "./other" | any |
|
||||
| test_tsx.vue:3:24:3:37 | MyComponentTsx | MyComponentTsx |
|
||||
| test_tsx.vue:4:7:4:7 | x | number |
|
||||
symbols
|
||||
| other.ts:1:1:8:0 | <toplevel> | other.ts |
|
||||
| test.vue:2:3:6:0 | <toplevel> | test.vue |
|
||||
| test_tsx.vue:2:3:6:0 | <toplevel> | test_tsx.vue |
|
||||
importTarget
|
||||
| htmlfile.html:4:13:4:42 | import ... other"; | other.ts:1:1:8:0 | <toplevel> |
|
||||
| other.ts:1:1:1:35 | import ... t.vue"; | test.vue:2:3:6:0 | <toplevel> |
|
||||
|
||||
@@ -2,8 +2,4 @@ import javascript
|
||||
|
||||
query ClassDefinition classDeclaration() { any() }
|
||||
|
||||
query Type exprType(Expr e) { result = e.getType() }
|
||||
|
||||
query predicate symbols(Module mod, CanonicalName name) { ast_node_symbol(mod, name) }
|
||||
|
||||
query predicate importTarget(Import imprt, Module mod) { imprt.getImportedModule() = mod }
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
| After |
|
||||
| AfterX |
|
||||
| Before |
|
||||
| BeforeX |
|
||||
| Box<Expand<T[]>> |
|
||||
| Box<S> |
|
||||
| Box<S> |
|
||||
| Box<T[]> |
|
||||
| Box<number> |
|
||||
| C<T> |
|
||||
| C<T[]> |
|
||||
| Expand<T> |
|
||||
| Expand<T[]> |
|
||||
| ExpandUsingObjectLiteral<T> |
|
||||
| ExpandUsingObjectLiteral<T[]> |
|
||||
| Expansive<T> |
|
||||
| Expansive<T> |
|
||||
| Expansive<T[]> |
|
||||
| Expansive<T[]> |
|
||||
| Expansive<number> |
|
||||
| Expansive<string> |
|
||||
| ExpansiveA<S> |
|
||||
| ExpansiveA<S> |
|
||||
| ExpansiveA<T> |
|
||||
| ExpansiveA<T> |
|
||||
| ExpansiveB<S> |
|
||||
| ExpansiveB<S> |
|
||||
| ExpansiveB<T> |
|
||||
| ExpansiveB<T[]> |
|
||||
| ExpansiveB<T[]> |
|
||||
| ExpansiveB<number> |
|
||||
| ExpansiveByInference<T> |
|
||||
| ExpansiveByInference<T[]> |
|
||||
| ExpansiveC<T> |
|
||||
| ExpansiveC<T> |
|
||||
| ExpansiveC<T> |
|
||||
| ExpansiveC<T[]> |
|
||||
| ExpansiveC<T[]> |
|
||||
| ExpansiveC<number> |
|
||||
| ExpansiveConstructSignature<T> |
|
||||
| ExpansiveConstructSignature<T[]> |
|
||||
| ExpansiveD<T> |
|
||||
| ExpansiveD<T> |
|
||||
| ExpansiveD<T> |
|
||||
| ExpansiveD<T> |
|
||||
| ExpansiveFunctionType<T> |
|
||||
| ExpansiveFunctionType<T[]> |
|
||||
| ExpansiveMethod<T> |
|
||||
| ExpansiveMethod<T[]> |
|
||||
| ExpansiveParameter<T> |
|
||||
| ExpansiveParameter<T[]> |
|
||||
| ExpansiveSignature<T> |
|
||||
| ExpansiveSignature<T[]> |
|
||||
| ExpansiveSignatureTypeBound<T> |
|
||||
| ExpansiveSignatureTypeBound<T[]> |
|
||||
| ExpansiveX<T> |
|
||||
| ExpansiveX<T[]> |
|
||||
| NonExpansive<Box<number>> |
|
||||
| NonExpansive<T> |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
| T[] |
|
||||
@@ -1,4 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from TypeReference type
|
||||
select type
|
||||
@@ -1 +0,0 @@
|
||||
export let x = 1;
|
||||
@@ -1,8 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
class ExpansiveByInference<T> {
|
||||
x: T;
|
||||
y = new ExpansiveByInference([this.x]); // Inferred to be `ExpansiveByInference<T[]>`
|
||||
|
||||
constructor(arg: T) {}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
class C<T> {
|
||||
x: C<T[]>;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
interface ExpandUsingObjectLiteral<T> {
|
||||
x: {
|
||||
foo: ExpandUsingObjectLiteral<T[]>
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
interface ExpansiveSignature<T> {
|
||||
x: { (): ExpansiveSignature<T[]>; }
|
||||
}
|
||||
|
||||
interface ExpansiveParameter<T> {
|
||||
x: { (param: ExpansiveParameter<T[]>): void; }
|
||||
}
|
||||
|
||||
interface ExpansiveConstructSignature<T> {
|
||||
x: { new(): ExpansiveConstructSignature<T[]>; }
|
||||
}
|
||||
|
||||
interface ExpansiveMethod<T> {
|
||||
method(): ExpansiveMethod<T[]>;
|
||||
}
|
||||
|
||||
interface ExpansiveFunctionType<T> {
|
||||
x: () => ExpansiveFunctionType<T[]>;
|
||||
}
|
||||
|
||||
interface ExpansiveSignatureTypeBound<T> {
|
||||
foo : { <G extends ExpansiveSignatureTypeBound<T[]>>(x: G): G };
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
interface Before {
|
||||
x: Expansive<number>;
|
||||
}
|
||||
|
||||
interface Expansive<T> {
|
||||
x: Expansive<T[]>;
|
||||
}
|
||||
|
||||
interface After {
|
||||
x: Expansive<string>;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
interface ExpansiveA<T> {
|
||||
x: ExpansiveB<T[]>;
|
||||
}
|
||||
|
||||
interface ExpansiveB<S> {
|
||||
x: ExpansiveA<S>;
|
||||
}
|
||||
|
||||
|
||||
interface ExpansiveC<T> {
|
||||
x: ExpansiveD<T>;
|
||||
}
|
||||
interface ExpansiveD<T> {
|
||||
x: ExpansiveC<T[]>;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
// The expansive edge may be preceded by non-expansive edges.
|
||||
|
||||
interface ExpansiveA<T> {
|
||||
a: ExpansiveB<T>;
|
||||
b: ExpansiveB<number>;
|
||||
x: ExpansiveB<T[]>;
|
||||
}
|
||||
|
||||
interface ExpansiveB<S> {
|
||||
x: ExpansiveA<S>;
|
||||
}
|
||||
|
||||
|
||||
interface ExpansiveC<T> {
|
||||
x: ExpansiveD<T>;
|
||||
}
|
||||
|
||||
interface ExpansiveD<T> {
|
||||
a: ExpansiveC<T>;
|
||||
b: ExpansiveC<number>;
|
||||
x: ExpansiveC<T[]>;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
// Box is not expansive by itself but expansions may go "through" it.
|
||||
interface Box<S> {
|
||||
x: S;
|
||||
}
|
||||
|
||||
// A too simple algorithm might classify this as expansive.
|
||||
interface NonExpansive<T> {
|
||||
x: NonExpansive<Box<number>>;
|
||||
y: Box<T[]>;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
interface Expansive<T> {
|
||||
x: Expansive<T[]>;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
interface Expand<T> {
|
||||
x: Box<Expand<T[]>>
|
||||
}
|
||||
|
||||
// Box is not expansive by itself but expansions may go "through" it.
|
||||
interface Box<S> {
|
||||
x: S;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,15 +0,0 @@
|
||||
import * as dummy from "./dummy";
|
||||
|
||||
interface BeforeX {
|
||||
x: number;
|
||||
}
|
||||
|
||||
interface ExpansiveX<T> {
|
||||
a: BeforeX;
|
||||
x: ExpansiveX<T[]>;
|
||||
b: BeforeX;
|
||||
}
|
||||
|
||||
interface AfterX {
|
||||
x: string;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
| B in module 'mylib' | A in module 'mylib' |
|
||||
| C in module 'mylib' | B in module 'mylib' |
|
||||
| D in module 'mylib' | C in module 'mylib' |
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from TypeName tn
|
||||
where tn.hasQualifiedName("mylib", _)
|
||||
select tn, tn.getABaseTypeName()
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface A {}
|
||||
export interface B extends A {}
|
||||
export interface C extends B {}
|
||||
export interface D extends C {}
|
||||
@@ -1 +0,0 @@
|
||||
semmle-extractor-options:--exclude node_modules/**
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import { D } from "mylib";
|
||||
|
||||
export var foo: D = null;
|
||||
@@ -1,9 +0,0 @@
|
||||
import { ExternalType1, Augmentation } from "esmodule";
|
||||
|
||||
declare module "esmodule" {
|
||||
export interface Augmentation {
|
||||
x: ExternalType1;
|
||||
}
|
||||
}
|
||||
|
||||
let x: Augmentation;
|
||||
@@ -1,16 +0,0 @@
|
||||
import { ExternalType1, externalSymbol } from "esmodule";
|
||||
|
||||
function f(arg: ExternalType1) {
|
||||
let y = arg.x; // y should be ExternalType2
|
||||
}
|
||||
|
||||
let foo = 5;
|
||||
|
||||
let bar: { x: number };
|
||||
|
||||
interface InternalType {
|
||||
x: number;
|
||||
[externalSymbol]: number;
|
||||
}
|
||||
let symb = externalSymbol;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { OtherClass } from "esmodule/otherfile";
|
||||
import { UtilClass } from "esmodule/util";
|
||||
import { UtilExtraClass } from "esmodule/util/extra";
|
||||
|
||||
let c1 = new OtherClass();
|
||||
let c2 = new UtilClass();
|
||||
let c3 = new UtilExtraClass();
|
||||
@@ -1,3 +0,0 @@
|
||||
/// <reference types="legacy"/>
|
||||
|
||||
let d = new LegacyGlobals.LegacySubclass();
|
||||
@@ -1,3 +0,0 @@
|
||||
import { LegacyClass } from "legacy";
|
||||
|
||||
let c: LegacyClass;
|
||||
@@ -1,3 +0,0 @@
|
||||
/// <reference types="modern"/>
|
||||
|
||||
let d = new ModernGlobals.ModernSubclass();
|
||||
@@ -1,3 +0,0 @@
|
||||
import { ModernClass } from "modern";
|
||||
|
||||
let c: ModernClass;
|
||||
@@ -1,10 +0,0 @@
|
||||
export interface ExternalType1 {
|
||||
x: ExternalType2;
|
||||
}
|
||||
|
||||
export interface ExternalType2 {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export const externalSymbol: unique symbol;
|
||||
@@ -1 +0,0 @@
|
||||
export declare class OtherClass {}
|
||||
@@ -1 +0,0 @@
|
||||
export declare class UtilExtraClass {}
|
||||
@@ -1 +0,0 @@
|
||||
export declare class UtilClass {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user