rcov 0.6.0.1-mswin32 → 0.7.0.1-mswin32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/BLURB +1 -1
- data/CHANGES +18 -0
- data/Rakefile +4 -3
- data/THANKS +9 -0
- data/bin/rcov +43 -3
- data/ext/rcovrt/callsite.c +242 -0
- data/ext/rcovrt/{rcov.c → rcovrt.c} +48 -216
- data/lib/rcov/rcovtask.rb +1 -1
- data/lib/rcov/report.rb +8 -2
- data/lib/rcov/version.rb +2 -2
- data/lib/rcov.rb +45 -3
- data/lib/rcovrt.so +0 -0
- data/mingw-rbconfig.rb +2 -2
- data/rcov.vim +38 -0
- metadata +7 -4
    
        data/BLURB
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            Source code, additional information, screenshots... available at 
         | 
| 3 3 | 
             
                http://eigenclass.org/hiki.rb?rcov
         | 
| 4 4 | 
             
            Release information:
         | 
| 5 | 
            -
                http://eigenclass.org/hiki.rb?rcov+0. | 
| 5 | 
            +
                http://eigenclass.org/hiki.rb?rcov+0.7.0
         | 
| 6 6 |  | 
| 7 7 | 
             
            If you're on win32, you can also find a pre-built rcovrt.so (which makes
         | 
| 8 8 | 
             
            code coverage analysis >100 times faster) in the above-mentioned pages.
         | 
    
        data/CHANGES
    CHANGED
    
    | @@ -1,6 +1,24 @@ | |
| 1 1 |  | 
| 2 2 | 
             
            User-visible changes.
         | 
| 3 3 |  | 
| 4 | 
            +
            Since 0.6.0 (2006-06-12)
         | 
| 5 | 
            +
            ========================
         | 
| 6 | 
            +
            Features
         | 
| 7 | 
            +
            --------
         | 
| 8 | 
            +
            * coverage/callsite data from multiple runs can be aggregated (--aggregate) 
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Bugfixes
         | 
| 11 | 
            +
            --------
         | 
| 12 | 
            +
            * the SCRIPT_LINES__ workaround works better
         | 
| 13 | 
            +
            * fixed silly bug in coverage data acquisition (line after the correct one
         | 
| 14 | 
            +
              marked in some situations)
         | 
| 15 | 
            +
            * avoid problems with repeated path separators in default ignore list, based
         | 
| 16 | 
            +
              on rbconfig's data
         | 
| 17 | 
            +
             | 
| 18 | 
            +
             | 
| 19 | 
            +
            Minor enhancements
         | 
| 20 | 
            +
            ------------------
         | 
| 21 | 
            +
             | 
| 4 22 | 
             
            Since 0.5.0 (2006-05-30)
         | 
| 5 23 | 
             
            ========================
         | 
| 6 24 | 
             
            Features
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -48,7 +48,7 @@ Rake::TestTask.new(:test_rcovrt => ["ext/rcovrt/rcovrt.so"]) do |t| | |
| 48 48 | 
             
              t.verbose = true
         | 
| 49 49 | 
             
            end
         | 
| 50 50 |  | 
| 51 | 
            -
            file "ext/rcovrt/rcovrt.so" => "ext/rcovrt | 
| 51 | 
            +
            file "ext/rcovrt/rcovrt.so" => FileList["ext/rcovrt/*.c"] do
         | 
| 52 52 | 
             
              ruby "setup.rb config"
         | 
| 53 53 | 
             
              ruby "setup.rb setup"
         | 
| 54 54 | 
             
            end
         | 
| @@ -87,9 +87,10 @@ PKG_FILES = FileList[ | |
| 87 87 | 
             
            "bin/rcov",
         | 
| 88 88 | 
             
            "lib/**/*.rb",
         | 
| 89 89 | 
             
            "ext/rcovrt/extconf.rb",
         | 
| 90 | 
            -
            "ext/rcovrt | 
| 90 | 
            +
            "ext/rcovrt/*.c",
         | 
| 91 | 
            +
            "ext/rcovrt/*.h",
         | 
| 91 92 | 
             
            "LEGAL", "LICENSE", "Rakefile", "Rantfile", "README.*", "THANKS", "test/*.rb",
         | 
| 92 | 
            -
            "mingw-rbconfig.rb",
         | 
| 93 | 
            +
            "mingw-rbconfig.rb", "rcov.vim",
         | 
| 93 94 | 
             
            "setup.rb", "BLURB", "CHANGES"
         | 
| 94 95 | 
             
            ]
         | 
| 95 96 |  | 
    
        data/THANKS
    CHANGED
    
    | @@ -41,3 +41,12 @@ Coda Hale: | |
| 41 41 | 
             
            Tim Shadel:
         | 
| 42 42 | 
             
            * reported that the last comment block was not being marked even when
         | 
| 43 43 | 
             
              it was the last thing in the file
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            Thomas Leitner:
         | 
| 46 | 
            +
            * reported that the SCRIPT_LINES__ workaround did not always work
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            Assaph Mehr:
         | 
| 49 | 
            +
            * beta-tested 0.7.0 and found a bug in --aggregate (missing files)
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            Ryan Kinderman:
         | 
| 52 | 
            +
            * suggested that -Ipath be passed to ruby instead of rcov in RcovTasks
         | 
    
        data/bin/rcov
    CHANGED
    
    | @@ -56,6 +56,7 @@ options.coverage_diff_mode = :compare | |
| 56 56 | 
             
            options.coverage_diff_save = false
         | 
| 57 57 | 
             
            options.diff_cmd = "diff"
         | 
| 58 58 | 
             
            options.report_cov_bug_for = nil
         | 
| 59 | 
            +
            options.aggregate_file = nil
         | 
| 59 60 |  | 
| 60 61 | 
             
            EXTRA_HELP = <<-EOF
         | 
| 61 62 |  | 
| @@ -165,6 +166,12 @@ EOF | |
| 165 166 | 
             
                        "ANSI color sequences unless -n.") do
         | 
| 166 167 | 
             
                    options.textmode = :coverage
         | 
| 167 168 | 
             
                end
         | 
| 169 | 
            +
                opts.on("--aggregate FILE", "Aggregate data from previous runs",
         | 
| 170 | 
            +
                                            "in FILE. Overwrites FILE with the",
         | 
| 171 | 
            +
                                            "merged data. FILE is created if",
         | 
| 172 | 
            +
                                            "necessary.") do |file|
         | 
| 173 | 
            +
                  options.aggregate_file = file
         | 
| 174 | 
            +
                end
         | 
| 168 175 | 
             
                opts.on("-D [FILE]", "--text-coverage-diff [FILE]",
         | 
| 169 176 | 
             
                        "Compare code coverage with saved state",
         | 
| 170 177 | 
             
                        "in FILE, defaults to coverage.info.",
         | 
| @@ -177,7 +184,8 @@ EOF | |
| 177 184 | 
             
                    options.coverage_diff_mode = :compare
         | 
| 178 185 | 
             
                    options.coverage_diff_file = file if file && !file.empty?
         | 
| 179 186 | 
             
                end
         | 
| 180 | 
            -
                opts.on("--save [FILE]", "Save coverage data to FILE | 
| 187 | 
            +
                opts.on("--save [FILE]", "Save coverage data to FILE,",
         | 
| 188 | 
            +
                        "for later use with rcov -D.",
         | 
| 181 189 | 
             
                        "(default: coverage.info)") do |file|
         | 
| 182 190 | 
             
                    options.coverage_diff_save = true
         | 
| 183 191 | 
             
                    options.coverage_diff_mode = :record
         | 
| @@ -289,8 +297,33 @@ require 'rcov' | |
| 289 297 |  | 
| 290 298 | 
             
            options.callsites = true if options.report_cov_bug_for
         | 
| 291 299 |  | 
| 300 | 
            +
            def rcov_load_aggregate_data(file)
         | 
| 301 | 
            +
                require 'zlib'
         | 
| 302 | 
            +
                begin
         | 
| 303 | 
            +
                    old_data = nil
         | 
| 304 | 
            +
                    Zlib::GzipReader.open(file){|gz| old_data = Marshal.load(gz) }
         | 
| 305 | 
            +
                rescue
         | 
| 306 | 
            +
                    old_data = {}
         | 
| 307 | 
            +
                end
         | 
| 308 | 
            +
                old_data || {}
         | 
| 309 | 
            +
            end
         | 
| 310 | 
            +
             | 
| 311 | 
            +
            def rcov_save_aggregate_data(file)
         | 
| 312 | 
            +
                require 'zlib'
         | 
| 313 | 
            +
                Zlib::GzipWriter.open(file) do |f|
         | 
| 314 | 
            +
                    Marshal.dump({:callsites => $rcov_callsite_analyzer, 
         | 
| 315 | 
            +
                                 :coverage => $rcov_code_coverage_analyzer}, f)
         | 
| 316 | 
            +
                end
         | 
| 317 | 
            +
            end
         | 
| 318 | 
            +
             | 
| 292 319 | 
             
            if options.callsites 
         | 
| 293 | 
            -
                 | 
| 320 | 
            +
                if options.aggregate_file
         | 
| 321 | 
            +
                    saved_aggregate_data = rcov_load_aggregate_data(options.aggregate_file)
         | 
| 322 | 
            +
                    if saved_aggregate_data[:callsites]
         | 
| 323 | 
            +
                        $rcov_callsite_analyzer = saved_aggregate_data[:callsites]
         | 
| 324 | 
            +
                    end
         | 
| 325 | 
            +
                end
         | 
| 326 | 
            +
                $rcov_callsite_analyzer ||= Rcov::CallSiteAnalyzer.new
         | 
| 294 327 | 
             
                $rcov_callsite_analyzer.install_hook
         | 
| 295 328 | 
             
            else
         | 
| 296 329 | 
             
                $rcov_callsite_analyzer = nil
         | 
| @@ -333,12 +366,19 @@ end | |
| 333 366 |  | 
| 334 367 | 
             
            formatters << make_formatter[Rcov::TextCoverageDiff] if options.coverage_diff_save
         | 
| 335 368 |  | 
| 336 | 
            -
             | 
| 369 | 
            +
            if options.aggregate_file
         | 
| 370 | 
            +
                saved_aggregate_data ||= rcov_load_aggregate_data(options.aggregate_file)
         | 
| 371 | 
            +
                if saved_aggregate_data[:coverage]
         | 
| 372 | 
            +
                    $rcov_code_coverage_analyzer = saved_aggregate_data[:coverage]
         | 
| 373 | 
            +
                end
         | 
| 374 | 
            +
            end
         | 
| 375 | 
            +
            $rcov_code_coverage_analyzer ||= Rcov::CodeCoverageAnalyzer.new
         | 
| 337 376 |  | 
| 338 377 | 
             
            # must be registered before test/unit puts its own
         | 
| 339 378 | 
             
            END {
         | 
| 340 379 | 
             
                $rcov_code_coverage_analyzer.remove_hook
         | 
| 341 380 | 
             
                $rcov_callsite_analyzer.remove_hook if $rcov_callsite_analyzer
         | 
| 381 | 
            +
                rcov_save_aggregate_data(options.aggregate_file) if options.aggregate_file
         | 
| 342 382 | 
             
                $rcov_code_coverage_analyzer.dump_coverage_info(formatters)
         | 
| 343 383 | 
             
                if options.report_cov_bug_for
         | 
| 344 384 | 
             
                    defsite = $rcov_callsite_analyzer.defsite(options.report_cov_bug_for)
         | 
| @@ -0,0 +1,242 @@ | |
| 1 | 
            +
            #include <ruby.h>
         | 
| 2 | 
            +
            #include <env.h>
         | 
| 3 | 
            +
            #include <node.h>
         | 
| 4 | 
            +
            #include <st.h>
         | 
| 5 | 
            +
            #include <stdlib.h>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
            static char callsite_hook_set_p;
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            typedef struct {
         | 
| 11 | 
            +
                    char *sourcefile;
         | 
| 12 | 
            +
                    unsigned int sourceline;
         | 
| 13 | 
            +
                    VALUE curr_meth;
         | 
| 14 | 
            +
            } type_def_site;       
         | 
| 15 | 
            +
            static VALUE caller_info = 0;
         | 
| 16 | 
            +
            static VALUE method_def_site_info = 0;
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            static caller_stack_len = 1;
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            /*
         | 
| 21 | 
            +
             *
         | 
| 22 | 
            +
             * callsite hook and associated functions
         | 
| 23 | 
            +
             *
         | 
| 24 | 
            +
             * */
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            static VALUE
         | 
| 27 | 
            +
            record_callsite_info(VALUE args)
         | 
| 28 | 
            +
            {
         | 
| 29 | 
            +
              VALUE caller_ary;
         | 
| 30 | 
            +
              VALUE curr_meth;
         | 
| 31 | 
            +
              VALUE count_hash;
         | 
| 32 | 
            +
              VALUE count;
         | 
| 33 | 
            +
              VALUE *pargs = (VALUE *)args;
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              caller_ary = pargs[0];
         | 
| 36 | 
            +
              curr_meth = pargs[1];
         | 
| 37 | 
            +
              count_hash = rb_hash_aref(caller_info, curr_meth);
         | 
| 38 | 
            +
              if(TYPE(count_hash) != T_HASH) { 
         | 
| 39 | 
            +
                      /* Qnil, anything else should be impossible unless somebody's been
         | 
| 40 | 
            +
                       * messing with ObjectSpace */
         | 
| 41 | 
            +
                      count_hash = rb_hash_new();
         | 
| 42 | 
            +
                      rb_hash_aset(caller_info, curr_meth, count_hash);
         | 
| 43 | 
            +
              }
         | 
| 44 | 
            +
              count = rb_hash_aref(count_hash, caller_ary);
         | 
| 45 | 
            +
              if(count == Qnil) 
         | 
| 46 | 
            +
                      count = INT2FIX(0);
         | 
| 47 | 
            +
              count = INT2FIX(FIX2UINT(count) + 1);
         | 
| 48 | 
            +
              rb_hash_aset(count_hash, caller_ary, count);
         | 
| 49 | 
            +
              /*
         | 
| 50 | 
            +
              printf("CALLSITE: %s -> %s   %d\n", RSTRING(rb_inspect(curr_meth))->ptr,
         | 
| 51 | 
            +
                              RSTRING(rb_inspect(caller_ary))->ptr, FIX2INT(count));
         | 
| 52 | 
            +
              */
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              return Qnil;
         | 
| 55 | 
            +
            }
         | 
| 56 | 
            +
             | 
| 57 | 
            +
             | 
| 58 | 
            +
            static VALUE
         | 
| 59 | 
            +
            record_method_def_site(VALUE args)
         | 
| 60 | 
            +
            {
         | 
| 61 | 
            +
              type_def_site *pargs = (type_def_site *)args;
         | 
| 62 | 
            +
              VALUE def_site_info;
         | 
| 63 | 
            +
              VALUE hash;
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              if( RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth)) )
         | 
| 66 | 
            +
                      return Qnil;
         | 
| 67 | 
            +
              def_site_info = rb_ary_new();
         | 
| 68 | 
            +
              rb_ary_push(def_site_info, rb_str_new2(pargs->sourcefile));
         | 
| 69 | 
            +
              rb_ary_push(def_site_info, INT2NUM(pargs->sourceline+1));
         | 
| 70 | 
            +
              rb_hash_aset(method_def_site_info, pargs->curr_meth, def_site_info);
         | 
| 71 | 
            +
              /*
         | 
| 72 | 
            +
              printf("DEFSITE: %s:%d  for %s\n", pargs->sourcefile, pargs->sourceline+1,
         | 
| 73 | 
            +
                              RSTRING(rb_inspect(pargs->curr_meth))->ptr);
         | 
| 74 | 
            +
              */
         | 
| 75 | 
            +
              
         | 
| 76 | 
            +
              return Qnil;
         | 
| 77 | 
            +
            }
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            static VALUE
         | 
| 80 | 
            +
            callsite_custom_backtrace(int lev)
         | 
| 81 | 
            +
            {
         | 
| 82 | 
            +
              struct FRAME *frame = ruby_frame;
         | 
| 83 | 
            +
              VALUE ary;
         | 
| 84 | 
            +
              NODE *n;
         | 
| 85 | 
            +
              VALUE level;
         | 
| 86 | 
            +
              VALUE klass;
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              ary = rb_ary_new();
         | 
| 89 | 
            +
              if (frame->last_func == ID_ALLOCATOR) {
         | 
| 90 | 
            +
                      frame = frame->prev;
         | 
| 91 | 
            +
              }
         | 
| 92 | 
            +
              for (; frame && (n = frame->node); frame = frame->prev) {
         | 
| 93 | 
            +
                      if (frame->prev && frame->prev->last_func) {
         | 
| 94 | 
            +
                              if (frame->prev->node == n) continue;
         | 
| 95 | 
            +
                              level = rb_ary_new();
         | 
| 96 | 
            +
                              klass = frame->prev->last_class ? frame->prev->last_class : Qnil;
         | 
| 97 | 
            +
                              if(TYPE(klass) == T_ICLASS) {
         | 
| 98 | 
            +
                                      klass = CLASS_OF(klass);
         | 
| 99 | 
            +
                              }
         | 
| 100 | 
            +
                              rb_ary_push(level, klass);
         | 
| 101 | 
            +
                              rb_ary_push(level, ID2SYM(frame->prev->last_func));
         | 
| 102 | 
            +
                              rb_ary_push(level, rb_str_new2(n->nd_file));
         | 
| 103 | 
            +
                              rb_ary_push(level, INT2NUM(nd_line(n)));
         | 
| 104 | 
            +
                      }
         | 
| 105 | 
            +
                      else {
         | 
| 106 | 
            +
                              level = rb_ary_new();
         | 
| 107 | 
            +
                              rb_ary_push(level, Qnil);
         | 
| 108 | 
            +
                              rb_ary_push(level, Qnil);
         | 
| 109 | 
            +
                              rb_ary_push(level, rb_str_new2(n->nd_file));
         | 
| 110 | 
            +
                              rb_ary_push(level, INT2NUM(nd_line(n)));
         | 
| 111 | 
            +
                      }
         | 
| 112 | 
            +
                      rb_ary_push(ary, level);
         | 
| 113 | 
            +
                      if(--lev == 0)
         | 
| 114 | 
            +
                              break;
         | 
| 115 | 
            +
              }
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              return ary;
         | 
| 118 | 
            +
            }
         | 
| 119 | 
            +
              
         | 
| 120 | 
            +
            static void
         | 
| 121 | 
            +
            coverage_event_callsite_hook(rb_event_t event, NODE *node, VALUE self, 
         | 
| 122 | 
            +
                            ID mid, VALUE klass)
         | 
| 123 | 
            +
            {
         | 
| 124 | 
            +
             VALUE caller_ary;
         | 
| 125 | 
            +
             VALUE curr_meth;
         | 
| 126 | 
            +
             VALUE args[2];
         | 
| 127 | 
            +
             int status;
         | 
| 128 | 
            +
             | 
| 129 | 
            +
             caller_ary = callsite_custom_backtrace(caller_stack_len);
         | 
| 130 | 
            +
             | 
| 131 | 
            +
             if(TYPE(klass) == T_ICLASS) {
         | 
| 132 | 
            +
                     klass = CLASS_OF(klass);
         | 
| 133 | 
            +
             }
         | 
| 134 | 
            +
             curr_meth = rb_ary_new();
         | 
| 135 | 
            +
             rb_ary_push(curr_meth, klass);
         | 
| 136 | 
            +
             rb_ary_push(curr_meth, ID2SYM(mid));
         | 
| 137 | 
            +
             | 
| 138 | 
            +
             args[0] = caller_ary;
         | 
| 139 | 
            +
             args[1] = curr_meth;
         | 
| 140 | 
            +
             rb_protect(record_callsite_info, (VALUE)args, &status);
         | 
| 141 | 
            +
             if(!status && node) {
         | 
| 142 | 
            +
                     type_def_site args;        
         | 
| 143 | 
            +
                     
         | 
| 144 | 
            +
                     args.sourcefile = node->nd_file;
         | 
| 145 | 
            +
                     args.sourceline = nd_line(node) - 1;
         | 
| 146 | 
            +
                     args.curr_meth = curr_meth;
         | 
| 147 | 
            +
                     rb_protect(record_method_def_site, (VALUE)&args, NULL);
         | 
| 148 | 
            +
             }
         | 
| 149 | 
            +
             if(status)
         | 
| 150 | 
            +
                     rb_gv_set("$!", Qnil);
         | 
| 151 | 
            +
            }
         | 
| 152 | 
            +
             | 
| 153 | 
            +
             | 
| 154 | 
            +
            static VALUE
         | 
| 155 | 
            +
            cov_install_callsite_hook(VALUE self)
         | 
| 156 | 
            +
            {
         | 
| 157 | 
            +
              if(!callsite_hook_set_p) {
         | 
| 158 | 
            +
                      if(TYPE(caller_info) != T_HASH)
         | 
| 159 | 
            +
                              caller_info = rb_hash_new();
         | 
| 160 | 
            +
                      callsite_hook_set_p = 1;
         | 
| 161 | 
            +
                      rb_add_event_hook(coverage_event_callsite_hook, 
         | 
| 162 | 
            +
                                      RUBY_EVENT_CALL);
         | 
| 163 | 
            +
                      
         | 
| 164 | 
            +
                      return Qtrue;
         | 
| 165 | 
            +
              } else
         | 
| 166 | 
            +
                      return Qfalse;
         | 
| 167 | 
            +
            }
         | 
| 168 | 
            +
             | 
| 169 | 
            +
             | 
| 170 | 
            +
            static VALUE
         | 
| 171 | 
            +
            cov_remove_callsite_hook(VALUE self)
         | 
| 172 | 
            +
            {
         | 
| 173 | 
            +
             if(!callsite_hook_set_p) 
         | 
| 174 | 
            +
                     return Qfalse;
         | 
| 175 | 
            +
             else {
         | 
| 176 | 
            +
                     rb_remove_event_hook(coverage_event_callsite_hook);
         | 
| 177 | 
            +
                     callsite_hook_set_p = 0;
         | 
| 178 | 
            +
                     return Qtrue;
         | 
| 179 | 
            +
             }
         | 
| 180 | 
            +
            }
         | 
| 181 | 
            +
             | 
| 182 | 
            +
             | 
| 183 | 
            +
            static VALUE
         | 
| 184 | 
            +
            cov_generate_callsite_info(VALUE self)
         | 
| 185 | 
            +
            {
         | 
| 186 | 
            +
              VALUE ret;
         | 
| 187 | 
            +
             | 
| 188 | 
            +
              ret = rb_ary_new();
         | 
| 189 | 
            +
              rb_ary_push(ret, caller_info);
         | 
| 190 | 
            +
              rb_ary_push(ret, method_def_site_info);
         | 
| 191 | 
            +
              return ret;
         | 
| 192 | 
            +
            }
         | 
| 193 | 
            +
             | 
| 194 | 
            +
             | 
| 195 | 
            +
            static VALUE
         | 
| 196 | 
            +
            cov_reset_callsite(VALUE self)
         | 
| 197 | 
            +
            {
         | 
| 198 | 
            +
              if(callsite_hook_set_p) {
         | 
| 199 | 
            +
            	  rb_raise(rb_eRuntimeError, 
         | 
| 200 | 
            +
            		  "Cannot reset the callsite info in the middle of a traced run.");
         | 
| 201 | 
            +
            	  return Qnil;
         | 
| 202 | 
            +
              }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
              caller_info = rb_hash_new();
         | 
| 205 | 
            +
              method_def_site_info = rb_hash_new();
         | 
| 206 | 
            +
              return Qnil;
         | 
| 207 | 
            +
            }
         | 
| 208 | 
            +
             | 
| 209 | 
            +
            void
         | 
| 210 | 
            +
            Init_rcov_callsite()
         | 
| 211 | 
            +
            {
         | 
| 212 | 
            +
             VALUE mRcov;
         | 
| 213 | 
            +
             VALUE mRCOV__;
         | 
| 214 | 
            +
             ID id_rcov = rb_intern("Rcov");
         | 
| 215 | 
            +
             ID id_coverage__ = rb_intern("RCOV__");
         | 
| 216 | 
            +
             ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
         | 
| 217 | 
            +
             | 
| 218 | 
            +
             if(rb_const_defined(rb_cObject, id_rcov)) 
         | 
| 219 | 
            +
                     mRcov = rb_const_get(rb_cObject, id_rcov);
         | 
| 220 | 
            +
             else
         | 
| 221 | 
            +
                     mRcov = rb_define_module("Rcov");
         | 
| 222 | 
            +
             | 
| 223 | 
            +
             if(rb_const_defined(mRcov, id_coverage__))
         | 
| 224 | 
            +
                     mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
         | 
| 225 | 
            +
             else
         | 
| 226 | 
            +
                     mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
         | 
| 227 | 
            +
             | 
| 228 | 
            +
             callsite_hook_set_p = 0;
         | 
| 229 | 
            +
             caller_info = rb_hash_new();
         | 
| 230 | 
            +
             method_def_site_info = rb_hash_new();
         | 
| 231 | 
            +
             rb_gc_register_address(&caller_info);
         | 
| 232 | 
            +
             rb_gc_register_address(&method_def_site_info);
         | 
| 233 | 
            +
             
         | 
| 234 | 
            +
             rb_define_singleton_method(mRCOV__, "install_callsite_hook", 
         | 
| 235 | 
            +
                             cov_install_callsite_hook, 0);
         | 
| 236 | 
            +
             rb_define_singleton_method(mRCOV__, "remove_callsite_hook", 
         | 
| 237 | 
            +
                             cov_remove_callsite_hook, 0);
         | 
| 238 | 
            +
             rb_define_singleton_method(mRCOV__, "generate_callsite_info", 
         | 
| 239 | 
            +
            		 cov_generate_callsite_info, 0);
         | 
| 240 | 
            +
             rb_define_singleton_method(mRCOV__, "reset_callsite", cov_reset_callsite, 0);
         | 
| 241 | 
            +
            }
         | 
| 242 | 
            +
            /* vim: set sw=8 expandtab: */
         | 
| @@ -5,6 +5,8 @@ | |
| 5 5 | 
             
            #include <st.h>
         | 
| 6 6 | 
             
            #include <stdlib.h>
         | 
| 7 7 |  | 
| 8 | 
            +
            #define COVERAGE_DEBUG_EVENTS 0
         | 
| 9 | 
            +
             | 
| 8 10 | 
             
            #define RCOVRT_VERSION_MAJOR 2
         | 
| 9 11 | 
             
            #define RCOVRT_VERSION_MINOR 0
         | 
| 10 12 | 
             
            #define RCOVRT_VERSION_REV   0
         | 
| @@ -15,7 +17,6 @@ static VALUE oSCRIPT_LINES__; | |
| 15 17 | 
             
            static ID id_cover;
         | 
| 16 18 | 
             
            static st_table* coverinfo = 0;
         | 
| 17 19 | 
             
            static char coverage_hook_set_p;
         | 
| 18 | 
            -
            static char callsite_hook_set_p;
         | 
| 19 20 |  | 
| 20 21 | 
             
            struct cov_array {
         | 
| 21 22 | 
             
                    unsigned int len;
         | 
| @@ -25,204 +26,6 @@ struct cov_array { | |
| 25 26 | 
             
            static struct cov_array *cached_array = 0;
         | 
| 26 27 | 
             
            static char *cached_file = 0; 
         | 
| 27 28 |  | 
| 28 | 
            -
            typedef struct {
         | 
| 29 | 
            -
                    char *sourcefile;
         | 
| 30 | 
            -
                    unsigned int sourceline;
         | 
| 31 | 
            -
                    VALUE curr_meth;
         | 
| 32 | 
            -
            } type_def_site;       
         | 
| 33 | 
            -
            static VALUE caller_info = 0;
         | 
| 34 | 
            -
            static VALUE method_def_site_info = 0;
         | 
| 35 | 
            -
             | 
| 36 | 
            -
            static caller_stack_len = 1;
         | 
| 37 | 
            -
             | 
| 38 | 
            -
            /*
         | 
| 39 | 
            -
             *
         | 
| 40 | 
            -
             * callsite hook and associated functions
         | 
| 41 | 
            -
             *
         | 
| 42 | 
            -
             * */
         | 
| 43 | 
            -
             | 
| 44 | 
            -
            static VALUE
         | 
| 45 | 
            -
            record_callsite_info(VALUE args)
         | 
| 46 | 
            -
            {
         | 
| 47 | 
            -
              VALUE caller_ary;
         | 
| 48 | 
            -
              VALUE curr_meth;
         | 
| 49 | 
            -
              VALUE count_hash;
         | 
| 50 | 
            -
              VALUE count;
         | 
| 51 | 
            -
              VALUE *pargs = (VALUE *)args;
         | 
| 52 | 
            -
             | 
| 53 | 
            -
              caller_ary = pargs[0];
         | 
| 54 | 
            -
              curr_meth = pargs[1];
         | 
| 55 | 
            -
              count_hash = rb_hash_aref(caller_info, curr_meth);
         | 
| 56 | 
            -
              if(TYPE(count_hash) != T_HASH) { 
         | 
| 57 | 
            -
                      /* Qnil, anything else should be impossible unless somebody's been
         | 
| 58 | 
            -
                       * messing with ObjectSpace */
         | 
| 59 | 
            -
                      count_hash = rb_hash_new();
         | 
| 60 | 
            -
                      rb_hash_aset(caller_info, curr_meth, count_hash);
         | 
| 61 | 
            -
              }
         | 
| 62 | 
            -
              count = rb_hash_aref(count_hash, caller_ary);
         | 
| 63 | 
            -
              if(count == Qnil) 
         | 
| 64 | 
            -
                      count = INT2FIX(0);
         | 
| 65 | 
            -
              count = INT2FIX(FIX2UINT(count) + 1);
         | 
| 66 | 
            -
              rb_hash_aset(count_hash, caller_ary, count);
         | 
| 67 | 
            -
              /*
         | 
| 68 | 
            -
              printf("CALLSITE: %s -> %s   %d\n", RSTRING(rb_inspect(curr_meth))->ptr,
         | 
| 69 | 
            -
                              RSTRING(rb_inspect(caller_ary))->ptr, FIX2INT(count));
         | 
| 70 | 
            -
              */
         | 
| 71 | 
            -
             | 
| 72 | 
            -
              return Qnil;
         | 
| 73 | 
            -
            }
         | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
            static VALUE
         | 
| 77 | 
            -
            record_method_def_site(VALUE args)
         | 
| 78 | 
            -
            {
         | 
| 79 | 
            -
              type_def_site *pargs = (type_def_site *)args;
         | 
| 80 | 
            -
              VALUE def_site_info;
         | 
| 81 | 
            -
              VALUE hash;
         | 
| 82 | 
            -
             | 
| 83 | 
            -
              if( RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth)) )
         | 
| 84 | 
            -
                      return Qnil;
         | 
| 85 | 
            -
              def_site_info = rb_ary_new();
         | 
| 86 | 
            -
              rb_ary_push(def_site_info, rb_str_new2(pargs->sourcefile));
         | 
| 87 | 
            -
              rb_ary_push(def_site_info, INT2NUM(pargs->sourceline+1));
         | 
| 88 | 
            -
              rb_hash_aset(method_def_site_info, pargs->curr_meth, def_site_info);
         | 
| 89 | 
            -
              /*
         | 
| 90 | 
            -
              printf("DEFSITE: %s:%d  for %s\n", pargs->sourcefile, pargs->sourceline+1,
         | 
| 91 | 
            -
                              RSTRING(rb_inspect(pargs->curr_meth))->ptr);
         | 
| 92 | 
            -
              */
         | 
| 93 | 
            -
              
         | 
| 94 | 
            -
              return Qnil;
         | 
| 95 | 
            -
            }
         | 
| 96 | 
            -
             | 
| 97 | 
            -
            static VALUE
         | 
| 98 | 
            -
            callsite_custom_backtrace(int lev)
         | 
| 99 | 
            -
            {
         | 
| 100 | 
            -
              struct FRAME *frame = ruby_frame;
         | 
| 101 | 
            -
              VALUE ary;
         | 
| 102 | 
            -
              NODE *n;
         | 
| 103 | 
            -
              VALUE level;
         | 
| 104 | 
            -
              VALUE klass;
         | 
| 105 | 
            -
             | 
| 106 | 
            -
              ary = rb_ary_new();
         | 
| 107 | 
            -
              if (frame->last_func == ID_ALLOCATOR) {
         | 
| 108 | 
            -
                      frame = frame->prev;
         | 
| 109 | 
            -
              }
         | 
| 110 | 
            -
              for (; frame && (n = frame->node); frame = frame->prev) {
         | 
| 111 | 
            -
                      if (frame->prev && frame->prev->last_func) {
         | 
| 112 | 
            -
                              if (frame->prev->node == n) continue;
         | 
| 113 | 
            -
                              level = rb_ary_new();
         | 
| 114 | 
            -
                              klass = frame->prev->last_class ? frame->prev->last_class : Qnil;
         | 
| 115 | 
            -
                              if(TYPE(klass) == T_ICLASS) {
         | 
| 116 | 
            -
                                      klass = CLASS_OF(klass);
         | 
| 117 | 
            -
                              }
         | 
| 118 | 
            -
                              rb_ary_push(level, klass);
         | 
| 119 | 
            -
                              rb_ary_push(level, ID2SYM(frame->prev->last_func));
         | 
| 120 | 
            -
                              rb_ary_push(level, rb_str_new2(n->nd_file));
         | 
| 121 | 
            -
                              rb_ary_push(level, INT2NUM(nd_line(n)));
         | 
| 122 | 
            -
                      }
         | 
| 123 | 
            -
                      else {
         | 
| 124 | 
            -
                              level = rb_ary_new();
         | 
| 125 | 
            -
                              rb_ary_push(level, Qnil);
         | 
| 126 | 
            -
                              rb_ary_push(level, Qnil);
         | 
| 127 | 
            -
                              rb_ary_push(level, rb_str_new2(n->nd_file));
         | 
| 128 | 
            -
                              rb_ary_push(level, INT2NUM(nd_line(n)));
         | 
| 129 | 
            -
                      }
         | 
| 130 | 
            -
                      rb_ary_push(ary, level);
         | 
| 131 | 
            -
                      if(--lev == 0)
         | 
| 132 | 
            -
                              break;
         | 
| 133 | 
            -
              }
         | 
| 134 | 
            -
             | 
| 135 | 
            -
              return ary;
         | 
| 136 | 
            -
            }
         | 
| 137 | 
            -
              
         | 
| 138 | 
            -
            static void
         | 
| 139 | 
            -
            coverage_event_callsite_hook(rb_event_t event, NODE *node, VALUE self, 
         | 
| 140 | 
            -
                            ID mid, VALUE klass)
         | 
| 141 | 
            -
            {
         | 
| 142 | 
            -
             VALUE caller_ary;
         | 
| 143 | 
            -
             VALUE curr_meth;
         | 
| 144 | 
            -
             VALUE args[2];
         | 
| 145 | 
            -
             int status;
         | 
| 146 | 
            -
             | 
| 147 | 
            -
             caller_ary = callsite_custom_backtrace(caller_stack_len);
         | 
| 148 | 
            -
             | 
| 149 | 
            -
             if(TYPE(klass) == T_ICLASS) {
         | 
| 150 | 
            -
                     klass = CLASS_OF(klass);
         | 
| 151 | 
            -
             }
         | 
| 152 | 
            -
             curr_meth = rb_ary_new();
         | 
| 153 | 
            -
             rb_ary_push(curr_meth, klass);
         | 
| 154 | 
            -
             rb_ary_push(curr_meth, ID2SYM(mid));
         | 
| 155 | 
            -
             | 
| 156 | 
            -
             args[0] = caller_ary;
         | 
| 157 | 
            -
             args[1] = curr_meth;
         | 
| 158 | 
            -
             rb_protect(record_callsite_info, (VALUE)args, &status);
         | 
| 159 | 
            -
             if(!status && node) {
         | 
| 160 | 
            -
                     type_def_site args;        
         | 
| 161 | 
            -
                     
         | 
| 162 | 
            -
                     args.sourcefile = node->nd_file;
         | 
| 163 | 
            -
                     args.sourceline = nd_line(node) - 1;
         | 
| 164 | 
            -
                     args.curr_meth = curr_meth;
         | 
| 165 | 
            -
                     rb_protect(record_method_def_site, (VALUE)&args, NULL);
         | 
| 166 | 
            -
             }
         | 
| 167 | 
            -
             if(status)
         | 
| 168 | 
            -
                     rb_gv_set("$!", Qnil);
         | 
| 169 | 
            -
            }
         | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
            static VALUE
         | 
| 173 | 
            -
            cov_install_callsite_hook(VALUE self)
         | 
| 174 | 
            -
            {
         | 
| 175 | 
            -
              if(!callsite_hook_set_p) {
         | 
| 176 | 
            -
                      if(TYPE(caller_info) != T_HASH)
         | 
| 177 | 
            -
                              caller_info = rb_hash_new();
         | 
| 178 | 
            -
                      callsite_hook_set_p = 1;
         | 
| 179 | 
            -
                      rb_add_event_hook(coverage_event_callsite_hook, 
         | 
| 180 | 
            -
                                      RUBY_EVENT_CALL);
         | 
| 181 | 
            -
                      
         | 
| 182 | 
            -
                      return Qtrue;
         | 
| 183 | 
            -
              } else
         | 
| 184 | 
            -
                      return Qfalse;
         | 
| 185 | 
            -
            }
         | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 188 | 
            -
            static VALUE
         | 
| 189 | 
            -
            cov_remove_callsite_hook(VALUE self)
         | 
| 190 | 
            -
            {
         | 
| 191 | 
            -
             if(!callsite_hook_set_p) 
         | 
| 192 | 
            -
                     return Qfalse;
         | 
| 193 | 
            -
             else {
         | 
| 194 | 
            -
                     rb_remove_event_hook(coverage_event_callsite_hook);
         | 
| 195 | 
            -
                     callsite_hook_set_p = 0;
         | 
| 196 | 
            -
                     return Qtrue;
         | 
| 197 | 
            -
             }
         | 
| 198 | 
            -
            }
         | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
            static VALUE
         | 
| 202 | 
            -
            cov_generate_callsite_info(VALUE self)
         | 
| 203 | 
            -
            {
         | 
| 204 | 
            -
              VALUE ret;
         | 
| 205 | 
            -
             | 
| 206 | 
            -
              ret = rb_ary_new();
         | 
| 207 | 
            -
              rb_ary_push(ret, caller_info);
         | 
| 208 | 
            -
              rb_ary_push(ret, method_def_site_info);
         | 
| 209 | 
            -
              return ret;
         | 
| 210 | 
            -
            }
         | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
            static VALUE
         | 
| 214 | 
            -
            cov_reset_callsite(VALUE self)
         | 
| 215 | 
            -
            {
         | 
| 216 | 
            -
              if(callsite_hook_set_p) {
         | 
| 217 | 
            -
            	  rb_raise(rb_eRuntimeError, 
         | 
| 218 | 
            -
            		  "Cannot reset the callsite info in the middle of a traced run.");
         | 
| 219 | 
            -
            	  return Qnil;
         | 
| 220 | 
            -
              }
         | 
| 221 | 
            -
             | 
| 222 | 
            -
              caller_info = rb_hash_new();
         | 
| 223 | 
            -
              method_def_site_info = rb_hash_new();
         | 
| 224 | 
            -
              return Qnil;
         | 
| 225 | 
            -
            }
         | 
| 226 29 |  | 
| 227 30 | 
             
            /* 
         | 
| 228 31 | 
             
             *
         | 
| @@ -272,10 +75,10 @@ coverage_mark_caller() | |
| 272 75 | 
             
              for (; frame && (n = frame->node); frame = frame->prev) {
         | 
| 273 76 | 
             
                      if (frame->prev && frame->prev->last_func) {
         | 
| 274 77 | 
             
                              if (frame->prev->node == n) continue;
         | 
| 275 | 
            -
                              coverage_increase_counter_uncached(n->nd_file, nd_line(n), 1);
         | 
| 78 | 
            +
                              coverage_increase_counter_uncached(n->nd_file, nd_line(n) - 1, 1);
         | 
| 276 79 | 
             
                      }
         | 
| 277 80 | 
             
                      else {
         | 
| 278 | 
            -
                              coverage_increase_counter_uncached(n->nd_file, nd_line(n), 1);
         | 
| 81 | 
            +
                              coverage_increase_counter_uncached(n->nd_file, nd_line(n) - 1, 1);
         | 
| 279 82 | 
             
                      }
         | 
| 280 83 | 
             
                      break;
         | 
| 281 84 | 
             
              }
         | 
| @@ -300,19 +103,56 @@ coverage_event_coverage_hook(rb_event_t event, NODE *node, VALUE self, | |
| 300 103 | 
             
            {
         | 
| 301 104 | 
             
             char *sourcefile;
         | 
| 302 105 | 
             
             unsigned int sourceline;
         | 
| 106 | 
            +
             static unsigned int in_hook = 0;
         | 
| 303 107 |  | 
| 304 | 
            -
             if( | 
| 108 | 
            +
             if(in_hook) {
         | 
| 305 109 | 
             
                     return;
         | 
| 110 | 
            +
             }
         | 
| 111 | 
            +
             | 
| 112 | 
            +
             in_hook++;
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            #if COVERAGE_DEBUG_EVENTS
         | 
| 115 | 
            +
             do {
         | 
| 116 | 
            +
                     int status;
         | 
| 117 | 
            +
                     VALUE old_exception;
         | 
| 118 | 
            +
                     old_exception = rb_gv_get("$!");
         | 
| 119 | 
            +
                     rb_protect(rb_inspect, klass, &status);
         | 
| 120 | 
            +
                     if(!status) {
         | 
| 121 | 
            +
                             printf("EVENT: %d %s %s %s %d\n", event,
         | 
| 122 | 
            +
                                             klass ? RSTRING(rb_inspect(klass))->ptr : "", 
         | 
| 123 | 
            +
                                             mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
         | 
| 124 | 
            +
                                             : "unknown",
         | 
| 125 | 
            +
                                             node ? node->nd_file : "", node ? nd_line(node) : 0);
         | 
| 126 | 
            +
                     } else {
         | 
| 127 | 
            +
                             printf("EVENT: %d %s %s %d\n", event,
         | 
| 128 | 
            +
                                             mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid)) 
         | 
| 129 | 
            +
                                             : "unknown",
         | 
| 130 | 
            +
                                             node ? node->nd_file : "", node ? nd_line(node) : 0);
         | 
| 131 | 
            +
                     }
         | 
| 132 | 
            +
                     rb_gv_set("$!", old_exception);
         | 
| 133 | 
            +
             } while (0); 
         | 
| 134 | 
            +
            #endif
         | 
| 135 | 
            +
             | 
| 136 | 
            +
             if(event & RUBY_EVENT_C_CALL) {
         | 
| 137 | 
            +
                     coverage_mark_caller();
         | 
| 138 | 
            +
             }
         | 
| 139 | 
            +
             if(event & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_CLASS)) {
         | 
| 140 | 
            +
                     in_hook--;
         | 
| 141 | 
            +
                     return;
         | 
| 142 | 
            +
             }
         | 
| 306 143 |  | 
| 307 | 
            -
             if(node == NULL)
         | 
| 144 | 
            +
             if(node == NULL) {
         | 
| 145 | 
            +
                     in_hook--;
         | 
| 308 146 | 
             
                     return;
         | 
| 147 | 
            +
             }
         | 
| 309 148 |  | 
| 310 149 | 
             
             sourcefile = node->nd_file;
         | 
| 311 150 | 
             
             sourceline = nd_line(node) - 1;
         | 
| 312 151 |  | 
| 313 152 | 
             
             coverage_increase_counter_cached(sourcefile, sourceline);
         | 
| 314 | 
            -
             if(event  | 
| 153 | 
            +
             if(event & RUBY_EVENT_CALL)
         | 
| 315 154 | 
             
                     coverage_mark_caller();
         | 
| 155 | 
            +
             in_hook--;
         | 
| 316 156 | 
             
            }
         | 
| 317 157 |  | 
| 318 158 |  | 
| @@ -323,6 +163,8 @@ cov_install_coverage_hook(VALUE self) | |
| 323 163 | 
             
            	  if(!coverinfo)
         | 
| 324 164 | 
             
            		  coverinfo = st_init_strtable();
         | 
| 325 165 | 
             
                      coverage_hook_set_p = 1;
         | 
| 166 | 
            +
                      /* TODO: allow C_CALL too, since it's supported already
         | 
| 167 | 
            +
                       * the overhead is around ~30%, tested on typo */
         | 
| 326 168 | 
             
                      rb_add_event_hook(coverage_event_coverage_hook, 
         | 
| 327 169 | 
             
                                   RUBY_EVENT_ALL & ~RUBY_EVENT_C_CALL &
         | 
| 328 170 | 
             
                                   ~RUBY_EVENT_C_RETURN & ~RUBY_EVENT_CLASS);
         | 
| @@ -461,27 +303,17 @@ Init_rcovrt() | |
| 461 303 | 
             
                     rb_const_set(rb_cObject, id_script_lines__, oSCRIPT_LINES__);
         | 
| 462 304 | 
             
             }
         | 
| 463 305 |  | 
| 464 | 
            -
             caller_info = rb_hash_new();
         | 
| 465 | 
            -
             method_def_site_info = rb_hash_new();
         | 
| 466 | 
            -
             rb_gc_register_address(&caller_info);
         | 
| 467 | 
            -
             rb_gc_register_address(&method_def_site_info);
         | 
| 468 | 
            -
             | 
| 469 306 | 
             
             coverage_hook_set_p = 0;
         | 
| 470 307 |  | 
| 471 308 | 
             
             rb_define_singleton_method(mRCOV__, "install_coverage_hook", 
         | 
| 472 309 | 
             
                             cov_install_coverage_hook, 0);
         | 
| 473 310 | 
             
             rb_define_singleton_method(mRCOV__, "remove_coverage_hook", 
         | 
| 474 311 | 
             
                             cov_remove_coverage_hook, 0);
         | 
| 475 | 
            -
             rb_define_singleton_method(mRCOV__, "install_callsite_hook", 
         | 
| 476 | 
            -
                             cov_install_callsite_hook, 0);
         | 
| 477 | 
            -
             rb_define_singleton_method(mRCOV__, "remove_callsite_hook", 
         | 
| 478 | 
            -
                             cov_remove_callsite_hook, 0);
         | 
| 479 312 | 
             
             rb_define_singleton_method(mRCOV__, "generate_coverage_info", 
         | 
| 480 313 | 
             
            		 cov_generate_coverage_info, 0);
         | 
| 481 | 
            -
             rb_define_singleton_method(mRCOV__, "generate_callsite_info", 
         | 
| 482 | 
            -
            		 cov_generate_callsite_info, 0);
         | 
| 483 314 | 
             
             rb_define_singleton_method(mRCOV__, "reset_coverage", cov_reset_coverage, 0);
         | 
| 484 | 
            -
             rb_define_singleton_method(mRCOV__, "reset_callsite", cov_reset_callsite, 0);
         | 
| 485 315 | 
             
             rb_define_singleton_method(mRCOV__, "ABI", cov_ABI, 0);
         | 
| 316 | 
            +
             | 
| 317 | 
            +
             Init_rcov_callsite();
         | 
| 486 318 | 
             
            }
         | 
| 487 319 | 
             
            /* vim: set sw=8 expandtab: */
         | 
    
        data/lib/rcov/rcovtask.rb
    CHANGED
    
    | @@ -112,8 +112,8 @@ module Rcov | |
| 112 112 | 
             
                        else %!"#{rcov_path}"!
         | 
| 113 113 | 
             
            	    end
         | 
| 114 114 | 
             
                      ruby_opts = @ruby_opts.clone
         | 
| 115 | 
            -
                      ruby_opts.push run_code
         | 
| 116 115 | 
             
                      ruby_opts.push( "-I#{lib_path}" )
         | 
| 116 | 
            +
                      ruby_opts.push run_code
         | 
| 117 117 | 
             
            	  ruby_opts.push( "-w" ) if @warning
         | 
| 118 118 | 
             
            	  ruby ruby_opts.join(" ") + " " + option_list +
         | 
| 119 119 | 
             
                        %[ -o "#{@output_dir}" ] +
         | 
    
        data/lib/rcov/report.rb
    CHANGED
    
    | @@ -4,8 +4,14 @@ | |
| 4 4 | 
             
            module Rcov
         | 
| 5 5 |  | 
| 6 6 | 
             
            class Formatter # :nodoc:
         | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 7 | 
            +
                require 'pathname'
         | 
| 8 | 
            +
                ignore_files = [
         | 
| 9 | 
            +
                    /\A#{Regexp.escape(Pathname.new(Config::CONFIG["libdir"]).cleanpath.to_s)}/,
         | 
| 10 | 
            +
                    /\btc_[^.]*.rb/,
         | 
| 11 | 
            +
                    /_test\.rb\z/,
         | 
| 12 | 
            +
                    /\btest\//,
         | 
| 13 | 
            +
                    /\bvendor\//,
         | 
| 14 | 
            +
                    /\A#{Regexp.escape(__FILE__)}\z/]
         | 
| 9 15 | 
             
                DEFAULT_OPTS = {:ignore => ignore_files, :sort => :name, :sort_reverse => false,
         | 
| 10 16 | 
             
                                :output_threshold => 101, :dont_ignore => [], 
         | 
| 11 17 | 
             
                                :callsite_analyzer => nil, :comments_run_by_default => false}
         | 
    
        data/lib/rcov/version.rb
    CHANGED
    
    
    
        data/lib/rcov.rb
    CHANGED
    
    | @@ -559,6 +559,7 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer | |
| 559 559 | 
             
              # Return an array with the names of the files whose code was executed inside
         | 
| 560 560 | 
             
              # the block given to #run_hooked or between #install_hook and #remove_hook.
         | 
| 561 561 | 
             
              def analyzed_files
         | 
| 562 | 
            +
                update_script_lines__
         | 
| 562 563 | 
             
                raw_data_relative.select do |file, lines|
         | 
| 563 564 | 
             
                  @script_lines__.has_key?(file)
         | 
| 564 565 | 
             
                end.map{|fname,| fname}
         | 
| @@ -581,6 +582,7 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer | |
| 581 582 | 
             
              # reset the data at any time with #reset to start from scratch.
         | 
| 582 583 | 
             
              def data(filename)
         | 
| 583 584 | 
             
                raw_data = raw_data_relative
         | 
| 585 | 
            +
                update_script_lines__
         | 
| 584 586 | 
             
                unless @script_lines__.has_key?(filename) && 
         | 
| 585 587 | 
             
                       raw_data.has_key?(filename)
         | 
| 586 588 | 
             
                  return nil 
         | 
| @@ -611,6 +613,7 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer | |
| 611 613 | 
             
              def reset; super end
         | 
| 612 614 |  | 
| 613 615 | 
             
              def dump_coverage_info(formatters) # :nodoc:
         | 
| 616 | 
            +
                update_script_lines__
         | 
| 614 617 | 
             
                raw_data_relative.each do |file, lines|
         | 
| 615 618 | 
             
                  next if @script_lines__.has_key?(file) == false
         | 
| 616 619 | 
             
                  lines = @script_lines__[file]
         | 
| @@ -690,19 +693,58 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer | |
| 690 693 | 
             
                  ! different
         | 
| 691 694 | 
             
                end
         | 
| 692 695 |  | 
| 693 | 
            -
                 | 
| 694 | 
            -
                factors = (2..10).to_a.reverse
         | 
| 696 | 
            +
                factors = braindead_factorize(line_info.size)
         | 
| 695 697 | 
             
                factors.each do |n|
         | 
| 696 698 | 
             
                  if is_repeated[n]
         | 
| 697 699 | 
             
                    line_info = line_info[0, line_info.size / n]
         | 
| 698 700 | 
             
                    coverage_info = coverage_info[0, coverage_info.size / n]
         | 
| 699 701 | 
             
                    count_info = count_info[0, count_info.size / n]
         | 
| 700 702 | 
             
                  end
         | 
| 701 | 
            -
                end
         | 
| 703 | 
            +
                end if factors.size > 1   # don't even try if it's prime
         | 
| 702 704 |  | 
| 703 705 | 
             
                [line_info, coverage_info, count_info]
         | 
| 704 706 | 
             
              end
         | 
| 705 707 |  | 
| 708 | 
            +
              def braindead_factorize(num)
         | 
| 709 | 
            +
                return [0] if num == 0
         | 
| 710 | 
            +
                return [-1] + braindead_factorize(-num) if num < 0
         | 
| 711 | 
            +
                factors = []
         | 
| 712 | 
            +
                while num % 2 == 0
         | 
| 713 | 
            +
                  factors << 2
         | 
| 714 | 
            +
                  num /= 2
         | 
| 715 | 
            +
                end
         | 
| 716 | 
            +
                size = num
         | 
| 717 | 
            +
                n = 3
         | 
| 718 | 
            +
                max = Math.sqrt(num)
         | 
| 719 | 
            +
                while n <= max && n <= size
         | 
| 720 | 
            +
                  while size % n == 0
         | 
| 721 | 
            +
                    size /= n
         | 
| 722 | 
            +
                    factors << n
         | 
| 723 | 
            +
                  end
         | 
| 724 | 
            +
                  n += 2
         | 
| 725 | 
            +
                end
         | 
| 726 | 
            +
                factors << size if size != 1
         | 
| 727 | 
            +
                factors
         | 
| 728 | 
            +
              end
         | 
| 729 | 
            +
             | 
| 730 | 
            +
              def update_script_lines__
         | 
| 731 | 
            +
                @script_lines__ = @script_lines__.merge(SCRIPT_LINES__)
         | 
| 732 | 
            +
              end
         | 
| 733 | 
            +
             | 
| 734 | 
            +
              public
         | 
| 735 | 
            +
              def marshal_dump # :nodoc:
         | 
| 736 | 
            +
                # @script_lines__ is updated just before serialization so as to avoid
         | 
| 737 | 
            +
                # missing files in SCRIPT_LINES__
         | 
| 738 | 
            +
                ivs = {}
         | 
| 739 | 
            +
                update_script_lines__
         | 
| 740 | 
            +
                instance_variables.each{|iv| ivs[iv] = instance_variable_get(iv)}
         | 
| 741 | 
            +
                ivs
         | 
| 742 | 
            +
              end
         | 
| 743 | 
            +
             | 
| 744 | 
            +
              def marshal_load(ivs) # :nodoc:
         | 
| 745 | 
            +
                ivs.each_pair{|iv, val| instance_variable_set(iv, val)}
         | 
| 746 | 
            +
              end
         | 
| 747 | 
            +
             | 
| 706 748 | 
             
            end # CodeCoverageAnalyzer
         | 
| 707 749 |  | 
| 708 750 | 
             
            # A CallSiteAnalyzer can be used to obtain information about:
         | 
    
        data/lib/rcovrt.so
    CHANGED
    
    | Binary file | 
    
        data/mingw-rbconfig.rb
    CHANGED
    
    | @@ -7,8 +7,8 @@ | |
| 7 7 | 
             
            # mswin32 builds) is installed under $HOME/ruby-mingw32.
         | 
| 8 8 |  | 
| 9 9 | 
             
            module Config
         | 
| 10 | 
            -
              RUBY_VERSION == "1.8. | 
| 11 | 
            -
             | 
| 10 | 
            +
              #RUBY_VERSION == "1.8.5" or
         | 
| 11 | 
            +
              #  raise "ruby lib version (1.8.5) doesn't match executable version (#{RUBY_VERSION})"
         | 
| 12 12 |  | 
| 13 13 | 
             
              TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/i386-mingw32")
         | 
| 14 14 | 
             
              DESTDIR = '' unless defined? DESTDIR
         | 
    
        data/rcov.vim
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            " Vim compiler file
         | 
| 2 | 
            +
            " Language:	Ruby
         | 
| 3 | 
            +
            " Function:	Code coverage information with rcov
         | 
| 4 | 
            +
            " Maintainer:	Mauricio Fernandez <mfp at acm dot org>
         | 
| 5 | 
            +
            " Info:		
         | 
| 6 | 
            +
            " URL:		http://eigenclass.org/hiki.rb?rcov
         | 
| 7 | 
            +
            " ----------------------------------------------------------------------------
         | 
| 8 | 
            +
            "
         | 
| 9 | 
            +
            " Changelog:
         | 
| 10 | 
            +
            " 0.1:	initial version, shipped with rcov 0.6.0
         | 
| 11 | 
            +
            "
         | 
| 12 | 
            +
            " Comments:
         | 
| 13 | 
            +
            " Initial attempt. 
         | 
| 14 | 
            +
            " ----------------------------------------------------------------------------
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            if exists("current_compiler")
         | 
| 17 | 
            +
              finish
         | 
| 18 | 
            +
            endif
         | 
| 19 | 
            +
            let current_compiler = "rcov"
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            if exists(":CompilerSet") != 2		" older Vim always used :setlocal
         | 
| 22 | 
            +
              command -nargs=* CompilerSet setlocal <args>
         | 
| 23 | 
            +
            endif
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            let s:cpo_save = &cpo
         | 
| 26 | 
            +
            set cpo-=C
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            CompilerSet makeprg=rake\ $*\ RCOVOPTS=\"-D\ --no-html\ --no-color\"\ $*
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            CompilerSet errorformat=
         | 
| 31 | 
            +
                 \%+W\#\#\#\ %f:%l\,
         | 
| 32 | 
            +
                 \%-C\ \ \ ,
         | 
| 33 | 
            +
                 \%-C!!\ 
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            let &cpo = s:cpo_save
         | 
| 36 | 
            +
            unlet s:cpo_save
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            " vim: nowrap sw=2 sts=2 ts=8 ff=unix :
         | 
    
        metadata
    CHANGED
    
    | @@ -1,10 +1,10 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            -
            rubygems_version: 0. | 
| 2 | 
            +
            rubygems_version: 0.9.0
         | 
| 3 3 | 
             
            specification_version: 1
         | 
| 4 4 | 
             
            name: rcov
         | 
| 5 5 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 6 | 
            -
              version: 0. | 
| 7 | 
            -
            date: 2006- | 
| 6 | 
            +
              version: 0.7.0.1
         | 
| 7 | 
            +
            date: 2006-08-04 00:00:00 +02:00
         | 
| 8 8 | 
             
            summary: Code coverage analysis tool for Ruby
         | 
| 9 9 | 
             
            require_paths: 
         | 
| 10 10 | 
             
            - lib
         | 
| @@ -25,6 +25,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement | |
| 25 25 | 
             
            platform: mswin32
         | 
| 26 26 | 
             
            signing_key: 
         | 
| 27 27 | 
             
            cert_chain: 
         | 
| 28 | 
            +
            post_install_message: 
         | 
| 28 29 | 
             
            authors: 
         | 
| 29 30 | 
             
            - Mauricio Fernandez
         | 
| 30 31 | 
             
            files: 
         | 
| @@ -36,7 +37,8 @@ files: | |
| 36 37 | 
             
            - lib/rcov/rant.rb
         | 
| 37 38 | 
             
            - lib/rcov/report.rb
         | 
| 38 39 | 
             
            - ext/rcovrt/extconf.rb
         | 
| 39 | 
            -
            - ext/rcovrt/ | 
| 40 | 
            +
            - ext/rcovrt/rcovrt.c
         | 
| 41 | 
            +
            - ext/rcovrt/callsite.c
         | 
| 40 42 | 
             
            - LEGAL
         | 
| 41 43 | 
             
            - LICENSE
         | 
| 42 44 | 
             
            - Rakefile
         | 
| @@ -55,6 +57,7 @@ files: | |
| 55 57 | 
             
            - test/turn_off_rcovrt.rb
         | 
| 56 58 | 
             
            - test/test_CallSiteAnalyzer.rb
         | 
| 57 59 | 
             
            - mingw-rbconfig.rb
         | 
| 60 | 
            +
            - rcov.vim
         | 
| 58 61 | 
             
            - setup.rb
         | 
| 59 62 | 
             
            - BLURB
         | 
| 60 63 | 
             
            - CHANGES
         |