(body: SyntaxNode, _functionId: string)
| 5133 | } |
| 5134 | |
| 5135 | private visitFunctionBody(body: SyntaxNode, _functionId: string): void { |
| 5136 | if (!this.extractor) return; |
| 5137 | |
| 5138 | const visitForCallsAndStructure = (node: SyntaxNode): void => { |
| 5139 | const nodeType = node.type; |
| 5140 | |
| 5141 | // Function-as-value capture (#756) — function bodies are walked here, |
| 5142 | // not in visitNode, so the capture hook must fire in both walkers. |
| 5143 | this.maybeCaptureFnRefs(node, nodeType); |
| 5144 | |
| 5145 | // Rocket route-registration macros (`routes![…]` / `catchers![…]`): the |
| 5146 | // handler paths live in a raw token tree the call walker can't see. |
| 5147 | if (nodeType === 'macro_invocation') this.extractRustRouteMacro(node); |
| 5148 | |
| 5149 | if (this.extractor!.callTypes.includes(nodeType)) { |
| 5150 | this.extractCall(node); |
| 5151 | } else if (INSTANTIATION_KINDS.has(nodeType) || this.isVbnetConstructorShapedArrayCreation(node)) { |
| 5152 | // `new Foo()` inside a function body — emit an `instantiates` |
| 5153 | // reference. Without this branch the body walker only knew |
| 5154 | // about `call_expression`, so constructor invocations |
| 5155 | // produced no graph edges at all. |
| 5156 | this.extractInstantiation(node); |
| 5157 | // Anonymous class with body: `new T() { ... }` (Java/C#). Extract as |
| 5158 | // a class so interface-impl synthesis (Phase 5.5) can bridge T's |
| 5159 | // methods to the overrides — same rationale as in visitNode. |
| 5160 | const anonBody = this.findAnonymousClassBody(node); |
| 5161 | if (anonBody) { |
| 5162 | this.extractAnonymousClass(node, anonBody); |
| 5163 | return; |
| 5164 | } |
| 5165 | } else if (this.extractor!.extractBareCall) { |
| 5166 | const calleeName = this.extractor!.extractBareCall(node, this.source); |
| 5167 | if (calleeName && this.nodeStack.length > 0) { |
| 5168 | const callerId = this.nodeStack[this.nodeStack.length - 1]; |
| 5169 | if (callerId) { |
| 5170 | this.unresolvedReferences.push({ |
| 5171 | fromNodeId: callerId, |
| 5172 | referenceName: calleeName, |
| 5173 | referenceKind: 'calls', |
| 5174 | line: node.startPosition.row + 1, |
| 5175 | column: node.startPosition.column, |
| 5176 | }); |
| 5177 | } |
| 5178 | } |
| 5179 | } |
| 5180 | |
| 5181 | // C++ stack / direct-initialization construction — `Calculator calc(0)` |
| 5182 | // and `Widget w{1, 2}`. Unlike heap `new Calculator(0)` (a new_expression |
| 5183 | // handled above), these carry the constructor arguments directly on the |
| 5184 | // declarator with NO call/new node, so the body walker saw no constructor |
| 5185 | // invocation and recorded no `instantiates` edge (#1035). A declaration's |
| 5186 | // `type` field IS the constructed class name, so reuse extractInstantiation |
| 5187 | // (which strips template args / namespace and emits the `instantiates` |
| 5188 | // ref). Children still recurse below, so a nested ctor-arg call |
| 5189 | // (`Calculator calc(make())`) keeps its own `calls` ref. |
| 5190 | if (nodeType === 'declaration' && this.language === 'cpp' && this.isCppStackConstruction(node)) { |
| 5191 | this.extractInstantiation(node); |
| 5192 | } |
no outgoing calls
no test coverage detected