From b4aba4f49b457ac37d11849d6e1737c020e9882b Mon Sep 17 00:00:00 2001
From: "Jennifer (Jenny) Bryan" <jenny.f.bryan@gmail.com>
Date: Sun, 29 Nov 2020 19:55:17 -0800
Subject: [PATCH] Functions not objects (#557)

* Option to control whether undesirable function names can appear as symbol

Closes #556

* Use inlined source

* Simplify

* Add expectation

* Remove examples

* Make test more concise

* operator spacing

Co-authored-by: AshesITR <alexander.rosenstock@web.de>
Co-authored-by: Michael Chirico <michaelchirico4@gmail.com>
---
 R/undesirable_function_linter.R               | 22 ++++++++++++++-----
 man/linters.Rd                                | 17 +++++++++-----
 .../test-undesirable_function_linter.R        |  9 ++++++++
 3 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/R/undesirable_function_linter.R b/R/undesirable_function_linter.R
index a54994b33..8ca4d6e08 100644
--- a/R/undesirable_function_linter.R
+++ b/R/undesirable_function_linter.R
@@ -1,12 +1,22 @@
-#' @describeIn linters  Report the use of undesirable functions, e.g. \code{return}, \code{options},
-#'                      or \code{sapply} and suggest an alternative.
-#' @param fun  Named character vector, where the names are the names of the undesirable functions,
-#'             and the values are the text for the alternative function to use (or \code{NA}).
+#' @describeIn linters Report the use of undesirable functions, e.g.
+#'   \code{return}, \code{options}, or \code{sapply} and suggest an alternative.
+#' @param fun Named character vector, where the names are the names of the
+#'   undesirable functions, and the values are the text for the alternative
+#'   function to use (or \code{NA}).
+#' @param symbol_is_undesirable Whether to consider the use of an undesirable
+#'   function name as a symbol undesirable or not.
 #' @export
-undesirable_function_linter <- function(fun=default_undesirable_functions) {
+undesirable_function_linter <- function(fun = default_undesirable_functions,
+                                        symbol_is_undesirable = TRUE) {
+  stopifnot(is.logical(symbol_is_undesirable))
   function(source_file) {
+    if (symbol_is_undesirable) {
+      vals <- c("SYMBOL_FUNCTION_CALL", "SYMBOL")
+    } else {
+      vals <- "SYMBOL_FUNCTION_CALL"
+    }
     lapply(
-      ids_with_token(source_file, c("SYMBOL_FUNCTION_CALL", "SYMBOL"), fun=`%in%`),
+      ids_with_token(source_file, vals, fun = `%in%`),
       function(id) {
         token <- with_id(source_file, id)
         fun_name <- token[["text"]]
diff --git a/man/linters.Rd b/man/linters.Rd
index 6a4febf8e..7fee6467f 100644
--- a/man/linters.Rd
+++ b/man/linters.Rd
@@ -127,7 +127,10 @@ trailing_blank_lines_linter(source_file)
 
 trailing_whitespace_linter(source_file)
 
-undesirable_function_linter(fun = default_undesirable_functions)
+undesirable_function_linter(
+  fun = default_undesirable_functions,
+  symbol_is_undesirable = TRUE
+)
 
 undesirable_operator_linter(op = default_undesirable_operators)
 
@@ -165,8 +168,12 @@ match at least one of these styles.}
   \item{trailing}{Semicolons following the last statement on the line.}
 }}
 
-\item{fun}{Named character vector, where the names are the names of the undesirable functions,
-and the values are the text for the alternative function to use (or \code{NA}).}
+\item{fun}{Named character vector, where the names are the names of the
+undesirable functions, and the values are the text for the alternative
+function to use (or \code{NA}).}
+
+\item{symbol_is_undesirable}{Whether to consider the use of an undesirable
+function name as a symbol undesirable or not.}
 
 \item{op}{Named character vector, where the names are the names of the undesirable operators,
 and the values are the text for the alternative operator to use (or \code{NA}).}
@@ -270,8 +277,8 @@ arguments with incompatible types in \code{sprintf} calls.
 
 \item \code{trailing_whitespace_linter}: check there are no trailing whitespace characters.
 
-\item \code{undesirable_function_linter}: Report the use of undesirable functions, e.g. \code{return}, \code{options},
-or \code{sapply} and suggest an alternative.
+\item \code{undesirable_function_linter}: Report the use of undesirable functions, e.g.
+\code{return}, \code{options}, or \code{sapply} and suggest an alternative.
 
 \item \code{undesirable_operator_linter}: Report the use of undesirable operators, e.g. \code{`:::`} or \code{`<<-`}
 and suggest an alternative.
diff --git a/tests/testthat/test-undesirable_function_linter.R b/tests/testthat/test-undesirable_function_linter.R
index 1f356932d..0de14e808 100644
--- a/tests/testthat/test-undesirable_function_linter.R
+++ b/tests/testthat/test-undesirable_function_linter.R
@@ -16,3 +16,12 @@ test_that("linter returns correct linting", {
               ),
               linter)
 })
+
+test_that("it's possible to NOT lint symbols", {
+  linter <- undesirable_function_linter(
+    fun = c("dir" = NA, "log10" = "use log()"),
+    symbol_is_undesirable = FALSE
+  )
+  expect_lint("dir <- 'path/to/a/directory'", NULL, linter)
+  expect_lint("lapply(x, log10)", NULL, linter)
+})