[前][次][番号順一覧][スレッド一覧]

ruby-changes:73679

From: Samuel <ko1@a...>
Date: Thu, 22 Sep 2022 19:19:39 +0900 (JST)
Subject: [ruby-changes:73679] 9434a7333c (master): Enable coverage for eval.

https://git.ruby-lang.org/ruby.git/commit/?id=9434a7333c

From 9434a7333c2a23c680a977331a60ca7c502c1ac0 Mon Sep 17 00:00:00 2001
From: Samuel Williams <samuel.williams@o...>
Date: Sat, 17 Sep 2022 20:19:57 +1200
Subject: Enable coverage for eval.

---
 compile.c                                 |  6 +++---
 iseq.c                                    | 13 +++++++++++-
 spec/ruby/library/coverage/result_spec.rb | 34 +++++++++++++++++++++++--------
 test/coverage/test_coverage.rb            | 17 +++++++++++++++-
 vm_eval.c                                 |  8 ++++++++
 5 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/compile.c b/compile.c
index 45cb116983..7d553bfba1 100644
--- a/compile.c
+++ b/compile.c
@@ -2308,9 +2308,9 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) https://github.com/ruby/ruby/blob/trunk/compile.c#L2308
                 if (ISEQ_COVERAGE(iseq)) {
                     if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
                         !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
-                        int line = iobj->insn_info.line_no;
-                        if (line >= 1) {
-                            RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line - 1, INT2FIX(0));
+                        int line = iobj->insn_info.line_no - 1;
+                        if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
+                            RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
                         }
                     }
                     if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
diff --git a/iseq.c b/iseq.c
index 4892d93df1..9359fcfe4e 100644
--- a/iseq.c
+++ b/iseq.c
@@ -697,7 +697,6 @@ prepare_iseq_build(rb_iseq_t *iseq, https://github.com/ruby/ruby/blob/trunk/iseq.c#L697
     ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = NULL;
     ISEQ_COMPILE_DATA(iseq)->builtin_function_table = GET_VM()->builtin_function_table;
 
-
     if (option->coverage_enabled) {
         VALUE coverages = rb_get_coverages();
         if (RTEST(coverages)) {
@@ -928,6 +927,18 @@ rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_ https://github.com/ruby/ruby/blob/trunk/iseq.c#L927
 rb_iseq_t *
 rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth)
 {
+    VALUE coverages = rb_get_coverages();
+    if (RTEST(coverages) && RTEST(path) && !RTEST(rb_hash_has_key(coverages, path))) {
+        int line_offset = RB_NUM2INT(first_lineno) - 1;
+        int line_count = line_offset + ast_line_count(ast);
+
+        if (line_count >= 0) {
+            int len = (rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES) ? 0 : line_count;
+            VALUE coverage = rb_default_coverage(len);
+            rb_hash_aset(coverages, path, coverage);
+        }
+    }
+
     return rb_iseq_new_with_opt(ast, name, path, realpath, first_lineno,
                                 parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT);
 }
diff --git a/spec/ruby/library/coverage/result_spec.rb b/spec/ruby/library/coverage/result_spec.rb
index 4cc43e8462..61283e4545 100644
--- a/spec/ruby/library/coverage/result_spec.rb
+++ b/spec/ruby/library/coverage/result_spec.rb
@@ -91,15 +91,31 @@ describe 'Coverage.result' do https://github.com/ruby/ruby/blob/trunk/spec/ruby/library/coverage/result_spec.rb#L91
     Coverage.result.should_not include(@config_file)
   end
 
-  it 'returns the correct results when eval is used' do
-    Coverage.start
-    require @eval_code_file.chomp('.rb')
-    result = Coverage.result
+  ruby_version_is '3.1'...'3.2' do
+    it 'returns the correct results when eval is used' do
+      Coverage.start
+      require @eval_code_file.chomp('.rb')
+      result = Coverage.result
 
-    result.should == {
-        @eval_code_file => [
-            1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
-        ]
-    }
+      result.should == {
+          @eval_code_file => [
+              1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
+          ]
+      }
+    end
+  end
+
+  ruby_version_is '3.2' do
+    it 'returns the correct results when eval is used' do
+      Coverage.start
+      require @eval_code_file.chomp('.rb')
+      result = Coverage.result
+
+      result.should == {
+          @eval_code_file => [
+              1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1
+          ]
+      }
+    end
   end
 end
diff --git a/test/coverage/test_coverage.rb b/test/coverage/test_coverage.rb
index eefe7e7da6..1bb85b67b3 100644
--- a/test/coverage/test_coverage.rb
+++ b/test/coverage/test_coverage.rb
@@ -136,7 +136,7 @@ class TestCoverage < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/coverage/test_coverage.rb#L136
           f.puts 'REPEATS = 400'
           f.puts 'def add_method(target)'
           f.puts '  REPEATS.times do'
-          f.puts '    target.class_eval(<<~RUBY, __FILE__, __LINE__ + 1)'
+          f.puts '    target.class_eval(<<~RUBY)'
           f.puts '      def foo'
           f.puts '        #{"\n" * rand(REPEATS)}'
           f.puts '      end'
@@ -157,6 +157,21 @@ class TestCoverage < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/coverage/test_coverage.rb#L157
     }
   end
 
+  def test_eval_coverage
+    assert_in_out_err(%w[-rcoverage], <<-"end;", ["[1, nil, 1, nil]"], [])
+      Coverage.start
+
+      eval(<<-RUBY, TOPLEVEL_BINDING, "test.rb")
+      s = String.new
+      begin
+      s << "foo
+      bar".freeze; end
+      RUBY
+
+      p Coverage.result["test.rb"]
+    end;
+  end
+
   def test_nocoverage_optimized_line
     assert_ruby_status(%w[], "#{<<-"begin;"}\n#{<<-'end;'}")
     begin;
diff --git a/vm_eval.c b/vm_eval.c
index c7ad71e279..9d7a736ad9 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1672,6 +1672,8 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind, https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1672
     rb_iseq_t *iseq = NULL;
     rb_ast_t *ast;
     int isolated_depth = 0;
+    int coverage_enabled = Qtrue;
+
     {
         int depth = 1;
         const VALUE *ep = vm_block_ep(base_block);
@@ -1703,11 +1705,17 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind, https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1705
             rb_gc_register_mark_object(eval_default_path);
         }
         fname = eval_default_path;
+        coverage_enabled = Qfalse;
     }
 
     rb_parser_set_context(parser, parent, FALSE);
     ast = rb_parser_compile_string_path(parser, fname, src, line);
     if (ast->body.root) {
+        if (ast->body.compile_option == Qnil) {
+            ast->body.compile_option = rb_obj_hide(rb_ident_hash_new());
+        }
+        rb_hash_aset(ast->body.compile_option, rb_sym_intern_ascii_cstr("coverage_enabled"), coverage_enabled);
+
         iseq = rb_iseq_new_eval(&ast->body,
                                 ISEQ_BODY(parent)->location.label,
                                 fname, Qnil, INT2FIX(line),
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]