Skip to content

Commit 06ab473

Browse files
committed
Core: fix FSharpLint warning
Fixing the warning for maxNumberOfFunctionParameters rule.
1 parent 4c51a07 commit 06ab473

File tree

8 files changed

+188
-55
lines changed

8 files changed

+188
-55
lines changed

src/FSharpLint.Core/Application/Lint.fs

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -118,67 +118,82 @@ module Lint =
118118
{ IndentationRuleContext:Map<int,bool*int>
119119
NoTabCharactersRuleContext:(string * Range) list }
120120

121-
let runAstNodeRules (rules:RuleMetadata<AstNodeRuleConfig> []) (globalConfig:Rules.GlobalRuleConfig) typeCheckResults (filePath:string) (fileContent:string) (lines:string []) syntaxArray =
121+
type RunAstNodeRulesConfig =
122+
{ Rules: RuleMetadata<AstNodeRuleConfig> []
123+
GlobalConfig: Rules.GlobalRuleConfig
124+
TypeCheckResults: FSharpCheckFileResults option
125+
FilePath: string
126+
FileContent: string
127+
Lines: string []
128+
SyntaxArray: AbstractSyntaxArray.Node array }
129+
130+
let runAstNodeRules (config: RunAstNodeRulesConfig) =
122131
let mutable indentationRuleState = Map.empty
123132
let mutable noTabCharactersRuleState = List.empty
124133

125134
let collect index (astNode: AbstractSyntaxArray.Node) =
126-
let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth syntaxArray index
135+
let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth config.SyntaxArray index
127136
let astNodeParams =
128137
{
129138
AstNode = astNode.Actual
130139
NodeHashcode = astNode.Hashcode
131140
NodeIndex = index
132-
SyntaxArray = syntaxArray
141+
SyntaxArray = config.SyntaxArray
133142
GetParents = getParents
134-
FilePath = filePath
135-
FileContent = fileContent
136-
Lines = lines
137-
CheckInfo = typeCheckResults
138-
GlobalConfig = globalConfig }
143+
FilePath = config.FilePath
144+
FileContent = config.FileContent
145+
Lines = config.Lines
146+
CheckInfo = config.TypeCheckResults
147+
GlobalConfig = config.GlobalConfig }
139148
// Build state for rules with context.
140149
indentationRuleState <- Indentation.ContextBuilder.builder indentationRuleState astNode.Actual
141150
noTabCharactersRuleState <- NoTabCharacters.ContextBuilder.builder noTabCharactersRuleState astNode.Actual
142151

143-
rules
152+
config.Rules
144153
|> Array.collect (fun rule -> runAstNodeRule rule astNodeParams)
145154

146155
// Collect suggestions for AstNode rules, and build context for following rules.
147156
let astNodeSuggestions =
148-
syntaxArray
157+
config.SyntaxArray
149158
|> Array.mapi (fun index astNode -> (index, astNode))
150159
|> Array.collect (fun (index, astNode) -> collect index astNode)
151160

152161
let context =
153162
{ IndentationRuleContext = indentationRuleState
154163
NoTabCharactersRuleContext = noTabCharactersRuleState }
155164

156-
rules |> Array.iter (fun rule -> rule.RuleConfig.Cleanup())
165+
config.Rules |> Array.iter (fun rule -> rule.RuleConfig.Cleanup())
157166
(astNodeSuggestions, context)
158167

159-
let runLineRules (lineRules:Configuration.LineRules) (globalConfig:Rules.GlobalRuleConfig) (filePath:string) (fileContent:string) (lines:string []) (context:Context) =
168+
type RunLineRulesConfig = { LineRules: Configuration.LineRules
169+
GlobalConfig: Rules.GlobalRuleConfig
170+
FilePath: string
171+
FileContent: string
172+
Lines: string []
173+
Context: Context }
174+
let runLineRules (config: RunLineRulesConfig) =
160175
let collectErrors (line: string) (lineNumber: int) (isLastLine: bool) =
161176
let lineParams =
162177
{
163178
LineRuleParams.Line = line
164179
LineNumber = lineNumber + 1
165180
IsLastLine = isLastLine
166-
FilePath = filePath
167-
FileContent = fileContent
168-
Lines = lines
169-
GlobalConfig = globalConfig
181+
FilePath = config.FilePath
182+
FileContent = config.FileContent
183+
Lines = config.Lines
184+
GlobalConfig = config.GlobalConfig
170185
}
171186

172187
let indentationError =
173-
lineRules.IndentationRule
174-
|> Option.map (fun rule -> runLineRuleWithContext rule context.IndentationRuleContext lineParams)
188+
config.LineRules.IndentationRule
189+
|> Option.map (fun rule -> runLineRuleWithContext rule config.Context.IndentationRuleContext lineParams)
175190

176191
let noTabCharactersError =
177-
lineRules.NoTabCharactersRule
178-
|> Option.map (fun rule -> runLineRuleWithContext rule context.NoTabCharactersRuleContext lineParams)
192+
config.LineRules.NoTabCharactersRule
193+
|> Option.map (fun rule -> runLineRuleWithContext rule config.Context.NoTabCharactersRuleContext lineParams)
179194

180195
let lineErrors =
181-
lineRules.GenericLineRules
196+
config.LineRules.GenericLineRules
182197
|> Array.collect (fun rule -> runLineRule rule lineParams)
183198

184199
[|
@@ -187,7 +202,7 @@ module Lint =
187202
lineErrors |> Array.singleton
188203
|]
189204

190-
fileContent
205+
config.FileContent
191206
|> String.toLines
192207
|> Array.collect (fun (line, lineNumber, isLastLine) -> collectErrors line lineNumber isLastLine)
193208
|> Array.concat
@@ -230,8 +245,20 @@ module Lint =
230245
let syntaxArray = AbstractSyntaxArray.astToArray fileInfo.Ast
231246

232247
// Collect suggestions for AstNode rules
233-
let (astNodeSuggestions, context) = runAstNodeRules enabledRules.AstNodeRules enabledRules.GlobalConfig fileInfo.TypeCheckResults fileInfo.File fileInfo.Text lines syntaxArray
234-
let lineSuggestions = runLineRules enabledRules.LineRules enabledRules.GlobalConfig fileInfo.File fileInfo.Text lines context
248+
let (astNodeSuggestions, context) =
249+
runAstNodeRules { Rules = enabledRules.AstNodeRules
250+
GlobalConfig = enabledRules.GlobalConfig
251+
TypeCheckResults = fileInfo.TypeCheckResults
252+
FilePath = fileInfo.File
253+
FileContent = fileInfo.Text
254+
Lines = lines
255+
SyntaxArray = syntaxArray }
256+
let lineSuggestions = runLineRules { LineRules = enabledRules.LineRules
257+
GlobalConfig = enabledRules.GlobalConfig
258+
FilePath = fileInfo.File
259+
FileContent = fileInfo.Text
260+
Lines = lines
261+
Context = context }
235262

236263
[| lineSuggestions; astNodeSuggestions |]
237264
|> Array.concat

src/FSharpLint.Core/Application/Lint.fsi

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,27 @@ module Lint =
119119
member TryGetSuccess : byref<Suggestion.LintWarning list> -> bool
120120
member TryGetFailure : byref<LintFailure> -> bool
121121

122+
type RunAstNodeRulesConfig =
123+
{ Rules: RuleMetadata<AstNodeRuleConfig> []
124+
GlobalConfig: Rules.GlobalRuleConfig
125+
TypeCheckResults: FSharpCheckFileResults option
126+
FilePath: string
127+
FileContent: string
128+
Lines: string []
129+
SyntaxArray: AbstractSyntaxArray.Node array }
130+
122131
/// Runs all rules which take a node of the AST as input.
123-
val runAstNodeRules : RuleMetadata<AstNodeRuleConfig> [] -> Rules.GlobalRuleConfig -> FSharpCheckFileResults option -> string -> string -> string [] -> AbstractSyntaxArray.Node [] -> Suggestion.LintWarning [] * Context
132+
val runAstNodeRules : RunAstNodeRulesConfig -> Suggestion.LintWarning array * Context
133+
134+
type RunLineRulesConfig = { LineRules: Configuration.LineRules
135+
GlobalConfig: Rules.GlobalRuleConfig
136+
FilePath: string
137+
FileContent: string
138+
Lines: string []
139+
Context: Context }
124140

125141
/// Runs all rules which take a line of text as input.
126-
val runLineRules : LineRules -> Rules.GlobalRuleConfig -> string -> string -> string [] -> Context -> Suggestion.LintWarning []
142+
val runLineRules : RunLineRulesConfig -> Suggestion.LintWarning array
127143

128144
/// Lints an entire F# solution by linting all projects specified in the `.sln` file.
129145
val lintSolution : optionalParams:OptionalLintParameters -> solutionFilePath:string -> toolsPath:Ionide.ProjInfo.Types.ToolsPath -> LintResult

src/FSharpLint.Core/Rules/Hints/HintMatcher.fs

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ open FSharpLint.Framework.ExpressionUtilities
1313
open FSharpLint.Framework.HintParser
1414
open FSharpLint.Framework.Rules
1515

16+
type ToStringConfig = { Replace: bool
17+
ParentAstNode: AstNode option
18+
Args: AstNodeRuleParams
19+
MatchedVariables: Dictionary<char, SynExpr>
20+
ParentHintNode: option<HintNode>
21+
HintNode: HintNode }
22+
1623
type Config =
1724
{ HintTrie:MergeSyntaxTrees.Edges }
1825

@@ -503,15 +510,20 @@ module private FormatHint =
503510
Debug.Assert(false, "Expected operator to be an expression identifier, but was " + expression.ToString())
504511
String.Empty
505512

506-
let rec toString replace parentAstNode (args:AstNodeRuleParams) (matchedVariables:Dictionary<_, SynExpr>) parentHintNode hintNode =
507-
let toString = toString replace parentAstNode args matchedVariables (Some hintNode)
513+
let rec toString (config: ToStringConfig) =
514+
let toString hintNode = toString { Replace = config.Replace
515+
ParentAstNode = config.ParentAstNode
516+
Args = config.Args
517+
MatchedVariables = config.MatchedVariables
518+
ParentHintNode = (Some config.HintNode)
519+
HintNode = hintNode}
508520

509521
let str =
510-
match hintNode with
511-
| HintExpr(Expression.Variable(varChar)) when replace ->
512-
match matchedVariables.TryGetValue varChar with
522+
match config.HintNode with
523+
| HintExpr(Expression.Variable(varChar)) when config.Replace ->
524+
match config.MatchedVariables.TryGetValue varChar with
513525
| true, expr ->
514-
match ExpressionUtilities.tryFindTextOfRange expr.Range args.FileContent with
526+
match ExpressionUtilities.tryFindTextOfRange expr.Range config.Args.FileContent with
515527
| Some(replacement) -> replacement
516528
| _ -> varChar.ToString()
517529
| _ -> varChar.ToString()
@@ -543,7 +555,7 @@ module private FormatHint =
543555
| HintPat(Pattern.Parentheses(hint)) -> "(" + toString (HintPat hint) + ")"
544556
| HintExpr(Expression.Lambda(arguments, LambdaBody(body))) ->
545557
"fun "
546-
+ lambdaArgumentsToString replace parentAstNode args matchedVariables arguments
558+
+ lambdaArgumentsToString config.Replace config.ParentAstNode config.Args config.MatchedVariables arguments
547559
+ " -> " + toString (HintExpr body)
548560
| HintExpr(Expression.LambdaArg(argument)) ->
549561
toString (HintExpr argument)
@@ -569,33 +581,53 @@ module private FormatHint =
569581
"else " + toString (HintExpr expr)
570582
| HintExpr(Expression.Null)
571583
| HintPat(Pattern.Null) -> "null"
572-
if replace && Precedence.requiresParenthesis matchedVariables hintNode parentAstNode parentHintNode then "(" + str + ")"
584+
if config.Replace && Precedence.requiresParenthesis config.MatchedVariables config.HintNode config.ParentAstNode config.ParentHintNode then "(" + str + ")"
573585
else str
574586
and private lambdaArgumentsToString replace parentAstNode args matchedVariables (arguments:LambdaArg list) =
575587
arguments
576-
|> List.map (fun (LambdaArg expr) -> toString replace parentAstNode args matchedVariables None (HintExpr expr))
588+
|> List.map (fun (LambdaArg expr) -> toString { Replace = replace
589+
ParentAstNode = parentAstNode
590+
Args = args
591+
MatchedVariables = matchedVariables
592+
ParentHintNode = None
593+
HintNode = (HintExpr expr) } )
577594
|> String.concat " "
578595

579-
let private hintError typeChecks hint (args:AstNodeRuleParams) range matchedVariables parentAstNode =
580-
let matched = FormatHint.toString false None args matchedVariables None hint.MatchedNode
581-
582-
match hint.Suggestion with
596+
type HintErrorConfig = { TypeChecks: (unit -> bool) list
597+
Hint: Hint
598+
Args: AstNodeRuleParams
599+
Range: FSharp.Compiler.Text.Range
600+
MatchedVariables: Dictionary<char, SynExpr>
601+
ParentAstNode: AstNode option }
602+
let private hintError (config: HintErrorConfig) =
603+
let toStringConfig = { ToStringConfig.Replace = false
604+
ToStringConfig.ParentAstNode = None
605+
ToStringConfig.Args = config.Args
606+
ToStringConfig.MatchedVariables = config.MatchedVariables
607+
ToStringConfig.ParentHintNode = None
608+
ToStringConfig.HintNode = config.Hint.MatchedNode }
609+
let matched = FormatHint.toString toStringConfig
610+
611+
match config.Hint.Suggestion with
583612
| Suggestion.Expr(expr) ->
584-
let suggestion = FormatHint.toString false None args matchedVariables None (HintExpr expr)
613+
let suggestion = FormatHint.toString { toStringConfig with HintNode = (HintExpr expr) }
585614
let errorFormatString = Resources.GetString("RulesHintRefactor")
586615
let error = System.String.Format(errorFormatString, matched, suggestion)
587616

588-
let toText = FormatHint.toString true parentAstNode args matchedVariables None (HintExpr expr)
617+
let toText = FormatHint.toString { toStringConfig with
618+
Replace = true
619+
ParentAstNode = config.ParentAstNode
620+
HintNode = (HintExpr expr) }
589621

590622
let suggestedFix = lazy(
591-
ExpressionUtilities.tryFindTextOfRange range args.FileContent
592-
|> Option.map (fun fromText -> { FromText = fromText; FromRange = range; ToText = toText }))
623+
ExpressionUtilities.tryFindTextOfRange config.Range config.Args.FileContent
624+
|> Option.map (fun fromText -> { FromText = fromText; FromRange = config.Range; ToText = toText }))
593625

594-
{ Range = range; Message = error; SuggestedFix = Some suggestedFix; TypeChecks = typeChecks }
626+
{ Range = config.Range; Message = error; SuggestedFix = Some suggestedFix; TypeChecks = config.TypeChecks }
595627
| Suggestion.Message(message) ->
596628
let errorFormatString = Resources.GetString("RulesHintSuggestion")
597629
let error = System.String.Format(errorFormatString, matched, message)
598-
{ Range = range; Message = error; SuggestedFix = None; TypeChecks = typeChecks }
630+
{ Range = config.Range; Message = error; SuggestedFix = None; TypeChecks = config.TypeChecks }
599631

600632
let private getMethodParameters (checkFile:FSharpCheckFileResults) (methodIdent:LongIdentWithDots) =
601633
let symbol =
@@ -651,7 +683,12 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParser.Hint) =
651683
| AstNode.Expression(SynExpr.Paren(_)), HintExpr(_)
652684
| AstNode.Pattern(SynPat.Paren(_)), HintPat(_) -> ()
653685
| AstNode.Pattern(pattern), HintPat(hintPattern) when MatchPattern.matchHintPattern (pattern, hintPattern) ->
654-
hintError List.Empty hint args pattern.Range (Dictionary<_, _>()) None
686+
hintError { TypeChecks = List.Empty
687+
Hint = hint
688+
Args = args
689+
Range = pattern.Range
690+
MatchedVariables = (Dictionary<_, _>())
691+
ParentAstNode = None }
655692
|> suggestions.Add
656693
| AstNode.Expression(expr), HintExpr(hintExpr) ->
657694
let arguments =
@@ -665,7 +702,12 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParser.Hint) =
665702
match MatchExpression.matchHintExpr arguments with
666703
| MatchExpression.Match(typeChecks) ->
667704
let suggest checks =
668-
hintError checks hint args expr.Range arguments.MatchedVariables (List.tryHead breadcrumbs)
705+
hintError { TypeChecks = checks
706+
Hint = hint
707+
Args = args
708+
Range = expr.Range
709+
MatchedVariables = arguments.MatchedVariables
710+
ParentAstNode = (List.tryHead breadcrumbs) }
669711
|> suggestions.Add
670712

671713
match (hint.MatchedNode, hint.Suggestion) with

tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,15 @@ type TestAstNodeRuleBase (rule:Rule) =
3434
match checkFile with
3535
| Some false -> None
3636
| _ -> parseInfo.TypeCheckResults
37-
let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue "" fileName) input (input.Split("\n")) syntaxArray |> fst
37+
let suggestions =
38+
runAstNodeRules { Rules = Array.singleton rule
39+
GlobalConfig = globalConfig
40+
TypeCheckResults = checkResult
41+
FilePath = (Option.defaultValue "" fileName)
42+
FileContent = input
43+
Lines = (input.Split("\n"))
44+
SyntaxArray = syntaxArray }
45+
|> fst
3846
rule.RuleConfig.Cleanup()
3947

4048
suggestions |> Array.iter this.PostSuggestion

tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@ type TestHintMatcherBase () =
5757
match checkFile with
5858
| Some false -> None
5959
| _ -> parseInfo.TypeCheckResults
60-
let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue "" fileName) input (input.Split "\n") syntaxArray |> fst
60+
let suggestions = runAstNodeRules { Rules = Array.singleton rule
61+
GlobalConfig = globalConfig
62+
TypeCheckResults = checkResult
63+
FilePath = (Option.defaultValue "" fileName)
64+
FileContent = input
65+
Lines = (input.Split("\n"))
66+
SyntaxArray = syntaxArray }
67+
|> fst
6168
suggestions |> Array.iter this.PostSuggestion
6269
| _ ->
6370
failwithf "Failed to parse"

0 commit comments

Comments
 (0)