Skip to content

Commit 77c4568

Browse files
authored
Add format-string-to-format-symbol rule (#442)
1 parent d5162c6 commit 77c4568

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

default-recommendations/syntax-shortcuts-test.rkt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,28 @@ test: "syntax-e on a single format-id argument is removable"
2828

2929
test: "format-id call without any syntax-e unwrapped arguments not refactorable"
3030
- (format-id #'foo "~a.~a.~a" #'bar #'baz #'blah)
31+
32+
33+
test: "making a symbol with format can be simplified to format-symbol"
34+
- (string->symbol (format "make-~a" "foo"))
35+
- (format-symbol "make-~a" "foo")
36+
37+
38+
test: "making a symbol with format from a symbol can be simplified to format-symbol"
39+
- (string->symbol (format "make-~a" (symbol->string 'foo)))
40+
- (format-symbol "make-~a" 'foo)
41+
42+
43+
test: "making a symbol with format from an identifier can be simplified to format-symbol"
44+
- (string->symbol (format "make-~a" (symbol->string (syntax-e #'foo))))
45+
- (format-symbol "make-~a" #'foo)
46+
47+
48+
test: "making a symbol with format from a keyword can be simplified to format-symbol"
49+
- (string->symbol (format "make-~a" (keyword->string '#:foo)))
50+
- (format-symbol "make-~a" '#:foo)
51+
52+
53+
test: "making a symbol with format from a keyword syntax object can be simplified to format-symbol"
54+
- (string->symbol (format "make-~a" (keyword->string (syntax-e #'#:foo))))
55+
- (format-symbol "make-~a" #'#:foo)

default-recommendations/syntax-shortcuts.rkt

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
[syntax-shortcuts refactoring-suite?]))
1010

1111

12-
(require racket/syntax
12+
(require racket/string
13+
racket/syntax
1314
rebellion/private/static-name
1415
resyntax/base
1516
syntax/parse)
@@ -43,5 +44,65 @@
4344
(format-id lctx fmt arg.simplified ...))
4445

4546

47+
(define-syntax-class format-symbol-argument
48+
#:attributes (simplified)
49+
#:literals (syntax-e keyword->string symbol->string)
50+
51+
(pattern (syntax-e inner:format-symbol-argument) #:attr simplified (attribute inner.simplified))
52+
53+
(pattern (keyword->string inner:format-symbol-argument)
54+
#:attr simplified (attribute inner.simplified))
55+
56+
(pattern (symbol->string inner:format-symbol-argument)
57+
#:attr simplified (attribute inner.simplified))
58+
59+
(pattern simplified:expr))
60+
61+
62+
;; The format-symbol function only allows ~a placeholders. Rather a fancy generic utilty that finds
63+
;; all placeholders, we just explicitly list out all the other ones and check one-by-one whether any
64+
;; of them are contained in the template string. That's easier to implement and the performance
65+
;; doesn't matter at all since template strings are almost always short.
66+
(define disallowed-format-symbol-placeholders
67+
(list "~n"
68+
"~%"
69+
"~s"
70+
"~S"
71+
"~v"
72+
"~V"
73+
"~.a"
74+
"~.A"
75+
"~.s"
76+
"~.S"
77+
"~.v"
78+
"~.V"
79+
"~e"
80+
"~E"
81+
"~c"
82+
"~C"
83+
"~b"
84+
"~B"
85+
"~o"
86+
"~O"
87+
"~x"
88+
"~X"
89+
"~ "
90+
"~\n"
91+
"~\t"))
92+
93+
94+
(define-refactoring-rule format-string-to-format-symbol
95+
#:description
96+
"This `format` expression can be simplified to an equivalent `format-symbol` expression."
97+
#:literals (format string->symbol)
98+
99+
(string->symbol (format template:str arg:format-symbol-argument ...))
100+
#:when (for/and ([disallowed (in-list disallowed-format-symbol-placeholders)])
101+
(not (string-contains? (syntax-e #'template) disallowed)))
102+
103+
(format-symbol template (~replacement arg.simplified #:original arg) ...))
104+
105+
46106
(define-refactoring-suite syntax-shortcuts
47-
#:rules (syntax-e-in-format-id-unnecessary))
107+
#:rules (format-string-to-format-symbol
108+
syntax-e-in-format-id-unnecessary))

0 commit comments

Comments
 (0)