UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

116 lines (115 loc) 6.8 kB
import { type CfgExpressionVertex, type CfgStatementVertex, CfgVertex, type ControlFlowInformation } from '../control-flow/control-flow-graph'; import { SemanticCfgGuidedVisitor, type SemanticCfgGuidedVisitorConfiguration } from '../control-flow/semantic-cfg-guided-visitor'; import { BuiltInProcName } from '../dataflow/environments/built-in-proc-name'; import type { DataflowGraph } from '../dataflow/graph/graph'; import { type DataflowGraphVertexFunctionCall, type DataflowGraphVertexVariableDefinition } from '../dataflow/graph/vertex'; import { type NoInfo, RNode } from '../r-bridge/lang-4.x/ast/model/model'; import type { NormalizedAst, ParentInformation } from '../r-bridge/lang-4.x/ast/model/processing/decorate'; import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id'; import type { AnyStateDomain, ValueDomain } from './domains/state-domain-like'; export type AbsintVisitorConfiguration = Omit<SemanticCfgGuidedVisitorConfiguration<NoInfo, ControlFlowInformation, NormalizedAst>, 'defaultVisitingOrder' | 'defaultVisitingType'>; /** * A control flow graph visitor to perform abstract interpretation. * * However, the visitor does not yet support inter-procedural abstract interpretation and abstract condition semantics. */ export declare abstract class AbstractInterpretationVisitor<StateDomain extends AnyStateDomain, Config extends AbsintVisitorConfiguration = AbsintVisitorConfiguration> extends SemanticCfgGuidedVisitor<NoInfo, ControlFlowInformation, NormalizedAst, DataflowGraph, Config & { defaultVisitingOrder: 'forward'; defaultVisitingType: 'exit'; }> { /** * The abstract trace of the abstract interpretation visitor mapping node IDs to the abstract state at the respective node. */ protected readonly trace: Map<NodeId, StateDomain>; /** * The current abstract state domain at the currently processed AST node. */ protected currentState: StateDomain; /** * The current worklist stack of next vertex IDs to visit. */ private stack; /** * A set of nodes representing variable definitions that have already been visited but whose assignment has not yet been processed. */ private readonly unassigned; /** * A map mapping assignments of replacement calls to their replacement calls for replacement calls that have already been visited but whose assignment has not yet been processed. */ private readonly replacements; constructor(config: Config, stateDomain: StateDomain); /** * Resolves the inferred abstract value of an AST node. * This requires that the abstract interpretation visitor has been completed, or at least started. * @param id - The ID of the node to get the inferred value for * @param state - An optional state abstract domain used to resolve the inferred abstract value (defaults to the state at the requested node) * @returns The inferred abstract value of the node, or `undefined` if no value was inferred for the node */ getAbstractValue(id: RNode<ParentInformation> | NodeId | undefined, state?: StateDomain): ValueDomain<StateDomain> | undefined; /** * Gets the inferred abstract state at the location of a specific AST node. * This requires that the abstract interpretation visitor has been completed, or at least started. * @param id - The ID of the node to get the abstract state at * @returns The abstract state at the node, or `undefined` if the node has no abstract state (i.e. the node has not been visited or is unreachable). */ getAbstractState(id: NodeId | undefined): StateDomain | undefined; /** * Gets the inferred abstract state at the end of the program (exit nodes of the control flow graph). * This requires that the abstract interpretation visitor has been completed, or at least started. * @returns The inferred abstract state at the end of the program */ getEndState(): StateDomain; /** * Gets the inferred abstract trace mapping AST nodes to the inferred abstract state at the respective node. * @returns The inferred abstract trace of the program */ getAbstractTrace(): ReadonlyMap<NodeId, StateDomain>; start(): void; protected startVisitor(start: readonly NodeId[]): void; protected visitNode(vertexId: NodeId): boolean; protected visitUnknown(vertex: CfgStatementVertex | CfgExpressionVertex): void; protected onDispatchFunctionCallOrigin(call: DataflowGraphVertexFunctionCall, origin: BuiltInProcName): void; protected onVariableDefinition({ vertex }: { vertex: DataflowGraphVertexVariableDefinition; }): void; protected onAssignmentCall({ target, source }: { call: DataflowGraphVertexFunctionCall; target?: NodeId; source?: NodeId; }): void; protected onReplacementCall({ target }: { call: DataflowGraphVertexFunctionCall; target?: NodeId; source?: NodeId; }): void; /** * This event triggers for every function call that is not a condition, loop, assignment, replacement call, or access operation. * * * For example, this triggers for `data.frame` in `x <- data.frame(id = 1:5, name = letters[1:5])`. * * This bundles all function calls that are no conditions, loops, assignments, replacement calls, and access operations. * @protected */ protected onFunctionCall(_data: { call: DataflowGraphVertexFunctionCall; }): void; /** Gets all AST nodes for the predecessor vertices that are leaf nodes and exit vertices */ protected getPredecessorNodes(vertexId: NodeId): NodeId[]; /** Gets each variable origin that has already been visited and whose assignment has already been processed */ protected getVariableOrigins(nodeId: NodeId): NodeId[]; /** Checks whether a node represents a unsupported (environment-changing) function call (e.g. `eval`, `load`, `attach`, `rm`, ...) */ protected isUnsupportedFunctionCall(nodeId: NodeId): boolean; /** We only perform widening at `for`, `while`, or `repeat` loops with more than one ingoing CFG edge */ protected isWideningPoint(nodeId: NodeId): boolean; /** * Checks whether a control flow graph vertex should be skipped during visitation. * By default, we only process entry vertices of widening points, vertices of leaf nodes, and exit vertices (no entry nodes of complex nodes). */ protected shouldSkipVertex(vertex: CfgVertex): boolean; /** * Whether widening should be performed at a widening point. * By default, we perform widening when the number of visits of the widening point reaches the widening threshold of the config. */ protected shouldWiden(wideningPoint: CfgVertex): boolean; }