Repository navigation
fix(c,cpp): a name in C or C++ code outside tests links to what the file's own includes declare - #2684
Merged
Conversation
…ile's own includes declare #2675 narrowed a C or C++ test's same-named candidates to the ones its translation unit declares. Production code now gets the same rule: protobuf's Python extension called the copies of upb's C API that the PHP extension bundles in php-upb.c, and its Java generator's calls of the free HasHasbit() went to ImmutableFieldGenerator::HasHasbit, a method beside the caller. Refinements the wider scope needed: - a source implements the same-stem header beside it, when it includes one: pyext/message.cc is no implementation of google/protobuf/message.h; - a header's own overloads reach the definitions its source holds: conformance/binary_wireformat.h's template Varint calls the .cc's; - narrowing never leaves a call with only functions its arguments can't fill, past one outside the unit that they can: glog's three-argument GetStackTrace(...) is not utilities.h's GetStackTrace(). This also mends 9 breakpad unittest calls #2675 had narrowed the same way; - nor, for a C call, to definitions only a flag nothing sets compiles, past one the build without it does: that stays #2615's choice. A file-level "call" (a macro, or a declaration read as a call) is left as it was. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 19, 2026
Merged
danusha2345
pushed a commit
to danusha2345/codegraph
that referenced
this pull request
Oct 20, 2026
…he name strategies; colbymchenry#1938/colbymchenry#1954 tests follow upstream's colbymchenry#2684/colbymchenry#2664 The same changes went into the rebased PR branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
What
#2675 made a C or C++ test link a name that several files declare to the one its translation unit declares. This applies the same rule to every C and C++ reference. Of the same-named candidates, the ones the file's unit declares come first:
static, an unnamed namespace, or a class only it declares.When the unit declares none of them, the candidates stay as they were, so it never guesses outside the unit.
On main f43432c, production code took whichever namesake the ranking put first:
python/*.c), its Lua binding (lua/*.c), the hpb backend and the benchmarks called the copies of upb's C API that the PHP extension bundles inphp-upb.c, or left them unlinked. Example:upb_Encode→upb/wire/encode.c,upb_Arena_New→upb/mem/arena.h.HasHasbit(descriptor)andIsRealOneof(field)thatjava/helpers.hdeclares. Main linked those calls toImmutableFieldGenerator::HasHasbit/IsRealOneof, member functions in the folder beside the callers.StringToHex(…)(58 calls) reaches the function itsdb_stress_common.hdeclares, notLDBCommand::StringToHex.CompressionTypeToString,EncodeKeyandNewWritableFilecalls that main left unlinked now link.Roundup/TruncateToPageBoundaryreachutil/aligned_buffer.h, notPosixMmapFile's methods.Random(123)reaches rocksdb'sRandom, not vendored gtest's.GetStackTrace()reaches utilities.cc's.AddLogSink,RemoveLogSinkandFlushLogFilesUnsafenow link to logging.cc.What the wider scope needed
Each item was measured with its own arm.
A source implements the header beside it. A source can include two headers named like it: protobuf's
python/google/protobuf/pyext/message.ccincludesgoogle/protobuf/pyext/message.handgoogle/protobuf/message.h. Read as implementing both, its freecmessage::MergeFromjoined every unit that includesmessage.h, and 33 generatedCopyFrombodies'MergeFrom(from)went there. Now, when a source includes a same-stem header in its own folder, only that one counts. With none beside it, all count, as in fix(c,cpp): a name in a C or C++ test links to what the test's own includes declare #2675: fmt'ssrc/format.ccimplementsinclude/fmt/format.h.A header's own overloads. A header's inline overload that calls the one its source defines is in the header's own unit. Example: protobuf's
conformance/binary_wireformat.hhastemplate <typename T> Wire Varint(T x) { return Varint(static_cast<uint64_t>(x)); }. Without this, 30 such calls narrowed to the header's own overload, injson/json.h, the cpp generator'shelpers.h,binary_wireformat.hand others.Argument count. Narrowing never leaves a call with only functions that can't take its arguments when a candidate outside the unit can. Without this, 4 production calls went wrong:
GetStackTrace(stack, ARRAYSIZE(stack), 1)calls went to utilities.cc'sGetStackTrace(). They mean the functionstacktrace.hdeclares, which thestacktrace_*-inl.hheaders thatstacktrace.ccincludes define.safe_readlink.htemplate's 3-argumentSafeReadLink(…)linked to the 2-parameter template itself.safe_readlink.cc, which defines the 3-parameter function, never includes its header.The guard also fixes 9 breakpad unittest calls that fix(c,cpp): a name in a C or C++ test links to what the test's own includes declare #2675 had narrowed the same wrong way. One limit: the check reads the definition's parameter list, which may not show what a call relies on, such as a default written only on the header's declaration. 35 calls like rocksdb's
CancelAllBackgroundWork(db)therefore keep main's target at main's confidence instead of 0.9.fix(c): a header's definition for a flag nothing sets, like lua-cjson's
#ifdef USE_INTERNAL_FPCONVfpconv_init, gives way to the source file the build compiles #2615's flag-only definitions. For a C call, narrowing doesn't leave only definitions that a flag nothing sets compiles, when the build without it compiles another. That choice stays fix(c): a header's definition for a flag nothing sets, like lua-cjson's#ifdef USE_INTERNAL_FPCONVfpconv_init, gives way to the source file the build compiles #2615's: fixturefpx/use.ccalls thefpx.cthat never includesfpx.h, not the header's#ifdef FPX_FASTdefinition. The full suite'sc-feature-macro-variants.test.tscaught this. It changes nothing in the 9 repos.A file-level "call" is left alone. A call outside any function is a macro, or a declaration read as a call, like the prototypes in rocksdb's
c.h.A/B (main f43432c vs this branch)
Full indexes with the same kernel. A site is (kind, source node, line, col, refName). I checked that main f43432c indexes these 9 repos byte-identically to main 24ea3c5, where most of the triage below was done. The branch was then rebased onto 22e9f7b. The three commits in between (#2680–#2682) change Go extraction and which build folders under
src/are scanned for TypeScript and friends; nothing on the C/C++ resolution path.Confidence only. The target is the same, but it is now the only candidate the unit declares, so
exact-match0.4/0.7 → 0.9. Of protobuf's sites, 15,492 went 0.7 → 0.9 and 5,901 went 0.4 → 0.9. rocksdb has 87 at 0.4 → 0.5: a C++ caller and a header indexed as C (see Notes).Triage
I read every (before → after target) group and sampled the large ones by file pair. I also checked argument counts mechanically: for each retargeted or added call, the number of arguments against the parameters of its new target. That check found the glog and breakpad cases the guard now handles. What it still flags is receiver guesses that were wrong before too, defaults declared on a header, macro wrappers, and calls whose arguments my audit script misread.
Right, or main's wrong target replaced by the right one:
upb_generator47, the benchmarks 37, the Lua binding 29;HasHasbit×22 andIsRealOneof×15;ReadTag(ptr, &tag)→internal::ReadTag, notCodedInputStream::ReadTag;GetClassData(*lhs)→internal::GetClassData;UnknownFieldParse(tag, std::string*, …)→parse_context.cc's overload;QualifiedClassName(d, Options())→ the cpp generator's ownOptions, not the C# generator's.StringToHex×58,Roundup×9,TruncateToPageBoundary×8,Info(logger_, …)×6 → the free functions;Random×14;db_full->WaitForCompact(…)→DB::;rocksdb_*C API fromexamples/*.c→db/c.cc;CopyFile(fs, …)→file/file_util.cublasCheck(…)×34 → thellmc/cublas_common.hthe programs include, and other functions from the sources they include.SafeReadLink×9;CreateGUID→guid_creator.cc.Wrong → wrong:
fs_->DeleteFile(…)wasFileTemperatureTestFSand is nowFaultInjectionTestFS;debug_iter->Valid()wasArenaWrappedDBIterand is nowSequenceIterWrapper;writable_file_->Close(…)was the enclosing wrapper and is nowWritableFile; the receiver is anFSWritableFile.Hash()(t)×7, a functor built from a template parameter, was a struct and is nowutil/hash.cc'sHashfunction.X::default_instance()/X::descriptor()guesses.using ptr = void*; callback(ptr());, which is no call.Right → wrong:
block_cache_tracer_->is_tracing_enabled()×4 in a header:BlockCacheTracer→IOTracer. Both headers are in the unit, and the receiver-word guess picks the other one.Removed, all wrong guesses:
debug_iter->GetProperty(…)→ArenaWrappedDBIter;FLAGS_block_cache_trace_file.empty()→BlockBuilder::empty;thread_.Get()→ThreadStatusUpdater::Get;Hash()(t)constructions.Options()→ the C# generator'sOptions, replaced by the cpp generator's;SourceCodeInfo::default_instance()→CodeGeneratorResponse_File;map->end()/erase()on astd::map→ protobuf'sMap.memory_blocks_.size()→MemoryMappedFile::size;line_map_.end()→StaticMap::end.Cost
Full indexes, interleaved main/branch, 3 rounds, same kernel:
The check runs for each C/C++ reference with two or more candidates, and now for production references too, not only tests'. It reuses the memoized include graph and same-stem header lists. The argument count is read only when narrowing would actually drop a candidate for a call.
Tests
__tests__/cpp-translation-unit.test.ts, 5 cases:upb_Encodefrom a Python-extension-shaped file reachesupb/wire/encode.c, not a PHP-bundled copy;HasHasbit(descriptor)reacheshelpers.h's free function, not the field generator's method beside it;GetStackTrace()reaches utilities.cc's (the 3-argument call beside it keeps the stacktrace definition).Varintcalls its source'sVarint;pyext/message.ccis no implementation ofgoogle/protobuf/message.h.Each refinement was checked by mutation: without the argument-count guard, without the same-folder rule, and without the own-header rule, exactly the matching test fails. #2675's
cpp-test-translation-unit.test.tsstill passes.The full suite runs on this change on main 22e9f7b, with the kernel built,
CODEGRAPH_KERNEL_EXPECT=1and--maxWorkers=4 --minWorkers=1: 7,528 passed, 0 failed, 80 skipped. An earlier run, before refinement 4, failedc-feature-macro-variants.test.tstwice; those two tests are what pin it.Notes
php-upb.c. The upb source that defines them includes only its internal header, for exampleupb/reflection/field_def.c→upb/reflection/internal/field_def.h, which then includes the public one the Python code includes. So the unit doesn't see that source as the implementation. Following a source's same-stem includes through such an internal header would close it. That's its own change and needs its own A/B, so I'll take it as the next follow-up.db_stress_tool/db_stress_common.hhas its first C++ construct past the 8 KB that the language check samples, so it is indexed as C. That is why itsStringToHexlost toLDBCommand::StringToHexon main: the ranking skips a C candidate for a C++ caller. In the 9 repos, it's the only header indexed as C for that reason, so I'm not changing the language check here.::boundary fix lives on another branch.🤖 Generated with Claude Code