mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
JS: Remove code path for TypeScript full extraction
This commit is contained in:
@@ -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;
|
||||
@@ -1065,75 +1063,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();
|
||||
}
|
||||
@@ -1246,18 +1195,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}.
|
||||
|
||||
@@ -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;
|
||||
@@ -142,53 +140,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 +192,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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user