@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
81 lines • 3.48 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cfgAnalyzeDeadCode = cfgAnalyzeDeadCode;
const logic_1 = require("../util/logic");
const semantic_cfg_guided_visitor_1 = require("./semantic-cfg-guided-visitor");
const alias_tracking_1 = require("../dataflow/eval/resolve/alias-tracking");
const log_1 = require("../util/log");
const r_function_call_1 = require("../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
const general_1 = require("../dataflow/eval/values/general");
const r_value_1 = require("../dataflow/eval/values/r-value");
class CfgConditionalDeadCodeRemoval extends semantic_cfg_guided_visitor_1.SemanticCfgGuidedVisitor {
cachedConditions = new Map();
getValue(id) {
const has = this.cachedConditions.get(id);
if (has) {
return has;
}
this.visitNode(id);
return this.cachedConditions.get(id) ?? logic_1.Ternary.Maybe;
}
unableToCalculateValue(id) {
this.cachedConditions.set(id, logic_1.Ternary.Maybe);
}
storeDefiniteValue(id, value) {
this.cachedConditions.set(id, value ? logic_1.Ternary.Always : logic_1.Ternary.Never);
}
startVisitor() {
for (const [from, targets] of this.config.controlFlow.graph.edges()) {
for (const [target, edge] of targets) {
if (edge.label === 1 /* CfgEdgeType.Cd */) {
const og = this.getValue(edge.caused);
if (og === logic_1.Ternary.Always && edge.when === 'FALSE') {
this.config.controlFlow.graph.removeEdge(from, target);
}
else if (og === logic_1.Ternary.Never && edge.when === 'TRUE') {
this.config.controlFlow.graph.removeEdge(from, target);
}
}
}
}
}
handleValuesFor(id, valueId) {
const values = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(valueId, { graph: this.config.dfg, full: true, idMap: this.config.normalizedAst.idMap }));
if (values === undefined || values.elements.length !== 1 || values.elements[0].type != 'logical' || !(0, r_value_1.isValue)(values.elements[0].value)) {
this.unableToCalculateValue(id);
return;
}
/* we should translate this to truthy later */
this.storeDefiniteValue(id, Boolean(values.elements[0].value));
}
handleWithCondition(data) {
const id = data.call.id;
if (data.condition === undefined || data.condition === r_function_call_1.EmptyArgument) {
this.unableToCalculateValue(id);
return;
}
this.handleValuesFor(id, typeof data.condition === 'object' ? data.condition.nodeId : data.condition);
}
onIfThenElseCall(data) {
this.handleWithCondition(data);
}
onWhileLoopCall(data) {
this.handleWithCondition(data);
}
}
/** Breaks unsatisfiable control dependencies */
function cfgAnalyzeDeadCode(cfg, info) {
if (!info.ast || !info.dfg) {
log_1.log.warn('cfgAnalyzeDeadCode called without ast or dfg, skipping dead code analysis');
return cfg;
}
const visitor = new CfgConditionalDeadCodeRemoval({
controlFlow: cfg,
normalizedAst: info.ast,
dfg: info.dfg,
defaultVisitingOrder: 'forward'
});
visitor.start();
return cfg;
}
//# sourceMappingURL=cfg-dead-code.js.map