UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

99 lines 3.99 kB
"use strict"; 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