Skip to content

Commit e38f138

Browse files
committed
refactor: allow suggestions/fixes to be generated lazily
1 parent 36f5ab9 commit e38f138

File tree

18 files changed

+133
-91
lines changed

18 files changed

+133
-91
lines changed

internal/linter/linter.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ func RunLinterOnProgram(logLevel utils.LogLevel, program *compiler.Program, file
161161
SourceFile: file,
162162
})
163163
},
164-
ReportRangeWithSuggestions: func(textRange core.TextRange, msg rule.RuleMessage, suggestions ...rule.RuleSuggestion) {
164+
ReportRangeWithSuggestions: func(textRange core.TextRange, msg rule.RuleMessage, suggestionsFn func() []rule.RuleSuggestion) {
165+
suggestions := suggestionsFn()
165166
onDiagnostic(rule.RuleDiagnostic{
166167
RuleName: r.Name,
167168
Range: textRange,
@@ -178,7 +179,8 @@ func RunLinterOnProgram(logLevel utils.LogLevel, program *compiler.Program, file
178179
SourceFile: file,
179180
})
180181
},
181-
ReportNodeWithFixes: func(node *ast.Node, msg rule.RuleMessage, fixes ...rule.RuleFix) {
182+
ReportNodeWithFixes: func(node *ast.Node, msg rule.RuleMessage, fixesFn func() []rule.RuleFix) {
183+
fixes := fixesFn()
182184
onDiagnostic(rule.RuleDiagnostic{
183185
RuleName: r.Name,
184186
Range: utils.TrimNodeTextRange(file, node),
@@ -188,7 +190,8 @@ func RunLinterOnProgram(logLevel utils.LogLevel, program *compiler.Program, file
188190
})
189191
},
190192

191-
ReportNodeWithSuggestions: func(node *ast.Node, msg rule.RuleMessage, suggestions ...rule.RuleSuggestion) {
193+
ReportNodeWithSuggestions: func(node *ast.Node, msg rule.RuleMessage, suggestionsFn func() []rule.RuleSuggestion) {
194+
suggestions := suggestionsFn()
192195
onDiagnostic(rule.RuleDiagnostic{
193196
RuleName: r.Name,
194197
Range: utils.TrimNodeTextRange(file, node),

internal/rule/rule.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,21 @@ type RuleContext struct {
114114
Program *compiler.Program
115115
TypeChecker *checker.Checker
116116
ReportRange func(textRange core.TextRange, msg RuleMessage)
117-
ReportRangeWithSuggestions func(textRange core.TextRange, msg RuleMessage, suggestions ...RuleSuggestion)
117+
ReportRangeWithSuggestions func(textRange core.TextRange, msg RuleMessage, suggestionsFn func() []RuleSuggestion)
118118
ReportNode func(node *ast.Node, msg RuleMessage)
119-
ReportNodeWithFixes func(node *ast.Node, msg RuleMessage, fixes ...RuleFix)
120-
ReportNodeWithSuggestions func(node *ast.Node, msg RuleMessage, suggestions ...RuleSuggestion)
119+
ReportNodeWithFixes func(node *ast.Node, msg RuleMessage, fixesFn func() []RuleFix)
120+
ReportNodeWithSuggestions func(node *ast.Node, msg RuleMessage, suggestionsFn func() []RuleSuggestion)
121121
}
122122

123123
func ReportNodeWithFixesOrSuggestions(ctx RuleContext, node *ast.Node, fix bool, msg RuleMessage, suggestionMsg RuleMessage, fixes ...RuleFix) {
124124
if fix {
125-
ctx.ReportNodeWithFixes(node, msg, fixes...)
125+
ctx.ReportNodeWithFixes(node, msg, func() []RuleFix { return fixes })
126126
} else {
127-
ctx.ReportNodeWithSuggestions(node, msg, RuleSuggestion{
128-
Message: suggestionMsg,
129-
FixesArr: fixes,
127+
ctx.ReportNodeWithSuggestions(node, msg, func() []RuleSuggestion {
128+
return []RuleSuggestion{{
129+
Message: suggestionMsg,
130+
FixesArr: fixes,
131+
}}
130132
})
131133
}
132134
}

internal/rules/await_thenable/await_thenable.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@ var AwaitThenableRule = rule.Rule{
5252
certainty := utils.NeedsToBeAwaited(ctx.TypeChecker, awaitArgument, awaitArgumentType)
5353

5454
if certainty == utils.TypeAwaitableNever {
55-
ctx.ReportNodeWithSuggestions(node, buildAwaitMessage(), rule.RuleSuggestion{
56-
Message: buildRemoveAwaitMessage(),
57-
FixesArr: []rule.RuleFix{
58-
rule.RuleFixRemoveRange(scanner.GetRangeOfTokenAtPosition(ctx.SourceFile, node.Pos())),
59-
},
55+
ctx.ReportNodeWithSuggestions(node, buildAwaitMessage(), func() []rule.RuleSuggestion {
56+
return []rule.RuleSuggestion{{
57+
Message: buildRemoveAwaitMessage(),
58+
FixesArr: []rule.RuleFix{
59+
rule.RuleFixRemoveRange(scanner.GetRangeOfTokenAtPosition(ctx.SourceFile, node.Pos())),
60+
},
61+
}}
6062
})
6163
}
6264
},
@@ -80,13 +82,15 @@ var AwaitThenableRule = rule.Rule{
8082
ctx.ReportRangeWithSuggestions(
8183
utils.GetForStatementHeadLoc(ctx.SourceFile, node),
8284
buildForAwaitOfNonAsyncIterableMessage(),
83-
// Note that this suggestion causes broken code for sync iterables
84-
// of promises, since the loop variable is not awaited.
85-
rule.RuleSuggestion{
86-
Message: buildConvertToOrdinaryForMessage(),
87-
FixesArr: []rule.RuleFix{
88-
rule.RuleFixRemove(ctx.SourceFile, stmt.AwaitModifier),
89-
},
85+
func() []rule.RuleSuggestion {
86+
// Note that this suggestion causes broken code for sync iterables
87+
// of promises, since the loop variable is not awaited.
88+
return []rule.RuleSuggestion{{
89+
Message: buildConvertToOrdinaryForMessage(),
90+
FixesArr: []rule.RuleFix{
91+
rule.RuleFixRemove(ctx.SourceFile, stmt.AwaitModifier),
92+
},
93+
}}
9094
},
9195
)
9296
},
@@ -126,7 +130,7 @@ var AwaitThenableRule = rule.Rule{
126130
})
127131
}
128132

129-
ctx.ReportNodeWithSuggestions(init, buildAwaitUsingOfNonAsyncDisposableMessage(), suggestions...)
133+
ctx.ReportNodeWithSuggestions(init, buildAwaitUsingOfNonAsyncDisposableMessage(), func() []rule.RuleSuggestion { return suggestions })
130134
}
131135
},
132136
}

internal/rules/no_array_delete/no_array_delete.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,15 @@ var NoArrayDeleteRule = rule.Rule{
7272
leftBracketTokenRange := scanner.GetRangeOfTokenAtPosition(ctx.SourceFile, expressionRange.End())
7373
rightBracketTokenRange := scanner.GetRangeOfTokenAtPosition(ctx.SourceFile, argumentRange.End())
7474

75-
ctx.ReportNodeWithSuggestions(node, buildNoArrayDeleteMessage(), rule.RuleSuggestion{
76-
Message: buildUseSpliceMessage(),
77-
FixesArr: []rule.RuleFix{
78-
rule.RuleFixRemoveRange(deleteTokenRange),
79-
rule.RuleFixReplaceRange(leftBracketTokenRange, ".splice("),
80-
rule.RuleFixReplaceRange(rightBracketTokenRange, ", 1)"),
81-
},
75+
ctx.ReportNodeWithSuggestions(node, buildNoArrayDeleteMessage(), func() []rule.RuleSuggestion {
76+
return []rule.RuleSuggestion{{
77+
Message: buildUseSpliceMessage(),
78+
FixesArr: []rule.RuleFix{
79+
rule.RuleFixRemoveRange(deleteTokenRange),
80+
rule.RuleFixReplaceRange(leftBracketTokenRange, ".splice("),
81+
rule.RuleFixReplaceRange(rightBracketTokenRange, ", 1)"),
82+
},
83+
}}
8284
})
8385
},
8486
}

internal/rules/no_confusing_void_expression/no_confusing_void_expression.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ var NoConfusingVoidExpressionRule = rule.Rule{
206206
}
207207

208208
if opts.IgnoreVoidOperator {
209-
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprArrowWrapVoidMessage(), insertVoidFix())
209+
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprArrowWrapVoidMessage(), func() []rule.RuleFix { return []rule.RuleFix{insertVoidFix()} })
210210
return
211211
}
212212

@@ -220,7 +220,7 @@ var NoConfusingVoidExpressionRule = rule.Rule{
220220
}
221221
}
222222

223-
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprArrowMessage(), fixes...)
223+
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprArrowMessage(), func() []rule.RuleFix { return fixes })
224224
return
225225
}
226226

@@ -234,7 +234,7 @@ var NoConfusingVoidExpressionRule = rule.Rule{
234234
}
235235

236236
if opts.IgnoreVoidOperator {
237-
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnWrapVoidMessage(), insertVoidFix())
237+
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnWrapVoidMessage(), func() []rule.RuleFix { return []rule.RuleFix{insertVoidFix()} })
238238
return
239239
}
240240

@@ -251,7 +251,7 @@ var NoConfusingVoidExpressionRule = rule.Rule{
251251
fixes = append(fixes, rule.RuleFixReplaceRange(returnToken, replaceText))
252252
}
253253

254-
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnLastMessage(), fixes...)
254+
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnLastMessage(), func() []rule.RuleFix { return fixes })
255255
return
256256
}
257257

@@ -272,14 +272,16 @@ var NoConfusingVoidExpressionRule = rule.Rule{
272272
rule.RuleFixInsertAfter(invalidAncestor, " }"),
273273
)
274274
}
275-
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnMessage(), fixes...)
275+
ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnMessage(), func() []rule.RuleFix { return fixes })
276276
return
277277
}
278278

279279
if opts.IgnoreVoidOperator {
280-
ctx.ReportNodeWithSuggestions(node, buildInvalidVoidExprWrapVoidMessage(), rule.RuleSuggestion{
281-
Message: buildVoidExprWrapVoidMessage(),
282-
FixesArr: []rule.RuleFix{insertVoidFix()},
280+
ctx.ReportNodeWithSuggestions(node, buildInvalidVoidExprWrapVoidMessage(), func() []rule.RuleSuggestion {
281+
return []rule.RuleSuggestion{{
282+
Message: buildVoidExprWrapVoidMessage(),
283+
FixesArr: []rule.RuleFix{insertVoidFix()},
284+
}}
283285
})
284286
return
285287
}

internal/rules/no_duplicate_type_constituents/no_duplicate_type_constituents.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ var NoDuplicateTypeConstituentsRule = rule.Rule{
166166
}
167167
}
168168
}
169-
ctx.ReportNodeWithFixes(constituentNode, message, fixes...)
169+
ctx.ReportNodeWithFixes(constituentNode, message, func() []rule.RuleFix { return fixes })
170170
}
171171

172172
var checkDuplicateRecursively func(

internal/rules/no_floating_promises/no_floating_promises.go

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -410,20 +410,25 @@ var NoFloatingPromisesRule = rule.Rule{
410410
msg = buildFloatingVoidMessage()
411411
}
412412

413-
ctx.ReportNodeWithSuggestions(node, msg, rule.RuleSuggestion{
414-
Message: buildFloatingFixVoidMessage(),
415-
FixesArr: (func() []rule.RuleFix {
416-
if isHigherPrecedenceThanUnary(exprStatement.Expression) {
417-
return []rule.RuleFix{rule.RuleFixInsertBefore(ctx.SourceFile, node, "void ")}
418-
}
419-
return []rule.RuleFix{
420-
rule.RuleFixInsertBefore(ctx.SourceFile, node, "void ("),
421-
rule.RuleFixInsertAfter(expression, ")"),
422-
}
423-
})(),
424-
}, rule.RuleSuggestion{
425-
Message: buildFloatingFixAwaitMessage(),
426-
FixesArr: addAwait(expression, exprStatement),
413+
ctx.ReportNodeWithSuggestions(node, msg, func() []rule.RuleSuggestion {
414+
return []rule.RuleSuggestion{
415+
{
416+
Message: buildFloatingFixVoidMessage(),
417+
FixesArr: func() []rule.RuleFix {
418+
if isHigherPrecedenceThanUnary(exprStatement.Expression) {
419+
return []rule.RuleFix{rule.RuleFixInsertBefore(ctx.SourceFile, node, "void ")}
420+
}
421+
return []rule.RuleFix{
422+
rule.RuleFixInsertBefore(ctx.SourceFile, node, "void ("),
423+
rule.RuleFixInsertAfter(expression, ")"),
424+
}
425+
}(),
426+
},
427+
{
428+
Message: buildFloatingFixAwaitMessage(),
429+
FixesArr: addAwait(expression, exprStatement),
430+
},
431+
}
427432
})
428433
} else {
429434
var msg rule.RuleMessage
@@ -432,9 +437,11 @@ var NoFloatingPromisesRule = rule.Rule{
432437
} else {
433438
msg = buildFloatingMessage()
434439
}
435-
ctx.ReportNodeWithSuggestions(node, msg, rule.RuleSuggestion{
436-
Message: buildFloatingFixAwaitMessage(),
437-
FixesArr: addAwait(expression, exprStatement),
440+
ctx.ReportNodeWithSuggestions(node, msg, func() []rule.RuleSuggestion {
441+
return []rule.RuleSuggestion{{
442+
Message: buildFloatingFixAwaitMessage(),
443+
FixesArr: addAwait(expression, exprStatement),
444+
}}
438445
})
439446
}
440447
},

internal/rules/no_meaningless_void_operator/no_meaningless_void_operator.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@ var NoMeaninglessVoidOperatorRule = rule.Rule{
5353
}
5454

5555
if mask&checker.TypeFlagsVoidLike != 0 {
56-
ctx.ReportNodeWithFixes(node, buildMeaninglessVoidOperatorMessage(ctx.TypeChecker.TypeToString(argType)), fixRemoveVoidKeyword())
56+
ctx.ReportNodeWithFixes(node, buildMeaninglessVoidOperatorMessage(ctx.TypeChecker.TypeToString(argType)), func() []rule.RuleFix { return []rule.RuleFix{fixRemoveVoidKeyword()} })
5757
} else if *opts.CheckNever && mask&checker.TypeFlagsNever != 0 {
58-
ctx.ReportNodeWithSuggestions(node, buildMeaninglessVoidOperatorMessage(ctx.TypeChecker.TypeToString(argType)), rule.RuleSuggestion{
59-
Message: buildRemoveVoidMessage(),
60-
FixesArr: []rule.RuleFix{fixRemoveVoidKeyword()},
58+
ctx.ReportNodeWithSuggestions(node, buildMeaninglessVoidOperatorMessage(ctx.TypeChecker.TypeToString(argType)), func() []rule.RuleSuggestion {
59+
return []rule.RuleSuggestion{{
60+
Message: buildRemoveVoidMessage(),
61+
FixesArr: []rule.RuleFix{fixRemoveVoidKeyword()},
62+
}}
6163
})
6264
}
6365
},

internal/rules/no_misused_spread/no_misused_spread.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,11 @@ var NoMisusedSpreadRule = rule.Rule{
227227
}
228228

229229
if isPromise(ctx.Program, ctx.TypeChecker, t) {
230-
ctx.ReportNodeWithSuggestions(node, buildNoPromiseSpreadInObjectMessage(), rule.RuleSuggestion{
231-
Message: buildAddAwaitMessage(),
232-
FixesArr: insertAwaitFix(ast.SkipParentheses(argument)),
230+
ctx.ReportNodeWithSuggestions(node, buildNoPromiseSpreadInObjectMessage(), func() []rule.RuleSuggestion {
231+
return []rule.RuleSuggestion{{
232+
Message: buildAddAwaitMessage(),
233+
FixesArr: insertAwaitFix(ast.SkipParentheses(argument)),
234+
}}
233235
})
234236

235237
return
@@ -242,7 +244,7 @@ var NoMisusedSpreadRule = rule.Rule{
242244
}
243245

244246
if isMap(ctx.Program, ctx.TypeChecker, t) {
245-
ctx.ReportNodeWithSuggestions(node, buildNoMapSpreadInObjectMessage(), getMapSpreadSuggestions(node, argument, t)...)
247+
ctx.ReportNodeWithSuggestions(node, buildNoMapSpreadInObjectMessage(), func() []rule.RuleSuggestion { return getMapSpreadSuggestions(node, argument, t) })
246248

247249
return
248250
}

internal/rules/no_unnecessary_boolean_literal_compare/no_unnecessary_boolean_literal_compare.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ var NoUnnecessaryBooleanLiteralCompareRule = rule.Rule{
204204
fixes = append(fixes, rule.RuleFixInsertBefore(ctx.SourceFile, mutatedNode, "("), rule.RuleFixInsertAfter(mutatedNode, " ?? true)"))
205205
}
206206

207-
ctx.ReportNodeWithFixes(node, msg, fixes...)
207+
ctx.ReportNodeWithFixes(node, msg, func() []rule.RuleFix { return fixes })
208208
},
209209
}
210210
},

0 commit comments

Comments
 (0)