@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
252 lines (251 loc) • 16.9 kB
TypeScript
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;
};