Receiver inference reads a C++ declaration as a type followed by the
name. What may stand between them was read as the type: in rocksdb's
`Iterator* const iter = iter_guard.get();` the type was `const`, which
names nothing, so the scan went on to an earlier function's `iter`, and
in protobuf's `io::EpsCopyOutputStream* PROTOBUF_NONNULL stream` the
type was a class named `PROTOBUF_NONNULL`. A name an annotation follows
(leveldb's `MemTable* imm_ GUARDED_BY(mutex_);`) was not read at all.
- The declarator regex (and the range-for type tail) reads past a cv-
qualifier or `__restrict` before or after a `*` or `&` (`T* const`,
`T const&`), the nullability annotations after one (abseil's and
clang's, and the ALL-CAPS macros c-cpp.ts already blanks for the
parser), and an ALL-CAPS annotation macro's call after the name.
- matchCppDeclarator hands the readers the type without those
annotations (cppDeclaratorType); cv-qualifiers stay, since what reads
a type reads past them. An ALL-CAPS word counts as an annotation only
after a `*` or `&`, so a type's own name stays (`OS_HANDLE* const h`),
and template arguments are kept as written.
- The call's own file, its same-named header, a class's members and a
range-for's variable are read that way; the local-name check for bare
calls reads past the qualifiers too.
- #2533's test that a method's parameter is no member used `T* const`
locals, which the scan couldn't read; it now declares no local, since
one the scan reads decides first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>