@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
101 lines • 3.56 kB
JavaScript
;
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