class Rcov::FileStatistics
def extend_heredocs
def extend_heredocs i = 0 while i < @lines.size unless is_code? i i += 1 next end #FIXME: using a restrictive regexp so that only <<[A-Z_a-z]\w* # matches when unquoted, so as to avoid problems with 1<<2 # (keep in mind that whereas puts <<2 is valid, puts 1<<2 is a # parse error, but a = 1<<2 is of course fine) scanner = StringScanner.new(@lines[i]) j = k = i loop do scanned_text = scanner.search_full(/<<(-?)(?:(['"`])((?:(?!\2).)+)\2|([A-Z_a-z]\w*))/, true, true) # k is the first line after the end delimiter for the last heredoc # scanned so far unless scanner.matched? i = k break end term = scanner[3] || scanner[4] # try to ignore symbolic bitshifts like 1<<LSHIFT ident_text = "<<#{scanner[1]}#{scanner[2]}#{term}#{scanner[2]}" if scanned_text[/\d+\s*#{Regexp.escape(ident_text)}/] # it was preceded by a number, ignore i = k break end must_mark = [] end_of_heredoc = (scanner[1] == "-") ? /^\s*#{Regexp.escape(term)}$/ : /^#{Regexp.escape(term)}$/ loop do break if j == @lines.size must_mark << j if end_of_heredoc =~ @lines[j] must_mark.each do |n| @heredoc_start[n] = i end if (must_mark + [i]).any?{|lineidx| @coverage[lineidx]} @coverage[i] ||= :inferred must_mark.each{|lineidx| @coverage[lineidx] ||= :inferred} end # move the "first line after heredocs" index if @lines[j+=1] =~ /^\s*\n$/ k = j end break end j += 1 end end i += 1 end end