diff --git a/cpp-generator/experimental/impl_header_parser.cpp b/cpp-generator/experimental/impl_header_parser.cpp index 6c55bdf..ead1556 100644 --- a/cpp-generator/experimental/impl_header_parser.cpp +++ b/cpp-generator/experimental/impl_header_parser.cpp @@ -337,12 +337,13 @@ ImplParseResult parseImplHeader(const QString& headerPath, // event prototypes from. (At preprocess time, `logos_events` // expands to `public`, but the raw source still carries the // token we recognise here.) + bool specifierStripped = false; while (true) { QRegularExpressionMatch em = eventsRe.match(line); if (em.hasMatch()) { state = InLogosEvents; - pendingDoc.clear(); line = line.mid(em.capturedEnd()).trimmed(); + specifierStripped = true; continue; } QRegularExpressionMatch am = accessRe.match(line); @@ -350,12 +351,22 @@ ImplParseResult parseImplHeader(const QString& headerPath, QString spec = am.captured(1); if (spec == "public") state = InPublic; else state = InPrivate; - pendingDoc.clear(); line = line.mid(am.capturedEnd()).trimmed(); + specifierStripped = true; continue; } break; } + // A *bare* specifier (nothing after the colon) is a section + // boundary and resets any pending doc-comment, mirroring Qt's + // `signals:`. But when a declaration shares the line, the doc + // comment preceding the whole line must still attach to that + // declaration — otherwise documentation, like the declaration + // itself (#76), would become formatting-dependent. So only clear + // here for the bare form; the same-line form keeps pendingDoc and + // attaches it in the declaration parser below. + if (specifierStripped && line.isEmpty()) + pendingDoc.clear(); // Only doc comments (/// or /** ... */ / /*! ... */) accumulate as // the pending description for the next method. Plain // and /* diff --git a/tests/experimental/fixtures/same_line_events_impl.h b/tests/experimental/fixtures/same_line_events_impl.h index aaf0062..e0e46ee 100644 --- a/tests/experimental/fixtures/same_line_events_impl.h +++ b/tests/experimental/fixtures/same_line_events_impl.h @@ -15,7 +15,11 @@ public: public: std::string greet(const std::string& name); // The exact prettier-formatted form from the issue: `logos_events`, - // a space, the colon, then the event prototype — all on one line. + // a space, the colon, then the event prototype — all on one line. The + // `///` doc comment above must still attach to the event: in the + // collapsed form there is nowhere else to put it, so dropping it would + // make documentation formatting-dependent too. + /// Fired once the latest version is known. logos_events : void versionReady(const std::string &version); // A further event after the section is already open (still same-line). diff --git a/tests/experimental/test_impl_header_parser.cpp b/tests/experimental/test_impl_header_parser.cpp index d9d6757..7892aab 100644 --- a/tests/experimental/test_impl_header_parser.cpp +++ b/tests/experimental/test_impl_header_parser.cpp @@ -386,6 +386,10 @@ TEST_F(ImplHeaderParserTest, SameLineSectionSpecifiers) ASSERT_EQ(versionReady->params.size(), 1); EXPECT_EQ(versionReady->params[0].name, "version"); EXPECT_EQ(versionReady->params[0].type.name, "tstr"); + // The `///` doc comment above the collapsed line must attach: in the + // same-line form there is nowhere else for it to go, so documentation + // must not be formatting-dependent either. + EXPECT_EQ(versionReady->description, "Fired once the latest version is known."); // An event declared after the section is already open, also same-line. const EventDecl* downloadProgress = findEvent("downloadProgress");