UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

158 lines 7.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Enrichments = exports.Enrichment = void 0; exports.enrichmentContent = enrichmentContent; exports.enrichElement = enrichElement; const objects_1 = require("../../util/objects"); const vertex_1 = require("../../dataflow/graph/vertex"); const assert_1 = require("../../util/assert"); const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id"); const cfg_simplification_1 = require("../../control-flow/cfg-simplification"); const call_context_query_executor_1 = require("../../queries/catalog/call-context-query/call-context-query-executor"); const cfg_kind_1 = require("../../project/cfg-kind"); const identify_link_to_last_call_relation_1 = require("../../queries/catalog/call-context-query/identify-link-to-last-call-relation"); const identifier_1 = require("../../dataflow/environments/identifier"); const df_helper_1 = require("../../dataflow/graph/df-helper"); /** * An enumeration that stores the names of the available enrichments that can be applied to a set of search elements. * See {@link FlowrSearchBuilder.with} for more information on how to apply enrichments. */ var Enrichment; (function (Enrichment) { Enrichment["CallTargets"] = "call-targets"; Enrichment["LastCall"] = "last-call"; Enrichment["CfgInformation"] = "cfg-information"; Enrichment["QueryData"] = "query-data"; })(Enrichment || (exports.Enrichment = Enrichment = {})); /** * The registry of enrichments that are currently supported by the search. * See {@link FlowrSearchBuilder.with} for more information on how to apply enrichments. */ exports.Enrichments = { [Enrichment.CallTargets]: { enrichElement: async (e, _s, analyzer, args, prev) => { // we don't resolve aliases here yet! const content = { targets: [] }; const df = await analyzer.dataflow(); const n = await analyzer.normalize(); const callVertex = df.graph.getVertex(e.node.info.id); if (callVertex?.tag === vertex_1.VertexType.FunctionCall) { const origins = df_helper_1.Dataflow.origin(df.graph, callVertex.id); if (!origins || origins.length === 0) { content.targets = [(0, node_id_1.recoverName)(callVertex.id, n.idMap)]; } else { // find call targets in user code (which have ids!) content.targets = content.targets.concat(origins.map(o => { switch (o.type) { case 2 /* OriginType.FunctionCallOrigin */: return { node: n.idMap.get(o.id), }; case 3 /* OriginType.BuiltInFunctionOrigin */: return identifier_1.Identifier.toString(o.fn.name); default: return undefined; } }).filter(assert_1.isNotUndefined)); if (content.targets.length === 0) { content.targets = [(0, node_id_1.recoverName)(callVertex.id, n.idMap)]; } } } // if there is a call target that is not built-in (ie a custom function), we don't want to include it here if (args?.onlyBuiltin && content.targets.some(t => typeof t !== 'string')) { content.targets = []; } if (prev) { content.targets.push(...prev.targets); } return content; }, // as built-in call target enrichments are not nodes, we don't return them as part of the mapper! mapper: ({ targets }) => targets.map(t => t).filter(t => t.node !== undefined) }, [Enrichment.LastCall]: { enrichElement: async (e, _s, analyzer, args, prev) => { (0, assert_1.guard)(args && args.length, `${Enrichment.LastCall} enrichment requires at least one argument`); const content = prev ?? { linkedIds: [] }; const df = (await analyzer.dataflow()).graph; const vertex = df.getVertex(e.node.info.id); if (vertex?.tag === vertex_1.VertexType.FunctionCall) { const n = await analyzer.normalize(); const cfg = (await analyzer.controlflow(undefined, cfg_kind_1.CfgKind.Quick)).graph; for (const arg of args) { const lastCalls = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelationSync)(vertex.id, cfg, df, { ...arg, callName: (0, call_context_query_executor_1.promoteCallName)(arg.callName), type: 'link-to-last-call', }); for (const lastCall of lastCalls) { content.linkedIds.push({ node: n.idMap.get(lastCall) }); } } } return content; }, mapper: ({ linkedIds }) => linkedIds }, [Enrichment.CfgInformation]: { enrichElement: (e, search, _data, _args, prev) => { const searchContent = search.enrichmentContent(Enrichment.CfgInformation); return { ...prev, isRoot: searchContent.cfg.graph.rootIds().has(e.node.info.id), isReachable: searchContent.reachableNodes?.has(e.node.info.id) }; }, enrichSearch: async (_search, data, args, prev) => { args = { forceRefresh: false, checkReachable: false, simplificationPasses: cfg_simplification_1.DefaultCfgSimplificationOrder, ...args }; // short-circuit if we already have a cfg stored if (!args.forceRefresh && prev?.simpleCfg) { return prev; } const content = { ...prev, cfg: await data.controlflow(args.simplificationPasses, cfg_kind_1.CfgKind.WithDataflow), }; if (args.checkReachable) { content.reachableNodes = (0, cfg_simplification_1.cfgFindAllReachable)(content.cfg); } return content; } }, [Enrichment.QueryData]: { // the query data enrichment is just a "pass-through" that passes the query data to the underlying search enrichElement: (_e, _search, _data, args, prev) => (args ?? prev), enrichSearch: (_search, _data, args, prev) => (0, objects_1.deepMergeObject)(prev, args) } }; /** * Returns the content of the given enrichment type from a {@link FlowrSearchElement}. * If the search element is not enriched with the given enrichment, `undefined` is returned. * @param e - The search element whose enrichment content should be retrieved. * @param enrichment - The enrichment content, if present, else `undefined`. */ function enrichmentContent(e, enrichment) { return e?.enrichments?.[enrichment]; } /** * Enriches the given search element with the given enrichment type, using the provided analysis data. */ async function enrichElement(e, s, analyzer, enrichment, args) { const enrichmentData = exports.Enrichments[enrichment]; const prev = e?.enrichments; return { ...e, enrichments: { ...prev ?? {}, [enrichment]: await enrichmentData.enrichElement?.(e, s, analyzer, args, prev?.[enrichment]) } }; } //# sourceMappingURL=search-enrichers.js.map