UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

252 lines (251 loc) 16.9 kB
import { DataflowGraph } from './graph'; import { EdgeType } from './edge'; import { emptyGraph } from './dataflowgraph-builder'; import { getOriginInDfg } from '../origin/dfg-get-origin'; import { CallGraph } from './call-graph'; import { computeCallGraphSummaries, propagateTransitiveSideEffects } from '../internal/process/functions/call/built-in/transitive-side-effects'; import { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id'; import type { REnvironmentInformation } from '../environments/environment'; import type { DataflowGraphVertexInfo } from './vertex'; import { Identifier } from '../environments/identifier'; /** * This is the root helper object to work with the {@link DataflowGraph}. * * - {@link Dataflow.visualize} - for visualization helpers (e.g., rendering the DFG as a mermaid graph), * - {@link Dataflow.views} - for working with specific views of the dataflow graph (e.g., the call graph), * - {@link Dataflow.edge} - for working with the edges in the dataflow graph, * - {@link Dataflow.qualify} - for the package-qualified `pkg::fn` identifier of a call from its id and graph, * - {@link Dataflow.resolve} - for resolving a name against an environment, * - {@link Dataflow.packagesOf} - for the packages a set of nodes (e.g. a slice) calls into, * - {@link Dataflow.valueIsUsed}/{@link Dataflow.hasComputedArguments} - for what a call does with, and gets as, values, * @example * ```ts * Dataflow.origin(graph, id); // where the use at `id` comes from * Dataflow.edge.includesType(edge, EdgeType.Reads); // the edge helpers * Dataflow.visualize.mermaid.url(graph); // a link to the rendered graph * ``` */ export declare const Dataflow: { readonly name: "Dataflow"; /** * Maps to flowR's dataflow edge helper to work with the edges in the dataflow graph */ readonly edge: { readonly name: "DfEdge"; readonly typesToNames: (this: void, { types }: { types: number; }) => Set<import("./edge").EdgeTypeName>; readonly splitTypes: (this: void, { types }: { types: number; }) => EdgeType[]; readonly typeToName: (this: void, type: EdgeType) => string; readonly includesType: (this: void, { types }: { types: number; }, typesToInclude: EdgeType) => boolean; readonly doesNotIncludeType: (this: void, { types }: { types: number; }, any: EdgeType) => boolean; readonly hasAnyType: (this: void, { types }: { types: number; }) => boolean; readonly hasNoType: (this: void, { types }: { types: number; }) => boolean; readonly isOnlyType: (this: void, { types }: { types: number; }, only: EdgeType) => boolean; }; /** * Dispatches to helper objects that relate to (sub-) views of the dataflow graph, e.g. the call graph. */ readonly views: { /** * Maps to flowR's helper object for the call-graph */ readonly callGraph: { readonly name: "CallGraph"; readonly computeSubCallGraph: (this: void, graph: CallGraph, entryPoints: Set<NodeId>) => CallGraph; readonly entryPoints: (this: void, graph: CallGraph) => Set<NodeId>; readonly unreachableCalls: (this: void, graph: CallGraph) => NodeId[]; readonly dropTransitiveEdges: (this: void, graph: CallGraph) => CallGraph; readonly compute: (this: void, graph: DataflowGraph) => CallGraph; readonly visualize: { readonly mermaid: { readonly name: "DataflowMermaid"; readonly convert: (this: void, config: import("../../util/mermaid/dfg").MermaidGraphConfiguration) => { string: string; mermaid: import("../../util/mermaid/dfg").MermaidGraph; }; readonly raw: (this: void, graph: DataflowGraph | import("../info").DataflowInformation, includeEnvironments?: boolean, mark?: ReadonlySet<NodeId>, simplified?: boolean, qualifyBaseR?: boolean) => string; readonly url: (this: void, graph: DataflowGraph | import("../info").DataflowInformation, includeEnvironments?: boolean, mark?: ReadonlySet<NodeId>, simplified?: boolean, qualifyBaseR?: boolean) => string; }; readonly quads: { readonly convert: typeof import("./quads").df2quads; }; }; readonly diffGraphs: <G extends DataflowGraph>(this: void, left: import("../../util/diff-graph").NamedGraph<G>, right: import("../../util/diff-graph").NamedGraph<G>, config?: Partial<import("../../util/diff").GenericDiffConfiguration>) => import("../../util/diff-graph").GraphDifferenceReport; readonly invertGraph: <G extends DataflowGraph>(this: void, graph: G, cleanEnv: REnvironmentInformation) => G; readonly resolveGraphCriteria: <G extends DataflowGraph>(graph: G, ctx: import("../../project/context/flowr-analyzer-context").ReadOnlyFlowrAnalyzerContext, idMap?: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").AstIdMap) => G; readonly reaches: <G extends DataflowGraph>(this: void, from: NodeId, to: NodeId, graph: G, knownReachability?: import("../../util/collections/defaultmap").DefaultMap<NodeId, Set<NodeId>>) => boolean; }; }; /** * Dispatches to helper functions to create new dataflow graphs, e.g. from a pipeline or an empty graph. */ readonly create: { /** * Creates an empty dataflow graph with the given id map (or a new one if not provided). * @see {@link emptyGraph} */ readonly empty: typeof emptyGraph; }; /** * Returns the origin of a vertex in the dataflow graph * @see {@link getOriginInDfg} - for the underlying function */ readonly origin: typeof getOriginInDfg; /** * Name and value resolution. * @see {@link Resolve} - the helper object itself, which documents which entry point to reach for */ readonly resolve: { readonly name: "Resolve"; readonly byName: typeof import("../environments/resolve-by-name").resolveByNameAnyType; readonly byNameAndType: typeof import("../environments/resolve-by-name").resolveByName; readonly toBuiltIn: typeof import("../environments/resolve-by-name").resolvesToBuiltInConstant; readonly toConstants: typeof import("../eval/resolve/alias-tracking").resolveToConstants; readonly toValue: typeof import("../eval/resolve/alias-tracking").resolveIdToValue; readonly toSingleString: typeof import("../eval/resolve/alias-tracking").resolveIdToSingleString; readonly argument: { readonly name: "argument"; readonly toName: typeof import("../../abstract-interpretation/data-frame/resolve-args").resolveIdToArgName; readonly value: typeof import("../../abstract-interpretation/data-frame/resolve-args").resolveIdToArgValue; readonly stringVector: typeof import("../../abstract-interpretation/data-frame/resolve-args").resolveIdToArgStringVector; readonly symbolName: typeof import("../../abstract-interpretation/data-frame/resolve-args").resolveIdToArgValueSymbolName; readonly vectorLength: typeof import("../../abstract-interpretation/data-frame/resolve-args").resolveIdToArgVectorLength; }; }; /** * The qualified identifier of the call with the given id, or `undefined` if it does not resolve to a package * export and is not itself already namespaced (with `purrr` loaded, a `map()` call yields * `Identifier.make('map', 'purrr')`; an explicit `pkg::fn()` call yields `pkg::fn` unchanged). * * This is the compact form of {@link Identifier.toQualified}, reconstructing both the * {@link Dataflow.origin|origins} and the call's name from the graph. * @param id - The id of the call to qualify * @param graph - The graph the call is part of * @param qualifyBaseR - Whether to also qualify a bare base-R call from the package exporting it * (`sd` yields `stats::sd`), which needs neither a loaded database nor graph edges. * Set this to `false` to only qualify what the origins resolve to (or what is already namespaced). */ readonly qualify: (this: void, id: NodeId, graph: DataflowGraph, qualifyBaseR?: boolean) => Identifier | undefined; /** * The packages the given nodes call into, as {@link Dataflow.qualify} resolves every call among them. * This is what a selection needs, which is not what the program loads: a `library()` whose exports the * selection never calls does not make the package needed. Base R is left out unless `includeBaseR`. * @param nodes - the ids to consider, e.g. the result of a slice * @param graph - the graph the ids belong to * @param includeBaseR - whether to also report base-R packages */ readonly packagesOf: (this: void, nodes: Iterable<NodeId>, graph: DataflowGraph, includeBaseR?: boolean) => Set<string>; /** * Whether the call's result is passed on -- assigned, handed to another call, returned -- rather than left * for R to auto-print. A bare `anova(a, b)` is an output the program reports; the `summary(m)` of * `x <- summary(m)` is not. * * Only an edge that carries the value counts. A plain {@link EdgeType.Reads} does not: it also chains the * calls that share a side effect, which would report `plot(x)` as consumed by the `lines(y)` drawn after it. */ readonly valueIsUsed: (this: void, id: NodeId, graph: DataflowGraph) => boolean; /** * Whether any argument of the call carries a value the program worked out, rather than only literals the * author typed: `cat("starting\n")` is a log line, `cat("n =", length(m))` is a finding. * A call among the arguments counts as computed, even one over literals such as `paste("a", "b")`. */ readonly hasComputedArguments: (this: void, id: NodeId, graph: DataflowGraph) => boolean; /** * Interprocedural propagation of escaped side effects (attached packages, `<<-` definitions) to their callers. */ readonly sideEffects: { readonly propagateTransitive: typeof propagateTransitiveSideEffects; readonly callGraphSummaries: typeof computeCallGraphSummaries; }; /** * Only returns the sub-part of the graph that is determined by the given selection. * In other words, this will return a graph with only vertices that are part of the selected ids, * and edges that are between such selected vertices. * @param graph - the dataflow graph to slice for * @param select - the ids to select in the reduced graph * @param includeMissingTargets - if set to true, this will include edges which target vertices that are not selected! */ readonly reduceGraph: <G extends DataflowGraph>(this: void, graph: G, select: ReadonlySet<NodeId>, includeMissingTargets?: boolean) => G; /** * Equivalent to {@link Dataflow.reduceGraph|`reduceGraph`} followed by {@link Dataflow.invertGraph|`invertGraph`} * but in a single pass over the graph, allocating only one intermediate object instead of two. * Use this when you need the reduced-and-inverted graph for a forward traversal within a restriction set. */ readonly reduceAndInvertGraph: <G extends DataflowGraph>(this: void, graph: G, select: ReadonlySet<NodeId>, cleanEnv: REnvironmentInformation) => G; /** * Whether the node is quoted, i.e., affected by a {@link EdgeType.NonStandardEvaluation} edge that actually * keeps it from being evaluated (as `quote` and `substitute` do). * * Loops mark their body as non-standard-evaluated as well, yet that body really is evaluated (and its symbols * really are read), so such an edge does not quote. Use this instead of testing for the edge type directly * whenever you want to know whether something is evaluated at all. * @param id - The id of the node to check * @param graph - The graph the node is part of * @param withOutgoing - Whether to also consider the outgoing edges of the node (i.e., whether the node itself * quotes something), and not just the ingoing ones (i.e., whether it is quoted) */ readonly isQuoted: (this: void, id: NodeId, graph: DataflowGraph, withOutgoing?: boolean) => boolean; /** * Given the id of a vertex (usually a variable use), * this returns a reachable provenance set by calculating a non-interprocedural and non-context sensitive backward slice, but stopping at the given ids! * You can obtain the corresponding graph using {@link Dataflow.reduceGraph}. * @param id - The id to use as a seed for provenance calculation * @param graph - The graph to perform the provenance calculation on * @param consider - The ids to restrict the calculation too (e.g., the ids contained within a function definition to restrict the analysis to) * @param followEdges - Which edges to consider in the provenance traversal, if you set this to undefined this will automatically track all edges * @see {@link Dataflow.provenanceGraph} - for a convenience wrapper to directly obtain the graph of the provenance. */ readonly provenance: (this: void, id: NodeId, graph: DataflowGraph, consider?: ReadonlySet<NodeId>, followEdges?: number | undefined) => Set<NodeId>; /** * A simple visitor akin to {@link RNode.visitAst} to traverse the dataflow graph starting from the start id and only * respecting edge direction. * @param graph - The dataflow graph to operate on. * @param start - The start id of the visitation. * @param onVertex - The function to execute for each vertex, if this returns `true` the visitation will stop from this vertex. */ readonly visitDfg: (this: void, graph: DataflowGraph, start: NodeId, onVertex: (vtx: DataflowGraphVertexInfo) => (boolean | void)) => void; /** * A convenience wrapper for {@link Dataflow.reduceGraph|reducing} the {@link Dataflow.provenance|provenance} of a graph. * @param id - The id to use as a seed for provenance calculation * @param graph - The graph to perform the provenance calculation on * @param consider - The ids to restrict the calculation too (e.g., the ids contained within a function definition to restrict the analysis to) * @see {@link Dataflow.provenance} */ readonly provenanceGraph: (this: void, id: NodeId, graph: DataflowGraph, consider?: ReadonlySet<NodeId>) => DataflowGraph; readonly visualize: { readonly mermaid: { readonly name: "DataflowMermaid"; readonly convert: (this: void, config: import("../../util/mermaid/dfg").MermaidGraphConfiguration) => { string: string; mermaid: import("../../util/mermaid/dfg").MermaidGraph; }; readonly raw: (this: void, graph: DataflowGraph | import("../info").DataflowInformation, includeEnvironments?: boolean, mark?: ReadonlySet<NodeId>, simplified?: boolean, qualifyBaseR?: boolean) => string; readonly url: (this: void, graph: DataflowGraph | import("../info").DataflowInformation, includeEnvironments?: boolean, mark?: ReadonlySet<NodeId>, simplified?: boolean, qualifyBaseR?: boolean) => string; }; readonly quads: { readonly convert: typeof import("./quads").df2quads; }; }; readonly diffGraphs: <G extends DataflowGraph>(this: void, left: import("../../util/diff-graph").NamedGraph<G>, right: import("../../util/diff-graph").NamedGraph<G>, config?: Partial<import("../../util/diff").GenericDiffConfiguration>) => import("../../util/diff-graph").GraphDifferenceReport; readonly invertGraph: <G extends DataflowGraph>(this: void, graph: G, cleanEnv: REnvironmentInformation) => G; readonly resolveGraphCriteria: <G extends DataflowGraph>(graph: G, ctx: import("../../project/context/flowr-analyzer-context").ReadOnlyFlowrAnalyzerContext, idMap?: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").AstIdMap) => G; readonly reaches: <G extends DataflowGraph>(this: void, from: NodeId, to: NodeId, graph: G, knownReachability?: import("../../util/collections/defaultmap").DefaultMap<NodeId, Set<NodeId>>) => boolean; /** * Maps to flowR's main graph object to store and manipulate the dataflow graph * @see {@link DataflowGraph} */ readonly graph: typeof DataflowGraph; };