@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
99 lines • 3.99 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.usedFunctions = exports.AllCallsFileBase = void 0;
const common_syntax_probability_1 = require("../../common-syntax-probability");
const post_process_1 = require("./post-process");
const unpack_argument_1 = require("../../../../dataflow/internal/process/functions/call/argument/unpack-argument");
const type_1 = require("../../../../r-bridge/lang-4.x/ast/model/type");
const statistics_file_1 = require("../../../output/statistics-file");
const edge_1 = require("../../../../dataflow/graph/edge");
const identifier_1 = require("../../../../dataflow/environments/identifier");
const range_1 = require("../../../../util/range");
const r_project_1 = require("../../../../r-bridge/lang-4.x/ast/model/nodes/r-project");
const initialFunctionUsageInfo = {
allFunctionCalls: 0,
args: {
// only if called without arguments
0: 0n,
1: (0, common_syntax_probability_1.emptyCommonSyntaxTypeCounts)()
},
/** `a(b(), c(3, d()))` has 3 (`b`, `c`, `d`) */
nestedFunctionCalls: 0,
deepestNesting: 0,
unnamedCalls: 0
};
exports.AllCallsFileBase = 'all-calls';
exports.usedFunctions = {
name: 'Used Functions',
description: 'All functions called, split into various sub-categories',
process(existing, input) {
visitCalls(existing, input);
return existing;
},
initialValue: initialFunctionUsageInfo,
postProcess: post_process_1.postProcess
};
function classifyArguments(args, existing) {
if (args.length === 0) {
existing[0]++;
return;
}
let i = 1;
for (const arg of args) {
if (arg === undefined) {
existing[0]++;
continue;
}
existing[i] = (0, common_syntax_probability_1.updateCommonSyntaxTypeCounts)(existing[i] ?? (0, common_syntax_probability_1.emptyCommonSyntaxTypeCounts)(), arg);
i++;
}
}
function visitCalls(info, input) {
const calls = [];
const allCalls = [];
r_project_1.RProject.visitAst(input.normalizedRAst.ast, node => {
if (node.type !== type_1.RType.FunctionCall) {
return;
}
if (calls.length > 0) {
info.nestedFunctionCalls++;
(0, statistics_file_1.appendStatisticsFile)(exports.usedFunctions.name, 'nested-calls', [node.lexeme], input.filepath);
info.deepestNesting = Math.max(info.deepestNesting, calls.length);
}
const dataflowNode = input.dataflow.graph.get(node.info.id);
let hasCallsEdge = false;
if (dataflowNode) {
hasCallsEdge = dataflowNode[1].values().some(e => edge_1.DfEdge.includesType(e, edge_1.EdgeType.Calls));
}
if (!node.named) {
info.unnamedCalls++;
(0, statistics_file_1.appendStatisticsFile)(exports.usedFunctions.name, 'unnamed-calls', [node.lexeme], input.filepath);
allCalls.push([
undefined,
range_1.SourceRange.getStart(node.location),
node.arguments.length,
'',
hasCallsEdge ? 1 : 0
]);
}
else {
allCalls.push([
node.functionName.lexeme,
range_1.SourceRange.getStart(node.location),
node.arguments.length,
identifier_1.Identifier.getNamespace(node.functionName.content) ?? '',
hasCallsEdge ? 1 : 0
]);
}
classifyArguments(node.arguments.map(e => (0, unpack_argument_1.unpackNonameArg)(e)), info.args);
calls.push(node);
}, node => {
// drop again :D
if (node.type === type_1.RType.FunctionCall) {
calls.pop();
}
});
info.allFunctionCalls += allCalls.length;
(0, statistics_file_1.appendStatisticsFile)(exports.usedFunctions.name, exports.AllCallsFileBase, allCalls, input.filepath);
}
//# sourceMappingURL=used-functions.js.map