Commit Graph
2 Commits
Author SHA1 Message Date
ba209d9489 feat(c/c++): resolve function-pointer dispatch (#932) (#954)
C/C++ polymorphism is the function pointer: a struct fn-pointer field, concrete
functions registered into it through a table (`{"add", cmd_add}`), a designated
initializer (`.handler = on_open`), or an assignment, then dispatched indirectly
(`p->fn(argv)`). Static extraction captures neither the registration→field
binding nor the indirect call, so the dispatcher→handler edge was missing — git's
run_builtin looked like it called nothing, a vtable's implementations had no
callers, and the hook_demo.c in the issue was unreachable.

Add a resolution-layer synthesizer keyed by (struct type, fn-pointer field). It
reads source (the established Celery/Sidekiq/Spring pattern — C extraction has no
struct fields or indirect-call edges to build on) in passes: collect fn-pointer
typedefs, parse struct field layouts, collect registrations (positional matched
by field index, designated, and assignment), propagate field←field assignments
(so a generic hook slot reassigned from a registry — the hook_demo.c
`h->func = found->fn` shape — inherits the registry field's handlers), then link
each indirect dispatch site to the registered handlers. Receiver type resolves
from the enclosing function's params/locals, falling back to a field name unique
to one struct. Covers both the command-table idiom (git, redis) and the
ops-struct/vtable idiom (curl content-encoders, protocol handlers).

Pure edge synthesis (no node growth); high precision via the (struct, field) key.

Validated: git 502 edges (run_builtin→cmd_* plus git_hash_algo/archiver/reftable
vtables), redis 357 (dictType.hashFunction, connection + reply-object vtables),
curl 478 (Curl_cwtype.do_init → deflate/gzip/brotli/zstd); 0 non-function targets
on all three; node-stable; 0 on the lua control (its {name,fn} tables register
into the Lua VM, with no C indirect call to bridge). Full suite 1665 pass.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 13:34:11 -05:00
74327814ee feat: wire up framework route extraction (#89)
* docs: add framework extract wiring plan

* feat(resolution): replace extractNodes with extract() returning nodes and references

* feat(resolution): add getApplicableFrameworks helper for per-language dispatch

* feat(django): emit route nodes and route->view references in extract()

* feat(flask,fastapi): emit route nodes and route->handler references

* feat(express): emit route nodes and route->handler references

* feat(laravel): emit route nodes and route->handler references

* feat(rails): emit route nodes and route->handler references

* feat(spring): emit route nodes and route->handler references

* feat(go): emit route nodes and route->handler references

* feat(rust): emit route nodes and route->handler references

* feat(aspnet): emit route nodes and route->handler references

* feat(swift,vapor): emit route nodes and route->handler references

* chore(react,svelte): migrate resolvers to extract() interface

* feat(extraction): run framework extractors after tree-sitter parse

* docs: document framework route extraction

* feat(strip-comments): add per-language comment stripper for framework extractors

Replaces comment characters and string-literal contents with spaces (not
removal) so source offsets stay valid for downstream regex match index ->
line number conversion. Handles Python triple-quoted docstrings, Ruby
=begin/=end, Rust nested block comments, and the standard //, #, /* */
forms across the supported languages.

This is consumed by framework extract() methods in a follow-up commit so
that commented-out / docstring routing examples don't surface as phantom
route nodes in the graph.

* feat(frameworks): strip comments before regex extraction (prevents phantom routes)

Pipes the per-language stripCommentsForRegex helper into every framework
extract() that scans raw source: django/flask/fastapi (python.ts),
express, laravel, rails, spring, go, rust, aspnet, vapor, plus
swiftui/uikit struct extraction in swift.ts.

Without this, examples like:

    # path('/admin/', AdminPanel.as_view())
    """ path('/users/', UserListView.as_view()) """
    urlpatterns = [path('/real/', RealView.as_view())]

produced 3 phantom route nodes. Now only the real one is extracted.

Each framework gets a regression test in __tests__/frameworks.test.ts
asserting that line-, block-, docstring- and (where relevant)
heredoc-style commented-out routes do not surface as nodes.

---------

Co-authored-by: Colby McHenry <me@colbymchenry.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:03:33 -05:00