@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
168 lines • 9.95 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.postProcess = postProcess;
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const defined_functions_1 = require("./defined-functions");
const post_processing_1 = require("../../post-processing");
const summarizer_1 = require("../../../../util/summarizer");
const files_1 = require("../../../../util/files");
const time_1 = require("../../../../util/text/time");
const arrays_1 = require("../../../../util/collections/arrays");
function getFnDefCsv(idx, info) {
return `${JSON.stringify(idx)},${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.total.flat()))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.parameters.flat()))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.length.lines.flat()))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.length.chars.flat()))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.length.nonWhitespaceChars.flat()))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)([0]))}` /* this has to be changed once we have explicit returns again */
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)([0]))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.returns.onlyExplicit.flat()))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.returns.onlyImplicit.flat()))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.exitPointsLinePercentageInDef.flat(2)))}`
+ `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.linePercentageInFile.flat()))}\n`;
}
function addToList(data, count, filepath, config) {
data.count.push(count);
if (count > 0) {
(0, post_processing_1.recordFilePath)(data, filepath, config);
}
}
function retrievePerFileDefinitionInformation(featureRoot, info, config, outputPath) {
/**
* maps fn-name (including namespace) to several definition information
* we use tuples to reduce the memory!
*/
const definitionsPerFile = [];
const mergedSuperDefinitions = emptyFunctionDefinitionSummary();
// we collect only `all-calls`
(0, files_1.readLineByLineSync)(path_1.default.join(featureRoot, `${defined_functions_1.AllDefinitionsFileBase}.txt`), (line, lineNumber) => processNextLine(definitionsPerFile, lineNumber, info, JSON.parse(String(line))));
console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions process completed, start to write out function info`);
const fnOutStream = fs_1.default.createWriteStream(path_1.default.join(outputPath, 'function-definitions.csv'));
const prefixes = ['total', 'params', 'length-lines', 'length-chars', 'length-non-ws-chars', 'return-explicit', 'return-implicit', 'return-only-explicit', 'return-only-implicit', 'exit-points-line-crac', 'def-line-frac'];
const others = prefixes.flatMap(summarizer_1.summarizedMeasurement2CsvHeader).join(',');
fnOutStream.write(`counter,${others}\n`);
for (const [idx, info] of definitionsPerFile.entries()) {
fnOutStream.write(getFnDefCsv(idx, info));
mergedSuperDefinitions.total.push(...info.total);
mergedSuperDefinitions.parameters.push(...info.parameters);
mergedSuperDefinitions.length.lines.push(...info.length.lines);
mergedSuperDefinitions.length.chars.push(...info.length.chars);
mergedSuperDefinitions.length.nonWhitespaceChars.push(...info.length.nonWhitespaceChars);
mergedSuperDefinitions.returns.onlyExplicit.push(...info.returns.onlyExplicit);
mergedSuperDefinitions.returns.onlyImplicit.push(...info.returns.onlyImplicit);
mergedSuperDefinitions.exitPointsLinePercentageInDef.push(...info.exitPointsLinePercentageInDef);
mergedSuperDefinitions.linePercentageInFile.push(...info.linePercentageInFile);
mergedSuperDefinitions.callsites.push(...info.callsites);
}
// now, write the ultimate summary at the end of the file
fnOutStream.write(getFnDefCsv('all', mergedSuperDefinitions));
fnOutStream.close();
}
function retrieveMetaInformation(info, config, outputPath) {
const data = {
total: (0, post_processing_1.emptySummarizedWithProject)(),
lambdasOnly: (0, post_processing_1.emptySummarizedWithProject)(),
assignedFunctions: (0, post_processing_1.emptySummarizedWithProject)(),
nestedFunctions: (0, post_processing_1.emptySummarizedWithProject)(),
recursive: (0, post_processing_1.emptySummarizedWithProject)(),
deepestNesting: (0, post_processing_1.emptySummarizedWithProject)()
};
for (const [filepath, meta] of info.entries()) {
const us = meta.definedFunctions;
addToList(data.total, us.total, filepath, config);
addToList(data.lambdasOnly, us.lambdasOnly, filepath, config);
addToList(data.assignedFunctions, us.assignedFunctions, filepath, config);
addToList(data.nestedFunctions, us.nestedFunctions, filepath, config);
addToList(data.recursive, us.recursive, filepath, config);
addToList(data.deepestNesting, us.deepestNesting, filepath, config);
}
console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions metadata reading completed, summarizing and writing to file`);
const out = fs_1.default.createWriteStream(path_1.default.join(outputPath, 'function-definitions-meta.csv'));
out.write(`kind,unique-projects,unique-files,${(0, summarizer_1.summarizedMeasurement2CsvHeader)()}\n`);
for (const [key, val] of Object.entries(data)) {
const data = val;
out.write(`${JSON.stringify(key)},${data.uniqueProjects.size},${data.uniqueFiles.size},${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(data.count))}\n`);
}
out.close();
}
function retrieveAssignedFunctionNames(featureRoot, config, outputPath) {
const varNames = new Map();
(0, files_1.readLineByLineSync)(path_1.default.join(featureRoot, 'assignedFunctions.txt'), line => {
const parsed = JSON.parse(String(line));
const [hits, context] = parsed;
const countsForFile = (0, arrays_1.array2bag)(hits);
for (const [name, count] of countsForFile.entries()) {
let get = varNames.get(name);
if (!get) {
get = (0, post_processing_1.emptySummarizedWithProject)();
varNames.set(name, get);
}
addToList(get, count, context ?? '', config);
}
});
const varNamesOut = fs_1.default.createWriteStream(path_1.default.join(outputPath, 'function-definitions-var-names.csv'));
varNamesOut.write(`name,unique-projects,unique-files,${(0, summarizer_1.summarizedMeasurement2CsvHeader)()}\n`);
for (const [key, val] of varNames.entries()) {
varNamesOut.write(`${JSON.stringify(key)},${val.uniqueProjects.size},${val.uniqueFiles.size},${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(val.count))}\n`);
}
varNamesOut.close();
}
/**
* Note: the summary does not contain a 0, for each function that `is _not_ called` by a file. Hence, the minimum can not be 0 (division for mean etc. will still be performed on total file count)
*/
function postProcess(featureRoot, info, outputPath, config) {
// each number[][] contains a 'number[]' per file
retrievePerFileDefinitionInformation(featureRoot, info, config, outputPath);
console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions reading completed, summarizing info...`);
retrieveMetaInformation(info, config, outputPath);
retrieveAssignedFunctionNames(featureRoot, config, outputPath);
}
function emptyFunctionDefinitionSummary() {
return {
total: [],
parameters: [],
length: {
lines: [],
chars: [],
nonWhitespaceChars: []
},
returns: {
explicit: [],
implicit: [],
onlyExplicit: [],
onlyImplicit: []
},
exitPointsLinePercentageInDef: [],
linePercentageInFile: [],
callsites: []
};
}
function processNextLine(data, lineNumber, info, line) {
if (lineNumber % 2_500 === 0) {
console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions processed ${lineNumber} lines`);
}
const [hits, context] = line;
const forFile = emptyFunctionDefinitionSummary();
for (const { location, length, returns, numberOfParameters, callsites } of hits) {
const stats = info.get(context ?? '')?.stats.lines[0].length;
// we retrieve the first component fo the path
forFile.total.push(1);
forFile.parameters.push(numberOfParameters);
forFile.length.lines.push(length.lines);
forFile.length.chars.push(length.characters);
forFile.length.nonWhitespaceChars.push(length.nonWhitespaceCharacters);
forFile.exitPointsLinePercentageInDef.push(returns.map(r => r.location[0]).map(l => l / length.lines));
forFile.callsites.push(callsites.length);
if (stats) {
forFile.linePercentageInFile.push(location[0] / stats);
}
}
// push all of that to main :D
forFile.total = [forFile.total.length];
data.push(forFile);
}
//# sourceMappingURL=post-process.js.map