Repository navigation
fix(cpp): a declaration inside a string literal is not a receiver's declaration - #2531
Merged
Merged
Conversation
…eclaration C++ receiver inference reads back from a call for a line that declares the receiver, blanking comments (cppCodeOf) but not string literals. Text inside one was taken for the declaration: - protobuf's upb generator emits C code from raw strings: `GenerateRepeatedSetters(upb::FieldDefPtr field, …)` writes `upb_MiniTableField field = $field_init$;` inside an `R"cc( … )cc"`, then calls `field.ctype()` on its own parameter. The scan found the template's line first, and the call got no edge (a C struct has no methods). - rocksdb's log messages read as declarations: `"… in WriteBatch handler; …"` made `handler` a `WriteBatch`, and `"… remote compaction (…"` gave `compaction` the type `remote`, so calls fell to guesses by the method's name. New cpp-raw-strings.ts reads a file once, when it holds `R"`, as the compiler does (comments, string and character literals, raw strings with their delimiters), and keeps the column ranges each raw string takes per line. The receiver scan, in the file and its header, blanks those and the contents of the line's ordinary string and character literals before cppCodeOf. A character literal holding a quote (`'"'`), a digit separator (`1'000`) and an `R"(` inside a comment don't hide the code after them. 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.
Summary
C++ receiver inference no longer takes text inside a string literal for the receiver's declaration. Follow-up to #2493, which found the raw-string case in protobuf's upb generator.
Why
inferCppReceiverTypereads back from a call for the first line that declares the receiver. It blanks comments (cppCodeOf) but not string literals, so a declaration-shaped text inside one won:R"cc( … )cc"templates.GenerateRepeatedSetters(upb::FieldDefPtr field, …)writesupb_MiniTableField field = $field_init$;inside one, then callsfield.ctype()on its own parameter. The scan found the template's line, tookfieldfor the C structupb_MiniTableField(no methods), and the call got no edge (before fix(cpp): a call on a declared pointer, value or reference reaches the class its type names, not a namesake #2493, a guess)."… in WriteBatch handler; …"madehandleraWriteBatch;"… Starting remote compaction (…"gavecompactionthe typeremote;"…(rejected; output buffer … of input)"gaveinputthe typeof. Those calls fell to guesses by the method's name, or to nothing.What changed
src/resolution/cpp-raw-strings.ts:cppRawStringLines(file)reads a file once, only when it holdsR", the way the compiler does: comments, ordinary string and character literals, and raw strings (R,u8R,uR,UR,LR; delimiters up to 16 characters). It keeps, per line, the column ranges each raw string literal takes. Memoized per file, cleared with the other name-matcher memos.cppLiteralsBlanked(text, line, rawLines)blanks those ranges plus the contents of the line's ordinary string and character literals, columns kept. A character literal holding a quote ('"'), a digit separator (1'000) and a quote orR"(inside a/* … */don't hide the code after them.inferCppReceiverTyperuns each candidate line through it beforecppCodeOf, in the calling file and in its header.Validation
Main
80e4b459vs this branch, full index of each repo (kernel included), dumps compared by natural keys, every changed call site joined to where main's scan found the receiver's declaration:rocksdb, 89 — all improvements:
compaction->…on aCompaction*,handler->…on aWriteBatch::Handler*.handler->PutCF(…)-style calls reachWriteBatch::Handler. 17 chained calls likecompaction->column_family_data()->GetID()reachColumnFamilyData/Versionnow thatcompaction's type is read. 2limiter->GetName()reachConcurrentTaskLimiter.Slice:input.size()wasCompactionInputFiles::size,key.ToString()was a stress test'sKeyGenerator::ToString.TestPartResultArray::sizeandFilePath::c_stron twostd::strings, andDBIter::ValueColumnsState::valueon astd::optional<Slice>.protobuf, 25:
upb::FieldDefPtrparameters (ext.message_type(),ext.name(), …), formerly shadowed by declarations in its raw-string templates.file->name()→CodeGeneratorResponse_File::name, triggered by the string"…expected prefixes file (".autolocal whose initializer the scan can't type:auto oneof = message->oneof_decl(i);andconst auto* value = enum_->value(j);. Before, a declaration inside a string literal above it stopped the scan (no edge, right by accident). Now the scan reaches theauto, keeps going as it always has for an unreadableauto, and the call falls to the existing name guess (upb::OneofDefPtr::name,EnumValue::options). That fallback predates this change.Tests
__tests__/cpp-string-literal-declarations.test.ts(3 cases):)inside);printer->Print("Stub* runner = nullptr;")).Both fail on main and pass here. A guard passes on both: a declaration after
'"', a digit separator, or a/* R"( … */on the same line is still read. A naive line blanker fails it.The C++ resolution suites pass: 313 tests, 0 failures.
CPU (process CPU time of a full index, interleaved runs): rocksdb main 128.0 / 123.7 s vs this branch 136.4 / 121.3 s; protobuf 278.8 / 288.2 s vs 286.7 / 273.4 s. No measurable cost: a file is read for raw strings only when it contains
R", once.🤖 Generated with Claude Code