diff --git a/default-recommendations/boolean-shortcuts-test.rkt b/default-recommendations/boolean-shortcuts-test.rkt index ccf7de0..f37cbd0 100644 --- a/default-recommendations/boolean-shortcuts-test.rkt +++ b/default-recommendations/boolean-shortcuts-test.rkt @@ -109,6 +109,24 @@ test: "when not can be refactored to use unless" ------------------------------ +test: "refactoring negated when into unless preserves comments" +------------------------------ +; comment before +(when + ; strangely positioned comment before + (not 'foo) + ; comment after + (displayln "not foo")) +------------------------------ +------------------------------ +; comment before +; strangely positioned comment before +(unless 'foo + ; comment after + (displayln "not foo")) +------------------------------ + + test: "unless not can be refactored to use when" ------------------------------ (unless (not 'foo) @@ -118,3 +136,21 @@ test: "unless not can be refactored to use when" (when 'foo (displayln "foo")) ------------------------------ + + +test: "refactoring negated unless into when preserves comments" +------------------------------ +; comment before +(unless + ; strangely positioned comment before + (not 'foo) + ; comment after + (displayln "foo")) +------------------------------ +------------------------------ +; comment before +; strangely positioned comment before +(when 'foo + ; comment after + (displayln "foo")) +------------------------------ diff --git a/default-recommendations/boolean-shortcuts.rkt b/default-recommendations/boolean-shortcuts.rkt index e6a00e1..adcb7a7 100644 --- a/default-recommendations/boolean-shortcuts.rkt +++ b/default-recommendations/boolean-shortcuts.rkt @@ -16,6 +16,7 @@ resyntax/default-recommendations/private/syntax-tree resyntax/refactoring-rule resyntax/refactoring-suite + resyntax/private/syntax-neighbors resyntax/private/syntax-replacement syntax/parse) @@ -67,18 +68,25 @@ (and condition then)]) +(define-syntax-class negated-condition + #:attributes (flipped) + #:literals (not) + (pattern (not base-condition:expr) + #:with flipped #`(~replacement base-condition #:original #,this-syntax))) + + (define-refactoring-rule inverted-when - #:description "This negated when expression can be replaced by an unless expression." - #:literals (when not) - [(when (~and negated (not condition)) body0 body ...) - (unless condition (ORIGINAL-GAP negated body0) body0 body ...)]) + #:description "This negated `when` expression can be replaced by an `unless` expression." + #:literals (when) + [(when-id:when negated:negated-condition body ...) + ((~replacement unless #:original when-id) negated.flipped body ...)]) (define-refactoring-rule inverted-unless #:description "This negated `unless` expression can be replaced by a `when` expression." - #:literals (unless not) - [(unless (~and negated (not condition)) body0 body ...) - (when condition (ORIGINAL-GAP negated body0) body0 body ...)]) + #:literals (unless) + [(unless-id:unless negated:negated-condition body ...) + ((~replacement when #:original unless-id) negated.flipped body ...)]) (define boolean-shortcuts diff --git a/default-recommendations/conditional-shortcuts.rkt b/default-recommendations/conditional-shortcuts.rkt index 700d818..2b0763d 100644 --- a/default-recommendations/conditional-shortcuts.rkt +++ b/default-recommendations/conditional-shortcuts.rkt @@ -20,6 +20,7 @@ resyntax/default-recommendations/private/syntax-lines resyntax/refactoring-rule resyntax/refactoring-suite + resyntax/private/syntax-neighbors resyntax/private/syntax-replacement syntax/parse) @@ -130,15 +131,16 @@ clause ... last-non-else-clause (~and outer-else-clause [else (cond nested-clause ...)])) (outer-cond-id clause ... last-non-else-clause - (ORIGINAL-GAP last-non-else-clause outer-else-clause) - nested-clause ...)]) + (ORIGINAL-GAP last-non-else-clause outer-else-clause) + nested-clause ...)]) (define-syntax-class let-refactorable-cond-clause - #:attributes ([refactored 0]) + #:attributes (refactored) (pattern - [condition:expr let-expr:body-with-refactorable-let-expression] - #:with refactored #'[condition let-expr.refactored ...])) + (~and clause [condition:expr let-expr:body-with-refactorable-let-expression]) + #:with refactored + #'(~replacement [condition let-expr.refactored ...] #:original clause))) (define (first-syntax stx) @@ -155,20 +157,8 @@ #:description "Internal definitions are recommended instead of `let` expressions, to reduce nesting." #:literals (cond) - [((~and outer-cond-id cond) - clause-before ... - clause:let-refactorable-cond-clause - clause-after ...) - #:with form-before (or (last-syntax #'(clause-before ...)) #'outer-cond-id) - #:with (after ...) - (let ([form-after (first-syntax #'(clause-after ...))]) - (if form-after - #`((ORIGINAL-GAP clause #,form-after) clause-after ...) - (list))) - (outer-cond-id clause-before ... - (ORIGINAL-GAP form-before clause) - clause.refactored - after ...)]) + [(cond-id:cond clause-before ... clause:let-refactorable-cond-clause clause-after ...) + (cond-id clause-before ... clause.refactored clause-after ...)]) (define-syntax-class if-arm @@ -202,9 +192,7 @@ (if (attribute else-expr.uses-begin?) #'([else (ORIGINAL-GAP then-expr else-expr) else-expr.refactored ...]) #'((ORIGINAL-GAP then-expr else-expr) [else else-expr.refactored ...])) - (cond - true-branch ... - false-branch ...)]) + (cond true-branch ... false-branch ...)]) (define-refactoring-rule if-let-to-cond diff --git a/default-recommendations/for-loop-shortcuts.rkt b/default-recommendations/for-loop-shortcuts.rkt index 75a43bf..4ffe991 100644 --- a/default-recommendations/for-loop-shortcuts.rkt +++ b/default-recommendations/for-loop-shortcuts.rkt @@ -21,7 +21,7 @@ resyntax/default-recommendations/private/metafunction resyntax/default-recommendations/private/syntax-identifier-sets resyntax/default-recommendations/private/syntax-lines - resyntax/private/syntax-replacement + resyntax/private/syntax-neighbors syntax/parse) @@ -61,9 +61,9 @@ #:attributes (flat? [leading-clause 1] trailing-expression) (pattern - (append-map - (_:lambda-by-any-name (y:id) append-map-body:sequence-syntax-convertible-list-expression) - list-expression:sequence-syntax-convertible-list-expression) + (append-map + (_:lambda-by-any-name (y:id) append-map-body:sequence-syntax-convertible-list-expression) + list-expression:sequence-syntax-convertible-list-expression) #:with flat? #false #:with (leading-clause ...) #'([y list-expression.refactored]) #:with trailing-expression #'append-map-body.refactored) @@ -79,31 +79,31 @@ #:literals (map filter append-map) (pattern - (map - (_:lambda-by-any-name (x:id) loop-body:expr ...+) - (filter - (_:lambda-by-any-name (y:id) filter-body:expr) - list-expression:sequence-syntax-convertible-list-expression)) + (map + (_:lambda-by-any-name (x:id) loop-body:expr ...+) + (filter + (_:lambda-by-any-name (y:id) filter-body:expr) + list-expression:sequence-syntax-convertible-list-expression)) #:when (bound-identifier=? #'x #'y) #:with nesting-loop? #false #:with loop-clauses #'([x list-expression.refactored] #:when filter-body) #:with loop #'(for/list loop-clauses loop-body ...)) (pattern - (map - (_:lambda-by-any-name (x:id) loop-body:expr ...+) - (append-map - (_:lambda-by-any-name (y:id) append-map-body:sequence-syntax-convertible-list-expression) - list-expression:sequence-syntax-convertible-list-expression)) + (map + (_:lambda-by-any-name (x:id) loop-body:expr ...+) + (append-map + (_:lambda-by-any-name (y:id) append-map-body:sequence-syntax-convertible-list-expression) + list-expression:sequence-syntax-convertible-list-expression)) #:when (not (bound-identifier=? #'x #'y)) #:with nesting-loop? #true #:with loop-clauses #'([y list-expression.refactored] [x append-map-body.refactored]) #:with loop #'(for*/list loop-clauses loop-body ...)) (pattern - (map - (_:lambda-by-any-name (x:id) loop-body:expr ...+) - list-expression:sequence-syntax-convertible-list-expression) + (map + (_:lambda-by-any-name (x:id) loop-body:expr ...+) + list-expression:sequence-syntax-convertible-list-expression) #:with nesting-loop? #false #:with loop-clauses #'([x list-expression.refactored]) #:with loop #'(for/list loop-clauses loop-body ...))) @@ -180,14 +180,14 @@ #:description "`for` loops can build vectors directly." #:literals (list->vector) [(list->vector (loop-id:for-list-id clauses body ...)) - (loop-id.vector-id (ORIGINAL-GAP loop-id clauses) clauses body ...)]) + ((~replacement loop-id.vector-id #:original loop-id) clauses body ...)]) (define-refactoring-rule list->set-to-for/set #:description "`for` loops can build sets directly" #:literals (list->set) [(list->set (loop-id:for-list-id clauses body ...)) - (loop-id.set-id (ORIGINAL-GAP loop-id clauses) clauses body ...)]) + ((~replacement loop-id.set-id #:original loop-id) clauses body ...)]) (define-refactoring-rule for/fold-building-hash-to-for/hash @@ -195,8 +195,8 @@ #:literals (for/fold for*/fold hash make-immutable-hash) [((~or (~and for/fold (~bind [loop #'for/hash])) (~and for*/fold (~bind [loop #'for*/hash]))) ([h:id (~or (hash) (make-immutable-hash))]) iteration-clauses - body ... - (hash-set h-usage:id key value)) + body ... + (hash-set h-usage:id key value)) #:when (free-identifier=? #'h #'h-usage) #:when (not (set-member? (syntax-free-identifiers #'(body ...)) #'h)) (loop iteration-clauses body ... (values key value))]) @@ -247,10 +247,11 @@ [((~and loop-id (~or for/and for*/and)) (~and original-clauses (clause ...)) (~and original-body (or condition:condition-expression ...+ last-condition))) - (loop-id (ORIGINAL-GAP loop-id original-clauses) - (clause ... (~@ (~if condition.negated? #:when #:unless) condition.base-condition) ...) - (ORIGINAL-GAP original-clauses original-body) - last-condition)]) + (loop-id + (~replacement + (clause ... (~@ (~if condition.negated? #:when #:unless) condition.base-condition) ...) + #:original original-clauses) + (~replacement last-condition #:original original-body))]) (define-syntax-class apply-append-refactorable-for-loop diff --git a/default-recommendations/gap-preservation-test.rkt b/default-recommendations/gap-preservation-test.rkt index 6e838ae..627c811 100644 --- a/default-recommendations/gap-preservation-test.rkt +++ b/default-recommendations/gap-preservation-test.rkt @@ -65,3 +65,70 @@ test: "comments preserved in splice when form inserted at end" c "foo")) ----------------------------------- + + +test: "comments preserved in splice when first form replaced" +----------------------------------- +(define (code replace-first-with-foo a b c) + (replace-first-with-foo a + ; buggy comment after (sorawee/fmt#68) + b + c)) +----------------------------------- +----------------------------------- +(define (code replace-first-with-foo a b c) + ; buggy comment after (sorawee/fmt#68) +("foo" b c)) +----------------------------------- + + +test: "comments preserved in splice when second form replaced" +----------------------------------- +(define (code replace-second-with-foo a b c) + (replace-second-with-foo a + ; buggy comment before (sorawee/fmt#68) + b + ; comment after + c)) +----------------------------------- +----------------------------------- +(define (code replace-second-with-foo a b c) + ; buggy comment before (sorawee/fmt#68) +(a "foo" + ; comment after + c)) +----------------------------------- + + +test: "comments preserved in splice when last form replaced" +----------------------------------- +(define (code replace-last-with-foo a b c) + (replace-last-with-foo a + b + ; comment before + c)) +----------------------------------- +----------------------------------- +(define (code replace-last-with-foo a b c) + (a b + ; comment before + "foo")) +----------------------------------- + + +test: "comments preserved in splice when first and last forms replaced" +----------------------------------- +(define (code replace-first-and-last-with-foo a b c) + (replace-first-and-last-with-foo a + ; buggy comment after (sorawee/fmt#68) + b + ; comment before + c)) +----------------------------------- +----------------------------------- +(define (code replace-first-and-last-with-foo a b c) + ; buggy comment after (sorawee/fmt#68) +("foo" b + ; comment before + "foo")) +----------------------------------- diff --git a/default-recommendations/gap-preservation.rkt b/default-recommendations/gap-preservation.rkt index 961451d..2e7ab85 100644 --- a/default-recommendations/gap-preservation.rkt +++ b/default-recommendations/gap-preservation.rkt @@ -15,19 +15,10 @@ [gap-preservation-rules refactoring-suite?])) -(require (for-syntax racket/base) - racket/list - rebellion/private/static-name - resyntax/default-recommendations/private/boolean - resyntax/default-recommendations/private/definition-context - resyntax/default-recommendations/private/exception - resyntax/default-recommendations/private/let-binding - resyntax/default-recommendations/private/metafunction - resyntax/default-recommendations/private/syntax-lines +(require rebellion/private/static-name resyntax/refactoring-rule resyntax/refactoring-suite - resyntax/private/syntax-replacement - syntax/parse) + resyntax/private/syntax-neighbors) ;@---------------------------------------------------------------------------------------------------- @@ -57,6 +48,31 @@ [(insert-foo-first-and-last a ...) ("foo" a ... "foo")]) +(define-refactoring-rule suggest-replacing-first-with-foo + #:description "This refactoring rule is for testing Resyntax, ignore its suggestions." + #:datum-literals (replace-first-with-foo) + [(replace-first-with-foo old a ...) ((~replacement "foo" #:original old) a ...)]) + + +(define-refactoring-rule suggest-replacing-second-with-foo + #:description "This refactoring rule is for testing Resyntax, ignore its suggestions." + #:datum-literals (replace-second-with-foo) + [(replace-second-with-foo a0 old a ...) (a0 (~replacement "foo" #:original old) a ...)]) + + +(define-refactoring-rule suggest-replacing-last-with-foo + #:description "This refactoring rule is for testing Resyntax, ignore its suggestions." + #:datum-literals (replace-last-with-foo) + [(replace-last-with-foo a ... old) (a ... (~replacement "foo" #:original old))]) + + +(define-refactoring-rule suggest-replacing-first-and-last-with-foo + #:description "This refactoring rule is for testing Resyntax, ignore its suggestions." + #:datum-literals (replace-first-and-last-with-foo) + [(replace-first-and-last-with-foo old1 a ... old2) + ((~replacement "foo" #:original old1) a ... (~replacement "foo" #:original old2))]) + + (define gap-preservation-rules (refactoring-suite #:name (name gap-preservation-rules) @@ -64,4 +80,8 @@ (list suggest-inserting-foo-first suggest-inserting-foo-second suggest-inserting-foo-last - suggest-inserting-foo-first-and-last))) \ No newline at end of file + suggest-inserting-foo-first-and-last + suggest-replacing-first-with-foo + suggest-replacing-second-with-foo + suggest-replacing-last-with-foo + suggest-replacing-first-and-last-with-foo))) diff --git a/default-recommendations/hash-shortcuts.rkt b/default-recommendations/hash-shortcuts.rkt index fc14a01..dd86b62 100644 --- a/default-recommendations/hash-shortcuts.rkt +++ b/default-recommendations/hash-shortcuts.rkt @@ -19,7 +19,7 @@ resyntax/default-recommendations/private/syntax-identifier-sets resyntax/refactoring-rule resyntax/refactoring-suite - resyntax/private/syntax-replacement + resyntax/private/syntax-neighbors syntax/parse) @@ -30,7 +30,7 @@ #:description "The lambda can be removed from the failure result in this `hash-ref` expression." #:literals (hash-ref) [((~and ref hash-ref) h:expr k:expr (~and lambda-expr (_:lambda-by-any-name () v:literal-constant))) - (ref h k (ORIGINAL-GAP k lambda-expr) v)]) + (ref h k (~replacement v #:original lambda-expr))]) (define-refactoring-rule hash-ref!-with-constant-lambda-to-hash-ref!-without-lambda @@ -38,7 +38,7 @@ #:literals (hash-ref!) [((~and ref hash-ref!) h:expr k:expr (~and lambda-expr (_:lambda-by-any-name () v:literal-constant))) - (ref h k (ORIGINAL-GAP k lambda-expr) v)]) + (ref h k (~replacement v #:original lambda-expr))]) (define-syntax-class value-initializer diff --git a/default-recommendations/legacy-syntax-migrations.rkt b/default-recommendations/legacy-syntax-migrations.rkt index 033b63e..1ff42c2 100644 --- a/default-recommendations/legacy-syntax-migrations.rkt +++ b/default-recommendations/legacy-syntax-migrations.rkt @@ -17,6 +17,7 @@ rebellion/private/static-name resyntax/refactoring-rule resyntax/refactoring-suite + resyntax/private/syntax-neighbors resyntax/private/syntax-replacement syntax/parse) @@ -59,8 +60,8 @@ "The `syntax-local-match-introduce` function is a legacy function that's equivalent to\ `syntax-local-introduce`." #:literals (syntax-local-match-introduce) - [((~and id syntax-local-match-introduce) stx) - (syntax-local-introduce (ORIGINAL-GAP id stx) stx)]) + [(id:syntax-local-match-introduce stx) + ((~replacement syntax-local-introduce #:original id) stx)]) (define-refactoring-rule syntax-local-provide-introduce-migration @@ -68,8 +69,8 @@ "The `syntax-local-provide-introduce` function is a legacy function that's equivalent to\ `syntax-local-introduce`." #:literals (syntax-local-provide-introduce) - [((~and id syntax-local-provide-introduce) stx) - (syntax-local-introduce (ORIGINAL-GAP id stx) stx)]) + [(id:syntax-local-provide-introduce stx) + ((~replacement syntax-local-introduce #:original id) stx)]) (define-refactoring-rule syntax-local-require-introduce-migration @@ -77,8 +78,8 @@ "The `syntax-local-require-introduce` function is a legacy function that's equivalent to\ `syntax-local-introduce`." #:literals (syntax-local-require-introduce) - [((~and id syntax-local-require-introduce) stx) - (syntax-local-introduce (ORIGINAL-GAP id stx) stx)]) + [(id:syntax-local-require-introduce stx) + ((~replacement syntax-local-introduce #:original id) stx)]) (define-refactoring-rule syntax-local-syntax-parse-pattern-introduce-migration @@ -86,8 +87,8 @@ "The `syntax-local-syntax-parse-pattern-introduce` function is a legacy function that's equivalent\ to `syntax-local-introduce`." #:literals (syntax-local-syntax-parse-pattern-introduce) - [((~and id syntax-local-syntax-parse-pattern-introduce) stx) - (syntax-local-introduce (ORIGINAL-GAP id stx) stx)]) + [(id:syntax-local-syntax-parse-pattern-introduce stx) + ((~replacement syntax-local-introduce #:original id) stx)]) (define legacy-syntax-migrations diff --git a/default-recommendations/private/let-binding.rkt b/default-recommendations/private/let-binding.rkt index 01cf352..ee73696 100644 --- a/default-recommendations/private/let-binding.rkt +++ b/default-recommendations/private/let-binding.rkt @@ -19,7 +19,7 @@ rebellion/type/record resyntax/default-recommendations/private/graph resyntax/private/source - resyntax/private/syntax-replacement + resyntax/private/syntax-neighbors resyntax/refactoring-rule syntax/id-set syntax/parse @@ -284,14 +284,8 @@ #:with id* id #`(define (id* . args) body ...)] - [_ - (cond - [different-lines? #`(define #,id (ORIGINAL-GAP #,id-side #,rhs) #,rhs)] - [else #`(define #,id #,rhs)])])] - [_ - (cond - [different-lines? #`(define-values #,id-side #,rhs)] - [else #`(define-values #,id-side #,rhs)])])) + [_ #`(define (~replacement #,id #:original #,id-side) #,rhs)])] + [_ #`(define-values #,id-side #,rhs)])) (define (binding-clause-depends-on? dependant dependency) diff --git a/default-recommendations/syntax-parse-shortcuts.rkt b/default-recommendations/syntax-parse-shortcuts.rkt index 16d3e79..517ae62 100644 --- a/default-recommendations/syntax-parse-shortcuts.rkt +++ b/default-recommendations/syntax-parse-shortcuts.rkt @@ -12,6 +12,7 @@ (require rebellion/private/static-name resyntax/refactoring-rule resyntax/refactoring-suite + resyntax/private/syntax-neighbors resyntax/private/syntax-replacement syntax/parse syntax/parse/define) @@ -23,15 +24,14 @@ (define-refactoring-rule define-simple-macro-to-define-syntax-parse-rule #:description "The `define-simple-macro` form has been renamed to `define-syntax-parse-rule`." #:literals (define-simple-macro) - [((~and original define-simple-macro) first-form form ...) + [(original:define-simple-macro header form ...) ;; The define-simple-macro is a renamed alias of define-syntax-parse-rule, so it's ;; free-identifier=?. As a result, we need to check the actual symbol of the identifier instead of ;; just its binding. See https://github.com/jackfirth/resyntax/issues/106. #:when (equal? (syntax-e #'original) 'define-simple-macro) - (define-syntax-parse-rule (ORIGINAL-GAP original first-form) - first-form form ...)]) + ((~replacement define-syntax-parse-rule #:original original) header form ...)]) (define syntax-parse-shortcuts diff --git a/private/refactoring-result.rkt b/private/refactoring-result.rkt index 045ffcb..99b2252 100644 --- a/private/refactoring-result.rkt +++ b/private/refactoring-result.rkt @@ -38,6 +38,7 @@ resyntax/private/code-snippet resyntax/private/line-replacement resyntax/private/linemap + resyntax/private/logger resyntax/private/source resyntax/private/string-indent resyntax/private/string-replacement @@ -106,6 +107,7 @@ ;; format any refactored code initially generated by Resyntax. (define (format-refactored-code refactored-source-code #:start start #:end end) (define changed-code-substring (substring refactored-source-code start end)) + (log-resyntax-debug "about to format unformatted code:\n~a" changed-code-substring) (define initial-columns (string-column-offset refactored-source-code start)) (define formatted-code-substring (program-format changed-code-substring #:indent initial-columns)) diff --git a/private/syntax-neighbors.rkt b/private/syntax-neighbors.rkt index bd464cc..709b3a7 100644 --- a/private/syntax-neighbors.rkt +++ b/private/syntax-neighbors.rkt @@ -14,16 +14,19 @@ (provide + ~replacement (contract-out [syntax-original-leading-neighbor (-> syntax? (or/c syntax? #false))] [syntax-original-trailing-neighbor (-> syntax? (or/c syntax? #false))] [syntax-originally-neighbors? (-> syntax? syntax? boolean?)] - [syntax-mark-original-neighbors (-> syntax? syntax?)])) + [syntax-mark-original-neighbors (-> syntax? syntax?)] + [syntax-extract-original (-> syntax? syntax?)])) (require guard racket/syntax-srcloc - syntax/parse) + syntax/parse + syntax/parse/experimental/template) (module+ test @@ -71,17 +74,30 @@ (syntax-property stx 'original-trailing-neighbor)) -(define/guard (syntax-originally-neighbors? left-stx right-stx) - (define left-trailer (syntax-original-trailing-neighbor left-stx)) - (define right-leader (syntax-original-leading-neighbor right-stx)) - (guard (and left-trailer right-leader) #:else #false) - (define left-srcloc (syntax-srcloc left-stx)) - (define left-trailer-srcloc (syntax-srcloc left-trailer)) - (define right-srcloc (syntax-srcloc right-stx)) - (define right-leader-srcloc (syntax-srcloc right-leader)) - (guard (and left-srcloc left-trailer-srcloc right-srcloc right-leader-srcloc) #:else #false) - (and (equal? left-trailer-srcloc right-srcloc) - (equal? right-leader-srcloc left-srcloc))) +(define-template-metafunction (~replacement stx) + (syntax-parse stx + [(_ new-stx #:original orig-syntax) + (syntax-property #'new-stx 'replacement-for #'orig-syntax)])) + + +(define (syntax-extract-original stx) + (or (syntax-property stx 'replacement-for) stx)) + + +(define (syntax-originally-neighbors? left-stx right-stx) + (let* ([left-stx (syntax-extract-original left-stx)] + [right-stx (syntax-extract-original right-stx)]) + (guarded-block + (define left-trailer (syntax-original-trailing-neighbor left-stx)) + (define right-leader (syntax-original-leading-neighbor right-stx)) + (guard (and left-trailer right-leader) #:else #false) + (define left-srcloc (syntax-srcloc left-stx)) + (define left-trailer-srcloc (syntax-srcloc left-trailer)) + (define right-srcloc (syntax-srcloc right-stx)) + (define right-leader-srcloc (syntax-srcloc right-leader)) + (guard (and left-srcloc left-trailer-srcloc right-srcloc right-leader-srcloc) #:else #false) + (and (equal? left-trailer-srcloc right-srcloc) + (equal? right-leader-srcloc left-srcloc))))) (module+ test diff --git a/private/syntax-replacement.rkt b/private/syntax-replacement.rkt index 411c3b1..5371fe6 100644 --- a/private/syntax-replacement.rkt +++ b/private/syntax-replacement.rkt @@ -128,9 +128,11 @@ (define/guard (original-separator-piece stx trailing-stx) (guard (syntax-originally-neighbors? stx trailing-stx) #:else #false) - (define stx-end (+ (sub1 (syntax-position stx)) (syntax-span stx))) - (define trailing-start (sub1 (syntax-position trailing-stx))) - (copied-string stx-end trailing-start)) + (let* ([stx (syntax-extract-original stx)] + [trailing-stx (syntax-extract-original trailing-stx)]) + (define stx-end (+ (sub1 (syntax-position stx)) (syntax-span stx))) + (define trailing-start (sub1 (syntax-position trailing-stx))) + (copied-string stx-end trailing-start))) (define/guard (shift-left vs) diff --git a/testing/refactoring-test.rkt b/testing/refactoring-test.rkt index 16552c0..ff17391 100644 --- a/testing/refactoring-test.rkt +++ b/testing/refactoring-test.rkt @@ -17,6 +17,7 @@ racket/match racket/port racket/pretty + racket/string racket/stxparam rackunit rackunit/private/check-info @@ -121,34 +122,39 @@ (define-check (check-suite-refactors suite original-program expected-program) (define logged-messages-builder (make-vector-builder)) - (define results - (with-intercepted-logging - (λ (log-entry) - (vector-builder-add logged-messages-builder (vector-ref log-entry 1))) - #:logger resyntax-logger - (λ () (refactor original-program #:suite suite)) - 'debug)) - (define logged-messages (build-vector logged-messages-builder)) + + (define (save-log log-entry) + (vector-builder-add logged-messages-builder (vector-ref log-entry 1))) + + (define (call-with-logs-captured proc) + (with-intercepted-logging save-log #:logger resyntax-logger proc 'debug)) + + (define (build-logs-info) + (string-info (string-join (vector->list (build-vector logged-messages-builder)) "\n"))) + + (define results (call-with-logs-captured (λ () (refactor original-program #:suite suite)))) (with-check-info* (if (empty? results) - (list (check-info 'logs logged-messages)) - (list (check-info 'logs logged-messages) - (check-info 'matched-rules (refactoring-results-matched-rules-info results)))) + '() + (list (check-info 'matched-rules (refactoring-results-matched-rules-info results)))) (λ () (define replacement (with-handlers ([exn:fail? (λ (e) - (with-check-info (['original (string-block original-program)] + (with-check-info (['logs (build-logs-info)] + ['original (string-block original-program)] ['expected (string-block expected-program)] ['exception e]) (fail-check "an error occurred while processing refactoring results")))]) - (transduce results - (mapping refactoring-result-string-replacement) - #:into union-into-string-replacement))) + (call-with-logs-captured + (λ () (transduce results + (mapping refactoring-result-string-replacement) + #:into union-into-string-replacement))))) (define refactored-program (string-apply-replacement original-program replacement)) - (with-check-info (['actual (string-block refactored-program)] + (with-check-info (['logs (build-logs-info)] + ['actual (string-block refactored-program)] ['expected (string-block expected-program)]) (when (empty? results) (fail-check "no changes were made")) @@ -160,11 +166,13 @@ (match-define (program-output original-stdout original-stderr) (eval-program original-program)) (match-define (program-output actual-stdout actual-stderr) (eval-program refactored-program)) (unless (equal? original-stdout actual-stdout) - (with-check-info (['actual (string-block actual-stdout)] + (with-check-info (['logs (build-logs-info)] + ['actual (string-block actual-stdout)] ['original (string-block original-stdout)]) (fail-check "output to stdout changed"))) (unless (equal? original-stderr actual-stderr) - (with-check-info (['actual (string-block actual-stderr)] + (with-check-info (['logs (build-logs-info)] + ['actual (string-block actual-stderr)] ['original (string-block original-stderr)]) (fail-check "output to stderr changed"))))))