fix(resolution): stop typed external receivers and nested member calls from fabricating method edges - #1651
Open
zyyyyynnn wants to merge 9 commits into
Open
Conversation
…s from fabricating method edges When a receiver's local declaration or type annotation provides a concrete type (such as built-in Map/Set, an external package, or a non-matching class), failure to validate a project method on that type now stays unresolved instead of falling through to unique method-name guessing. In addition, TS/JS member-expression extraction now preserves static receiver chains (e.g. \holder.values.get\, \ his.store.get\, \ his.mailer.send\) in both the WASM extractor and the native Rust kernel. Multi-segment TS/JS receivers enforce an exclusive precision boundary in the resolver, preventing dropped-receiver calls from fabricating caller edges or self-edges on same-named project methods. Validated project receivers continue to resolve normally. Fixes colbymchenry#1566
… retry, and scoped this.field recall (colbymchenry#1566)
…project type nodes (colbymchenry#1566) - Extract canonical method call reference parser (parseMethodCallReference) covering dot, C++ explicit operator, scope, Lua single colon, and R dollar syntax - Bind inferred receiver types strictly to visible project type nodes in graph (bindProjectReceiverType) rather than loose type names - Restructure typed receiver conformance retry as node-anchored BFS traversal following extends/implements graph edges - Add constructor parameter property and direct ownership checks to avoid intermediate class hijacking of this.<field> receivers - Add comprehensive positive, negative, same-name duplicate, and external SDK isolation regression tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1566.
Prevents TypeScript/JavaScript calls on built-in and external receivers (such as
Map.get,Map.set,Map.has,Promise.then, and external SDK imports) from incorrectly resolving to unrelated same-named project methods or fabricating self-edges, while preserving exact object-literal / store call chains (useStore.getState().reset(),get().reset()), strict lexical ownership verification on typed project instances, out-of-line method definitions (such as C++ class declarations in headers with method bodies in source files), and deterministic inheritance traversal.Architecture
parseMethodCallReference):a.b), C++ explicit operator (a.operator+), scope (A::b), Lua/Luau single colon (a:b), and R dollar (a$b).bindProjectReceiverType):Map,Set,Promise) and unresolved external imports (from "external-sdk") returnnulland never bind to project decoy classes.resolveTsJsCallResultMember):useStore.getState().reset,get().reset,factory().get) rather than degrading them to bare method names.holder[key].get()) remain unlinked.constant/variablecontainers; final member resolution uses the existing fix(resolution): resolve calls to object-literal namespace members (#1573) #1597 exact-container containment rules. Unproven call results remain safely unresolved with zero fallback to generic name guessing.getDirectCallableCandidatesOnTypeNode/resolveMethodOnTypeNode):type::method); merely appearing inside the same file or textual class range is not sufficient evidence.resolveTypedReceiverCallsViaConformance):implements,extends) originating fromreceiverTypeNodeId.inferTsJsFieldReceiverType):this.<field>from class properties, constructor parameter properties, and explicit initializers, verifying direct constructor ownership so nested classes within method bodies do not hijack outer class field types.Safety Invariant
Receiver context is authoritative. A call edge is created only when the receiver binds to a specific project type or indexed container and the target member carries exact ownership evidence for that scope. Physical file co-location may help disambiguate candidates but is never required for ownership; same-name, source-range, or ambiguous candidates remain unresolved.
Regression Coverage
Map.get/set/hasnegative control: built-in Map method calls never fabricate edges to project methods (LRUCache).class Map extends BaseMapin another file does not capture built-inMapcalls.import { ExternalClient } from "external-sdk"never links to projectExternalClientor its base classes.Servicereceiver never resolves to nestedLocal::sendor nestedfunction save.useDerived(service)never resolves to nestedLocal::runor nestedfunction runwithinBaseService.Derived -> Basecorrectly resolves cross-fileBase::rundefined in.cppwhenBaseis declared in.hpp.Workerwithin function does not capture top-levelWorker::run; deeper nestedWorkerinside inner function is not visible to outer scope.Localconstructor parameter property does not hijackServiceconstructor or fabricateService.mailer.useStore.getState().reset()and in-storeget().reset()resolve to exact store actions while isolating top-level and sibling store decoys.factory().reset()inside a store action resolvesfactory()without misconnecting to sibling store actions.Engineclasses in different packages resolve only to their own base hierarchy.Related Issues