Skip to content

fix(cpp): a -> call on a declared container iterator calls the element's method - #2576

Merged
colbymchenry merged 1 commit into
mainfrom
claude/cpp-iterator-arrow
Oct 15, 2026
Merged

colbymchenry merged 1 commit into
mainfrom
claude/cpp-iterator-arrow

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Summary

This is the follow-up left after #2573.

A -> call on a C++ receiver declared as a container's iterator was matched by the method's name alone. Examples: std::deque<Slice>::const_iterator it; it->data(), and std::vector<std::string>::const_iterator itr; itr->c_str(). Such a call could reach any class with a method of that name: in rocksdb, itr->c_str() reached gtest's FilePath::c_str.

A -> on an iterator now reaches the container's element, the same way -> on a smart pointer already reaches what it holds (matchCppHeldTypeCall):

  • A new cppArrowTarget reads the element from the container's template arguments (cppRangeElementOf). It does this before the container's own iterator alias is followed, because following it would lose those arguments: protobuf's RepeatedPtrField<T>::iterator is a typedef of internal::RepeatedPtrIterator<Element>.
  • So the -> branch now also takes declarations read through an alias. Holders are unaffected, since cppHeldType only matches the literal std::unique_ptr<…>-style spellings.
  • The element is looked up as C++ does.
  • A library element (std::string) or the caller's own template parameter calls no project method, as with std::unique_ptr<T>.
  • Some elements are written only by a class template's own begin()/operator*, using its parameter (googletest's ParamGenerator<T>::iterator). Only the specialization decides those, so their calls go on as before.

Validation

  • New test __tests__/cpp-iterator-arrow.test.ts (5 tests): 4 fail on main and pass here. The ParamGenerator guard passes on both.
  • Mutations: switching off each part fails its test:
    • the iterator target: 4 tests;
    • taking aliased declarations: 1;
    • the class-template guard: 1;
    • the caller's-own-parameter branch: 1;
    • reading the container before the alias: 1.
  • A/B (full index, main vs fix) on google/leveldb, fmtlib/fmt, redis (C control), facebook/rocksdb and protocolbuffers/protobuf. Every site was triaged:
    • rocksdb, 13 added:
      • stringappend2.cc's it->data() and it->size() on a std::deque<Slice>::const_iterator now reach Slice;
      • 11 calls in data_structure.h on auto it = findPosition(i) reach Interval::start, end and has_end. findPosition returns std::vector<Interval<Slice, Comparator>>::iterator. They land on the primary template's methods, the same targets main already gives . calls on that type in the same function.
    • rocksdb, 1 removed: itr->c_str() on a std::vector<std::string>::const_iterator had linked to gtest's FilePath::c_str. It now links to nothing, which is correct for a std::string element.
    • fmt and rocksdb, 1 metadata-only change each: the vendored gtest's property_with_matching_key->SetValue on a std::vector<TestProperty>::iterator keeps its target, with confidence up from 0.7/0.65 to 0.9.
    • leveldb, redis and protobuf: byte-identical. protobuf's iterator calls are on messages generated into descriptor.pb.h, which is 1.04 MB, just over the 1 MiB source-file cap. So it's indexed with no nodes, and those calls go on as before.
  • Full suite: 7,139 passed and 1 failed. The failure was daemon-pid-reuse.test.ts (MCP daemon takeover after SIGKILL), a process-timing test unrelated to resolution; it passed twice when rerun alone.

Remaining, out of scope: iterators that are auto locals initialized by a library container's begin()/find() (about 80 it->m() sites across rocksdb and protobuf), and (*it)->m() / (*it).m() dereferences (about 30). Each needs its own typing step.

🤖 Generated with Claude Code

…ent's method

`std::deque<Slice>::const_iterator it; it->data()` was matched by the
method's name alone, so it could reach any class with a `data`, and
`itr->c_str()` on a `std::vector<std::string>::const_iterator` reached
gtest's `FilePath::c_str`. A `->` on a value of an iterator type now
reaches the container's element, as `->` on a smart pointer reaches what it
holds: the element is read from the container's template arguments
(cppRangeElementOf), before the container's own `iterator` alias would
lose them (protobuf's `RepeatedPtrField<T>::iterator`), and looked up as
C++ does. A library element (`std::string`) or the caller's template
parameter calls no project method. An element only a class template's own
`begin()`/`operator*` writes with its parameter (googletest's
`ParamGenerator<T>::iterator`) goes on as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@colbymchenry
colbymchenry merged commit 8fe3156 into main Oct 15, 2026
@colbymchenry
colbymchenry deleted the claude/cpp-iterator-arrow branch October 15, 2026 16:36
colbymchenry added a commit that referenced this pull request Oct 15, 2026
…s the element's method through `->` (#2579)

`auto it = logs_.begin(); it->IsSyncing()` had no type for `it`: a call
on a library container (`std::deque<LogWriterNumber>`) returned nothing
the auto-local reader could use, so `->` calls on it were matched by the
method's name. A standard or abseil container's `begin`/`end`/`find`/
`lower_bound`/`rbegin`/… now types as `<container>::iterator`, and a
standard search (`std::lower_bound`, `std::find_if`, `std::next`, …) as
the iterator it is given first; #2576's cppArrowTarget then reaches the
container's element.

The element is looked up where the container's type is written (the
`auto` local's declared site, a data member's class), not where the call
is: an element nested in another class (`vs->obsolete_files_.begin()`)
finds that class's type, not a namesake visible at the call. A holder's
type stays looked up at the call: from a pimpl member's header the lookup
finds a namesake (protobuf's other `DescriptorIndex`) or nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant