EDITED to use base functions:
You can use sys.calls()
to see the call stack, and then look through it for lines with debug info. Here's a demonstration that does it.
# First, some code that will generate a warning
fun <- function(x, y){
z = sum(x,y)
if(z > 15)
warning("Potential problem")
return(z)
}
x = 10; y = 20
# Here's a handler that looks through the call stack
# for locations. Not all calls have recorded locations
# (most packages are installed without debug info)
# but this will find the debug info if it is there,
# and add it to the warning message.
locatedWarnings <- function(e) {
calls <- sys.calls()
locations <- character()
for (i in rev(seq_along(calls)))
if (!is.null(srcref <- getSrcref(calls[[i]])))
locations <- c(locations, sprintf("%s:%d", getSrcFilename(srcref), srcref[1]))
# If we found any locations, redo the warning
# with those locations prepended to the message
if (length(locations)) {
call <- if (!is.null(e$call)) paste("In", deparse(e$call)) else ""
warning(sprintf("%s at %s: %s", call, paste(locations, collapse=","), conditionMessage(e)), call. = FALSE)
invokeRestart("muffleWarning")
}
}
withCallingHandlers(fun(x, y),
warning = locatedWarnings)
#> Warning: In fun(x, y) at <text>:5: Potential problem
#> [1] 30
Created on 2023-02-15 with reprex v2.0.2
If you put this example in a file and source it with the default keep.source = TRUE
, you'll get the filename and line for the warning line as well as the withCallingHandlers()
line. Not sure why reprex
didn't give the second one. If you just execute it by cut and paste to the console you won't get very useful line info, because every statement restarts the line count.