UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

101 lines 3.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeDoesCallQuery = executeDoesCallQuery; const log_1 = require("../../../util/log"); const node_id_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/node-id"); const identifier_1 = require("../../../dataflow/environments/identifier"); const parse_1 = require("../../../slicing/criterion/parse"); /** * Execute does call queries on the given analyzer. */ async function executeDoesCallQuery({ analyzer }, queries) { const start = Date.now(); const cg = await analyzer.callGraph(); const idMap = (await analyzer.normalize()).idMap; const results = {}; for (const query of queries) { const id = query.queryId ?? JSON.stringify(query); if (id in results) { log_1.log.warn(`Duplicate query id '${id}' in does-call queries, SKIP.`); continue; } const nodeId = parse_1.SlicingCriterion.tryParse(query.call, idMap); if (!nodeId) { results[id] = false; continue; } const c = makeCallMatcher(query.calls); results[id] = findCallersMatchingConstraints(cg, nodeId, c); } return { '.meta': { timing: Date.now() - start }, results }; } function makeCallMatcher(constraint) { switch (constraint.type) { case 'calls-id': return (vtx) => vtx.id === constraint.id; case 'name': if (constraint.nameExact) { return (vtx) => vtx.name === constraint.name; } else { const regex = new RegExp(constraint.name); return (vtx) => 'name' in vtx && vtx.name ? regex.test(identifier_1.Identifier.getName(vtx.name)) : false; } case 'and': { let matchersAndRemain = constraint.calls.map(makeCallMatcher); return (vtx, cg) => { const matchersToRemove = []; for (const matcher of matchersAndRemain) { if (matcher(vtx, cg)) { matchersToRemove.push(matcher); } } matchersAndRemain = matchersAndRemain.filter(m => !matchersToRemove.includes(m)); return matchersAndRemain.length === 0; }; } case 'or': { const matchersOr = constraint.calls.map(makeCallMatcher); return (vtx, cg) => matchersOr.some(m => m(vtx, cg)); } default: { throw new Error(`Unhandled constraint type ${JSON.stringify(constraint)}`); } } } function findCallersMatchingConstraints(cg, start, constraints) { const visited = new Set(); const toVisit = [start]; while (toVisit.length > 0) { const cur = toVisit.pop(); if (visited.has(cur)) { continue; } visited.add(cur); if (node_id_1.NodeId.isBuiltIn(cur)) { const name = node_id_1.NodeId.fromBuiltIn(cur); if (constraints({ id: cur, name }, cg)) { return { call: start }; } continue; } const vtx = cg.getVertex(cur); if (!vtx) { continue; } // check if matches if (constraints(vtx, cg)) { return { call: start }; } for (const out of cg.outgoingEdges(cur) ?? []) { toVisit.push(out[0]); } } return false; } //# sourceMappingURL=does-call-query-executor.js.map