diff --git a/lib/tapioca/helpers/rbi_files_helper.rb b/lib/tapioca/helpers/rbi_files_helper.rb index ffd2ed108..9ce8141b0 100644 --- a/lib/tapioca/helpers/rbi_files_helper.rb +++ b/lib/tapioca/helpers/rbi_files_helper.rb @@ -174,7 +174,21 @@ def shims_or_todos_have_duplicates?(nodes, shim_rbi_dir:, todo_rbi_file:) shims_or_todos = extract_shims_and_todos(nodes, shim_rbi_dir: shim_rbi_dir, todo_rbi_file: todo_rbi_file) return false if shims_or_todos.empty? + not_shims_or_todos = nodes - shims_or_todos shims_or_todos_empty_scopes = extract_empty_scopes(shims_or_todos) + + # We need to discard classes that are redefining the parent of a class + shims_or_todos_empty_scopes.select! do |scope| + # Empty modules are always duplicates + next true unless scope.is_a?(RBI::Class) + + # Empty classes without parents are also duplicates + parent_name = scope.superclass_name + next true unless parent_name + + # Empty classes that are not redefining the parent are also duplicates + not_shims_or_todos.any? { |node| node.is_a?(RBI::Class) && node.superclass_name == parent_name } + end return true unless shims_or_todos_empty_scopes.empty? mixins = extract_mixins(shims_or_todos) diff --git a/spec/tapioca/cli/check_shims_spec.rb b/spec/tapioca/cli/check_shims_spec.rb index beb1a58c3..0f0ee171b 100644 --- a/spec/tapioca/cli/check_shims_spec.rb +++ b/spec/tapioca/cli/check_shims_spec.rb @@ -295,6 +295,58 @@ class Qux refute_success_status(result) end + it "ignores duplicates that have a parent class" do + @project.write!("sorbet/rbi/gems/foo@1.0.0.rbi", <<~RBI) + class Foo + end + class Bar < Foo + end + RBI + + @project.write!("sorbet/rbi/shims/foo.rbi", <<~RBI) + class Foo < Baz + end + class Bar < Baz + end + RBI + + result = @project.tapioca("check-shims --no-payload") + assert_success_status(result) + end + + it "detects duplicates that have a parent class" do + @project.write!("sorbet/rbi/gems/foo@1.0.0.rbi", <<~RBI) + class Foo + end + class Bar < Foo + end + RBI + + @project.write!("sorbet/rbi/shims/foo.rbi", <<~RBI) + class Foo + end + class Bar < Foo + end + RBI + + result = @project.tapioca("check-shims --no-payload") + + assert_stderr_equals(<<~ERR, result) + + Duplicated RBI for ::Foo: + * sorbet/rbi/shims/foo.rbi:1:0-2:3 + * sorbet/rbi/gems/foo@1.0.0.rbi:1:0-2:3 + + Duplicated RBI for ::Bar: + * sorbet/rbi/shims/foo.rbi:3:0-4:3 + * sorbet/rbi/gems/foo@1.0.0.rbi:3:0-4:3 + + Please remove the duplicated definitions from sorbet/rbi/shims and sorbet/rbi/todo.rbi + ERR + + refute_success_status(result) + end + it "detects duplicates from same shim file" do @project.write!("sorbet/rbi/gems/foo@1.0.0.rbi", <<~RBI) class Foo