UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

144 lines 7.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeDependenciesQuery = executeDependenciesQuery; const query_1 = require("../../query"); const dependencies_query_format_1 = require("./dependencies-query-format"); const graph_1 = require("../../../dataflow/graph/graph"); const log_1 = require("../../../util/log"); const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type"); const retriever_1 = require("../../../r-bridge/retriever"); const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call"); const visitor_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/visitor"); const assert_1 = require("../../../util/assert"); const objects_1 = require("../../../util/objects"); const SupportedVertexTypes = [type_1.RType.String, type_1.RType.Logical, type_1.RType.Number]; const Unknown = 'unknown'; function executeDependenciesQuery(data, queries) { if (queries.length !== 1) { log_1.log.warn('Dependencies query expects only up to one query, but got ', queries.length, 'only using the first query'); } const now = Date.now(); const [query] = queries; const ignoreDefault = query.ignoreDefaultFunctions ?? false; const libraryFunctions = getFunctionsToCheck(query.libraryFunctions, ignoreDefault, dependencies_query_format_1.LibraryFunctions); const sourceFunctions = getFunctionsToCheck(query.sourceFunctions, ignoreDefault, dependencies_query_format_1.SourceFunctions); const readFunctions = getFunctionsToCheck(query.readFunctions, ignoreDefault, dependencies_query_format_1.ReadFunctions); const writeFunctions = getFunctionsToCheck(query.writeFunctions, ignoreDefault, dependencies_query_format_1.WriteFunctions); const numberOfFunctions = libraryFunctions.length + sourceFunctions.length + readFunctions.length + writeFunctions.length; const results = numberOfFunctions === 0 ? { kinds: {}, '.meta': { timing: 0 } } : (0, query_1.executeQueriesOfSameType)(data, ...makeCallContextQuery(libraryFunctions, 'library'), ...makeCallContextQuery(sourceFunctions, 'source'), ...makeCallContextQuery(readFunctions, 'read'), ...makeCallContextQuery(writeFunctions, 'write')); const libraries = getResults(data, results, 'library', libraryFunctions, (id, vertex, argument) => ({ nodeId: id, functionName: vertex.name, libraryName: argument ?? Unknown }), [type_1.RType.Symbol]); if (!ignoreDefault) { /* for libraries, we have to additionally track all uses of `::` and `:::`, for this we currently simply traverse all uses */ (0, visitor_1.visitAst)(data.ast.ast, n => { if (n.type === type_1.RType.Symbol && n.namespace) { /* we should improve the identification of ':::' */ libraries.push({ nodeId: n.info.id, functionName: (n.info.fullLexeme ?? n.lexeme).includes(':::') ? ':::' : '::', libraryName: n.namespace }); } }); } const sourcedFiles = getResults(data, results, 'source', sourceFunctions, (id, vertex, argument, linkedIds) => ({ nodeId: id, functionName: vertex.name, file: argument ?? Unknown, linkedIds: (linkedIds?.length ?? 0) > 0 ? linkedIds : undefined })); const readData = getResults(data, results, 'read', readFunctions, (id, vertex, argument, linkedIds) => ({ nodeId: id, functionName: vertex.name, source: argument ?? Unknown, linkedIds: (linkedIds?.length ?? 0) > 0 ? linkedIds : undefined })); const writtenData = getResults(data, results, 'write', writeFunctions, (id, vertex, argument, linkedIds) => ({ nodeId: id, functionName: vertex.name, // write functions that don't have argIndex are assumed to write to stdout destination: argument ?? ((linkedIds?.length ?? 0) > 0 ? Unknown : 'stdout'), linkedIds: (linkedIds?.length ?? 0) > 0 ? linkedIds : undefined })); return { '.meta': { timing: Date.now() - now }, libraries, sourcedFiles, readData, writtenData }; } function makeCallContextQuery(functions, kind) { return functions.map(f => ({ type: 'call-context', callName: f.name, includeAliases: false, callNameExact: true, subkind: f.name, linkTo: f.linkTo ? { type: 'link-to-last-call', callName: f.linkTo } : undefined, kind })); } function getResults(data, results, kind, functions, makeInfo, additionalAllowedTypes) { return Object.entries(results?.kinds[kind]?.subkinds ?? {}).flatMap(([name, results]) => results.flatMap(({ id, linkedIds }) => { const vertex = data.dataflow.graph.getVertex(id); const info = functions.find(f => f.name === name); let index = info.argIdx; if (info.argName) { const arg = vertex?.args.findIndex(arg => arg !== r_function_call_1.EmptyArgument && arg.name === info.argName); if (arg >= 0) { index = arg; } } const args = index !== undefined ? getArgumentValue(data, vertex, index, additionalAllowedTypes) : undefined; if (!args) { return (0, objects_1.compactRecord)(makeInfo(id, vertex, undefined, linkedIds)); } return args.flatMap(a => (0, objects_1.compactRecord)(makeInfo(id, vertex, a, linkedIds))); })).filter(assert_1.isNotUndefined) ?? []; } function getArgumentValue({ dataflow: { graph } }, vertex, argumentIndex, additionalAllowedTypes) { if (vertex) { if (argumentIndex === 'unnamed') { // return all unnamed arguments const references = vertex.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.getReferenceOfArgument); return references.map(ref => { if (!ref) { return undefined; } let valueNode = graph.idMap?.get(ref); if (valueNode?.type === type_1.RType.Argument) { valueNode = valueNode.value; } if (valueNode) { const allowedTypes = [...SupportedVertexTypes, ...additionalAllowedTypes ?? []]; return allowedTypes.includes(valueNode.type) ? (0, retriever_1.removeRQuotes)(valueNode.lexeme) : Unknown; } }); } if (vertex.args.length > argumentIndex) { const arg = (0, graph_1.getReferenceOfArgument)(vertex.args[argumentIndex]); if (arg) { let valueNode = graph.idMap?.get(arg); if (valueNode?.type === type_1.RType.Argument) { valueNode = valueNode.value; } if (valueNode) { const allowedTypes = [...SupportedVertexTypes, ...additionalAllowedTypes ?? []]; return [allowedTypes.includes(valueNode.type) ? (0, retriever_1.removeRQuotes)(valueNode.lexeme) : Unknown]; } } } } return undefined; } function getFunctionsToCheck(customFunctions, ignoreDefaultFunctions, defaultFunctions) { const functions = ignoreDefaultFunctions ? [] : [...defaultFunctions]; if (customFunctions) { functions.push(...customFunctions); } return functions; } //# sourceMappingURL=dependencies-query-executor.js.map