mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-06 08:35:21 +08:00
Merge pull request #1853 from DeusData/fix/issue-1746-dockerfile-eof-whitespace-resume
fix: ignore trailing Dockerfile whitespace at EOF
This commit is contained in:
+28
-8
@@ -814,17 +814,37 @@ static void cbm_error_regions_push(cbm_error_regions_t *acc, TSNode n) {
|
||||
* Deliberately narrow — ZERO-WIDTH AT EOF ONLY. A MISSING or ERROR node with
|
||||
* WIDTH still counts even at EOF (a Makefile whose last recipe line is
|
||||
* unterminated really does lose the recipe), and anything before EOF is
|
||||
* untouched. */
|
||||
static bool cbm_is_eof_terminator_miss(TSNode n, int source_len) {
|
||||
* untouched.
|
||||
*
|
||||
* #1746: the Dockerfile grammar places that zero-width missing newline before
|
||||
* trailing horizontal whitespace rather than at raw EOF. Preserve the broad
|
||||
* exact-EOF rule above; only extend it past spaces/tabs when the missing token
|
||||
* is specifically a newline. */
|
||||
static bool cbm_is_eof_terminator_miss(TSNode n, const char *source, int source_len) {
|
||||
if (!ts_node_is_missing(n) || source_len < 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t start = ts_node_start_byte(n);
|
||||
uint32_t end = ts_node_end_byte(n);
|
||||
return start == end && end == (uint32_t)source_len;
|
||||
if (start != end || end > (uint32_t)source_len) {
|
||||
return false;
|
||||
}
|
||||
if (end == (uint32_t)source_len) {
|
||||
return true;
|
||||
}
|
||||
if (!source || strcmp(ts_node_type(n), "\n") != 0) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = end; i < (uint32_t)source_len; i++) {
|
||||
if (source[i] != ' ' && source[i] != '\t') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cbm_collect_error_regions(TSNode n, cbm_error_regions_t *acc, int source_len) {
|
||||
static void cbm_collect_error_regions(TSNode n, cbm_error_regions_t *acc, const char *source,
|
||||
int source_len) {
|
||||
if (acc->count >= CBM_MAX_ERROR_REGIONS) {
|
||||
return;
|
||||
}
|
||||
@@ -832,12 +852,12 @@ static void cbm_collect_error_regions(TSNode n, cbm_error_regions_t *acc, int so
|
||||
for (uint32_t i = 0; i < k && acc->count < CBM_MAX_ERROR_REGIONS; i++) {
|
||||
TSNode c = ts_node_child(n, i);
|
||||
if (ts_node_is_missing(c) || strcmp(ts_node_type(c), "ERROR") == 0) {
|
||||
if (cbm_is_eof_terminator_miss(c, source_len)) {
|
||||
if (cbm_is_eof_terminator_miss(c, source, source_len)) {
|
||||
continue; /* absent final newline only — nothing was dropped */
|
||||
}
|
||||
cbm_error_regions_push(acc, c); /* top-most region; do not descend */
|
||||
} else if (ts_node_has_error(c)) {
|
||||
cbm_collect_error_regions(c, acc, source_len);
|
||||
cbm_collect_error_regions(c, acc, source, source_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1460,7 +1480,7 @@ CBMFileResult *cbm_extract_file_ex(const char *source, int source_len, CBMLangua
|
||||
* already extract. */
|
||||
if (ts_node_has_error(root)) {
|
||||
cbm_error_regions_t raw_regs = {{0}, {0}, 0};
|
||||
cbm_collect_error_regions(root, &raw_regs, source_len);
|
||||
cbm_collect_error_regions(root, &raw_regs, source, source_len);
|
||||
if (raw_regs.count > 0) {
|
||||
int defs_before = result->defs.count;
|
||||
cbm_extract_definitions(&pp_ctx);
|
||||
@@ -1618,7 +1638,7 @@ CBMFileResult *cbm_extract_file_ex(const char *source, int source_len, CBMLangua
|
||||
if (strcmp(ts_node_type(root), "ERROR") == 0) {
|
||||
cbm_error_regions_push(®s, root); /* whole file unparseable */
|
||||
} else {
|
||||
cbm_collect_error_regions(root, ®s, source_len);
|
||||
cbm_collect_error_regions(root, ®s, source, source_len);
|
||||
}
|
||||
cbm_subtract_recovered_regions(®s, &result->defs);
|
||||
/* #1071: don't flag a benign function-like-macro call (defined in-file)
|
||||
|
||||
@@ -295,6 +295,55 @@ TEST(dockerfile_with_final_newline_still_clean_issue1610) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* #1746: on Windows, a Dockerfile whose final instruction is followed by one
|
||||
* ASCII space and then EOF was reported as parse_partial. */
|
||||
TEST(dockerfile_trailing_space_at_eof_not_flagged_issue1746) {
|
||||
const char *src = "FROM scratch\nENTRYPOINT [\"a\"] ";
|
||||
CBMFileResult *r = do_extract(src, CBM_LANG_DOCKERFILE, "Dockerfile");
|
||||
ASSERT_NOT_NULL(r);
|
||||
bool flagged = r->parse_incomplete;
|
||||
if (flagged) {
|
||||
fprintf(stderr, " exact issue #1746 fixture flagged: ranges=%s\n",
|
||||
r->error_ranges ? r->error_ranges : "(none)");
|
||||
}
|
||||
cbm_free_result(r);
|
||||
if (flagged) {
|
||||
FAIL("trailing horizontal whitespace at Dockerfile EOF must not be parse_partial");
|
||||
}
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* The same bytes WITH the LF must stay clean. This is a separate test so the
|
||||
* control executes even while the exact affected fixture is RED. */
|
||||
TEST(dockerfile_trailing_space_with_final_newline_clean_issue1746) {
|
||||
const char *src = "FROM scratch\nENTRYPOINT [\"a\"] \n";
|
||||
CBMFileResult *r = do_extract(src, CBM_LANG_DOCKERFILE, "Dockerfile");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->parse_incomplete);
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* Removing the trailing space while retaining EOF must also stay clean. */
|
||||
TEST(dockerfile_without_trailing_space_at_eof_clean_issue1746) {
|
||||
const char *src = "FROM scratch\nENTRYPOINT [\"a\"]";
|
||||
CBMFileResult *r = do_extract(src, CBM_LANG_DOCKERFILE, "Dockerfile");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->parse_incomplete);
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* The reporter also observed the same failure when the first line uses CRLF. */
|
||||
TEST(dockerfile_crlf_trailing_space_at_eof_not_flagged_issue1746) {
|
||||
const char *src = "FROM scratch\r\nENTRYPOINT [\"a\"] ";
|
||||
CBMFileResult *r = do_extract(src, CBM_LANG_DOCKERFILE, "Dockerfile");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->parse_incomplete);
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* Language-general, not a Dockerfile patch: these four were each proven to flag
|
||||
* on a stripped trailing newline. */
|
||||
TEST(missing_final_newline_not_flagged_across_grammars_issue1610) {
|
||||
@@ -381,6 +430,10 @@ SUITE(parse_coverage) {
|
||||
RUN_TEST(c_trailing_recovered_defs_keep_flag);
|
||||
RUN_TEST(dockerfile_missing_final_newline_not_flagged_issue1610);
|
||||
RUN_TEST(dockerfile_with_final_newline_still_clean_issue1610);
|
||||
RUN_TEST(dockerfile_trailing_space_at_eof_not_flagged_issue1746);
|
||||
RUN_TEST(dockerfile_trailing_space_with_final_newline_clean_issue1746);
|
||||
RUN_TEST(dockerfile_without_trailing_space_at_eof_clean_issue1746);
|
||||
RUN_TEST(dockerfile_crlf_trailing_space_at_eof_not_flagged_issue1746);
|
||||
RUN_TEST(missing_final_newline_not_flagged_across_grammars_issue1610);
|
||||
RUN_TEST(real_error_before_eof_still_flagged_without_final_newline_issue1610);
|
||||
RUN_TEST(width_bearing_error_at_eof_still_flagged_issue1610);
|
||||
|
||||
Reference in New Issue
Block a user