Closed malta895 closed 2 years ago
I can confirm this issue.
Removing the expand-file-name
call makes the function work when the lcov contains just absolute paths. The problem is that the parsing occurs in a new buffer and the call expects this buffer to have a file associated, something that causes the argument to return nil, which is not a string and thus the error we're getting.
One solution I see is working in terms of the default-directory variable, which is defined at that point. However, there are no guarantees that the relative paths and the default directory match. They would match if the coverage collector is called from the current buffer, which for the project I am working on is not the case.
If your lcov has absolute paths, the ugly workaround I have and works is evaluating the following expression:
(defun cov--lcov-parse (&optional buffer)
"Parse lcov trace file in BUFFER.
Read from `current-buffer' if BUFFER is nil.
Return a list `((FILE . ((LINE-NUM EXEC-COUNT) ...)) ...)'."
(let ((data (make-hash-table :test 'equal)) ; the collected data
filelines ; data for the current SourceFile
sourcefile) ; the current SourceFile
(with-current-buffer (or buffer (current-buffer))
(save-excursion
(save-match-data
(save-restriction
(widen)
(goto-char (point-min))
(while (not (eobp))
(unless (looking-at cov--lcov-prefix-re)
(error "Unable to parse lcov data from %s: %s"
(or (buffer-file-name) (buffer-name))
(buffer-substring (line-beginning-position) (line-end-position))))
(goto-char (match-end 0))
(pcase (match-string 1)
;; Each SF signals the start of a new SourceFile.
("SF" (if (or sourcefile filelines)
(error "lcov parse error, SF with no preceeding end_of_record %s:%d"
(buffer-file-name) (line-number-at-pos (point)))
;; SF always hold an absolute path
(setq sourcefile (file-truename
(buffer-substring (point) (line-end-position))))
(setq filelines
(or (gethash sourcefile data)
(puthash sourcefile (make-hash-table :test 'eql) data)))))
;; DA:<line-num>,<exec-count>[,...]
("DA" (if (looking-at (rx (group-n 1 (1+ digit)) ?,
(group-n 2 (1+ digit))
(optional ?, (group (* any)))))
(let ((lineno (string-to-number (match-string 1)))
(count (string-to-number (match-string 2))))
(puthash lineno (+ (gethash lineno filelines 0) count) filelines))
(error "lcov parse error, bad DA line %s:%d"
(buffer-file-name) (line-number-at-pos (point)))))
;; End of coverage data for a source file, push
;; current file information to `data'
("end_of_record" (setq sourcefile nil filelines nil)))
(forward-line 1))))))
;; TODO: Make it possible - or even mandatory - to use hashes instead of lists
(cl-loop for sf being the hash-keys of data using (hash-values lines)
collect (cons sf
(cl-loop for lineno being the hash-keys of lines
using (hash-values count)
collect (list lineno count))))))
Right, the coverage data is read into a temporary buffer to be parsed. The buffer file name is not set. Definitely a bug.
I am using Emacs version: 27.1, with Spacemacs.
I'm trying to get cov to work on a javascript project, the coverage report file is located at:
To find the
lcov.info
relatively from the root of the project, I set:When I visit any
.js
file in my project and activatecov-mode
, the functioncov--lcov-parse
fails with the errorwrong type argument stringp nil
, thrown by the functionfile-name-directory
at this line, where it seems that the variablebuffer-file-name
is foundnil
.I can see from the debugger that the path to the
lcov.info
file is correct.I also tried by setting the absolute
cov-lcov-file-name
, with the same outcome.Did I get something wrong in my configuration, or is it a possible bug?