Skip to content

Commit 51114d9

Browse files
committed
find the .External() call when rewriting module function formals
1 parent a791bbe commit 51114d9

3 files changed

Lines changed: 28 additions & 6 deletions

File tree

‎ChangeLog‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
* inst/tinytest/test_internal_function.R: Idem
1313
* inst/tinytest/test_internal_function_cpp11.R: Idem
1414

15+
* R/00_classes.R (.cppfunction_formals_gets): Find the .External() call
16+
in the body of the function instead of assuming it is the second
17+
element, which it is not once coverage tools have instrumented the body
18+
* R/00_classes.R (.cppfunction_set_external_args): New helper
19+
* inst/tinytest/test_module.R: Test it with an instrumented body
20+
1521
2026-10-23 Dirk Eddelbuettel <edd@debian.org>
1622

1723
* DESCRIPTION (Version, Date): Roll micro version and date

‎R/00_classes.R‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,23 @@ setClass( "C++Function",
117117
contains = "function"
118118
)
119119

120-
.cppfunction_formals_gets <- function (fun, envir = environment(fun), value) {
121-
bd <- body(fun)
122-
b2 <- bd[[2L]]
123-
for( i in seq_along(value) ){
124-
b2[[3L+i]] <- as.name( names(value)[i] )
120+
## passes the arguments named in 'names' on from the .External(entry,
121+
## pointer, ...) call in expr; the call is searched for rather than assumed
122+
## to be a top-level statement, as coverage tools wrap each statement
123+
.cppfunction_set_external_args <- function( expr, names ){
124+
if( !is.call( expr ) )
125+
return( expr )
126+
if( identical( expr[[1L]], as.name( ".External" ) ) )
127+
return( as.call( c( as.list( expr )[1:3], lapply( names, as.name ) ) ) )
128+
for( i in seq_along( expr )[-1L] ){
129+
if( is.call( expr[[i]] ) )
130+
expr[[i]] <- .cppfunction_set_external_args( expr[[i]], names )
125131
}
126-
bd[[2]] <- b2
132+
expr
133+
}
134+
135+
.cppfunction_formals_gets <- function (fun, envir = environment(fun), value) {
136+
bd <- .cppfunction_set_external_args( body(fun), names(value) )
127137
f <- fun@.Data
128138
formals(f) <- value
129139
body(f) <- bd

‎inst/tinytest/test_module.R‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ expect_equal( foo_formals(), 20.0 )
5050
expect_equal( foo_formals( y = 3.0 ), 6.0 )
5151
expect_error( foo_short_formals(), "expecting 2, got 1" )
5252

53+
## formals<- finds the .External() call wherever it is in the body, e.g.
54+
## inside the block that coverage tools (covr) wrap each statement in
55+
wrapped <- quote({ if (TRUE) { covr:::count("key"); .External(entry, pointer, ...) } })
56+
expect_equal( deparse( Rcpp:::.cppfunction_set_external_args( wrapped, c("x", "y") ) ),
57+
deparse( quote({ if (TRUE) { covr:::count("key"); .External(entry, pointer, x, y) } }) ) )
58+
5359
w <- new( ModuleWorld )
5460
expect_equal( w$greet(), "hello" )
5561
w$set( "hello world" )

0 commit comments

Comments
 (0)