@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
105 lines • 5.53 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FILE_PATH_VALIDITY = void 0;
const linter_format_1 = require("../linter-format");
const flowr_search_builder_1 = require("../../search/flowr-search-builder");
const range_1 = require("../../util/range");
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 happens_before_1 = require("../../control-flow/happens-before");
const linter_tags_1 = require("../linter-tags");
const search_enrichers_1 = require("../../search/search-executor/search-enrichers");
exports.FILE_PATH_VALIDITY = {
createSearch: (config) => flowr_search_builder_1.Q.fromQuery({
type: 'dependencies',
enabledCategories: ['read', 'write'],
readFunctions: config.additionalReadFunctions,
writeFunctions: config.additionalWriteFunctions
}).with(search_enrichers_1.Enrichment.CfgInformation),
processSearchResult: (elements, config, data) => {
const cfg = elements.enrichmentContent(search_enrichers_1.Enrichment.CfgInformation).cfg.graph;
const metadata = {
totalReads: 0,
totalUnknown: 0,
totalWritesBeforeAlways: 0,
totalValid: 0
};
const results = elements.enrichmentContent(search_enrichers_1.Enrichment.QueryData).queries['dependencies'];
return {
results: elements.getElements().flatMap(element => {
const matchingRead = results.read.find(r => r.nodeId === element.node.info.id);
if (!matchingRead) {
return [];
}
metadata.totalReads++;
const loc = range_1.SourceLocation.fromNode(element.node);
if (!loc) {
return [];
}
// check if we can't parse the file path statically
if (matchingRead.value === dependencies_query_format_1.Unknown) {
metadata.totalUnknown++;
if (config.includeUnknown) {
return [{
involvedId: matchingRead.nodeId,
loc,
filePath: dependencies_query_format_1.Unknown,
certainty: linter_format_1.LintingResultCertainty.Uncertain
}];
}
else {
return [];
}
}
// check if any write to the same file happens before the read, and exclude this case if so
const writesToFile = results.write.filter(r => samePath(r.value, matchingRead.value, data.analyzer.flowrConfig.solver.resolveSource?.ignoreCapitalization));
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)(data.analyzer.flowrConfig.solver.resolveSource, matchingRead.value, {
referenceChain: element.node.info.file ? [element.node.info.file] : [],
ctx: data.analyzer.inspectContext()
});
if (paths && paths.length) {
metadata.totalValid++;
return [];
}
return [{
involvedId: matchingRead.nodeId,
loc,
filePath: matchingRead.value,
certainty: writesBefore && writesBefore.length && writesBefore.every(w => w === logic_1.Ternary.Maybe) ? linter_format_1.LintingResultCertainty.Uncertain : linter_format_1.LintingResultCertainty.Certain
}];
}),
'.meta': metadata
};
},
info: {
name: 'File Path Validity',
description: 'Checks whether file paths used in read and write operations are valid and point to existing files.',
// checks all found paths for whether they're valid to ensure correctness, but doesn't handle non-constant paths so not all will be returned
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
tags: [linter_tags_1.LintingRuleTag.Robustness, linter_tags_1.LintingRuleTag.Reproducibility, linter_tags_1.LintingRuleTag.Bug],
defaultConfig: {
additionalReadFunctions: [],
additionalWriteFunctions: [],
includeUnknown: false
}
},
prettyPrint: {
[linter_format_1.LintingPrettyPrintContext.Query]: result => `Path \`${result.filePath}\` at ${range_1.SourceLocation.format(result.loc)}`,
[linter_format_1.LintingPrettyPrintContext.Full]: result => `Path \`${result.filePath}\` at ${range_1.SourceLocation.format(result.loc)} does not point to a valid file`
}
};
function samePath(a, b, ignoreCapitalization) {
if (ignoreCapitalization === true) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return a === b;
}
//# sourceMappingURL=file-path-validity.js.map