/** * Scope-chain lookup primitives shared across language providers. * * Five functions: * - `findReceiverTypeBinding` — walk scope.typeBindings up the chain * for a receiver name. * - `lookupBindingsAt` — read finalized + augmented binding refs at * one scope, deduped by `def.nodeId`. The dual-source-aware * primitive every other binding lookup composes with. * - `findClassBindingInScope` — walk scope.bindings + the indexes via * `lookupBindingsAt` for a class-kind binding. * - `findOwnedMember` — find a method/field owned by a class def * across all parsed files by (ownerId, simpleName). * - `findExportedDef` — find a file-level exported def (top-of-module * class / function) by simpleName. * * Next-consumer contract: every OO or module-capable language hits the * same pre-finalize / post-finalize binding split and the same * "resolve member on owner with MRO" pattern. All four are reusable * as-is for TypeScript, Java, Kotlin, Ruby, etc. */ import type { BindingRef, ParsedFile, ScopeId, SymbolDefinition, TypeRef } from '../../../../_shared/index.js'; import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; import type { SemanticModel } from '../../model/semantic-model.js'; import type { WorkspaceResolutionIndex } from '../workspace-index.js'; /** * Look up binding refs at `scopeId` for `name`, consulting both the * finalize-owned `bindings` channel and the post-finalize * `bindingAugmentations` channel (see invariant I8 in * `contract/scope-resolver.ts`). Finalized refs come first; augmented * refs append, deduped by `def.nodeId` so a sibling that's also * explicitly imported doesn't double-emit. * * Returns a shared frozen empty array when neither channel has the * name — callers can compare against `=== EMPTY_BINDINGS` if they * want a fast-path miss check. The bucket arrays are returned by * reference when only one channel populates them; the merged path * allocates a fresh array. * * Walker primitives (`findClassBindingInScope`, * `findCallableBindingInScope`, `findExportedDefByName`) and * post-finalize passes that read finalized bindings (e.g. * `propagateImportedReturnTypes`, `namespace-targets`) MUST go * through this helper instead of `scopes.bindings.get(...)` directly, * so the augmentation channel is always visible. */ export declare function lookupBindingsAt(scopeId: ScopeId, name: string, scopes: ScopeResolutionIndexes): readonly BindingRef[]; /** * Return the union of bound names at `scopeId` across both the * finalized and augmented channels. Companion to `lookupBindingsAt` * for callers that need to iterate every name at a scope (e.g. * `propagateImportedReturnTypes`). Order is not guaranteed; callers * that need stable iteration should sort externally. * * Fast paths (zero allocation) when at most one channel is populated: * returns the underlying `Map.keys()` iterator directly. Only when both * channels carry names do we materialize a `Set` for deduplication. * * Scope: enumerates only the per-scope `bindings` and `bindingAugmentations` * channels. It deliberately EXCLUDES the scope-independent * `workspaceFqnBindings` channel (PHP FQN keys, C# global-namespace simple * names). `lookupBindingsAt` consults that third channel when resolving a * specific name, but name *enumeration* here does not — those names apply at * every scope and would flood per-scope callers. Callers that need * workspace-level names must read `workspaceFqnBindings` directly. */ export declare function namesAtScope(scopeId: ScopeId, scopes: ScopeResolutionIndexes): Iterable; /** * True when a def's `type` names a class-like declaration — every kind * that collapses to `@scope.class` in the scope-extractor query contract. * * Semantics widened historically from `'Class' | 'Interface'` to cover * C#-shape languages (struct, record, enum, trait). Languages that emit * only `'Class'` are unaffected — the extra kinds never appear in their * parsed output. */ export declare function isClassLike(t: string): boolean; /** * Walk the scope chain from `startScope` looking for a typeBinding * named `receiverName`. Returns the TypeRef or undefined if no binding * exists in the chain. */ export declare function findReceiverTypeBinding(startScope: ScopeId, receiverName: string, scopes: ScopeResolutionIndexes): TypeRef | undefined; /** * Resolve a typeBinding for `name` from the per-namespace channel * (`namespaceTypeBindings`) across the namespaces accessible from `moduleScopeId`. * First accessible-namespace hit wins. Returns `undefined` when the module has no * accessibility entry (non-module scope id, or a bundle that didn't populate the * channel — all non-C# today). Shared by the two typeBindings chain-walkers so * the named-namespace fallback stays identical between them. */ export declare function namespaceTypeBindingFor(moduleScopeId: ScopeId | null, name: string, scopes: ScopeResolutionIndexes): TypeRef | undefined; /** * Walk the scope chain from `startScope` to its enclosing Module scope id, or * `null` if none is found. Used by chain-followers that need the module scope to * consult the accessibility-gated per-namespace channels. */ export declare function moduleScopeIdOf(startScope: ScopeId, scopes: ScopeResolutionIndexes): ScopeId | null; /** * Look up a class-like binding by name in the given scope's chain. * * "Class-like" covers `Class | Interface | Struct | Record | Enum | * Trait` via the shared `isClassLike` predicate — every kind that * collapses to `@scope.class` in the scope-extractor query contract. * * Walks the scope chain upward and consults TWO sources at each step: * 1. `scope.bindings` — populated during scope-extraction Pass 2 with * local declarations (`origin: 'local'`). * 2. The cross-file finalized + augmented bindings, via * `lookupBindingsAt` (per I8: finalized = canonical immutable * output; augmented = post-finalize hooks like * `populateNamespaceSiblings`). * * Without (2) we'd miss every cross-file class-receiver call. */ export declare function findClassBindingInScope(startScope: ScopeId, receiverName: string, scopes: ScopeResolutionIndexes): SymbolDefinition | undefined; /** * Resolve a class-like inheritance target using the shared inheritance * resolution chain. Keeps pre-emitted heritage edges and language-specific * consumers of `inherits` sites aligned. */ export declare function resolveInheritanceBaseInScope(startScope: ScopeId, baseName: string, scopes: ScopeResolutionIndexes, rawQualifiedName?: string, enclosingClassDef?: SymbolDefinition): SymbolDefinition | undefined; /** * Import/include-aware disambiguation for an *ambiguous* class-like base * name. Engages ONLY as a fallback after `findClassBindingInScope` has * already returned `undefined` — i.e. the scope-chain walk and the * single-match `qualifiedNames` fast paths could not pick a winner because * several same-named class-like defs exist (e.g. two `class Handler`s in * different headers/namespaces). * * Disambiguates by the referencing file's import graph: the enclosing * module scope's finalized `ImportEdge[]` (C++ `#include`, C# `using`, etc.) * each carry the exporting file in `targetFile`. A candidate whose defining * file is brought in by one of those edges is preferred. Resolution is * tiered, strictest first, and only commits when EXACTLY ONE candidate * survives a tier — so a still-ambiguous name keeps the historical * "return undefined" refusal: * * 1. Exact file match — candidate.filePath === an import's `targetFile` * (covers C++ `#include "handler_a.h"` → that header's class). * 2. Same-directory match — candidate.filePath sits in the same directory * as some import target file (covers C# `using MyApp.Models;`, where the * namespace import resolves to ONE representative file in the namespace's * directory, not necessarily the file declaring the referenced type). * * Language-neutral: keyed only on the finalized import edges and the * candidate defs' `filePath`. Returns `undefined` (preserving refusal) when * the name is single-match-resolvable already (never reached — caller gates * on `findClassBindingInScope` miss), when no import disambiguates, or when * a tier leaves more than one survivor. */ export declare function resolveAmbiguousInheritanceBaseViaImports(startScope: ScopeId, baseName: string, scopes: ScopeResolutionIndexes): SymbolDefinition | undefined; /** * Predicate for value-receiver bridge: the labels for which * `reconcileOwnership` registers methods/fields under the def's * `nodeId` as the `ownerId`. Explicit allowlist so future NodeLabel * additions (Module, Namespace, TypeAlias, EnumMember, etc.) do NOT * silently widen the bridge — adding a new ownerable label requires * touching both this predicate and `reconcileOwnership`. * * See: `scope-resolution/pipeline/reconcile-ownership.ts` Property / * Variable / Const / Static registration block. */ export declare function isOwnableValueLabel(t: string): boolean; /** * Look up a value-binding (Const/Variable/Property/Static) by name in * the given scope's chain. Used by the value-receiver-owner bridge * for object-literal services such as: * * export const fooService = { getUser(id) {...} }; * * where `fooService` is a `Const`/`Variable` whose `nodeId` is the * `ownerId` of the member method. Neither `findClassBindingInScope` * (rejects non-class-like) nor `findReceiverTypeBinding` (no typeBinding * for an unannotated literal) finds it. * * Mirrors `findClassBindingInScope` exactly; only the accepted def-type * predicate differs. */ export declare function findValueBindingInScope(startScope: ScopeId, receiverName: string, scopes: ScopeResolutionIndexes): SymbolDefinition | undefined; /** * Look up a callable (Function/Method/Constructor) by name in the * given scope's chain. Uses the dual-source pattern (scope.bindings + * `lookupBindingsAt` for finalized + augmented) so cross-file * imports are visible — without it free calls to imported functions * never resolve via the post-pass. * * Mirrors `findClassBindingInScope` exactly; only the accepted * def-type predicate differs. */ export declare function findCallableBindingInScope(startScope: ScopeId, callableName: string, scopes: ScopeResolutionIndexes): SymbolDefinition | undefined; /** * Look up all callable bindings (Function/Method/Constructor) by name * from the nearest scope in the chain that binds `callableName`. * * Preserves the original scope-walk boundary used by * `findCallableBindingInScope`: once any callable binding is found in a * scope, outer scopes are not consulted. */ export declare function findAllCallableBindingsInScope(startScope: ScopeId, callableName: string, scopes: ScopeResolutionIndexes): readonly SymbolDefinition[]; /** * ISO C++ `[basic.lookup.unqual]` §7: ADL is suppressed when ordinary * unqualified lookup finds: * - a name that is NOT a function or function template, OR * - a block-scope function declaration that is NOT a using-declaration. * * Combined walker that stops at the **nearest scope** where `name` has any * binding (callable or non-callable) and returns: * - `callables`: Function/Method/Constructor defs found at that scope * - `nonCallableFound`: a non-function binding was present (variable, class, etc.) * - `blockScopeDeclFound`: a callable was found at a Function or Block scope * (block-scope function declaration that blocks ADL) * * One pass, one stop — no divergence between callable collection and blocker * detection. */ export declare function findCallableBindingsAndAdlBlocker(startScope: ScopeId, name: string, scopes: ScopeResolutionIndexes): { callables: readonly SymbolDefinition[]; nonCallableFound: boolean; blockScopeDeclFound: boolean; }; /** * Populate `ownerId` on every def structurally owned by a Class * scope — methods (defs in Function scopes whose parent is Class) * and class-body fields (defs directly in Class scopes). * * Generic OO ownership rule. Languages that want richer ownership * (e.g. inner-class qualification) can compose with this as a base * step. * * Mutates `parsed.localDefs` in place via type cast — `SymbolDefinition` * is `readonly` for consumers but the extractor returns plain objects. * Defs are shared by reference between `localDefs` and `Scope.ownedDefs`, * so this single mutation is visible from both sides. */ export declare function populateClassOwnedMembers(parsed: ParsedFile): void; /** * Tag every def declared inside one or more `Namespace` scopes with its * enclosing-namespace path (`NS`, `Outer.Inner`) on a sidecar `namespacePrefix` * field — WITHOUT touching `qualifiedName`. * * Some scope-extractors qualify a nested type by its enclosing CLASS chain * (`A.Inner`) but drop the enclosing NAMESPACE, while the structure phase keys * the graph node by the full path (`NS.A.Inner`). `resolveDefGraphId` reads this * tag to retry the node lookup with the namespace-prefixed key before the * simple-name fallback, so same-tail nested bases don't collapse across sibling * namespace members (#1982). `qualifiedName` is deliberately left unchanged, so * the `qualifiedName`-keyed resolution index and existing namespace resolution * (brace-init, UDC ranking, two-phase lookup) are untouched. * * Language-agnostic: it acts only on `Namespace`-kind scopes (a namespace-free * language is a no-op) and is opt-in per provider (call after `populateOwners`). * Namespace segments are taken as each namespace def's own tail, so it composes * for nested namespaces regardless of whether the inner namespace's name is * stored simple or already dotted. Skips defs already carrying the prefix. */ export declare function tagNamespacePrefixes(parsed: ParsedFile): void; /** * Walk a scope chain upward looking for the innermost enclosing * Class scope and return that class's def. Used by per-language * `super` receiver branches to discover the dispatch base. */ export declare function findEnclosingClassDef(startScope: ScopeId, scopes: ScopeResolutionIndexes): SymbolDefinition | undefined; /** * Find a free-function def by simple name across all parsed files, * preferring scope-chain-visible bindings (import + finalized scope * bindings) before falling back to a workspace-wide simple-name scan. * * The fallback scan is intentionally loose so per-language compound * resolvers can find a callable target even when the binding chain * doesn't surface it (e.g. cross-package re-exports the finalize * pass missed). Strictly-typed languages may want to disable the * fallback by simply not calling this helper from their compound * resolver. */ export declare function findExportedDefByName(name: string, inScope: ScopeId, scopes: ScopeResolutionIndexes, index: WorkspaceResolutionIndex): SymbolDefinition | undefined; /** * Find a member of a class by simple name — delegates to * `SemanticModel.methods` (methods / functions / constructors) with a * fallback to `SemanticModel.fields` (properties / fields / * variables). After `runScopeResolution`'s reconciliation pass * populates both registries from `parsed.localDefs[i].ownerId` * (post-`populateOwners`), this is the single authoritative view of * class membership — no parallel scope-resolution index needed. * * Returns the first-seen overload for methods without arity or * return-type narrowing. Callers that need arity-aware dispatch use * `lookupMethodByOwner(owner, name, argCount)` directly. */ export declare function findOwnedMember(ownerDefId: string, memberName: string, model: SemanticModel): SymbolDefinition | undefined; /** * Find a file-level def (top-of-module class / function / variable) * by simple name — consults the target file's Module scope's * finalized bindings. Only defs bound at module-scope with * `origin === 'local'` qualify, matching the historical * "module-export-visible" semantics. Class methods and class-body * fields bind at their containing class scope and are naturally * excluded. * * Reads from `WorkspaceResolutionIndex.moduleScopeByFile` (scope-tied * lookup that doesn't live on `SemanticModel`). This intentionally * does NOT call `lookupBindingsAt`: `findExportedDef` answers "what * did the target file declare locally at module scope?", while * `bindingAugmentations` models importer-side visibility created by * post-finalize hooks. Callers that need importer-visible exports use * `findExportedDefByName`, which is dual-channel aware. */ export declare function findExportedDef(targetFile: string, memberName: string, index: WorkspaceResolutionIndex): SymbolDefinition | undefined;