UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

204 lines (203 loc) 11.8 kB
import type { FlowrConfig } from '../config'; import type { KnownParser, KnownParserInformation } from '../r-bridge/parser'; import { type Queries, type QueryResults, type SupportedQueryTypes } from '../queries/query'; import type { ControlFlowInformation } from '../control-flow/control-flow-graph'; import type { NormalizedAst } from '../r-bridge/lang-4.x/ast/model/processing/decorate'; import type { DataflowInformation } from '../dataflow/info'; import type { CfgSimplificationPassName } from '../control-flow/cfg-simplification'; import type { PipelinePerStepMetaInformation } from '../core/steps/pipeline/pipeline'; import type { AnalyzerCacheType, FlowrAnalyzerCache } from './cache/flowr-analyzer-cache'; import type { FlowrSearchLike, SearchOutput } from '../search/flowr-search-builder'; import { type GetSearchElements } from '../search/flowr-search-executor'; import type { FlowrAnalyzerContext, ReadOnlyFlowrAnalyzerContext } from './context/flowr-analyzer-context'; import { CfgKind } from './cfg-kind'; import type { RAnalysisRequest } from './context/flowr-analyzer-files-context'; import type { RParseRequest, RParseRequestFromFile } from '../r-bridge/retriever'; import { fileProtocol } from '../r-bridge/retriever'; import type { FlowrFileProvider } from './context/flowr-file'; import type { Tree } from 'web-tree-sitter'; import type { CallGraph } from '../dataflow/graph/call-graph'; /** * Extends the {@link ReadonlyFlowrAnalysisProvider} with methods that allow modifying the analyzer state. */ export interface FlowrAnalysisProvider<Parser extends KnownParser = KnownParser> extends ReadonlyFlowrAnalysisProvider<Parser> { /** * Returns project context information. * If you are a user that wants to inspect the context, prefer {@link inspectContext} instead. * Please be aware that modifications to the context may break analyzer assumptions. */ context(): FlowrAnalyzerContext; /** * Add one or multiple requests to analyze. * @param request - One or multiple requests or a file path (with the `file://` protocol). If you just enter a string without the {@link fileProtocol}, it will be interpreted as R code. * @see {@link FlowrAnalysisProvider.addFile|addFile} - for adding files to the analyzer's context. */ addRequest(...request: (RAnalysisRequest | `${typeof fileProtocol}${string}` | string)[]): void; /** * Add one or multiple files to the analyzer's context. * @param f - One or multiple file paths, file providers, or parse requests from file. * @see {@link FlowrFileProvider} - for creating custom file providers. * @see {@link FlowrAnalysisProvider.addRequest|addRequest} - for adding analysis requests to the analyzer. */ addFile(...f: (string | FlowrFileProvider<string> | RParseRequestFromFile)[]): void; /** * Reset the analyzer state, including the context and the cache. */ reset(): void; } /** * Exposes the central analyses and information provided by the {@link FlowrAnalyzer} to the linter, search, and query APIs. * This allows us to exchange the underlying implementation of the analyzer without affecting the APIs. * You can also use {@link ReadonlyFlowrAnalysisProvider#parseStandalone|parseStandalone} to parse standalone R code snippets. */ export interface ReadonlyFlowrAnalysisProvider<Parser extends KnownParser = KnownParser> { /** * Returns a set of additional data and helper functions exposed by the underlying {@link KnownParser}, * including the parser's {@link BaseParserInformation.name} and corresponding version information. */ parserInformation(): KnownParserInformation; /** * Returns a read-only version of the project context information. * This is the preferred method for users that want to inspect the context. */ inspectContext(): ReadOnlyFlowrAnalyzerContext; /** * Get the parse output for the request. * * The parse result type depends on the {@link KnownParser} used by the analyzer. * @param force - Do not use the cache, instead force a new parse. * @see {@link ReadonlyFlowrAnalysisProvider#peekParse} - to get the parse output if already available without triggering a new computation. */ parse(force?: boolean): Promise<NonNullable<AnalyzerCacheType<Parser>['parse']>>; /** * Peek at the parse output for the request, if it was already computed. */ peekParse(): NonNullable<AnalyzerCacheType<Parser>['parse']> | undefined; /** * Parse standalone R code provided as a string or via the `file://` protocol. * @note this method will always use the {@link TreeSitterExecutor} internally, make sure it is initialized! * @param data - The R code to parse, either as a string or as a `file://` URL. */ parseStandalone(data: `${typeof fileProtocol}${string}` | string | RParseRequest): Tree; /** * Get the normalized abstract syntax tree for the request. * @param force - Do not use the cache, instead force new analyses. * @see {@link ReadonlyFlowrAnalysisProvider#peekNormalize} - to get the normalized AST if already available without triggering a new computation. */ normalize(force?: boolean): Promise<NormalizedAst & PipelinePerStepMetaInformation>; /** * Peek at the normalized abstract syntax tree for the request, if it was already computed. */ peekNormalize(): NormalizedAst & PipelinePerStepMetaInformation | undefined; /** * Normalize standalone R code provided as a string or via the `file://` protocol. * @note this method will always use the {@link TreeSitterExecutor} internally, make sure it is initialized! * @param data - The R code to normalize, either as a string or as a `file://` URL. */ normalizeStandalone(data: `${typeof fileProtocol}${string}` | string | RParseRequest): NormalizedAst; /** * Get the dataflow graph for the request. * @param force - Do not use the cache, instead force new analyses. * @see {@link ReadonlyFlowrAnalysisProvider#peekDataflow} - to get the dataflow graph if already available without triggering a new computation. */ dataflow(force?: boolean): Promise<DataflowInformation & PipelinePerStepMetaInformation>; /** * Peek at the dataflow graph for the request, if it was already computed. */ peekDataflow(): DataflowInformation & PipelinePerStepMetaInformation | undefined; /** * Get the control flow graph (CFG) for the request. * @param simplifications - Simplification passes to be applied to the CFG. * @param kind - The kind of CFG that is requested. By default, the CFG without dataflow information is returned. * @param force - Do not use the cache, instead force new analyses. * @see {@link ReadonlyFlowrAnalysisProvider#peekControlflow} - to get the CFG if already available without triggering a new computation. */ controlflow(simplifications?: readonly CfgSimplificationPassName[], kind?: CfgKind, force?: boolean): Promise<ControlFlowInformation>; /** * Peek at the control flow graph (CFG) for the request, if it was already computed. */ peekControlflow(simplifications?: readonly CfgSimplificationPassName[], kind?: CfgKind): ControlFlowInformation | undefined; /** * Calculate the call graph for the request. */ callGraph(force?: boolean): Promise<CallGraph>; /** * Peek at the call graph for the request, if it was already computed. */ peekCallGraph(): CallGraph | undefined; /** * Access the query API for the request. * @param query - The list of queries. */ query<Types extends SupportedQueryTypes = SupportedQueryTypes>(query: Queries<Types>): Promise<QueryResults<Types>>; /** * Run a search on the current analysis. */ runSearch<Search extends FlowrSearchLike>(search: Search): Promise<GetSearchElements<SearchOutput<Search>>>; /** * This executes all steps of the core analysis (parse, normalize, dataflow). */ runFull(force?: boolean): Promise<void>; /** This is the config used for the analyzer */ flowrConfig: FlowrConfig; } /** * Central class for conducting analyses with FlowR. * Use the {@link FlowrAnalyzerBuilder} to create a new instance. * * If you want the original pattern of creating a pipeline and running all steps, you can still do this with {@link FlowrAnalyzer#runFull}. * * To inspect the context of the analyzer, use {@link FlowrAnalyzer#inspectContext} (if you are a plugin and need to modify it, use {@link FlowrAnalyzer#context} instead). * @see https://github.com/flowr-analysis/flowr/wiki/Analyzer */ export declare class FlowrAnalyzer<Parser extends KnownParser = KnownParser> implements ReadonlyFlowrAnalysisProvider<Parser> { /** The parser and engine backend */ private readonly parser; /** The cache used for storing analysis results */ private readonly cache; private readonly ctx; private parserInfo; /** * Create a new analyzer instance. * **Prefer the use of the {@link FlowrAnalyzerBuilder} instead of calling this constructor directly.** * @param parser - The parser to use for parsing the given request. * @param ctx - The context to use for the analyses. * @param cache - The caching layer to use for storing analysis results. */ constructor(parser: Parser, ctx: FlowrAnalyzerContext, cache: FlowrAnalyzerCache<Parser>); get flowrConfig(): FlowrConfig; context(): FlowrAnalyzerContext; parserInformation(): KnownParserInformation; inspectContext(): ReadOnlyFlowrAnalyzerContext; reset(): void; parseStandalone(data: `${typeof fileProtocol}${string}` | string | RParseRequest): Tree; normalizeStandalone(data: `${typeof fileProtocol}${string}` | string | RParseRequest): NormalizedAst; addRequest(...request: (RAnalysisRequest | readonly RAnalysisRequest[] | `${typeof fileProtocol}${string}` | string)[]): this; addFile(...f: (string | FlowrFileProvider | RParseRequestFromFile)[]): this; /** * Add a request created from the given input. * This is a convenience method that uses {@link requestFromInput} internally. */ private addRequestFromInput; /** * Add one or multiple requests to analyze the builder. */ private addAnalysisRequest; parse(force?: boolean): Promise<NonNullable<AnalyzerCacheType<Parser>['parse']>>; peekParse(): NonNullable<AnalyzerCacheType<Parser>['parse']> | undefined; normalize(force?: boolean): Promise<NonNullable<AnalyzerCacheType<Parser>['normalize']>>; peekNormalize(): NonNullable<AnalyzerCacheType<Parser>['normalize']> | undefined; dataflow(force?: boolean): Promise<NonNullable<AnalyzerCacheType<Parser>['dataflow']>>; peekDataflow(): NonNullable<AnalyzerCacheType<Parser>['dataflow']> | undefined; runFull(force?: boolean): Promise<void>; controlflow(simplifications?: readonly CfgSimplificationPassName[], kind?: CfgKind, force?: boolean): Promise<ControlFlowInformation>; peekControlflow(simplifications?: readonly CfgSimplificationPassName[], kind?: CfgKind): ControlFlowInformation | undefined; callGraph(force?: boolean): Promise<CallGraph>; peekCallGraph(): CallGraph | undefined; query<Types extends SupportedQueryTypes = SupportedQueryTypes>(query: Queries<Types>): Promise<QueryResults<Types>>; runSearch<Search extends FlowrSearchLike>(search: Search): Promise<GetSearchElements<SearchOutput<Search>>>; /** * Close the parser if it was created by this builder. This is only required if you rely on an RShell/remote engine. */ close(): boolean | void; }