@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
140 lines • 5.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.usedPackages = exports.initialUsedPackageInfos = void 0;
const xpath = __importStar(require("xpath-ts2"));
const post_process_1 = require("./post-process");
const statistics_file_1 = require("../../../output/statistics-file");
exports.initialUsedPackageInfos = {
library: 0,
require: 0,
loadNamespace: 0,
requireNamespace: 0,
attachNamespace: 0,
withinApply: 0,
'::': 0,
':::': 0,
/** just contains all occurrences where it is impossible to statically determine which package is loaded */
'<loadedByVariable>': 0
};
// based on the extraction routine of lintr search for function calls which are not character-loads (we can not trace those...)
const withinApply = xpath.parse(`
//SYMBOL_FUNCTION_CALL[contains(.,"apply")]/../..
//SYMBOL[text()='require' or text()='library' or text()='loadNamespace' or text()='requireNamespace' or text()='attachNamespace']
/../..
`);
// horrible ways I found exploratively like loading within `sapply`
const libraryOrRequire = xpath.parse(`
//SYMBOL_FUNCTION_CALL[text() = $variable]
/parent::expr
/parent::expr[
expr[2][STR_CONST]
or (
expr[2][SYMBOL]
and not(
SYMBOL_SUB[text() = 'character.only']
/following-sibling::expr[1]
/NUM_CONST[text() = 'TRUE' or text() = 'T']
)
)
]/OP-LEFT-PAREN[1]/following-sibling::expr[1][SYMBOL | STR_CONST]
`);
// there is no except in xpath 1.0?
const packageLoadedWithVariableLoadRequire = xpath.parse(`
//SYMBOL_FUNCTION_CALL[text() = 'library' or text() = 'require']
/parent::expr
/parent::expr[
expr[2][SYMBOL]
and (
SYMBOL_SUB[text() = 'character.only']
/following-sibling::expr[1]
/NUM_CONST[text() = 'TRUE' or text() = 'T']
)
]/OP-LEFT-PAREN[1]/following-sibling::expr[1][SYMBOL | STR_CONST]
`);
const packageLoadedWithVariableNamespaces = xpath.parse(`
//SYMBOL_FUNCTION_CALL[text() = 'loadNamespace' or text() = 'requireNamespace' or text() = 'attachNamespace']/../following-sibling::expr[1][SYMBOL]
`);
const queryForFunctionCall = xpath.parse(`
//SYMBOL_FUNCTION_CALL[text() = $variable]/../following-sibling::expr[1][STR_CONST]
`);
// otherwise, the parser seems to fail
const queryForNsAccess = xpath.parse(`
//NS_GET[text() = $variable]/../SYMBOL_PACKAGE[1]
|
//NS_GET_INT[text() = $variable]/../SYMBOL_PACKAGE[1]
`);
const queries = [
{
types: ['library', 'require'],
query: libraryOrRequire
},
{
types: ['loadNamespace', 'requireNamespace', 'attachNamespace'],
query: queryForFunctionCall
},
{
types: ['::', ':::'],
query: queryForNsAccess
}
];
exports.usedPackages = {
name: 'Used Packages',
description: 'All the packages used in the code',
process(existing, input) {
// we will unify in the end, so we can count, group etc. but we do not re-count multiple packages in the same file
for (const q of queries) {
for (const fn of q.types) {
const nodes = q.query.select({ node: input.parsedRAst, variables: { variable: fn } });
existing[fn] += nodes.length;
(0, statistics_file_1.appendStatisticsFile)(this.name, fn, nodes, input.filepath, true);
}
}
const nodesForVariableLoad = [
...packageLoadedWithVariableLoadRequire.select({ node: input.parsedRAst }),
...packageLoadedWithVariableNamespaces.select({ node: input.parsedRAst })
];
existing['<loadedByVariable>'] += nodesForVariableLoad.length;
// should not be unique as variables may be repeated, and we have no idea
(0, statistics_file_1.appendStatisticsFile)(this.name, '<loadedByVariable>', nodesForVariableLoad, input.filepath);
const withinApplyNodes = withinApply.select({ node: input.parsedRAst });
existing.withinApply += withinApplyNodes.length;
(0, statistics_file_1.appendStatisticsFile)(this.name, 'withinApply', withinApplyNodes, input.filepath);
return existing;
},
initialValue: exports.initialUsedPackageInfos,
postProcess: post_process_1.postProcess
};
//# sourceMappingURL=used-packages.js.map