Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions src/CoverageTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,24 @@ const CovCount = Union{Nothing,Int}
"""
has_embedded_errors(expr)

Recursively check if an expression contains any `:error` nodes.
Recursively check if an expression contains any `:error` nodes that represent
actual parse errors. This excludes false positives like `Expr(:error, :symbol)`
which appear when JuliaSyntax parses `break label` where `label` happens to be
named `:error` or other keywords.

True parse errors either have no arguments `Expr(:error)` or have string messages.
"""
function has_embedded_errors(expr)
expr isa Expr || return false
expr.head === :error && return true
if expr.head === :error
# Expr(:error, :symbol) appears from "break symbol" where symbol is a label name
# This is not a parse error, just unfortunate naming when the label is :error, :done, etc.
# Real parse errors are Expr(:error) with no args or Expr(:error, "message string")
if length(expr.args) == 1 && expr.args[1] isa Symbol
return false # This is a label reference, not a parse error
end
return true # This is a real parse error
end
return any(has_embedded_errors, expr.args)
end

Expand All @@ -46,7 +59,7 @@ function find_error_line(expr, last_line=nothing)
return Int(line_num), false
end
end

if expr.head === :error
# Found an error, return the last seen line number
return last_line, true
Expand Down
13 changes: 13 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ end
# Test no error
ast_no_error = Expr(:block, :(x = 1), :(y = 2))
@test !CoverageTools.has_embedded_errors(ast_no_error)

# Test Expr(:error, :symbol) from "break label" is NOT treated as an error
# This can occur when JuliaSyntax parses "break error" where "error" is a label name
ast_break_label = Expr(:&&, :(val === nothing), :(break), Expr(:error, :error))
@test !CoverageTools.has_embedded_errors(ast_break_label)

# Test with other label names
ast_break_done = Expr(:block, Expr(:error, :done))
@test !CoverageTools.has_embedded_errors(ast_break_done)

# But real error messages (strings) should still be detected
ast_real_error = Expr(:block, Expr(:error, "syntax error"))
@test CoverageTools.has_embedded_errors(ast_real_error)
end

withenv("DISABLE_AMEND_COVERAGE_FROM_SRC" => nothing) do
Expand Down
Loading