Skip to content

Commit 34d4cda

Browse files
stronger guarantees for output
result should at least be parsable
1 parent f672907 commit 34d4cda

File tree

6 files changed

+64
-20
lines changed

6 files changed

+64
-20
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* ensure a trailing blank line also if the input is cached (#867).
3737
* Preserve trailing blank line in roxygen examples to simplify concatenation of
3838
examples (#880).
39+
* guarantee that styled code is now parsable (#892).
3940
* An error is now thrown on styling if input unicode characters can't be
4041
correctly parsed for Windows and R < 4.2 (#883).
4142
* Fix argument name `filetype` in Example for `style_dir()` (#855).

R/communicate.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
#' changes carefully.
55
#' @param changed Boolean with indicating for each file whether or not it has
66
#' been changed.
7-
#' @inheritParams can_verify_roundtrip
7+
#' @inheritParams parse_tree_must_be_identical
88
#' @keywords internal
99
communicate_warning <- function(changed, transformers) {
1010
if (any(changed, na.rm = TRUE) &&
11-
!can_verify_roundtrip(transformers) &&
11+
!parse_tree_must_be_identical(transformers) &&
1212
!getOption("styler.quiet", FALSE)
1313
) {
1414
cat("Please review the changes carefully!", fill = TRUE)

R/transform-files.R

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,11 @@ parse_transform_serialize_r <- function(text,
246246
) %>%
247247
unlist()
248248

249-
if (can_verify_roundtrip(transformers)) {
250-
verify_roundtrip(text, text_out)
251-
}
249+
verify_roundtrip(
250+
text, text_out,
251+
parsable_only = !parse_tree_must_be_identical(transformers)
252+
)
253+
252254
text_out <- convert_newlines_to_linebreaks(text_out)
253255
if (cache_is_activated()) {
254256
cache_by_expression(text_out, transformers, more_specs = more_specs)
@@ -349,18 +351,23 @@ apply_transformers <- function(pd_nested, transformers) {
349351
#' @param transformers The list of transformer functions used for styling.
350352
#' Needed for reverse engineering the scope.
351353
#' @keywords internal
352-
can_verify_roundtrip <- function(transformers) {
354+
parse_tree_must_be_identical <- function(transformers) {
353355
length(transformers$token) == 0
354356
}
355357

356358
#' Verify the styling
357359
#'
358360
#' If scope was set to "line_breaks" or lower (compare [tidyverse_style()]),
359361
#' we can compare the expression before and after styling and return an error if
360-
#' it is not the same. Note that this method ignores roxygen code examples and
362+
#' it is not the same.
363+
#' If that's not possible, a weaker guarantee that we want to give is that the
364+
#' resulting code is parsable.
365+
#' @param parsable_only If we should only check for the code to be parsable.
366+
#' @inheritParams expressions_are_identical
367+
#' @section Limitation:
368+
#' Note that this method ignores roxygen code examples and
361369
#' comments and no verification can be conducted if tokens are in the styling
362370
#' scope.
363-
#' @inheritParams expressions_are_identical
364371
#' @importFrom rlang abort
365372
#' @examples
366373
#' styler:::verify_roundtrip("a+1", "a + 1")
@@ -369,8 +376,19 @@ can_verify_roundtrip <- function(transformers) {
369376
#' styler:::verify_roundtrip("a+1", "b - 3")
370377
#' }
371378
#' @keywords internal
372-
verify_roundtrip <- function(old_text, new_text) {
373-
if (!expressions_are_identical(old_text, new_text)) {
379+
verify_roundtrip <- function(old_text, new_text, parsable_only = FALSE) {
380+
if (parsable_only) {
381+
rlang::with_handlers(
382+
parse_text(new_text),
383+
error = function(e) {
384+
rlang::abort(paste0(
385+
"Styling resulted in code that isn't parsable. This should not ",
386+
"happen. Please file a bug report on GitHub ",
387+
"(https://github.com/r-lib/styler/issues) using a reprex."
388+
))
389+
}
390+
)
391+
} else if (!expressions_are_identical(old_text, new_text)) {
374392
msg <- paste(
375393
"The expression evaluated before the styling is not the same as the",
376394
"expression after styling. This should not happen. Please file a",

man/can_verify_roundtrip.Rd renamed to man/parse_tree_must_be_identical.Rd

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/verify_roundtrip.Rd

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-roundtrip.R

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
context("roundtrip works")
22

33

4-
test_that("can_verify_roundtrip works", {
5-
expect_true(can_verify_roundtrip(tidyverse_style(scope = "line_breaks")))
6-
expect_true(can_verify_roundtrip(tidyverse_style(scope = "spaces")))
7-
expect_true(can_verify_roundtrip(tidyverse_style(scope = "indention")))
8-
expect_false(can_verify_roundtrip(tidyverse_style(scope = "tokens")))
4+
test_that("parse_tree_must_be_identical works", {
5+
expect_true(
6+
parse_tree_must_be_identical(tidyverse_style(scope = "line_breaks"))
7+
)
8+
expect_true(parse_tree_must_be_identical(tidyverse_style(scope = "spaces")))
9+
expect_true(
10+
parse_tree_must_be_identical(tidyverse_style(scope = "indention"))
11+
)
12+
expect_false(parse_tree_must_be_identical(tidyverse_style(scope = "tokens")))
913
})
1014

1115
test_that("correct styling does not give an error", {
@@ -15,3 +19,15 @@ test_that("correct styling does not give an error", {
1519
test_that("corrupt styling does give an error", {
1620
expect_error(verify_roundtrip("1-1", "1 + 1"), "bug")
1721
})
22+
23+
24+
test_that("the output is asserted to be parsable", {
25+
expect_error(
26+
verify_roundtrip("1+1", "1 +) 1", parsable_only = TRUE),
27+
"Styling resulted in code that isn't parsable."
28+
)
29+
30+
expect_silent(
31+
verify_roundtrip("1+1", "1 + 1", parsable_only = TRUE)
32+
)
33+
})

0 commit comments

Comments
 (0)