import { type EngineIndex, type EngineSymbol } from "./engine-index.js"; /** One line of code, located. */ export interface SourceSite { /** Relative to the engine root, or to the project directory for `project`. */ file: string; line: number; text: string; /** `source` is an engine .cpp, `header` an engine .h, `project` the user's own code. */ kind: "source" | "header" | "project"; /** The owning module, for an engine file. Crossing one is a Build.cs edit. */ module?: string; /** The function the line sits in, when it could be recognised. */ caller?: string; } /** What a file-reading answer has to say about the tree it read. */ export interface TreeStatus { /** * Whether the engine tree contains .cpp files at all. False on a launcher * install, where an empty result means "this install cannot answer that" * rather than "nothing uses this". */ engineSourcesAvailable: boolean; /** Set when the search stopped at its limit rather than at the end. */ truncated: boolean; filesScanned: number; note?: string; } /** * The directory of the module owning a header. * * The engine and its plugins are laid out differently, and both have to give a * single directory that holds the module's Public, Private and Classes: * * Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h * -> Engine/Source/Runtime/Engine * Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/X.h * -> Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities * * It is what makes a definition search cheap: a member of `UAbilitySystem * Component` is defined in its own module or nowhere, so one module directory * is read instead of the whole tree. */ export declare function moduleDirFor(relHeader: string): string; /** * The engine directories named by a `trees` list. * * `Plugins` is `Engine/Plugins`, a sibling of `Engine/Source` rather than a * child of it, so it cannot be joined the way the other three are. `all` is * every tree that exists on this install. */ export declare function treeRoots(engineRoot: string, trees: readonly string[]): string[]; /** * Does this engine ship sources? * * Answered by walking directories until the first .cpp, which never reads a * file. A source build answers in milliseconds because the first module has * one; a launcher install pays a directory walk to prove the absence, which is * the honest cost of the honest answer. */ export declare function engineSourcesAvailable(engineRoot: string, trees?: readonly string[]): boolean; /** Strip a namespace qualification and any template arguments off a type name. */ export declare function baseTypeName(name: string): string; export interface HierarchyNode { name: string; kind: EngineSymbol["kind"]; module: string; include: string; header: string; line: number; exported: boolean; parent?: string; deprecated?: EngineSymbol["deprecated"]; /** Distance from the queried symbol: 1 is a direct parent or child. */ depth: number; /** True when this node's module differs from the queried symbol's, which is * what forces a Build.cs dependency to reach it. */ crossesModule: boolean; } export interface HierarchyResult { symbol: string; found: boolean; self?: HierarchyNode; /** Nearest parent first, up to the last one the index could resolve. */ ancestors: HierarchyNode[]; /** * The first base name the walk could not resolve, when there was one. It is * not proof the type does not exist: a base behind a template or a macro is * out of reach of a regex index. */ unresolvedAncestor?: string; descendants: HierarchyNode[]; directDescendantCount: number; /** Every module named anywhere in the answer, so the Build.cs cost is visible. */ modules: string[]; /** Modules other than the queried symbol's own. */ crossModuleDependencies: string[]; truncated: boolean; note?: string; } export declare function childIndex(index: EngineIndex): Map; /** * What a class derives from and what derives from it. * * Ancestors are a walk up `parent`, which the index already records, resolving * each name through the same ranking a lookup uses so the answer is the header * a caller would include. The walk stops at the first name that does not * resolve and says which one it was, because "the chain ends here" and "I * could not follow it further" are different facts. * * Descendants default to one generation. Asking for every transitive subclass * of `UObject` is a list of tens of thousands of names that no caller can act * on, so depth is opt-in and the result says when it was cut short. */ export declare function classHierarchy(index: EngineIndex, name: string, options?: { depth?: number; limit?: number; direction?: "ancestors" | "descendants" | "both"; }): HierarchyResult; export interface ReferenceResult extends TreeStatus { symbol: string; siteCount: number; /** Distinct files among the reported sites. */ fileCount: number; sites: SourceSite[]; /** Every module the reported sites live in. */ modules: string[]; } /** * Where a symbol is named across the engine tree and, optionally, the project. * * Deliberately broader than `find_callers`: a reference is a member * declaration, a UPROPERTY type, a cast, a template argument, or a call. That * is the question "what would break if this changed", which is what an agent * is really asking when it wants to see how a type is woven into the engine. * * Both headers and sources are searched, because on any install a great deal * of the interesting usage is in headers, and a launcher install has nothing * else. `#include` lines and comments are skipped: neither is a use of the * symbol, and both would otherwise dominate the result for a common type. */ export declare function findReferences(engineRoot: string, symbol: string, options?: { limit?: number; trees?: readonly string[]; projectDir?: string | null; includeProject?: boolean; }): ReferenceResult; export interface CallerResult extends TreeStatus { symbol: string; siteCount: number; sites: SourceSite[]; /** Unique enclosing functions, when they could be recognised. */ callers: string[]; modules: string[]; } /** * Is the name at `at` being called, or declared? * * Both read as `Name(`, and the difference is entirely in what comes before. * Nothing, an operator, a bracket or a `.`/`->`/`::` means a call. * An identifier means a return type, so it is a declaration: `virtual void * BeginPlay();` is not a call to BeginPlay, and counting it as one made every * header fallback report the declaration it was looking past. * * The two exceptions are the reason this is a function rather than a regex. A * trailing `*` or `&` belongs to a return type (`FVector* GetActor()`), and a * control-flow keyword is a word that legitimately precedes a call * (`return BeginPlay();`). */ export declare function looksLikeCall(text: string, at: number): boolean; /** * Who calls a function. * * Prefers .cpp files, because a call in a body is a caller and a mention in a * header is usually a declaration. On an install with no sources it falls back * to headers, where Unreal keeps a great deal of inline implementation, and to * the project's own tree, and says that is what it did. * * A line is a call when the name is followed by an open parenthesis and the * line is not itself a declaration of it. The definition of the function being * asked about is excluded too: it is not one of its own callers. */ export declare function findCallers(engineRoot: string, symbol: string, options?: { limit?: number; trees?: readonly string[]; projectDir?: string | null; includeProject?: boolean; }): CallerResult; export interface Callee { name: string; /** How many times the body calls it. */ count: number; /** `member` is `->Name()` or `.Name()`, `scoped` is `Type::Name()`, `free` is neither. */ call: "member" | "scoped" | "free"; /** Where the callee is declared, when the index knows the name. */ module?: string; include?: string; kind?: EngineSymbol["kind"]; } export interface CalleeResult extends TreeStatus { symbol: string; found: boolean; definition?: { file: string; line: number; endLine: number; kind: "source" | "header" | "project"; bodyLines: number; }; callees: Callee[]; calleeCount: number; /** Modules the resolvable callees live in, which is the Build.cs cost of * writing code that does the same thing. */ modules: string[]; } /** * The body of a function, from the line its definition starts on. * * Brace matching from the first `{`, ignoring braces inside a string, a * character literal or a line comment. A block comment holding an unbalanced * brace would defeat it, which has not happened in practice and would produce * a body that runs long rather than a wrong answer. */ export declare function extractBody(lines: string[], startLine: number): { body: string[]; endLine: number; } | null; /** Names a body calls, with how each call was written. */ export declare function callsIn(body: string, ownName: string): Map; /** * What a function calls. * * The body has to be found before it can be read, and finding it is what the * index makes cheap: a member of a class is defined in that class's own module * or nowhere, so the search is one module directory rather than the tree. On * an install with no sources the same search finds the inline body in the * header instead, which is where Unreal keeps a large share of its small * functions, and reports that it did. * * Each callee is looked back up in the index, so the answer carries the module * and include of everything the function reaches. That is the Build.cs cost of * writing code that does the same thing, which is the reason to ask. */ export declare function findCallees(index: EngineIndex, symbol: string, options?: { projectDir?: string | null; limit?: number; trees?: readonly string[]; }): CalleeResult; export interface ContextResult { symbol: string; found: boolean; header?: string; include?: string; module?: string; kind?: EngineSymbol["kind"] | "member"; /** The declaration's own line. */ declarationLine?: number; startLine?: number; endLine?: number; /** The lines themselves, as text, with the declaration inside them. */ text?: string; /** Set when the declaration opens a body that closed inside the window. */ bodyEndLine?: number; /** Other headers declaring the same name, when there is more than one. */ alsoDeclaredIn?: string[]; privateHeader?: boolean; note?: string; } /** * The code around a declaration. * * `verify_symbols` returns the declaration line, which is the signature and * nothing else. What a caller usually needs next is the twenty lines around * it: the sibling overloads, the UPROPERTY above it, the comment explaining * which of three similar methods to call. This returns that without the caller * having to know the engine's path layout or open the file. * * Accepts `Class::Member` as well as a bare type, resolved exactly as * `verify_symbols` resolves them, so the two agree about what a name means. */ export declare function symbolContext(index: EngineIndex, name: string, options?: { before?: number; after?: number; }): ContextResult;