Skip to content

Commit 553630f

Browse files
committed
Fix .try_as_list listable setting; add tests
1 parent 218e1df commit 553630f

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

R/FunctionReporter.R

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -398,17 +398,19 @@ FunctionReporter <- R6::R6Class(
398398
# an environment pointer then we can break x up into list of components
399399
listable <- .is_listable_expr(x)
400400
if (!is.list(x) && listable) {
401-
x <- .try_as_list(x)
401+
result <- .try_as_list(x)
402+
x <- result$value
403+
listable <- result$listable
402404

403-
if (length(x) > 0){
405+
if (listable && length(x) > 0){
404406
# Check for expression of the form foo$bar
405407
# We still want to split it up because foo might be a function
406408
# but we want to get rid of bar, because it's a symbol in foo's namespace
407409
# and not a symbol that could be reliably matched to the package namespace
408410
if (identical(x[[1]], quote(`$`))) {
409411
x <- x[1:2]
410412
}
411-
} else {
413+
} else if (listable) {
412414
# make empty lists "not listable" so recursion stops
413415
listable <- FALSE
414416
}
@@ -456,21 +458,26 @@ FunctionReporter <- R6::R6Class(
456458
# [description]
457459
.try_as_list <- function(x) {
458460
tryCatch(
459-
as.list(x),
461+
list(
462+
value = as.list(x),
463+
listable = TRUE
464+
),
460465
error = function(e) {
461466
log_warn(sprintf(
462467
paste0(
463-
".parse_function: as.list() failed for ",
468+
"Expression parsing: as.list() failed for ",
464469
"typeof=%s class=%s; treating as unlistable. ",
465470
"Please report to pkgnet maintainers in an issue. ",
466-
"Error: %s",
471+
"Error: %s"
467472
),
468473
typeof(x),
469474
paste(class(x), collapse = ","),
470475
conditionMessage(e)
471476
))
472-
listable <<- FALSE
473-
return(x)
477+
list(
478+
value = x,
479+
listable = FALSE
480+
)
474481
}
475482
)
476483
}
@@ -689,8 +696,10 @@ FunctionReporter <- R6::R6Class(
689696
# If it is not a list but listable...
690697
if (!is.list(x) && listable) {
691698
# Convert to list
692-
xList <- .try_as_list(x)
693-
if (length(xList) > 0){
699+
result <- .try_as_list(x)
700+
xList <- result$value
701+
listable <- result$listable
702+
if (listable && length(xList) > 0){
694703
# Check if expression x is from _$_
695704
if (identical(xList[[1]], quote(`$`))) {
696705
# Check if expression x is of form self$foo, private$foo, or super$foo
@@ -709,7 +718,7 @@ FunctionReporter <- R6::R6Class(
709718
# Left Hand is not a _$_. Proceed as normal list.
710719
x <- xList
711720
}
712-
} else {
721+
} else if (listable) {
713722
# List is zero length. This might occur when encountering a "break" command.
714723
# Make empty list "non-listable" so recursion stops in following step.
715724
listable <- FALSE
@@ -731,4 +740,3 @@ FunctionReporter <- R6::R6Class(
731740
}
732741
return(out)
733742
}
734-

tests/testthat/test-FunctionReporter-class.R

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,39 @@ test_that(".parse_R6_expression correctly parses expressions containing a next s
340340
})
341341
})
342342

343+
test_that(".is_listable_expr treats external pointers as unlistable", {
344+
ptr <- new("externalptr")
345+
expect_false(pkgnet:::.is_listable_expr(ptr))
346+
})
347+
348+
test_that(".parse_function falls back when as.list fails on listable objects", {
349+
if (!methods::isClass("PkgnetNoListable")) {
350+
methods::setClass("PkgnetNoListable", slots = c(x = "numeric"))
351+
}
352+
obj <- methods::new("PkgnetNoListable", x = 1)
353+
354+
expect_true(pkgnet:::.is_listable_expr(obj))
355+
expect_error(as.list(obj))
356+
357+
result <- expect_no_error(pkgnet:::.parse_function(obj))
358+
expect_true(is.character(result))
359+
expect_length(result, 1)
360+
})
361+
362+
test_that(".parse_R6_expression falls back when as.list fails on listable objects", {
363+
if (!methods::isClass("PkgnetNoListable")) {
364+
methods::setClass("PkgnetNoListable", slots = c(x = "numeric"))
365+
}
366+
obj <- methods::new("PkgnetNoListable", x = 1)
367+
368+
expect_true(pkgnet:::.is_listable_expr(obj))
369+
expect_error(as.list(obj))
370+
371+
result <- expect_no_error(pkgnet:::.parse_R6_expression(obj))
372+
expect_true(is.character(result))
373+
expect_length(result, 1)
374+
})
375+
343376

344377
test_that("FunctionReporter R6 edge extraction handles case where all methods have the same number of dependencies", {
345378

0 commit comments

Comments
 (0)