@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
93 lines • 4.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.R2_FILE_PATH_VALIDITY = void 0;
const linter_format_1 = require("../linter-format");
const flowr_search_builder_1 = require("../../search/flowr-search-builder");
const dfg_1 = require("../../util/mermaid/dfg");
const dependencies_query_format_1 = require("../../queries/catalog/dependencies-query/dependencies-query-format");
const built_in_source_1 = require("../../dataflow/internal/process/functions/call/built-in/built-in-source");
const logic_1 = require("../../util/logic");
const config_1 = require("../../config");
const retriever_1 = require("../../r-bridge/retriever");
const read_functions_1 = require("../../queries/catalog/dependencies-query/function-info/read-functions");
const write_functions_1 = require("../../queries/catalog/dependencies-query/function-info/write-functions");
const extract_cfg_1 = require("../../control-flow/extract-cfg");
const happens_before_1 = require("../../control-flow/happens-before");
exports.R2_FILE_PATH_VALIDITY = {
createSearch: (config) => flowr_search_builder_1.Q.fromQuery({
type: 'dependencies',
// we only want to check read and write functions, so we explicitly clear all others
ignoreDefaultFunctions: true,
readFunctions: read_functions_1.ReadFunctions.concat(config.additionalReadFunctions),
writeFunctions: write_functions_1.WriteFunctions.concat(config.additionalWriteFunctions)
}),
processSearchResult: (elements, config, data) => {
const cfg = (0, extract_cfg_1.extractSimpleCfg)(data.normalize).graph;
const metadata = {
totalReads: 0,
totalUnknown: 0,
totalWritesBeforeAlways: 0,
totalValid: 0
};
return {
results: elements.getElements().flatMap(element => {
const results = element.queryResult;
const matchingRead = results.readData.find(r => r.nodeId == element.node.info.id);
if (!matchingRead) {
return [];
}
metadata.totalReads++;
const range = element.node.info.fullRange;
// check if we can't parse the file path statically
if (matchingRead.source === dependencies_query_format_1.Unknown) {
metadata.totalUnknown++;
if (config.includeUnknown) {
return [{
range,
filePath: dependencies_query_format_1.Unknown,
certainty: linter_format_1.LintingCertainty.Maybe
}];
}
else {
return [];
}
}
// check if any write to the same file happens before the read, and exclude this case if so
const writesToFile = results.writtenData.filter(r => samePath(r.destination, matchingRead.source));
const writesBefore = writesToFile.map(w => (0, happens_before_1.happensBefore)(cfg, w.nodeId, element.node.info.id));
if (writesBefore.some(w => w === logic_1.Ternary.Always)) {
metadata.totalWritesBeforeAlways++;
return [];
}
// check if the file exists!
const paths = (0, built_in_source_1.findSource)(matchingRead.source, {
referenceChain: element.node.info.file ? [(0, retriever_1.requestFromInput)(`file://${element.node.info.file}`)] : []
});
if (paths && paths.length) {
metadata.totalValid++;
return [];
}
return [{
range,
filePath: matchingRead.source,
certainty: writesBefore && writesBefore.length && writesBefore.every(w => w === logic_1.Ternary.Maybe) ? linter_format_1.LintingCertainty.Maybe : linter_format_1.LintingCertainty.Definitely
}];
}),
'.meta': metadata
};
},
prettyPrint: result => `Path \`${result.filePath}\` at ${(0, dfg_1.formatRange)(result.range)}`,
defaultConfig: {
additionalReadFunctions: [],
additionalWriteFunctions: [],
includeUnknown: false
}
};
function samePath(a, b) {
if ((0, config_1.getConfig)().solver.resolveSource?.ignoreCapitalization === true) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return a === b;
}
//# sourceMappingURL=2-file-path-validity.js.map