Skip to content

Commit 61e585b

Browse files
Copilotjackfirth
andauthored
Filter out refactoring suggestions that produce non-compiling code (#747)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: jackfirth <[email protected]>
1 parent 4801d3a commit 61e585b

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

main.rkt

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,19 @@
214214
(refactor-visited-forms
215215
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))
216216

217-
(refactoring-result-set #:base-source source #:results results))
217+
(define result-set (refactoring-result-set #:base-source source #:results results))
218+
219+
;; Filter out result sets that produce non-compiling code
220+
(cond
221+
[(and (not (empty? results))
222+
(not (refactoring-result-set-compiles? result-set)))
223+
(log-resyntax-warning
224+
"dropping ~a refactoring suggestion~a for ~a because the modified code does not compile"
225+
(length results)
226+
(if (equal? (length results) 1) "" "s")
227+
(or (source-path source) "string source"))
228+
(refactoring-result-set #:base-source source #:results '())]
229+
[else result-set]))
218230

219231

220232
(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
@@ -335,6 +347,18 @@
335347
(grouping into-list)
336348
(mapping
337349
(λ (e) (refactoring-result-set #:base-source (entry-key e) #:results (entry-value e))))
350+
(filtering
351+
(λ (result-set)
352+
(define compiles? (refactoring-result-set-compiles? result-set))
353+
(unless compiles?
354+
(define source (refactoring-result-set-base-source result-set))
355+
(define num-results (length (refactoring-result-set-results result-set)))
356+
(log-resyntax-warning
357+
"dropping ~a refactoring suggestion~a for ~a because the modified code does not compile"
358+
num-results
359+
(if (equal? num-results 1) "" "s")
360+
(or (source-path source) "string source")))
361+
compiles?))
338362
(indexing refactoring-result-set-base-source)
339363
#:into into-hash))
340364

@@ -478,4 +502,28 @@
478502
(check-false (set-empty? (refactoring-suite-analyzers test-suite)))
479503
;; Verify that all analyzers in the suite are expansion-analyzer?
480504
(check-true (for/and ([analyzer (in-set (refactoring-suite-analyzers test-suite))])
481-
(expansion-analyzer? analyzer)))))
505+
(expansion-analyzer? analyzer))))
506+
507+
(test-case "broken refactoring rules are filtered out"
508+
;; Define a refactoring rule that produces code that doesn't compile
509+
(define-refactoring-rule breaking-rule
510+
#:description "Breaking refactoring rule"
511+
#:datum-literals (foo)
512+
#:literals (define)
513+
(define foo 42)
514+
(if))
515+
516+
(define breaking-suite (refactoring-suite #:rules (list breaking-rule)))
517+
(define test-source (string-source "#lang racket/base\n\n(define foo 42)\n"))
518+
519+
;; Test with direct analyze
520+
(define result-set (resyntax-analyze test-source #:suite breaking-suite))
521+
(check-equal? (length (refactoring-result-set-results result-set)) 0
522+
"Breaking suggestions should be filtered from resyntax-analyze")
523+
524+
;; Test with multipass analyze
525+
(define analysis
526+
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
527+
#:suite breaking-suite))
528+
(check-equal? (resyntax-analysis-total-fixes analysis) 0
529+
"Breaking suggestions should be filtered from resyntax-analyze-all")))

private/refactoring-result.rkt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
[refactoring-result-set-updated-source (-> refactoring-result-set? modified-source?)]
3232
[refactoring-result-set-results (-> refactoring-result-set? (listof refactoring-result?))]
3333
[refactoring-result-set-modified-lines (-> refactoring-result-set? immutable-range-set?)]
34+
[refactoring-result-set-compiles? (-> refactoring-result-set? boolean?)]
3435
[refactoring-result-map-commits
3536
(-> (hash/c source? refactoring-result-set?) (listof resyntax-commit?))]))
3637

@@ -129,6 +130,10 @@
129130
#:into (into-range-set natural<=>)))
130131

131132

133+
(define (refactoring-result-set-compiles? result-set)
134+
(source-can-expand? (refactoring-result-set-updated-source result-set)))
135+
136+
132137
(define string-replacement<=> (comparator-map natural<=> string-replacement-start))
133138

134139

private/source.rkt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
[source-read-syntax (-> source? syntax?)]
1717
[source-read-language (-> source? (or/c module-path? #false))]
1818
[source-expand (-> source? syntax?)]
19+
[source-can-expand? (-> source? boolean?)]
1920
[source-text-of (-> source? syntax? immutable-string?)]
2021
[file-source? (-> any/c boolean?)]
2122
[file-source (-> path-string? file-source?)]
@@ -125,13 +126,36 @@
125126
(check-equal? (source-read-language (string-source "#lang scribble/manual")) 'scribble/manual)
126127
(check-equal? (source-read-language (string-source "#lang info")) 'info)
127128
(check-equal? (source-read-language (string-source "#lang setup/infotab")) 'setup/infotab)
128-
(check-equal? (source-read-language (string-source "(void)")) #false)))
129+
(check-equal? (source-read-language (string-source "(void)")) #false))
130+
131+
(test-case "source-can-expand?"
132+
;; Valid racket code should expand successfully
133+
(check-true (source-can-expand? (string-source "#lang racket/base\n(define x 42)")))
134+
(check-true (source-can-expand? (string-source "#lang racket\n(or 1 2 3)")))
135+
136+
;; Invalid racket code should not expand
137+
(check-false (source-can-expand? (string-source "#lang racket/base\n(if)")))
138+
(check-false (source-can-expand? (string-source "#lang racket/base\n(define)")))
139+
140+
;; Modified sources should also be testable
141+
(define orig (string-source "#lang racket/base\n(define foo 42)"))
142+
(define valid-mod (modified-source orig "#lang racket/base\n(define foo 43)"))
143+
(define invalid-mod (modified-source orig "#lang racket/base\n(if)"))
144+
(check-true (source-can-expand? valid-mod))
145+
(check-false (source-can-expand? invalid-mod))))
129146

130147

131148
(define (source-expand code)
132149
(expand (source-read-syntax code)))
133150

134151

152+
(define (source-can-expand? code)
153+
(with-handlers ([exn:fail? (λ (_) #false)])
154+
(parameterize ([current-namespace (make-base-namespace)])
155+
(source-expand code))
156+
#true))
157+
158+
135159
(define/guard (source-path code)
136160
(guard-match (or (file-source path) (modified-source (file-source path) _)) code #:else #false)
137161
path)

0 commit comments

Comments
 (0)