@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
124 lines • 5.72 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processS3Dispatch = processS3Dispatch;
const processor_1 = require("../../../../../processor");
const info_1 = require("../../../../../info");
const known_call_handling_1 = require("../known-call-handling");
const logger_1 = require("../../../../../logger");
const linker_1 = require("../../../../linker");
const common_1 = require("../common");
const unpack_argument_1 = require("../argument/unpack-argument");
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
const r_value_1 = require("../../../../../eval/values/r-value");
const identifier_1 = require("../../../../../environments/identifier");
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
const range_1 = require("../../../../../../util/range");
const r_argument_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
/**
* Process an S3 dispatch call like `UseMethod`.
*/
function processS3Dispatch(name, args, rootId, data, config) {
if (args.length === 0 && !config.inferFromClosure) {
logger_1.dataflowLogger.warn('empty s3, skipping');
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
}
const params = {
[config.args.generic]: 'generic',
[config.args.object]: 'object',
'...': '...'
};
const argMaps = (0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params);
const generic = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('generic')?.[0]));
if (!generic && !config.inferFromClosure) {
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
}
const obj = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('object')?.[0]));
const dfObj = obj ? (0, processor_1.processDataflowFor)(obj, data) : info_1.DataflowInformation.initialize(rootId, data);
if ((0, info_1.alwaysExits)(dfObj)) {
(0, common_1.patchFunctionCall)({
nextGraph: dfObj.graph,
rootId,
name,
data,
argumentProcessResult: [dfObj],
origin: built_in_proc_name_1.BuiltInProcName.S3Dispatch
});
return dfObj;
}
if (!generic) {
(0, common_1.patchFunctionCall)({
nextGraph: dfObj.graph,
rootId,
name,
data,
argumentProcessResult: [dfObj],
origin: built_in_proc_name_1.BuiltInProcName.S3DispatchNext
});
const ingoing = dfObj.in.concat(dfObj.unknownReferences);
ingoing.push({ nodeId: rootId, name: name.content, cds: data.cds, type: identifier_1.ReferenceType.Function });
return {
hooks: dfObj.hooks,
environment: dfObj.environment,
exitPoints: dfObj.exitPoints,
graph: dfObj.graph,
entryPoint: rootId,
in: ingoing,
out: dfObj.out,
unknownReferences: []
};
}
const n = (0, alias_tracking_1.resolveIdToValue)(generic.info.id, { environment: data.environment, resolve: data.ctx.config.solver.variables, idMap: data.completeAst.idMap, full: true, ctx: data.ctx });
const accessedIdentifiers = [];
if (n.type === 'set') {
for (const elem of n.elements) {
if (elem.type === 'string' && (0, r_value_1.isValue)(elem.value)) {
accessedIdentifiers.push(elem.value.str);
}
}
}
if (accessedIdentifiers.length === 0) {
logger_1.dataflowLogger.warn('s3 dispatch with non-resolvable generic, skipping');
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
}
const dfGeneric = (0, processor_1.processDataflowFor)(generic, data);
const symbol = {
type: type_1.RType.Symbol,
info: generic.info,
content: accessedIdentifiers[0],
lexeme: accessedIdentifiers[0],
location: generic.location ?? range_1.SourceRange.invalid()
};
(0, common_1.patchFunctionCall)({
nextGraph: dfGeneric.graph,
rootId: generic.info.id,
name: symbol,
data,
argumentProcessResult: [], // arguments will be attached by the accompanying enveloping function definition
origin: built_in_proc_name_1.BuiltInProcName.S3Dispatch
});
(0, common_1.patchFunctionCall)({
nextGraph: dfGeneric.graph,
rootId,
name,
data,
argumentProcessResult: [dfGeneric, dfObj],
origin: built_in_proc_name_1.BuiltInProcName.Function
});
const ingoing = dfObj.in.concat(dfGeneric.in, dfObj.unknownReferences, dfGeneric.unknownReferences);
ingoing.push({ nodeId: rootId, name: name.content, cds: data.cds, type: identifier_1.ReferenceType.Function });
for (const id of accessedIdentifiers) {
ingoing.push({ nodeId: generic.info.id, name: id, cds: data.cds, type: identifier_1.ReferenceType.S3MethodPrefix });
}
return {
hooks: dfGeneric.hooks.concat(dfObj?.hooks),
environment: dfGeneric.environment,
exitPoints: dfObj.exitPoints.concat(dfGeneric.exitPoints),
graph: dfObj.graph.mergeWith(dfGeneric.graph),
entryPoint: rootId,
in: ingoing,
out: dfGeneric.out.concat(dfObj.out),
unknownReferences: []
};
}
//# sourceMappingURL=built-in-s-three-dispatch.js.map