gitnexus 1.6.5-rc.8 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_shared/scope-resolution/finalize-algorithm.js +10 -2
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +26 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.js +22 -3
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js +18 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +2 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +1 -0
- package/dist/cli/ai-context.js +70 -16
- package/dist/cli/analyze.d.ts +30 -2
- package/dist/cli/analyze.js +45 -5
- package/dist/cli/index.js +8 -1
- package/dist/cli/setup.js +18 -0
- package/dist/cli/wiki.d.ts +2 -0
- package/dist/cli/wiki.js +11 -0
- package/dist/core/augmentation/engine.js +24 -4
- package/dist/core/embeddings/http-client.js +22 -6
- package/dist/core/incremental/shadow-candidates.d.ts +44 -0
- package/dist/core/incremental/shadow-candidates.js +74 -0
- package/dist/core/incremental/subgraph-extract.d.ts +64 -0
- package/dist/core/incremental/subgraph-extract.js +111 -0
- package/dist/core/ingestion/call-processor.d.ts +12 -1
- package/dist/core/ingestion/call-processor.js +183 -47
- package/dist/core/ingestion/class-extractors/configs/c-cpp.js +38 -0
- package/dist/core/ingestion/class-extractors/generic.js +8 -0
- package/dist/core/ingestion/class-types.d.ts +15 -0
- package/dist/core/ingestion/community-processor.js +18 -0
- package/dist/core/ingestion/import-resolvers/standard.d.ts +5 -0
- package/dist/core/ingestion/import-resolvers/standard.js +31 -1
- package/dist/core/ingestion/import-resolvers/utils.js +4 -0
- package/dist/core/ingestion/languages/c-cpp.js +20 -2
- package/dist/core/ingestion/languages/cpp/adl.d.ts +141 -0
- package/dist/core/ingestion/languages/cpp/adl.js +478 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.d.ts +18 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +170 -0
- package/dist/core/ingestion/languages/cpp/arity.d.ts +17 -0
- package/dist/core/ingestion/languages/cpp/arity.js +31 -0
- package/dist/core/ingestion/languages/cpp/captures.d.ts +2 -0
- package/dist/core/ingestion/languages/cpp/captures.js +1131 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +31 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.js +47 -0
- package/dist/core/ingestion/languages/cpp/file-local-linkage.d.ts +118 -0
- package/dist/core/ingestion/languages/cpp/file-local-linkage.js +266 -0
- package/dist/core/ingestion/languages/cpp/header-scan.d.ts +8 -0
- package/dist/core/ingestion/languages/cpp/header-scan.js +50 -0
- package/dist/core/ingestion/languages/cpp/import-decomposer.d.ts +19 -0
- package/dist/core/ingestion/languages/cpp/import-decomposer.js +111 -0
- package/dist/core/ingestion/languages/cpp/import-target.d.ts +10 -0
- package/dist/core/ingestion/languages/cpp/import-target.js +13 -0
- package/dist/core/ingestion/languages/cpp/index.d.ts +11 -0
- package/dist/core/ingestion/languages/cpp/index.js +11 -0
- package/dist/core/ingestion/languages/cpp/inline-namespaces.d.ts +67 -0
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +176 -0
- package/dist/core/ingestion/languages/cpp/interpret.d.ts +35 -0
- package/dist/core/ingestion/languages/cpp/interpret.js +113 -0
- package/dist/core/ingestion/languages/cpp/merge-bindings.d.ts +13 -0
- package/dist/core/ingestion/languages/cpp/merge-bindings.js +29 -0
- package/dist/core/ingestion/languages/cpp/query.d.ts +3 -0
- package/dist/core/ingestion/languages/cpp/query.js +508 -0
- package/dist/core/ingestion/languages/cpp/range-bindings.d.ts +20 -0
- package/dist/core/ingestion/languages/cpp/range-bindings.js +212 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.d.ts +17 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +246 -0
- package/dist/core/ingestion/languages/cpp/simple-hooks.d.ts +24 -0
- package/dist/core/ingestion/languages/cpp/simple-hooks.js +62 -0
- package/dist/core/ingestion/languages/cpp/two-phase-lookup.d.ts +76 -0
- package/dist/core/ingestion/languages/cpp/two-phase-lookup.js +195 -0
- package/dist/core/ingestion/languages/java/arity-metadata.d.ts +18 -0
- package/dist/core/ingestion/languages/java/arity-metadata.js +40 -0
- package/dist/core/ingestion/languages/java/arity.d.ts +10 -0
- package/dist/core/ingestion/languages/java/arity.js +24 -0
- package/dist/core/ingestion/languages/java/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/java/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/java/captures.d.ts +17 -0
- package/dist/core/ingestion/languages/java/captures.js +187 -0
- package/dist/core/ingestion/languages/java/import-decomposer.d.ts +18 -0
- package/dist/core/ingestion/languages/java/import-decomposer.js +85 -0
- package/dist/core/ingestion/languages/java/import-target.d.ts +17 -0
- package/dist/core/ingestion/languages/java/import-target.js +100 -0
- package/dist/core/ingestion/languages/java/index.d.ts +29 -0
- package/dist/core/ingestion/languages/java/index.js +29 -0
- package/dist/core/ingestion/languages/java/interpret.d.ts +13 -0
- package/dist/core/ingestion/languages/java/interpret.js +131 -0
- package/dist/core/ingestion/languages/java/merge-bindings.d.ts +12 -0
- package/dist/core/ingestion/languages/java/merge-bindings.js +40 -0
- package/dist/core/ingestion/languages/java/query.d.ts +30 -0
- package/dist/core/ingestion/languages/java/query.js +192 -0
- package/dist/core/ingestion/languages/java/receiver-binding.d.ts +11 -0
- package/dist/core/ingestion/languages/java/receiver-binding.js +95 -0
- package/dist/core/ingestion/languages/java/scope-resolver.d.ts +50 -0
- package/dist/core/ingestion/languages/java/scope-resolver.js +74 -0
- package/dist/core/ingestion/languages/java/simple-hooks.d.ts +13 -0
- package/dist/core/ingestion/languages/java/simple-hooks.js +34 -0
- package/dist/core/ingestion/languages/java.js +11 -0
- package/dist/core/ingestion/languages/php/arity-metadata.d.ts +28 -0
- package/dist/core/ingestion/languages/php/arity-metadata.js +63 -0
- package/dist/core/ingestion/languages/php/arity.d.ts +25 -0
- package/dist/core/ingestion/languages/php/arity.js +40 -0
- package/dist/core/ingestion/languages/php/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/php/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/php/captures.d.ts +34 -0
- package/dist/core/ingestion/languages/php/captures.js +739 -0
- package/dist/core/ingestion/languages/php/import-decomposer.d.ts +28 -0
- package/dist/core/ingestion/languages/php/import-decomposer.js +265 -0
- package/dist/core/ingestion/languages/php/import-target.d.ts +47 -0
- package/dist/core/ingestion/languages/php/import-target.js +100 -0
- package/dist/core/ingestion/languages/php/index.d.ts +68 -0
- package/dist/core/ingestion/languages/php/index.js +72 -0
- package/dist/core/ingestion/languages/php/interpret.d.ts +36 -0
- package/dist/core/ingestion/languages/php/interpret.js +241 -0
- package/dist/core/ingestion/languages/php/merge-bindings.d.ts +19 -0
- package/dist/core/ingestion/languages/php/merge-bindings.js +47 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.d.ts +51 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.js +288 -0
- package/dist/core/ingestion/languages/php/query.d.ts +32 -0
- package/dist/core/ingestion/languages/php/query.js +326 -0
- package/dist/core/ingestion/languages/php/receiver-binding.d.ts +36 -0
- package/dist/core/ingestion/languages/php/receiver-binding.js +128 -0
- package/dist/core/ingestion/languages/php/scope-resolver.d.ts +23 -0
- package/dist/core/ingestion/languages/php/scope-resolver.js +358 -0
- package/dist/core/ingestion/languages/php/simple-hooks.d.ts +42 -0
- package/dist/core/ingestion/languages/php/simple-hooks.js +111 -0
- package/dist/core/ingestion/languages/php.d.ts +0 -7
- package/dist/core/ingestion/languages/php.js +15 -0
- package/dist/core/ingestion/markdown-processor.js +6 -1
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +3 -0
- package/dist/core/ingestion/parsing-processor.d.ts +22 -2
- package/dist/core/ingestion/parsing-processor.js +123 -50
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +54 -2
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +5 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +119 -11
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +14 -0
- package/dist/core/ingestion/pipeline.d.ts +13 -0
- package/dist/core/ingestion/registry-primary-flag.js +2 -0
- package/dist/core/ingestion/scope-extractor.js +4 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +167 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +3 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +1 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +12 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +1 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +16 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +36 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +204 -13
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +1 -1
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +55 -4
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +186 -5
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +10 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +207 -9
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +13 -1
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +6 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +86 -8
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +30 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +90 -8
- package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
- package/dist/core/ingestion/tree-sitter-queries.js +23 -0
- package/dist/core/ingestion/utils/ast-helpers.js +6 -1
- package/dist/core/ingestion/utils/template-arguments.d.ts +11 -0
- package/dist/core/ingestion/utils/template-arguments.js +65 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +3 -0
- package/dist/core/ingestion/workers/parse-worker.js +42 -1
- package/dist/core/lbug/lbug-adapter.d.ts +39 -0
- package/dist/core/lbug/lbug-adapter.js +348 -48
- package/dist/core/run-analyze.d.ts +2 -0
- package/dist/core/run-analyze.js +323 -29
- package/dist/core/search/hybrid-search.d.ts +3 -0
- package/dist/core/search/hybrid-search.js +23 -6
- package/dist/core/wiki/generator.js +4 -3
- package/dist/core/wiki/html-viewer.js +2 -1
- package/dist/core/wiki/llm-client.d.ts +4 -0
- package/dist/core/wiki/llm-client.js +3 -3
- package/dist/core/wiki/mermaid-sanitizer.d.ts +2 -0
- package/dist/core/wiki/mermaid-sanitizer.js +100 -0
- package/dist/mcp/local/local-backend.js +20 -7
- package/dist/storage/file-hash.d.ts +47 -0
- package/dist/storage/file-hash.js +86 -0
- package/dist/storage/parse-cache.d.ts +73 -0
- package/dist/storage/parse-cache.js +253 -0
- package/dist/storage/repo-manager.d.ts +41 -1
- package/dist/storage/repo-manager.js +61 -6
- package/hooks/claude/gitnexus-hook.cjs +42 -4
- package/hooks/claude/hook-db-lock-probe.cjs +238 -0
- package/hooks/claude/hook-lock.cjs +119 -0
- package/hooks/claude/win-rm-list-json.ps1 +76 -0
- package/package.json +1 -1
- package/scripts/build.js +6 -2
- package/vendor/node_modules/node-addon-api/node_addon_api.target.mk +16 -16
- package/vendor/node_modules/node-addon-api/node_addon_api_except.target.mk +16 -16
- package/vendor/node_modules/node-addon-api/node_addon_api_except_all.target.mk +16 -16
- package/vendor/node_modules/node-addon-api/node_addon_api_maybe.target.mk +16 -16
- package/web/assets/{agent-BpHQleHE.js → agent-D2kLt6Dl.js} +91 -91
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-DvIkEGkp.js +36 -0
- package/web/assets/blockDiagram-7IZFK4PR-B4niSLvR.js +132 -0
- package/web/assets/{c4Diagram-DFAF54RM-DeJV1rCn.js → c4Diagram-Y2BXMSZH-DIzEXalR.js} +6 -6
- package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +4 -0
- package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +1 -0
- package/web/assets/{chunk-7RZVMHOQ-BdIU-RGO.js → chunk-3SSMPTDK-BzGeeheI.js} +1 -1
- package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +159 -0
- package/web/assets/chunk-5IMINLNL-CnTLsXIV.js +1 -0
- package/web/assets/chunk-5VCL7Z4A-w1BCx98Z.js +1 -0
- package/web/assets/chunk-6764PJDD-ChwMM2z4.js +1 -0
- package/web/assets/chunk-67TQ5CYL-CChC2cAv.js +124 -0
- package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +10 -0
- package/web/assets/chunk-7W6UQGC5-CgFyfZ6k.js +1 -0
- package/web/assets/chunk-AQ6EADP3-CCFje6lL.js +1 -0
- package/web/assets/{chunk-KSICW3F5-C2tZmXwv.js → chunk-AZZRMDJM-5E9ARdDQ.js} +1 -1
- package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +1 -0
- package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +1 -0
- package/web/assets/chunk-INKRHTLW-ELpfuk9h.js +70 -0
- package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +1 -0
- package/web/assets/{chunk-AEOMTBSW-D7qjBMHW.js → chunk-JQRUD6KW-Dcq_Qnyy.js} +1 -1
- package/web/assets/chunk-KGFNY3KK-W-VR57xb.js +62 -0
- package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +1 -0
- package/web/assets/chunk-KNLZD3CH-BuZBOcso.js +1 -0
- package/web/assets/chunk-KRXBNO2N-DH2NPM7I.js +1 -0
- package/web/assets/chunk-LCXTWHL2-CqJ0oo1x.js +231 -0
- package/web/assets/chunk-LII3EMHJ-3X33tCpU.js +1 -0
- package/web/assets/chunk-QA3QBVWF-D5Ha3GgB.js +2 -0
- package/web/assets/chunk-RERM46MO-DQNbXtfw.js +1 -0
- package/web/assets/chunk-RG4AUYOV-D0M6vdq9.js +206 -0
- package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +1 -0
- package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +1 -0
- package/web/assets/chunk-T2UQINTJ-kGYG7ppP.js +1 -0
- package/web/assets/chunk-T5OCTHI4--9wWpVws.js +1 -0
- package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +1 -0
- package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +1 -0
- package/web/assets/chunk-UY5QBCOK-Du-c56gs.js +1 -0
- package/web/assets/chunk-W44A43WB-lrCpuupA.js +1 -0
- package/web/assets/chunk-ZXARS5L4-CSZRiyOf.js +1 -0
- package/web/assets/classDiagram-KGZ6W3CR-BB-saqC1.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-Bp2bAlS5.js +1 -0
- package/web/assets/cose-bilkent-UX7MHV2Q-BHv2bbtl.js +1 -0
- package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BUxnDPOY.js +43 -0
- package/web/assets/diagram-GF46GFSD-BJTyqqvI.js +24 -0
- package/web/assets/diagram-HNR7UZ2L-fUWreZzx.js +3 -0
- package/web/assets/diagram-QXG6HAR7-DilMHamP.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-8KUrarg1.js +10 -0
- package/web/assets/erDiagram-L5TCEMPS-Doj9mSiW.js +85 -0
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +1 -0
- package/web/assets/{flowDiagram-OTCZ4VVT-aAZw4c_M.js → flowDiagram-H6V6AXG4-BOSR-i3p.js} +12 -12
- package/web/assets/ganttDiagram-JCBTUEKG-BHQssTz6.js +292 -0
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +106 -0
- package/web/assets/index-j4-NuleT.js +623 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Ce_TvtaV.js +2 -0
- package/web/assets/{ishikawaDiagram-YMYX4NHK-BF8AtDaj.js → ishikawaDiagram-BNXS4ZKH-4MXIDCSF.js} +6 -6
- package/web/assets/journeyDiagram-M6C3CM3L-DNPYCpvq.js +139 -0
- package/web/assets/kanban-definition-75IXJCU3-yYdfm8Kk.js +89 -0
- package/web/assets/{katex-GD7MH7QM-CJiOjBBJ.js → katex-K3KEBU37-CrVLz8l7.js} +1 -1
- package/web/assets/mindmap-definition-2TDM6QVE-DFNEKM77.js +96 -0
- package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +1 -0
- package/web/assets/pieDiagram-CU6KROY3-iZAqpvhd.js +30 -0
- package/web/assets/quadrantDiagram-VICAPDV7-bAm6Hi_5.js +7 -0
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +1 -0
- package/web/assets/requirementDiagram-JXO7QTGE-CtDijhnf.js +84 -0
- package/web/assets/sankeyDiagram-URQDO5SZ-LFJz53u5.js +40 -0
- package/web/assets/sequenceDiagram-VS2MUI6T-BdjvyCHM.js +162 -0
- package/web/assets/stateDiagram-7D4R322I-e5odN9fG.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-vPsvjR2D.js +1 -0
- package/web/assets/timeline-definition-O6YCAMPW-DPAksNQp.js +120 -0
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +1 -0
- package/web/assets/vennDiagram-MWXL3ELB-Dtlfdt7J.js +34 -0
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +1 -0
- package/web/assets/wardleyDiagram-CUQ6CDDI-B23uRMUC.js +78 -0
- package/web/assets/{xychartDiagram-ZHJ5623Y-DZ7fP1_3.js → xychartDiagram-N2JHSOCM-DxwHeksW.js} +6 -6
- package/web/index.html +13 -2
- package/web/assets/architecture-YZFGNWBL-S5CXDPWN-BUzkWgDl.js +0 -1
- package/web/assets/architectureDiagram-EMZXCZ2Q-CXbzok1G.js +0 -36
- package/web/assets/blockDiagram-IGV67L2C-DA1QJ4ZB.js +0 -132
- package/web/assets/chunk-3GS5O3IE-B8hpnia8.js +0 -231
- package/web/assets/chunk-3YCYZ6SJ-B-BVu21C.js +0 -1
- package/web/assets/chunk-6NTNNK5N-DW-jYSDr.js +0 -1
- package/web/assets/chunk-A34GCYZU-BbZl-IKy.js +0 -1
- package/web/assets/chunk-DJ7UZH7F-B5tMfF87.js +0 -1
- package/web/assets/chunk-DKKBVRCY-Djm-6K_e.js +0 -4
- package/web/assets/chunk-DU5LTGQ6-QPoynYcp.js +0 -1
- package/web/assets/chunk-FXACKDTF-jieSmbe2.js +0 -159
- package/web/assets/chunk-H3VCZNTA-8EMHZ3SV.js +0 -1
- package/web/assets/chunk-HN6EAY2L-CgE_agsD.js +0 -1
- package/web/assets/chunk-O5ABG6QK-DEZV1O19.js +0 -1
- package/web/assets/chunk-PK6DOVAG-BXv0JnsJ.js +0 -206
- package/web/assets/chunk-RNJOYNJ4-BiBkF9dN.js +0 -1
- package/web/assets/chunk-RWUO3TPN-DTWzAhQ1.js +0 -1
- package/web/assets/chunk-TBF5ZNIQ-BSl6s9lT.js +0 -1
- package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +0 -1
- package/web/assets/chunk-TYMNRAUI-D1NDLIMG.js +0 -1
- package/web/assets/chunk-VELTKBKT-C9dVN39o.js +0 -1
- package/web/assets/chunk-W7ZLLLMY-Bu-cdLzs.js +0 -1
- package/web/assets/chunk-WSB5WSVC-Dor71SOz.js +0 -1
- package/web/assets/chunk-XGPFEOL4-CUonLRle.js +0 -1
- package/web/assets/classDiagram-PPOCWD7C-Cdd6UdVv.js +0 -1
- package/web/assets/classDiagram-v2-23LJLIIU-DNhxY2Ib.js +0 -1
- package/web/assets/cose-bilkent-PNC4W37J-DdZq7Qz_.js +0 -1
- package/web/assets/dagre-E77IOHMT-Cfj_6e17.js +0 -4
- package/web/assets/diagram-H7BISOXX-BNvpsrBv.js +0 -43
- package/web/assets/diagram-JC5VWROH-Cn0rtDbJ.js +0 -24
- package/web/assets/diagram-LXUTUG65-CHfoVKNm.js +0 -10
- package/web/assets/diagram-WEHSV5V5-BLxHksnu.js +0 -24
- package/web/assets/erDiagram-GCSMX5X6-DfdN6iqF.js +0 -85
- package/web/assets/ganttDiagram-MUNLMDZQ-BEfC_7Or.js +0 -292
- package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-B6ZeRLP0.js +0 -1
- package/web/assets/gitGraphDiagram-3HKGZ4G3-CG0kC8Q5.js +0 -106
- package/web/assets/index-3NUCUW2s.js +0 -886
- package/web/assets/info-OMHHGYJF-BF2H5H6G-BIOsZy0W.js +0 -1
- package/web/assets/infoDiagram-MN7RKWGX-DUoMH-pq.js +0 -2
- package/web/assets/journeyDiagram-SO5T7YLQ-BW8oKa3N.js +0 -139
- package/web/assets/kanban-definition-LJHFXRCJ-DzbOsR-2.js +0 -89
- package/web/assets/mindmap-definition-2EUWGEK5-BIXGQALq.js +0 -96
- package/web/assets/packet-4T2RLAQJ-EV4IVRXR-Bs7ysNMU.js +0 -1
- package/web/assets/pie-ZZUOXDRM-N23DN5KN-Csi8nnbH.js +0 -1
- package/web/assets/pieDiagram-3IATQBI2-QY-u7P6a.js +0 -30
- package/web/assets/quadrantDiagram-E256RVCF-Di4aNiU8.js +0 -7
- package/web/assets/radar-PYXPWWZC-P6TP7ZYP-DJlyXh2-.js +0 -1
- package/web/assets/requirementDiagram-M5DCFWZL-CzUUrhQD.js +0 -84
- package/web/assets/sankeyDiagram-L3NBLAOT-D2fbMiIU.js +0 -10
- package/web/assets/sequenceDiagram-ZOUHS735-BNdkqguh.js +0 -157
- package/web/assets/stateDiagram-MLPALWAM-51_Q2w2L.js +0 -1
- package/web/assets/stateDiagram-v2-B5LQ5ZB2-8nHs2aNE.js +0 -1
- package/web/assets/timeline-definition-5SPVSISX-DkMiGj4Z.js +0 -120
- package/web/assets/treeView-SZITEDCU-5DXDK3XO-Cy6P0_CZ.js +0 -1
- package/web/assets/treemap-W4RFUUIX-WYLRDWKO-C_pp1R7A.js +0 -1
- package/web/assets/vennDiagram-IE5QUKF5-BCxMmf9q.js +0 -34
- package/web/assets/wardley-RL74JXVD-BCRCBASE-CMStJhpn.js +0 -1
- package/web/assets/wardleyDiagram-XU3VSMPF-ijlLF77s.js +0 -20
- /package/web/assets/{context-builder-CqQNhRj1.js → context-builder-_HS0v2ma.js} +0 -0
|
@@ -0,0 +1,1131 @@
|
|
|
1
|
+
import { findNodeAtRange, nodeToCapture, syntheticCapture, } from '../../utils/ast-helpers.js';
|
|
2
|
+
import { getCppParser, getCppScopeQuery } from './query.js';
|
|
3
|
+
import { getTreeSitterBufferSize } from '../../constants.js';
|
|
4
|
+
import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
|
|
5
|
+
import { splitCppInclude, splitCppUsingDecl } from './import-decomposer.js';
|
|
6
|
+
import { computeCppDeclarationArity, computeCppCallArity } from './arity-metadata.js';
|
|
7
|
+
import { markCppAnonymousNamespaceRange, markFileLocal } from './file-local-linkage.js';
|
|
8
|
+
import { markCppDependentBase } from './two-phase-lookup.js';
|
|
9
|
+
import { markCppAdlSiteArgs, markCppAdlSiteNoAdl } from './adl.js';
|
|
10
|
+
import { markCppInlineNamespaceRange } from './inline-namespaces.js';
|
|
11
|
+
export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
|
|
12
|
+
let tree = cachedTree;
|
|
13
|
+
if (tree === undefined) {
|
|
14
|
+
tree = parseSourceSafe(getCppParser(), sourceText, undefined, {
|
|
15
|
+
bufferSize: getTreeSitterBufferSize(sourceText),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const rawMatches = getCppScopeQuery().matches(tree.rootNode);
|
|
19
|
+
const out = [];
|
|
20
|
+
// Track ranges where typedef-struct was captured as @declaration.struct
|
|
21
|
+
// so we can suppress the duplicate @declaration.typedef match.
|
|
22
|
+
const structTypedefRanges = new Set();
|
|
23
|
+
for (const m of rawMatches) {
|
|
24
|
+
const grouped = {};
|
|
25
|
+
for (const c of m.captures) {
|
|
26
|
+
const tag = '@' + c.name;
|
|
27
|
+
if (tag.startsWith('@_'))
|
|
28
|
+
continue;
|
|
29
|
+
grouped[tag] = nodeToCapture(tag, c.node);
|
|
30
|
+
}
|
|
31
|
+
if (Object.keys(grouped).length === 0)
|
|
32
|
+
continue;
|
|
33
|
+
// ── Handle #include statements ──────────────────────────────────
|
|
34
|
+
if (grouped['@import.statement'] !== undefined) {
|
|
35
|
+
const anchor = grouped['@import.statement'];
|
|
36
|
+
const includeNode = findNodeAtRange(tree.rootNode, anchor.range, 'preproc_include');
|
|
37
|
+
if (includeNode !== null) {
|
|
38
|
+
const split = splitCppInclude(includeNode);
|
|
39
|
+
if (split !== null) {
|
|
40
|
+
out.push(split);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// ── Handle using declarations (using namespace / using name) ────
|
|
46
|
+
if (grouped['@import.using-decl'] !== undefined) {
|
|
47
|
+
const anchor = grouped['@import.using-decl'];
|
|
48
|
+
const usingNode = findNodeAtRange(tree.rootNode, anchor.range, 'using_declaration');
|
|
49
|
+
if (usingNode !== null) {
|
|
50
|
+
const split = splitCppUsingDecl(usingNode);
|
|
51
|
+
if (split !== null) {
|
|
52
|
+
out.push(split);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ── Track typedef-struct ranges ─────────────────────────────────
|
|
58
|
+
const structAnchor = grouped['@declaration.struct'] ?? grouped['@declaration.class'];
|
|
59
|
+
if (structAnchor !== undefined) {
|
|
60
|
+
const r = structAnchor.range;
|
|
61
|
+
structTypedefRanges.add(`${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`);
|
|
62
|
+
}
|
|
63
|
+
// Suppress @declaration.typedef if the same range was already captured
|
|
64
|
+
const typedefAnchor = grouped['@declaration.typedef'];
|
|
65
|
+
if (typedefAnchor !== undefined) {
|
|
66
|
+
const r = typedefAnchor.range;
|
|
67
|
+
const key = `${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`;
|
|
68
|
+
if (structTypedefRanges.has(key))
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// ── Enrich function/method declarations with arity metadata ─────
|
|
72
|
+
const declAnchor = grouped['@declaration.function'] ?? grouped['@declaration.method'];
|
|
73
|
+
if (declAnchor !== undefined) {
|
|
74
|
+
const fnNode = findNodeAtRange(tree.rootNode, declAnchor.range, 'function_definition') ??
|
|
75
|
+
findNodeAtRange(tree.rootNode, declAnchor.range, 'declaration') ??
|
|
76
|
+
findNodeAtRange(tree.rootNode, declAnchor.range, 'field_declaration');
|
|
77
|
+
if (fnNode !== null) {
|
|
78
|
+
const arity = computeCppDeclarationArity(fnNode);
|
|
79
|
+
if (arity.parameterCount !== undefined) {
|
|
80
|
+
grouped['@declaration.parameter-count'] = syntheticCapture('@declaration.parameter-count', fnNode, String(arity.parameterCount));
|
|
81
|
+
}
|
|
82
|
+
if (arity.requiredParameterCount !== undefined) {
|
|
83
|
+
grouped['@declaration.required-parameter-count'] = syntheticCapture('@declaration.required-parameter-count', fnNode, String(arity.requiredParameterCount));
|
|
84
|
+
}
|
|
85
|
+
if (arity.parameterTypes !== undefined) {
|
|
86
|
+
grouped['@declaration.parameter-types'] = syntheticCapture('@declaration.parameter-types', fnNode, JSON.stringify(arity.parameterTypes));
|
|
87
|
+
}
|
|
88
|
+
// Detect static storage class (file-local linkage)
|
|
89
|
+
if (hasStaticStorageClass(fnNode)) {
|
|
90
|
+
const nameText = grouped['@declaration.name']?.text;
|
|
91
|
+
if (nameText !== undefined) {
|
|
92
|
+
markFileLocal(filePath, nameText);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Detect anonymous namespace (file-local linkage)
|
|
96
|
+
if (isInsideAnonymousNamespace(fnNode)) {
|
|
97
|
+
const nameText = grouped['@declaration.name']?.text;
|
|
98
|
+
if (nameText !== undefined) {
|
|
99
|
+
markFileLocal(filePath, nameText);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// ── Detect static variables (file-local linkage) ────────────────
|
|
105
|
+
const varDeclAnchor = grouped['@declaration.variable'];
|
|
106
|
+
if (varDeclAnchor !== undefined) {
|
|
107
|
+
const varNode = findNodeAtRange(tree.rootNode, varDeclAnchor.range, 'declaration');
|
|
108
|
+
if (varNode !== null) {
|
|
109
|
+
if (hasStaticStorageClass(varNode) || isInsideAnonymousNamespace(varNode)) {
|
|
110
|
+
const nameText = grouped['@declaration.name']?.text;
|
|
111
|
+
if (nameText !== undefined) {
|
|
112
|
+
markFileLocal(filePath, nameText);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// ── Enrich call references with arity ───────────────────────────
|
|
118
|
+
const callAnchor = grouped['@reference.call.free'] ??
|
|
119
|
+
grouped['@reference.call.member'] ??
|
|
120
|
+
grouped['@reference.call.qualified'];
|
|
121
|
+
if (callAnchor !== undefined && grouped['@reference.arity'] === undefined) {
|
|
122
|
+
const callNode = findNodeAtRange(tree.rootNode, callAnchor.range, 'call_expression');
|
|
123
|
+
if (callNode !== null) {
|
|
124
|
+
grouped['@reference.arity'] = syntheticCapture('@reference.arity', callNode, String(computeCppCallArity(callNode)));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// ── Enrich constructor calls (new Foo()) with arity ─────────────
|
|
128
|
+
const ctorCallAnchor = grouped['@reference.call.constructor'];
|
|
129
|
+
if (ctorCallAnchor !== undefined && grouped['@reference.arity'] === undefined) {
|
|
130
|
+
const newNode = findNodeAtRange(tree.rootNode, ctorCallAnchor.range, 'new_expression');
|
|
131
|
+
if (newNode !== null) {
|
|
132
|
+
grouped['@reference.arity'] = syntheticCapture('@reference.arity', newNode, String(computeCppCallArity(newNode)));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ── Synthesize argument types for overload narrowing ────────────
|
|
136
|
+
const anyCallAnchor = callAnchor ?? ctorCallAnchor;
|
|
137
|
+
if (anyCallAnchor !== undefined && grouped['@reference.parameter-types'] === undefined) {
|
|
138
|
+
const cNode = findNodeAtRange(tree.rootNode, anyCallAnchor.range, 'call_expression') ??
|
|
139
|
+
findNodeAtRange(tree.rootNode, anyCallAnchor.range, 'new_expression');
|
|
140
|
+
if (cNode !== null) {
|
|
141
|
+
const argTypes = inferCppCallArgTypes(cNode);
|
|
142
|
+
if (argTypes !== undefined && argTypes.length > 0) {
|
|
143
|
+
grouped['@reference.parameter-types'] = syntheticCapture('@reference.parameter-types', cNode, JSON.stringify(argTypes));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// ── Inline namespace detection ──────────────────────────────────
|
|
148
|
+
// `inline namespace v1 { ... }` — tree-sitter-cpp exposes the
|
|
149
|
+
// `inline` keyword as a child of `namespace_definition`. Record the
|
|
150
|
+
// namespace's source range so `populateCppInlineNamespaceScopes`
|
|
151
|
+
// (during populateOwners) can match it back to the corresponding
|
|
152
|
+
// Namespace scope.
|
|
153
|
+
// `@declaration.namespace` fires only for NAMED namespaces (the query
|
|
154
|
+
// requires a `name: (namespace_identifier)` child). Use the unconditional
|
|
155
|
+
// `@scope.namespace` capture so the anonymous-namespace branch also runs.
|
|
156
|
+
const namespaceScopeAnchor = grouped['@declaration.namespace'] ?? grouped['@scope.namespace'];
|
|
157
|
+
if (namespaceScopeAnchor !== undefined) {
|
|
158
|
+
const nsNode = findNodeAtRange(tree.rootNode, namespaceScopeAnchor.range, 'namespace_definition');
|
|
159
|
+
if (nsNode !== null) {
|
|
160
|
+
// Range coords stored in the shared Range shape use 1-based
|
|
161
|
+
// line numbers (see `ast-helpers.ts` rangeForNode where
|
|
162
|
+
// `startPosition.row + 1` is applied). Match that convention so
|
|
163
|
+
// the populators can join against `Scope.range`.
|
|
164
|
+
const nsRange = {
|
|
165
|
+
startLine: nsNode.startPosition.row + 1,
|
|
166
|
+
startCol: nsNode.startPosition.column,
|
|
167
|
+
endLine: nsNode.endPosition.row + 1,
|
|
168
|
+
endCol: nsNode.endPosition.column,
|
|
169
|
+
};
|
|
170
|
+
if (isInlineNamespace(nsNode)) {
|
|
171
|
+
markCppInlineNamespaceRange(filePath, nsRange);
|
|
172
|
+
}
|
|
173
|
+
// Anonymous namespace: `namespace_definition` with no `name` field.
|
|
174
|
+
// Recorded so `expandCppWildcardNames` can propagate its members
|
|
175
|
+
// to including TUs even though their names are also `markFileLocal`'d
|
|
176
|
+
// (which blocks the global free-call fallback's cross-file path).
|
|
177
|
+
if ((nsNode.childForFieldName?.('name') ?? null) === null) {
|
|
178
|
+
markCppAnonymousNamespaceRange(filePath, nsRange);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// ── ADL (Koenig lookup) per-site recording ──────────────────────
|
|
183
|
+
// Only free-call sites (no explicit receiver) participate in ADL —
|
|
184
|
+
// qualified `Ns::f(s)` and member `obj.f(s)` calls bypass the
|
|
185
|
+
// free-call fallback entirely (handled by receiver-bound-calls).
|
|
186
|
+
if (grouped['@reference.call.free'] !== undefined) {
|
|
187
|
+
const freeCallNode = findNodeAtRange(tree.rootNode, grouped['@reference.call.free'].range, 'call_expression');
|
|
188
|
+
if (freeCallNode !== null) {
|
|
189
|
+
const adlAnchorRange = grouped['@reference.call.free'].range;
|
|
190
|
+
if (isParenthesizedFunctionCall(freeCallNode)) {
|
|
191
|
+
markCppAdlSiteNoAdl(filePath, adlAnchorRange.startLine, adlAnchorRange.startCol);
|
|
192
|
+
}
|
|
193
|
+
const adlArgs = inferCppCallAdlArgs(freeCallNode);
|
|
194
|
+
if (adlArgs.length > 0) {
|
|
195
|
+
markCppAdlSiteArgs(filePath, adlAnchorRange.startLine, adlAnchorRange.startCol, adlArgs);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ── Post-process @type-binding.assignment for auto declarations ──
|
|
200
|
+
// The wildcard `type: (_)` in the @type-binding.assignment query
|
|
201
|
+
// pattern matches before the more specific @type-binding.alias and
|
|
202
|
+
// @type-binding.member-access patterns. When the type is `auto`
|
|
203
|
+
// (placeholder_type_specifier), we re-inspect the AST to synthesize
|
|
204
|
+
// the correct capture tags so interpret.ts can produce the right
|
|
205
|
+
// rawTypeName for compound-receiver chain resolution.
|
|
206
|
+
if (grouped['@type-binding.assignment'] !== undefined &&
|
|
207
|
+
grouped['@type-binding.type']?.text === 'auto') {
|
|
208
|
+
const anchor = grouped['@type-binding.assignment'];
|
|
209
|
+
const declNode = findNodeAtRange(tree.rootNode, anchor.range, 'declaration');
|
|
210
|
+
if (declNode !== null) {
|
|
211
|
+
const declarator = declNode.childForFieldName('declarator');
|
|
212
|
+
if (declarator?.type === 'init_declarator') {
|
|
213
|
+
const valueNode = declarator.childForFieldName('value');
|
|
214
|
+
if (valueNode !== null) {
|
|
215
|
+
if (valueNode.type === 'identifier') {
|
|
216
|
+
// auto alias = existingVar → promote to @type-binding.alias
|
|
217
|
+
grouped['@type-binding.alias'] = anchor;
|
|
218
|
+
grouped['@type-binding.type'] = nodeToCapture('@type-binding.type', valueNode);
|
|
219
|
+
delete grouped['@type-binding.assignment'];
|
|
220
|
+
}
|
|
221
|
+
else if (valueNode.type === 'field_expression') {
|
|
222
|
+
// auto addr = user.address → promote to @type-binding.member-access
|
|
223
|
+
const argNode = valueNode.childForFieldName('argument');
|
|
224
|
+
const fieldNode = valueNode.childForFieldName('field');
|
|
225
|
+
if (argNode !== null && fieldNode !== null) {
|
|
226
|
+
grouped['@type-binding.member-access'] = anchor;
|
|
227
|
+
grouped['@type-binding.member-access-receiver'] = nodeToCapture('@type-binding.member-access-receiver', argNode);
|
|
228
|
+
grouped['@type-binding.type'] = nodeToCapture('@type-binding.type', fieldNode);
|
|
229
|
+
delete grouped['@type-binding.assignment'];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else if (valueNode.type === 'call_expression') {
|
|
233
|
+
const fnNode = valueNode.childForFieldName('function');
|
|
234
|
+
if (fnNode?.type === 'field_expression') {
|
|
235
|
+
// auto city = addr.getCity() → promote to @type-binding.alias
|
|
236
|
+
// with dotted rawName "addr.getCity" for compound-receiver
|
|
237
|
+
const argNode = fnNode.childForFieldName('argument');
|
|
238
|
+
const fieldNode = fnNode.childForFieldName('field');
|
|
239
|
+
if (argNode !== null && fieldNode !== null) {
|
|
240
|
+
grouped['@type-binding.member-access'] = anchor;
|
|
241
|
+
grouped['@type-binding.member-access-receiver'] = nodeToCapture('@type-binding.member-access-receiver', argNode);
|
|
242
|
+
grouped['@type-binding.type'] = nodeToCapture('@type-binding.type', fieldNode);
|
|
243
|
+
delete grouped['@type-binding.assignment'];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
out.push(grouped);
|
|
252
|
+
}
|
|
253
|
+
// ── Emit inheritance references for scope-resolution MRO / EXTENDS ──
|
|
254
|
+
// Walk every class/struct base list and synthesize `@reference.inherits`
|
|
255
|
+
// captures consumed by the registry-primary graph bridge. The lookup name
|
|
256
|
+
// is normalized to the bare class name so `Base<T>` / `outer::v1::Base<T>`
|
|
257
|
+
// resolve through V1's simple-name `findClassBindingInScope('Base')`.
|
|
258
|
+
emitCppInheritanceCaptures(tree.rootNode, out);
|
|
259
|
+
// ── Detect dependent-base relationships for two-phase template lookup ──
|
|
260
|
+
// Walk the tree once, finding every `template_declaration` whose
|
|
261
|
+
// child is a class/struct definition with a `base_class_clause` whose
|
|
262
|
+
// base names reference an in-scope template parameter. Record the
|
|
263
|
+
// (className, dependentBaseName) pair so `populateCppDependentBases`
|
|
264
|
+
// (called from the `populateOwners` hook) can resolve names to nodeIds
|
|
265
|
+
// and the resolver can suppress unqualified-call binding to those
|
|
266
|
+
// bases per ISO C++ two-phase lookup.
|
|
267
|
+
detectCppDependentBases(tree.rootNode, filePath);
|
|
268
|
+
return out;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Walk every C++ class/struct base clause and emit `@reference.inherits`
|
|
272
|
+
* captures for each base so scope resolution can resolve them into EXTENDS
|
|
273
|
+
* edges. Lookup names are normalized to bare class names (`Base<T>` → `Base`,
|
|
274
|
+
* `outer::v1::Base<T>` → `Base`) to match the V1 simple-name
|
|
275
|
+
* `findClassBindingInScope` contract. This intentionally preserves the
|
|
276
|
+
* existing scope-chain tradeoff: qualified namespace context is discarded
|
|
277
|
+
* here instead of introducing a C++-only name-resolution lane in shared
|
|
278
|
+
* ingestion infrastructure.
|
|
279
|
+
*/
|
|
280
|
+
function emitCppInheritanceCaptures(root, out) {
|
|
281
|
+
const stack = [root];
|
|
282
|
+
while (stack.length > 0) {
|
|
283
|
+
const node = stack.pop();
|
|
284
|
+
if (node.type === 'class_specifier' || node.type === 'struct_specifier') {
|
|
285
|
+
const baseClause = findChildOfType(node, ['base_class_clause']);
|
|
286
|
+
if (baseClause !== null) {
|
|
287
|
+
for (const base of iterBaseClasses(baseClause)) {
|
|
288
|
+
const baseName = extractBaseLookupName(base);
|
|
289
|
+
if (baseName.length === 0)
|
|
290
|
+
continue;
|
|
291
|
+
out.push({
|
|
292
|
+
'@reference.inherits': nodeToCapture('@reference.inherits', base),
|
|
293
|
+
'@reference.name': syntheticCapture('@reference.name', base, baseName),
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
299
|
+
const child = node.child(i);
|
|
300
|
+
if (child !== null)
|
|
301
|
+
stack.push(child);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Walk the AST finding every template_declaration containing a class or
|
|
307
|
+
* struct definition with a dependent base. Records (className, baseName)
|
|
308
|
+
* pairs into the module-level state via `markCppDependentBase`.
|
|
309
|
+
*
|
|
310
|
+
* A base is "dependent" when its name (typically a template_type like
|
|
311
|
+
* `Base<T>`) uses a template parameter of the enclosing template_declaration.
|
|
312
|
+
* Conservative bias: `typename T::U`, `decltype(...)` and template-template
|
|
313
|
+
* parameter shapes are also treated as dependent.
|
|
314
|
+
*/
|
|
315
|
+
function detectCppDependentBases(root, filePath) {
|
|
316
|
+
const stack = [root];
|
|
317
|
+
while (stack.length > 0) {
|
|
318
|
+
const node = stack.pop();
|
|
319
|
+
if (node.type === 'template_declaration') {
|
|
320
|
+
// Collect template-parameter names declared by this declaration.
|
|
321
|
+
// Inner template_declarations shadow outer ones — handled by the
|
|
322
|
+
// recursive descent below (each template_declaration creates its
|
|
323
|
+
// own parameter scope).
|
|
324
|
+
const params = collectTemplateParameterNames(node);
|
|
325
|
+
// Find the class/struct definition inside this template_declaration.
|
|
326
|
+
const classNode = findChildOfType(node, ['class_specifier', 'struct_specifier']);
|
|
327
|
+
if (classNode !== null) {
|
|
328
|
+
const className = getTypeIdentifierName(classNode);
|
|
329
|
+
if (className !== '') {
|
|
330
|
+
const baseClause = findChildOfType(classNode, ['base_class_clause']);
|
|
331
|
+
if (baseClause !== null) {
|
|
332
|
+
for (const base of iterBaseClasses(baseClause)) {
|
|
333
|
+
if (isBaseDependent(base, params)) {
|
|
334
|
+
const baseName = extractBaseLookupName(base);
|
|
335
|
+
if (baseName !== '') {
|
|
336
|
+
markCppDependentBase(filePath, className, baseName);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
345
|
+
const child = node.child(i);
|
|
346
|
+
if (child !== null)
|
|
347
|
+
stack.push(child);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/** Collect simple template parameter names from a template_declaration. */
|
|
352
|
+
function collectTemplateParameterNames(templateDecl) {
|
|
353
|
+
const names = new Set();
|
|
354
|
+
const paramList = findChildOfType(templateDecl, ['template_parameter_list']);
|
|
355
|
+
if (paramList === null)
|
|
356
|
+
return names;
|
|
357
|
+
for (let i = 0; i < paramList.childCount; i++) {
|
|
358
|
+
const param = paramList.child(i);
|
|
359
|
+
if (param === null)
|
|
360
|
+
continue;
|
|
361
|
+
if (param.type === 'type_parameter_declaration' ||
|
|
362
|
+
param.type === 'optional_type_parameter_declaration' ||
|
|
363
|
+
param.type === 'variadic_type_parameter_declaration') {
|
|
364
|
+
const idNode = findFirstDescendantOfType(param, 'type_identifier');
|
|
365
|
+
if (idNode !== null)
|
|
366
|
+
names.add(idNode.text);
|
|
367
|
+
}
|
|
368
|
+
else if (param.type === 'parameter_declaration' ||
|
|
369
|
+
param.type === 'optional_parameter_declaration' ||
|
|
370
|
+
param.type === 'variadic_parameter_declaration') {
|
|
371
|
+
// Non-type template parameter (e.g. `template<int N>`).
|
|
372
|
+
const idNode = findFirstDescendantOfType(param, 'identifier');
|
|
373
|
+
if (idNode !== null)
|
|
374
|
+
names.add(idNode.text);
|
|
375
|
+
}
|
|
376
|
+
else if (param.type === 'template_template_parameter_declaration') {
|
|
377
|
+
// template-template parameter (e.g. `template<template<class> class TT>`)
|
|
378
|
+
const idNode = findFirstDescendantOfType(param, 'type_identifier');
|
|
379
|
+
if (idNode !== null)
|
|
380
|
+
names.add(idNode.text);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return names;
|
|
384
|
+
}
|
|
385
|
+
/** Yield each base-class entry from a `base_class_clause`. */
|
|
386
|
+
function* iterBaseClasses(baseClause) {
|
|
387
|
+
for (let i = 0; i < baseClause.childCount; i++) {
|
|
388
|
+
const child = baseClause.child(i);
|
|
389
|
+
if (child === null)
|
|
390
|
+
continue;
|
|
391
|
+
// Skip ':', ',', and access_specifier nodes — the base names are
|
|
392
|
+
// type_identifier, template_type, or qualified_identifier.
|
|
393
|
+
if (child.type === 'type_identifier' ||
|
|
394
|
+
child.type === 'template_type' ||
|
|
395
|
+
child.type === 'qualified_identifier') {
|
|
396
|
+
yield child;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* A base is dependent when:
|
|
402
|
+
* - it's a `template_type` and its argument list contains a
|
|
403
|
+
* `type_identifier` matching one of the enclosing template's params
|
|
404
|
+
* (e.g., `Base<T>` where `T` is a template parameter), OR
|
|
405
|
+
* - it contains a `typename`, `decltype`, or `template_template_parameter`
|
|
406
|
+
* shape (conservatively treated as dependent).
|
|
407
|
+
*
|
|
408
|
+
* Non-dependent: `Base<int>`, `ConcreteBase`, `Base<MyConcrete>` where
|
|
409
|
+
* `MyConcrete` is not a template parameter.
|
|
410
|
+
*/
|
|
411
|
+
function isBaseDependent(baseNode, templateParams) {
|
|
412
|
+
if (baseNode.type !== 'template_type') {
|
|
413
|
+
// Bare `type_identifier` or `qualified_identifier` bases — not
|
|
414
|
+
// dependent (the base name itself doesn't reference a template
|
|
415
|
+
// parameter at this level).
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
// Walk all descendants of the template_argument_list looking for any
|
|
419
|
+
// type_identifier matching a template parameter, or any conservative-
|
|
420
|
+
// dependent shape.
|
|
421
|
+
const stack = [baseNode];
|
|
422
|
+
while (stack.length > 0) {
|
|
423
|
+
const node = stack.pop();
|
|
424
|
+
if (node.type === 'type_identifier' && templateParams.has(node.text)) {
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
if (node.type === 'decltype' ||
|
|
428
|
+
node.type === 'dependent_type' ||
|
|
429
|
+
node.type === 'template_template_parameter_declaration') {
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
if (node.type === 'qualified_identifier') {
|
|
433
|
+
// `typename T::U` or `T::nested` — if any inner identifier matches
|
|
434
|
+
// a template parameter, dependent.
|
|
435
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
436
|
+
const c = node.child(i);
|
|
437
|
+
if (c !== null)
|
|
438
|
+
stack.push(c);
|
|
439
|
+
}
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
443
|
+
const c = node.child(i);
|
|
444
|
+
if (c !== null)
|
|
445
|
+
stack.push(c);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Recursively extract the bare lookup name of a base class node.
|
|
452
|
+
* Examples: `Base` → `Base`, `Base<T>` → `Base`,
|
|
453
|
+
* `outer::v1::Base<T>` → `Base`. Namespace qualifiers are intentionally
|
|
454
|
+
* dropped to align with V1 scope-chain lookup everywhere else in the
|
|
455
|
+
* registry-primary pipeline.
|
|
456
|
+
*/
|
|
457
|
+
function extractBaseLookupName(baseNode) {
|
|
458
|
+
if (baseNode.type === 'type_identifier' || baseNode.type === 'identifier')
|
|
459
|
+
return baseNode.text;
|
|
460
|
+
if (baseNode.type === 'template_type') {
|
|
461
|
+
const nameNode = baseNode.childForFieldName('name');
|
|
462
|
+
if (nameNode !== null)
|
|
463
|
+
return extractBaseLookupName(nameNode);
|
|
464
|
+
const id = findFirstDescendantOfType(baseNode, 'type_identifier') ??
|
|
465
|
+
findFirstDescendantOfType(baseNode, 'identifier');
|
|
466
|
+
if (id !== null)
|
|
467
|
+
return id.text;
|
|
468
|
+
}
|
|
469
|
+
if (baseNode.type === 'qualified_identifier') {
|
|
470
|
+
const nameNode = baseNode.childForFieldName('name');
|
|
471
|
+
if (nameNode !== null) {
|
|
472
|
+
const nested = extractBaseLookupName(nameNode);
|
|
473
|
+
if (nested.length > 0)
|
|
474
|
+
return nested;
|
|
475
|
+
}
|
|
476
|
+
for (let i = baseNode.childCount - 1; i >= 0; i--) {
|
|
477
|
+
const child = baseNode.child(i);
|
|
478
|
+
if (child === null)
|
|
479
|
+
continue;
|
|
480
|
+
const nested = extractBaseLookupName(child);
|
|
481
|
+
if (nested.length > 0)
|
|
482
|
+
return nested;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return '';
|
|
486
|
+
}
|
|
487
|
+
/** Find the first direct child matching one of the given types. */
|
|
488
|
+
function findChildOfType(node, types) {
|
|
489
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
490
|
+
const c = node.child(i);
|
|
491
|
+
if (c !== null && types.includes(c.type))
|
|
492
|
+
return c;
|
|
493
|
+
}
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
/** Recursive search for the first descendant of a given type. */
|
|
497
|
+
function findFirstDescendantOfType(node, type) {
|
|
498
|
+
if (node.type === type)
|
|
499
|
+
return node;
|
|
500
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
501
|
+
const c = node.child(i);
|
|
502
|
+
if (c === null)
|
|
503
|
+
continue;
|
|
504
|
+
const hit = findFirstDescendantOfType(c, type);
|
|
505
|
+
if (hit !== null)
|
|
506
|
+
return hit;
|
|
507
|
+
}
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
/** Get the name of a class/struct/template_type node via its `name` field. */
|
|
511
|
+
function getTypeIdentifierName(node) {
|
|
512
|
+
const nameNode = node.childForFieldName('name');
|
|
513
|
+
if (nameNode !== null)
|
|
514
|
+
return nameNode.text;
|
|
515
|
+
const id = findFirstDescendantOfType(node, 'type_identifier');
|
|
516
|
+
return id !== null ? id.text : '';
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Infer argument types from a call_expression or new_expression node.
|
|
520
|
+
* Used for overload disambiguation by parameter types.
|
|
521
|
+
*
|
|
522
|
+
* Only literal types are inferred — identifiers and complex expressions
|
|
523
|
+
* return empty string (unknown) so narrowOverloadCandidates treats them
|
|
524
|
+
* as any-match.
|
|
525
|
+
*/
|
|
526
|
+
function inferCppCallArgTypes(node) {
|
|
527
|
+
const argList = node.childForFieldName('arguments');
|
|
528
|
+
if (argList === null)
|
|
529
|
+
return undefined;
|
|
530
|
+
const types = [];
|
|
531
|
+
for (let i = 0; i < argList.childCount; i++) {
|
|
532
|
+
const child = argList.child(i);
|
|
533
|
+
if (child === null)
|
|
534
|
+
continue;
|
|
535
|
+
if (child.type === ',' || child.type === '(' || child.type === ')')
|
|
536
|
+
continue;
|
|
537
|
+
const litType = inferCppLiteralType(child);
|
|
538
|
+
if (litType !== '') {
|
|
539
|
+
types.push(litType);
|
|
540
|
+
}
|
|
541
|
+
else if (child.type === 'identifier') {
|
|
542
|
+
// Variable reference — look up declared type in enclosing scope
|
|
543
|
+
types.push(lookupDeclaredTypeForIdentifier(child));
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
types.push('');
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return types.length > 0 ? types : undefined;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Infer the canonical type name of a C++ literal AST node.
|
|
553
|
+
* Returns empty string for non-literal / unknown nodes.
|
|
554
|
+
*/
|
|
555
|
+
function inferCppLiteralType(node) {
|
|
556
|
+
switch (node.type) {
|
|
557
|
+
case 'number_literal': {
|
|
558
|
+
const text = node.text;
|
|
559
|
+
// Floating-point literals contain '.', 'e', 'E', or end with 'f'/'F'
|
|
560
|
+
if (text.includes('.') ||
|
|
561
|
+
text.includes('e') ||
|
|
562
|
+
text.includes('E') ||
|
|
563
|
+
text.endsWith('f') ||
|
|
564
|
+
text.endsWith('F')) {
|
|
565
|
+
return 'double';
|
|
566
|
+
}
|
|
567
|
+
return 'int';
|
|
568
|
+
}
|
|
569
|
+
case 'string_literal':
|
|
570
|
+
case 'raw_string_literal':
|
|
571
|
+
case 'concatenated_string':
|
|
572
|
+
return 'string';
|
|
573
|
+
case 'char_literal':
|
|
574
|
+
return 'char';
|
|
575
|
+
case 'true':
|
|
576
|
+
case 'false':
|
|
577
|
+
return 'bool';
|
|
578
|
+
case 'null':
|
|
579
|
+
case 'nullptr':
|
|
580
|
+
return 'null';
|
|
581
|
+
default:
|
|
582
|
+
return '';
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Look up the declared type of a variable by scanning sibling declarations
|
|
587
|
+
* in the enclosing compound_statement (function body). Handles:
|
|
588
|
+
* - `std::string result = ...` → 'string'
|
|
589
|
+
* - `int n = ...` → 'int'
|
|
590
|
+
* - `const int n = ...` → 'int'
|
|
591
|
+
* Returns empty string if no declaration found or type is auto/placeholder.
|
|
592
|
+
*/
|
|
593
|
+
function lookupDeclaredTypeForIdentifier(identNode) {
|
|
594
|
+
const varName = identNode.text;
|
|
595
|
+
// Walk up to the enclosing compound_statement (function body)
|
|
596
|
+
let scope = identNode.parent;
|
|
597
|
+
while (scope !== null &&
|
|
598
|
+
scope.type !== 'compound_statement' &&
|
|
599
|
+
scope.type !== 'translation_unit') {
|
|
600
|
+
scope = scope.parent;
|
|
601
|
+
}
|
|
602
|
+
if (scope === null)
|
|
603
|
+
return '';
|
|
604
|
+
// Scan declarations in the scope for a matching variable name
|
|
605
|
+
for (let i = 0; i < scope.childCount; i++) {
|
|
606
|
+
const stmt = scope.child(i);
|
|
607
|
+
if (stmt === null || stmt.type !== 'declaration')
|
|
608
|
+
continue;
|
|
609
|
+
const typeNode = stmt.childForFieldName('type');
|
|
610
|
+
if (typeNode === null)
|
|
611
|
+
continue;
|
|
612
|
+
// Skip auto/placeholder types — those need chain-follow, not literal
|
|
613
|
+
if (typeNode.type === 'placeholder_type_specifier')
|
|
614
|
+
continue;
|
|
615
|
+
// Check init_declarator children for the variable name
|
|
616
|
+
const declarator = stmt.childForFieldName('declarator');
|
|
617
|
+
if (declarator === null)
|
|
618
|
+
continue;
|
|
619
|
+
if (declarator.type === 'init_declarator') {
|
|
620
|
+
const nameChild = declarator.childForFieldName('declarator');
|
|
621
|
+
if (nameChild !== null && nameChild.text === varName) {
|
|
622
|
+
return normalizeCppTypeText(typeNode.text);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
else if (declarator.text === varName) {
|
|
626
|
+
return normalizeCppTypeText(typeNode.text);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return '';
|
|
630
|
+
}
|
|
631
|
+
/** Normalize a type-specifier text for argument type matching.
|
|
632
|
+
* Strips qualifiers (const, volatile), namespace prefixes (std::),
|
|
633
|
+
* and pointer/reference markers. */
|
|
634
|
+
function normalizeCppTypeText(text) {
|
|
635
|
+
let t = text.trim();
|
|
636
|
+
t = t.replace(/\b(const|volatile|static|extern|mutable)\b/g, '').trim();
|
|
637
|
+
t = t.replace(/^.*::/, ''); // strip namespace prefix
|
|
638
|
+
t = t.replace(/[*&]/g, '').trim();
|
|
639
|
+
return t;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Detect whether a `namespace_definition` AST node is inline.
|
|
643
|
+
* Tree-sitter-cpp exposes the `inline` keyword as an anonymous child
|
|
644
|
+
* node — we scan direct children for that keyword.
|
|
645
|
+
*/
|
|
646
|
+
function isInlineNamespace(nsNode) {
|
|
647
|
+
for (let i = 0; i < nsNode.childCount; i++) {
|
|
648
|
+
const c = nsNode.child(i);
|
|
649
|
+
if (c === null)
|
|
650
|
+
continue;
|
|
651
|
+
if (c.type === 'inline')
|
|
652
|
+
return true;
|
|
653
|
+
// Some grammar variants surface keywords by their text rather than
|
|
654
|
+
// by a dedicated node type; check both for resilience.
|
|
655
|
+
if (c.text === 'inline' && (c.type === 'storage_class_specifier' || c.type === 'inline')) {
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Detect `(f)(args)` shape — the call-expression's `function` field is a
|
|
663
|
+
* `parenthesized_expression`. ISO C++ specifies that this form suppresses
|
|
664
|
+
* ADL (`[basic.lookup.argdep]/3.1`): the parenthesized name is treated as
|
|
665
|
+
* an ordinary unqualified-lookup-only callee.
|
|
666
|
+
*/
|
|
667
|
+
function isParenthesizedFunctionCall(callNode) {
|
|
668
|
+
const fn = callNode.childForFieldName('function');
|
|
669
|
+
return fn !== null && fn.type === 'parenthesized_expression';
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Per-argument ADL classification: walk each argument of a free call and
|
|
673
|
+
* classify its declared type for associated-namespace lookup.
|
|
674
|
+
*
|
|
675
|
+
* Value/pointer/reference class-typed args and template specializations
|
|
676
|
+
* with explicit type arguments contribute; function pointers, primitives,
|
|
677
|
+
* literals, and other unsupported shapes produce an empty result.
|
|
678
|
+
*
|
|
679
|
+
* Class-typed values/pointers/references (`N::S`, `N::S*`, `N::S&`) all
|
|
680
|
+
* preserve the class name for associated-namespace lookup.
|
|
681
|
+
* Function pointers remain excluded even when their return type names a
|
|
682
|
+
* class, because the associated entity is the pointed-to function type,
|
|
683
|
+
* not the return type.
|
|
684
|
+
*/
|
|
685
|
+
function inferCppCallAdlArgs(callNode) {
|
|
686
|
+
const argList = callNode.childForFieldName('arguments');
|
|
687
|
+
if (argList === null)
|
|
688
|
+
return [];
|
|
689
|
+
const out = [];
|
|
690
|
+
for (let i = 0; i < argList.childCount; i++) {
|
|
691
|
+
const child = argList.child(i);
|
|
692
|
+
if (child === null)
|
|
693
|
+
continue;
|
|
694
|
+
if (child.type === ',' || child.type === '(' || child.type === ')')
|
|
695
|
+
continue;
|
|
696
|
+
out.push(classifyAdlArg(child));
|
|
697
|
+
}
|
|
698
|
+
return out;
|
|
699
|
+
}
|
|
700
|
+
const ADL_TEMPLATE_RECURSION_MAX_DEPTH = 8;
|
|
701
|
+
const EMPTY_ADL_ARG = {
|
|
702
|
+
simpleClassName: '',
|
|
703
|
+
templateSimpleClassName: '',
|
|
704
|
+
templateNamespace: '',
|
|
705
|
+
templateArgClassNames: [],
|
|
706
|
+
templateArgNamespaces: [],
|
|
707
|
+
};
|
|
708
|
+
function classifyAdlArg(argNode) {
|
|
709
|
+
// Literals and primitive-shaped expressions never have associated namespaces.
|
|
710
|
+
if (argNode.type === 'number_literal' ||
|
|
711
|
+
argNode.type === 'string_literal' ||
|
|
712
|
+
argNode.type === 'raw_string_literal' ||
|
|
713
|
+
argNode.type === 'char_literal' ||
|
|
714
|
+
argNode.type === 'true' ||
|
|
715
|
+
argNode.type === 'false' ||
|
|
716
|
+
argNode.type === 'null' ||
|
|
717
|
+
argNode.type === 'nullptr') {
|
|
718
|
+
return EMPTY_ADL_ARG;
|
|
719
|
+
}
|
|
720
|
+
// Qualified expression (a::b) — may be a function, variable, enum value,
|
|
721
|
+
// or static member. Record as a potential function reference; resolution
|
|
722
|
+
// time verifies via workspace lookup that a Function/Method with this simple
|
|
723
|
+
// name exists in the extracted namespace before contributing to the set.
|
|
724
|
+
if (argNode.type === 'qualified_identifier') {
|
|
725
|
+
return {
|
|
726
|
+
simpleClassName: '',
|
|
727
|
+
templateSimpleClassName: '',
|
|
728
|
+
templateNamespace: '',
|
|
729
|
+
templateArgClassNames: [],
|
|
730
|
+
templateArgNamespaces: [],
|
|
731
|
+
functionRefText: argNode.text,
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
// Variable reference — look up its declared type (preserving pointer /
|
|
735
|
+
// reference / qualified-name shape; the existing arity-narrowing helper
|
|
736
|
+
// strips this info).
|
|
737
|
+
if (argNode.type === 'identifier') {
|
|
738
|
+
const result = lookupAdlIdentifierType(argNode);
|
|
739
|
+
if (result === null) {
|
|
740
|
+
// Not found in the local compound_statement scope — could be a
|
|
741
|
+
// free-function reference (unqualified name, namespace scope).
|
|
742
|
+
return {
|
|
743
|
+
simpleClassName: '',
|
|
744
|
+
templateSimpleClassName: '',
|
|
745
|
+
templateNamespace: '',
|
|
746
|
+
templateArgClassNames: [],
|
|
747
|
+
templateArgNamespaces: [],
|
|
748
|
+
functionRefText: argNode.text,
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
return result;
|
|
752
|
+
}
|
|
753
|
+
// Other shapes (calls, member access, operators) — V1 unsupported.
|
|
754
|
+
return EMPTY_ADL_ARG;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Returns `true` when `varName` appears as a parameter name in the nearest
|
|
758
|
+
* enclosing `function_definition` or `function_declarator` that contains
|
|
759
|
+
* `identNode`. Parameters live in `parameter_list` (a sibling of the
|
|
760
|
+
* `compound_statement`), so the `compound_statement`-local declaration scan
|
|
761
|
+
* in `lookupAdlIdentifierType` would not find them — causing them to be
|
|
762
|
+
* mistakenly classified as potential free-function references.
|
|
763
|
+
*
|
|
764
|
+
* In tree-sitter-cpp a `function_definition` does NOT expose `parameters`
|
|
765
|
+
* as a direct named field; parameters live inside the nested
|
|
766
|
+
* `function_declarator`. For `function_declarator` nodes the `parameters`
|
|
767
|
+
* field IS direct. Both cases are handled below.
|
|
768
|
+
*/
|
|
769
|
+
function isIdentifierAFunctionParameter(identNode, varName) {
|
|
770
|
+
let node = identNode.parent;
|
|
771
|
+
let safety = 64;
|
|
772
|
+
while (node !== null && safety-- > 0) {
|
|
773
|
+
let params = null;
|
|
774
|
+
if (node.type === 'function_declarator') {
|
|
775
|
+
// parameters is a direct field on function_declarator.
|
|
776
|
+
params = node.childForFieldName('parameters');
|
|
777
|
+
}
|
|
778
|
+
else if (node.type === 'function_definition') {
|
|
779
|
+
// function_definition carries parameters inside its `declarator` field
|
|
780
|
+
// (which is a function_declarator). Walk through it.
|
|
781
|
+
const decl = node.childForFieldName('declarator');
|
|
782
|
+
if (decl !== null && decl.type === 'function_declarator') {
|
|
783
|
+
params = decl.childForFieldName('parameters');
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (params !== null) {
|
|
787
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
788
|
+
const param = params.namedChild(i);
|
|
789
|
+
if (param === null)
|
|
790
|
+
continue;
|
|
791
|
+
const declNode = param.childForFieldName('declarator');
|
|
792
|
+
if (declNode === null)
|
|
793
|
+
continue;
|
|
794
|
+
const leafName = extractDeclaratorLeafName(declNode);
|
|
795
|
+
if (leafName === varName)
|
|
796
|
+
return true;
|
|
797
|
+
}
|
|
798
|
+
// Only check the immediately enclosing function — do not climb further.
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
801
|
+
if (node.type === 'translation_unit')
|
|
802
|
+
break;
|
|
803
|
+
node = node.parent;
|
|
804
|
+
}
|
|
805
|
+
return false;
|
|
806
|
+
}
|
|
807
|
+
function lookupAdlIdentifierType(identNode) {
|
|
808
|
+
const varName = identNode.text;
|
|
809
|
+
let scope = identNode.parent;
|
|
810
|
+
while (scope !== null &&
|
|
811
|
+
scope.type !== 'compound_statement' &&
|
|
812
|
+
scope.type !== 'translation_unit') {
|
|
813
|
+
scope = scope.parent;
|
|
814
|
+
}
|
|
815
|
+
if (scope === null)
|
|
816
|
+
return null;
|
|
817
|
+
// Function parameters live in the enclosing function's `parameter_list`,
|
|
818
|
+
// NOT inside the `compound_statement`, so the declaration scan below would
|
|
819
|
+
// never find them and would return `null` — incorrectly triggering the
|
|
820
|
+
// free-function-reference path. Check the parameter_list first.
|
|
821
|
+
if (isIdentifierAFunctionParameter(identNode, varName)) {
|
|
822
|
+
return EMPTY_ADL_ARG;
|
|
823
|
+
}
|
|
824
|
+
let foundAsLocalFunctionPointer = false;
|
|
825
|
+
for (let i = 0; i < scope.childCount; i++) {
|
|
826
|
+
const stmt = scope.child(i);
|
|
827
|
+
if (stmt === null || stmt.type !== 'declaration')
|
|
828
|
+
continue;
|
|
829
|
+
const typeNode = stmt.childForFieldName('type');
|
|
830
|
+
if (typeNode === null)
|
|
831
|
+
continue;
|
|
832
|
+
if (typeNode.type === 'placeholder_type_specifier')
|
|
833
|
+
continue;
|
|
834
|
+
const declarator = stmt.childForFieldName('declarator');
|
|
835
|
+
if (declarator === null)
|
|
836
|
+
continue;
|
|
837
|
+
// Unwrap declarator chain to find pointer/reference markers and the
|
|
838
|
+
// variable name. `init_declarator > pointer_declarator > identifier`
|
|
839
|
+
// means pointer-typed; repeated pointer wrappers still count as pointer
|
|
840
|
+
// typed; `init_declarator > reference_declarator > ...` (or
|
|
841
|
+
// `rvalue_reference_declarator`) means reference-typed; bare
|
|
842
|
+
// `init_declarator > identifier` is value.
|
|
843
|
+
// Function-pointer wrappers (`pointer_declarator > function_declarator`)
|
|
844
|
+
// must not contribute ADL associated namespaces.
|
|
845
|
+
let isFunctionPointer = false;
|
|
846
|
+
let inner = declarator;
|
|
847
|
+
let nameText = null;
|
|
848
|
+
let safety = 16; // bound walk depth defensively
|
|
849
|
+
while (safety-- > 0) {
|
|
850
|
+
if (inner.type === 'pointer_declarator') {
|
|
851
|
+
if (findFirstDescendantOfType(inner, 'function_declarator') !== null) {
|
|
852
|
+
isFunctionPointer = true;
|
|
853
|
+
// Extract the name from within the function-pointer declarator chain
|
|
854
|
+
// so `foundAsLocalFunctionPointer` can detect a matching declaration.
|
|
855
|
+
nameText = extractDeclaratorLeafName(inner);
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
const next = inner.childForFieldName('declarator');
|
|
859
|
+
if (next === null)
|
|
860
|
+
break;
|
|
861
|
+
inner = next;
|
|
862
|
+
continue;
|
|
863
|
+
}
|
|
864
|
+
if (inner.type === 'reference_declarator' || inner.type === 'rvalue_reference_declarator') {
|
|
865
|
+
// reference_declarator has a single child (the inner declarator).
|
|
866
|
+
let next = null;
|
|
867
|
+
for (let j = 0; j < inner.namedChildCount; j++) {
|
|
868
|
+
const c = inner.namedChild(j);
|
|
869
|
+
if (c !== null) {
|
|
870
|
+
next = c;
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (next === null)
|
|
875
|
+
break;
|
|
876
|
+
inner = next;
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
if (inner.type === 'init_declarator') {
|
|
880
|
+
const next = inner.childForFieldName('declarator');
|
|
881
|
+
if (next === null)
|
|
882
|
+
break;
|
|
883
|
+
inner = next;
|
|
884
|
+
continue;
|
|
885
|
+
}
|
|
886
|
+
if (inner.type === 'function_declarator') {
|
|
887
|
+
isFunctionPointer = true;
|
|
888
|
+
// Extract the name from the inner declarator (e.g. `(*g)` in `void (*g)()`).
|
|
889
|
+
const innerDecl = inner.childForFieldName('declarator');
|
|
890
|
+
if (innerDecl !== null)
|
|
891
|
+
nameText = extractDeclaratorLeafName(innerDecl);
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
// Reached the leaf — usually `identifier`. Take its text.
|
|
895
|
+
nameText = inner.text;
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
if (nameText === varName && isFunctionPointer) {
|
|
899
|
+
// Explicitly declared as a function-pointer variable — must not be
|
|
900
|
+
// treated as a free-function reference by the caller.
|
|
901
|
+
foundAsLocalFunctionPointer = true;
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
if (isFunctionPointer || nameText !== varName)
|
|
905
|
+
continue;
|
|
906
|
+
const simpleClassName = extractAdlSimpleTypeName(typeNode);
|
|
907
|
+
const { templateSimpleClassName, templateNamespace, templateArgClassNames, templateArgNamespaces, } = extractAdlTemplateInfo(typeNode);
|
|
908
|
+
return {
|
|
909
|
+
simpleClassName,
|
|
910
|
+
templateSimpleClassName,
|
|
911
|
+
templateNamespace,
|
|
912
|
+
templateArgClassNames,
|
|
913
|
+
templateArgNamespaces,
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
// If the identifier was found in local scope as a function-pointer variable,
|
|
917
|
+
// return EMPTY_ADL_ARG so the caller does NOT treat it as a free-function
|
|
918
|
+
// reference. Otherwise return null to indicate "not in local scope".
|
|
919
|
+
//
|
|
920
|
+
// Known limitation (Finding 4): variables whose type is a typedef/using alias
|
|
921
|
+
// for a function-pointer type are NOT detected here. For example:
|
|
922
|
+
// using Callback = void (*)();
|
|
923
|
+
// Callback g;
|
|
924
|
+
// foo(g); // `g`'s declarator is `identifier` with type `Callback`
|
|
925
|
+
// The declarator has no `pointer_declarator` wrapper, so `isFunctionPointer`
|
|
926
|
+
// stays false and `extractAdlSimpleTypeName` returns `"Callback"`. ADL then
|
|
927
|
+
// looks for a class named `Callback`; if none exists, this degrades to
|
|
928
|
+
// EMPTY_ADL_ARG (class not found → no namespace contributed). If a class
|
|
929
|
+
// named `Callback` does exist, a spurious namespace contribution could occur.
|
|
930
|
+
// Risk is low in practice; a future fix should resolve the typedef/alias chain.
|
|
931
|
+
return foundAsLocalFunctionPointer ? EMPTY_ADL_ARG : null;
|
|
932
|
+
}
|
|
933
|
+
/** Extract the simple class-like type name from a `type:` field node.
|
|
934
|
+
* Returns '' for primitives and any other
|
|
935
|
+
* unsupported type-only shape. Function pointers are filtered at the
|
|
936
|
+
* declarator level in `lookupAdlIdentifierType`. */
|
|
937
|
+
function extractAdlSimpleTypeName(typeNode) {
|
|
938
|
+
if (typeNode.type === 'type_descriptor') {
|
|
939
|
+
const innerType = typeNode.childForFieldName('type');
|
|
940
|
+
if (innerType !== null)
|
|
941
|
+
return extractAdlSimpleTypeName(innerType);
|
|
942
|
+
for (let i = 0; i < typeNode.childCount; i++) {
|
|
943
|
+
const child = typeNode.child(i);
|
|
944
|
+
if (child === null)
|
|
945
|
+
continue;
|
|
946
|
+
if (child.type === 'type_identifier' ||
|
|
947
|
+
child.type === 'qualified_identifier' ||
|
|
948
|
+
child.type === 'template_type') {
|
|
949
|
+
return extractAdlSimpleTypeName(child);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
return '';
|
|
953
|
+
}
|
|
954
|
+
if (typeNode.type === 'primitive_type')
|
|
955
|
+
return '';
|
|
956
|
+
if (typeNode.type === 'sized_type_specifier')
|
|
957
|
+
return '';
|
|
958
|
+
if (typeNode.type === 'type_identifier')
|
|
959
|
+
return typeNode.text;
|
|
960
|
+
if (typeNode.type === 'template_type') {
|
|
961
|
+
const nameNode = typeNode.childForFieldName('name');
|
|
962
|
+
if (nameNode !== null)
|
|
963
|
+
return extractAdlSimpleTypeName(nameNode);
|
|
964
|
+
const id = findFirstDescendantOfType(typeNode, 'type_identifier');
|
|
965
|
+
return id !== null ? id.text : '';
|
|
966
|
+
}
|
|
967
|
+
if (typeNode.type === 'qualified_identifier') {
|
|
968
|
+
const nameNode = typeNode.childForFieldName('name');
|
|
969
|
+
if (nameNode !== null)
|
|
970
|
+
return extractAdlSimpleTypeName(nameNode);
|
|
971
|
+
const id = findFirstDescendantOfType(typeNode, 'type_identifier');
|
|
972
|
+
return id !== null ? id.text : '';
|
|
973
|
+
}
|
|
974
|
+
// Function pointers, decltype, etc — unsupported for ADL participation.
|
|
975
|
+
return '';
|
|
976
|
+
}
|
|
977
|
+
function extractAdlTypeNamespace(typeNode) {
|
|
978
|
+
if (typeNode.type === 'type_descriptor') {
|
|
979
|
+
const innerType = typeNode.childForFieldName('type');
|
|
980
|
+
if (innerType !== null)
|
|
981
|
+
return extractAdlTypeNamespace(innerType);
|
|
982
|
+
for (let i = 0; i < typeNode.childCount; i++) {
|
|
983
|
+
const child = typeNode.child(i);
|
|
984
|
+
if (child === null)
|
|
985
|
+
continue;
|
|
986
|
+
if (child.type === 'qualified_identifier' ||
|
|
987
|
+
child.type === 'template_type' ||
|
|
988
|
+
child.type === 'type_identifier') {
|
|
989
|
+
return extractAdlTypeNamespace(child);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
return '';
|
|
993
|
+
}
|
|
994
|
+
if (typeNode.type === 'template_type') {
|
|
995
|
+
const nameNode = typeNode.childForFieldName('name');
|
|
996
|
+
return nameNode !== null ? extractAdlTypeNamespace(nameNode) : '';
|
|
997
|
+
}
|
|
998
|
+
if (typeNode.type === 'qualified_identifier') {
|
|
999
|
+
const scope = typeNode.childForFieldName('scope');
|
|
1000
|
+
if (scope !== null)
|
|
1001
|
+
return normalizeCppNamespaceQName(scope.text);
|
|
1002
|
+
return extractNamespaceFromQualifiedText(typeNode.text);
|
|
1003
|
+
}
|
|
1004
|
+
return '';
|
|
1005
|
+
}
|
|
1006
|
+
function extractAdlTemplateInfo(typeNode) {
|
|
1007
|
+
const templateTypeNode = findTemplateTypeNode(typeNode);
|
|
1008
|
+
if (templateTypeNode === null) {
|
|
1009
|
+
return {
|
|
1010
|
+
templateSimpleClassName: '',
|
|
1011
|
+
templateNamespace: '',
|
|
1012
|
+
templateArgClassNames: [],
|
|
1013
|
+
templateArgNamespaces: [],
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
const templateArgClassNames = [];
|
|
1017
|
+
const templateArgNamespaces = [];
|
|
1018
|
+
collectAdlTemplateArgs(templateTypeNode, 0, templateArgClassNames, templateArgNamespaces);
|
|
1019
|
+
return {
|
|
1020
|
+
templateSimpleClassName: extractAdlSimpleTypeName(templateTypeNode),
|
|
1021
|
+
templateNamespace: extractAdlTypeNamespace(typeNode),
|
|
1022
|
+
templateArgClassNames,
|
|
1023
|
+
templateArgNamespaces,
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
function collectAdlTemplateArgs(templateTypeNode, depth, outClassNames, outNamespaces) {
|
|
1027
|
+
if (depth >= ADL_TEMPLATE_RECURSION_MAX_DEPTH)
|
|
1028
|
+
return;
|
|
1029
|
+
if (templateTypeNode.type !== 'template_type')
|
|
1030
|
+
return;
|
|
1031
|
+
const argList = templateTypeNode.childForFieldName('arguments') ??
|
|
1032
|
+
findChildOfType(templateTypeNode, ['template_argument_list']);
|
|
1033
|
+
if (argList === null)
|
|
1034
|
+
return;
|
|
1035
|
+
for (let i = 0; i < argList.namedChildCount; i++) {
|
|
1036
|
+
const arg = argList.namedChild(i);
|
|
1037
|
+
if (arg === null || arg.type !== 'type_descriptor')
|
|
1038
|
+
continue;
|
|
1039
|
+
const simpleClassName = extractAdlSimpleTypeName(arg);
|
|
1040
|
+
if (simpleClassName.length > 0)
|
|
1041
|
+
outClassNames.push(simpleClassName);
|
|
1042
|
+
const ns = extractAdlTypeNamespace(arg);
|
|
1043
|
+
if (ns.length > 0)
|
|
1044
|
+
outNamespaces.push(ns);
|
|
1045
|
+
const nestedType = arg.childForFieldName('type');
|
|
1046
|
+
const nestedTemplate = nestedType !== null ? findTemplateTypeNode(nestedType) : null;
|
|
1047
|
+
if (nestedTemplate !== null) {
|
|
1048
|
+
collectAdlTemplateArgs(nestedTemplate, depth + 1, outClassNames, outNamespaces);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
function findTemplateTypeNode(typeNode) {
|
|
1053
|
+
if (typeNode.type === 'template_type')
|
|
1054
|
+
return typeNode;
|
|
1055
|
+
if (typeNode.type === 'type_descriptor') {
|
|
1056
|
+
const innerType = typeNode.childForFieldName('type');
|
|
1057
|
+
if (innerType !== null)
|
|
1058
|
+
return findTemplateTypeNode(innerType);
|
|
1059
|
+
return null;
|
|
1060
|
+
}
|
|
1061
|
+
if (typeNode.type === 'qualified_identifier') {
|
|
1062
|
+
const nameNode = typeNode.childForFieldName('name');
|
|
1063
|
+
if (nameNode !== null)
|
|
1064
|
+
return findTemplateTypeNode(nameNode);
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
function normalizeCppNamespaceQName(text) {
|
|
1070
|
+
const normalized = text.replace(/^::/, '').replace(/::$/, '').replace(/::/g, '.');
|
|
1071
|
+
return normalized;
|
|
1072
|
+
}
|
|
1073
|
+
function extractNamespaceFromQualifiedText(text) {
|
|
1074
|
+
const cleaned = text.replace(/\s+/g, '');
|
|
1075
|
+
const idx = cleaned.lastIndexOf('::');
|
|
1076
|
+
if (idx <= 0)
|
|
1077
|
+
return '';
|
|
1078
|
+
return normalizeCppNamespaceQName(cleaned.slice(0, idx));
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Walk a declarator node chain, unwrapping pointer/reference/function/
|
|
1082
|
+
* parenthesized wrappers, and return the text of the innermost identifier.
|
|
1083
|
+
* Returns `null` when no identifier is found within `safety` steps.
|
|
1084
|
+
* Used by `lookupAdlIdentifierType` to extract the variable name from
|
|
1085
|
+
* function-pointer declarator trees such as `(*g)()` in `void (*g)()`.
|
|
1086
|
+
*/
|
|
1087
|
+
function extractDeclaratorLeafName(node) {
|
|
1088
|
+
let cur = node;
|
|
1089
|
+
let safety = 16;
|
|
1090
|
+
while (safety-- > 0) {
|
|
1091
|
+
if (cur.type === 'identifier' || cur.type === 'type_identifier')
|
|
1092
|
+
return cur.text;
|
|
1093
|
+
// Common wrapper nodes — follow the 'declarator' field when present.
|
|
1094
|
+
const next = cur.childForFieldName('declarator') ??
|
|
1095
|
+
// parenthesized_declarator: single named child
|
|
1096
|
+
(cur.type === 'parenthesized_declarator' ? cur.namedChild(0) : null);
|
|
1097
|
+
if (next === null)
|
|
1098
|
+
return null;
|
|
1099
|
+
cur = next;
|
|
1100
|
+
}
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Check if a C++ function_definition or declaration has `static` storage class.
|
|
1105
|
+
*/
|
|
1106
|
+
function hasStaticStorageClass(node) {
|
|
1107
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
1108
|
+
const child = node.child(i);
|
|
1109
|
+
if (child !== null && child.type === 'storage_class_specifier' && child.text === 'static') {
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return false;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Check if a node is inside an anonymous namespace (file-local linkage in C++).
|
|
1117
|
+
* Anonymous namespaces have no `name` field in tree-sitter-cpp.
|
|
1118
|
+
*/
|
|
1119
|
+
function isInsideAnonymousNamespace(node) {
|
|
1120
|
+
let ancestor = node.parent ?? null;
|
|
1121
|
+
while (ancestor !== null) {
|
|
1122
|
+
if (ancestor.type === 'namespace_definition') {
|
|
1123
|
+
// Anonymous namespace: has declaration_list but no name child
|
|
1124
|
+
const nameChild = ancestor.childForFieldName?.('name') ?? null;
|
|
1125
|
+
if (nameChild === null)
|
|
1126
|
+
return true;
|
|
1127
|
+
}
|
|
1128
|
+
ancestor = ancestor.parent;
|
|
1129
|
+
}
|
|
1130
|
+
return false;
|
|
1131
|
+
}
|