Skip to content

Commit 78325e1

Browse files
authored
Fix server mode live reload for C files (#1647)
## Summary - The C parser didn't call `add_to_classes_or_modules` when creating classes/modules, so `clear_file_contributions` couldn't clean up old entries during server mode re-parse — causing duplicate methods when editing C files with live reload. - Add the call in both `find_class` and `handle_class_module`, matching what the Ruby parsers already do.
1 parent 237f113 commit 78325e1

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

lib/rdoc/parser/c.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ def find_class(raw_name, name, base_name = nil)
683683
container.name = base_name if base_name
684684

685685
container.record_location @top_level
686+
@top_level.add_to_classes_or_modules container
686687
@classes[raw_name] = container
687688
end
688689
@classes[raw_name]
@@ -898,6 +899,7 @@ def handle_class_module(var_name, type, class_name, parent, in_module)
898899
end
899900

900901
cm.record_location enclosure.top_level
902+
enclosure.top_level.add_to_classes_or_modules cm
901903

902904
find_class_comment cm.full_name, cm
903905

test/rdoc/parser/c_test.rb

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,6 +2215,83 @@ def test_markup_format_override
22152215
assert_equal("markdown", klass.attributes.find {|a| a.name == "default_format"}.comment.format)
22162216
end
22172217

2218+
def test_clear_file_contributions_removes_c_methods
2219+
content = <<~C
2220+
/* Document-class: Foo */
2221+
VALUE cFoo = rb_define_class("Foo", rb_cObject);
2222+
2223+
/* call-seq: bar -> nil */
2224+
VALUE foo_bar(VALUE self) { return Qnil; }
2225+
2226+
void Init_Foo(void) {
2227+
cFoo = rb_define_class("Foo", rb_cObject);
2228+
rb_define_method(cFoo, "bar", foo_bar, 0);
2229+
}
2230+
C
2231+
2232+
util_get_class content, 'cFoo'
2233+
2234+
klass = @store.find_class_named 'Foo'
2235+
assert_equal 1, klass.method_list.size
2236+
2237+
@store.clear_file_contributions @top_level.relative_name
2238+
assert_equal 0, klass.method_list.size
2239+
end
2240+
2241+
def test_reparse_c_file_no_duplicates
2242+
content = <<~C
2243+
/* Document-class: Foo
2244+
* Original comment
2245+
*/
2246+
VALUE cFoo = rb_define_class("Foo", rb_cObject);
2247+
2248+
/* call-seq: bar -> nil */
2249+
VALUE foo_bar(VALUE self) { return Qnil; }
2250+
2251+
void Init_Foo(void) {
2252+
cFoo = rb_define_class("Foo", rb_cObject);
2253+
rb_define_method(cFoo, "bar", foo_bar, 0);
2254+
}
2255+
C
2256+
2257+
# First parse
2258+
util_get_class content, 'cFoo'
2259+
2260+
klass = @store.find_class_named 'Foo'
2261+
assert_equal 1, klass.method_list.size
2262+
2263+
# Simulate server mode re-parse: clear then parse again
2264+
@store.clear_file_contributions @top_level.relative_name
2265+
@top_level.classes_or_modules.clear
2266+
2267+
updated_content = <<~C
2268+
/* Document-class: Foo
2269+
* Updated comment
2270+
*/
2271+
VALUE cFoo = rb_define_class("Foo", rb_cObject);
2272+
2273+
/* call-seq: bar -> nil */
2274+
VALUE foo_bar(VALUE self) { return Qnil; }
2275+
2276+
/* call-seq: baz -> nil */
2277+
VALUE foo_baz(VALUE self) { return Qnil; }
2278+
2279+
void Init_Foo(void) {
2280+
cFoo = rb_define_class("Foo", rb_cObject);
2281+
rb_define_method(cFoo, "bar", foo_bar, 0);
2282+
rb_define_method(cFoo, "baz", foo_baz, 0);
2283+
}
2284+
C
2285+
2286+
util_get_class updated_content, 'cFoo'
2287+
2288+
klass = @store.find_class_named 'Foo'
2289+
method_names = klass.method_list.map(&:name)
2290+
assert_equal 2, method_names.size
2291+
assert_include method_names, 'bar'
2292+
assert_include method_names, 'baz'
2293+
end
2294+
22182295
def util_get_class(content, name = nil)
22192296
@parser = util_parser content
22202297
@parser.scan

0 commit comments

Comments
 (0)