Commit Graph
3 Commits
Author SHA1 Message Date
2ff7a99c0e fix(cpp): bound the macro-visibility include walk (#2127) (#2292)
* fix(cpp): bound the macro-visibility include walk (#2127)

isVisibleCppMacro walks the call site's translation unit to learn whether a
function-like macro is visible there (#1838). A header whose guard the walk
cannot decide -- `#define X_H 1` (the OpenSceneGraph / osgEarth idiom, which
guardsItself does not read as a guard), or any header reached under an
unknown `#if`, where neither its guard nor `#pragma once` settles -- was re-scanned on
every inclusion path, and every re-scan pushed its define events onto the
cached timeline again. On a layered include graph that is 2^depth scans and
2^depth timeline entries: "Resolving refs" died with "Ineffective
mark-compacts near heap limit" at the first ref whose file reached such a
tree, at the same ref whatever the heap size.

The walk now keeps a version that every observable change bumps
(definitions, `#pragma once`, the macro-name set). A re-entry with the same
inherited truth, while the version still equals that of an earlier visit
which itself changed nothing, is skipped: it would start from the same state,
take the same branches and change nothing again, and the events it would push
repeat each macro's current state, already its last event. Include cycles cut
by the recursion stack are recorded per visit and must still be cut for a
skip. A hard budget of 1M directive events per walk bounds what is left;
past it the timeline is unknown and nothing at or after the cut line is
suppressed, so the budget can only fall back to ordinary resolution, never
invent a macro.

Answers are unchanged: 20,000 random include graphs (guards bare / valued /
pragma once / under flags, #if/#elif/#else, #undef, cycles) give identical
isVisibleCppMacro results to the previous walker on 1.25M queries, with
about one re-entry in eight skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 73db32f81a)

* docs(changelog): credit the C/C++ macro walk bound

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:49:00 +00:00
Colby MchenryandClaude Opus 5.5 15a5d1d0cd fix(c): keep an #undef under an undecidable #if unknown; a macro call never binds to a type (#2069, #2070) (#2081)
Two follow-ups to the unreleased macro-visibility work (#1838/#1839):

- #2069: `#undef FLAG` under an `#if` nothing in the source decides made a
  never-seen FLAG certainly undefined, so `#ifdef FLAG` was read as false
  and the functions it guards lost their callers (CPython's
  `Py_GIL_DISABLED`). A name no directive has touched is now unknown; only
  an #undef on a certain line clears it.
- #2070: dropping the macro constant from a call's candidates let the next
  same-named node win, so expat's `PREFIX(scanRef)(...)` instantiated an
  unrelated `struct PREFIX`. When the name is a function-like macro in the
  project, only a function or method is an eligible callee.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 00:46:41 +00:00
fa25883ab0 fix(cpp): resolve local constructors and macro visibility (#1839) (#2035)
* fix(cpp): macro invocations are not calls; local objects call their constructor

A function-like macro invocation (`TRACE_POINT(1)`) parses as a call, and
the resolver bound it to a same-named free function in another translation
unit — a caller and a callee that never existed (#1838). And local object
initialization (`Widget w;` / `Widget w(1);` / `Widget w{1};`) reached the
class node instead of a constructor, or nothing at all for the default
form (#1839).

Extraction (wasm walker and the Rust kernel, in parity):
- every `preproc_function_def` becomes a `constant` node whose signature
  is the directive, so the index knows which names are macros;
- a C++ declaration emits one `calls` ref per constructed object, shaped
  `ns::T::T/<arity>`; pointer, reference and function declarators,
  `extern`, and array element braces construct nothing; the #1035
  `instantiates` ref is unchanged;
- constructors carry their parameter list as the signature.

Resolution:
- `cpp-macro-visibility.ts` walks the translation unit (root file plus
  in-repo includes, each file once) over per-file summaries of
  function-like defines, undefs and includes, evaluating what each file
  can decide itself (literals, its own defines, the include-guard idiom).
  A call whose name is definitely a macro at that point, or a name that
  only macros bear, resolves to nothing. A macro that exists in one build
  configuration only (CMSIS's `__DSB()` under the ARM compilers, a
  target's HAL compat header) keeps the call to the function the other
  configuration compiles; a wrapper macro that calls its own name is how
  that function gets called and hides nothing.
- `cpp-constructor.ts` resolves the constructor refs: the type in the
  lexical namespaces of the call site, then the single overload whose
  parameter count admits the arguments; two admitting overloads, an
  initializer_list overload, or an aggregate yield no edge.
- a `#define` constant is never a `calls` target and does not count
  toward the same-name ceiling.

Measured on a betaflight tree (4,017 files, wasm arm): 153 `calls` edges
lost — all fabricated (`MIN`/`MAX` bound to a CLI enum member, macros
misparsed as functions, a cross-vendor `SWAPBYTE`) — and 34 constructor
edges gained; indexing 34s vs 30s.

Fixes #1838
Fixes #1839

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(cpp): resolve local constructors and macro visibility (#1839)

Local construction lacked constructor calls, while macro invocations could bind unrelated functions.
Resolve constructors using lexical types and overload signatures, preserving separately declared defaults and array element construction.
Evaluate macro directives in translation-unit order, respecting reinclusion, guards and pragma once.
Mirror extraction in Rust and WASM, preserve type dependencies, and distinguish them in CLI output.

Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-27 13:46:34 +00:00