Skip to content

Commit 7a7da57

Browse files
sbearrowsjimhester
andauthored
Feature add error message for incorrect decorators (#180)
Co-authored-by: Jim Hester <[email protected]>
1 parent 6de7785 commit 7a7da57

File tree

7 files changed

+115
-0
lines changed

7 files changed

+115
-0
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
# cpp11 0.2.7
77

8+
* Outputting more informative error message when cpp11 decorators are incorrectly formatted (@sbearrows, #127)
89
* Fix spurious diffs from `tools::package_native_routine_registration_skeleton()` by temporarily using C collation (@sbearrows, #171)
910
* Fix a transient memory leak for functions that return values from `cpp11::unwind_protect()` and `cpp11::safe` (#154)
1011
* `cpp_source()` now gets an argument `dir` to allow customized temporary directory to store generated source files.

R/register.R

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ cpp_register <- function(path = ".", quiet = FALSE) {
4646
return(invisible(character()))
4747
}
4848

49+
check_valid_attributes(all_decorations)
50+
4951
funs <- get_registered_functions(all_decorations, "cpp11::register", quiet)
5052

5153
package <- desc::desc_get("Package", file = file.path(path, "DESCRIPTION"))
@@ -274,3 +276,22 @@ get_cpp_register_needs <- function() {
274276
res <- read.dcf(system.file("DESCRIPTION", package = "cpp11"))[, "Config/Needs/cpp11/cpp_register"]
275277
strsplit(res, "[[:space:]]*,[[:space:]]*")[[1]]
276278
}
279+
280+
check_valid_attributes <- function(decorations) {
281+
282+
bad_decor <- !decorations$decoration %in% c("cpp11::register", "cpp11::init")
283+
284+
if(any(bad_decor)) {
285+
lines <- decorations$line[bad_decor]
286+
file <- decorations$file[bad_decor]
287+
names <- decorations$decoration[bad_decor]
288+
bad_lines <- glue::glue_collapse(glue::glue("- Invalid attribute `{names}` on
289+
line {lines} in file '{file}'."), "\n")
290+
291+
msg <- glue::glue("cpp11 attributes must be either `cpp11::register` or `cpp11::init`:
292+
{bad_lines}
293+
")
294+
stop(msg, call. = FALSE)
295+
296+
}
297+
}

R/source.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, qu
105105
suppressWarnings(
106106
all_decorations <- decor::cpp_decorations(dir, is_attribute = TRUE)
107107
)
108+
109+
check_valid_attributes(all_decorations)
110+
108111
cli_suppress(
109112
funs <- get_registered_functions(all_decorations, "cpp11::register")
110113
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[[cpp11:register]] int foo() { return 1; }
2+
3+
[[cpp11:register]] double bar(bool run) { return 1.0; }
4+
5+
[[cpp11::register]] bool baz(bool run, int value = 0) { return true; }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[[cpp11:register]] int foo() { return 1; }

tests/testthat/test-register.R

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,3 +703,36 @@ describe("generate_init_functions", {
703703
expect_equal(generate_init_functions(funs), list(declarations = "\nvoid foo(DllInfo* dll);\nvoid bar(DllInfo* dll);\n", calls = "\n foo(dll);\n bar(dll);"))
704704
})
705705
})
706+
707+
test_that("check_valid_attributes does not return an error if all registers are correct", {
708+
pkg <- local_package()
709+
p <- pkg_path(pkg)
710+
dir.create(file.path(p, "src"))
711+
file.copy(test_path("single.cpp"), file.path(p, "src", "single.cpp"))
712+
713+
expect_error_free(cpp_register(p))
714+
715+
pkg <- local_package()
716+
p <- pkg_path(pkg)
717+
dir.create(file.path(p, "src"))
718+
file.copy(test_path("multiple.cpp"), file.path(p, "src", "multiple.cpp"))
719+
720+
expect_error_free(cpp_register(p))
721+
})
722+
723+
724+
test_that("check_valid_attributes returns an error if one or more registers is incorrect", {
725+
pkg <- local_package()
726+
p <- pkg_path(pkg)
727+
dir.create(file.path(p, "src"))
728+
file.copy(test_path("single_incorrect.cpp"), file.path(p, "src", "single_incorrect.cpp"))
729+
730+
expect_error(cpp_register(p))
731+
732+
pkg <- local_package()
733+
p <- pkg_path(pkg)
734+
dir.create(file.path(p, "src"))
735+
file.copy(test_path("multiple_incorrect.cpp"), file.path(p, "src", "multiple_incorrect.cpp"))
736+
737+
expect_error(cpp_register(p))
738+
})

tests/testthat/test-source.R

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,54 @@ test_that("generate_include_paths handles paths with spaces", {
102102
}
103103
})
104104

105+
test_that("check_valid_attributes does not return an error if all registers are correct", {
106+
expect_error_free(
107+
cpp11::cpp_source(code = '#include <cpp11.hpp>
108+
using namespace cpp11::literals;
109+
[[cpp11::register]]
110+
cpp11::list fn() {
111+
cpp11::writable::list x;
112+
x.push_back({"foo"_nm = 1});
113+
return x;
114+
}
115+
[[cpp11::register]]
116+
cpp11::list fn2() {
117+
cpp11::writable::list x;
118+
x.push_back({"foo"_nm = 1});
119+
return x;
120+
}'))
121+
})
122+
123+
test_that("check_valid_attributes returns an error if one or more registers is incorrect", {
124+
expect_error(
125+
cpp11::cpp_source(code = '#include <cpp11.hpp>
126+
using namespace cpp11::literals;
127+
[[cpp11:register]]
128+
cpp11::list fn() {
129+
cpp11::writable::list x;
130+
x.push_back({"foo"_nm = 1});
131+
return x;
132+
}
133+
[[cpp11::register]]
134+
cpp11::list fn2() {
135+
cpp11::writable::list x;
136+
x.push_back({"foo"_nm = 1});
137+
return x;
138+
}'))
139+
140+
expect_error(
141+
cpp11::cpp_source(code = '#include <cpp11.hpp>
142+
using namespace cpp11::literals;
143+
[[cpp11:register]]
144+
cpp11::list fn() {
145+
cpp11::writable::list x;
146+
x.push_back({"foo"_nm = 1});
147+
return x;
148+
}
149+
[[cpp11::egister]]
150+
cpp11::list fn2() {
151+
cpp11::writable::list x;
152+
x.push_back({"foo"_nm = 1});
153+
return x;
154+
}'))
155+
})

0 commit comments

Comments
 (0)