From 141484308672aea180dbbd4a190a52e94dc794a4 Mon Sep 17 00:00:00 2001 From: Khushi Sarawagi Date: Fri, 9 Oct 2026 13:27:22 +0530 Subject: [PATCH 1/3] Preserve trailing struct comments in generated C (closes #336) --- src/compiler/codegen_c_reader.c | 1 + src/compiler/parser.c | 5 +++++ src/compiler/symbols.h | 1 + test/cgen_test/CMakeLists.txt | 5 +++++ test/cgen_test/cgen_test.c | 6 ++++++ test/cgen_test/check_doc_comments.cmake | 27 +++++++++++++++++++++++++ 6 files changed, 45 insertions(+) create mode 100644 test/cgen_test/check_doc_comments.cmake diff --git a/src/compiler/codegen_c_reader.c b/src/compiler/codegen_c_reader.c index fb5994bce..751b62867 100644 --- a/src/compiler/codegen_c_reader.c +++ b/src/compiler/codegen_c_reader.c @@ -1252,6 +1252,7 @@ static void gen_struct(fb_output_t *out, fb_compound_type_t *ct) fprintf(out->fp, " uint8_t __padding%u[%u];\n", pad_index, pad); } + print_doc(out, " ", ct->trailing_doc); fprintf(out->fp, "};\n"); if (do_pad) { fprintf(out->fp, "#pragma pack()\n"); diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 45b5c9da2..272673a77 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -1063,6 +1063,11 @@ static void parse_compound_type(fb_parser_t *P, fb_compound_type_t *ct, long tok goto fail; } } + if (ct->symbol.kind == fb_is_struct) { + revert_symbols(&P->doc); + ct->trailing_doc = P->doc; + } + P->doc = 0; if (!optional(P, '}') && t) { error_tok_2(P, P->token, "Declaration missing closing '}' to match", t); } diff --git a/src/compiler/symbols.h b/src/compiler/symbols.h index 075206806..50d9b6d14 100644 --- a/src/compiler/symbols.h +++ b/src/compiler/symbols.h @@ -265,6 +265,7 @@ struct fb_compound_type { fb_member_t *primary_key; fb_metadata_t *metadata; fb_doc_t *doc; + fb_doc_t *trailing_doc; fb_value_t type; fb_symbol_table_t index; /* Only for enums. */ diff --git a/test/cgen_test/CMakeLists.txt b/test/cgen_test/CMakeLists.txt index 2edc040c6..5908c6668 100644 --- a/test/cgen_test/CMakeLists.txt +++ b/test/cgen_test/CMakeLists.txt @@ -13,6 +13,11 @@ target_link_libraries(cgen_test ) add_test(cgen_test cgen_test${CMAKE_EXECUTABLE_SUFFIX}) +add_test(NAME cgen_test_doc_comments + COMMAND ${CMAKE_COMMAND} + -DCGEN_TEST=$ + -P ${CMAKE_CURRENT_SOURCE_DIR}/check_doc_comments.cmake +) # Compilation of the generated code tests many import edge cases diff --git a/test/cgen_test/cgen_test.c b/test/cgen_test/cgen_test.c index 6d58ed1a9..09ab7b96e 100644 --- a/test/cgen_test/cgen_test.c +++ b/test/cgen_test/cgen_test.c @@ -72,6 +72,12 @@ int main(void) "struct shade (force_align:2) { x: byte; y: byte; z: byte;\n" "/// alpha is unsigned!\n" "alpha: ubyte (key); }\n" + "struct comment_source { value: int;\n" + "/// trailing_doc_comment_should_be_kept\n" + "/// second_trailing_doc_comment_should_be_kept\n" + "}\n" + "/// following_type_doc_should_remain\n" + "struct comment_target { value: int; }\n" "/// the.ui is a union\n" "///\n" "/// We got one blank comment line above.\n" diff --git a/test/cgen_test/check_doc_comments.cmake b/test/cgen_test/check_doc_comments.cmake new file mode 100644 index 000000000..800ff4614 --- /dev/null +++ b/test/cgen_test/check_doc_comments.cmake @@ -0,0 +1,27 @@ +execute_process( + COMMAND "${CGEN_TEST}" + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE error +) + +if(NOT result EQUAL 0) + message(FATAL_ERROR "cgen_test failed (${result}): ${error}") +endif() + +set(expected_struct_doc [=[struct the_comment_source { + alignas(4) int32_t value; + /** trailing_doc_comment_should_be_kept + * second_trailing_doc_comment_should_be_kept */ +};]=]) +string(FIND "${output}" "${expected_struct_doc}" trailing_doc_pos) +if(trailing_doc_pos EQUAL -1) + message(FATAL_ERROR "trailing struct doc comments were not kept inside comment_source") +endif() + +set(expected_target_doc [=[/** following_type_doc_should_remain */ +struct the_comment_target {]=]) +string(FIND "${output}" "${expected_target_doc}" following_doc_pos) +if(following_doc_pos EQUAL -1) + message(FATAL_ERROR "doc comment after closing brace was not attached to comment_target") +endif() From 74477ee7e30a7cb920cd9bca479e3f8412d8540a Mon Sep 17 00:00:00 2001 From: Khushi Sarawagi Date: Fri, 9 Oct 2026 17:20:48 +0530 Subject: [PATCH 2/3] Move comment checks into cgen_test --- test/cgen_test/CMakeLists.txt | 5 --- test/cgen_test/cgen_test.c | 49 ++++++++++++++++++++++++- test/cgen_test/check_doc_comments.cmake | 27 -------------- 3 files changed, 48 insertions(+), 33 deletions(-) delete mode 100644 test/cgen_test/check_doc_comments.cmake diff --git a/test/cgen_test/CMakeLists.txt b/test/cgen_test/CMakeLists.txt index 5908c6668..2edc040c6 100644 --- a/test/cgen_test/CMakeLists.txt +++ b/test/cgen_test/CMakeLists.txt @@ -13,11 +13,6 @@ target_link_libraries(cgen_test ) add_test(cgen_test cgen_test${CMAKE_EXECUTABLE_SUFFIX}) -add_test(NAME cgen_test_doc_comments - COMMAND ${CMAKE_COMMAND} - -DCGEN_TEST=$ - -P ${CMAKE_CURRENT_SOURCE_DIR}/check_doc_comments.cmake -) # Compilation of the generated code tests many import edge cases diff --git a/test/cgen_test/cgen_test.c b/test/cgen_test/cgen_test.c index 09ab7b96e..79a20cfde 100644 --- a/test/cgen_test/cgen_test.c +++ b/test/cgen_test/cgen_test.c @@ -38,8 +38,10 @@ * */ #include +#include #include #include "flatcc/flatcc.h" +#include "flatcc/support/readfile.h" int main(void) { @@ -78,6 +80,12 @@ int main(void) "}\n" "/// following_type_doc_should_remain\n" "struct comment_target { value: int; }\n" + "table comment_table { value: int;\n" + "/// drop table comment\n" + "}\n" + "union comment_union { point,\n" + "/// drop union comment\n" + "}\n" "/// the.ui is a union\n" "///\n" "/// We got one blank comment line above.\n" @@ -132,14 +140,17 @@ int main(void) flatcc_options_t opts; flatcc_context_t ctx = 0; + char *output = 0, *resized_output; + size_t output_size = 0; int ret = -1; + const char *outfile = "cgen_test_output.tmp"; flatcc_init_options(&opts); opts.cgen_common_reader = 1; opts.cgen_reader = 1; opts.cgen_common_builder = 1; opts.cgen_builder = 1; - opts.gen_stdout = 1; + opts.gen_outfile = outfile; /* The basename xyzzy is derived from path. */ if (!(ctx = flatcc_create_context(&opts, name, 0, 0))) { @@ -156,6 +167,40 @@ int main(void) fprintf(stderr, "failed to generate output for C\n"); goto done; }; + if (!(output = readfile(outfile, 0, &output_size))) { + fprintf(stderr, "failed to read generated output for C\n"); + goto done; + } + if (!(resized_output = (char *)realloc(output, output_size + 1))) { + fprintf(stderr, "failed to allocate generated output buffer\n"); + goto done; + } + output = resized_output; + output[output_size] = '\0'; + if (!strstr(output, + "struct the_comment_source {\n" + " alignas(4) int32_t value;\n" + " /** trailing_doc_comment_should_be_kept\n" + " * second_trailing_doc_comment_should_be_kept */\n" + "};")) { + fprintf(stderr, "trailing struct doc comments were not kept inside comment_source\n"); + goto done; + } + if (!strstr(output, + "/** following_type_doc_should_remain */\n" + "struct the_comment_target {")) { + fprintf(stderr, "doc comment after closing brace was not attached to comment_target\n"); + goto done; + } + if (strstr(output, "drop table comment") || + strstr(output, "drop union comment")) { + fprintf(stderr, "trailing table or union doc comments were unexpectedly emitted\n"); + goto done; + } + if (fwrite(output, 1, output_size, stdout) != output_size) { + fprintf(stderr, "failed to write generated output to stdout\n"); + goto done; + } fprintf(stdout, "\n#if 0 /* FlatBuffers Schema Source */\n" "%s\n" @@ -164,6 +209,8 @@ int main(void) } ret = 0; done: + free(output); + remove(outfile); flatcc_destroy_context(ctx); return ret; } diff --git a/test/cgen_test/check_doc_comments.cmake b/test/cgen_test/check_doc_comments.cmake deleted file mode 100644 index 800ff4614..000000000 --- a/test/cgen_test/check_doc_comments.cmake +++ /dev/null @@ -1,27 +0,0 @@ -execute_process( - COMMAND "${CGEN_TEST}" - RESULT_VARIABLE result - OUTPUT_VARIABLE output - ERROR_VARIABLE error -) - -if(NOT result EQUAL 0) - message(FATAL_ERROR "cgen_test failed (${result}): ${error}") -endif() - -set(expected_struct_doc [=[struct the_comment_source { - alignas(4) int32_t value; - /** trailing_doc_comment_should_be_kept - * second_trailing_doc_comment_should_be_kept */ -};]=]) -string(FIND "${output}" "${expected_struct_doc}" trailing_doc_pos) -if(trailing_doc_pos EQUAL -1) - message(FATAL_ERROR "trailing struct doc comments were not kept inside comment_source") -endif() - -set(expected_target_doc [=[/** following_type_doc_should_remain */ -struct the_comment_target {]=]) -string(FIND "${output}" "${expected_target_doc}" following_doc_pos) -if(following_doc_pos EQUAL -1) - message(FATAL_ERROR "doc comment after closing brace was not attached to comment_target") -endif() From e18b7caae7d98f6bda274811fdd9f417bb76171e Mon Sep 17 00:00:00 2001 From: Khushi Sarawagi Date: Sat, 10 Oct 2026 09:40:25 +0530 Subject: [PATCH 3/3] Clarify cgen test output comment --- test/cgen_test/cgen_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/cgen_test/cgen_test.c b/test/cgen_test/cgen_test.c index 79a20cfde..33b9efee8 100644 --- a/test/cgen_test/cgen_test.c +++ b/test/cgen_test/cgen_test.c @@ -1,7 +1,7 @@ /* - * Parse and verify schema complex nonsense schema, then generate common - * and schema specific files for reader and builder, all outfileenated to - * stdout, followed by the schema source in a comment. + * Parse and verify a complex schema, generate reader and builder C code + * to a temporary file, check doc-comment placement, then write the + * generated code and schema source to stdout. * * Notes: *