From 3482661425e312d0af7aa7e2e96d293d8feaceeb Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Tue, 12 Dec 2023 12:58:43 +0330 Subject: [PATCH 01/48] build: run FSharpLint with 1 extra rule --- build.fsx | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/build.fsx b/build.fsx index 3430f4ca5..55bf17750 100644 --- a/build.fsx +++ b/build.fsx @@ -36,6 +36,7 @@ open Fake.IO.FileSystemOperators open Fake.IO.Globbing.Operators open Fake.Core.TargetOperators open Fake.Api +open Newtonsoft.Json.Linq open System open System.IO @@ -249,12 +250,34 @@ Target.create "Push" (fun _ -> Target.create "SelfCheck" (fun _ -> - let srcDir = Path.Combine(rootDir.FullName, "src") |> DirectoryInfo + let runLinter () = + let srcDir = Path.Combine(rootDir.FullName, "src") |> DirectoryInfo - let consoleProj = Path.Combine(srcDir.FullName, "FSharpLint.Console", "FSharpLint.Console.fsproj") |> FileInfo - let sol = Path.Combine(rootDir.FullName, solutionFileName) |> FileInfo - exec "dotnet" $"run --framework net9.0 lint %s{sol.FullName}" consoleProj.Directory.FullName -) + let consoleProj = Path.Combine(srcDir.FullName, "FSharpLint.Console", "FSharpLint.Console.fsproj") |> FileInfo + let sol = Path.Combine(rootDir.FullName, solutionFileName) |> FileInfo + + exec "dotnet" $"run --framework net9.0 lint %s{sol.FullName}" consoleProj.Directory.FullName + + printfn "Running self-check with default rules..." + runLinter () + + let fsharplintJsonDir = Path.Combine("src", "FSharpLint.Core", "fsharplint.json") + let fsharplintJsonText = File.ReadAllText fsharplintJsonDir + + let recommendedRules = [ "recursiveAsyncFunction" ] + + let jsonObj = JObject.Parse fsharplintJsonText + + for key in recommendedRules do + let token = jsonObj.SelectToken key + + if not (isNull token) then + token.SelectToken("enabled").Replace(JValue true) |> ignore + + File.WriteAllText(fsharplintJsonDir, jsonObj.ToString()) + + printfn "Now re-running self-check with more rules enabled..." + runLinter ()) // -------------------------------------------------------------------------------------- // Build order From 8b716ea1e1c213d54902019f0e6a385a420094b9 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Tue, 12 Dec 2023 16:10:41 +0330 Subject: [PATCH 02/48] build: run FSharpLint with 1 extra rule --- build.fsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/build.fsx b/build.fsx index 55bf17750..891ac78ae 100644 --- a/build.fsx +++ b/build.fsx @@ -264,7 +264,16 @@ Target.create "SelfCheck" (fun _ -> let fsharplintJsonDir = Path.Combine("src", "FSharpLint.Core", "fsharplint.json") let fsharplintJsonText = File.ReadAllText fsharplintJsonDir - let recommendedRules = [ "recursiveAsyncFunction" ] + let recommendedRules = + [ + "recursiveAsyncFunction" + (* + "nestedStatements" // not enable for now + "cyclomaticComplexity" rule is too complex and we can enable it later + "avoidSinglePipeOperator" rule must be improved and we can enable it later + *) + "maxLinesInLambdaFunction" + ] let jsonObj = JObject.Parse fsharplintJsonText From 7ac7fe2722ef0659deb4bb5c22d2102752a405c4 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Tue, 12 Dec 2023 16:13:41 +0330 Subject: [PATCH 03/48] Core,Tests: fix FSharpLint warning Fixing the warning for MaxLinesInLambdaFunction rule. Co-authored-by: webwarrior-ws --- src/FSharpLint.Core/Application/Lint.fs | 68 ++++++----- src/FSharpLint.Core/Framework/HintParser.fs | 20 ++-- src/FSharpLint.Core/Framework/Suppression.fs | 41 ++++--- src/FSharpLint.Core/Framework/Utilities.fs | 8 +- ...TailCallDiagnosticsInRecursiveFunctions.fs | 37 +++--- .../Conventions/FavourStaticEmptyFields.fs | 9 +- .../Rules/Conventions/NoPartialFunctions.fs | 106 +++++++++++++----- .../Conventions/RecursiveAsyncFunction.fs | 33 ++++-- .../Rules/Conventions/RedundantNewKeyword.fs | 16 ++- .../Conventions/SuggestUseAutoProperty.fs | 22 ++-- .../UsedUnderscorePrefixedElements.fs | 34 +++--- .../PatternMatchClauseIndentation.fs | 57 ++++++---- .../PatternMatchClausesOnNewLine.fs | 12 +- .../PatternMatchExpressionIndentation.fs | 10 +- .../PatternMatchOrClausesOnNewLine.fs | 18 +-- .../Formatting/Spacing/ClassMemberSpacing.fs | 12 +- .../Formatting/Spacing/ModuleDeclSpacing.fs | 45 ++++---- .../TupleFormatting/TupleCommaSpacing.fs | 43 ++++--- .../TupleFormatting/TupleIndentation.fs | 18 +-- .../TupleFormatting/TupleParentheses.fs | 24 ++-- .../Rules/Formatting/TypedItemSpacing.fs | 8 +- .../Formatting/UnionDefinitionIndentation.fs | 12 +- .../Rules/Hints/HintMatcher.fs | 3 +- .../Rules/Hints/HintsHelper.fs | 8 +- tests/FSharpLint.Core.Tests/TestUtils.fs | 6 +- 25 files changed, 408 insertions(+), 262 deletions(-) diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index a8170f0fc..aa33c5926 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -123,29 +123,33 @@ module Lint = let mutable indentationRuleState = Map.empty let mutable noTabCharactersRuleState = List.empty + let collect i (astNode: AbstractSyntaxArray.Node) = + let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth syntaxArray i + let astNodeParams = + { + AstNode = astNode.Actual + NodeHashcode = astNode.Hashcode + NodeIndex = i + SyntaxArray = syntaxArray + GetParents = getParents + FilePath = filePath + FileContent = fileContent + Lines = lines + CheckInfo = typeCheckResults + GlobalConfig = globalConfig + } + // Build state for rules with context. + indentationRuleState <- Indentation.ContextBuilder.builder indentationRuleState astNode.Actual + noTabCharactersRuleState <- NoTabCharacters.ContextBuilder.builder noTabCharactersRuleState astNode.Actual + + rules + |> Array.collect (fun rule -> runAstNodeRule rule astNodeParams) + // Collect suggestions for AstNode rules, and build context for following rules. let astNodeSuggestions = syntaxArray |> Array.mapi (fun i astNode -> (i, astNode)) - |> Array.collect (fun (i, astNode) -> - let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth syntaxArray i - let astNodeParams = - { AstNode = astNode.Actual - NodeHashcode = astNode.Hashcode - NodeIndex = i - SyntaxArray = syntaxArray - GetParents = getParents - FilePath = filePath - FileContent = fileContent - Lines = lines - CheckInfo = typeCheckResults - GlobalConfig = globalConfig } - // Build state for rules with context. - indentationRuleState <- Indentation.ContextBuilder.builder indentationRuleState astNode.Actual - noTabCharactersRuleState <- NoTabCharacters.ContextBuilder.builder noTabCharactersRuleState astNode.Actual - - rules - |> Array.collect (fun rule -> runAstNodeRule rule astNodeParams)) + |> Array.collect (fun (i, astNode) -> collect i astNode) let context = { IndentationRuleContext = indentationRuleState @@ -155,17 +159,17 @@ module Lint = (astNodeSuggestions, context) let runLineRules (lineRules:Configuration.LineRules) (globalConfig:Rules.GlobalRuleConfig) (filePath:string) (fileContent:string) (lines:string []) (context:Context) = - fileContent - |> String.toLines - |> Array.collect (fun (line, lineNumber, isLastLine) -> + let collectErrors (line: string) (lineNumber: int) (isLastLine: bool) = let lineParams = - { LineRuleParams.Line = line - LineNumber = lineNumber + 1 - IsLastLine = isLastLine - FilePath = filePath - FileContent = fileContent - Lines = lines - GlobalConfig = globalConfig } + { + LineRuleParams.Line = line + LineNumber = lineNumber + 1 + IsLastLine = isLastLine + FilePath = filePath + FileContent = fileContent + Lines = lines + GlobalConfig = globalConfig + } let indentationError = lineRules.IndentationRule @@ -183,7 +187,11 @@ module Lint = indentationError |> Option.toArray noTabCharactersError |> Option.toArray lineErrors |> Array.singleton - |]) + |] + + fileContent + |> String.toLines + |> Array.collect (fun (line, lineNumber, isLastLine) -> collectErrors line lineNumber isLastLine) |> Array.concat |> Array.concat diff --git a/src/FSharpLint.Core/Framework/HintParser.fs b/src/FSharpLint.Core/Framework/HintParser.fs index 210b03e69..0325e9871 100644 --- a/src/FSharpLint.Core/Framework/HintParser.fs +++ b/src/FSharpLint.Core/Framework/HintParser.fs @@ -924,18 +924,20 @@ module HintParser = else preturn "" + let checkPrefix remOpChars expr = + if prefix = "&" then Expression.AddressOf(true, expr) + else if prefix = "&&" then Expression.AddressOf(false, expr) + else if prefix = "!" || prefix = "~" then + let opIdent = Expression.Identifier [prefix + remOpChars] + Expression.PrefixOperator(opIdent, expr) + else + let opIdent = Expression.Identifier ["~" + prefix + remOpChars] + Expression.PrefixOperator(opIdent, expr) + let prefixOp = PrefixOperator( prefix, remainingOpChars, precedence, true, (), - fun remOpChars expr -> - if prefix = "&" then Expression.AddressOf(true, expr) - else if prefix = "&&" then Expression.AddressOf(false, expr) - else if prefix = "!" || prefix = "~" then - let opIdent = Expression.Identifier [prefix + remOpChars] - Expression.PrefixOperator(opIdent, expr) - else - let opIdent = Expression.Identifier ["~" + prefix + remOpChars] - Expression.PrefixOperator(opIdent, expr)) + checkPrefix) opp.AddOperator(prefixOp) diff --git a/src/FSharpLint.Core/Framework/Suppression.fs b/src/FSharpLint.Core/Framework/Suppression.fs index af48797e1..6a5f1b316 100644 --- a/src/FSharpLint.Core/Framework/Suppression.fs +++ b/src/FSharpLint.Core/Framework/Suppression.fs @@ -31,10 +31,7 @@ let private extractRules (rules:Set) (str:string) = let parseSuppressionInfo (rules:Set) (lines:string list) = let rules = rules |> Set.map (fun rule -> rule.ToLowerInvariant()) - lines - |> List.mapi (fun lineNum line -> (lineNum + 1, line)) - |> List.filter (fun (_, line) -> line.Contains("fsharplint:")) - |> List.choose (fun (lineNum, line) -> + let choose lineNum line = let matched = Regex.Match (line, ".*fsharplint:([a-z\-]+)\s*(.*)$") if matched.Success then let suppressionTarget = @@ -48,7 +45,12 @@ let parseSuppressionInfo (rules:Set) (lines:string list) = | "disable-line" -> Some (lineNum, DisableLine suppressionTarget) | "disable-next-line" -> Some (lineNum + 1, DisableLine suppressionTarget) | _ -> None - else None) + else None + + lines + |> List.mapi (fun lineNum line -> (lineNum + 1, line)) + |> List.filter (fun (_, line) -> line.Contains("fsharplint:")) + |> List.choose (fun (lineNum, line) -> choose lineNum line) |> List.groupBy (fun (line, _) -> line) |> List.map (fun (line, suppressions) -> { Line = line @@ -61,22 +63,25 @@ let isSuppressed (rule:String) (line:int) (lineSuppressions:LineSuppression list false else let rule = rule.ToLowerInvariant() + + + let fold (disabledRules:Set) (lineSuppression:LineSuppression) = + let innerFold (disabledRules:Set) suppression = + match suppression with + | Enable(rules) -> + Set.difference disabledRules rules + | Disable(rules) -> + Set.union disabledRules rules + | DisableLine(rules) -> + if line = lineSuppression.Line then + Set.union disabledRules rules + else + disabledRules + lineSuppression.Suppressions |> List.fold innerFold disabledRules let disabledRules = lineSuppressions |> List.takeWhile (fun lineSupression -> lineSupression.Line <= line) - |> List.fold (fun (disabledRules:Set) (lineSuppression:LineSuppression) -> - lineSuppression.Suppressions |> List.fold (fun (disabledRules:Set) suppression -> - match suppression with - | Enable(rules) -> - Set.difference disabledRules rules - | Disable(rules) -> - Set.union disabledRules rules - | DisableLine(rules) -> - if line = lineSuppression.Line then - Set.union disabledRules rules - else - disabledRules - ) disabledRules) Set.empty + |> List.fold fold Set.empty disabledRules.Contains(rule) diff --git a/src/FSharpLint.Core/Framework/Utilities.fs b/src/FSharpLint.Core/Framework/Utilities.fs index 4ba2e6a5b..f1881d247 100644 --- a/src/FSharpLint.Core/Framework/Utilities.fs +++ b/src/FSharpLint.Core/Framework/Utilities.fs @@ -121,15 +121,17 @@ module ExpressionUtilities = let countPrecedingCommentLines (text:string) (startPos:pos) (endPos:pos) = let range = Range.mkRange "" startPos endPos - tryFindTextOfRange range text - |> Option.map (fun precedingText -> + let map (precedingText: string) = let lines = precedingText.Split '\n' |> Array.rev |> Array.tail lines |> Array.takeWhile (fun line -> line.TrimStart().StartsWith("//")) - |> Array.length) + |> Array.length + + tryFindTextOfRange range text + |> Option.map map |> Option.defaultValue 0 let rangeContainsOtherRange (containingRange:Range) (range:Range) = diff --git a/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs b/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs index 4b6e832d1..774d19568 100644 --- a/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs +++ b/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs @@ -21,26 +21,25 @@ let private emitWarning (func: UnneededRecKeyword.RecursiveFunctionInfo) = let runner (args: AstNodeRuleParams) = match args.AstNode, args.CheckInfo with | UnneededRecKeyword.RecursiveFunctions(funcs), Some checkInfo -> - funcs - |> List.choose - (fun functionInfo -> - if UnneededRecKeyword.functionIsCalledInOneOf checkInfo functionInfo funcs then - let hasTailCallAttribute = - functionInfo.Attributes - |> List.collect (fun attrs -> attrs.Attributes) - |> List.exists - (fun attr -> - match attr.TypeName with - | SynLongIdent([ident], _, _) -> - ident.idText = "TailCall" || ident.idText = "TailCallAttribute" - | _ -> false) - if hasTailCallAttribute then - None - else - emitWarning functionInfo |> Some - else + let processFunction functionInfo = + if UnneededRecKeyword.functionIsCalledInOneOf checkInfo functionInfo funcs then + let hasTailCallAttribute = + functionInfo.Attributes + |> List.collect (fun attrs -> attrs.Attributes) + |> List.exists + (fun attr -> + match attr.TypeName with + | SynLongIdent([ident], _, _) -> + ident.idText = "TailCall" || ident.idText = "TailCallAttribute" + | _ -> false) + if hasTailCallAttribute then None - ) + else + emitWarning functionInfo |> Some + else + None + funcs + |> List.choose processFunction |> List.toArray | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs b/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs index aeb3c20dc..2b1c2a087 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs @@ -47,9 +47,8 @@ let private runner (args: AstNodeRuleParams) = if isArray then EmptyArrayLiteral else EmptyListLiteral generateError args.FileContent range emptyLiteralType | AstNode.Expression(SynExpr.Record(_, _, synExprRecordField, _)) -> - synExprRecordField - |> List.map (fun field -> - match field with + let mapping = + function | SynExprRecordField(_, _, expr, _) -> match expr with | Some(SynExpr.ArrayOrList(isArray, [], range)) -> @@ -59,7 +58,9 @@ let private runner (args: AstNodeRuleParams) = generateError args.FileContent range EmptyStringLiteral | Some(SynExpr.App(_, _, _, SynExpr.Const (SynConst.String ("", _, range), _), _)) -> generateError args.FileContent range EmptyStringLiteral - | _ -> Array.empty) + | _ -> Array.empty + synExprRecordField + |> List.map mapping |> Array.concat | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs index 502db2f95..bed790ea5 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs @@ -245,8 +245,7 @@ let private matchesBuiltinFSharpType (typeName: string) (fsharpType: FSharpType) let private isNonStaticInstanceMemberCall (checkFile:FSharpCheckFileResults) names lineText (range: Range) :(Option) = let typeChecks = - (partialInstanceMemberIdentifiers - |> List.map (fun replacement -> + let map (replacement: string * option * string * Replacement) = match replacement with | (fullyQualifiedInstanceMember, _, _, replacementStrategy) -> if not (fullyQualifiedInstanceMember.Contains ".") then @@ -289,20 +288,48 @@ let private isNonStaticInstanceMemberCall (checkFile:FSharpCheckFileResults) nam if typeMatches then match replacementStrategy with - | PatternMatch -> - Some { Range = range - Message = String.Format(Resources.GetString "RulesConventionsNoPartialFunctionsPatternMatchError", fullyQualifiedInstanceMember) - SuggestedFix = None - TypeChecks = (fun () -> typeMatches) |> List.singleton } - | Function replacementFunctionName -> - Some { Range = range - Message = String.Format(Resources.GetString "RulesConventionsNoPartialFunctionsReplacementError", replacementFunctionName, fullyQualifiedInstanceMember) - SuggestedFix = Some (lazy ( Some { FromText = (String.concat "." names) ; FromRange = range; ToText = replacementFunctionName })) - TypeChecks = (fun () -> typeMatches) |> List.singleton } + | PatternMatch -> + Some + { + Range = range + Message = + String.Format( + Resources.GetString + "RulesConventionsNoPartialFunctionsPatternMatchError", + fullyQualifiedInstanceMember + ) + SuggestedFix = None + TypeChecks = (fun () -> typeMatches) |> List.singleton + } + | Function replacementFunctionName -> + Some + { + Range = range + Message = + String.Format( + Resources.GetString "RulesConventionsNoPartialFunctionsReplacementError", + replacementFunctionName, + fullyQualifiedInstanceMember + ) + SuggestedFix = + Some( + lazy + (Some + { + FromText = (String.concat "." names) + FromRange = range + ToText = replacementFunctionName + }) + ) + TypeChecks = (fun () -> typeMatches) |> List.singleton + } else None | _ -> None - | _ -> None)) + | _ -> None + + (partialInstanceMemberIdentifiers + |> List.map map) match List.tryFind(fun (typeCheck:Option) -> typeCheck.IsSome) typeChecks with | None -> None | Some instanceMember -> instanceMember @@ -314,8 +341,7 @@ let private checkMemberCallOnExpression (originalRange: Range): array = match getTypedExpressionForRange checkFile range with | Some expression -> - partialInstanceMemberIdentifiers - |> List.choose (fun (fullyQualifiedInstanceMember, _, _, replacementStrategy) -> + let choose (fullyQualifiedInstanceMember: string) (replacementStrategy: Replacement) = let typeName = fullyQualifiedInstanceMember.Split(".").[0] let fsharpType = expression.Type @@ -329,17 +355,47 @@ let private checkMemberCallOnExpression if matchesType then match replacementStrategy with | PatternMatch -> - Some { Range = originalRange - Message = String.Format(Resources.GetString "RulesConventionsNoPartialFunctionsPatternMatchError", fullyQualifiedInstanceMember) - SuggestedFix = None - TypeChecks = (fun () -> true) |> List.singleton } + Some + { + Range = originalRange + Message = + String.Format( + Resources.GetString "RulesConventionsNoPartialFunctionsPatternMatchError", + fullyQualifiedInstanceMember + ) + SuggestedFix = None + TypeChecks = (fun () -> true) |> List.singleton + } | Function replacementFunctionName -> - Some { Range = originalRange - Message = String.Format(Resources.GetString "RulesConventionsNoPartialFunctionsReplacementError", replacementFunctionName, fullyQualifiedInstanceMember) - SuggestedFix = Some (lazy ( Some { FromText = (ExpressionUtilities.tryFindTextOfRange originalRange flieContent).Value ; FromRange = originalRange; ToText = replacementFunctionName })) - TypeChecks = (fun () -> true) |> List.singleton } + Some + { + Range = originalRange + Message = + String.Format( + Resources.GetString "RulesConventionsNoPartialFunctionsReplacementError", + replacementFunctionName, + fullyQualifiedInstanceMember + ) + SuggestedFix = + Some( + lazy + (Some + { + FromText = + (ExpressionUtilities.tryFindTextOfRange originalRange flieContent) + .Value + FromRange = originalRange + ToText = replacementFunctionName + }) + ) + TypeChecks = (fun () -> true) |> List.singleton + } else - None) + None + + partialInstanceMemberIdentifiers + |> List.choose (fun (fullyQualifiedInstanceMember, _, _, replacementStrategy) -> + choose fullyQualifiedInstanceMember replacementStrategy) |> List.toArray | None -> Array.empty @@ -371,4 +427,4 @@ let rule config = Identifier = Identifiers.NoPartialFunctions RuleConfig = { AstNodeRuleConfig.Runner = runner config Cleanup = ignore } } - |> AstNodeRule + |> AstNodeRule \ No newline at end of file diff --git a/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs b/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs index 923e441e0..567d65d4b 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs @@ -31,6 +31,26 @@ let private getFunctionNameFromAsyncCompExprBinding = function let checkRecursiveAsyncFunction (args:AstNodeRuleParams) (range:Range) (doBangExpr:SynExpr) breadcrumbs = let doTokenRange = Range.mkRange "do!" (Position.mkPos range.StartLine range.StartColumn) (Position.mkPos range.StartLine (range.StartColumn + 3)) + + let suggestFix () = + let suggestedFix = + lazy + (ExpressionUtilities.tryFindTextOfRange doTokenRange args.FileContent + |> Option.map (fun fromText -> + { + FromText = fromText + FromRange = doTokenRange + ToText = "return!" + })) + + { + Range = range + Message = Resources.GetString("RulesConventionsRecursiveAsyncFunctionError") + SuggestedFix = Some suggestedFix + TypeChecks = [] + } + |> Some + match doBangExpr with | SynExpr.App (funcExpr=(SynExpr.Ident callerIdent)) -> breadcrumbs @@ -43,18 +63,7 @@ let checkRecursiveAsyncFunction (args:AstNodeRuleParams) (range:Range) (doBangEx | _ -> []) |> List.choose getFunctionNameFromAsyncCompExprBinding |> List.filter ((=) callerIdent.idText) - |> List.choose (fun _ -> - let suggestedFix = lazy( - ExpressionUtilities.tryFindTextOfRange doTokenRange args.FileContent - |> Option.map (fun fromText -> - { FromText = fromText - FromRange = doTokenRange - ToText = "return!" })) - - { Range = range - Message = Resources.GetString("RulesConventionsRecursiveAsyncFunctionError") - SuggestedFix = Some suggestedFix - TypeChecks = [] } |> Some) + |> List.choose (fun _ -> suggestFix ()) |> List.toArray | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs index d95cc67c2..9f7c3e3e6 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs @@ -16,7 +16,7 @@ let private implementsIDisposable (fsharpType:FSharpType) = else false -let private doesNotImplementIDisposable (checkFile:FSharpCheckFileResults) (ident: SynLongIdent) = fun () -> +let private doesNotImplementIDisposable (checkFile:FSharpCheckFileResults) (ident: SynLongIdent) = let names = ident.LongIdent |> List.map (fun x -> x.idText) let symbol = checkFile.GetSymbolUseAtLocation(ident.Range.StartLine, ident.Range.EndColumn, "", names) @@ -45,10 +45,16 @@ let runner args = match args.AstNode, args.CheckInfo with | AstNode.Expression(SynExpr.New(_, SynType.LongIdent(identifier), _, range)), Some checkInfo | AstNode.Expression(SynExpr.New(_, SynType.App(SynType.LongIdent(identifier), _, _, _, _, _, _), _, range)), Some checkInfo -> - { Range = range - Message = Resources.GetString("RulesRedundantNewKeyword") - SuggestedFix = Some (generateFix args.FileContent range) - TypeChecks = [ doesNotImplementIDisposable checkInfo identifier ] } |> Array.singleton + { + Range = range + Message = Resources.GetString("RulesRedundantNewKeyword") + SuggestedFix = Some(generateFix args.FileContent range) + TypeChecks = + [ + fun () -> doesNotImplementIDisposable checkInfo identifier + ] + } + |> Array.singleton | _ -> Array.empty let rule = diff --git a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs index e1efccf39..69a85df50 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs @@ -12,19 +12,21 @@ let rec private isImmutableValueExpression (args: AstNodeRuleParams) (expression | SynExpr.Const (_constant, _range) -> true | SynExpr.Ident ident -> let isMutableVariable = + let exists memberDef = + match memberDef with + | SynMemberDefn.LetBindings (bindings, _, _, _) -> + bindings + |> List.exists (fun (SynBinding (_, _, _, isMutable, _, _, _, headPat, _, _, _, _, _)) -> + match headPat with + | SynPat.Named (SynIdent(bindingIdent, _), _, _, _) when isMutable -> + bindingIdent.idText = ident.idText + | _ -> false) + | _ -> false + match args.GetParents args.NodeIndex with | TypeDefinition (SynTypeDefn (_, SynTypeDefnRepr.ObjectModel (_, members, _), _, _, _, _)) :: _ -> members - |> List.exists (fun (memberDef: SynMemberDefn) -> - match memberDef with - | SynMemberDefn.LetBindings (bindings, _, _, _) -> - bindings - |> List.exists (fun (SynBinding (_, _, _, isMutable, _, _, _, headPat, _, _, _, _, _)) -> - match headPat with - | SynPat.Named (SynIdent(bindingIdent, _), _, _, _) when isMutable -> - bindingIdent.idText = ident.idText - | _ -> false) - | _ -> false) + |> List.exists exists | _ -> false not isMutableVariable diff --git a/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs b/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs index 1ca49f0ab..c270f4ce4 100644 --- a/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs +++ b/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs @@ -13,23 +13,29 @@ open FSharpLint.Framework.Rules let runner (args: AstNodeRuleParams) = // hack to only run rule once if args.NodeIndex = 0 then + let choose (usage: FSharpSymbolUse) = + match usage.Symbol with + | :? FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue as symbol -> + let conditions = + not usage.IsFromDefinition + && symbol.FullName.StartsWith "_" + && symbol.FullName <> "_" + && not symbol.IsCompilerGenerated + if conditions then + Some { + Range = usage.Range + Message = String.Format(Resources.GetString ("RulesUsedUnderscorePrefixedElements")) + SuggestedFix = None + TypeChecks = List.Empty + } + else + None + | _ -> None + match args.CheckInfo with | Some checkResults -> checkResults.GetAllUsesOfAllSymbolsInFile() - |> Seq.choose (fun usage -> - match usage.Symbol with - | :? FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue as symbol -> - if not usage.IsFromDefinition && symbol.FullName.StartsWith "_" - && symbol.FullName <> "_" && not symbol.IsCompilerGenerated then - Some { - Range = usage.Range - Message = String.Format(Resources.GetString ("RulesUsedUnderscorePrefixedElements")) - SuggestedFix = None - TypeChecks = List.Empty - } - else - None - | _ -> None ) + |> Seq.choose choose |> Seq.toArray | None -> Array.empty else diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs index 016005119..93c2f8317 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs @@ -15,42 +15,53 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa let matchStartIndentation = ExpressionUtilities.getLeadingSpaces matchExprRange args.FileContent let indentationLevelError = + + let bind (firstClause: SynMatchClause) = + let clauseIndentation = ExpressionUtilities.getLeadingSpaces firstClause.Range args.FileContent + if isLambda then + if clauseIndentation <> matchStartIndentation + args.GlobalConfig.numIndentationSpaces then + { + Range = firstClause.Range + Message = Resources.GetString("RulesFormattingLambdaPatternMatchClauseIndentationError") + SuggestedFix = None + TypeChecks = [] + } + |> Some + else + None + elif clauseIndentation <> matchStartIndentation then + { + Range = firstClause.Range + Message = Resources.GetString("RulesFormattingPatternMatchClauseIndentationError") + SuggestedFix = None + TypeChecks = [] + } + |> Some + else + None + if isLambda && config.AllowSingleLineLambda && clauses |> List.forall (fun clause -> clause.Range.StartLine = matchExprRange.StartLine) then None else clauses |> List.tryHead - |> Option.bind (fun firstClause -> - let clauseIndentation = ExpressionUtilities.getLeadingSpaces firstClause.Range args.FileContent - if isLambda then - if clauseIndentation <> matchStartIndentation + args.GlobalConfig.numIndentationSpaces then - { Range = firstClause.Range - Message = Resources.GetString("RulesFormattingLambdaPatternMatchClauseIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some - else - None - elif clauseIndentation <> matchStartIndentation then - { Range = firstClause.Range - Message = Resources.GetString("RulesFormattingPatternMatchClauseIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some - else - None) + |> Option.bind bind let consistentIndentationErrors = - clauses - |> List.toArray - |> Array.map (fun clause -> (clause, ExpressionUtilities.getLeadingSpaces clause.Range args.FileContent)) - |> Array.pairwise - |> Array.choose (fun ((_, clauseOneSpaces), (clauseTwo, clauseTwoSpaces)) -> + let choose (clauseOneSpaces: int) (clauseTwo: SynMatchClause) (clauseTwoSpaces: int) = if clauseOneSpaces <> clauseTwoSpaces then { Range = clauseTwo.Range Message = Resources.GetString("RulesFormattingPatternMatchClauseSameIndentationError") SuggestedFix = None TypeChecks = [] } |> Some else - None) + None + + clauses + |> List.toArray + |> Array.map (fun clause -> (clause, ExpressionUtilities.getLeadingSpaces clause.Range args.FileContent)) + |> Array.pairwise + |> Array.choose (fun ((_, clauseOneSpaces), (clauseTwo, clauseTwoSpaces)) -> choose clauseOneSpaces clauseTwo clauseTwoSpaces) [| indentationLevelError |> Option.toArray diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs index 03302b81a..2a79d93ff 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs @@ -9,17 +9,19 @@ open FSharpLint.Framework.Rules open FSharpLint.Rules.Helper let check args _ (clauses:SynMatchClause list) _ = - clauses - |> List.toArray - |> Array.pairwise - |> Array.choose (fun (clauseOne, clauseTwo) -> + let choose (clauseOne: SynMatchClause) (clauseTwo: SynMatchClause) = if clauseOne.Range.EndLine = clauseTwo.Range.StartLine then { Range = clauseTwo.Range Message = Resources.GetString("RulesFormattingPatternMatchClausesOnNewLineError") SuggestedFix = None TypeChecks = [] } |> Some else - None) + None + + clauses + |> List.toArray + |> Array.pairwise + |> Array.choose (fun (clauseOne, clauseTwo) -> choose clauseOne clauseTwo) let runner (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args check diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs index ee72ffdeb..1506a5be4 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs @@ -9,9 +9,7 @@ open FSharpLint.Framework.Rules open FSharpLint.Rules.Helper let check (args:AstNodeRuleParams) _ (clauses:SynMatchClause list) _ = - clauses - |> List.toArray - |> Array.choose (fun clause -> + let choose clause = let (SynMatchClause (pat, guard, expr, _, _, _)) = clause let clauseIndentation = ExpressionUtilities.getLeadingSpaces clause.Range args.FileContent let exprIndentation = ExpressionUtilities.getLeadingSpaces expr.Range args.FileContent @@ -25,7 +23,11 @@ let check (args:AstNodeRuleParams) _ (clauses:SynMatchClause list) _ = SuggestedFix = None TypeChecks = [] } |> Some else - None) + None + + clauses + |> List.toArray + |> Array.choose choose let runner (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args check diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs index 6718f6504..9a26b081e 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs @@ -9,6 +9,15 @@ open FSharpLint.Framework.Rules open FSharpLint.Rules.Helper let check args _ (clauses:SynMatchClause list) _ = + let choose (clauseOne: SynPat) (clauseTwo: SynPat) = + if clauseOne.Range.EndLine = clauseTwo.Range.StartLine then + { Range = clauseTwo.Range + Message = Resources.GetString("RulesFormattingPatternMatchOrClausesOnNewLineError") + SuggestedFix = None + TypeChecks = [] } |> Some + else + None + clauses |> List.toArray |> Array.collect (function @@ -16,14 +25,7 @@ let check args _ (clauses:SynMatchClause list) _ = [|firstPat; secondPat|] | _ -> [||]) |> Array.pairwise - |> Array.choose (fun (clauseOne, clauseTwo) -> - if clauseOne.Range.EndLine = clauseTwo.Range.StartLine then - { Range = clauseTwo.Range - Message = Resources.GetString("RulesFormattingPatternMatchOrClausesOnNewLineError") - SuggestedFix = None - TypeChecks = [] } |> Some - else - None) + |> Array.choose (fun (clauseOne, clauseTwo) -> choose clauseOne clauseTwo) let runner (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args check diff --git a/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs index f8c997457..c4625b587 100644 --- a/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs @@ -10,10 +10,7 @@ open FSharpLint.Framework.Rules open FSharpLint.Framework.ExpressionUtilities let checkClassMemberSpacing (args:AstNodeRuleParams) (members:SynMemberDefns) = - members - |> List.toArray - |> Array.pairwise - |> Array.choose (fun (memberOne, memberTwo) -> + let choose (memberOne: SynMemberDefn) (memberTwo: SynMemberDefn) = let numPrecedingCommentLines = countPrecedingCommentLines args.FileContent memberOne.Range.End memberTwo.Range.Start if memberTwo.Range.StartLine <> memberOne.Range.EndLine + 2 + numPrecedingCommentLines then let intermediateRange = @@ -34,7 +31,12 @@ let checkClassMemberSpacing (args:AstNodeRuleParams) (members:SynMemberDefns) = SuggestedFix = None TypeChecks = [] } |> Some else - None) + None + + members + |> List.toArray + |> Array.pairwise + |> Array.choose (fun (memberOne, memberTwo) -> choose memberOne memberTwo) let runner args = match args.AstNode with diff --git a/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs index cb91518b2..c227825a9 100644 --- a/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs @@ -10,32 +10,35 @@ open FSharpLint.Framework.Rules open FSharpLint.Framework.ExpressionUtilities let checkModuleDeclSpacing (args:AstNodeRuleParams) synModuleOrNamespace = + + let choose (declOne: SynModuleDecl) (declTwo: SynModuleDecl) = + let numPrecedingCommentLines = countPrecedingCommentLines args.FileContent declOne.Range.End declTwo.Range.Start + if declTwo.Range.StartLine <> declOne.Range.EndLine + 3 + numPrecedingCommentLines then + let intermediateRange = + let startLine = declOne.Range.EndLine + 1 + let endLine = declTwo.Range.StartLine + let endOffset = if startLine = endLine then 1 else 0 + + Range.mkRange + "" + (Position.mkPos (declOne.Range.EndLine + 1) 0) + (Position.mkPos (declTwo.Range.StartLine + endOffset) 0) + { + Range = intermediateRange + Message = Resources.GetString("RulesFormattingModuleDeclSpacingError") + SuggestedFix = None + TypeChecks = [] + } + |> Some + else + None + match synModuleOrNamespace with | SynModuleOrNamespace (_, _, _, decls, _, _, _, _, _) -> decls |> List.toArray |> Array.pairwise - |> Array.choose (fun (declOne, declTwo) -> - let numPrecedingCommentLines = countPrecedingCommentLines args.FileContent declOne.Range.End declTwo.Range.Start - if declTwo.Range.StartLine <> declOne.Range.EndLine + 3 + numPrecedingCommentLines then - let intermediateRange = - let startLine = declOne.Range.EndLine + 1 - let endLine = declTwo.Range.StartLine - let endOffset = - if startLine = endLine - then 1 - else 0 - - Range.mkRange - "" - (Position.mkPos (declOne.Range.EndLine + 1) 0) - (Position.mkPos (declTwo.Range.StartLine + endOffset) 0) - { Range = intermediateRange - Message = Resources.GetString("RulesFormattingModuleDeclSpacingError") - SuggestedFix = None - TypeChecks = [] } |> Some - else - None) + |> Array.choose (fun (declOne, declTwo) -> choose declOne declTwo) let runner args = match args.AstNode with diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs index f16cc28fa..2557160ba 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs @@ -11,26 +11,35 @@ open FSharpLint.Rules.Helper // Check for single space after commas in tuple. let checkTupleCommaSpacing (args:AstNodeRuleParams) (tupleExprs:SynExpr list) tupleRange _ = + let choose (expr: SynExpr) (nextExpr: SynExpr) = + if expr.Range.EndLine = nextExpr.Range.StartLine && expr.Range.EndColumn + 2 <> nextExpr.Range.StartColumn then + let commaRange = Range.mkRange "" expr.Range.End nextExpr.Range.Start + let map commaText = + lazy + ({ + FromRange = commaRange + FromText = commaText + ToText = ", " + } + |> Some) + let suggestedFix = + ExpressionUtilities.tryFindTextOfRange commaRange args.FileContent + |> Option.map map + + { + Range = commaRange + Message = Resources.GetString("RulesFormattingTupleCommaSpacingError") + SuggestedFix = suggestedFix + TypeChecks = [] + } + |> Some + else + None + tupleExprs |> List.toArray |> Array.pairwise - |> Array.choose (fun (expr, nextExpr) -> - if expr.Range.EndLine = nextExpr.Range.StartLine && expr.Range.EndColumn + 2 <> nextExpr.Range.StartColumn then - let commaRange = Range.mkRange "" expr.Range.End nextExpr.Range.Start - let suggestedFix = - ExpressionUtilities.tryFindTextOfRange commaRange args.FileContent - |> Option.map (fun commaText -> - lazy( - { FromRange = commaRange - FromText = commaText - ToText = ", " } |> Some - ) ) - { Range = commaRange - Message = Resources.GetString("RulesFormattingTupleCommaSpacingError") - SuggestedFix = suggestedFix - TypeChecks = [] } |> Some - else - None) + |> Array.choose (fun (expr, nextExpr) -> choose expr nextExpr) let runner (args:AstNodeRuleParams) = TupleFormatting.isActualTuple args checkTupleCommaSpacing diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs index d80ba107b..939a6d36d 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs @@ -12,19 +12,21 @@ open FSharpLint.Rules.Helper // Check that tuple items on separate lines have consistent indentation. let checkTupleIndentation _ (tupleExprs:SynExpr list) _ _ = + let choose (expr: SynExpr) (nextExpr: SynExpr) = + if expr.Range.StartColumn <> nextExpr.Range.StartColumn then + { Range = Range.mkRange "" expr.Range.Start nextExpr.Range.End + Message = Resources.GetString("RulesFormattingTupleIndentationError") + SuggestedFix = None + TypeChecks = [] } |> Some + else + None + tupleExprs |> List.toArray |> Array.groupBy (fun expr -> expr.Range.StartLine) |> Array.choose (snd >> Array.tryHead) |> Array.pairwise - |> Array.choose (fun (expr, nextExpr) -> - if expr.Range.StartColumn <> nextExpr.Range.StartColumn then - { Range = Range.mkRange "" expr.Range.Start nextExpr.Range.End - Message = Resources.GetString("RulesFormattingTupleIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some - else - None) + |> Array.choose (fun (expr, nextExpr) -> choose expr nextExpr) let runner (args:AstNodeRuleParams) = TupleFormatting.isActualTuple args checkTupleIndentation diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs index 23d96ddaf..539bac942 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs @@ -9,19 +9,27 @@ open FSharpLint.Framework.Rules open FSharpLint.Rules.Helper let checkTupleHasParentheses (args:AstNodeRuleParams) _ range parentNode = + let map text = + let suggestedFix = + lazy + ({ + FromRange = range + FromText = text + ToText = $"({text})" + } + |> Some) + + { Range = range + Message = Resources.GetString("RulesFormattingTupleParenthesesError") + SuggestedFix = Some suggestedFix + TypeChecks = [] } + match parentNode with | Some (AstNode.Expression (SynExpr.Paren _)) -> Array.empty | _ -> ExpressionUtilities.tryFindTextOfRange range args.FileContent - |> Option.map (fun text -> - let suggestedFix = lazy( - { FromRange = range; FromText = text; ToText = $"({text})" } - |> Some) - { Range = range - Message = Resources.GetString("RulesFormattingTupleParenthesesError") - SuggestedFix = Some suggestedFix - TypeChecks = [] }) + |> Option.map map |> Option.toArray let runner (args:AstNodeRuleParams) = TupleFormatting.isActualTuple args checkTupleHasParentheses diff --git a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs index a28fd51f4..cc64be060 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs @@ -44,8 +44,7 @@ let private checkRange (config:Config) (args:AstNodeRuleParams) (range:Range) = let (expectedSpacesBefore, expectedSpacesAfter) = expectedSpacesFromConfig config.TypedItemStyle - ExpressionUtilities.tryFindTextOfRange range args.FileContent - |> Option.bind (fun text -> + let bind (text: string) = match text.Split(':') with | [|otherText; typeText|] -> let spacesBeforeColon = getTrailingSpaces otherText @@ -66,7 +65,10 @@ let private checkRange (config:Config) (args:AstNodeRuleParams) (range:Range) = TypeChecks = [] } else None - | _ -> None) + | _ -> None + + ExpressionUtilities.tryFindTextOfRange range args.FileContent + |> Option.bind bind /// Checks for correct spacing around colon of a typed item. let runner (config:Config) (args:AstNodeRuleParams) = diff --git a/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs index 1dd6465cd..0276fabf2 100644 --- a/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs @@ -32,17 +32,19 @@ let checkUnionDefinitionIndentation (args:AstNodeRuleParams) typeDefnRepr typeDe None let consistentIndentationErrors = - cases - |> List.toArray - |> Array.pairwise - |> Array.choose (fun (caseOne, caseTwo) -> + let choose caseOne caseTwo = if getUnionCaseStartColumn caseOne <> getUnionCaseStartColumn caseTwo then { Range = caseTwo.Range Message = Resources.GetString("RulesFormattingUnionDefinitionSameIndentationError") SuggestedFix = None TypeChecks = [] } |> Some else - None) + None + + cases + |> List.toArray + |> Array.pairwise + |> Array.choose (fun (caseOne, caseTwo) -> choose caseOne caseTwo) [| indentationLevelError |> Option.toArray diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index 0860507bc..b162cca7b 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -218,7 +218,7 @@ module private MatchExpression = | ExpressionUtilities.Identifier([ident], _), ExpressionUtilities.Identifier([opIdent], _) when opIdent.idText = "op_Equality" -> match arguments.FSharpCheckFileResults with | Some(checkFile) -> - fun () -> + let checkSymbol () = let symbolUse = checkFile.GetSymbolUseAtLocation( ident.idRange.StartLine, ident.idRange.EndColumn, "", [ident.idText]) @@ -231,6 +231,7 @@ module private MatchExpression = | :? FSharpMemberOrFunctionOrValue as x -> not x.IsProperty | _ -> true | None -> true + checkSymbol |> List.singleton |> Match | None -> diff --git a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs index 0d31aea21..ecb7d0a02 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs @@ -54,8 +54,7 @@ let rec checkTrie i trie (nodeArray:AbstractSyntaxArray.Node []) (boundVariables | true, trie -> checkTrie (i + 1) trie nodeArray boundVariables notify | false, _ -> () - trie.Edges.AnyMatch - |> List.iter (fun (var, trie) -> + let collect var trie = match var with | Some(var) -> match boundVariables.TryGetValue var with @@ -65,5 +64,8 @@ let rec checkTrie i trie (nodeArray:AbstractSyntaxArray.Node []) (boundVariables boundVariables.Add(var, i) checkTrie (i + node.NumberOfChildren + 1) trie nodeArray boundVariables notify | true, _ -> () - | None -> checkTrie (i + node.NumberOfChildren + 1) trie nodeArray boundVariables notify) + | None -> checkTrie (i + node.NumberOfChildren + 1) trie nodeArray boundVariables notify + + trie.Edges.AnyMatch + |> List.iter (fun (var, trie) -> collect var trie) diff --git a/tests/FSharpLint.Core.Tests/TestUtils.fs b/tests/FSharpLint.Core.Tests/TestUtils.fs index 3db24e14c..7b01cf42f 100644 --- a/tests/FSharpLint.Core.Tests/TestUtils.fs +++ b/tests/FSharpLint.Core.Tests/TestUtils.fs @@ -30,11 +30,13 @@ let getPerformanceTestInput = let memoizedResult = ref None - fun () -> + let getMemoizedResult () = match !memoizedResult with | Some(result) -> result | None -> let text = performanceTestSourceFile |> File.ReadAllText let result = (generateAst text, text) memoizedResult := Some(result) - result \ No newline at end of file + result + + getMemoizedResult From f259492b4045054402e4449b05075b60cca8316e Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Tue, 12 Dec 2023 16:30:44 +0330 Subject: [PATCH 04/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 891ac78ae..ae5da296e 100644 --- a/build.fsx +++ b/build.fsx @@ -273,6 +273,7 @@ Target.create "SelfCheck" (fun _ -> "avoidSinglePipeOperator" rule must be improved and we can enable it later *) "maxLinesInLambdaFunction" + "maxLinesInMatchLambdaFunction" ] let jsonObj = JObject.Parse fsharplintJsonText From 83738b1c249b9507188ef19e21c6f689b705b654 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Tue, 12 Dec 2023 16:31:03 +0330 Subject: [PATCH 05/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index ae5da296e..89429bce0 100644 --- a/build.fsx +++ b/build.fsx @@ -274,6 +274,7 @@ Target.create "SelfCheck" (fun _ -> *) "maxLinesInLambdaFunction" "maxLinesInMatchLambdaFunction" + "maxLinesInValue" ] let jsonObj = JObject.Parse fsharplintJsonText From 75432be02c6bdf1a270ed92864bf9c10fb32fc5d Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 1 Feb 2024 13:28:24 +0330 Subject: [PATCH 06/48] Core.Tests: fix FSharpLint warning Fixing the warning for MaxLinesInValue rule. --- tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs index 6d3b3a970..f2eb37105 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs @@ -11,6 +11,8 @@ open NUnit.Framework open FParsec open TestUtils +// fsharplint:disable MaxLinesInValue + let possibleMatches (syntaxArray:AbstractSyntaxArray.Node []) (hintTrie:Edges) notify = for i = 0 to syntaxArray.Length - 1 do let node = syntaxArray.[i] From 6b9fef6016304790d8d53243b477aa8f84d2b8ac Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Tue, 12 Dec 2023 16:48:12 +0330 Subject: [PATCH 07/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 89429bce0..40a1571cc 100644 --- a/build.fsx +++ b/build.fsx @@ -275,6 +275,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInLambdaFunction" "maxLinesInMatchLambdaFunction" "maxLinesInValue" + "maxLinesInFunction" ] let jsonObj = JObject.Parse fsharplintJsonText From 109979e21a6ee5e19925d85aa22d5c9b7a6231f1 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:28:07 +0330 Subject: [PATCH 08/48] Core: fix FSharpLint warning Fixing the warning for MaxLinesInFunction rule: ``` ========== Linting C:\Users\PC\source\repos\FSharpLint\src\FSharpLint.Core\Application\Configuration.fs ========== Function was 121 lines long, suggested to be less than 100 lines long. Error on line 611 starting at column 4 let flattenConfig (config:Configuration) = ``` --- .../Application/Configuration.fs | 61 ++++++++------- src/FSharpLint.Core/Framework/Ast.fs | 78 ++++++++----------- 2 files changed, 67 insertions(+), 72 deletions(-) diff --git a/src/FSharpLint.Core/Application/Configuration.fs b/src/FSharpLint.Core/Application/Configuration.fs index de6621336..cf0006edf 100644 --- a/src/FSharpLint.Core/Application/Configuration.fs +++ b/src/FSharpLint.Core/Application/Configuration.fs @@ -617,6 +617,39 @@ let private parseHints (hints:string []) = |> Array.toList |> MergeSyntaxTrees.mergeHints +let findDeprecation config deprecatedAllRules allRules = + if config.NonPublicValuesNames.IsSome && + (config.PrivateValuesNames.IsSome || config.InternalValuesNames.IsSome) then + failwith "nonPublicValuesNames has been deprecated, use privateValuesNames and/or internalValuesNames instead" + + let astNodeRules = ResizeArray() + let lineRules = ResizeArray() + let mutable indentationRule = None + let mutable noTabCharactersRule = None + Array.append allRules deprecatedAllRules + |> Array.distinctBy (function // Discard any deprecated rules which were define in a non-deprecated form. + | Rule.AstNodeRule rule -> rule.Identifier + | Rule.LineRule rule -> rule.Identifier + | Rule.IndentationRule rule -> rule.Identifier + | Rule.NoTabCharactersRule rule -> rule.Identifier) + |> Array.iter (function + | AstNodeRule rule -> astNodeRules.Add rule + | LineRule rule -> lineRules.Add(rule) + | IndentationRule rule -> indentationRule <- Some rule + | NoTabCharactersRule rule -> noTabCharactersRule <- Some rule) + + { + LoadedRules.GlobalConfig = getGlobalConfig config.Global + DeprecatedRules = deprecatedAllRules + AstNodeRules = astNodeRules.ToArray() + LineRules = + { + GenericLineRules = lineRules.ToArray() + IndentationRule = indentationRule + NoTabCharactersRule = noTabCharactersRule + } + } + let flattenConfig (config:Configuration) = let deprecatedAllRules = [| @@ -716,30 +749,4 @@ let flattenConfig (config:Configuration) = config.FavourAsKeyword |> Option.bind (constructRuleIfEnabled FavourAsKeyword.rule) |] |> Array.choose id - if config.NonPublicValuesNames.IsSome && - (config.PrivateValuesNames.IsSome || config.InternalValuesNames.IsSome) then - failwith "nonPublicValuesNames has been deprecated, use privateValuesNames and/or internalValuesNames instead" - - let astNodeRules = ResizeArray() - let lineRules = ResizeArray() - let mutable indentationRule = None - let mutable noTabCharactersRule = None - Array.append allRules deprecatedAllRules - |> Array.distinctBy (function // Discard any deprecated rules which were define in a non-deprecated form. - | Rule.AstNodeRule rule -> rule.Identifier - | Rule.LineRule rule -> rule.Identifier - | Rule.IndentationRule rule -> rule.Identifier - | Rule.NoTabCharactersRule rule -> rule.Identifier) - |> Array.iter (function - | AstNodeRule rule -> astNodeRules.Add rule - | LineRule rule -> lineRules.Add(rule) - | IndentationRule rule -> indentationRule <- Some rule - | NoTabCharactersRule rule -> noTabCharactersRule <- Some rule) - - { LoadedRules.GlobalConfig = getGlobalConfig config.Global - DeprecatedRules = deprecatedAllRules - AstNodeRules = astNodeRules.ToArray() - LineRules = - { GenericLineRules = lineRules.ToArray() - IndentationRule = indentationRule - NoTabCharactersRule = noTabCharactersRule } } + findDeprecation config deprecatedAllRules allRules diff --git a/src/FSharpLint.Core/Framework/Ast.fs b/src/FSharpLint.Core/Framework/Ast.fs index 81ab7fc14..c52fe9d57 100644 --- a/src/FSharpLint.Core/Framework/Ast.fs +++ b/src/FSharpLint.Core/Framework/Ast.fs @@ -254,7 +254,9 @@ module Ast = add <| Pattern lhs add <| Pattern rhs - let inline private expressionChildren node add = + let inline private expressionChildren (node: SynExpr) (add: AstNode -> unit) = + let addMany = List.iter add + match node with | SynExpr.Paren(expression, _, _, _) | SynExpr.DotGet(expression, _, _, _) @@ -273,9 +275,7 @@ module Ast = | SynExpr.YieldOrReturn(_, expression, _, _) | SynExpr.YieldOrReturnFrom(_, expression, _, _) -> add <| Expression expression | SynExpr.SequentialOrImplicitYield(_, expression1, expression2, ifNotExpression, _) -> - add <| Expression expression1 - add <| Expression expression2 - add <| Expression ifNotExpression + addMany [Expression expression1; Expression expression2; Expression ifNotExpression] | SynExpr.Quote(expression, _, expression1, _, _) | SynExpr.Sequential(_, _, expression, expression1, _, _) | SynExpr.NamedIndexedPropertySet(_, expression, expression1, _) @@ -285,11 +285,9 @@ module Ast = | SynExpr.TryFinally(expression, expression1, _, _, _, _) | SynExpr.Set(expression, expression1, _) | SynExpr.DotSet(expression, _, expression1, _) -> - add <| Expression expression1 - add <| Expression expression + addMany [Expression expression1; Expression expression] | SynExpr.Typed(expression, synType, _) -> - add <| Type synType - add <| Expression expression + addMany [Type synType; Expression expression] | SynExpr.Tuple(_, expressions, _, _) | SynExpr.ArrayOrList(_, expressions, _) -> expressions |> List.revIter (Expression >> add) | SynExpr.Record(_, Some(expr, _), _, _) -> add <| Expression expr @@ -300,34 +298,18 @@ module Ast = | SynExpr.ObjExpr(synType, _, _, bindings, _, _, _, _) -> bindings |> List.revIter (Binding >> add) add <| Type synType - | SynExpr.ImplicitZero(_) - | SynExpr.Null(_) - | SynExpr.Const(_) - | SynExpr.DiscardAfterMissingQualificationAfterDot(_) - | SynExpr.FromParseError(_) - | SynExpr.LibraryOnlyILAssembly(_) - | SynExpr.LibraryOnlyStaticOptimization(_) - | SynExpr.LibraryOnlyUnionCaseFieldGet(_) - | SynExpr.LibraryOnlyUnionCaseFieldSet(_) - | SynExpr.ArbitraryAfterError(_) -> () | SynExpr.DotNamedIndexedPropertySet(expression, _, expression1, expression2, _) | SynExpr.For(_, _, _, _, expression, _, expression1, expression2, _) -> - add <| Expression expression2 - add <| Expression expression1 - add <| Expression expression + addMany [Expression expression2; Expression expression1; Expression expression] | SynExpr.LetOrUseBang(_, _, _, pattern, rightHandSide, andBangs, leftHandSide, _, _) -> - add <| Expression rightHandSide - add <| Expression leftHandSide + addMany [Expression rightHandSide; Expression leftHandSide] // TODO: is the the correct way to handle the new `and!` syntax? andBangs |> List.iter (fun (SynExprAndBang(_, _, _, pattern, body, _, _)) -> - add <| Expression body - add <| Pattern pattern + addMany [Expression body; Pattern pattern] ) add <| Pattern pattern | SynExpr.ForEach(_, _, _, _, pattern, expression, expression1, _) -> - add <| Expression expression1 - add <| Expression expression - add <| Pattern pattern + addMany [Expression expression1; Expression expression; Pattern pattern] | SynExpr.MatchLambda(_, _, matchClauses, _, _) -> matchClauses |> List.revIter (Match >> add) | SynExpr.TryWith(expression, matchClauses, _, _, _, _) @@ -342,8 +324,7 @@ module Ast = | SynExpr.TypeTest(expression, synType, _) | SynExpr.Upcast(expression, synType, _) | SynExpr.Downcast(expression, synType, _) -> - add <| Type synType - add <| Expression expression + addMany [Type synType; Expression expression] | SynExpr.LetOrUse(_, _, bindings, expression, _, _) -> add <| Expression expression bindings |> List.revIter (Binding >> add) @@ -351,39 +332,46 @@ module Ast = | SynExpr.LongIdent(_, SynLongIdent(ident, _, _), _, range) -> add <| Identifier(ident |> List.map (fun x -> x.idText), range) | SynExpr.IfThenElse(cond, body, Some(elseExpr), _, _, _, _) -> - add <| Else elseExpr - add <| Expression body - add <| Expression cond + addMany [Else elseExpr; Expression body; Expression cond] | SynExpr.IfThenElse(cond, body, None, _, _, _, _) -> - add <| Expression body - add <| Expression cond - | SynExpr.InterpolatedString(contents, _, range) -> + addMany [Expression body; Expression cond] + | SynExpr.InterpolatedString(contents, _, range) -> contents |> List.iter ( function - | SynInterpolatedStringPart.String _ -> - () - | SynInterpolatedStringPart.FillExpr (expr, _ident) -> - add <| Expression expr + | SynInterpolatedStringPart.String _ -> () + | SynInterpolatedStringPart.FillExpr (expr, _ident) -> add <| Expression expr ) + (* + | SynExpr.ImplicitZero(_) + | SynExpr.Null(_) + | SynExpr.Const(_) + | SynExpr.DiscardAfterMissingQualificationAfterDot(_) + | SynExpr.FromParseError(_) + | SynExpr.LibraryOnlyILAssembly(_) + | SynExpr.LibraryOnlyStaticOptimization(_) + | SynExpr.LibraryOnlyUnionCaseFieldGet(_) + | SynExpr.LibraryOnlyUnionCaseFieldSet(_) + | SynExpr.ArbitraryAfterError(_) | SynExpr.Lambda(_) | SynExpr.DotLambda(_) | SynExpr.App(_) - | SynExpr.Fixed(_) + | SynExpr.Fixed(_) -> () + *) | SynExpr.Typar(_) -> () | SynExpr.WhileBang(_, expression, expression1, _) -> add <| Expression expression1 add <| Expression expression - | SynExpr.DebugPoint(_debugPoint, _, innerExpr) -> + | SynExpr.DebugPoint(_debugPoint, _, innerExpr) -> add <| Expression innerExpr | SynExpr.Dynamic(funcExpr, _, argExpr, _) -> - add <| Expression funcExpr - add <| Expression argExpr - | SynExpr.IndexFromEnd(expr, _) -> + addMany [Expression funcExpr; Expression argExpr] + | SynExpr.IndexFromEnd(expr, _) -> add <| Expression expr | SynExpr.IndexRange(expr1, _, expr2, _, _, _) -> expr1 |> Option.iter (Expression >> add) expr2 |> Option.iter (Expression >> add) + | _ -> () let inline private typeSimpleRepresentationChildren node add = match node with From 06e841944aacf28ad00c7ed97977ba62de36ecef Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:30:23 +0330 Subject: [PATCH 09/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 40a1571cc..5d45f3c0d 100644 --- a/build.fsx +++ b/build.fsx @@ -276,6 +276,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInMatchLambdaFunction" "maxLinesInValue" "maxLinesInFunction" + "maxLinesInMember" ] let jsonObj = JObject.Parse fsharplintJsonText From bc139f2558ab076e394c6540bd04b2cb1d6e4a7f Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 1 Feb 2024 13:28:15 +0330 Subject: [PATCH 10/48] Core.Tests: fix FSharpLint warning Fixing the warning for MaxLinesInMember rule. --- tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs index f2eb37105..21c2451fd 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs @@ -11,7 +11,7 @@ open NUnit.Framework open FParsec open TestUtils -// fsharplint:disable MaxLinesInValue +// fsharplint:disable MaxLinesInValue MaxLinesInMember let possibleMatches (syntaxArray:AbstractSyntaxArray.Node []) (hintTrie:Edges) notify = for i = 0 to syntaxArray.Length - 1 do From b67fd008f4efe66d87b0ce1008f07658270c67ac Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:31:49 +0330 Subject: [PATCH 11/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 5d45f3c0d..9317c6b68 100644 --- a/build.fsx +++ b/build.fsx @@ -277,6 +277,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInValue" "maxLinesInFunction" "maxLinesInMember" + "maxLinesInConstructor" ] let jsonObj = JObject.Parse fsharplintJsonText From 8442de9d48d7aa9a13d1eba83b72b5bd0e18239b Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:35:34 +0330 Subject: [PATCH 12/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 9317c6b68..524eb5546 100644 --- a/build.fsx +++ b/build.fsx @@ -278,6 +278,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInFunction" "maxLinesInMember" "maxLinesInConstructor" + "maxLinesInProperty" ] let jsonObj = JObject.Parse fsharplintJsonText From 59d611020edc4b1091c09fffbabd48f72c080476 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:38:07 +0330 Subject: [PATCH 13/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 524eb5546..98f66b5d3 100644 --- a/build.fsx +++ b/build.fsx @@ -279,6 +279,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInMember" "maxLinesInConstructor" "maxLinesInProperty" + "maxLinesInModule" ] let jsonObj = JObject.Parse fsharplintJsonText From 8b95d5b23eeb371655fd54cb07da27650cd348b8 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:42:06 +0330 Subject: [PATCH 14/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 98f66b5d3..d6509e7e8 100644 --- a/build.fsx +++ b/build.fsx @@ -280,6 +280,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInConstructor" "maxLinesInProperty" "maxLinesInModule" + "maxLinesInRecord" ] let jsonObj = JObject.Parse fsharplintJsonText From 88e5143c413f5ca48e1dc029afa2933235c5d714 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:46:22 +0330 Subject: [PATCH 15/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index d6509e7e8..a57a90250 100644 --- a/build.fsx +++ b/build.fsx @@ -281,6 +281,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInProperty" "maxLinesInModule" "maxLinesInRecord" + "maxLinesInEnum" ] let jsonObj = JObject.Parse fsharplintJsonText From 74e8e5560a15795ea83b350a9efb19d5e5e79cdc Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:47:04 +0330 Subject: [PATCH 16/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index a57a90250..c2e2ff3ff 100644 --- a/build.fsx +++ b/build.fsx @@ -282,6 +282,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInModule" "maxLinesInRecord" "maxLinesInEnum" + "maxLinesInUnion" ] let jsonObj = JObject.Parse fsharplintJsonText From 3d1c09855094edf4736977d62b35df6a429aa81f Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:51:15 +0330 Subject: [PATCH 17/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index c2e2ff3ff..ceeff5cb3 100644 --- a/build.fsx +++ b/build.fsx @@ -283,6 +283,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInRecord" "maxLinesInEnum" "maxLinesInUnion" + "maxLinesInClass" ] let jsonObj = JObject.Parse fsharplintJsonText From 80e2a42ea38f411822c89fb7712536b9219a1468 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 12:58:17 +0330 Subject: [PATCH 18/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index ceeff5cb3..41f288ab6 100644 --- a/build.fsx +++ b/build.fsx @@ -284,6 +284,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInEnum" "maxLinesInUnion" "maxLinesInClass" + "favourTypedIgnore" ] let jsonObj = JObject.Parse fsharplintJsonText From 74d42c10e1ddd4301ea9b16e9dd5cfa1740c63d0 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 13:08:22 +0330 Subject: [PATCH 19/48] Core,Tests: fix FSharpLint warning Fixing the warning for the FavourTypedIgnore rule: ``` Use a generic type parameter when calling the 'ignore' function. Error on line 518 starting at column 16 lintWarnings.AddLast warning |> ignore ``` --- src/FSharpLint.Core/Application/Lint.fs | 12 ++++++------ src/FSharpLint.Core/Framework/Utilities.fs | 2 +- .../Rules/Conventions/CyclomaticComplexity.fs | 2 +- src/FSharpLint.Core/Rules/Hints/HintMatcher.fs | 2 +- tests/FSharpLint.Benchmarks/Benchmark.fs | 2 +- tests/FSharpLint.Benchmarks/Program.fs | 2 +- .../Framework/TestAbstractSyntaxArray.fs | 2 +- tests/FSharpLint.FunctionalTest/TestApi.fs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index aa33c5926..edcfe6aa0 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -283,10 +283,10 @@ module Lint = use p = new System.Diagnostics.Process(StartInfo = psi) let sbOut = System.Text.StringBuilder() - p.OutputDataReceived.Add(fun ea -> sbOut.AppendLine(ea.Data) |> ignore) + p.OutputDataReceived.Add(fun ea -> sbOut.AppendLine(ea.Data) |> ignore) let sbErr = System.Text.StringBuilder() - p.ErrorDataReceived.Add(fun ea -> sbErr.AppendLine(ea.Data) |> ignore) - p.Start() |> ignore + p.ErrorDataReceived.Add(fun ea -> sbErr.AppendLine(ea.Data) |> ignore) + p.Start() |> ignore p.BeginOutputReadLine() p.BeginErrorReadLine() p.WaitForExit() @@ -411,7 +411,7 @@ module Lint = let projectProgress = Option.defaultValue ignore optionalParams.ReportLinterProgress let warningReceived (warning:Suggestion.LintWarning) = - lintWarnings.AddLast warning |> ignore + lintWarnings.AddLast warning |> ignore> optionalParams.ReceivedWarning |> Option.iter (fun func -> func warning) @@ -521,7 +521,7 @@ module Lint = let lintWarnings = LinkedList() let warningReceived (warning:Suggestion.LintWarning) = - lintWarnings.AddLast warning |> ignore + lintWarnings.AddLast warning |> ignore> optionalParams.ReceivedWarning |> Option.iter (fun func -> func warning) let lintInformation = @@ -563,7 +563,7 @@ module Lint = let lintWarnings = LinkedList() let warningReceived (warning:Suggestion.LintWarning) = - lintWarnings.AddLast warning |> ignore + lintWarnings.AddLast warning |> ignore> optionalParams.ReceivedWarning |> Option.iter (fun func -> func warning) diff --git a/src/FSharpLint.Core/Framework/Utilities.fs b/src/FSharpLint.Core/Framework/Utilities.fs index f1881d247..2368f1169 100644 --- a/src/FSharpLint.Core/Framework/Utilities.fs +++ b/src/FSharpLint.Core/Framework/Utilities.fs @@ -17,7 +17,7 @@ module Dictionary = let addOrUpdate key value (dict:Dictionary<'Key,'Value>) = if dict.ContainsKey(key) then - dict.Remove(key) |> ignore + dict.Remove(key) |> ignore dict.Add(key, value) diff --git a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs index 99c307280..29d6e6c78 100644 --- a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs +++ b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs @@ -52,7 +52,7 @@ type private BindingStack(maxComplexity: int) = let popped = tier1.Head tier1 <- tier1.Tail if popped.Complexity > maxComplexity then - tier2.Add popped |> ignore + tier2.Add popped |> ignore // finally, push the item on to the stack tier1 <- bs::tier1 diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index b162cca7b..daf16aff8 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -255,7 +255,7 @@ module private MatchExpression = | _ -> NoMatch | Expression.Variable(var) -> match expr with - | AstNode.Expression(expr) -> arguments.MatchedVariables.TryAdd(var, expr) |> ignore + | AstNode.Expression(expr) -> arguments.MatchedVariables.TryAdd(var, expr) |> ignore | _ -> () Match([]) | Expression.Wildcard -> diff --git a/tests/FSharpLint.Benchmarks/Benchmark.fs b/tests/FSharpLint.Benchmarks/Benchmark.fs index c7962c848..910967a3f 100644 --- a/tests/FSharpLint.Benchmarks/Benchmark.fs +++ b/tests/FSharpLint.Benchmarks/Benchmark.fs @@ -35,4 +35,4 @@ type Benchmark () = [] member this.LintParsedFile () = - lintParsedFile OptionalLintParameters.Default fileInfo sourceFile |> ignore + lintParsedFile OptionalLintParameters.Default fileInfo sourceFile |> ignore diff --git a/tests/FSharpLint.Benchmarks/Program.fs b/tests/FSharpLint.Benchmarks/Program.fs index 13768750c..5df8f4193 100644 --- a/tests/FSharpLint.Benchmarks/Program.fs +++ b/tests/FSharpLint.Benchmarks/Program.fs @@ -11,5 +11,5 @@ let main _ = .Run( DefaultConfig.Instance .AddJob(Job.Default) - .AddDiagnoser(EtwProfiler())) |> ignore + .AddDiagnoser(EtwProfiler())) |> ignore 0 diff --git a/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs b/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs index 31c9158ae..2978746cc 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs @@ -95,7 +95,7 @@ type TestAst() = for _ in 0..iterations do stopwatch.Restart() - astToArray tree |> ignore + astToArray tree |> ignore stopwatch.Stop() diff --git a/tests/FSharpLint.FunctionalTest/TestApi.fs b/tests/FSharpLint.FunctionalTest/TestApi.fs index f42a6ffb2..3be1a5de4 100644 --- a/tests/FSharpLint.FunctionalTest/TestApi.fs +++ b/tests/FSharpLint.FunctionalTest/TestApi.fs @@ -49,7 +49,7 @@ module TestApi = for _ in 0..iterations do stopwatch.Restart() - lintParsedFile OptionalLintParameters.Default fileInfo sourceFile |> ignore + lintParsedFile OptionalLintParameters.Default fileInfo sourceFile |> ignore stopwatch.Stop() From 729216a3c0e871291c3b3d61ebfaa6b56796542c Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 14:35:48 +0330 Subject: [PATCH 20/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 41f288ab6..d58dfb18b 100644 --- a/build.fsx +++ b/build.fsx @@ -285,6 +285,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInUnion" "maxLinesInClass" "favourTypedIgnore" + "favourStaticEmptyFields" ] let jsonObj = JObject.Parse fsharplintJsonText From 7df8c9e7ddf9c4cd136e54bb539698ed77f33572 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 14:37:20 +0330 Subject: [PATCH 21/48] Core,Tests: fix FSharpLint warning Fixing the warning for FavourStaticEmptyFields rule. --- .../Application/Configuration.fs | 4 +- src/FSharpLint.Core/Application/Lint.fs | 2 +- .../Framework/AbstractSyntaxArray.fs | 4 +- src/FSharpLint.Core/Framework/Ast.fs | 4 +- src/FSharpLint.Core/Framework/HintParser.fs | 21 +++++---- src/FSharpLint.Core/Framework/Utilities.fs | 6 +-- .../Conventions/AvoidSinglePipeOperator.fs | 2 +- .../Conventions/Binding/FavourAsKeyword.fs | 4 +- .../Binding/FavourIgnoreOverLetWild.fs | 2 +- .../Conventions/Binding/FavourTypedIgnore.fs | 10 ++-- .../Conventions/Binding/TupleOfWildcards.fs | 8 +++- .../Conventions/Binding/UselessBinding.fs | 6 +-- .../Binding/WildcardNamedWithAsPattern.fs | 2 +- .../Rules/Conventions/CyclomaticComplexity.fs | 6 +-- .../FavourNonMutablePropertyInitialization.fs | 6 +-- .../CanBeReplacedWithComposition.fs | 12 ++--- .../ReimplementsFunction.fs | 10 ++-- .../Rules/Conventions/Naming/NamingHelper.fs | 18 ++++---- .../Rules/Conventions/NestedStatements.fs | 7 ++- .../Rules/Conventions/NoPartialFunctions.fs | 6 +-- .../MaxNumberOfBooleanOperatorsInCondition.fs | 8 +++- .../MaxNumberOfFunctionParameters.fs | 8 +++- .../NumberOfItems/MaxNumberOfItemsInTuple.fs | 8 +++- .../NumberOfItems/MaxNumberOfMembers.fs | 8 +++- .../FailwithBadUsage.fs | 2 +- ...lwithfWithArgumentsMatchingFormatString.fs | 6 ++- .../RaiseWithTooManyArgumentsHelper.fs | 2 +- .../Conventions/RecursiveAsyncFunction.fs | 4 +- .../Rules/Conventions/RedundantNewKeyword.fs | 4 +- .../SourceLength/SourceLengthHelper.fs | 19 ++++---- .../PatternMatchClauseIndentation.fs | 15 +++--- .../PatternMatchClausesOnNewLine.fs | 11 +++-- .../PatternMatchExpressionIndentation.fs | 11 +++-- .../PatternMatchOrClausesOnNewLine.fs | 13 ++++-- .../Formatting/Spacing/ClassMemberSpacing.fs | 13 ++++-- .../Formatting/Spacing/ModuleDeclSpacing.fs | 4 +- .../TupleFormatting/TupleCommaSpacing.fs | 4 +- .../TupleFormatting/TupleIndentation.fs | 19 ++++---- .../TupleFormatting/TupleParentheses.fs | 12 +++-- .../Rules/Formatting/TypePrefixing.fs | 6 +-- .../Rules/Formatting/TypedItemSpacing.fs | 12 +++-- .../Formatting/UnionDefinitionIndentation.fs | 22 +++++---- .../Rules/Hints/HintMatcher.fs | 24 +++++----- .../Rules/Typography/Indentation.fs | 46 +++++++++++-------- .../Rules/Typography/MaxCharactersOnLine.fs | 13 ++++-- .../Rules/Typography/MaxLinesInFile.fs | 12 +++-- .../Rules/Typography/NoTabCharacters.fs | 4 +- .../Rules/Typography/TrailingNewLineInFile.fs | 11 +++-- .../Typography/TrailingWhitespaceOnLine.fs | 13 ++++-- .../Framework/TestExpressionUtilities.fs | 3 +- .../Rules/Conventions/SourceLength.fs | 4 +- .../Rules/TestAstNodeRule.fs | 3 +- .../Rules/TestHintMatcherBase.fs | 3 +- .../Rules/TestIndentationRule.fs | 7 ++- .../Rules/TestNoTabCharactersRule.fs | 8 +++- 55 files changed, 307 insertions(+), 195 deletions(-) diff --git a/src/FSharpLint.Core/Application/Configuration.fs b/src/FSharpLint.Core/Application/Configuration.fs index cf0006edf..2a371f0db 100644 --- a/src/FSharpLint.Core/Application/Configuration.fs +++ b/src/FSharpLint.Core/Application/Configuration.fs @@ -81,7 +81,7 @@ module IgnoreFiles = else doesGlobSeqMatchPathSeq remaining currentlyMatchingGlobs | [] -> false - doesGlobSeqMatchPathSeq path [] + doesGlobSeqMatchPathSeq path List.Empty let shouldFileBeIgnored (ignorePaths:Ignore list) (filePath:string) = let segments = filePath.Split Path.DirectorySeparatorChar |> Array.toList @@ -355,7 +355,7 @@ with this.noTabCharacters |> Option.bind (constructRuleIfEnabled NoTabCharacters.rule) |> Option.toArray |] |> Array.concat -let private getOrEmptyList hints = hints |> Option.defaultValue [||] +let private getOrEmptyList hints = hints |> Option.defaultValue Array.empty type HintConfig = { add:string [] option diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index edcfe6aa0..a3d8a512c 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -498,7 +498,7 @@ module Lint = | LintResult.Success warnings -> (List.append warnings successes, failures) | LintResult.Failure err -> - (successes, err :: failures)) ([], []) + (successes, err :: failures)) (List.Empty, List.Empty) match failures with | [] -> diff --git a/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs b/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs index a1715ad15..c54f795af 100644 --- a/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs +++ b/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs @@ -300,5 +300,5 @@ module AbstractSyntaxArray = else breadcrumbs - if i = 0 then [] - else getBreadcrumbs [] (syntaxArray.[i].ParentIndex) |> List.rev + if i = 0 then List.Empty + else getBreadcrumbs List.Empty (syntaxArray.[i].ParentIndex) |> List.rev diff --git a/src/FSharpLint.Core/Framework/Ast.fs b/src/FSharpLint.Core/Framework/Ast.fs index c52fe9d57..b53c7744c 100644 --- a/src/FSharpLint.Core/Framework/Ast.fs +++ b/src/FSharpLint.Core/Framework/Ast.fs @@ -68,7 +68,7 @@ module Ast = match functionApplication with | AstNode.Expression(SynExpr.App(_, _, _, _, range) as functionApplication) -> - Some(flatten [] functionApplication, range) + Some(flatten List.Empty functionApplication, range) | _ -> None [] @@ -100,7 +100,7 @@ module Ast = match lambda with | AstNode.Expression(SynExpr.Lambda(_, _, _, _, _, range, _) as lambda) -> - getLambdaParametersAndExpression [] lambda + getLambdaParametersAndExpression List.Empty lambda |> Option.map (fun x -> (x, range)) | _ -> None diff --git a/src/FSharpLint.Core/Framework/HintParser.fs b/src/FSharpLint.Core/Framework/HintParser.fs index 0325e9871..10c0ae9c7 100644 --- a/src/FSharpLint.Core/Framework/HintParser.fs +++ b/src/FSharpLint.Core/Framework/HintParser.fs @@ -1,5 +1,6 @@ namespace FSharpLint.Framework +open System open FParsec open FSharp.Compiler.Tokenization @@ -146,7 +147,7 @@ module HintParser = override this.GetHashCode() = hash (this.AnyMatch, hash this.Lookup) - static member Empty = { Lookup = Dictionary<_, _>(); AnyMatch = [] } + static member Empty = { Lookup = Dictionary<_, _>(); AnyMatch = List.Empty } let private getConstKey = function | Constant.Unit -> SyntaxHintNode.Unit @@ -235,7 +236,7 @@ module HintParser = | HintExpr(Expression.Constant(_)) | HintExpr(Expression.Null) | HintExpr(Expression.Wildcard) - | HintExpr(Expression.Variable(_)) -> [] + | HintExpr(Expression.Variable(_)) -> List.Empty | HintPat(Pattern.Cons(lhs, rhs)) | HintPat(Pattern.Or(lhs, rhs)) -> [HintPat lhs; HintPat rhs] | HintPat(Pattern.Array(patterns)) @@ -246,7 +247,7 @@ module HintParser = | HintPat(Pattern.Identifier(_)) | HintPat(Pattern.Constant(_)) | HintPat(Pattern.Wildcard) - | HintPat(Pattern.Null) -> [] + | HintPat(Pattern.Null) -> List.Empty let private getConstantHashCode = function | Constant.Bool(x) -> hash x @@ -320,7 +321,7 @@ module HintParser = transposeHead next rest | [] -> builtList - transposeHead [] hintLists + transposeHead List.Empty hintLists let isAnyMatch = function | ((SyntaxHintNode.Wildcard | SyntaxHintNode.Variable), _, _, _) -> true @@ -387,7 +388,7 @@ module HintParser = getEdges transposed let charListToString charList = - Seq.fold (fun x y -> x + y.ToString()) "" charList + Seq.fold (fun x y -> x + y.ToString()) String.Empty charList let pischar chars : Parser = satisfy (fun x -> List.exists ((=) x) chars) @@ -424,7 +425,7 @@ module HintParser = pidentstartchar .>>. many pidentchar |>> fun (start, rest) -> start::rest >>= fun ident -> - let identStr = System.String.Join("", ident) + let identStr = System.String.Join(String.Empty, ident) let isKeyword = List.exists ((=) identStr) FSharpKeywords.KeywordNames @@ -902,9 +903,9 @@ module HintParser = let addInfixOperator prefix precedence associativity = let remainingOpChars = if prefix = "=" then - notFollowedBy (pstring "==>") |>> fun _ -> "" + notFollowedBy (pstring "==>") |>> fun _ -> String.Empty else if prefix = "|" then - notFollowedBy (pstring "]") |>> fun _ -> "" + notFollowedBy (pstring "]") |>> fun _ -> String.Empty else manySatisfy (isAnyOf Operators.opchars) @@ -922,7 +923,7 @@ module HintParser = else if prefix = "~" then manySatisfy ((=) '~') else - preturn "" + preturn String.Empty let checkPrefix remOpChars expr = if prefix = "&" then Expression.AddressOf(true, expr) @@ -1026,7 +1027,7 @@ module HintParser = let addInfixOperator operator precedence associativity = let remainingOpChars = if operator = "|" then - notFollowedBy (pstring "]") |>> fun _ -> "" + notFollowedBy (pstring "]") |>> fun _ -> String.Empty else manySatisfy (isAnyOf Operators.opchars) diff --git a/src/FSharpLint.Core/Framework/Utilities.fs b/src/FSharpLint.Core/Framework/Utilities.fs index 2368f1169..6c963da23 100644 --- a/src/FSharpLint.Core/Framework/Utilities.fs +++ b/src/FSharpLint.Core/Framework/Utilities.fs @@ -42,7 +42,7 @@ module ExpressionUtilities = checkFile.GetSymbolUseAtLocation( range.StartLine, range.EndColumn, - "", + String.Empty, identNames) | _ -> None @@ -94,7 +94,7 @@ module ExpressionUtilities = | _ -> None let getLeadingSpaces (range:Range) (text:string) = - let range = Range.mkRange "" (Position.mkPos range.StartLine 0) range.End + let range = Range.mkRange String.Empty (Position.mkPos range.StartLine 0) range.End tryFindTextOfRange range text |> Option.map (fun text -> text.ToCharArray() @@ -119,7 +119,7 @@ module ExpressionUtilities = /// Counts the number of comment lines preceding the given range of text. let countPrecedingCommentLines (text:string) (startPos:pos) (endPos:pos) = - let range = Range.mkRange "" startPos endPos + let range = Range.mkRange String.Empty startPos endPos let map (precedingText: string) = let lines = diff --git a/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs b/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs index 66ffaf440..3e985568f 100644 --- a/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs +++ b/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs @@ -21,7 +21,7 @@ let runner (args: AstNodeRuleParams) = let checkParentPiped (expr: AstNode) = match expr with | AstNode.Expression(SynExpr.App(_exprAtomicFlag, _isInfix, funcExpr, _argExpr, _range)) -> - checkExpr funcExpr outerArgExpr range [] |> Seq.isEmpty + checkExpr funcExpr outerArgExpr range List.Empty |> Seq.isEmpty | _ -> false match expr with diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs index 1d3d3cdbc..c0a68a0bd 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs @@ -21,7 +21,7 @@ let private checkForNamedPatternEqualsConstant (args:AstNodeRuleParams) pattern | SynExpr.App(_, _, ExpressionUtilities.Identifier([opIdent], _), SynExpr.Ident(ident), _) when opIdent.idText = "op_Equality" && Option.contains ident.idText patternIdent -> - let fromRange = Range.mkRange "" range.Start constRange.End + let fromRange = Range.mkRange String.Empty range.Start constRange.End let suggestedFix = ExpressionUtilities.tryFindTextOfRange fromRange args.FileContent @@ -39,7 +39,7 @@ let private checkForNamedPatternEqualsConstant (args:AstNodeRuleParams) pattern { Range = fromRange Message = Resources.GetString("RulesFavourAsKeyword") SuggestedFix = suggestedFix - TypeChecks = [] } |> Array.singleton + TypeChecks = List.Empty } |> Array.singleton | _ -> Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs index eccb524cc..5e41504ec 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs @@ -21,7 +21,7 @@ let private checkForBindingToAWildcard pattern range fileContent (expr: SynExpr) SuggestedFix = Some (lazy (Some({ FromRange = letBindingRange FromText = fileContent ToText = sprintf "(%s) |> ignore" exprText }))) - TypeChecks = [] } |> Array.singleton + TypeChecks = List.Empty } |> Array.singleton else Array.empty | None -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs index c7706ad5a..c4516ba55 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs @@ -19,10 +19,12 @@ let private runner (args: AstNodeRuleParams) = FromRange = range ToText = identifier })) - { Range = range - Message = String.Format(Resources.GetString "RulesFavourTypedIgnore", identifier) - SuggestedFix = Some suggestedFix - TypeChecks = [] } + { + Range = range + Message = String.Format(Resources.GetString "RulesFavourTypedIgnore", identifier) + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } let isTyped expression identifier range text = match expression with diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs index d3a136dbb..01146706a 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs @@ -29,7 +29,13 @@ let private checkTupleOfWildcards fileContents pattern identifier identifierRang let error = String.Format(errorFormat, refactorFrom, refactorTo) let suggestedFix = lazy( Some { SuggestedFix.FromRange = identifierRange; FromText = fileContents; ToText = refactorTo }) - { Range = range; Message = error; SuggestedFix = Some suggestedFix; TypeChecks = [] } |> Array.singleton + { + Range = range + Message = error + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } + |> Array.singleton | _ -> Array.empty let private isTupleMemberArgs breadcrumbs tupleRange = diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs index 408de053c..36022b62f 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs @@ -25,7 +25,7 @@ let private checkForUselessBinding (checkInfo:FSharpCheckFileResults option) pat let checkNotMutable (ident:Ident) = fun () -> let symbol = checkInfo.GetSymbolUseAtLocation( - ident.idRange.StartLine, ident.idRange.EndColumn, "", [ident.idText]) + ident.idRange.StartLine, ident.idRange.EndColumn, String.Empty, [ident.idText]) match symbol with | Some(symbol) -> isNotMutable symbol @@ -51,9 +51,9 @@ let private runner (args:AstNodeRuleParams) = let maybeSuggestedFix = match args.GetParents(args.NodeIndex) with | AstNode.ModuleDeclaration(SynModuleDecl.Let(_, _, range)) :: _ -> - Some({ FromRange = range; FromText = "let"; ToText = "" }) + Some({ FromRange = range; FromText = "let"; ToText = String.Empty }) | AstNode.Expression(SynExpr.LetOrUse(_, false, _, _, range, _)) :: _ -> - Some({ FromRange = range; FromText = "use"; ToText = "" }) + Some({ FromRange = range; FromText = "use"; ToText = String.Empty }) | _ -> None match args.AstNode with | AstNode.Binding(SynBinding(_, _, _, isMutable, _, _, _, pattern, _, expr, range, _, _)) diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs index c811a4f28..9e22a0aa3 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs @@ -17,7 +17,7 @@ let private checkForWildcardNamedWithAsPattern fileContents pattern = { Range = range Message = Resources.GetString("RulesWildcardNamedWithAsPattern") SuggestedFix = Some suggestedFix - TypeChecks = [] } |> Array.singleton + TypeChecks = List.Empty } |> Array.singleton | _ -> Array.empty let private runner (args:AstNodeRuleParams) = diff --git a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs index 29d6e6c78..79bf87496 100644 --- a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs +++ b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs @@ -38,7 +38,7 @@ type private BindingScopeComparer() = /// A two-tiered stack-like structure for containing BindingScopes. type private BindingStack(maxComplexity: int) = - let mutable tier1 = [] + let mutable tier1 = List.Empty let mutable tier2 = SortedSet(BindingScopeComparer()) member this.Push (args:AstNodeRuleParams) (bs: BindingScope) = @@ -76,7 +76,7 @@ type private BindingStack(maxComplexity: int) = /// Clears the stack. member this.Clear() = - tier1 <- [] + tier1 <- List.Empty tier2.Clear() /// A stack to track the current cyclomatic complexity of a binding scope. @@ -194,7 +194,7 @@ let runner (config:Config) (args:AstNodeRuleParams) : WarningDetails[] = pos.Column, pos.Line) |> Seq.map (fun scope -> // transform into WarningDetails let errMsg = String.Format(Resources.GetString("RulesCyclomaticComplexityError"), scope.Complexity, config.MaxComplexity) - { Range = scope.Binding.RangeOfBindingWithRhs; Message = errMsg; SuggestedFix = None; TypeChecks = [] }) + { Range = scope.Binding.RangeOfBindingWithRhs; Message = errMsg; SuggestedFix = None; TypeChecks = List.Empty }) |> Seq.toList let ret = match warningDetails with | Some x -> x::fromStack diff --git a/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs b/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs index 81e67ea84..23323c31b 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs @@ -53,12 +53,12 @@ let rec private processLetBinding (instanceNames: Set) (body: SynExpr) : Array.append (processLetBinding instanceNames expr1) (processLetBinding instanceNames expr2) - | _ -> [||] + | _ -> Array.empty and processExpression (expression: SynExpr) : array = match expression with | SynExpr.LetOrUse(_, _, bindings, body, _, _) -> - let instanceNames = extraFromBindings bindings [] |> Set.ofList + let instanceNames = extraFromBindings bindings List.Empty |> Set.ofList processLetBinding instanceNames body | SynExpr.Sequential(_, _, expr1, expr2, _, _) -> Array.append @@ -69,7 +69,7 @@ and processExpression (expression: SynExpr) : array = let runner args = match args.AstNode with | Binding(SynBinding(_, _, _, _, _, _, _, _, _, SynExpr.LetOrUse(_, _, bindings, body, _, _), _, _, _)) -> - let instanceNames = extraFromBindings bindings [] |> Set.ofList + let instanceNames = extraFromBindings bindings List.Empty |> Set.ofList processLetBinding instanceNames body | Match(SynMatchClause(_, _, expr, _, _, _)) -> processExpression expr diff --git a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs index 2b110ea66..003f929c6 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs @@ -39,21 +39,21 @@ let private validateLambdaCannotBeReplacedWithComposition fileContents _ lambda if lastArgument.idText = lambdaArgument.idText then funcString :: calledFunctionIdents else - [] + List.Empty | SynExpr.App(_, false, _, _, _) as nextFunction -> lambdaArgumentIsLastApplicationInFunctionCalls nextFunction lambdaArgument (funcString :: calledFunctionIdents) - | _ -> [] - | _ -> [] - | _ -> [] + | _ -> List.Empty + | _ -> List.Empty + | _ -> List.Empty match lambda.Arguments with | [singleParameter] -> match Helper.FunctionReimplementation.getLambdaParamIdent singleParameter with | Some paramIdent -> - match lambdaArgumentIsLastApplicationInFunctionCalls expression paramIdent [] with + match lambdaArgumentIsLastApplicationInFunctionCalls expression paramIdent List.Empty with | [] -> None | funcStrings -> Some funcStrings | None -> None @@ -68,7 +68,7 @@ let private validateLambdaCannotBeReplacedWithComposition fileContents _ lambda { Range = range Message = Resources.GetString("RulesCanBeReplacedWithComposition") SuggestedFix = Some suggestedFix - TypeChecks = [] } |> Array.singleton + TypeChecks = List.Empty } |> Array.singleton let runner (args:AstNodeRuleParams) = Helper.FunctionReimplementation.checkLambda args (validateLambdaCannotBeReplacedWithComposition args.FileContent) diff --git a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs index e204d209a..4f2492cd3 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs @@ -35,10 +35,12 @@ let private validateLambdaIsNotPointless (text:string) lambda range = ExpressionUtilities.tryFindTextOfRange range text |> Option.map (fun fromText -> { FromText = fromText; FromRange = range; ToText = identifier })) - { Range = range - Message = String.Format(Resources.GetString("RulesReimplementsFunction"), identifier) - SuggestedFix = Some suggestedFix - TypeChecks = [] } + { + Range = range + Message = String.Format(Resources.GetString("RulesReimplementsFunction"), identifier) + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } let argumentsAsIdentifiers = lambda.Arguments diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs index d2738940a..db4d18df1 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs @@ -13,14 +13,14 @@ open FSharp.Compiler.Symbols module QuickFixes = let removeAllUnderscores (ident:Ident) = lazy( - let toText = ident.idText.Replace("_", "") + let toText = ident.idText.Replace("_", String.Empty) Some { FromText = ident.idText; FromRange = ident.idRange; ToText = toText }) let removeNonPrefixingUnderscores (ident:Ident) = lazy( let prefixingUnderscores = ident.idText |> Seq.takeWhile (fun x -> x = '_') |> String.Concat - let toText = prefixingUnderscores + ident.idText.Replace("_", "") + let toText = prefixingUnderscores + ident.idText.Replace("_", String.Empty) Some { FromText = ident.idText; FromRange = ident.idRange; ToText = toText }) let addPrefix prefix (ident:Ident) = lazy( @@ -37,7 +37,7 @@ module QuickFixes = let firstChar = map withoutPrefix.[0] |> string let rest = withoutPrefix.Substring 1 prefix + firstChar + rest - else "" + else String.Empty let toPascalCase (ident:Ident) = lazy( let pascalCaseIdent = ident.idText |> mapFirstChar Char.ToUpper @@ -150,10 +150,12 @@ let private checkIdentifier (namingConfig:NamingConfig) (identifier:Ident) (idTe if notOperator idText && isNotDoubleBackTickedIdent identifier then checkIdentifierPart namingConfig identifier idText |> Array.map (fun (message, suggestedFix) -> - { Range = identifier.idRange - Message = message - SuggestedFix = Some suggestedFix - TypeChecks = [] }) + { + Range = identifier.idRange + Message = message + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + }) else Array.empty @@ -261,7 +263,7 @@ let isMeasureType = isAttribute "Measure" let isNotUnionCase (checkFile:FSharpCheckFileResults) (ident:Ident) = let symbol = checkFile.GetSymbolUseAtLocation( - ident.idRange.StartLine, ident.idRange.EndColumn, "", [ident.idText]) + ident.idRange.StartLine, ident.idRange.EndColumn, String.Empty, [ident.idText]) match symbol with | Some(symbol) when (symbol.Symbol :? FSharpUnionCase) -> false diff --git a/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs b/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs index a1c0ba89b..8ae39f2be 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs @@ -116,7 +116,12 @@ let runner (config:Config) (args:AstNodeRuleParams) = getRange node |> Option.map (fun range -> - { Range = range; Message = error config.Depth; SuggestedFix = None; TypeChecks = [] }) + { + Range = range + Message = error config.Depth + SuggestedFix = None + TypeChecks = List.Empty + }) |> Option.toArray else depth <- depth + 1 diff --git a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs index bed790ea5..93420df70 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs @@ -92,7 +92,7 @@ let private checkIfPartialIdentifier (config:Config) (identifier:string) (range: Range = range Message = String.Format(Resources.GetString ("RulesConventionsNoPartialFunctionsAdditionalError"), identifier) SuggestedFix = None - TypeChecks = [] + TypeChecks = List.Empty } else Map.tryFind identifier partialFunctionIdentifiers @@ -103,14 +103,14 @@ let private checkIfPartialIdentifier (config:Config) (identifier:string) (range: Range = range Message = String.Format(Resources.GetString ("RulesConventionsNoPartialFunctionsPatternMatchError"), identifier) SuggestedFix = None - TypeChecks = [] + TypeChecks = List.Empty } | Function replacementFunction -> { Range = range Message = String.Format(Resources.GetString "RulesConventionsNoPartialFunctionsReplacementError", replacementFunction, identifier) SuggestedFix = Some (lazy ( Some { FromText = identifier; FromRange = range; ToText = replacementFunction })) - TypeChecks = [] + TypeChecks = List.Empty }) let rec private tryFindTypedExpression (range: Range) (expression: FSharpExpr) = diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs index 7b45cd4d0..63d8449c4 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs @@ -39,7 +39,13 @@ let private validateCondition (maxBooleanOperators:int) condition = if numberOfBooleanOperators > maxBooleanOperators then let errorFormatString = Resources.GetString("RulesNumberOfItemsBooleanConditionsError") let error = String.Format(errorFormatString, maxBooleanOperators) - { Range = condition.Range; Message = error; SuggestedFix = None; TypeChecks = [] } |> Array.singleton + { + Range = condition.Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs index 2b76f7d61..84e379a4b 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs @@ -13,7 +13,13 @@ let private validateFunction (maxParameters:int) (constructorArguments:SynArgPat when List.length parameters > maxParameters -> let errorFormatString = Resources.GetString("RulesNumberOfItemsFunctionError") let error = String.Format(errorFormatString, maxParameters) - { Range = parameters.[maxParameters].Range; Message = error; SuggestedFix = None; TypeChecks = [] } |> Array.singleton + { + Range = parameters.[maxParameters].Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton | _ -> Array.empty let private runner (config:Helper.NumberOfItems.Config) (args:AstNodeRuleParams) = diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs index a3da5258d..a8ecee7d2 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs @@ -24,7 +24,13 @@ let private validateTuple (maxItems:int) (items:SynExpr list) = if List.length items > maxItems then let errorFormatString = Resources.GetString("RulesNumberOfItemsTupleError") let error = String.Format(errorFormatString, maxItems) - { Range = items.[maxItems].Range; Message = error; SuggestedFix = None; TypeChecks = [] } |> Array.singleton + { + Range = items.[maxItems].Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs index e0a53120e..f9a5e02ba 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs @@ -32,7 +32,13 @@ let private validateType (maxMembers:int) members typeRepresentation = if List.length members > maxMembers then let errorFormatString = Resources.GetString("RulesNumberOfItemsClassMembersError") let error = String.Format(errorFormatString, maxMembers) - { Range = members.[maxMembers].Range; Message = error; SuggestedFix = None; TypeChecks = [] } |> Array.singleton + { + Range = members.[maxMembers].Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs index c2bab841a..937dabfb1 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs @@ -70,7 +70,7 @@ let private runner (args: AstNodeRuleParams) = || failwithId.idText = "failwithf" -> match expression with - | SynExpr.Const (SynConst.String (id, _, _), _) when id = "" -> + | SynExpr.Const (SynConst.String (id, _, _), _) when id = String.Empty -> generateError failwithId.idText id range BadUsageType.EmptyMessage maybeIdentifier | SynExpr.Const (SynConst.String (id, _, _), _) when id <> fakeExternDeclErrorMsg -> let isDuplicate = diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs index b67d3f7ed..976eda47f 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs @@ -1,5 +1,7 @@ module FSharpLint.Rules.FailwithfWithArgumentsMatchingFormatString +open System + open FSharpLint.Framework open FSharpLint.Framework.Suggestion open FSharp.Compiler.Syntax @@ -13,12 +15,12 @@ let private runner (args:AstNodeRuleParams) = | FuncApp(expressions, range) -> match expressions with | SynExpr.Ident(ident)::SynExpr.Const(SynConst.String(formatString, _, _), _)::arguments - when ident.idText = "failwithf" && List.length arguments = formatString.Replace("%%", "").Split('%').Length -> + when ident.idText = "failwithf" && List.length arguments = formatString.Replace("%%", String.Empty).Split('%').Length -> { Range = range Message = Resources.GetString "FailwithfWithArgumentsMatchingFormatString" SuggestedFix = None - TypeChecks = [] + TypeChecks = List.Empty } |> Array.singleton | _ -> Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs index a5a46177d..ebdd95236 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs @@ -23,7 +23,7 @@ let checkRaiseWithTooManyArgs (raiseType:string) (count:int) (ruleName:string) ( Range = range Message = Resources.GetString ruleName SuggestedFix = None - TypeChecks = [] + TypeChecks = List.Empty } |> Array.singleton | _ -> Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs b/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs index 567d65d4b..0f3a51917 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs @@ -47,7 +47,7 @@ let checkRecursiveAsyncFunction (args:AstNodeRuleParams) (range:Range) (doBangEx Range = range Message = Resources.GetString("RulesConventionsRecursiveAsyncFunctionError") SuggestedFix = Some suggestedFix - TypeChecks = [] + TypeChecks = List.Empty } |> Some @@ -60,7 +60,7 @@ let checkRecursiveAsyncFunction (args:AstNodeRuleParams) (range:Range) (doBangEx bindings | AstNode.Expression (SynExpr.LetOrUse (true, false, bindings, _, _, _)) -> bindings - | _ -> []) + | _ -> List.Empty) |> List.choose getFunctionNameFromAsyncCompExprBinding |> List.filter ((=) callerIdent.idText) |> List.choose (fun _ -> suggestFix ()) diff --git a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs index 9f7c3e3e6..f8e46ad4b 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs @@ -1,5 +1,7 @@ module FSharpLint.Rules.RedundantNewKeyword +open System + open FSharpLint.Framework open FSharpLint.Framework.Suggestion open FSharp.Compiler.Symbols @@ -18,7 +20,7 @@ let private implementsIDisposable (fsharpType:FSharpType) = let private doesNotImplementIDisposable (checkFile:FSharpCheckFileResults) (ident: SynLongIdent) = let names = ident.LongIdent |> List.map (fun x -> x.idText) - let symbol = checkFile.GetSymbolUseAtLocation(ident.Range.StartLine, ident.Range.EndColumn, "", names) + let symbol = checkFile.GetSymbolUseAtLocation(ident.Range.StartLine, ident.Range.EndColumn, String.Empty, names) match symbol with | Some(symbol) when (symbol.Symbol :? FSharpMemberOrFunctionOrValue) -> diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs index 6ecc22f48..8d7af4a14 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs @@ -40,16 +40,16 @@ let private stripMultilineComments (source: string) = let rec getTopLevelBalancedPairs (toProcess: List) (stack: List) : List = match toProcess with - | [] -> [] + | [] -> List.Empty | Begin(index)::tail -> getTopLevelBalancedPairs tail (index::stack) | End(index)::tail -> match stack with - | [] -> [] - | [ beginIndex ] -> (beginIndex, index) :: getTopLevelBalancedPairs tail [] + | [] -> List.Empty + | [ beginIndex ] -> (beginIndex, index) :: getTopLevelBalancedPairs tail List.Empty | _::restOfStack -> getTopLevelBalancedPairs tail restOfStack - getTopLevelBalancedPairs markers [] + getTopLevelBalancedPairs markers List.Empty |> List.fold (fun (currSource: string) (startIndex, endIndex) -> currSource.Substring(0, startIndex) @@ -73,10 +73,13 @@ let checkSourceLengthRule (config:Config) range fileContents errorName = let skipResult = sourceCodeLines.Length - commentLinesCount - blankLinesCount if skipResult > config.MaxLines then - { Range = range - Message = error errorName config.MaxLines skipResult - SuggestedFix = None - TypeChecks = [] } |> Array.singleton + { + Range = range + Message = error errorName config.MaxLines skipResult + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty | None -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs index 93c2f8317..c9f1ac0d3 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs @@ -24,7 +24,7 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa Range = firstClause.Range Message = Resources.GetString("RulesFormattingLambdaPatternMatchClauseIndentationError") SuggestedFix = None - TypeChecks = [] + TypeChecks = List.Empty } |> Some else @@ -34,7 +34,7 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa Range = firstClause.Range Message = Resources.GetString("RulesFormattingPatternMatchClauseIndentationError") SuggestedFix = None - TypeChecks = [] + TypeChecks = List.Empty } |> Some else @@ -50,10 +50,13 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa let consistentIndentationErrors = let choose (clauseOneSpaces: int) (clauseTwo: SynMatchClause) (clauseTwoSpaces: int) = if clauseOneSpaces <> clauseTwoSpaces then - { Range = clauseTwo.Range - Message = Resources.GetString("RulesFormattingPatternMatchClauseSameIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = clauseTwo.Range + Message = Resources.GetString("RulesFormattingPatternMatchClauseSameIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs index 2a79d93ff..5e910aa52 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs @@ -11,10 +11,13 @@ open FSharpLint.Rules.Helper let check args _ (clauses:SynMatchClause list) _ = let choose (clauseOne: SynMatchClause) (clauseTwo: SynMatchClause) = if clauseOne.Range.EndLine = clauseTwo.Range.StartLine then - { Range = clauseTwo.Range - Message = Resources.GetString("RulesFormattingPatternMatchClausesOnNewLineError") - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = clauseTwo.Range + Message = Resources.GetString("RulesFormattingPatternMatchClausesOnNewLineError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs index 1506a5be4..8cf8da643 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs @@ -18,10 +18,13 @@ let check (args:AstNodeRuleParams) _ (clauses:SynMatchClause list) _ = |> Option.map (fun expr -> expr.Range.EndLine) |> Option.defaultValue pat.Range.EndLine if expr.Range.StartLine <> matchPatternEndLine && exprIndentation <> clauseIndentation + args.GlobalConfig.numIndentationSpaces then - { Range = expr.Range - Message = Resources.GetString("RulesFormattingMatchExpressionIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = expr.Range + Message = Resources.GetString("RulesFormattingMatchExpressionIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs index 9a26b081e..0f1d31076 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs @@ -11,10 +11,13 @@ open FSharpLint.Rules.Helper let check args _ (clauses:SynMatchClause list) _ = let choose (clauseOne: SynPat) (clauseTwo: SynPat) = if clauseOne.Range.EndLine = clauseTwo.Range.StartLine then - { Range = clauseTwo.Range - Message = Resources.GetString("RulesFormattingPatternMatchOrClausesOnNewLineError") - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = clauseTwo.Range + Message = Resources.GetString("RulesFormattingPatternMatchOrClausesOnNewLineError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None @@ -23,7 +26,7 @@ let check args _ (clauses:SynMatchClause list) _ = |> Array.collect (function | SynMatchClause (SynPat.Or (firstPat, secondPat, _, _), _, _, _, _, _) -> [|firstPat; secondPat|] - | _ -> [||]) + | _ -> Array.empty) |> Array.pairwise |> Array.choose (fun (clauseOne, clauseTwo) -> choose clauseOne clauseTwo) diff --git a/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs index c4625b587..c1a4979e3 100644 --- a/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs @@ -22,14 +22,17 @@ let checkClassMemberSpacing (args:AstNodeRuleParams) (members:SynMemberDefns) = else 0 Range.mkRange - "" + String.Empty (Position.mkPos (memberOne.Range.EndLine + 1) 0) (Position.mkPos (memberTwo.Range.StartLine + endOffset) 0) - { Range = intermediateRange - Message = Resources.GetString("RulesFormattingClassMemberSpacingError") - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = intermediateRange + Message = Resources.GetString("RulesFormattingClassMemberSpacingError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None diff --git a/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs index c227825a9..6957f8e6c 100644 --- a/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs @@ -20,14 +20,14 @@ let checkModuleDeclSpacing (args:AstNodeRuleParams) synModuleOrNamespace = let endOffset = if startLine = endLine then 1 else 0 Range.mkRange - "" + String.Empty (Position.mkPos (declOne.Range.EndLine + 1) 0) (Position.mkPos (declTwo.Range.StartLine + endOffset) 0) { Range = intermediateRange Message = Resources.GetString("RulesFormattingModuleDeclSpacingError") SuggestedFix = None - TypeChecks = [] + TypeChecks = List.Empty } |> Some else diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs index 2557160ba..751d6c7fc 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs @@ -13,7 +13,7 @@ open FSharpLint.Rules.Helper let checkTupleCommaSpacing (args:AstNodeRuleParams) (tupleExprs:SynExpr list) tupleRange _ = let choose (expr: SynExpr) (nextExpr: SynExpr) = if expr.Range.EndLine = nextExpr.Range.StartLine && expr.Range.EndColumn + 2 <> nextExpr.Range.StartColumn then - let commaRange = Range.mkRange "" expr.Range.End nextExpr.Range.Start + let commaRange = Range.mkRange String.Empty expr.Range.End nextExpr.Range.Start let map commaText = lazy ({ @@ -30,7 +30,7 @@ let checkTupleCommaSpacing (args:AstNodeRuleParams) (tupleExprs:SynExpr list) tu Range = commaRange Message = Resources.GetString("RulesFormattingTupleCommaSpacingError") SuggestedFix = suggestedFix - TypeChecks = [] + TypeChecks = List.Empty } |> Some else diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs index 939a6d36d..daed91dab 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs @@ -12,14 +12,17 @@ open FSharpLint.Rules.Helper // Check that tuple items on separate lines have consistent indentation. let checkTupleIndentation _ (tupleExprs:SynExpr list) _ _ = - let choose (expr: SynExpr) (nextExpr: SynExpr) = - if expr.Range.StartColumn <> nextExpr.Range.StartColumn then - { Range = Range.mkRange "" expr.Range.Start nextExpr.Range.End - Message = Resources.GetString("RulesFormattingTupleIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some - else - None + let choose (expr: SynExpr) (nextExpr: SynExpr) = + if expr.Range.StartColumn <> nextExpr.Range.StartColumn then + { + Range = Range.mkRange "" expr.Range.Start nextExpr.Range.End + Message = Resources.GetString("RulesFormattingTupleIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some + else + None tupleExprs |> List.toArray diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs index 539bac942..f2a4966c6 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs @@ -9,7 +9,7 @@ open FSharpLint.Framework.Rules open FSharpLint.Rules.Helper let checkTupleHasParentheses (args:AstNodeRuleParams) _ range parentNode = - let map text = + let map text = let suggestedFix = lazy ({ @@ -19,10 +19,12 @@ let checkTupleHasParentheses (args:AstNodeRuleParams) _ range parentNode = } |> Some) - { Range = range - Message = Resources.GetString("RulesFormattingTupleParenthesesError") - SuggestedFix = Some suggestedFix - TypeChecks = [] } + { + Range = range + Message = Resources.GetString("RulesFormattingTupleParenthesesError") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } match parentNode with | Some (AstNode.Expression (SynExpr.Paren _)) -> diff --git a/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs b/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs index 3cae5dda8..02319facd 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs @@ -27,7 +27,7 @@ let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName t { Range = range Message = Resources.GetString("RulesFormattingGenericPrefixError") SuggestedFix = Some suggestedFix - TypeChecks = [] } |> Some + TypeChecks = List.Empty } |> Some match lid |> longIdentWithDotsToString with | "list" @@ -46,7 +46,7 @@ let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName t { Range = range Message = String.Format(recommendPostfixErrMsg.Value, typeName) SuggestedFix = Some suggestedFix - TypeChecks = [] } |> Some + TypeChecks = List.Empty } |> Some else if isPostfix && config.Mode = Mode.Always then prefixSuggestion typeName @@ -61,7 +61,7 @@ let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName t { Range = range Message = Resources.GetString("RulesFormattingF#ArrayPostfixError") SuggestedFix = Some suggestedFix - TypeChecks = [] } |> Some + TypeChecks = List.Empty } |> Some | typeName -> match (isPostfix, config.Mode) with diff --git a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs index cc64be060..45bc8f385 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs @@ -59,10 +59,12 @@ let private checkRange (config:Config) (args:AstNodeRuleParams) (range:Range) = |> Some) let errorFormatString = Resources.GetString("RulesFormattingTypedItemSpacingError") Some - { Range = range - Message = String.Format(errorFormatString, expectedSpacesBefore, expectedSpacesAfter) - SuggestedFix = Some suggestedFix - TypeChecks = [] } + { + Range = range + Message = String.Format(errorFormatString, expectedSpacesBefore, expectedSpacesAfter) + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } else None | _ -> None @@ -78,7 +80,7 @@ let runner (config:Config) (args:AstNodeRuleParams) = // NOTE: This currently does not work for fields in union cases, since the range on union case fields is incorrect, // only including the type and not the field name. (https://github.com/dotnet/fsharp/issues/9279) checkRange config args range |> Option.toArray - | _ -> [||] + | _ -> Array.empty let rule config = { Name = "TypedItemSpacing" diff --git a/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs index 0276fabf2..6770a39ce 100644 --- a/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs @@ -24,20 +24,26 @@ let checkUnionDefinitionIndentation (args:AstNodeRuleParams) typeDefnRepr typeDe | firstCase :: _ -> let indentationLevelError = if getUnionCaseStartColumn firstCase - 2 <> typeDefnStartColumn + args.GlobalConfig.numIndentationSpaces then - { Range = firstCase.Range - Message = Resources.GetString("RulesFormattingUnionDefinitionIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = firstCase.Range + Message = Resources.GetString("RulesFormattingUnionDefinitionIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None let consistentIndentationErrors = let choose caseOne caseTwo = if getUnionCaseStartColumn caseOne <> getUnionCaseStartColumn caseTwo then - { Range = caseTwo.Range - Message = Resources.GetString("RulesFormattingUnionDefinitionSameIndentationError") - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = caseTwo.Range + Message = Resources.GetString("RulesFormattingUnionDefinitionSameIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index daf16aff8..40d8422b4 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -221,7 +221,7 @@ module private MatchExpression = let checkSymbol () = let symbolUse = checkFile.GetSymbolUseAtLocation( - ident.idRange.StartLine, ident.idRange.EndColumn, "", [ident.idText]) + ident.idRange.StartLine, ident.idRange.EndColumn, String.Empty, [ident.idText]) match symbolUse with | Some(symbolUse) -> @@ -239,8 +239,8 @@ module private MatchExpression = match filterParens arguments.Breadcrumbs with | PossiblyInMethod | PossiblyInConstructor -> NoMatch - | _ -> Match([]) - | _ -> Match([]) + | _ -> Match(List.Empty) + | _ -> Match(List.Empty) let rec matchHintExpr arguments = let expr = removeParens arguments.Expression @@ -251,19 +251,19 @@ module private MatchExpression = match expr with | AstNode.Expression(ExpressionUtilities.Identifier([identifier], _)) when identifier.idText = arguments.LambdaArguments.[variable] -> - Match([]) + Match(List.Empty) | _ -> NoMatch | Expression.Variable(var) -> match expr with | AstNode.Expression(expr) -> arguments.MatchedVariables.TryAdd(var, expr) |> ignore | _ -> () - Match([]) + Match(List.Empty) | Expression.Wildcard -> - Match([]) + Match(List.Empty) | Expression.Null | Expression.Constant(_) | Expression.Identifier(_) -> - if matchExpr expr = Some(arguments.Hint) then Match([]) + if matchExpr expr = Some(arguments.Hint) then Match(List.Empty) else NoMatch | Expression.Parentheses(hint) -> arguments.SubHint(expr, hint) |> matchHintExpr @@ -299,7 +299,7 @@ module private MatchExpression = if List.length expressions = List.length hintExpressions then (expressions, hintExpressions) ||> List.map2 (fun x y -> arguments.SubHint(x, y) |> matchHintExpr) - |> List.fold (&&~) (Match([])) + |> List.fold (&&~) (Match(List.Empty)) else NoMatch @@ -492,7 +492,7 @@ module private FormatHint = | Expression.Identifier(identifier) -> String.concat "." identifier | x -> Debug.Assert(false, $"Expected operator to be an expression identifier, but was {x.ToString()}") - "" + String.Empty let rec toString replace parentAstNode (args:AstNodeRuleParams) (matchedVariables:Dictionary<_, SynExpr>) parentHintNode hintNode = let toString = toString replace parentAstNode args matchedVariables (Some hintNode) @@ -523,7 +523,7 @@ module private FormatHint = each) |> String.concat "." | HintExpr(Expression.FunctionApplication(expressions)) -> - expressions |> surroundExpressionsString (HintExpr >> toString) "" "" " " + expressions |> surroundExpressionsString (HintExpr >> toString) String.Empty String.Empty " " | HintExpr(Expression.InfixOperator(operator, leftHint, rightHint)) -> $"{toString (HintExpr leftHint)} {opToString operator} {toString (HintExpr rightHint)}" | HintPat(Pattern.Cons(leftHint, rightHint)) -> @@ -595,7 +595,7 @@ let private getMethodParameters (checkFile:FSharpCheckFileResults) (methodIdent: checkFile.GetSymbolUseAtLocation( methodIdent.Range.StartLine, methodIdent.Range.EndColumn, - "", + String.Empty, methodIdent.LongIdent |> List.map (fun x -> x.idText)) match symbol with @@ -644,7 +644,7 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParser.Hint) = | AstNode.Expression(SynExpr.Paren(_)), HintExpr(_) | AstNode.Pattern(SynPat.Paren(_)), HintPat(_) -> () | AstNode.Pattern(pattern), HintPat(hintPattern) when MatchPattern.matchHintPattern (pattern, hintPattern) -> - hintError [] hint args pattern.Range (Dictionary<_, _>()) None + hintError List.Empty hint args pattern.Range (Dictionary<_, _>()) None |> suggestions.Add | AstNode.Expression(expr), HintExpr(hintExpr) -> let arguments = diff --git a/src/FSharpLint.Core/Rules/Typography/Indentation.fs b/src/FSharpLint.Core/Rules/Typography/Indentation.fs index 2f5ed2ae8..5d6b3af95 100644 --- a/src/FSharpLint.Core/Rules/Typography/Indentation.fs +++ b/src/FSharpLint.Core/Rules/Typography/Indentation.fs @@ -28,7 +28,7 @@ module ContextBuilder = | other -> (other::items) - helper [] seqExpr + helper List.Empty seqExpr |> List.rev let private createAbsoluteAndOffsetOverrides expectedIndentation (rangeToUpdate:Range) = @@ -47,7 +47,7 @@ module ContextBuilder = |> List.concat fields::subRecords | _ -> - [] + List.Empty let private createAbsoluteAndOffsetOverridesBasedOnFirst (ranges:Range list) = match ranges with @@ -57,7 +57,7 @@ module ContextBuilder = |> List.collect (fun other -> [ for lineNumber=other.StartLine to other.EndLine do yield (lineNumber, (true, expectedIndentation)) ]) - | _ -> [] + | _ -> List.Empty let private indentationOverridesForNode (node:AstNode) = match node with @@ -98,7 +98,7 @@ module ContextBuilder = match funcExpr with | ExpressionUtilities.Identifier([ ident ], _) when ident.idText = "op_ColonEquals" -> // := for reference cell assignment should be handled like normal equals, not like an infix operator. - [] + List.Empty | _ -> let expectedIndentation = innerArg.Range.StartColumn createAbsoluteAndOffsetOverrides expectedIndentation outerArg.Range @@ -125,7 +125,7 @@ module ContextBuilder = |> List.map (fun ((_, fieldIdent), _, _) -> fieldIdent.idRange) |> firstRangePerLine |> createAbsoluteAndOffsetOverridesBasedOnFirst - | _ -> [] + | _ -> List.Empty let builder current node = indentationOverridesForNode node @@ -135,7 +135,7 @@ module ContextBuilder = let checkIndentation (expectedSpaces:int) (line:string) (lineNumber:int) (indentationOverrides:Map) = let lineTrimmedStart = line.TrimStart() let numLeadingSpaces = line.Length - lineTrimmedStart.Length - let range = Range.mkRange "" (Position.mkPos lineNumber 0) (Position.mkPos lineNumber numLeadingSpaces) + let range = Range.mkRange String.Empty (Position.mkPos lineNumber 0) (Position.mkPos lineNumber numLeadingSpaces) if lineTrimmedStart.StartsWith "//" || lineTrimmedStart.StartsWith "(*" then None @@ -144,27 +144,37 @@ let checkIndentation (expectedSpaces:int) (line:string) (lineNumber:int) (indent | (true, expectedIndentation) -> if numLeadingSpaces <> expectedIndentation then let errorString = Resources.GetString("RulesTypographyOverridenIndentationError") - { Range = range - Message = errorString - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = range + Message = errorString + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None | (false, indentationOffset) -> if (numLeadingSpaces - indentationOffset) % expectedSpaces <> 0 then let errorFormatString = Resources.GetString("RulesTypographyOverridenIndentationError") - { Range = range - Message = String.Format(errorFormatString, expectedSpaces) - SuggestedFix = None - TypeChecks = [] } |> Some + + { + Range = range + Message = String.Format(errorFormatString, expectedSpaces) + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None elif numLeadingSpaces % expectedSpaces <> 0 then let errorFormatString = Resources.GetString("RulesTypographyIndentationError") - { Range = range - Message = String.Format(errorFormatString, expectedSpaces) - SuggestedFix = None - TypeChecks = [] } |> Some + { + Range = range + Message = String.Format(errorFormatString, expectedSpaces) + SuggestedFix = None + TypeChecks = List.Empty + } + |> Some else None diff --git a/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs b/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs index 621f0ef2b..93d562902 100644 --- a/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs +++ b/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs @@ -13,12 +13,15 @@ let checkMaxCharactersOnLine (config:Config) (args:LineRuleParams) = let maxCharacters = config.MaxCharactersOnLine let lineLength = String.length args.Line if lineLength > maxCharacters then - let range = Range.mkRange "" (Position.mkPos args.LineNumber (maxCharacters + 1)) (Position.mkPos args.LineNumber lineLength) + let range = Range.mkRange String.Empty (Position.mkPos args.LineNumber (maxCharacters + 1)) (Position.mkPos args.LineNumber lineLength) let errorFormatString = Resources.GetString("RulesTypographyLineLengthError") - { Range = range - Message = String.Format(errorFormatString, (maxCharacters + 1)) - SuggestedFix = None - TypeChecks = [] } |> Array.singleton + { + Range = range + Message = String.Format(errorFormatString, (maxCharacters + 1)) + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty diff --git a/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs b/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs index a45b432fa..e7d6b6352 100644 --- a/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs +++ b/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs @@ -12,10 +12,14 @@ type Config = { MaxLinesInFile:int } let private checkNumberOfLinesInFile numberOfLines line maxLines = if numberOfLines > maxLines then let errorFormatString = Resources.GetString("RulesTypographyFileLengthError") - { Range = Range.mkRange "" (Position.mkPos (maxLines + 1) 0) (Position.mkPos numberOfLines (String.length line)) - Message = String.Format(errorFormatString, (maxLines + 1)) - SuggestedFix = None - TypeChecks = [] } |> Array.singleton + { + Range = + Range.mkRange "" (Position.mkPos (maxLines + 1) 0) (Position.mkPos numberOfLines (String.length line)) + Message = String.Format(errorFormatString, (maxLines + 1)) + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty diff --git a/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs b/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs index 96886e6a6..92e7d31dd 100644 --- a/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs +++ b/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs @@ -24,7 +24,7 @@ let checkNoTabCharacters literalStrings (args:LineRuleParams) = let indexOfTab = args.Line.IndexOf('\t') if indexOfTab >= 0 then - let range = Range.mkRange "" (Position.mkPos args.LineNumber indexOfTab) (Position.mkPos args.LineNumber (indexOfTab + 1)) + let range = Range.mkRange String.Empty (Position.mkPos args.LineNumber indexOfTab) (Position.mkPos args.LineNumber (indexOfTab + 1)) if isInLiteralString literalStrings range |> not then { Range = range Message = Resources.GetString("RulesTypographyTabCharacterError") @@ -37,7 +37,7 @@ let checkNoTabCharacters literalStrings (args:LineRuleParams) = ToText = String.replicate args.GlobalConfig.numIndentationSpaces " " } )) ) - TypeChecks = [] } |> Array.singleton + TypeChecks = List.Empty } |> Array.singleton else Array.empty else diff --git a/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs b/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs index 0eccac9c4..3fdcf035c 100644 --- a/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs +++ b/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs @@ -9,10 +9,13 @@ open FSharp.Compiler.Text let checkTrailingNewLineInFile (args:LineRuleParams) = if args.IsLastLine && args.FileContent.EndsWith("\n") then let pos = Position.mkPos args.LineNumber 0 - { Range = Range.mkRange "" pos pos - Message = Resources.GetString("RulesTypographyTrailingLineError") - SuggestedFix = None - TypeChecks = [] } |> Array.singleton + { + Range = Range.mkRange "" pos pos + Message = Resources.GetString("RulesTypographyTrailingLineError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty diff --git a/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs b/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs index 27495ffa2..a6252cac4 100644 --- a/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs +++ b/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs @@ -46,11 +46,14 @@ let checkTrailingWhitespaceOnLine (config:Config) (args:LineRuleParams) = if stringEndsWithWhitespace then let whitespaceLength = lengthOfWhitespaceOnEnd line - let range = Range.mkRange "" (Position.mkPos lineNumber (line.Length - whitespaceLength)) (Position.mkPos lineNumber line.Length) - { Range = range - Message = Resources.GetString("RulesTypographyTrailingWhitespaceError") - SuggestedFix = None - TypeChecks = [] } |> Array.singleton + let range = Range.mkRange String.Empty (Position.mkPos lineNumber (line.Length - whitespaceLength)) (Position.mkPos lineNumber line.Length) + { + Range = range + Message = Resources.GetString("RulesTypographyTrailingWhitespaceError") + SuggestedFix = None + TypeChecks = List.Empty + } + |> Array.singleton else Array.empty diff --git a/tests/FSharpLint.Core.Tests/Framework/TestExpressionUtilities.fs b/tests/FSharpLint.Core.Tests/Framework/TestExpressionUtilities.fs index 459a7d029..7f401b454 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestExpressionUtilities.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestExpressionUtilities.fs @@ -1,5 +1,6 @@ module FSharpLint.Core.Tests.TestExpressionUtilities +open System open NUnit.Framework open FSharp.Compiler.Text open FSharpLint.Framework.ExpressionUtilities @@ -11,7 +12,7 @@ type TestExpressionUtilities() = let text = "123\n345\n678" let textOfRange (line1, col1) (line2, col2) = - tryFindTextOfRange (Range.mkRange "" (Position.mkPos line1 col1) (Position.mkPos line2 col2)) text + tryFindTextOfRange (Range.mkRange String.Empty (Position.mkPos line1 col1) (Position.mkPos line2 col2)) text Assert.AreEqual(Some "123", textOfRange (1, 0) (1, 3)) Assert.AreEqual(Some "345", textOfRange (2, 0) (2, 3)) diff --git a/tests/FSharpLint.Core.Tests/Rules/Conventions/SourceLength.fs b/tests/FSharpLint.Core.Tests/Rules/Conventions/SourceLength.fs index 34d8669d5..6ed14cc08 100644 --- a/tests/FSharpLint.Core.Tests/Rules/Conventions/SourceLength.fs +++ b/tests/FSharpLint.Core.Tests/Rules/Conventions/SourceLength.fs @@ -15,8 +15,8 @@ let generateNewLines numNewLines numIndents = else String.replicate numIndents " " $"{indentationChars}printf System.String.Empty\n") - (Array.create numNewLines "") - |> String.concat "" + (Array.create numNewLines String.Empty) + |> String.concat String.Empty let generateAbstractMembers numMembers numIndents = Array.init numMembers (fun index -> $"abstract member Foo%i{index} : unit -> unit\n") diff --git a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs index 56283f051..0487e9cf4 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs @@ -1,5 +1,6 @@ module FSharpLint.Core.Tests.TestAstNodeRuleBase +open System open FSharp.Compiler.CodeAnalysis open FSharpLint.Application open FSharpLint.Framework @@ -34,7 +35,7 @@ type TestAstNodeRuleBase (rule:Rule) = match checkFile with | Some false -> None | _ -> parseInfo.TypeCheckResults - let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue "" fileName) input (input.Split("\n")) syntaxArray |> fst + let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue String.Empty fileName) input (input.Split("\n")) syntaxArray |> fst rule.RuleConfig.Cleanup() suggestions |> Array.iter this.PostSuggestion diff --git a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs index fc13aa975..3cf4c0188 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs @@ -1,5 +1,6 @@ module FSharpLint.Core.Tests.TestHintMatcherBase +open System open FParsec open FSharp.Compiler.CodeAnalysis open FSharpLint.Application @@ -57,7 +58,7 @@ type TestHintMatcherBase () = match checkFile with | Some false -> None | _ -> parseInfo.TypeCheckResults - let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue "" fileName) input (input.Split "\n") syntaxArray |> fst + let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue String.Empty fileName) input (input.Split "\n") syntaxArray |> fst suggestions |> Array.iter this.PostSuggestion | _ -> failwithf "Failed to parse" \ No newline at end of file diff --git a/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs index c139cdb7b..f5b27657a 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs @@ -32,7 +32,12 @@ type TestIndentationRuleBase (rule:Rule) = let syntaxArray = AbstractSyntaxArray.astToArray parseResults.ParseTree let (_, context) = runAstNodeRules Array.empty globalConfig None fileName input lines syntaxArray - let lineRules = { LineRules.IndentationRule = Some rule; NoTabCharactersRule = None; GenericLineRules = [||] } + let lineRules = + { + LineRules.IndentationRule = Some rule + NoTabCharactersRule = None + GenericLineRules = Array.empty + } runLineRules lineRules globalConfig fileName input lines context |> Array.iter this.PostSuggestion \ No newline at end of file diff --git a/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs index 694ffdf99..04f0b3a9c 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs @@ -32,7 +32,11 @@ type TestNoTabCharactersRuleBase (rule:Rule) = let syntaxArray = AbstractSyntaxArray.astToArray parseResults.ParseTree let (_, context) = runAstNodeRules Array.empty globalConfig None fileName input lines syntaxArray - let lineRules = { LineRules.IndentationRule = None; NoTabCharactersRule = Some rule; GenericLineRules = [||] } - + let lineRules = + { + LineRules.IndentationRule = None + NoTabCharactersRule = Some rule + GenericLineRules = Array.empty + } runLineRules lineRules globalConfig fileName input lines context |> Array.iter this.PostSuggestion \ No newline at end of file From 6c0ce42dafea95ddc41810df347b000fa5e288a3 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 15:57:52 +0330 Subject: [PATCH 22/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index d58dfb18b..93dfda25c 100644 --- a/build.fsx +++ b/build.fsx @@ -286,6 +286,7 @@ Target.create "SelfCheck" (fun _ -> "maxLinesInClass" "favourTypedIgnore" "favourStaticEmptyFields" + "favourConsistentThis" ] let jsonObj = JObject.Parse fsharplintJsonText From 86e423ba915cd3ad01dfe91d08ab5ed1bc8aa880 Mon Sep 17 00:00:00 2001 From: webwarrior-ws Date: Tue, 29 Jul 2025 14:45:04 +0200 Subject: [PATCH 23/48] Core,Tests: fix FSharpLint warning Fixing the warning for FavourConsistentThis rule. --- src/FSharpLint.Core/Application/Lint.fs | 8 ++++---- src/FSharpLint.Core/Framework/HintParser.fs | 8 ++++---- .../FSharpLint.Core.Tests/Framework/TestConfiguration.fs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index a3d8a512c..ae76e1c9d 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -330,12 +330,12 @@ module Lint = | Success of Suggestion.LintWarning list | Failure of LintFailure - member self.TryGetSuccess([] success:byref) = - match self with + member this.TryGetSuccess([] success:byref) = + match this with | Success value -> success <- value; true | _ -> false - member self.TryGetFailure([] failure:byref) = - match self with + member this.TryGetFailure([] failure:byref) = + match this with | Failure value -> failure <- value; true | _ -> false diff --git a/src/FSharpLint.Core/Framework/HintParser.fs b/src/FSharpLint.Core/Framework/HintParser.fs index 10c0ae9c7..d49c3671f 100644 --- a/src/FSharpLint.Core/Framework/HintParser.fs +++ b/src/FSharpLint.Core/Framework/HintParser.fs @@ -135,14 +135,14 @@ module HintParser = { Lookup:Dictionary AnyMatch:(char option * Node) list } - override lhs.Equals(other) = + override this.Equals(other) = match other with | :? Edges as rhs -> let getList dict = Seq.toList dict |> List.map (fun (x:KeyValuePair<_, _>) -> (x.Key, x.Value)) - lhs.AnyMatch = rhs.AnyMatch && - lhs.Lookup.Count = rhs.Lookup.Count && - getList lhs.Lookup = getList rhs.Lookup + this.AnyMatch = rhs.AnyMatch && + this.Lookup.Count = rhs.Lookup.Count && + getList this.Lookup = getList rhs.Lookup | _ -> false override this.GetHashCode() = hash (this.AnyMatch, hash this.Lookup) diff --git a/tests/FSharpLint.Core.Tests/Framework/TestConfiguration.fs b/tests/FSharpLint.Core.Tests/Framework/TestConfiguration.fs index a5b53bdae..2da2f1738 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestConfiguration.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestConfiguration.fs @@ -4,8 +4,8 @@ open NUnit.Framework open FSharpLint.Framework.Configuration type System.String with - member path.ToPlatformIndependentPath() = - path.Replace('\\', System.IO.Path.DirectorySeparatorChar) + member this.ToPlatformIndependentPath() = + this.Replace('\\', System.IO.Path.DirectorySeparatorChar) let configWithHints hints = { Configuration.Zero with Hints = hints } From 4a6cf75472dbd48483c6f7a1c693f0a0ad035ea8 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 16:01:25 +0330 Subject: [PATCH 24/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 93dfda25c..ff6dfa377 100644 --- a/build.fsx +++ b/build.fsx @@ -287,6 +287,7 @@ Target.create "SelfCheck" (fun _ -> "favourTypedIgnore" "favourStaticEmptyFields" "favourConsistentThis" + "avoidTooShortNames" ] let jsonObj = JObject.Parse fsharplintJsonText From e9410e83af1de4d76230b0e8d44ae6a99fac6d7b Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 13 Dec 2023 16:10:20 +0330 Subject: [PATCH 25/48] Console,Core,Tests: fix FSharpLint warning Fixing the warning for AvoidTooShortNames rule. --- src/FSharpLint.Console/Output.fs | 2 +- src/FSharpLint.Console/Program.fs | 4 +- .../Application/Configuration.fs | 2 +- src/FSharpLint.Core/Application/Lint.fs | 46 ++++---- .../Framework/AbstractSyntaxArray.fs | 24 ++-- src/FSharpLint.Core/Framework/Ast.fs | 44 ++++---- src/FSharpLint.Core/Framework/HintParser.fs | 98 ++++++++-------- src/FSharpLint.Core/Framework/ParseFile.fs | 4 +- src/FSharpLint.Core/Framework/Resources.fs | 2 +- src/FSharpLint.Core/Framework/Utilities.fs | 18 +-- src/FSharpLint.Core/Prelude.fs | 14 +-- .../Conventions/Binding/BindingHelper.fs | 6 +- .../Conventions/Binding/TupleOfWildcards.fs | 2 +- .../Conventions/Binding/UselessBinding.fs | 2 +- .../Rules/Conventions/CyclomaticComplexity.fs | 14 +-- .../ReimplementsFunction.fs | 8 +- .../Rules/Conventions/Naming/LiteralNames.fs | 2 +- .../Rules/Conventions/Naming/NamingHelper.fs | 32 +++--- .../Rules/Conventions/NestedStatements.fs | 48 ++++---- .../MaxNumberOfBooleanOperatorsInCondition.fs | 2 +- .../NumberOfItems/MaxNumberOfItemsInTuple.fs | 12 +- .../Rules/Conventions/RedundantNewKeyword.fs | 2 +- .../SourceLength/SourceLengthHelper.fs | 4 +- .../Rules/Formatting/TypedItemSpacing.fs | 20 ++-- .../Rules/Hints/HintMatcher.fs | 106 +++++++++--------- .../Rules/Hints/HintsHelper.fs | 32 +++--- tests/FSharpLint.Benchmarks/Benchmark.fs | 2 +- .../Framework/TestAbstractSyntaxArray.fs | 22 ++-- .../Rules/Conventions/CyclomaticComplexity.fs | 12 +- .../Rules/TestRuleBase.fs | 23 ++-- tests/FSharpLint.FunctionalTest/TestApi.fs | 2 +- 31 files changed, 306 insertions(+), 305 deletions(-) diff --git a/src/FSharpLint.Console/Output.fs b/src/FSharpLint.Console/Output.fs index b0b48f071..058d4cdb9 100644 --- a/src/FSharpLint.Console/Output.fs +++ b/src/FSharpLint.Console/Output.fs @@ -23,7 +23,7 @@ type StandardOutput () = if String.length errorLine = 0 then "^" else errorLine - |> Seq.mapi (fun i _ -> if i = range.StartColumn then "^" else " ") + |> Seq.mapi (fun index _ -> if index = range.StartColumn then "^" else " ") |> Seq.reduce (+) $"{getErrorMessage range}{Environment.NewLine}{errorLine}{Environment.NewLine}{highlightColumnLine}" diff --git a/src/FSharpLint.Console/Program.fs b/src/FSharpLint.Console/Program.fs index 86439c632..519a42ea9 100644 --- a/src/FSharpLint.Console/Program.fs +++ b/src/FSharpLint.Console/Program.fs @@ -129,9 +129,9 @@ let private start (arguments:ParseResults) (toolsPath:Ionide.ProjInfo. | _ -> Lint.lintProject lintParams target toolsPath handleLintResult lintResult with - | e -> + | exn -> let target = if fileType = FileType.Source then "source" else target - $"Lint failed while analysing %s{target}.{Environment.NewLine}Failed with: %s{e.Message}{Environment.NewLine}Stack trace: {e.StackTrace}" + $"Lint failed while analysing %s{target}.{Environment.NewLine}Failed with: %s{exn.Message}{Environment.NewLine}Stack trace: {exn.StackTrace}" |> handleError | _ -> () diff --git a/src/FSharpLint.Core/Application/Configuration.fs b/src/FSharpLint.Core/Application/Configuration.fs index 2a371f0db..0d053b7b9 100644 --- a/src/FSharpLint.Core/Application/Configuration.fs +++ b/src/FSharpLint.Core/Application/Configuration.fs @@ -577,7 +577,7 @@ let loadConfig (configPath:string) = let defaultConfiguration = let assembly = typeof.GetTypeInfo().Assembly let resourceName = Assembly.GetExecutingAssembly().GetManifestResourceNames() - |> Seq.find (fun n -> n.EndsWith("fsharplint.json", System.StringComparison.Ordinal)) + |> Seq.find (fun resourceFile -> resourceFile.EndsWith("fsharplint.json", System.StringComparison.Ordinal)) use stream = assembly.GetManifestResourceStream(resourceName) match stream with | null -> failwithf "Resource '%s' not found in assembly '%s'" resourceName (assembly.FullName) diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index ae76e1c9d..e532108fe 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -61,8 +61,8 @@ module Lint = with get() = let getParseFailureReason = function | ParseFile.FailedToParseFile failures -> - let getFailureReason (x:FSharpDiagnostic) = - $"failed to parse file {x.FileName}, message: {x.Message}" + let getFailureReason (fSharpDiagnostic:FSharpDiagnostic) = + $"failed to parse file {fSharpDiagnostic.FileName}, message: {fSharpDiagnostic.Message}" String.Join(", ", failures |> Array.map getFailureReason) | ParseFile.AbortedTypeCheck -> "Type check failed. You might want to build your solution/project first and try again." @@ -85,8 +85,8 @@ module Lint = $"Lint failed to parse files. Failed with: {failureReasons}" [] - type Result<'T> = - | Success of 'T + type Result<'SuccessType> = + | Success of 'SuccessType | Failure of LintFailure /// Provides information on what the linter is currently doing. @@ -104,9 +104,9 @@ module Lint = /// Path of the F# file the progress information is for. member this.FilePath() = match this with - | Starting(f) - | ReachedEnd(f, _) - | Failed(f, _) -> f + | Starting(filePath) + | ReachedEnd(filePath, _) + | Failed(filePath, _) -> filePath [] type LintInfo = @@ -123,13 +123,13 @@ module Lint = let mutable indentationRuleState = Map.empty let mutable noTabCharactersRuleState = List.empty - let collect i (astNode: AbstractSyntaxArray.Node) = - let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth syntaxArray i + let collect index (astNode: AbstractSyntaxArray.Node) = + let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth syntaxArray index let astNodeParams = { AstNode = astNode.Actual NodeHashcode = astNode.Hashcode - NodeIndex = i + NodeIndex = index SyntaxArray = syntaxArray GetParents = getParents FilePath = filePath @@ -148,8 +148,8 @@ module Lint = // Collect suggestions for AstNode rules, and build context for following rules. let astNodeSuggestions = syntaxArray - |> Array.mapi (fun i astNode -> (i, astNode)) - |> Array.collect (fun (i, astNode) -> collect i astNode) + |> Array.mapi (fun index astNode -> (index, astNode)) + |> Array.collect (fun (index, astNode) -> collect index astNode) let context = { IndentationRuleContext = indentationRuleState @@ -212,7 +212,7 @@ module Lint = let cancelHasNotBeenRequested () = match lintInfo.CancellationToken with - | Some(x) -> not x.IsCancellationRequested + | Some(value) -> not value.IsCancellationRequested | None -> true let enabledRules = Configuration.flattenConfig lintInfo.Configuration @@ -265,7 +265,7 @@ module Lint = with | :? TimeoutException -> () // Do nothing. with - | e -> Failed(fileInfo.File, e) |> lintInfo.ReportLinterProgress + | exn -> Failed(fileInfo.File, exn) |> lintInfo.ReportLinterProgress ReachedEnd(fileInfo.File, fileWarnings |> Seq.toList) |> lintInfo.ReportLinterProgress @@ -281,17 +281,17 @@ module Lint = UseShellExecute = false ) - use p = new System.Diagnostics.Process(StartInfo = psi) + use proc = new System.Diagnostics.Process(StartInfo = psi) let sbOut = System.Text.StringBuilder() - p.OutputDataReceived.Add(fun ea -> sbOut.AppendLine(ea.Data) |> ignore) + proc.OutputDataReceived.Add(fun ea -> sbOut.AppendLine(ea.Data) |> ignore) let sbErr = System.Text.StringBuilder() - p.ErrorDataReceived.Add(fun ea -> sbErr.AppendLine(ea.Data) |> ignore) - p.Start() |> ignore - p.BeginOutputReadLine() - p.BeginErrorReadLine() - p.WaitForExit() + proc.ErrorDataReceived.Add(fun ea -> sbErr.AppendLine(ea.Data) |> ignore) + proc.Start() |> ignore + proc.BeginOutputReadLine() + proc.BeginErrorReadLine() + proc.WaitForExit() - let exitCode = p.ExitCode + let exitCode = proc.ExitCode (exitCode, (workingDir, exePath, args)) @@ -451,7 +451,7 @@ module Lint = | Ok projectOptions -> match parseFilesInProject (Array.toList projectOptions.SourceFiles) projectOptions with | Success _ -> lintWarnings |> Seq.toList |> LintResult.Success - | Failure x -> LintResult.Failure x + | Failure lintFailure -> LintResult.Failure lintFailure | Error error -> MSBuildFailedToLoadProjectFile (projectFilePath, BuildFailure.InvalidProjectFileMessage error) |> LintResult.Failure diff --git a/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs b/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs index c54f795af..aaa08e9e9 100644 --- a/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs +++ b/src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs @@ -274,9 +274,9 @@ module AbstractSyntaxArray = let result = Array.zeroCreate nodes.Count - let mutable i = 0 - while i < nodes.Count do - let skip = skips.[i] + let mutable index = 0 + while index < nodes.Count do + let skip = skips.[index] let node = nodes.[skip.Index] result.[skip.Index] <- @@ -285,20 +285,20 @@ module AbstractSyntaxArray = NumberOfChildren = skip.NumberOfChildren ParentIndex = skip.ParentIndex } - i <- i + 1 + index <- index + 1 result - let getBreadcrumbs maxBreadcrumbs (syntaxArray:Node []) i = - let rec getBreadcrumbs breadcrumbs i = - if i = 0 then - let node = syntaxArray.[i] + let getBreadcrumbs maxBreadcrumbs (syntaxArray:Node []) index = + let rec getBreadcrumbs breadcrumbs index = + if index = 0 then + let node = syntaxArray.[index] node.Actual::breadcrumbs - else if i < syntaxArray.Length && (List.length breadcrumbs) < maxBreadcrumbs then - let node = syntaxArray.[i] + else if index < syntaxArray.Length && (List.length breadcrumbs) < maxBreadcrumbs then + let node = syntaxArray.[index] getBreadcrumbs (node.Actual::breadcrumbs) node.ParentIndex else breadcrumbs - if i = 0 then List.Empty - else getBreadcrumbs List.Empty (syntaxArray.[i].ParentIndex) |> List.rev + if index = 0 then List.Empty + else getBreadcrumbs List.Empty (syntaxArray.[index].ParentIndex) |> List.rev diff --git a/src/FSharpLint.Core/Framework/Ast.fs b/src/FSharpLint.Core/Framework/Ast.fs index b53c7744c..09037aeeb 100644 --- a/src/FSharpLint.Core/Framework/Ast.fs +++ b/src/FSharpLint.Core/Framework/Ast.fs @@ -61,8 +61,8 @@ module Ast = | "op_PipeLeft" | "op_PipeLeft2" | "op_PipeLeft3" -> flatten (lhs::flattened) rhs | _ -> flatten (lhs::flattened) app - | x -> - let leftExpr, rightExpr = (x, y) + | expression -> + let leftExpr, rightExpr = (expression, y) flatten (rightExpr::flattened) leftExpr | expr -> expr::flattened @@ -82,7 +82,7 @@ module Ast = _, [SynMatchClause(SynPat.Wild(_), _, expr, _, _, _)], _, _) -> removeAutoGeneratedMatchesFromLambda expr - | x -> x + | synExpr -> synExpr let (|IsCurriedLambda|_|) = function | SynExpr.Lambda(_, _, parameter, (SynExpr.Lambda(_) as inner), _, _, _) as outer @@ -101,7 +101,7 @@ module Ast = match lambda with | AstNode.Expression(SynExpr.Lambda(_, _, _, _, _, range, _) as lambda) -> getLambdaParametersAndExpression List.Empty lambda - |> Option.map (fun x -> (x, range)) + |> Option.map (fun lambdaExprs -> (lambdaExprs, range)) | _ -> None let (|Cons|_|) pattern = @@ -122,8 +122,8 @@ module Ast = | _ -> None module List = - let inline revIter f items = - items |> List.rev |> List.iter f + let inline revIter action items = + items |> List.rev |> List.iter action let inline private moduleDeclarationChildren node add = match node with @@ -330,7 +330,7 @@ module Ast = bindings |> List.revIter (Binding >> add) | SynExpr.Ident(ident) -> add <| Identifier([ident.idText], ident.idRange) | SynExpr.LongIdent(_, SynLongIdent(ident, _, _), _, range) -> - add <| Identifier(ident |> List.map (fun x -> x.idText), range) + add <| Identifier(ident |> List.map (fun identifier -> identifier.idText), range) | SynExpr.IfThenElse(cond, body, Some(elseExpr), _, _, _, _) -> addMany [Else elseExpr; Expression body; Expression cond] | SynExpr.IfThenElse(cond, body, None, _, _, _, _) -> @@ -433,7 +433,7 @@ module Ast = /// Extracts the child nodes to be visited from a given node. let traverseNode node add = match node with - | ModuleDeclaration(x) -> moduleDeclarationChildren x add + | ModuleDeclaration(moduleDecl) -> moduleDeclarationChildren moduleDecl add | ModuleOrNamespace(SynModuleOrNamespace(_, _, _, moduleDeclarations, _, _, _, _, _)) -> moduleDeclarations |> List.revIter (ModuleDeclaration >> add) | Binding(SynBinding(_, _, _, _, _, _, _, pattern, _, expression, _, _, _)) -> @@ -446,33 +446,33 @@ module Ast = members |> List.revIter (MemberDefinition >> add) add <| TypeRepresentation typeRepresentation add <| ComponentInfo componentInfo - | TypeSimpleRepresentation(x) -> typeSimpleRepresentationChildren x add - | Type(x) -> typeChildren x add - | Match(x) -> matchChildren x add - | MemberDefinition(x) -> memberDefinitionChildren x add + | TypeSimpleRepresentation(value) -> typeSimpleRepresentationChildren value add + | Type(value) -> typeChildren value add + | Match(value) -> matchChildren value add + | MemberDefinition(value) -> memberDefinitionChildren value add | Field(SynField(_, _, _, synType, _, _, _, _, _)) -> add <| Type synType - | Pattern(x) -> patternChildren x add - | ConstructorArguments(x) -> constructorArgumentsChildren x add - | SimplePattern(x) -> simplePatternChildren x add - | LambdaArg(x) - | SimplePatterns(x) -> simplePatternsChildren x add + | Pattern(value) -> patternChildren value add + | ConstructorArguments(value) -> constructorArgumentsChildren value add + | SimplePattern(value) -> simplePatternChildren value add + | LambdaArg(value) + | SimplePatterns(value) -> simplePatternsChildren value add | InterfaceImplementation(SynInterfaceImpl(synType, _, bindings, _, _)) -> bindings |> List.revIter (Binding >> add) add <| Type synType - | TypeRepresentation(x) -> typeRepresentationChildren x add + | TypeRepresentation value -> typeRepresentationChildren value add | FuncApp(exprs, _) -> exprs |> List.revIter (Expression >> add) | Lambda({ Arguments = args; Body = body }, _) -> add <| LambdaBody(body) args |> List.revIter (LambdaArg >> add) - | LambdaBody(x) - | Else(x) - | Expression(x) -> expressionChildren x add + | LambdaBody(expression) + | Else(expression) + | Expression(expression) -> expressionChildren expression add | File(ParsedInput.ImplFile(ParsedImplFileInput(_, _, _, _, _, moduleOrNamespaces, _, _, _))) -> moduleOrNamespaces |> List.revIter (ModuleOrNamespace >> add) - | UnionCase(x) -> unionCaseChildren x add + | UnionCase(unionCase) -> unionCaseChildren unionCase add | File(ParsedInput.SigFile(_)) | ComponentInfo(_) | EnumCase(_) diff --git a/src/FSharpLint.Core/Framework/HintParser.fs b/src/FSharpLint.Core/Framework/HintParser.fs index d49c3671f..19a02bdd5 100644 --- a/src/FSharpLint.Core/Framework/HintParser.fs +++ b/src/FSharpLint.Core/Framework/HintParser.fs @@ -138,7 +138,7 @@ module HintParser = override this.Equals(other) = match other with | :? Edges as rhs -> - let getList dict = Seq.toList dict |> List.map (fun (x:KeyValuePair<_, _>) -> (x.Key, x.Value)) + let getList dict = Seq.toList dict |> List.map (fun (dictItems:KeyValuePair<_, _>) -> (dictItems.Key, dictItems.Value)) this.AnyMatch = rhs.AnyMatch && this.Lookup.Count = rhs.Lookup.Count && @@ -231,7 +231,7 @@ module HintParser = [HintExpr ifCond; HintExpr bodyExpr; HintExpr elseExpr] | HintExpr(Expression.If(ifCond, bodyExpr, None)) -> [HintExpr ifCond; HintExpr bodyExpr] - | HintExpr(Expression.Else(x)) -> [HintExpr x] + | HintExpr(Expression.Else(expression)) -> [HintExpr expression] | HintExpr(Expression.Identifier(_)) | HintExpr(Expression.Constant(_)) | HintExpr(Expression.Null) @@ -250,24 +250,24 @@ module HintParser = | HintPat(Pattern.Null) -> List.Empty let private getConstantHashCode = function - | Constant.Bool(x) -> hash x - | Constant.Byte(x) -> hash x - | Constant.Bytes(x) -> hash x - | Constant.Char(x) -> hash x - | Constant.Decimal(x) -> hash x - | Constant.Double(x) -> hash x - | Constant.Int16(x) -> hash x - | Constant.Int32(x) -> hash x - | Constant.Int64(x) -> hash x - | Constant.IntPtr(x) -> hash x - | Constant.SByte(x) -> hash x - | Constant.Single(x) -> hash x - | Constant.String(x) -> hash x - | Constant.UInt16(x) -> hash x - | Constant.UInt32(x) -> hash x - | Constant.UInt64(x) -> hash x - | Constant.UIntPtr(x) -> hash x - | Constant.UserNum(x, y) -> hash (x, y) + | Constant.Bool value -> hash value + | Constant.Byte value -> hash value + | Constant.Bytes value -> hash value + | Constant.Char value -> hash value + | Constant.Decimal value -> hash value + | Constant.Double value -> hash value + | Constant.Int16 value -> hash value + | Constant.Int32 value -> hash value + | Constant.Int64 value -> hash value + | Constant.IntPtr value -> hash value + | Constant.SByte value -> hash value + | Constant.Single value -> hash value + | Constant.String value -> hash value + | Constant.UInt16 value -> hash value + | Constant.UInt32 value -> hash value + | Constant.UInt64 value -> hash value + | Constant.UIntPtr value -> hash value + | Constant.UserNum(intValue, charValue) -> hash (intValue, charValue) | _ -> 0 let private getIdentifierHashCode = function @@ -388,13 +388,13 @@ module HintParser = getEdges transposed let charListToString charList = - Seq.fold (fun x y -> x + y.ToString()) String.Empty charList + Seq.fold (fun concatenatedString charElement -> concatenatedString + charElement.ToString()) String.Empty charList - let pischar chars : Parser = - satisfy (fun x -> List.exists ((=) x) chars) + let pischar chars : Parser = + satisfy (fun character -> List.exists ((=) character) chars) - let pnotchar chars : Parser = - satisfy (fun x -> not <| List.exists ((=) x) chars) + let pnotchar chars : Parser = + satisfy (fun character -> not <| List.exists ((=) character) chars) module Operators = let pfirstopchar: Parser = @@ -447,7 +447,7 @@ module HintParser = let private plongident: (CharStream -> Reply) = choice [ attempt (sepBy1 pident (skipChar '.')) - pident |>> fun x -> [x] ] + pident |>> fun identChars -> [identChars] ] let private pidentorop: (CharStream -> Reply) = choice @@ -468,7 +468,7 @@ module HintParser = match operator with | Some(operator) -> identifiers@[operator] | None -> identifiers) - attempt (pidentorop |>> fun x -> [x]) + attempt (pidentorop |>> fun identOrOpChars -> [identOrOpChars]) plongident ] |>> List.map charListToString @@ -494,7 +494,7 @@ module HintParser = let private pescapechar: Parser = skipChar '\\' >>. pischar ['"';'\\';'\'';'n';'t';'b';'r';'a';'f';'v'] - |>> fun x -> Map.find x escapeMap + |>> fun escapeChar -> Map.find escapeChar escapeMap let private pnonescapechars: Parser = skipChar '\\' @@ -509,29 +509,29 @@ module HintParser = let private punicodegraphshort: Parser = skipString "\\u" >>. many1 hex - >>= fun x -> - if x.Length <> 4 then + >>= fun unicodegraphChars -> + if unicodegraphChars.Length <> 4 then fail "Unicode graph short must be 4 hex characters long" else - preturn (x |> charListToString |> hexToCharacter) + preturn (unicodegraphChars |> charListToString |> hexToCharacter) let private punicodegraphlong: Parser = skipString "\\U" >>. many1 hex - >>= fun x -> - if x.Length <> 8 then + >>= fun unicodegraphChars -> + if unicodegraphChars.Length <> 8 then fail "Unicode graph long must be 8 hex characters long" else - preturn (x |> charListToString |> hexToCharacter) + preturn (unicodegraphChars |> charListToString |> hexToCharacter) let private ptrigraph: Parser = skipChar '\\' >>. many1 digit - >>= fun x -> - if x.Length <> 3 then + >>= fun trigraphChars -> + if trigraphChars.Length <> 3 then fail "Trigraph must be 3 characters long" else - preturn (x |> charListToString |> decimalToCharacter) + preturn (trigraphChars |> charListToString |> decimalToCharacter) let private pnewline: Parser = pchar '\n' <|> (skipChar '\r' >>. skipChar '\n' >>% '\n') @@ -629,19 +629,19 @@ module HintParser = skipChar '0' >>. (skipChar 'x' <|> skipChar 'X') >>. many1 hex - |>> fun x -> '0'::'x'::x + |>> fun hexChars -> '0'::'x'::hexChars let private poctalint: Parser = skipChar '0' >>. (skipChar 'o' <|> skipChar 'O') >>. many1 octal - |>> fun x -> '0'::'o'::x + |>> fun octalChars -> '0'::'o'::octalChars let private pbinaryint: Parser = skipChar '0' >>. (skipChar 'b' <|> skipChar 'B') >>. many1 (pchar '0' <|> pchar '1') - |>> fun x -> '0'::'b'::x + |>> fun binaryChars -> '0'::'b'::binaryChars let private pint: (CharStream -> Reply) = choice @@ -784,7 +784,7 @@ module HintParser = satisfy isLetter .>> notFollowedBy (satisfy isLetter) - let ptuple (pparser:Parser<'T, unit>) : Parser<'T list, unit> = + let ptuple (pparser:Parser<'Element, unit>) : Parser<'Element list, unit> = skipChar '(' >>. pparser .>> skipChar ',' @@ -792,14 +792,14 @@ module HintParser = .>> skipChar ')' |>> fun (func, rest) -> (func::rest) - let plist (pparser:Parser<'T, unit>): Parser<'T list, unit> = + let plist (pparser:Parser<'Element, unit>): Parser<'Element list, unit> = skipChar '[' >>. spaces >>. sepEndBy pparser (skipChar ';') .>> spaces .>> skipChar ']' - let parray (pparser:Parser<'T, unit>): Parser<'T list, unit> = + let parray (pparser:Parser<'Element, unit>): Parser<'Element list, unit> = skipString "[|" >>. spaces >>. sepEndBy pparser (skipChar ';') @@ -1065,24 +1065,24 @@ module HintParser = let pexpressionbasedhint = parse { - let! m = Expressions.pexpression + let! expression = Expressions.pexpression do! phintcenter - let! s = psuggestion + let! suggestion = psuggestion - return { MatchedNode = HintExpr m; Suggestion = s } + return { MatchedNode = HintExpr expression; Suggestion = suggestion } } let ppatternbasedhint = parse { - let! m = Patterns.ppattern + let! pattern = Patterns.ppattern do! phintcenter - let! s = psuggestion + let! suggestion = psuggestion - return { MatchedNode = HintPat m; Suggestion = s } + return { MatchedNode = HintPat pattern; Suggestion = suggestion } } let phint: Parser = diff --git a/src/FSharpLint.Core/Framework/ParseFile.fs b/src/FSharpLint.Core/Framework/ParseFile.fs index d2183c0ae..8f92780f8 100644 --- a/src/FSharpLint.Core/Framework/ParseFile.fs +++ b/src/FSharpLint.Core/Framework/ParseFile.fs @@ -33,9 +33,9 @@ module ParseFile = | AbortedTypeCheck [] - type ParseFileResult<'T> = + type ParseFileResult<'Content> = | Failed of ParseFileFailure - | Success of 'T + | Success of 'Content let private parse file source (checker:FSharpChecker, options) = let sourceText = SourceText.ofString source diff --git a/src/FSharpLint.Core/Framework/Resources.fs b/src/FSharpLint.Core/Framework/Resources.fs index 1ca40f977..a25ec81dc 100644 --- a/src/FSharpLint.Core/Framework/Resources.fs +++ b/src/FSharpLint.Core/Framework/Resources.fs @@ -7,7 +7,7 @@ open System.Resources /// Used to retrieve multi-lingual strings inside of the app. type Resources() = static let resourceName = Assembly.GetExecutingAssembly().GetManifestResourceNames() - |> Seq.find (fun n -> n.EndsWith("Text.resources", System.StringComparison.Ordinal)) + |> Seq.find (fun resource -> resource.EndsWith("Text.resources", System.StringComparison.Ordinal)) static let resourceManager = ResourceManager(resourceName.Replace(".resources", System.String.Empty), typeof.GetTypeInfo().Assembly) diff --git a/src/FSharpLint.Core/Framework/Utilities.fs b/src/FSharpLint.Core/Framework/Utilities.fs index 6c963da23..55945c6fb 100644 --- a/src/FSharpLint.Core/Framework/Utilities.fs +++ b/src/FSharpLint.Core/Framework/Utilities.fs @@ -9,7 +9,7 @@ module Utilities = current <- current * 31 + hash one current * 31 + hash two - let () x y = System.IO.Path.Combine(x, y) + let () path1 path2 = System.IO.Path.Combine(path1, path2) module Dictionary = @@ -37,7 +37,7 @@ module ExpressionUtilities = let getSymbolFromIdent (checkFile:FSharpCheckFileResults option) expr = match (checkFile, expr) with | Some(checkFile), Identifier(ident, range) -> - let identNames = ident |> List.map (fun x -> x.idText) + let identNames = ident |> List.map (fun identifier -> identifier.idText) checkFile.GetSymbolUseAtLocation( range.StartLine, @@ -60,8 +60,8 @@ module ExpressionUtilities = /// Extracts an expression from parentheses e.g. ((x + 4)) -> x + 4 let rec removeParens = function - | SynExpr.Paren(x, _, _, _) -> removeParens x - | x -> x + | SynExpr.Paren(expr, _, _, _) -> removeParens expr + | expression -> expression /// Finds index of a given (line number, column) position in a string. let findPos (pos:pos) (str:string) = @@ -73,7 +73,7 @@ module ExpressionUtilities = else None findLineStart pos.Line 1 0 - |> Option.map (fun x -> x + pos.Column) + |> Option.map (fun lineStart -> lineStart + pos.Column) /// Converts a LongIdent to a String. let longIdentToString (lid:LongIdent) = @@ -106,7 +106,7 @@ module ExpressionUtilities = let synTypeToString (text:string) = function | SynType.Tuple _ as synType -> tryFindTextOfRange synType.Range text - |> Option.map (fun x -> $"({x})") + |> Option.map (fun extractedText -> $"({extractedText})") | other -> tryFindTextOfRange other.Range text @@ -150,15 +150,15 @@ module String = | null -> None | line -> Some line - let rec iterateLines currentLine i = + let rec iterateLines currentLine index = match currentLine with | Some line -> let nextLine = readLine () let isLastLine = Option.isNone nextLine - lines.Add(line, i, isLastLine) + lines.Add(line, index, isLastLine) - iterateLines nextLine (i + 1) + iterateLines nextLine (index + 1) | None -> () iterateLines (readLine ()) 0 diff --git a/src/FSharpLint.Core/Prelude.fs b/src/FSharpLint.Core/Prelude.fs index 5ff3b0c20..23a525c3b 100644 --- a/src/FSharpLint.Core/Prelude.fs +++ b/src/FSharpLint.Core/Prelude.fs @@ -4,11 +4,11 @@ namespace FSharpLint.Core module Prelude = module Async = - let combine f x y = async { - let! x = x - let! y = y - return f x y } + let combine operation firstAsync secondAsync = async { + let! firstOperation = firstAsync + let! secondOperation = secondAsync + return operation firstOperation secondOperation } - let map f xAsync = async { - let! x = xAsync - return f x } \ No newline at end of file + let map operation xAsync = async { + let! xAsyncArg = xAsync + return operation xAsyncArg } \ No newline at end of file diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/BindingHelper.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/BindingHelper.fs index 77125bb3f..dd9ec7ced 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/BindingHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/BindingHelper.fs @@ -4,9 +4,9 @@ open FSharpLint.Framework open FSharp.Compiler.Syntax open FSharpLint.Framework.Ast -let isLetBinding i (syntaxArray:AbstractSyntaxArray.Node []) = - if i > 0 then - match syntaxArray.[syntaxArray.[i].ParentIndex].Actual with +let isLetBinding index (syntaxArray:AbstractSyntaxArray.Node []) = + if index > 0 then + match syntaxArray.[syntaxArray.[index].ParentIndex].Actual with | AstNode.ModuleDeclaration(SynModuleDecl.Let(_)) | AstNode.Expression(SynExpr.LetOrUse(_, false, _, _, _, _)) -> true | _ -> false diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs index 01146706a..7888fe48d 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs @@ -58,7 +58,7 @@ let private runner (args:AstNodeRuleParams) = | AstNode.Pattern(SynPat.LongIdent(identifier, _, _, SynArgPats.Pats([SynPat.Paren(SynPat.Tuple(_, _, _, range) as pattern, _)]), _, identRange)) -> let breadcrumbs = args.GetParents 2 if (not << isTupleMemberArgs breadcrumbs) range then - let identifier = identifier.LongIdent |> List.map (fun x -> x.idText) + let identifier = identifier.LongIdent |> List.map (fun ident -> ident.idText) checkTupleOfWildcards args.FileContent pattern identifier identRange else Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs index 36022b62f..904f05af5 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs @@ -19,7 +19,7 @@ let private checkForUselessBinding (checkInfo:FSharpCheckFileResults option) pat let isNotMutable (symbol:FSharpSymbolUse) = match symbol.Symbol with - | :? FSharpMemberOrFunctionOrValue as v -> not v.IsMutable + | :? FSharpMemberOrFunctionOrValue as fSharpMemberOrFunctionOrValue -> not fSharpMemberOrFunctionOrValue.IsMutable | _ -> true let checkNotMutable (ident:Ident) = fun () -> diff --git a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs index 79bf87496..d528bc2fb 100644 --- a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs +++ b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs @@ -46,7 +46,7 @@ type private BindingStack(maxComplexity: int) = let isChildOfCurrent = if List.isEmpty tier1 then false else - args.GetParents args.NodeIndex |> List.tryFind (fun x -> Object.ReferenceEquals(tier1.Head.Node, x)) |> Option.isSome + args.GetParents args.NodeIndex |> List.tryFind (fun astNode -> Object.ReferenceEquals(tier1.Head.Node, astNode)) |> Option.isSome // if the node is not a child and the stack isn't empty, we're finished with the current head of tier1, so move it from tier1 to tier2 if not isChildOfCurrent && not (List.isEmpty tier1) then let popped = tier1.Head @@ -57,9 +57,9 @@ type private BindingStack(maxComplexity: int) = tier1 <- bs::tier1 member this.IncrComplexityOfCurrentScope incr = - let h = tier1.Head - let complexity = h.Complexity + incr - tier1 <- {h with Complexity = complexity}::tier1.Tail + let head = tier1.Head + let complexity = head.Complexity + incr + tier1 <- {head with Complexity = complexity}::tier1.Tail interface IEnumerable with member this.GetEnumerator() = @@ -131,8 +131,8 @@ let private countBooleanOperators expression = | SynExpr.MatchBang(_, _, clauses, _, _) | SynExpr.MatchLambda(_, _, clauses, _, _) | SynExpr.Match(_, _, clauses, _, _) -> - clauses |> List.sumBy (fun c -> - match c with + clauses |> List.sumBy (fun matchClause -> + match matchClause with | SynMatchClause(_, whenExprOpt, _, _, _, _) -> match whenExprOpt with | Some whenExpr -> @@ -197,7 +197,7 @@ let runner (config:Config) (args:AstNodeRuleParams) : WarningDetails[] = { Range = scope.Binding.RangeOfBindingWithRhs; Message = errMsg; SuggestedFix = None; TypeChecks = List.Empty }) |> Seq.toList let ret = match warningDetails with - | Some x -> x::fromStack + | Some warning -> warning::fromStack | None -> fromStack ret |> List.toArray else diff --git a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs index 4f2492cd3..97d5cbb37 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs @@ -24,11 +24,11 @@ let private validateLambdaIsNotPointless (text:string) lambda range = let generateError (identifier:LongIdent) = let identifier = identifier - |> List.map (fun x -> - if PrettyNaming.IsLogicalOpName x.idText then - PrettyNaming.ConvertValLogicalNameToDisplayNameCore x.idText |> sprintf "( %s )" + |> List.map (fun ident -> + if PrettyNaming.IsLogicalOpName ident.idText then + PrettyNaming.ConvertValLogicalNameToDisplayNameCore ident.idText |> sprintf "( %s )" else - x.idText) + ident.idText) |> String.concat "." let suggestedFix = lazy( diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs index 73e6da84a..e303d2ce1 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs @@ -12,7 +12,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = let rec getLiteralIdents = function | SynPat.Named(SynIdent(identifier, _), _, _, _) -> (identifier, identifier.idText, None) |> Array.singleton - | SynPat.Paren(p, _) -> getLiteralIdents p + | SynPat.Paren(pat, _) -> getLiteralIdents pat | _ -> Array.empty getLiteralIdents pattern diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs index db4d18df1..02ea75b93 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs @@ -18,7 +18,7 @@ module QuickFixes = let removeNonPrefixingUnderscores (ident:Ident) = lazy( let prefixingUnderscores = - ident.idText |> Seq.takeWhile (fun x -> x = '_') |> String.Concat + ident.idText |> Seq.takeWhile (fun char -> char = '_') |> String.Concat let toText = prefixingUnderscores + ident.idText.Replace("_", String.Empty) Some { FromText = ident.idText; FromRange = ident.idRange; ToText = toText }) @@ -31,7 +31,7 @@ module QuickFixes = let private mapFirstChar map (str:string) = let prefix = - str |> Seq.takeWhile (fun x -> x = '_') |> String.Concat + str |> Seq.takeWhile (fun char -> char = '_') |> String.Concat let withoutPrefix = str.Substring prefix.Length if withoutPrefix.Length > 0 then let firstChar = map withoutPrefix.[0] |> string @@ -55,7 +55,7 @@ let private NumberOfExpectedBackticks = 4 /// the information as to whether the identifier was backticked doesn't appear to be in the AST. let private isNotDoubleBackTickedIdent = let isDoubleBackTickedIdent (identifier:Ident) = - let diffOfRangeAgainstIdent (r:Range) = (r.EndColumn - r.StartColumn) - identifier.idText.Length + let diffOfRangeAgainstIdent (range:Range) = (range.EndColumn - range.StartColumn) - identifier.idText.Length let range = identifier.idRange not range.IsSynthetic && diffOfRangeAgainstIdent range = NumberOfExpectedBackticks @@ -178,7 +178,7 @@ let isActivePattern (identifier:Ident) = let activePatternIdentifiers (identifier:Ident) = identifier.idText.Split('|') |> Seq.toArray - |> Array.filter (fun x -> not <| String.IsNullOrEmpty(x) && x.Trim() <> "_") + |> Array.filter (fun identifierSegment -> not <| String.IsNullOrEmpty(identifierSegment) && identifierSegment.Trim() <> "_") /// Specifies access control level as described in @@ -191,16 +191,16 @@ type AccessControlLevel = | Private | Internal -let getAccessControlLevel (syntaxArray:AbstractSyntaxArray.Node []) i = +let getAccessControlLevel (syntaxArray:AbstractSyntaxArray.Node []) index = let resolveAccessControlLevel = function | Some(SynAccess.Public _) | None -> AccessControlLevel.Public | Some(SynAccess.Private _) -> AccessControlLevel.Private | Some(SynAccess.Internal _) -> AccessControlLevel.Internal - let rec getAccessibility state isPrivateWhenReachedBinding i = - if i = 0 then state + let rec getAccessibility state isPrivateWhenReachedBinding index = + if index = 0 then state else - let node = syntaxArray.[i] + let node = syntaxArray.[index] match node.Actual with | TypeSimpleRepresentation(SynTypeDefnSimpleRepr.Record(access, _, _)) | TypeSimpleRepresentation(SynTypeDefnSimpleRepr.Union(access, _, _)) @@ -238,7 +238,7 @@ let getAccessControlLevel (syntaxArray:AbstractSyntaxArray.Node []) i = | LambdaBody(_) | Expression(_) -> getAccessibility state true node.ParentIndex - getAccessibility AccessControlLevel.Public false i + getAccessibility AccessControlLevel.Public false index /// Is an attribute with a given name? @@ -301,19 +301,19 @@ let isModule (moduleKind:SynModuleOrNamespaceKind) = /// Is module name implicitly created from file name? let isImplicitModule (SynModuleOrNamespace.SynModuleOrNamespace(longIdent, _, moduleKind, _, _, _, _, range, _)) = - let zeroLengthRange (r:Range) = - (r.EndColumn - r.StartColumn) = 0 && r.StartLine = r.EndLine + let zeroLengthRange (range:Range) = + (range.EndColumn - range.StartColumn) = 0 && range.StartLine = range.EndLine // Check the identifiers in the module name have no length. // Not ideal but there's no attribute in the AST indicating the module is implicit from the file name. // TODO: does SynModuleOrNamespaceKind.AnonModule replace this check? - isModule moduleKind && longIdent |> List.forall (fun x -> zeroLengthRange x.idRange) + isModule moduleKind && longIdent |> List.forall (fun ident -> zeroLengthRange ident.idRange) -type GetIdents<'T> = AccessControlLevel -> SynPat -> 'T [] +type GetIdents<'Item> = AccessControlLevel -> SynPat -> 'Item [] /// Recursively get all identifiers from pattern using provided getIdents function and collect them into array. /// accessibility parameter is passed to getIdents, and can be narrowed down along the way (see checkAccessibility). -let rec getPatternIdents<'T> (accessibility:AccessControlLevel) (getIdents:GetIdents<'T>) argsAreParameters (pattern:SynPat) = +let rec getPatternIdents<'Item> (accessibility:AccessControlLevel) (getIdents:GetIdents<'Item>) argsAreParameters (pattern:SynPat) = match pattern with | SynPat.LongIdent(_, _, _, args, access, _) -> let identAccessibility = checkAccessibility accessibility access @@ -346,8 +346,8 @@ let rec getPatternIdents<'T> (accessibility:AccessControlLevel) (getIdents:GetId | SynPat.Or(p1, p2, _, _) -> [|p1; p2|] |> Array.collect (getPatternIdents accessibility getIdents false) - | SynPat.Paren(p, _) -> - getPatternIdents accessibility getIdents false p + | SynPat.Paren(pat, _) -> + getPatternIdents accessibility getIdents false pat | SynPat.Ands(pats, _) | SynPat.Tuple(_, pats, _, _) | SynPat.ArrayOrList(_, pats, _) -> diff --git a/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs b/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs index 8ae39f2be..28e20dbee 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs @@ -44,35 +44,35 @@ let private getRange node = | AstNode.Binding(node) -> Some node.RangeOfBindingWithRhs | _ -> None -let private distanceToCommonParent (syntaxArray:AbstractSyntaxArray.Node []) i j = - let mutable i = i - let mutable j = j +let private distanceToCommonParent (syntaxArray:AbstractSyntaxArray.Node []) iIndex jIndex = + let mutable iIndex = iIndex + let mutable jIndex = jIndex let mutable distance = 0 - while i <> j do - if i > j then - i <- syntaxArray.[i].ParentIndex + while iIndex <> jIndex do + if iIndex > jIndex then + iIndex <- syntaxArray.[iIndex].ParentIndex - if i <> j && areChildrenNested syntaxArray.[i].Actual then + if iIndex <> jIndex && areChildrenNested syntaxArray.[iIndex].Actual then distance <- distance + 1 else - j <- syntaxArray.[j].ParentIndex + jIndex <- syntaxArray.[jIndex].ParentIndex distance /// Is node a duplicate of a node in the AST containing ExtraSyntaxInfo /// e.g. lambda arg being a duplicate of the lambda. -let isMetaData args node i = - let parentIndex = args.SyntaxArray.[i].ParentIndex - if parentIndex = i then false +let isMetaData args node index = + let parentIndex = args.SyntaxArray.[index].ParentIndex + if parentIndex = index then false else Object.ReferenceEquals(node, args.SyntaxArray.[parentIndex].Actual) -let isElseIf args node i = +let isElseIf args node index = match node with | AstNode.Expression(SynExpr.IfThenElse(_)) -> - let parentIndex = args.SyntaxArray.[i].ParentIndex - if parentIndex = i then false + let parentIndex = args.SyntaxArray.[index].ParentIndex + if parentIndex = index then false else match args.SyntaxArray.[parentIndex].Actual with | AstNode.Expression(SynExpr.IfThenElse(_, _, Some(_), _, _, _, _)) -> true @@ -81,13 +81,13 @@ let isElseIf args node i = let mutable depth = 0 -let decrementDepthToCommonParent args i j = - if j < args.SyntaxArray.Length then +let decrementDepthToCommonParent args iIndex jIndex = + if jIndex < args.SyntaxArray.Length then // If next node in array is not a sibling or child of the current node. - let parent = args.SyntaxArray.[j].ParentIndex - if parent <> i && parent <> args.SyntaxArray.[i].ParentIndex then + let parent = args.SyntaxArray.[jIndex].ParentIndex + if parent <> iIndex && parent <> args.SyntaxArray.[iIndex].ParentIndex then // Decrement depth until we reach a common parent. - depth <- depth - (distanceToCommonParent args.SyntaxArray i j) + depth <- depth - (distanceToCommonParent args.SyntaxArray iIndex jIndex) let mutable skipToIndex = None @@ -103,15 +103,15 @@ let runner (config:Config) (args:AstNodeRuleParams) = true if not skip then - let i = args.NodeIndex + let index = args.NodeIndex let node = args.AstNode - decrementDepthToCommonParent args i (i + 1) + decrementDepthToCommonParent args index (index + 1) - if areChildrenNested node && not <| isMetaData args node i && not <| isElseIf args node i then + if areChildrenNested node && not <| isMetaData args node index && not <| isElseIf args node index then if depth >= config.Depth then // Skip children as we've had an error containing them. - let skipChildren = i + args.SyntaxArray.[i].NumberOfChildren + 1 - decrementDepthToCommonParent args i skipChildren + let skipChildren = index + args.SyntaxArray.[index].NumberOfChildren + 1 + decrementDepthToCommonParent args index skipChildren skipToIndex <- Some skipChildren getRange node diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs index 63d8449c4..8123f9824 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs @@ -29,7 +29,7 @@ let private validateCondition (maxBooleanOperators:int) condition = total + 1 else total - | x -> + | _ -> total let ruleName = "MaxNumberOfBooleanOperatorsInCondition" diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs index a8ecee7d2..9e19c2201 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs @@ -7,18 +7,18 @@ open FSharp.Compiler.Syntax open FSharpLint.Framework.Ast open FSharpLint.Framework.Rules -let private isInApplication (syntaxArray:AbstractSyntaxArray.Node[]) i = - let rec isApplicationNode i = - if i <= 0 then false +let private isInApplication (syntaxArray:AbstractSyntaxArray.Node[]) index = + let rec isApplicationNode nodeIndex = + if nodeIndex <= 0 then false else - let node = syntaxArray.[i] + let node = syntaxArray.[nodeIndex] match node.Actual with | AstNode.Expression(SynExpr.Paren(_)) -> isApplicationNode node.ParentIndex | AstNode.Expression(SynExpr.App(_) | SynExpr.New(_)) -> true | _ -> false - if i <= 0 then false - else isApplicationNode syntaxArray.[i].ParentIndex + if index <= 0 then false + else isApplicationNode syntaxArray.[index].ParentIndex let private validateTuple (maxItems:int) (items:SynExpr list) = if List.length items > maxItems then diff --git a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs index f8e46ad4b..3a4322581 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs @@ -19,7 +19,7 @@ let private implementsIDisposable (fsharpType:FSharpType) = false let private doesNotImplementIDisposable (checkFile:FSharpCheckFileResults) (ident: SynLongIdent) = - let names = ident.LongIdent |> List.map (fun x -> x.idText) + let names = ident.LongIdent |> List.map (fun identifier -> identifier.idText) let symbol = checkFile.GetSymbolUseAtLocation(ident.Range.StartLine, ident.Range.EndColumn, String.Empty, names) match symbol with diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs index 8d7af4a14..2ae9eec42 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs @@ -17,9 +17,9 @@ type private MultilineCommentMarker = | Begin of int | End of int -let private error name i actual = +let private error name lineCount actual = let errorFormatString = Resources.GetString("RulesSourceLengthError") - String.Format(errorFormatString, name, i, actual) + String.Format(errorFormatString, name, lineCount, actual) let private singleLineCommentRegex = Regex(@"^[\s]*\/\/.*$", RegexOptions.Multiline) diff --git a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs index 45bc8f385..fa39ce49d 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs @@ -16,21 +16,21 @@ type TypedItemStyle = [] type Config = { TypedItemStyle:TypedItemStyle } -let private getLeadingSpaces (s:string) = - let rec loop i = - if i < s.Length && s.[i] = ' ' - then loop (i + 1) - else i +let private getLeadingSpaces (text:string) = + let rec loop index = + if index < text.Length && text.[index] = ' ' + then loop (index + 1) + else index loop 0 -let private getTrailingSpaces (s:string) = - let rec loop i count = - if i >= 0 && s.[i] = ' ' - then loop (i - 1) (count + 1) +let private getTrailingSpaces (text:string) = + let rec loop index count = + if index >= 0 && text.[index] = ' ' + then loop (index - 1) (count + 1) else count - (loop (s.Length - 1) 0) + (loop (text.Length - 1) 0) let private expectedSpacesFromConfig (typedItemStyle:TypedItemStyle) = match typedItemStyle with diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index 40d8422b4..c38eb03e1 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -76,29 +76,29 @@ let private matchLambdaArguments (hintArgs:HintParser.LambdaArg list) (actualArg /// Converts a SynConst (FSharp AST) into a Constant (hint AST). let private matchConst = function - | SynConst.Bool(x) -> Some(Constant.Bool(x)) - | SynConst.Int16(x) -> Some(Constant.Int16(x)) - | SynConst.Int32(x) -> Some(Constant.Int32(x)) - | SynConst.Int64(x) -> Some(Constant.Int64(x)) - | SynConst.UInt16(x) -> Some(Constant.UInt16(x)) - | SynConst.UInt32(x) -> Some(Constant.UInt32(x)) - | SynConst.UInt64(x) -> Some(Constant.UInt64(x)) - | SynConst.Byte(x) -> Some(Constant.Byte(x)) - | SynConst.Bytes(x, _, _) -> Some(Constant.Bytes(x)) - | SynConst.Char(x) -> Some(Constant.Char(x)) - | SynConst.Decimal(x) -> Some(Constant.Decimal(x)) - | SynConst.Double(x) -> Some(Constant.Double(x)) - | SynConst.SByte(x) -> Some(Constant.SByte(x)) - | SynConst.Single(x) -> Some(Constant.Single(x)) - | SynConst.String(x, _, _) -> Some(Constant.String(x)) - | SynConst.UIntPtr(x) -> Some(Constant.UIntPtr(unativeint x)) - | SynConst.IntPtr(x) -> Some(Constant.IntPtr(nativeint x)) - | SynConst.UserNum(x, endChar) -> - Some(Constant.UserNum(System.Numerics.BigInteger.Parse(x), endChar.[0])) - | SynConst.Unit -> Some(Constant.Unit) - | SynConst.UInt16s(_) + | SynConst.Bool value -> Some(Constant.Bool value) + | SynConst.Int16 value -> Some(Constant.Int16 value) + | SynConst.Int32 value -> Some(Constant.Int32 value) + | SynConst.Int64 value -> Some(Constant.Int64 value) + | SynConst.UInt16 value -> Some(Constant.UInt16 value) + | SynConst.UInt32 value -> Some(Constant.UInt32 value) + | SynConst.UInt64 value -> Some(Constant.UInt64 value) + | SynConst.Byte value -> Some(Constant.Byte value) + | SynConst.Bytes (value, _, _) -> Some(Constant.Bytes value) + | SynConst.Char value -> Some(Constant.Char value) + | SynConst.Decimal value -> Some(Constant.Decimal value) + | SynConst.Double value -> Some(Constant.Double value) + | SynConst.SByte value -> Some(Constant.SByte value) + | SynConst.Single value -> Some(Constant.Single value) + | SynConst.String (value, _, _) -> Some(Constant.String value) + | SynConst.UIntPtr value -> Some(Constant.UIntPtr(unativeint value)) + | SynConst.IntPtr value -> Some(Constant.IntPtr(nativeint value)) + | SynConst.UserNum (value, endChar) -> + Some(Constant.UserNum(System.Numerics.BigInteger.Parse(value), endChar.[0])) + | SynConst.Unit -> Some Constant.Unit + | SynConst.UInt16s _ | SynConst.SourceIdentifier _ - | SynConst.Measure(_) -> None + | SynConst.Measure _ -> None module private Precedence = let private ofHint hint = @@ -155,8 +155,8 @@ module private MatchExpression = /// Extracts an expression from parentheses e.g. ((x + 4)) -> x + 4 let rec private removeParens = function - | AstNode.Expression(SynExpr.Paren(x, _, _, _)) -> x |> AstNode.Expression |> removeParens - | x -> x + | AstNode.Expression(SynExpr.Paren(expr, _, _, _)) -> expr |> AstNode.Expression |> removeParens + | node -> node [] type Arguments = @@ -176,7 +176,7 @@ module private MatchExpression = let ident = identAsDecompiledOpName ident Some(Expression.Identifier([ident])) | AstNode.Expression(SynExpr.LongIdent(_, ident, _, _)) -> - let identifier = ident.LongIdent |> List.map (fun x -> x.idText) + let identifier = ident.LongIdent |> List.map (fun ident -> ident.idText) Some(Expression.Identifier(identifier)) | AstNode.Expression(SynExpr.Const(constant, _)) -> matchConst constant |> Option.map Expression.Constant @@ -228,7 +228,7 @@ module private MatchExpression = match symbolUse.Symbol with | :? FSharpParameter | :? FSharpField -> false - | :? FSharpMemberOrFunctionOrValue as x -> not x.IsProperty + | :? FSharpMemberOrFunctionOrValue as element -> not element.IsProperty | _ -> true | None -> true checkSymbol @@ -298,7 +298,7 @@ module private MatchExpression = and private doExpressionsMatch expressions hintExpressions (arguments:Arguments) = if List.length expressions = List.length hintExpressions then (expressions, hintExpressions) - ||> List.map2 (fun x y -> arguments.SubHint(x, y) |> matchHintExpr) + ||> List.map2 (fun expr hint -> arguments.SubHint(expr, hint) |> matchHintExpr) |> List.fold (&&~) (Match(List.Empty)) else NoMatch @@ -387,7 +387,7 @@ module private MatchPattern = let private matchPattern = function | SynPat.LongIdent(ident, _, _, _, _, _) -> - let identifier = ident.LongIdent |> List.map (fun x -> x.idText) + let identifier = ident.LongIdent |> List.map (fun ident -> ident.idText) Some(Pattern.Identifier(identifier)) | SynPat.Const(constant, _) -> matchConst constant |> Option.map Pattern.Constant @@ -397,8 +397,8 @@ module private MatchPattern = /// Extracts a pattern from parentheses e.g. ((x)) -> x let rec private removeParens = function - | SynPat.Paren(x, _) -> removeParens x - | x -> x + | SynPat.Paren(pattern, _) -> removeParens pattern + | pat -> pat let rec matchHintPattern (pattern, hint) = let pattern = removeParens pattern @@ -426,7 +426,7 @@ module private MatchPattern = and private doPatternsMatch patterns hintExpressions = (List.length patterns = List.length hintExpressions) - && (patterns, hintExpressions) ||> List.forall2 (fun x y -> matchHintPattern (x, y)) + && (patterns, hintExpressions) ||> List.forall2 (fun pattern hint -> matchHintPattern (pattern, hint)) and private matchList (pattern, hint) = match (pattern, hint) with @@ -460,24 +460,24 @@ module private MatchPattern = module private FormatHint = let private constantToString = function - | Constant.Bool(x) -> if x then "true" else "false" - | Constant.Int16(x) -> $"{x}s" - | Constant.Int32(x) -> $"{x}" - | Constant.Int64(x) -> $"{x}L" - | Constant.UInt16(x) -> $"{x}us" - | Constant.UInt32(x) -> $"{x}u" - | Constant.UInt64(x) -> $"{x}UL" - | Constant.Byte(x) -> $"{x}uy" - | Constant.Bytes(x) -> $"{x}" - | Constant.Char(x) -> $"'{x}'" - | Constant.Decimal(x) -> $"{x}m" - | Constant.Double(x) -> $"{x}" - | Constant.SByte(x) -> $"{x}y" - | Constant.Single(x) -> $"{x}f" - | Constant.String(x) -> $"\"{x}\"" - | Constant.UIntPtr(x) -> $"{x}" - | Constant.IntPtr(x) -> $"{x}" - | Constant.UserNum(x, _) -> $"{x}" + | Constant.Bool(value) -> if value then "true" else "false" + | Constant.Int16(value) -> $"{value}s" + | Constant.Int32(value) -> $"{value}" + | Constant.Int64(value) -> $"{value}L" + | Constant.UInt16(value) -> $"{value}us" + | Constant.UInt32(value) -> $"{value}u" + | Constant.UInt64(value) -> $"{value}UL" + | Constant.Byte(value) -> $"{value}uy" + | Constant.Bytes(value) -> $"{value}" + | Constant.Char(value) -> $"'{value}'" + | Constant.Decimal(value) -> $"{value}m" + | Constant.Double(value) -> $"{value}" + | Constant.SByte(value) -> $"{value}y" + | Constant.Single(value) -> $"{value}f" + | Constant.String(value) -> $"\"{value}\"" + | Constant.UIntPtr(value) -> $"{value}" + | Constant.IntPtr(value) -> $"{value}" + | Constant.UserNum(value, _) -> $"{value}" | Constant.Unit -> "()" let private surroundExpressionsString hintToString left right sep expressions = @@ -490,8 +490,8 @@ module private FormatHint = let private opToString = function | Expression.Identifier(identifier) -> String.concat "." identifier - | x -> - Debug.Assert(false, $"Expected operator to be an expression identifier, but was {x.ToString()}") + | expression -> + Debug.Assert(false, $"Expected operator to be an expression identifier, but was {expression.ToString()}") String.Empty let rec toString replace parentAstNode (args:AstNodeRuleParams) (matchedVariables:Dictionary<_, SynExpr>) parentHintNode hintNode = @@ -596,7 +596,7 @@ let private getMethodParameters (checkFile:FSharpCheckFileResults) (methodIdent: methodIdent.Range.StartLine, methodIdent.Range.EndColumn, String.Empty, - methodIdent.LongIdent |> List.map (fun x -> x.idText)) + methodIdent.LongIdent |> List.map (fun ident -> ident.idText)) match symbol with | Some(symbol) when (symbol.Symbol :? FSharpMemberOrFunctionOrValue) -> @@ -623,7 +623,7 @@ let private (|RequiresCheck|CanBeReplaced|CannotBeReplaced|) (breadcrumbs, range match filterParens breadcrumbs with | AstNode.Expression(SynExpr.Tuple(_, exprs, _, _))::AstNode.Expression(SynExpr.App(ExprAtomicFlag.Atomic, _, SynExpr.DotGet(_, _, methodIdent, _), _, _))::_ | AstNode.Expression(SynExpr.Tuple(_, exprs, _, _))::AstNode.Expression(SynExpr.App(ExprAtomicFlag.Atomic, _, SynExpr.LongIdent(_, methodIdent, _, _), _, _))::_ -> - match exprs |> List.tryFindIndex (fun x -> x.Range = range) with + match exprs |> List.tryFindIndex (fun expr -> expr.Range = range) with | Some(index) -> RequiresCheck(index, methodIdent) | None -> CannotBeReplaced | AstNode.Expression(SynExpr.App(ExprAtomicFlag.Atomic, _, SynExpr.DotGet(_, _, methodIdent, _), _, _))::_ diff --git a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs index ecb7d0a02..11b2d82b6 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs @@ -21,17 +21,17 @@ open MergeSyntaxTrees /// Confirms if two parts of the ast look alike. /// This is required as hints can bind variables: the bound location needs to be compared to /// parts of the ast that the hint covers with the same variable. -let private isMatch i j (nodeArray:AbstractSyntaxArray.Node []) = - let numChildrenI = nodeArray.[i].NumberOfChildren - let numChildrenJ = nodeArray.[j].NumberOfChildren +let private isMatch iIndex jIndex (nodeArray:AbstractSyntaxArray.Node []) = + let numChildrenI = nodeArray.[iIndex].NumberOfChildren + let numChildrenJ = nodeArray.[jIndex].NumberOfChildren if numChildrenI = numChildrenJ then let numChildren = numChildrenI { 0..numChildren } |> Seq.forall (fun child -> - i + child < nodeArray.Length && - j + child < nodeArray.Length && - nodeArray.[i + child].Hashcode = nodeArray.[j + child].Hashcode) + iIndex + child < nodeArray.Length && + jIndex + child < nodeArray.Length && + nodeArray.[iIndex + child].Hashcode = nodeArray.[jIndex + child].Hashcode) else false let inline private isParen (node:AbstractSyntaxArray.Node) = @@ -40,31 +40,31 @@ let inline private isParen (node:AbstractSyntaxArray.Node) = | _ -> false /// Compares the hint trie against a given location in the abstract syntax array. -let rec checkTrie i trie (nodeArray:AbstractSyntaxArray.Node []) (boundVariables:Dictionary<_, _>) notify = +let rec checkTrie index trie (nodeArray:AbstractSyntaxArray.Node []) (boundVariables:Dictionary<_, _>) notify = trie.MatchedHint |> List.iter notify - if i < nodeArray.Length then - let node = nodeArray.[i] + if index < nodeArray.Length then + let node = nodeArray.[index] if isParen node then // Skip the paren. - checkTrie (i + 1) trie nodeArray boundVariables notify + checkTrie (index + 1) trie nodeArray boundVariables notify else match trie.Edges.Lookup.TryGetValue node.Hashcode with - | true, trie -> checkTrie (i + 1) trie nodeArray boundVariables notify + | true, trie -> checkTrie (index + 1) trie nodeArray boundVariables notify | false, _ -> () let collect var trie = match var with | Some(var) -> match boundVariables.TryGetValue var with - | true, varI when isMatch varI i nodeArray -> - checkTrie (i + node.NumberOfChildren + 1) trie nodeArray boundVariables notify + | true, varI when isMatch varI index nodeArray -> + checkTrie (index + node.NumberOfChildren + 1) trie nodeArray boundVariables notify | false, _ -> - boundVariables.Add(var, i) - checkTrie (i + node.NumberOfChildren + 1) trie nodeArray boundVariables notify + boundVariables.Add(var, index) + checkTrie (index + node.NumberOfChildren + 1) trie nodeArray boundVariables notify | true, _ -> () - | None -> checkTrie (i + node.NumberOfChildren + 1) trie nodeArray boundVariables notify + | None -> checkTrie (index + node.NumberOfChildren + 1) trie nodeArray boundVariables notify trie.Edges.AnyMatch |> List.iter (fun (var, trie) -> collect var trie) diff --git a/tests/FSharpLint.Benchmarks/Benchmark.fs b/tests/FSharpLint.Benchmarks/Benchmark.fs index 910967a3f..4bec7ca83 100644 --- a/tests/FSharpLint.Benchmarks/Benchmark.fs +++ b/tests/FSharpLint.Benchmarks/Benchmark.fs @@ -23,7 +23,7 @@ type Benchmark () = parseResults.ParseTree - let () x y = Path.Combine(x, y) + let () basePath relativePath = Path.Combine(basePath, relativePath) let basePath = ".." ".." ".." ".." ".." ".." ".." ".." let sourceFile = basePath "TypeChecker.fs" diff --git a/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs b/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs index 2978746cc..8b59e9c44 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs @@ -12,20 +12,20 @@ open FSharpLint.Framework.ExpressionUtilities [] type TestAst() = - let unionCaseName (x:'T) = - match FSharpValue.GetUnionFields(x, typeof<'T>) with + let unionCaseName (unionCase: 'UnionType) = + match FSharpValue.GetUnionFields(unionCase, typeof<'UnionType>) with | case, _ -> case.Name let astToExpr ast = - let (|Module|_|) x = - match x with + let (|Module|_|) moduleOrNamespace = + match moduleOrNamespace with | SynModuleOrNamespace(_, _, _, SynModuleDecl.Expr(app, _)::_, _, _, _, _, _) -> Some(app) | _ -> None match ast with - | ParsedInput.ImplFile(x) -> - match x with + | ParsedInput.ImplFile(implFile) -> + match implFile with | ParsedImplFileInput(_, _, _, _, _, Module(app)::_, _, _, _) -> app | _ -> failwith "Expected at least one module or namespace." @@ -112,7 +112,7 @@ type TestAst() = let array = astToArray tree - let actual = array |> Array.map (fun x -> x.Hashcode) |> Array.toList + let actual = array |> Array.map (fun node -> node.Hashcode) |> Array.toList let expected = [ Utilities.hash2 SyntaxNode.ModuleOrNamespace 0 @@ -132,8 +132,8 @@ type TestAst() = Utilities.hash2 SyntaxNode.Identifier "woofs" ] Assert.AreEqual(expected, actual) - - let expected = array |> Array.map (fun x -> (x.NumberOfChildren, x.ParentIndex)) |> Array.toList + + let expected = array |> Array.map (fun node -> (node.NumberOfChildren, node.ParentIndex)) |> Array.toList Assert.AreEqual([ (14, 0) (13, 0) (12, 1) @@ -158,7 +158,7 @@ type TestAst() = let array = astToArray tree - let actual = array |> Array.map (fun x -> x.Hashcode) |> List.ofArray + let actual = array |> Array.map (fun node -> node.Hashcode) |> List.ofArray let expected = [ Utilities.hash2 SyntaxNode.ModuleOrNamespace 0 @@ -171,7 +171,7 @@ type TestAst() = Assert.AreEqual(expected, actual) - let expected = array |> Array.map (fun x -> (x.NumberOfChildren, x.ParentIndex)) |> List.ofArray + let expected = array |> Array.map (fun node -> (node.NumberOfChildren, node.ParentIndex)) |> List.ofArray Assert.AreEqual([ (6, 0) (5, 0) (4, 1) diff --git a/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs b/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs index 271a7a1a1..65e97a43e 100644 --- a/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs +++ b/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs @@ -14,9 +14,9 @@ let private MaxComplexity = 5 let private NewLine = "\n" /// Indent all lines of a string equally by the given number of spaces. -let private indent numSpaces (s: string) = +let private indent numSpaces (inputText: string) = let indentStr = String.replicate numSpaces " " - let result = indentStr + s.Replace(NewLine, $"{NewLine}{indentStr}") + let result = indentStr + inputText.Replace(NewLine, $"{NewLine}{indentStr}") result /// Generates a body of code containing a match expression. @@ -28,7 +28,7 @@ let private makeMatchSnippet len = /// Generates a body of code containing a match expression with a when clause containing a logical operator in each pattern. let private makeMatchSnippetWithLogicalOperatorsInWhenClause len = - let patterns = Seq.map (fun i -> $"| x when x = \"%d{i*len}\" || x = \"%d{i*len+1}\" -> ()") [| 1..len-1 |] |> String.concat NewLine + let patterns = Seq.map (fun index -> $"| x when x = \"%d{index*len}\" || x = \"%d{index*len+1}\" -> ()") [| 1..len-1 |] |> String.concat NewLine $"""match "dummyString" with {patterns} | _ -> ()""" @@ -93,8 +93,8 @@ let private matchExpressionWithCombinedPatterns len = /// Generates a body of code containing a match function with multiple patterns. let private matchFunction len = - $""" function -{(Seq.map (sprintf " | \"%d\"") [| 1..len-1 |] |> String.concat NewLine)} + $""" function +{(Seq.map (fun index -> (sprintf " | \"%d\"" index)) [| 1..len-1 |] |> String.concat NewLine)} | _ -> () f "dummyString" """ |> makeProgram "f" @@ -247,7 +247,7 @@ let f() = [] member this.EnsureRedundantWarningsNotReported() = // generates a vapid match clause - let genMatchClause i = $"""| "{i}" -> match str with + let genMatchClause index = $"""| "{index}" -> match str with | "A" -> () | "B" -> ()""" // create a snippet of code with 10 match clauses diff --git a/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs index 169886a5e..d8178b3b7 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs @@ -26,24 +26,24 @@ type TestRuleBase () = member _.ErrorRanges = suggestions - |> Seq.map (fun s -> (s.Details.Range.StartLine, s.Details.Range.StartColumn)) + |> Seq.map (fun linterSuggestion -> (linterSuggestion.Details.Range.StartLine, linterSuggestion.Details.Range.StartColumn)) |> List.ofSeq member _.ErrorExistsAt(startLine, startColumn) = suggestions - |> Seq.exists (fun s -> s.Details.Range.StartLine = startLine && s.Details.Range.StartColumn = startColumn) + |> Seq.exists (fun linterSuggestion -> linterSuggestion.Details.Range.StartLine = startLine && linterSuggestion.Details.Range.StartColumn = startColumn) member _.ErrorsAt(startLine, startColumn) = suggestions - |> Seq.filter (fun s -> s.Details.Range.StartLine = startLine && s.Details.Range.StartColumn = startColumn) + |> Seq.filter (fun linterSuggestion -> linterSuggestion.Details.Range.StartLine = startLine && linterSuggestion.Details.Range.StartColumn = startColumn) member _.ErrorExistsOnLine(startLine) = suggestions - |> Seq.exists (fun s -> s.Details.Range.StartLine = startLine) + |> Seq.exists (fun linterSuggestion -> linterSuggestion.Details.Range.StartLine = startLine) member _.NoErrorExistsOnLine(startLine) = suggestions - |> Seq.exists (fun s -> s.Details.Range.StartLine = startLine) + |> Seq.exists (fun linterSuggestion -> linterSuggestion.Details.Range.StartLine = startLine) |> not // prevent tests from passing if errors exist, just not on the line being checked @@ -58,15 +58,16 @@ type TestRuleBase () = | xs when xs.Count = 0 -> "No errors" | _ -> suggestions - |> Seq.map (fun s -> $"(({s.Details.Range.StartRange.StartLine}, {s.Details.Range.StartColumn}) - ({s.Details.Range.EndRange.EndLine}, {s.Details.Range.EndRange.EndColumn}) -> {s.Details.Message})") - |> (fun x -> String.Join("; ", x)) + |> Seq.map (fun linterSuggestion -> + $"(({linterSuggestion.Details.Range.StartRange.StartLine}, {linterSuggestion.Details.Range.StartColumn}) - ({linterSuggestion.Details.Range.EndRange.EndLine}, {linterSuggestion.Details.Range.EndRange.EndColumn}) -> {linterSuggestion.Details.Message})") + |> (fun suggestionMsg -> String.Join("; ", suggestionMsg)) member this.ErrorWithMessageExistsAt(message, startLine, startColumn) = this.ErrorsAt(startLine, startColumn) - |> Seq.exists (fun s -> s.Details.Message = message) + |> Seq.exists (fun linterSuggestion -> linterSuggestion.Details.Message = message) member _.AssertErrorWithMessageExists(message) = - let foundSuggestions = suggestions |> Seq.map (fun s -> s.Details.Message) + let foundSuggestions = suggestions |> Seq.map (fun linterSuggestion -> linterSuggestion.Details.Message) let foundSuggestionsStr = String.concat "," foundSuggestions Assert.IsTrue(foundSuggestions |> Seq.contains message, $"Couldn't find message '{message}', found: [{foundSuggestionsStr}]") @@ -76,10 +77,10 @@ type TestRuleBase () = member this.ApplyQuickFix (source:string) = let firstSuggestedFix = suggestions - |> Seq.choose (fun x -> x.Details.SuggestedFix) + |> Seq.choose (fun linterSuggestion -> linterSuggestion.Details.SuggestedFix) |> Seq.tryHead - match firstSuggestedFix |> Option.bind (fun x -> x.Value) with + match firstSuggestedFix |> Option.bind (fun suggestedFix -> suggestedFix.Value) with | Some(fix) -> let startIndex = ExpressionUtilities.findPos fix.FromRange.Start source let endIndex = ExpressionUtilities.findPos fix.FromRange.End source diff --git a/tests/FSharpLint.FunctionalTest/TestApi.fs b/tests/FSharpLint.FunctionalTest/TestApi.fs index 3be1a5de4..d72f87d1e 100644 --- a/tests/FSharpLint.FunctionalTest/TestApi.fs +++ b/tests/FSharpLint.FunctionalTest/TestApi.fs @@ -9,7 +9,7 @@ module TestApi = open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Text - let () x y = Path.Combine(x, y) + let () basePath relativePath = Path.Combine(basePath, relativePath) let basePath = TestContext.CurrentContext.TestDirectory ".." ".." ".." ".." ".." From 18852db96fc2323fdab3f6a06cb4c1a59b76d7c8 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Mon, 18 Dec 2023 15:07:22 +0330 Subject: [PATCH 26/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index ff6dfa377..2e94f018d 100644 --- a/build.fsx +++ b/build.fsx @@ -288,6 +288,7 @@ Target.create "SelfCheck" (fun _ -> "favourStaticEmptyFields" "favourConsistentThis" "avoidTooShortNames" + "asyncExceptionWithoutReturn" ] let jsonObj = JObject.Parse fsharplintJsonText From 681c3013cb3f22763a3d65a7e2528df6e54dafd4 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Fri, 22 Dec 2023 14:15:28 +0330 Subject: [PATCH 27/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 2e94f018d..5eb29715d 100644 --- a/build.fsx +++ b/build.fsx @@ -289,6 +289,7 @@ Target.create "SelfCheck" (fun _ -> "favourConsistentThis" "avoidTooShortNames" "asyncExceptionWithoutReturn" + "maxNumberOfItemsInTuple" ] let jsonObj = JObject.Parse fsharplintJsonText From 041cd261629c4f8161baf2c17b7d1253714a94c1 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Fri, 22 Dec 2023 14:15:48 +0330 Subject: [PATCH 28/48] build: run FSharpLint with 1 extra rule --- build.fsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.fsx b/build.fsx index 5eb29715d..7170cbc73 100644 --- a/build.fsx +++ b/build.fsx @@ -289,7 +289,8 @@ Target.create "SelfCheck" (fun _ -> "favourConsistentThis" "avoidTooShortNames" "asyncExceptionWithoutReturn" - "maxNumberOfItemsInTuple" + "maxNumberOfItemsInTuple" + "maxNumberOfFunctionParameters" ] let jsonObj = JObject.Parse fsharplintJsonText From a8d48cecf69f068c6d7c500b2742ea0ad759598e Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Fri, 22 Dec 2023 15:08:48 +0330 Subject: [PATCH 29/48] Core,Tests: fix FSharpLint warning Fixing the warning for maxNumberOfFunctionParameters rule. --- src/FSharpLint.Core/Application/Lint.fs | 90 ++++++++++---- src/FSharpLint.Core/Application/Lint.fsi | 25 +++- .../Rules/Formatting/TypePrefixing.fs | 79 ++++++++---- .../Rules/Hints/HintMatcher.fs | 114 ++++++++++++++---- .../Rules/TestAstNodeRule.fs | 15 ++- .../Rules/TestHintMatcherBase.fs | 13 +- .../Rules/TestIndentationRule.fs | 27 +++-- .../Rules/TestLineRule.fs | 22 +++- .../Rules/TestNoTabCharactersRule.fs | 26 +++- 9 files changed, 320 insertions(+), 91 deletions(-) diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index e532108fe..fcdf95fb0 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -119,35 +119,46 @@ module Lint = { IndentationRuleContext:Map NoTabCharactersRuleContext:(string * Range) list } - let runAstNodeRules (rules:RuleMetadata []) (globalConfig:Rules.GlobalRuleConfig) typeCheckResults (filePath:string) (fileContent:string) (lines:string []) syntaxArray = + type RunAstNodeRulesConfig = + { + Rules: RuleMetadata[] + GlobalConfig: Rules.GlobalRuleConfig + TypeCheckResults: FSharpCheckFileResults option + FilePath: string + FileContent: string + Lines: string[] + SyntaxArray: AbstractSyntaxArray.Node array + } + + let runAstNodeRules (config: RunAstNodeRulesConfig) = let mutable indentationRuleState = Map.empty let mutable noTabCharactersRuleState = List.empty let collect index (astNode: AbstractSyntaxArray.Node) = - let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth syntaxArray index + let getParents (depth:int) = AbstractSyntaxArray.getBreadcrumbs depth config.SyntaxArray index let astNodeParams = { AstNode = astNode.Actual NodeHashcode = astNode.Hashcode NodeIndex = index - SyntaxArray = syntaxArray + SyntaxArray = config.SyntaxArray GetParents = getParents - FilePath = filePath - FileContent = fileContent - Lines = lines - CheckInfo = typeCheckResults - GlobalConfig = globalConfig + FilePath = config.FilePath + FileContent = config.FileContent + Lines = config.Lines + CheckInfo = config.TypeCheckResults + GlobalConfig = config.GlobalConfig } // Build state for rules with context. indentationRuleState <- Indentation.ContextBuilder.builder indentationRuleState astNode.Actual noTabCharactersRuleState <- NoTabCharacters.ContextBuilder.builder noTabCharactersRuleState astNode.Actual - rules + config.Rules |> Array.collect (fun rule -> runAstNodeRule rule astNodeParams) // Collect suggestions for AstNode rules, and build context for following rules. let astNodeSuggestions = - syntaxArray + config.SyntaxArray |> Array.mapi (fun index astNode -> (index, astNode)) |> Array.collect (fun (index, astNode) -> collect index astNode) @@ -155,32 +166,41 @@ module Lint = { IndentationRuleContext = indentationRuleState NoTabCharactersRuleContext = noTabCharactersRuleState } - rules |> Array.iter (fun rule -> rule.RuleConfig.Cleanup()) + config.Rules |> Array.iter (fun rule -> rule.RuleConfig.Cleanup()) (astNodeSuggestions, context) - let runLineRules (lineRules:Configuration.LineRules) (globalConfig:Rules.GlobalRuleConfig) (filePath:string) (fileContent:string) (lines:string []) (context:Context) = + type RunLineRulesConfig = + { + LineRules: Configuration.LineRules + GlobalConfig: Rules.GlobalRuleConfig + FilePath: string + FileContent: string + Lines: string[] + Context: Context + } + let runLineRules (config: RunLineRulesConfig) = let collectErrors (line: string) (lineNumber: int) (isLastLine: bool) = let lineParams = - { + { LineRuleParams.Line = line LineNumber = lineNumber + 1 IsLastLine = isLastLine - FilePath = filePath - FileContent = fileContent - Lines = lines - GlobalConfig = globalConfig + FilePath = config.FilePath + FileContent = config.FileContent + Lines = config.Lines + GlobalConfig = config.GlobalConfig } let indentationError = - lineRules.IndentationRule - |> Option.map (fun rule -> runLineRuleWithContext rule context.IndentationRuleContext lineParams) + config.LineRules.IndentationRule + |> Option.map (fun rule -> runLineRuleWithContext rule config.Context.IndentationRuleContext lineParams) let noTabCharactersError = - lineRules.NoTabCharactersRule - |> Option.map (fun rule -> runLineRuleWithContext rule context.NoTabCharactersRuleContext lineParams) + config.LineRules.NoTabCharactersRule + |> Option.map (fun rule -> runLineRuleWithContext rule config.Context.NoTabCharactersRuleContext lineParams) let lineErrors = - lineRules.GenericLineRules + config.LineRules.GenericLineRules |> Array.collect (fun rule -> runLineRule rule lineParams) [| @@ -189,7 +209,7 @@ module Lint = lineErrors |> Array.singleton |] - fileContent + config.FileContent |> String.toLines |> Array.collect (fun (line, lineNumber, isLastLine) -> collectErrors line lineNumber isLastLine) |> Array.concat @@ -232,8 +252,28 @@ module Lint = let syntaxArray = AbstractSyntaxArray.astToArray fileInfo.Ast // Collect suggestions for AstNode rules - let (astNodeSuggestions, context) = runAstNodeRules enabledRules.AstNodeRules enabledRules.GlobalConfig fileInfo.TypeCheckResults fileInfo.File fileInfo.Text lines syntaxArray - let lineSuggestions = runLineRules enabledRules.LineRules enabledRules.GlobalConfig fileInfo.File fileInfo.Text lines context + let (astNodeSuggestions, context) = + runAstNodeRules + { + Rules = enabledRules.AstNodeRules + GlobalConfig = enabledRules.GlobalConfig + TypeCheckResults = fileInfo.TypeCheckResults + FilePath = fileInfo.File + FileContent = fileInfo.Text + Lines = lines + SyntaxArray = syntaxArray + } + + let lineSuggestions = + runLineRules + { + LineRules = enabledRules.LineRules + GlobalConfig = enabledRules.GlobalConfig + FilePath = fileInfo.File + FileContent = fileInfo.Text + Lines = lines + Context = context + } [| lineSuggestions; astNodeSuggestions |] |> Array.concat diff --git a/src/FSharpLint.Core/Application/Lint.fsi b/src/FSharpLint.Core/Application/Lint.fsi index 7d1f1ff95..7e697df5a 100644 --- a/src/FSharpLint.Core/Application/Lint.fsi +++ b/src/FSharpLint.Core/Application/Lint.fsi @@ -119,11 +119,32 @@ module Lint = member TryGetSuccess : byref -> bool member TryGetFailure : byref -> bool + type RunAstNodeRulesConfig = + { + Rules: RuleMetadata[] + GlobalConfig: Rules.GlobalRuleConfig + TypeCheckResults: FSharpCheckFileResults option + FilePath: string + FileContent: string + Lines: string[] + SyntaxArray: AbstractSyntaxArray.Node array + } + /// Runs all rules which take a node of the AST as input. - val runAstNodeRules : RuleMetadata [] -> Rules.GlobalRuleConfig -> FSharpCheckFileResults option -> string -> string -> string [] -> AbstractSyntaxArray.Node [] -> Suggestion.LintWarning [] * Context + val runAstNodeRules : RunAstNodeRulesConfig -> Suggestion.LintWarning [] * Context + + type RunLineRulesConfig = + { + LineRules: Configuration.LineRules + GlobalConfig: Rules.GlobalRuleConfig + FilePath: string + FileContent: string + Lines: string[] + Context: Context + } /// Runs all rules which take a line of text as input. - val runLineRules : LineRules -> Rules.GlobalRuleConfig -> string -> string -> string [] -> Context -> Suggestion.LintWarning [] + val runLineRules : RunLineRulesConfig -> Suggestion.LintWarning [] /// Lints an entire F# solution by linting all projects specified in the `.sln`, `slnx` or `.slnf` file. val lintSolution : optionalParams:OptionalLintParameters -> solutionFilePath:string -> toolsPath:Ionide.ProjInfo.Types.ToolsPath -> LintResult diff --git a/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs b/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs index 02319facd..0a9145df5 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs @@ -16,18 +16,31 @@ type Mode = [] type Config = { Mode: Mode } -let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName typeArgs isPostfix = +type CheckTypePrefixingConfig = + { + Config: Config + Args: AstNodeRuleParams + Range: FSharp.Compiler.Text.Range + TypeName: SynType + TypeArgs: string option + IsPostfix: bool + } + +let checkTypePrefixing (typePrefixingConfig: CheckTypePrefixingConfig) = let recommendPostfixErrMsg = lazy(Resources.GetString("RulesFormattingF#PostfixGenericError")) - match typeName with + match typePrefixingConfig.TypeName with | SynType.LongIdent lid -> let prefixSuggestion typeName = let suggestedFix = lazy( - (ExpressionUtilities.tryFindTextOfRange range args.FileContent, typeArgs) - ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = range; ToText = $"{typeName}<{typeArgs}>" })) - { Range = range - Message = Resources.GetString("RulesFormattingGenericPrefixError") - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } |> Some + (ExpressionUtilities.tryFindTextOfRange typePrefixingConfig.Range typePrefixingConfig.Args.FileContent, typePrefixingConfig.TypeArgs) + ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = typePrefixingConfig.Range; ToText = $"{typeName}<{typeArgs}>" })) + { + Range = typePrefixingConfig.Range + Message = Resources.GetString("RulesFormattingGenericPrefixError") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } + |> Some match lid |> longIdentWithDotsToString with | "list" @@ -38,39 +51,45 @@ let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName t | "Ref" as typeName -> // Prefer postfix. - if not isPostfix && config.Mode <> Mode.Always + if not typePrefixingConfig.IsPostfix && typePrefixingConfig.Config.Mode <> Mode.Always then let suggestedFix = lazy( - (ExpressionUtilities.tryFindTextOfRange range args.FileContent, typeArgs) - ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = range; ToText = $"{typeArgs} {typeName}" })) - { Range = range - Message = String.Format(recommendPostfixErrMsg.Value, typeName) - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } |> Some + (ExpressionUtilities.tryFindTextOfRange typePrefixingConfig.Range typePrefixingConfig.Args.FileContent, typePrefixingConfig.TypeArgs) + ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = typePrefixingConfig.Range; ToText = $"{typeArgs} {typeName}" })) + { + Range = typePrefixingConfig.Range + Message = String.Format(recommendPostfixErrMsg.Value, typeName) + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } + |> Some else - if isPostfix && config.Mode = Mode.Always then + if typePrefixingConfig.IsPostfix && typePrefixingConfig.Config.Mode = Mode.Always then prefixSuggestion typeName else None - | "array" when config.Mode <> Mode.Always -> + | "array" when typePrefixingConfig.Config.Mode <> Mode.Always -> // Prefer special postfix (e.g. int []). let suggestedFix = lazy( - (ExpressionUtilities.tryFindTextOfRange range args.FileContent, typeArgs) - ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = range; ToText = $"{typeArgs} []" })) - { Range = range - Message = Resources.GetString("RulesFormattingF#ArrayPostfixError") - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } |> Some + (ExpressionUtilities.tryFindTextOfRange typePrefixingConfig.Range typePrefixingConfig.Args.FileContent, typePrefixingConfig.TypeArgs) + ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = typePrefixingConfig.Range; ToText = $"{typeArgs} []" })) + { + Range = typePrefixingConfig.Range + Message = Resources.GetString("RulesFormattingF#ArrayPostfixError") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } + |> Some | typeName -> - match (isPostfix, config.Mode) with + match (typePrefixingConfig.IsPostfix, typePrefixingConfig.Config.Mode) with | true, Mode.Never -> None | true, _ -> prefixSuggestion typeName | false, Mode.Never -> - { Range = range + { Range = typePrefixingConfig.Range Message = String.Format(recommendPostfixErrMsg.Value, typeName) // TODO SuggestedFix = None @@ -84,7 +103,15 @@ let runner (config:Config) args = match args.AstNode with | AstNode.Type (SynType.App (typeName, _, typeArgs, _, _, isPostfix, range)) -> let typeArgs = typeArgsToString args.FileContent typeArgs - checkTypePrefixing config args range typeName typeArgs isPostfix + checkTypePrefixing + { + Config = config + Args = args + Range = range + TypeName = typeName + TypeArgs = typeArgs + IsPostfix = isPostfix + } |> Option.toArray | AstNode.Type (SynType.Array (1, _elementType, range)) when config.Mode = Mode.Always -> { Range = range diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index c38eb03e1..8403f6331 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -14,6 +14,16 @@ open FSharpLint.Framework.ExpressionUtilities open FSharpLint.Framework.HintParser open FSharpLint.Framework.Rules +type ToStringConfig = + { + Replace: bool + ParentAstNode: AstNode option + Args: AstNodeRuleParams + MatchedVariables: Dictionary + ParentHintNode: option + HintNode: HintNode + } + type Config = { HintTrie:MergeSyntaxTrees.Edges } @@ -494,15 +504,24 @@ module private FormatHint = Debug.Assert(false, $"Expected operator to be an expression identifier, but was {expression.ToString()}") String.Empty - let rec toString replace parentAstNode (args:AstNodeRuleParams) (matchedVariables:Dictionary<_, SynExpr>) parentHintNode hintNode = - let toString = toString replace parentAstNode args matchedVariables (Some hintNode) + let rec toString (config: ToStringConfig) = + let toString hintNode = + toString + { + Replace = config.Replace + ParentAstNode = config.ParentAstNode + Args = config.Args + MatchedVariables = config.MatchedVariables + ParentHintNode = (Some config.HintNode) + HintNode = hintNode + } let str = - match hintNode with - | HintExpr(Expression.Variable(varChar)) when replace -> - match matchedVariables.TryGetValue varChar with + match config.HintNode with + | HintExpr(Expression.Variable(varChar)) when config.Replace -> + match config.MatchedVariables.TryGetValue varChar with | true, expr -> - match ExpressionUtilities.tryFindTextOfRange expr.Range args.FileContent with + match ExpressionUtilities.tryFindTextOfRange expr.Range config.Args.FileContent with | Some(replacement) -> replacement | _ -> varChar.ToString() | _ -> varChar.ToString() @@ -537,7 +556,7 @@ module private FormatHint = | HintExpr(Expression.Parentheses(hint)) -> $"({toString (HintExpr hint)})" | HintPat(Pattern.Parentheses(hint)) -> $"({toString (HintPat hint)})" | HintExpr(Expression.Lambda(arguments, LambdaBody(body))) -> - $"fun {lambdaArgumentsToString replace parentAstNode args matchedVariables arguments} -> {toString (HintExpr body)}" + $"fun {lambdaArgumentsToString config.Replace config.ParentAstNode config.Args config.MatchedVariables arguments} -> {toString (HintExpr body)}" | HintExpr(Expression.LambdaArg(argument)) -> toString (HintExpr argument) | HintExpr(Expression.LambdaBody(body)) -> @@ -562,33 +581,70 @@ module private FormatHint = $"else {toString (HintExpr expr)}" | HintExpr(Expression.Null) | HintPat(Pattern.Null) -> "null" - if replace && Precedence.requiresParenthesis matchedVariables hintNode parentAstNode parentHintNode then $"({str})" + if config.Replace && Precedence.requiresParenthesis config.MatchedVariables config.HintNode config.ParentAstNode config.ParentHintNode then $"({str})" else str and private lambdaArgumentsToString replace parentAstNode args matchedVariables (arguments:LambdaArg list) = + let exprToString expr = + toString + { + Replace = replace + ParentAstNode = parentAstNode + Args = args + MatchedVariables = matchedVariables + ParentHintNode = None + HintNode = (HintExpr expr) + } arguments - |> List.map (fun (LambdaArg expr) -> toString replace parentAstNode args matchedVariables None (HintExpr expr)) + |> List.map (fun (LambdaArg expr) -> exprToString expr) |> String.concat " " -let private hintError typeChecks hint (args:AstNodeRuleParams) range matchedVariables parentAstNode = - let matched = FormatHint.toString false None args matchedVariables None hint.MatchedNode - - match hint.Suggestion with +type HintErrorConfig = + { + TypeChecks: (unit -> bool) list + Hint: Hint + Args: AstNodeRuleParams + Range: FSharp.Compiler.Text.Range + MatchedVariables: Dictionary + ParentAstNode: AstNode option + } + +let private hintError (config: HintErrorConfig) = + let toStringConfig = + { + ToStringConfig.Replace = false + ToStringConfig.ParentAstNode = None + ToStringConfig.Args = config.Args + ToStringConfig.MatchedVariables = config.MatchedVariables + ToStringConfig.ParentHintNode = None + ToStringConfig.HintNode = config.Hint.MatchedNode + } + + let matched = FormatHint.toString toStringConfig + + match config.Hint.Suggestion with | Suggestion.Expr(expr) -> - let suggestion = FormatHint.toString false None args matchedVariables None (HintExpr expr) + let suggestion = FormatHint.toString { toStringConfig with HintNode = (HintExpr expr) } let errorFormatString = Resources.GetString("RulesHintRefactor") let error = System.String.Format(errorFormatString, matched, suggestion) - let toText = FormatHint.toString true parentAstNode args matchedVariables None (HintExpr expr) + let toText = + FormatHint.toString + { + toStringConfig with + Replace = true + ParentAstNode = config.ParentAstNode + HintNode = (HintExpr expr) + } let suggestedFix = lazy( - ExpressionUtilities.tryFindTextOfRange range args.FileContent - |> Option.map (fun fromText -> { FromText = fromText; FromRange = range; ToText = toText })) + ExpressionUtilities.tryFindTextOfRange config.Range config.Args.FileContent + |> Option.map (fun fromText -> { FromText = fromText; FromRange = config.Range; ToText = toText })) - { Range = range; Message = error; SuggestedFix = Some suggestedFix; TypeChecks = typeChecks } + { Range = config.Range; Message = error; SuggestedFix = Some suggestedFix; TypeChecks = config.TypeChecks } | Suggestion.Message(message) -> let errorFormatString = Resources.GetString("RulesHintSuggestion") let error = System.String.Format(errorFormatString, matched, message) - { Range = range; Message = error; SuggestedFix = None; TypeChecks = typeChecks } + { Range = config.Range; Message = error; SuggestedFix = None; TypeChecks = config.TypeChecks } let private getMethodParameters (checkFile:FSharpCheckFileResults) (methodIdent: SynLongIdent) = let symbol = @@ -644,7 +700,15 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParser.Hint) = | AstNode.Expression(SynExpr.Paren(_)), HintExpr(_) | AstNode.Pattern(SynPat.Paren(_)), HintPat(_) -> () | AstNode.Pattern(pattern), HintPat(hintPattern) when MatchPattern.matchHintPattern (pattern, hintPattern) -> - hintError List.Empty hint args pattern.Range (Dictionary<_, _>()) None + hintError + { + TypeChecks = List.Empty + Hint = hint + Args = args + Range = pattern.Range + MatchedVariables = (Dictionary<_, _>()) + ParentAstNode = None + } |> suggestions.Add | AstNode.Expression(expr), HintExpr(hintExpr) -> let arguments = @@ -658,7 +722,15 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParser.Hint) = match MatchExpression.matchHintExpr arguments with | MatchExpression.Match(typeChecks) -> let suggest checks = - hintError checks hint args expr.Range arguments.MatchedVariables (List.tryHead breadcrumbs) + hintError + { + TypeChecks = checks + Hint = hint + Args = args + Range = expr.Range + MatchedVariables = arguments.MatchedVariables + ParentAstNode = (List.tryHead breadcrumbs) + } |> suggestions.Add match (hint.MatchedNode, hint.Suggestion) with diff --git a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs index 0487e9cf4..3ba92e914 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs @@ -35,7 +35,20 @@ type TestAstNodeRuleBase (rule:Rule) = match checkFile with | Some false -> None | _ -> parseInfo.TypeCheckResults - let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue String.Empty fileName) input (input.Split("\n")) syntaxArray |> fst + + let suggestions = + runAstNodeRules + { + Rules = Array.singleton rule + GlobalConfig = globalConfig + TypeCheckResults = checkResult + FilePath = (Option.defaultValue String.Empty fileName) + FileContent = input + Lines = (input.Split("\n")) + SyntaxArray = syntaxArray + } + |> fst + rule.RuleConfig.Cleanup() suggestions |> Array.iter this.PostSuggestion diff --git a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs index 3cf4c0188..65d70c400 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs @@ -58,7 +58,18 @@ type TestHintMatcherBase () = match checkFile with | Some false -> None | _ -> parseInfo.TypeCheckResults - let suggestions = runAstNodeRules (Array.singleton rule) globalConfig checkResult (Option.defaultValue String.Empty fileName) input (input.Split "\n") syntaxArray |> fst + let suggestions = + runAstNodeRules + { + Rules = Array.singleton rule + GlobalConfig = globalConfig + TypeCheckResults = checkResult + FilePath = (Option.defaultValue String.Empty fileName) + FileContent = input + Lines = (input.Split("\n")) + SyntaxArray = syntaxArray + } + |> fst suggestions |> Array.iter this.PostSuggestion | _ -> failwithf "Failed to parse" \ No newline at end of file diff --git a/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs index f5b27657a..96f66da98 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs @@ -31,13 +31,26 @@ type TestIndentationRuleBase (rule:Rule) = let lines = input.Split "\n" let syntaxArray = AbstractSyntaxArray.astToArray parseResults.ParseTree - let (_, context) = runAstNodeRules Array.empty globalConfig None fileName input lines syntaxArray - let lineRules = + let (_, context) = + runAstNodeRules + { + Rules = Array.empty + GlobalConfig = globalConfig + TypeCheckResults = None + FilePath = fileName + FileContent = input + Lines = lines + SyntaxArray = syntaxArray + } + let lineRules = { LineRules.IndentationRule = Some rule; NoTabCharactersRule = None; GenericLineRules = Array.empty } + + runLineRules { - LineRules.IndentationRule = Some rule - NoTabCharactersRule = None - GenericLineRules = Array.empty + LineRules = lineRules + GlobalConfig = globalConfig + FilePath = fileName + FileContent = input + Lines = lines + Context = context } - - runLineRules lineRules globalConfig fileName input lines context |> Array.iter this.PostSuggestion \ No newline at end of file diff --git a/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs index 5f0817dca..56d9fa3f3 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs @@ -31,8 +31,26 @@ type TestLineRuleBase (rule:Rule) = let lines = input.Split "\n" let syntaxArray = AbstractSyntaxArray.astToArray parseResults.ParseTree - let (_, context) = runAstNodeRules Array.empty globalConfig None fileName input lines syntaxArray + let (_, context) = + runAstNodeRules + { + Rules = Array.empty + GlobalConfig = globalConfig + TypeCheckResults = None + FilePath = fileName + FileContent = input + Lines = lines + SyntaxArray = syntaxArray + } let lineRules = { LineRules.IndentationRule = None; NoTabCharactersRule = None; GenericLineRules = [|rule|] } - runLineRules lineRules globalConfig fileName input lines context + runLineRules + { + LineRules = lineRules + GlobalConfig = globalConfig + FilePath = fileName + FileContent = input + Lines = lines + Context = context + } |> Array.iter this.PostSuggestion \ No newline at end of file diff --git a/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs index 04f0b3a9c..69d860708 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs @@ -31,12 +31,26 @@ type TestNoTabCharactersRuleBase (rule:Rule) = let lines = input.Split "\n" let syntaxArray = AbstractSyntaxArray.astToArray parseResults.ParseTree - let (_, context) = runAstNodeRules Array.empty globalConfig None fileName input lines syntaxArray - let lineRules = + let (_, context) = + runAstNodeRules + { + Rules = Array.empty + GlobalConfig = globalConfig + TypeCheckResults = None + FilePath = fileName + FileContent = input + Lines = lines + SyntaxArray = syntaxArray + } + let lineRules = { LineRules.IndentationRule = None; NoTabCharactersRule = Some rule; GenericLineRules = Array.empty } + + runLineRules { - LineRules.IndentationRule = None - NoTabCharactersRule = Some rule - GenericLineRules = Array.empty + LineRules = lineRules + GlobalConfig = globalConfig + FilePath = fileName + FileContent = input + Lines = lines + Context = context } - runLineRules lineRules globalConfig fileName input lines context |> Array.iter this.PostSuggestion \ No newline at end of file From 0efbfcfd1cebcc9a6743081f4139762ce747f67d Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Mon, 25 Dec 2023 12:12:12 +0330 Subject: [PATCH 30/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 7170cbc73..3fec2f3a9 100644 --- a/build.fsx +++ b/build.fsx @@ -291,6 +291,7 @@ Target.create "SelfCheck" (fun _ -> "asyncExceptionWithoutReturn" "maxNumberOfItemsInTuple" "maxNumberOfFunctionParameters" + "maxNumberOfMembers" ] let jsonObj = JObject.Parse fsharplintJsonText From 3a61be5741663a3d415e0002928ad6352f3cb60a Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Mon, 25 Dec 2023 12:14:06 +0330 Subject: [PATCH 31/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 3fec2f3a9..d615babb1 100644 --- a/build.fsx +++ b/build.fsx @@ -292,6 +292,7 @@ Target.create "SelfCheck" (fun _ -> "maxNumberOfItemsInTuple" "maxNumberOfFunctionParameters" "maxNumberOfMembers" + "maxNumberOfBooleanOperatorsInCondition" ] let jsonObj = JObject.Parse fsharplintJsonText From 0f3688d49986549ee662b14f25e843d1679e4599 Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Sat, 6 Jan 2024 11:22:32 +0800 Subject: [PATCH 32/48] build: run FSharpLint with 1 extra rule --- build.fsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.fsx b/build.fsx index d615babb1..bd7937be5 100644 --- a/build.fsx +++ b/build.fsx @@ -270,8 +270,8 @@ Target.create "SelfCheck" (fun _ -> (* "nestedStatements" // not enable for now "cyclomaticComplexity" rule is too complex and we can enable it later - "avoidSinglePipeOperator" rule must be improved and we can enable it later *) + "avoidSinglePipeOperator" "maxLinesInLambdaFunction" "maxLinesInMatchLambdaFunction" "maxLinesInValue" From 32c37736d696323da491dd7b064059c177cf70c5 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 10 Jan 2024 16:53:04 +0330 Subject: [PATCH 33/48] Core,Tests: fix FSharpLint warning Fixing the warning avoidSinglePipeOperator rule. --- src/FSharpLint.Console/Output.fs | 3 +- src/FSharpLint.Console/Program.fs | 10 +- .../Application/Configuration.fs | 442 +++++++++--------- src/FSharpLint.Core/Application/Lint.fs | 42 +- src/FSharpLint.Core/Framework/Ast.fs | 74 +-- src/FSharpLint.Core/Framework/AstInfo.fs | 117 ++--- src/FSharpLint.Core/Framework/HintParser.fs | 33 +- src/FSharpLint.Core/Framework/ParseFile.fs | 11 +- src/FSharpLint.Core/Framework/Suppression.fs | 4 +- src/FSharpLint.Core/Framework/Utilities.fs | 6 +- .../AsyncExceptionWithoutReturn.fs | 31 +- .../Conventions/AvoidSinglePipeOperator.fs | 27 +- .../Rules/Conventions/AvoidTooShortNames.fs | 26 +- .../Conventions/Binding/FavourAsKeyword.fs | 22 +- .../Binding/FavourIgnoreOverLetWild.fs | 27 +- .../Conventions/Binding/FavourTypedIgnore.fs | 16 +- .../Conventions/Binding/TupleOfWildcards.fs | 30 +- .../Conventions/Binding/UselessBinding.fs | 15 +- .../Binding/WildcardNamedWithAsPattern.fs | 24 +- .../Rules/Conventions/CyclomaticComplexity.fs | 32 +- ...TailCallDiagnosticsInRecursiveFunctions.fs | 8 +- .../Rules/Conventions/FavourConsistentThis.fs | 24 +- .../FavourNonMutablePropertyInitialization.fs | 14 +- .../Rules/Conventions/FavourReRaise.fs | 26 +- .../Conventions/FavourStaticEmptyFields.fs | 28 +- .../CanBeReplacedWithComposition.fs | 23 +- .../ReimplementsFunction.fs | 14 +- .../Conventions/Naming/ActivePatternNames.fs | 4 +- .../Conventions/Naming/EnumCasesNames.fs | 2 +- .../Conventions/Naming/ExceptionNames.fs | 2 +- .../Conventions/Naming/GenericTypesNames.fs | 2 +- .../Conventions/Naming/InterfaceNames.fs | 2 +- .../Conventions/Naming/InternalValuesNames.fs | 3 +- .../Rules/Conventions/Naming/LiteralNames.fs | 2 +- .../Conventions/Naming/MeasureTypeNames.fs | 2 +- .../Rules/Conventions/Naming/MemberNames.fs | 9 +- .../Rules/Conventions/Naming/NamingHelper.fs | 34 +- .../Conventions/Naming/ParameterNames.fs | 6 +- .../Conventions/Naming/PrivateValuesNames.fs | 7 +- .../Conventions/Naming/PublicValuesNames.fs | 3 +- .../Conventions/Naming/RecordFieldNames.fs | 3 +- .../Conventions/Naming/UnionCasesNames.fs | 2 +- .../Rules/Conventions/NestedStatements.fs | 15 +- .../Rules/Conventions/NoPartialFunctions.fs | 131 +++--- .../MaxNumberOfBooleanOperatorsInCondition.fs | 28 +- .../MaxNumberOfFunctionParameters.fs | 28 +- .../NumberOfItems/MaxNumberOfItemsInTuple.fs | 28 +- .../NumberOfItems/MaxNumberOfMembers.fs | 34 +- .../FailwithBadUsage.fs | 28 +- .../FailwithWithSingleArgument.fs | 14 +- ...lwithfWithArgumentsMatchingFormatString.fs | 27 +- .../InvalidArgWithTwoArguments.fs | 14 +- .../InvalidOpWithSingleArgument.fs | 14 +- .../NullArgWithSingleArgument.fs | 14 +- .../RaiseWithSingleArgument.fs | 14 +- .../RaiseWithTooManyArgumentsHelper.fs | 13 +- .../Conventions/RecursiveAsyncFunction.fs | 28 +- .../Rules/Conventions/RedundantNewKeyword.fs | 42 +- .../SourceLength/MaxLinesInClass.fs | 14 +- .../SourceLength/MaxLinesInConstructor.fs | 14 +- .../SourceLength/MaxLinesInEnum.fs | 14 +- .../SourceLength/MaxLinesInFunction.fs | 14 +- .../SourceLength/MaxLinesInLambdaFunction.fs | 14 +- .../MaxLinesInMatchLambdaFunction.fs | 14 +- .../SourceLength/MaxLinesInMember.fs | 14 +- .../SourceLength/MaxLinesInModule.fs | 14 +- .../SourceLength/MaxLinesInProperty.fs | 14 +- .../SourceLength/MaxLinesInRecord.fs | 14 +- .../SourceLength/MaxLinesInUnion.fs | 14 +- .../SourceLength/MaxLinesInValue.fs | 14 +- .../SourceLength/SourceLengthHelper.fs | 14 +- .../Conventions/SuggestUseAutoProperty.fs | 37 +- .../Rules/Conventions/UnneededRecKeyword.fs | 16 +- .../UsedUnderscorePrefixedElements.fs | 14 +- .../PatternMatchClauseIndentation.fs | 62 +-- .../PatternMatchClausesOnNewLine.fs | 28 +- .../PatternMatchExpressionIndentation.fs | 28 +- .../PatternMatchOrClausesOnNewLine.fs | 28 +- .../Formatting/Spacing/ClassMemberSpacing.fs | 28 +- .../Formatting/Spacing/ModuleDeclSpacing.fs | 28 +- .../TupleFormatting/TupleCommaSpacing.fs | 40 +- .../TupleFormatting/TupleIndentation.fs | 28 +- .../TupleFormatting/TupleParentheses.fs | 26 +- .../Rules/Formatting/TypePrefixing.fs | 81 ++-- .../Rules/Formatting/TypedItemSpacing.fs | 20 +- .../Formatting/UnionDefinitionIndentation.fs | 54 ++- .../Rules/Hints/HintMatcher.fs | 47 +- .../Rules/Hints/HintsHelper.fs | 9 +- .../Rules/Typography/Indentation.fs | 70 +-- .../Rules/Typography/MaxCharactersOnLine.fs | 27 +- .../Rules/Typography/MaxLinesInFile.fs | 29 +- .../Rules/Typography/NoTabCharacters.fs | 37 +- .../Rules/Typography/TrailingNewLineInFile.fs | 27 +- .../Typography/TrailingWhitespaceOnLine.fs | 29 +- .../Framework/TestAbstractSyntaxArray.fs | 14 +- .../Rules/Conventions/CyclomaticComplexity.fs | 6 +- .../Rules/TestAstNodeRule.fs | 4 +- .../Rules/TestHintMatcherBase.fs | 4 +- .../Rules/TestIndentationRule.fs | 4 +- .../Rules/TestLineRule.fs | 4 +- .../Rules/TestNoTabCharactersRule.fs | 4 +- .../Rules/TestRuleBase.fs | 4 +- tests/FSharpLint.Core.Tests/TestUtils.fs | 2 +- tests/FSharpLint.FunctionalTest/TestApi.fs | 2 +- 104 files changed, 1542 insertions(+), 1165 deletions(-) diff --git a/src/FSharpLint.Console/Output.fs b/src/FSharpLint.Console/Output.fs index 058d4cdb9..089a9cda0 100644 --- a/src/FSharpLint.Console/Output.fs +++ b/src/FSharpLint.Console/Output.fs @@ -59,5 +59,4 @@ type MSBuildOutput () = <| warning.RuleIdentifier <| warning.Details.Message member _.WriteError (error:string) = - $"FSharpLint error: {error}" - |> Console.Error.WriteLine \ No newline at end of file + Console.Error.WriteLine $"FSharpLint error: {error}" diff --git a/src/FSharpLint.Console/Program.fs b/src/FSharpLint.Console/Program.fs index 519a42ea9..0049ff76a 100644 --- a/src/FSharpLint.Console/Program.fs +++ b/src/FSharpLint.Console/Program.fs @@ -56,8 +56,8 @@ let private parserProgress (output:Output.IOutput) = function String.Format(Resources.GetString("ConsoleFinishedFile"), List.length warnings) |> output.WriteInfo | Failed (file, parseException) -> String.Format(Resources.GetString("ConsoleFailedToParseFile"), file) |> output.WriteError - $"Exception Message:{Environment.NewLine}{parseException.Message}{Environment.NewLine}Exception Stack Trace:{Environment.NewLine}{parseException.StackTrace}{Environment.NewLine}" - |> output.WriteError + output.WriteError + $"Exception Message:{Environment.NewLine}{parseException.Message}{Environment.NewLine}Exception Stack Trace:{Environment.NewLine}{parseException.StackTrace}{Environment.NewLine}" /// Infers the file type of the target based on its file extension. let internal inferFileType (target:string) = @@ -84,7 +84,7 @@ let private start (arguments:ParseResults) (toolsPath:Ionide.ProjInfo. let version = Assembly.GetExecutingAssembly().GetCustomAttributes false |> Seq.pick (function | :? AssemblyInformationalVersionAttribute as aiva -> Some aiva.InformationalVersion | _ -> None) - $"Current version: {version}" |> output.WriteInfo + output.WriteInfo $"Current version: {version}" Environment.Exit 0 let handleError (str:string) = @@ -131,8 +131,8 @@ let private start (arguments:ParseResults) (toolsPath:Ionide.ProjInfo. with | exn -> let target = if fileType = FileType.Source then "source" else target - $"Lint failed while analysing %s{target}.{Environment.NewLine}Failed with: %s{exn.Message}{Environment.NewLine}Stack trace: {exn.StackTrace}" - |> handleError + handleError + $"Lint failed while analysing %s{target}.{Environment.NewLine}Failed with: %s{exn.Message}{Environment.NewLine}Stack trace: {exn.StackTrace}" | _ -> () exitCode diff --git a/src/FSharpLint.Core/Application/Configuration.fs b/src/FSharpLint.Core/Application/Configuration.fs index 0d053b7b9..9537b8318 100644 --- a/src/FSharpLint.Core/Application/Configuration.fs +++ b/src/FSharpLint.Core/Application/Configuration.fs @@ -61,9 +61,11 @@ module IgnoreFiles = let private pathMatchesGlob (globs:Regex list) (path:string list) isDirectory = let rec getRemainingGlobSeqForMatches (pathSegment:string) (globSeqs:Regex list list) = - globSeqs |> List.choose (function - | globSegment::remaining when globSegment.IsMatch(pathSegment) -> Some remaining - | _ -> None) + List.choose + (function + | (globSegment: Regex)::remaining when globSegment.IsMatch(pathSegment) -> Some remaining + | _ -> None) + globSeqs let rec doesGlobSeqMatchPathSeq remainingPath currentlyMatchingGlobs = match remainingPath with @@ -73,7 +75,7 @@ module IgnoreFiles = let currentlyMatchingGlobs = getRemainingGlobSeqForMatches currentSegment currentlyMatchingGlobs - let aGlobWasCompletelyMatched = currentlyMatchingGlobs |> List.exists List.isEmpty + let aGlobWasCompletelyMatched = List.exists List.isEmpty currentlyMatchingGlobs let matched = aGlobWasCompletelyMatched && (isDirectory || (not isDirectory && List.isEmpty remaining)) @@ -86,13 +88,13 @@ module IgnoreFiles = let shouldFileBeIgnored (ignorePaths:Ignore list) (filePath:string) = let segments = filePath.Split Path.DirectorySeparatorChar |> Array.toList - ignorePaths |> List.fold (fun isCurrentlyIgnored ignoreGlob -> + List.fold (fun isCurrentlyIgnored ignoreGlob -> match ignoreGlob with | Ignore(glob, IsDirectory(isDirectory)) when not isCurrentlyIgnored && pathMatchesGlob glob segments isDirectory -> true | Negate(glob, IsDirectory(isDirectory)) when isCurrentlyIgnored && pathMatchesGlob glob segments isDirectory -> false - | _ -> isCurrentlyIgnored) false + | _ -> isCurrentlyIgnored) false ignorePaths // Non-standard record field naming for config serialization. // fsharplint:disable RecordFieldNames @@ -107,13 +109,13 @@ let constructRuleIfEnabled rule ruleConfig = if ruleConfig.Enabled then Some rul let constructRuleWithConfig rule ruleConfig = if ruleConfig.Enabled then - ruleConfig.Config |> Option.map rule + Option.map rule ruleConfig.Config else None let constructTypePrefixingRuleWithConfig rule (ruleConfig: RuleConfig) = if ruleConfig.Enabled then - let config = ruleConfig.Config |> Option.defaultValue { Mode = TypePrefixing.Mode.Hybrid } + let config = Option.defaultValue { Mode = TypePrefixing.Mode.Hybrid } ruleConfig.Config Some(rule config) else None @@ -124,11 +126,12 @@ type TupleFormattingConfig = tupleParentheses:EnabledConfig option } with member this.Flatten() = - [| - this.tupleCommaSpacing |> Option.bind (constructRuleIfEnabled TupleCommaSpacing.rule) - this.tupleIndentation |> Option.bind (constructRuleIfEnabled TupleIndentation.rule) - this.tupleParentheses |> Option.bind (constructRuleIfEnabled TupleParentheses.rule) - |] |> Array.choose id + Array.choose id + [| + Option.bind (constructRuleIfEnabled TupleCommaSpacing.rule) this.tupleCommaSpacing + Option.bind (constructRuleIfEnabled TupleIndentation.rule) this.tupleIndentation + Option.bind (constructRuleIfEnabled TupleParentheses.rule) this.tupleParentheses + |] type PatternMatchFormattingConfig = { patternMatchClausesOnNewLine:EnabledConfig option @@ -137,12 +140,13 @@ type PatternMatchFormattingConfig = patternMatchExpressionIndentation:EnabledConfig option } with member this.Flatten() = - [| - this.patternMatchClausesOnNewLine |> Option.bind (constructRuleIfEnabled PatternMatchClausesOnNewLine.rule) - this.patternMatchOrClausesOnNewLine |> Option.bind (constructRuleIfEnabled PatternMatchOrClausesOnNewLine.rule) - this.patternMatchClauseIndentation |> Option.bind (constructRuleWithConfig PatternMatchClauseIndentation.rule) - this.patternMatchExpressionIndentation |> Option.bind (constructRuleIfEnabled PatternMatchExpressionIndentation.rule) - |] |> Array.choose id + Array.choose id + [| + Option.bind (constructRuleIfEnabled PatternMatchClausesOnNewLine.rule) this.patternMatchClausesOnNewLine + Option.bind (constructRuleIfEnabled PatternMatchOrClausesOnNewLine.rule) this.patternMatchOrClausesOnNewLine + Option.bind (constructRuleWithConfig PatternMatchClauseIndentation.rule) this.patternMatchClauseIndentation + Option.bind (constructRuleIfEnabled PatternMatchExpressionIndentation.rule) this.patternMatchExpressionIndentation + |] type FormattingConfig = { typedItemSpacing:RuleConfig option @@ -154,15 +158,16 @@ type FormattingConfig = patternMatchFormatting:PatternMatchFormattingConfig option } with member this.Flatten() = - [| - this.typedItemSpacing |> Option.bind (constructRuleWithConfig TypedItemSpacing.rule) |> Option.toArray - this.typePrefixing |> Option.bind (constructTypePrefixingRuleWithConfig TypePrefixing.rule) |> Option.toArray - this.unionDefinitionIndentation |> Option.bind (constructRuleIfEnabled UnionDefinitionIndentation.rule) |> Option.toArray - this.moduleDeclSpacing |> Option.bind (constructRuleIfEnabled ModuleDeclSpacing.rule) |> Option.toArray - this.classMemberSpacing |> Option.bind (constructRuleIfEnabled ClassMemberSpacing.rule) |> Option.toArray - this.tupleFormatting |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - this.patternMatchFormatting |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - |] |> Array.concat + Array.concat + [| + this.typedItemSpacing |> Option.bind (constructRuleWithConfig TypedItemSpacing.rule) |> Option.toArray + this.typePrefixing |> Option.bind (constructTypePrefixingRuleWithConfig TypePrefixing.rule) |> Option.toArray + this.unionDefinitionIndentation |> Option.bind (constructRuleIfEnabled UnionDefinitionIndentation.rule) |> Option.toArray + this.moduleDeclSpacing |> Option.bind (constructRuleIfEnabled ModuleDeclSpacing.rule) |> Option.toArray + this.classMemberSpacing |> Option.bind (constructRuleIfEnabled ClassMemberSpacing.rule) |> Option.toArray + this.tupleFormatting |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + this.patternMatchFormatting |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + |] type RaiseWithTooManyArgsConfig = { failwithBadUsage:EnabledConfig option @@ -173,14 +178,15 @@ type RaiseWithTooManyArgsConfig = failwithfWithArgumentsMatchingFormatString:EnabledConfig option } with member this.Flatten() = - [| - this.failwithBadUsage |> Option.bind (constructRuleIfEnabled FailwithBadUsage.rule) |> Option.toArray - this.raiseWithSingleArgument |> Option.bind (constructRuleIfEnabled RaiseWithSingleArgument.rule) |> Option.toArray - this.nullArgWithSingleArgument |> Option.bind (constructRuleIfEnabled NullArgWithSingleArgument.rule) |> Option.toArray - this.invalidOpWithSingleArgument |> Option.bind (constructRuleIfEnabled InvalidOpWithSingleArgument.rule) |> Option.toArray - this.invalidArgWithTwoArguments |> Option.bind (constructRuleIfEnabled InvalidArgWithTwoArguments.rule) |> Option.toArray - this.failwithfWithArgumentsMatchingFormatString |> Option.bind (constructRuleIfEnabled FailwithfWithArgumentsMatchingFormatString.rule) |> Option.toArray - |] |> Array.concat + Array.concat + [| + this.failwithBadUsage |> Option.bind (constructRuleIfEnabled FailwithBadUsage.rule) |> Option.toArray + this.raiseWithSingleArgument |> Option.bind (constructRuleIfEnabled RaiseWithSingleArgument.rule) |> Option.toArray + this.nullArgWithSingleArgument |> Option.bind (constructRuleIfEnabled NullArgWithSingleArgument.rule) |> Option.toArray + this.invalidOpWithSingleArgument |> Option.bind (constructRuleIfEnabled InvalidOpWithSingleArgument.rule) |> Option.toArray + this.invalidArgWithTwoArguments |> Option.bind (constructRuleIfEnabled InvalidArgWithTwoArguments.rule) |> Option.toArray + this.failwithfWithArgumentsMatchingFormatString |> Option.bind (constructRuleIfEnabled FailwithfWithArgumentsMatchingFormatString.rule) |> Option.toArray + |] type SourceLengthConfig = { maxLinesInLambdaFunction:RuleConfig option @@ -197,20 +203,21 @@ type SourceLengthConfig = maxLinesInClass:RuleConfig option } with member this.Flatten() = - [| - this.maxLinesInLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInLambdaFunction.rule) |> Option.toArray - this.maxLinesInMatchLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInMatchLambdaFunction.rule) |> Option.toArray - this.maxLinesInValue |> Option.bind (constructRuleWithConfig MaxLinesInValue.rule) |> Option.toArray - this.maxLinesInFunction |> Option.bind (constructRuleWithConfig MaxLinesInFunction.rule) |> Option.toArray - this.maxLinesInMember |> Option.bind (constructRuleWithConfig MaxLinesInMember.rule) |> Option.toArray - this.maxLinesInConstructor |> Option.bind (constructRuleWithConfig MaxLinesInConstructor.rule) |> Option.toArray - this.maxLinesInProperty |> Option.bind (constructRuleWithConfig MaxLinesInProperty.rule) |> Option.toArray - this.maxLinesInModule |> Option.bind (constructRuleWithConfig MaxLinesInModule.rule) |> Option.toArray - this.maxLinesInRecord |> Option.bind (constructRuleWithConfig MaxLinesInRecord.rule) |> Option.toArray - this.maxLinesInEnum |> Option.bind (constructRuleWithConfig MaxLinesInEnum.rule) |> Option.toArray - this.maxLinesInUnion |> Option.bind (constructRuleWithConfig MaxLinesInUnion.rule) |> Option.toArray - this.maxLinesInClass |> Option.bind (constructRuleWithConfig MaxLinesInClass.rule) |> Option.toArray - |] |> Array.concat + Array.concat + [| + this.maxLinesInLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInLambdaFunction.rule) |> Option.toArray + this.maxLinesInMatchLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInMatchLambdaFunction.rule) |> Option.toArray + this.maxLinesInValue |> Option.bind (constructRuleWithConfig MaxLinesInValue.rule) |> Option.toArray + this.maxLinesInFunction |> Option.bind (constructRuleWithConfig MaxLinesInFunction.rule) |> Option.toArray + this.maxLinesInMember |> Option.bind (constructRuleWithConfig MaxLinesInMember.rule) |> Option.toArray + this.maxLinesInConstructor |> Option.bind (constructRuleWithConfig MaxLinesInConstructor.rule) |> Option.toArray + this.maxLinesInProperty |> Option.bind (constructRuleWithConfig MaxLinesInProperty.rule) |> Option.toArray + this.maxLinesInModule |> Option.bind (constructRuleWithConfig MaxLinesInModule.rule) |> Option.toArray + this.maxLinesInRecord |> Option.bind (constructRuleWithConfig MaxLinesInRecord.rule) |> Option.toArray + this.maxLinesInEnum |> Option.bind (constructRuleWithConfig MaxLinesInEnum.rule) |> Option.toArray + this.maxLinesInUnion |> Option.bind (constructRuleWithConfig MaxLinesInUnion.rule) |> Option.toArray + this.maxLinesInClass |> Option.bind (constructRuleWithConfig MaxLinesInClass.rule) |> Option.toArray + |] type NamesConfig = { interfaceNames:RuleConfig option @@ -233,27 +240,28 @@ type NamesConfig = internalValuesNames:RuleConfig option } with member this.Flatten() = - [| - this.interfaceNames |> Option.bind (constructRuleWithConfig InterfaceNames.rule) |> Option.toArray - this.genericTypesNames |> Option.bind (constructRuleWithConfig GenericTypesNames.rule) |> Option.toArray - this.exceptionNames |> Option.bind (constructRuleWithConfig ExceptionNames.rule) |> Option.toArray - this.typeNames |> Option.bind (constructRuleWithConfig TypeNames.rule) |> Option.toArray - this.recordFieldNames |> Option.bind (constructRuleWithConfig RecordFieldNames.rule) |> Option.toArray - this.enumCasesNames |> Option.bind (constructRuleWithConfig EnumCasesNames.rule) |> Option.toArray - this.unionCasesNames |> Option.bind (constructRuleWithConfig UnionCasesNames.rule) |> Option.toArray - this.moduleNames |> Option.bind (constructRuleWithConfig ModuleNames.rule) |> Option.toArray - this.literalNames |> Option.bind (constructRuleWithConfig LiteralNames.rule) |> Option.toArray - this.namespaceNames |> Option.bind (constructRuleWithConfig NamespaceNames.rule) |> Option.toArray - this.memberNames |> Option.bind (constructRuleWithConfig MemberNames.rule) |> Option.toArray - this.parameterNames |> Option.bind (constructRuleWithConfig ParameterNames.rule) |> Option.toArray - this.measureTypeNames |> Option.bind (constructRuleWithConfig MeasureTypeNames.rule) |> Option.toArray - this.activePatternNames |> Option.bind (constructRuleWithConfig ActivePatternNames.rule) |> Option.toArray - this.publicValuesNames |> Option.bind (constructRuleWithConfig PublicValuesNames.rule) |> Option.toArray - this.nonPublicValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) |> Option.toArray - this.nonPublicValuesNames |> Option.bind (constructRuleWithConfig InternalValuesNames.rule) |> Option.toArray - this.privateValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) |> Option.toArray - this.internalValuesNames|> Option.bind (constructRuleWithConfig InternalValuesNames.rule) |> Option.toArray - |] |> Array.concat + Array.concat + [| + this.interfaceNames |> Option.bind (constructRuleWithConfig InterfaceNames.rule) |> Option.toArray + this.genericTypesNames |> Option.bind (constructRuleWithConfig GenericTypesNames.rule) |> Option.toArray + this.exceptionNames |> Option.bind (constructRuleWithConfig ExceptionNames.rule) |> Option.toArray + this.typeNames |> Option.bind (constructRuleWithConfig TypeNames.rule) |> Option.toArray + this.recordFieldNames |> Option.bind (constructRuleWithConfig RecordFieldNames.rule) |> Option.toArray + this.enumCasesNames |> Option.bind (constructRuleWithConfig EnumCasesNames.rule) |> Option.toArray + this.unionCasesNames |> Option.bind (constructRuleWithConfig UnionCasesNames.rule) |> Option.toArray + this.moduleNames |> Option.bind (constructRuleWithConfig ModuleNames.rule) |> Option.toArray + this.literalNames |> Option.bind (constructRuleWithConfig LiteralNames.rule) |> Option.toArray + this.namespaceNames |> Option.bind (constructRuleWithConfig NamespaceNames.rule) |> Option.toArray + this.memberNames |> Option.bind (constructRuleWithConfig MemberNames.rule) |> Option.toArray + this.parameterNames |> Option.bind (constructRuleWithConfig ParameterNames.rule) |> Option.toArray + this.measureTypeNames |> Option.bind (constructRuleWithConfig MeasureTypeNames.rule) |> Option.toArray + this.activePatternNames |> Option.bind (constructRuleWithConfig ActivePatternNames.rule) |> Option.toArray + this.publicValuesNames |> Option.bind (constructRuleWithConfig PublicValuesNames.rule) |> Option.toArray + this.nonPublicValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) |> Option.toArray + this.nonPublicValuesNames |> Option.bind (constructRuleWithConfig InternalValuesNames.rule) |> Option.toArray + this.privateValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) |> Option.toArray + this.internalValuesNames|> Option.bind (constructRuleWithConfig InternalValuesNames.rule) |> Option.toArray + |] type NumberOfItemsConfig = { maxNumberOfItemsInTuple:RuleConfig option @@ -262,12 +270,13 @@ type NumberOfItemsConfig = maxNumberOfBooleanOperatorsInCondition:RuleConfig option } with member this.Flatten() = - [| - this.maxNumberOfItemsInTuple |> Option.bind (constructRuleWithConfig MaxNumberOfItemsInTuple.rule) |> Option.toArray - this.maxNumberOfFunctionParameters |> Option.bind (constructRuleWithConfig MaxNumberOfFunctionParameters.rule) |> Option.toArray - this.maxNumberOfMembers |> Option.bind (constructRuleWithConfig MaxNumberOfMembers.rule) |> Option.toArray - this.maxNumberOfBooleanOperatorsInCondition |> Option.bind (constructRuleWithConfig MaxNumberOfBooleanOperatorsInCondition.rule) |> Option.toArray - |] |> Array.concat + Array.concat + [| + this.maxNumberOfItemsInTuple |> Option.bind (constructRuleWithConfig MaxNumberOfItemsInTuple.rule) |> Option.toArray + this.maxNumberOfFunctionParameters |> Option.bind (constructRuleWithConfig MaxNumberOfFunctionParameters.rule) |> Option.toArray + this.maxNumberOfMembers |> Option.bind (constructRuleWithConfig MaxNumberOfMembers.rule) |> Option.toArray + this.maxNumberOfBooleanOperatorsInCondition |> Option.bind (constructRuleWithConfig MaxNumberOfBooleanOperatorsInCondition.rule) |> Option.toArray + |] type BindingConfig = { favourIgnoreOverLetWild:EnabledConfig option @@ -278,14 +287,15 @@ type BindingConfig = favourTypedIgnore:EnabledConfig option } with member this.Flatten() = - [| - this.favourIgnoreOverLetWild |> Option.bind (constructRuleIfEnabled FavourIgnoreOverLetWild.rule) |> Option.toArray - this.favourTypedIgnore |> Option.bind (constructRuleIfEnabled FavourTypedIgnore.rule) |> Option.toArray - this.wildcardNamedWithAsPattern |> Option.bind (constructRuleIfEnabled WildcardNamedWithAsPattern.rule) |> Option.toArray - this.uselessBinding |> Option.bind (constructRuleIfEnabled UselessBinding.rule) |> Option.toArray - this.tupleOfWildcards |> Option.bind (constructRuleIfEnabled TupleOfWildcards.rule) |> Option.toArray - this.favourAsKeyword |> Option.bind (constructRuleIfEnabled FavourAsKeyword.rule) |> Option.toArray - |] |> Array.concat + Array.concat + [| + this.favourIgnoreOverLetWild |> Option.bind (constructRuleIfEnabled FavourIgnoreOverLetWild.rule) |> Option.toArray + this.favourTypedIgnore |> Option.bind (constructRuleIfEnabled FavourTypedIgnore.rule) |> Option.toArray + this.wildcardNamedWithAsPattern |> Option.bind (constructRuleIfEnabled WildcardNamedWithAsPattern.rule) |> Option.toArray + this.uselessBinding |> Option.bind (constructRuleIfEnabled UselessBinding.rule) |> Option.toArray + this.tupleOfWildcards |> Option.bind (constructRuleIfEnabled TupleOfWildcards.rule) |> Option.toArray + this.favourAsKeyword |> Option.bind (constructRuleIfEnabled FavourAsKeyword.rule) |> Option.toArray + |] type ConventionsConfig = { recursiveAsyncFunction:EnabledConfig option @@ -312,30 +322,31 @@ type ConventionsConfig = ensureTailCallDiagnosticsInRecursiveFunctions:EnabledConfig option} with member this.Flatten() = - [| - this.recursiveAsyncFunction |> Option.bind (constructRuleIfEnabled RecursiveAsyncFunction.rule) |> Option.toArray - this.avoidTooShortNames |> Option.bind (constructRuleIfEnabled AvoidTooShortNames.rule) |> Option.toArray - this.redundantNewKeyword |> Option.bind (constructRuleIfEnabled RedundantNewKeyword.rule) |> Option.toArray - this.favourNonMutablePropertyInitialization |> Option.bind (constructRuleIfEnabled FavourNonMutablePropertyInitialization.rule) |> Option.toArray - this.favourReRaise |> Option.bind (constructRuleIfEnabled FavourReRaise.rule) |> Option.toArray - this.favourStaticEmptyFields |> Option.bind (constructRuleIfEnabled FavourStaticEmptyFields.rule) |> Option.toArray - this.asyncExceptionWithoutReturn |> Option.bind (constructRuleIfEnabled AsyncExceptionWithoutReturn.rule) |> Option.toArray - this.unneededRecKeyword |> Option.bind (constructRuleIfEnabled UnneededRecKeyword.rule) |> Option.toArray - this.nestedStatements |> Option.bind (constructRuleWithConfig NestedStatements.rule) |> Option.toArray - this.favourConsistentThis |> Option.bind (constructRuleWithConfig FavourConsistentThis.rule) |> Option.toArray - this.cyclomaticComplexity |> Option.bind (constructRuleWithConfig CyclomaticComplexity.rule) |> Option.toArray - this.reimplementsFunction |> Option.bind (constructRuleIfEnabled ReimplementsFunction.rule) |> Option.toArray - this.canBeReplacedWithComposition |> Option.bind (constructRuleIfEnabled CanBeReplacedWithComposition.rule) |> Option.toArray - this.avoidSinglePipeOperator|> Option.bind (constructRuleIfEnabled AvoidSinglePipeOperator.rule) |> Option.toArray - this.usedUnderscorePrefixedElements |> Option.bind (constructRuleIfEnabled UsedUnderscorePrefixedElements.rule) |> Option.toArray - this.raiseWithTooManyArgs |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - this.sourceLength |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - this.naming |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - this.numberOfItems |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - this.binding |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - this.suggestUseAutoProperty |> Option.bind (constructRuleIfEnabled SuggestUseAutoProperty.rule) |> Option.toArray - this.ensureTailCallDiagnosticsInRecursiveFunctions |> Option.bind (constructRuleIfEnabled EnsureTailCallDiagnosticsInRecursiveFunctions.rule) |> Option.toArray - |] |> Array.concat + Array.concat + [| + this.recursiveAsyncFunction |> Option.bind (constructRuleIfEnabled RecursiveAsyncFunction.rule) |> Option.toArray + this.avoidTooShortNames |> Option.bind (constructRuleIfEnabled AvoidTooShortNames.rule) |> Option.toArray + this.redundantNewKeyword |> Option.bind (constructRuleIfEnabled RedundantNewKeyword.rule) |> Option.toArray + this.favourNonMutablePropertyInitialization |> Option.bind (constructRuleIfEnabled FavourNonMutablePropertyInitialization.rule) |> Option.toArray + this.favourReRaise |> Option.bind (constructRuleIfEnabled FavourReRaise.rule) |> Option.toArray + this.favourStaticEmptyFields |> Option.bind (constructRuleIfEnabled FavourStaticEmptyFields.rule) |> Option.toArray + this.asyncExceptionWithoutReturn |> Option.bind (constructRuleIfEnabled AsyncExceptionWithoutReturn.rule) |> Option.toArray + this.unneededRecKeyword |> Option.bind (constructRuleIfEnabled UnneededRecKeyword.rule) |> Option.toArray + this.nestedStatements |> Option.bind (constructRuleWithConfig NestedStatements.rule) |> Option.toArray + this.favourConsistentThis |> Option.bind (constructRuleWithConfig FavourConsistentThis.rule) |> Option.toArray + this.cyclomaticComplexity |> Option.bind (constructRuleWithConfig CyclomaticComplexity.rule) |> Option.toArray + this.reimplementsFunction |> Option.bind (constructRuleIfEnabled ReimplementsFunction.rule) |> Option.toArray + this.canBeReplacedWithComposition |> Option.bind (constructRuleIfEnabled CanBeReplacedWithComposition.rule) |> Option.toArray + this.avoidSinglePipeOperator|> Option.bind (constructRuleIfEnabled AvoidSinglePipeOperator.rule) |> Option.toArray + this.usedUnderscorePrefixedElements |> Option.bind (constructRuleIfEnabled UsedUnderscorePrefixedElements.rule) |> Option.toArray + this.raiseWithTooManyArgs |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + this.sourceLength |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + this.naming |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + this.numberOfItems |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + this.binding |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + this.suggestUseAutoProperty |> Option.bind (constructRuleIfEnabled SuggestUseAutoProperty.rule) |> Option.toArray + this.ensureTailCallDiagnosticsInRecursiveFunctions |> Option.bind (constructRuleIfEnabled EnsureTailCallDiagnosticsInRecursiveFunctions.rule) |> Option.toArray + |] type TypographyConfig = { indentation:EnabledConfig option @@ -346,16 +357,17 @@ type TypographyConfig = noTabCharacters:EnabledConfig option } with member this.Flatten() = - [| - this.indentation |> Option.bind (constructRuleIfEnabled Indentation.rule) |> Option.toArray - this.maxCharactersOnLine |> Option.bind (constructRuleWithConfig MaxCharactersOnLine.rule) |> Option.toArray - this.trailingWhitespaceOnLine |> Option.bind (constructRuleWithConfig TrailingWhitespaceOnLine.rule) |> Option.toArray - this.maxLinesInFile |> Option.bind (constructRuleWithConfig MaxLinesInFile.rule) |> Option.toArray - this.trailingNewLineInFile |> Option.bind (constructRuleIfEnabled TrailingNewLineInFile.rule) |> Option.toArray - this.noTabCharacters |> Option.bind (constructRuleIfEnabled NoTabCharacters.rule) |> Option.toArray - |] |> Array.concat - -let private getOrEmptyList hints = hints |> Option.defaultValue Array.empty + Array.concat + [| + this.indentation |> Option.bind (constructRuleIfEnabled Indentation.rule) |> Option.toArray + this.maxCharactersOnLine |> Option.bind (constructRuleWithConfig MaxCharactersOnLine.rule) |> Option.toArray + this.trailingWhitespaceOnLine |> Option.bind (constructRuleWithConfig TrailingWhitespaceOnLine.rule) |> Option.toArray + this.maxLinesInFile |> Option.bind (constructRuleWithConfig MaxLinesInFile.rule) |> Option.toArray + this.trailingNewLineInFile |> Option.bind (constructRuleIfEnabled TrailingNewLineInFile.rule) |> Option.toArray + this.noTabCharacters |> Option.bind (constructRuleIfEnabled NoTabCharacters.rule) |> Option.toArray + |] + +let private getOrEmptyList hints = Option.defaultValue Array.empty hints type HintConfig = { add:string [] option @@ -650,103 +662,107 @@ let findDeprecation config deprecatedAllRules allRules = } } +// fsharplint:disable MaxLinesInFunction let flattenConfig (config:Configuration) = let deprecatedAllRules = - [| - config.formatting |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - config.conventions |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - config.typography |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat - config.Hints |> Option.map (fun config -> HintMatcher.rule { HintMatcher.Config.HintTrie = parseHints (getOrEmptyList config.add) }) |> Option.toArray - |] |> Array.concat + Array.concat + [| + config.formatting |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + config.conventions |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + config.typography |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat + config.Hints |> Option.map (fun config -> HintMatcher.rule { HintMatcher.Config.HintTrie = parseHints (getOrEmptyList config.add) }) |> Option.toArray + |] let allRules = - [| - config.TypedItemSpacing |> Option.bind (constructRuleWithConfig TypedItemSpacing.rule) - config.TypePrefixing |> Option.bind (constructTypePrefixingRuleWithConfig TypePrefixing.rule) - config.UnionDefinitionIndentation |> Option.bind (constructRuleIfEnabled UnionDefinitionIndentation.rule) - config.ModuleDeclSpacing |> Option.bind (constructRuleIfEnabled ModuleDeclSpacing.rule) - config.ClassMemberSpacing |> Option.bind (constructRuleIfEnabled ClassMemberSpacing.rule) - config.TupleCommaSpacing |> Option.bind (constructRuleIfEnabled TupleCommaSpacing.rule) - config.TupleIndentation |> Option.bind (constructRuleIfEnabled TupleIndentation.rule) - config.TupleParentheses |> Option.bind (constructRuleIfEnabled TupleParentheses.rule) - config.PatternMatchClausesOnNewLine |> Option.bind (constructRuleIfEnabled PatternMatchClausesOnNewLine.rule) - config.PatternMatchOrClausesOnNewLine |> Option.bind (constructRuleIfEnabled PatternMatchOrClausesOnNewLine.rule) - config.PatternMatchClauseIndentation |> Option.bind (constructRuleWithConfig PatternMatchClauseIndentation.rule) - config.PatternMatchExpressionIndentation |> Option.bind (constructRuleIfEnabled PatternMatchExpressionIndentation.rule) - config.RecursiveAsyncFunction |> Option.bind (constructRuleIfEnabled RecursiveAsyncFunction.rule) - config.AvoidTooShortNames |> Option.bind (constructRuleIfEnabled AvoidTooShortNames.rule) - config.RedundantNewKeyword |> Option.bind (constructRuleIfEnabled RedundantNewKeyword.rule) - config.FavourNonMutablePropertyInitialization |> Option.bind (constructRuleIfEnabled FavourNonMutablePropertyInitialization.rule) - config.FavourReRaise |> Option.bind (constructRuleIfEnabled FavourReRaise.rule) - config.FavourStaticEmptyFields |> Option.bind (constructRuleIfEnabled FavourStaticEmptyFields.rule) - config.AsyncExceptionWithoutReturn |> Option.bind (constructRuleIfEnabled AsyncExceptionWithoutReturn.rule) - config.UnneededRecKeyword |> Option.bind (constructRuleIfEnabled UnneededRecKeyword.rule) - config.NestedStatements |> Option.bind (constructRuleWithConfig NestedStatements.rule) - config.FavourConsistentThis |> Option.bind (constructRuleWithConfig FavourConsistentThis.rule) - config.CyclomaticComplexity |> Option.bind (constructRuleWithConfig CyclomaticComplexity.rule) - config.ReimplementsFunction |> Option.bind (constructRuleIfEnabled ReimplementsFunction.rule) - config.CanBeReplacedWithComposition |> Option.bind (constructRuleIfEnabled CanBeReplacedWithComposition.rule) - config.AvoidSinglePipeOperator |> Option.bind (constructRuleIfEnabled AvoidSinglePipeOperator.rule) - config.UsedUnderscorePrefixedElements |> Option.bind (constructRuleIfEnabled UsedUnderscorePrefixedElements.rule) - config.FailwithBadUsage |> Option.bind (constructRuleIfEnabled FailwithBadUsage.rule) - config.RaiseWithSingleArgument |> Option.bind (constructRuleIfEnabled RaiseWithSingleArgument.rule) - config.FailwithWithSingleArgument |> Option.bind (constructRuleIfEnabled FailwithWithSingleArgument.rule) - config.NullArgWithSingleArgument |> Option.bind (constructRuleIfEnabled NullArgWithSingleArgument.rule) - config.InvalidOpWithSingleArgument |> Option.bind (constructRuleIfEnabled InvalidOpWithSingleArgument.rule) - config.InvalidArgWithTwoArguments |> Option.bind (constructRuleIfEnabled InvalidArgWithTwoArguments.rule) - config.FailwithfWithArgumentsMatchingFormatString |> Option.bind (constructRuleIfEnabled FailwithfWithArgumentsMatchingFormatString.rule) - config.MaxLinesInLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInLambdaFunction.rule) - config.MaxLinesInMatchLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInMatchLambdaFunction.rule) - config.MaxLinesInValue |> Option.bind (constructRuleWithConfig MaxLinesInValue.rule) - config.MaxLinesInFunction |> Option.bind (constructRuleWithConfig MaxLinesInFunction.rule) - config.MaxLinesInMember |> Option.bind (constructRuleWithConfig MaxLinesInMember.rule) - config.MaxLinesInConstructor |> Option.bind (constructRuleWithConfig MaxLinesInConstructor.rule) - config.MaxLinesInProperty |> Option.bind (constructRuleWithConfig MaxLinesInProperty.rule) - config.MaxLinesInModule |> Option.bind (constructRuleWithConfig MaxLinesInModule.rule) - config.MaxLinesInRecord |> Option.bind (constructRuleWithConfig MaxLinesInRecord.rule) - config.MaxLinesInEnum |> Option.bind (constructRuleWithConfig MaxLinesInEnum.rule) - config.MaxLinesInUnion |> Option.bind (constructRuleWithConfig MaxLinesInUnion.rule) - config.MaxLinesInClass |> Option.bind (constructRuleWithConfig MaxLinesInClass.rule) - config.InterfaceNames |> Option.bind (constructRuleWithConfig InterfaceNames.rule) - config.GenericTypesNames |> Option.bind (constructRuleWithConfig GenericTypesNames.rule) - config.ExceptionNames |> Option.bind (constructRuleWithConfig ExceptionNames.rule) - config.TypeNames |> Option.bind (constructRuleWithConfig TypeNames.rule) - config.RecordFieldNames |> Option.bind (constructRuleWithConfig RecordFieldNames.rule) - config.EnumCasesNames |> Option.bind (constructRuleWithConfig EnumCasesNames.rule) - config.UnionCasesNames |> Option.bind (constructRuleWithConfig UnionCasesNames.rule) - config.ModuleNames |> Option.bind (constructRuleWithConfig ModuleNames.rule) - config.LiteralNames |> Option.bind (constructRuleWithConfig LiteralNames.rule) - config.NamespaceNames |> Option.bind (constructRuleWithConfig NamespaceNames.rule) - config.MemberNames |> Option.bind (constructRuleWithConfig MemberNames.rule) - config.ParameterNames |> Option.bind (constructRuleWithConfig ParameterNames.rule) - config.MeasureTypeNames |> Option.bind (constructRuleWithConfig MeasureTypeNames.rule) - config.ActivePatternNames |> Option.bind (constructRuleWithConfig ActivePatternNames.rule) - config.PublicValuesNames |> Option.bind (constructRuleWithConfig PublicValuesNames.rule) - config.NonPublicValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) - config.NonPublicValuesNames |> Option.bind (constructRuleWithConfig InternalValuesNames.rule) - config.PrivateValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) - config.InternalValuesNames |> Option.bind (constructRuleWithConfig InternalValuesNames.rule) - config.UnnestedFunctionNames |> Option.bind (constructRuleWithConfig UnnestedFunctionNames.rule) - config.NestedFunctionNames |> Option.bind (constructRuleWithConfig NestedFunctionNames.rule) - config.MaxNumberOfItemsInTuple |> Option.bind (constructRuleWithConfig MaxNumberOfItemsInTuple.rule) - config.MaxNumberOfFunctionParameters |> Option.bind (constructRuleWithConfig MaxNumberOfFunctionParameters.rule) - config.MaxNumberOfMembers |> Option.bind (constructRuleWithConfig MaxNumberOfMembers.rule) - config.MaxNumberOfBooleanOperatorsInCondition |> Option.bind (constructRuleWithConfig MaxNumberOfBooleanOperatorsInCondition.rule) - config.FavourIgnoreOverLetWild |> Option.bind (constructRuleIfEnabled FavourIgnoreOverLetWild.rule) - config.FavourTypedIgnore |> Option.bind (constructRuleIfEnabled FavourTypedIgnore.rule) - config.WildcardNamedWithAsPattern |> Option.bind (constructRuleIfEnabled WildcardNamedWithAsPattern.rule) - config.UselessBinding |> Option.bind (constructRuleIfEnabled UselessBinding.rule) - config.TupleOfWildcards |> Option.bind (constructRuleIfEnabled TupleOfWildcards.rule) - config.Indentation |> Option.bind (constructRuleIfEnabled Indentation.rule) - config.MaxCharactersOnLine |> Option.bind (constructRuleWithConfig MaxCharactersOnLine.rule) - config.TrailingWhitespaceOnLine |> Option.bind (constructRuleWithConfig TrailingWhitespaceOnLine.rule) - config.MaxLinesInFile |> Option.bind (constructRuleWithConfig MaxLinesInFile.rule) - config.TrailingNewLineInFile |> Option.bind (constructRuleIfEnabled TrailingNewLineInFile.rule) - config.NoTabCharacters |> Option.bind (constructRuleIfEnabled NoTabCharacters.rule) - config.NoPartialFunctions |> Option.bind (constructRuleWithConfig NoPartialFunctions.rule) - config.SuggestUseAutoProperty |> Option.bind (constructRuleIfEnabled SuggestUseAutoProperty.rule) - config.EnsureTailCallDiagnosticsInRecursiveFunctions |> Option.bind (constructRuleIfEnabled EnsureTailCallDiagnosticsInRecursiveFunctions.rule) - config.FavourAsKeyword |> Option.bind (constructRuleIfEnabled FavourAsKeyword.rule) - |] |> Array.choose id + Array.choose + id + [| + config.TypedItemSpacing |> Option.bind (constructRuleWithConfig TypedItemSpacing.rule) + config.TypePrefixing |> Option.bind (constructTypePrefixingRuleWithConfig TypePrefixing.rule) + config.UnionDefinitionIndentation |> Option.bind (constructRuleIfEnabled UnionDefinitionIndentation.rule) + config.ModuleDeclSpacing |> Option.bind (constructRuleIfEnabled ModuleDeclSpacing.rule) + config.ClassMemberSpacing |> Option.bind (constructRuleIfEnabled ClassMemberSpacing.rule) + config.TupleCommaSpacing |> Option.bind (constructRuleIfEnabled TupleCommaSpacing.rule) + config.TupleIndentation |> Option.bind (constructRuleIfEnabled TupleIndentation.rule) + config.TupleParentheses |> Option.bind (constructRuleIfEnabled TupleParentheses.rule) + config.PatternMatchClausesOnNewLine |> Option.bind (constructRuleIfEnabled PatternMatchClausesOnNewLine.rule) + config.PatternMatchOrClausesOnNewLine |> Option.bind (constructRuleIfEnabled PatternMatchOrClausesOnNewLine.rule) + config.PatternMatchClauseIndentation |> Option.bind (constructRuleWithConfig PatternMatchClauseIndentation.rule) + config.PatternMatchExpressionIndentation |> Option.bind (constructRuleIfEnabled PatternMatchExpressionIndentation.rule) + config.RecursiveAsyncFunction |> Option.bind (constructRuleIfEnabled RecursiveAsyncFunction.rule) + config.AvoidTooShortNames |> Option.bind (constructRuleIfEnabled AvoidTooShortNames.rule) + config.RedundantNewKeyword |> Option.bind (constructRuleIfEnabled RedundantNewKeyword.rule) + config.FavourNonMutablePropertyInitialization |> Option.bind (constructRuleIfEnabled FavourNonMutablePropertyInitialization.rule) + config.FavourReRaise |> Option.bind (constructRuleIfEnabled FavourReRaise.rule) + config.FavourStaticEmptyFields |> Option.bind (constructRuleIfEnabled FavourStaticEmptyFields.rule) + config.AsyncExceptionWithoutReturn |> Option.bind (constructRuleIfEnabled AsyncExceptionWithoutReturn.rule) + config.UnneededRecKeyword |> Option.bind (constructRuleIfEnabled UnneededRecKeyword.rule) + config.NestedStatements |> Option.bind (constructRuleWithConfig NestedStatements.rule) + config.FavourConsistentThis |> Option.bind (constructRuleWithConfig FavourConsistentThis.rule) + config.CyclomaticComplexity |> Option.bind (constructRuleWithConfig CyclomaticComplexity.rule) + config.ReimplementsFunction |> Option.bind (constructRuleIfEnabled ReimplementsFunction.rule) + config.CanBeReplacedWithComposition |> Option.bind (constructRuleIfEnabled CanBeReplacedWithComposition.rule) + config.AvoidSinglePipeOperator |> Option.bind (constructRuleIfEnabled AvoidSinglePipeOperator.rule) + config.UsedUnderscorePrefixedElements |> Option.bind (constructRuleIfEnabled UsedUnderscorePrefixedElements.rule) + config.FailwithBadUsage |> Option.bind (constructRuleIfEnabled FailwithBadUsage.rule) + config.RaiseWithSingleArgument |> Option.bind (constructRuleIfEnabled RaiseWithSingleArgument.rule) + config.FailwithWithSingleArgument |> Option.bind (constructRuleIfEnabled FailwithWithSingleArgument.rule) + config.NullArgWithSingleArgument |> Option.bind (constructRuleIfEnabled NullArgWithSingleArgument.rule) + config.InvalidOpWithSingleArgument |> Option.bind (constructRuleIfEnabled InvalidOpWithSingleArgument.rule) + config.InvalidArgWithTwoArguments |> Option.bind (constructRuleIfEnabled InvalidArgWithTwoArguments.rule) + config.FailwithfWithArgumentsMatchingFormatString |> Option.bind (constructRuleIfEnabled FailwithfWithArgumentsMatchingFormatString.rule) + config.MaxLinesInLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInLambdaFunction.rule) + config.MaxLinesInMatchLambdaFunction |> Option.bind (constructRuleWithConfig MaxLinesInMatchLambdaFunction.rule) + config.MaxLinesInValue |> Option.bind (constructRuleWithConfig MaxLinesInValue.rule) + config.MaxLinesInFunction |> Option.bind (constructRuleWithConfig MaxLinesInFunction.rule) + config.MaxLinesInMember |> Option.bind (constructRuleWithConfig MaxLinesInMember.rule) + config.MaxLinesInConstructor |> Option.bind (constructRuleWithConfig MaxLinesInConstructor.rule) + config.MaxLinesInProperty |> Option.bind (constructRuleWithConfig MaxLinesInProperty.rule) + config.MaxLinesInModule |> Option.bind (constructRuleWithConfig MaxLinesInModule.rule) + config.MaxLinesInRecord |> Option.bind (constructRuleWithConfig MaxLinesInRecord.rule) + config.MaxLinesInEnum |> Option.bind (constructRuleWithConfig MaxLinesInEnum.rule) + config.MaxLinesInUnion |> Option.bind (constructRuleWithConfig MaxLinesInUnion.rule) + config.MaxLinesInClass |> Option.bind (constructRuleWithConfig MaxLinesInClass.rule) + config.InterfaceNames |> Option.bind (constructRuleWithConfig InterfaceNames.rule) + config.GenericTypesNames |> Option.bind (constructRuleWithConfig GenericTypesNames.rule) + config.ExceptionNames |> Option.bind (constructRuleWithConfig ExceptionNames.rule) + config.TypeNames |> Option.bind (constructRuleWithConfig TypeNames.rule) + config.RecordFieldNames |> Option.bind (constructRuleWithConfig RecordFieldNames.rule) + config.EnumCasesNames |> Option.bind (constructRuleWithConfig EnumCasesNames.rule) + config.UnionCasesNames |> Option.bind (constructRuleWithConfig UnionCasesNames.rule) + config.ModuleNames |> Option.bind (constructRuleWithConfig ModuleNames.rule) + config.LiteralNames |> Option.bind (constructRuleWithConfig LiteralNames.rule) + config.NamespaceNames |> Option.bind (constructRuleWithConfig NamespaceNames.rule) + config.MemberNames |> Option.bind (constructRuleWithConfig MemberNames.rule) + config.ParameterNames |> Option.bind (constructRuleWithConfig ParameterNames.rule) + config.MeasureTypeNames |> Option.bind (constructRuleWithConfig MeasureTypeNames.rule) + config.ActivePatternNames |> Option.bind (constructRuleWithConfig ActivePatternNames.rule) + config.PublicValuesNames |> Option.bind (constructRuleWithConfig PublicValuesNames.rule) + config.NonPublicValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) + config.NonPublicValuesNames |> Option.bind (constructRuleWithConfig InternalValuesNames.rule) + config.PrivateValuesNames |> Option.bind (constructRuleWithConfig PrivateValuesNames.rule) + config.InternalValuesNames |> Option.bind (constructRuleWithConfig InternalValuesNames.rule) + config.UnnestedFunctionNames |> Option.bind (constructRuleWithConfig UnnestedFunctionNames.rule) + config.NestedFunctionNames |> Option.bind (constructRuleWithConfig NestedFunctionNames.rule) + config.MaxNumberOfItemsInTuple |> Option.bind (constructRuleWithConfig MaxNumberOfItemsInTuple.rule) + config.MaxNumberOfFunctionParameters |> Option.bind (constructRuleWithConfig MaxNumberOfFunctionParameters.rule) + config.MaxNumberOfMembers |> Option.bind (constructRuleWithConfig MaxNumberOfMembers.rule) + config.MaxNumberOfBooleanOperatorsInCondition |> Option.bind (constructRuleWithConfig MaxNumberOfBooleanOperatorsInCondition.rule) + config.FavourIgnoreOverLetWild |> Option.bind (constructRuleIfEnabled FavourIgnoreOverLetWild.rule) + config.FavourTypedIgnore |> Option.bind (constructRuleIfEnabled FavourTypedIgnore.rule) + config.WildcardNamedWithAsPattern |> Option.bind (constructRuleIfEnabled WildcardNamedWithAsPattern.rule) + config.UselessBinding |> Option.bind (constructRuleIfEnabled UselessBinding.rule) + config.TupleOfWildcards |> Option.bind (constructRuleIfEnabled TupleOfWildcards.rule) + config.Indentation |> Option.bind (constructRuleIfEnabled Indentation.rule) + config.MaxCharactersOnLine |> Option.bind (constructRuleWithConfig MaxCharactersOnLine.rule) + config.TrailingWhitespaceOnLine |> Option.bind (constructRuleWithConfig TrailingWhitespaceOnLine.rule) + config.MaxLinesInFile |> Option.bind (constructRuleWithConfig MaxLinesInFile.rule) + config.TrailingNewLineInFile |> Option.bind (constructRuleIfEnabled TrailingNewLineInFile.rule) + config.NoTabCharacters |> Option.bind (constructRuleIfEnabled NoTabCharacters.rule) + config.NoPartialFunctions |> Option.bind (constructRuleWithConfig NoPartialFunctions.rule) + config.SuggestUseAutoProperty |> Option.bind (constructRuleIfEnabled SuggestUseAutoProperty.rule) + config.EnsureTailCallDiagnosticsInRecursiveFunctions |> Option.bind (constructRuleIfEnabled EnsureTailCallDiagnosticsInRecursiveFunctions.rule) + config.FavourAsKeyword |> Option.bind (constructRuleIfEnabled FavourAsKeyword.rule) + |] findDeprecation config deprecatedAllRules allRules diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index fcdf95fb0..bf9a2a986 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -64,7 +64,7 @@ module Lint = let getFailureReason (fSharpDiagnostic:FSharpDiagnostic) = $"failed to parse file {fSharpDiagnostic.FileName}, message: {fSharpDiagnostic.Message}" - String.Join(", ", failures |> Array.map getFailureReason) + String.Join(", ", Array.map getFailureReason failures) | ParseFile.AbortedTypeCheck -> "Type check failed. You might want to build your solution/project first and try again." match this with @@ -153,8 +153,9 @@ module Lint = indentationRuleState <- Indentation.ContextBuilder.builder indentationRuleState astNode.Actual noTabCharactersRuleState <- NoTabCharacters.ContextBuilder.builder noTabCharactersRuleState astNode.Actual - config.Rules - |> Array.collect (fun rule -> runAstNodeRule rule astNodeParams) + Array.collect + (fun (rule: RuleMetadata) -> runAstNodeRule rule astNodeParams) + config.Rules // Collect suggestions for AstNode rules, and build context for following rules. let astNodeSuggestions = @@ -166,7 +167,7 @@ module Lint = { IndentationRuleContext = indentationRuleState NoTabCharactersRuleContext = noTabCharactersRuleState } - config.Rules |> Array.iter (fun rule -> rule.RuleConfig.Cleanup()) + Array.iter (fun (rule: RuleMetadata) -> rule.RuleConfig.Cleanup()) config.Rules (astNodeSuggestions, context) type RunLineRulesConfig = @@ -192,21 +193,22 @@ module Lint = } let indentationError = - config.LineRules.IndentationRule - |> Option.map (fun rule -> runLineRuleWithContext rule config.Context.IndentationRuleContext lineParams) + Option.map + (fun rule -> runLineRuleWithContext rule config.Context.IndentationRuleContext lineParams) + config.LineRules.IndentationRule let noTabCharactersError = - config.LineRules.NoTabCharactersRule - |> Option.map (fun rule -> runLineRuleWithContext rule config.Context.NoTabCharactersRuleContext lineParams) + Option.map + (fun rule -> runLineRuleWithContext rule config.Context.NoTabCharactersRuleContext lineParams) + config.LineRules.NoTabCharactersRule let lineErrors = - config.LineRules.GenericLineRules - |> Array.collect (fun rule -> runLineRule rule lineParams) + Array.collect (fun rule -> runLineRule rule lineParams) config.LineRules.GenericLineRules [| - indentationError |> Option.toArray - noTabCharactersError |> Option.toArray - lineErrors |> Array.singleton + Option.toArray indentationError + Option.toArray noTabCharactersError + Array.singleton lineErrors |] config.FileContent @@ -242,8 +244,8 @@ module Lint = [| enabledRules.LineRules.IndentationRule |> Option.map (fun rule -> rule.Name) |> Option.toArray enabledRules.LineRules.NoTabCharactersRule |> Option.map (fun rule -> rule.Name) |> Option.toArray - enabledRules.LineRules.GenericLineRules |> Array.map (fun rule -> rule.Name) - enabledRules.AstNodeRules |> Array.map (fun rule -> rule.Name) + Array.map (fun rule -> rule.Name) enabledRules.LineRules.GenericLineRules + Array.map (fun rule -> rule.Name) enabledRules.AstNodeRules |] |> Array.concat |> Set.ofArray let suppressionInfo = Suppression.parseSuppressionInfo allRuleNames (Array.toList lines) @@ -307,7 +309,7 @@ module Lint = with | exn -> Failed(fileInfo.File, exn) |> lintInfo.ReportLinterProgress - ReachedEnd(fileInfo.File, fileWarnings |> Seq.toList) |> lintInfo.ReportLinterProgress + ReachedEnd(fileInfo.File, Seq.toList fileWarnings) |> lintInfo.ReportLinterProgress let private runProcess (workingDir:string) (exePath:string) (args:string) = let psi = @@ -453,7 +455,7 @@ module Lint = let warningReceived (warning:Suggestion.LintWarning) = lintWarnings.AddLast warning |> ignore> - optionalParams.ReceivedWarning |> Option.iter (fun func -> func warning) + Option.iter (fun func -> func warning) optionalParams.ReceivedWarning let checker = FSharpChecker.Create(keepAssemblyContents=true) @@ -476,7 +478,7 @@ module Lint = |> List.filter (not << isIgnoredFile) |> List.map (fun file -> ParseFile.parseFile file checker (Some projectOptions)) - let failedFiles = parsedFiles |> List.choose getFailedFiles + let failedFiles = List.choose getFailedFiles parsedFiles if List.isEmpty failedFiles then parsedFiles @@ -563,7 +565,7 @@ module Lint = let warningReceived (warning:Suggestion.LintWarning) = lintWarnings.AddLast warning |> ignore> - optionalParams.ReceivedWarning |> Option.iter (fun func -> func warning) + Option.iter (fun func -> func warning) optionalParams.ReceivedWarning let lintInformation = { Configuration = config CancellationToken = optionalParams.CancellationToken @@ -605,7 +607,7 @@ module Lint = let warningReceived (warning:Suggestion.LintWarning) = lintWarnings.AddLast warning |> ignore> - optionalParams.ReceivedWarning |> Option.iter (fun func -> func warning) + Option.iter (fun func -> func warning) optionalParams.ReceivedWarning let lintInformation = { Configuration = config diff --git a/src/FSharpLint.Core/Framework/Ast.fs b/src/FSharpLint.Core/Framework/Ast.fs index 09037aeeb..a290b4b68 100644 --- a/src/FSharpLint.Core/Framework/Ast.fs +++ b/src/FSharpLint.Core/Framework/Ast.fs @@ -42,8 +42,7 @@ module Ast = /// Concatenates the nested-list structure of `SynAttributes` into a `SynAttribute list` to keep other code /// mostly unchanged. let extractAttributes (attrs:SynAttributes) = - attrs - |> List.collect (fun attrList -> attrList.Attributes) + List.collect (fun (attrList: SynAttributeList) -> attrList.Attributes) attrs /// Inlines pipe operators to give a flat function application expression /// e.g. `x |> List.map id` to `List.map id x`. @@ -94,8 +93,11 @@ module Ast = | IsCurriedLambda(parameter, curriedLambda) -> getLambdaParametersAndExpression (parameter::parameters) curriedLambda | SynExpr.Lambda(_, _, parameter, body, _, _, _) -> - { Arguments = parameter::parameters |> List.rev - Body = removeAutoGeneratedMatchesFromLambda body } |> Some + Some + { + Arguments = parameter :: parameters |> List.rev + Body = removeAutoGeneratedMatchesFromLambda body + } | _ -> None match lambda with @@ -128,13 +130,13 @@ module Ast = let inline private moduleDeclarationChildren node add = match node with | SynModuleDecl.NestedModule(componentInfo, _, moduleDeclarations, _, _, _) -> - moduleDeclarations |> List.revIter (ModuleDeclaration >> add) + List.revIter (ModuleDeclaration >> add) moduleDeclarations add <| ComponentInfo componentInfo - | SynModuleDecl.Let(_, bindings, _) -> bindings |> List.revIter (Binding >> add) + | SynModuleDecl.Let(_, bindings, _) -> List.revIter (Binding >> add) bindings | SynModuleDecl.Expr(expression, _) -> add <| Expression expression - | SynModuleDecl.Types(typeDefinitions, _) -> typeDefinitions |> List.revIter (TypeDefinition >> add) + | SynModuleDecl.Types(typeDefinitions, _) -> List.revIter (TypeDefinition >> add) typeDefinitions | SynModuleDecl.Exception(SynExceptionDefn.SynExceptionDefn(repr, _, members, _), _) -> - members |> List.revIter (MemberDefinition >> add) + List.revIter (MemberDefinition >> add) members add <| ExceptionRepresentation repr | SynModuleDecl.NamespaceFragment(moduleOrNamespace) -> add <| ModuleOrNamespace moduleOrNamespace | SynModuleDecl.Open(_) @@ -171,7 +173,7 @@ module Ast = | SynType.Array(_, synType, _) -> add <| Type synType | SynType.StaticConstantExpr(expression, _) -> add <| Expression expression | SynType.AnonRecd (_, typeNames, _) -> - typeNames |> List.revIter (snd >> Type >> add) + List.revIter (snd >> Type >> add) typeNames | SynType.Paren(innerType, _) -> add <| Type innerType | SynType.Intersection(synTyparOpt, types, _, _) -> @@ -199,9 +201,9 @@ module Ast = | SynMemberDefn.ImplicitInherit(synType, expression, _, _, _) -> add <| Expression expression add <| Type synType - | SynMemberDefn.LetBindings(bindings, _, _, _) -> bindings |> List.revIter (Binding >> add) + | SynMemberDefn.LetBindings(bindings, _, _, _) -> List.revIter (Binding >> add) bindings | SynMemberDefn.Interface(synType, _, Some(members), _) -> - members |> List.revIter (MemberDefinition >> add) + List.revIter (MemberDefinition >> add) members add <| Type synType | SynMemberDefn.Interface(synType, _, None, _) | SynMemberDefn.Inherit(Some synType, _, _, _) -> add <| Type synType @@ -216,8 +218,8 @@ module Ast = | SynMemberDefn.AutoProperty(_, _, _, None, _, _, _, _, _, expression, _, _) -> add <| Expression expression | SynMemberDefn.GetSetMember(memberDefnForGet, memberDefnForSet, _, _) -> - memberDefnForGet |> Option.iter (Binding >> add) - memberDefnForSet |> Option.iter (Binding >> add) + Option.iter (Binding >> add) memberDefnForGet + Option.iter (Binding >> add) memberDefnForSet let inline private patternChildren node add = match node with @@ -235,7 +237,7 @@ module Ast = | SynPat.Attrib(pattern, _, _) | SynPat.Paren(pattern, _) -> add <| Pattern pattern | SynPat.Named(_) -> () - | SynPat.Record(patternsAndIdentifier, _) -> patternsAndIdentifier |> List.revIter (fun (_, _, pattern) -> pattern |> Pattern |> add) + | SynPat.Record(patternsAndIdentifier, _) -> List.revIter (fun (_, _, pattern) -> pattern |> Pattern |> add) patternsAndIdentifier | SynPat.Const(_) | SynPat.Wild(_) | SynPat.FromParseError(_) @@ -289,14 +291,14 @@ module Ast = | SynExpr.Typed(expression, synType, _) -> addMany [Type synType; Expression expression] | SynExpr.Tuple(_, expressions, _, _) - | SynExpr.ArrayOrList(_, expressions, _) -> expressions |> List.revIter (Expression >> add) + | SynExpr.ArrayOrList(_, expressions, _) -> List.revIter (Expression >> add) expressions | SynExpr.Record(_, Some(expr, _), _, _) -> add <| Expression expr | SynExpr.Record(_, None, _, _) -> () | SynExpr.AnonRecd(_, Some (expr,_), _, _, _) -> add <| Expression expr | SynExpr.AnonRecd(_, None, _, _, _) -> () | SynExpr.ObjExpr(synType, _, _, bindings, _, _, _, _) -> - bindings |> List.revIter (Binding >> add) + List.revIter (Binding >> add) bindings add <| Type synType | SynExpr.DotNamedIndexedPropertySet(expression, _, expression1, expression2, _) | SynExpr.For(_, _, _, _, expression, _, expression1, expression2, _) -> @@ -304,21 +306,21 @@ module Ast = | SynExpr.LetOrUseBang(_, _, _, pattern, rightHandSide, andBangs, leftHandSide, _, _) -> addMany [Expression rightHandSide; Expression leftHandSide] // TODO: is the the correct way to handle the new `and!` syntax? - andBangs |> List.iter (fun (SynExprAndBang(_, _, _, pattern, body, _, _)) -> + List.iter (fun (SynExprAndBang(_, _, _, pattern, body, _, _)) -> addMany [Expression body; Pattern pattern] - ) + ) andBangs add <| Pattern pattern | SynExpr.ForEach(_, _, _, _, pattern, expression, expression1, _) -> addMany [Expression expression1; Expression expression; Pattern pattern] | SynExpr.MatchLambda(_, _, matchClauses, _, _) -> - matchClauses |> List.revIter (Match >> add) + List.revIter (Match >> add) matchClauses | SynExpr.TryWith(expression, matchClauses, _, _, _, _) | SynExpr.MatchBang(_, expression, matchClauses, _, _) | SynExpr.Match(_, expression, matchClauses, _, _) -> - matchClauses |> List.revIter (Match >> add) + List.revIter (Match >> add) matchClauses add <| Expression expression | SynExpr.TypeApp(expression, _, types, _, _, _, _) -> - types |> List.revIter (Type >> add) + List.revIter (Type >> add) types add <| Expression expression | SynExpr.New(_, synType, expression, _) | SynExpr.TypeTest(expression, synType, _) @@ -327,21 +329,21 @@ module Ast = addMany [Type synType; Expression expression] | SynExpr.LetOrUse(_, _, bindings, expression, _, _) -> add <| Expression expression - bindings |> List.revIter (Binding >> add) + List.revIter (Binding >> add) bindings | SynExpr.Ident(ident) -> add <| Identifier([ident.idText], ident.idRange) | SynExpr.LongIdent(_, SynLongIdent(ident, _, _), _, range) -> - add <| Identifier(ident |> List.map (fun identifier -> identifier.idText), range) + add <| Identifier(List.map (fun (identifier: Ident) -> identifier.idText) ident, range) | SynExpr.IfThenElse(cond, body, Some(elseExpr), _, _, _, _) -> addMany [Else elseExpr; Expression body; Expression cond] | SynExpr.IfThenElse(cond, body, None, _, _, _, _) -> addMany [Expression body; Expression cond] | SynExpr.InterpolatedString(contents, _, range) -> - contents - |> List.iter ( + List.iter ( function | SynInterpolatedStringPart.String _ -> () | SynInterpolatedStringPart.FillExpr (expr, _ident) -> add <| Expression expr - ) + ) + contents (* | SynExpr.ImplicitZero(_) | SynExpr.Null(_) @@ -375,9 +377,9 @@ module Ast = let inline private typeSimpleRepresentationChildren node add = match node with - | SynTypeDefnSimpleRepr.Union(_, unionCases, _) -> unionCases |> List.revIter (UnionCase >> add) - | SynTypeDefnSimpleRepr.Enum(enumCases, _) -> enumCases |> List.revIter (EnumCase >> add) - | SynTypeDefnSimpleRepr.Record(_, fields, _) -> fields |> List.revIter (Field >> add) + | SynTypeDefnSimpleRepr.Union(_, unionCases, _) -> List.revIter (UnionCase >> add) unionCases + | SynTypeDefnSimpleRepr.Enum(enumCases, _) -> List.revIter (EnumCase >> add) enumCases + | SynTypeDefnSimpleRepr.Record(_, fields, _) -> List.revIter (Field >> add) fields | SynTypeDefnSimpleRepr.TypeAbbrev(_, synType, _) -> add <| Type synType | SynTypeDefnSimpleRepr.Exception(exceptionRepr) -> add <| ExceptionRepresentation exceptionRepr | SynTypeDefnSimpleRepr.General(_) @@ -417,7 +419,7 @@ module Ast = let inline private typeRepresentationChildren node add = match node with | SynTypeDefnRepr.ObjectModel(_, members, _) -> - members |> List.revIter (MemberDefinition >> add) + List.revIter (MemberDefinition >> add) members | SynTypeDefnRepr.Simple(typeSimpleRepresentation, _) -> add <| TypeSimpleRepresentation typeSimpleRepresentation | SynTypeDefnRepr.Exception(exceptionRepr) -> @@ -426,7 +428,7 @@ module Ast = let inline private unionCaseChildren node add = match node with | SynUnionCase(caseType=(SynUnionCaseKind.Fields fields)) -> - fields |> List.revIter (Field >> add) + List.revIter (Field >> add) fields | SynUnionCase(caseType=(SynUnionCaseKind.FullType (fullType, _))) -> add (Type fullType) @@ -435,15 +437,15 @@ module Ast = match node with | ModuleDeclaration(moduleDecl) -> moduleDeclarationChildren moduleDecl add | ModuleOrNamespace(SynModuleOrNamespace(_, _, _, moduleDeclarations, _, _, _, _, _)) -> - moduleDeclarations |> List.revIter (ModuleDeclaration >> add) + List.revIter (ModuleDeclaration >> add) moduleDeclarations | Binding(SynBinding(_, _, _, _, _, _, _, pattern, _, expression, _, _, _)) -> add <| Expression expression add <| Pattern pattern | ExceptionRepresentation(SynExceptionDefnRepr.SynExceptionDefnRepr(_, unionCase, _, _, _, _)) -> add <| UnionCase unionCase | TypeDefinition(SynTypeDefn(componentInfo, typeRepresentation, members, implicitCtor, _, _)) -> - implicitCtor |> Option.iter (MemberDefinition >> add) - members |> List.revIter (MemberDefinition >> add) + Option.iter (MemberDefinition >> add) implicitCtor + List.revIter (MemberDefinition >> add) members add <| TypeRepresentation typeRepresentation add <| ComponentInfo componentInfo | TypeSimpleRepresentation(value) -> typeSimpleRepresentationChildren value add @@ -457,10 +459,10 @@ module Ast = | LambdaArg(value) | SimplePatterns(value) -> simplePatternsChildren value add | InterfaceImplementation(SynInterfaceImpl(synType, _, bindings, _, _)) -> - bindings |> List.revIter (Binding >> add) + List.revIter (Binding >> add) bindings add <| Type synType | TypeRepresentation value -> typeRepresentationChildren value add - | FuncApp(exprs, _) -> exprs |> List.revIter (Expression >> add) + | FuncApp(exprs, _) -> List.revIter (Expression >> add) exprs | Lambda({ Arguments = args; Body = body }, _) -> add <| LambdaBody(body) args |> List.revIter (LambdaArg >> add) diff --git a/src/FSharpLint.Core/Framework/AstInfo.fs b/src/FSharpLint.Core/Framework/AstInfo.fs index d3c431280..6064a4029 100644 --- a/src/FSharpLint.Core/Framework/AstInfo.fs +++ b/src/FSharpLint.Core/Framework/AstInfo.fs @@ -28,61 +28,64 @@ module AstInfo = | None -> Function let operatorIdentifiers = - [ "op_Nil" - "op_ColonColon" - "op_Addition" - "op_Splice" - "op_SpliceUntyped" - "op_Increment" - "op_Decrement" - "op_Subtraction" - "op_Multiply" - "op_Exponentiation" - "op_Division" - "op_Append" - "op_Concatenate" - "op_Modulus" - "op_BitwiseAnd" - "op_BitwiseOr" - "op_ExclusiveOr" - "op_LeftShift" - "op_LogicalNot" - "op_RightShift" - "op_UnaryPlus" - "op_UnaryNegation" - "op_AddressOf" - "op_IntegerAddressOf" - "op_BooleanAnd" - "op_BooleanOr" - "op_LessThanOrEqual" - "op_Equality" - "op_Inequality" - "op_GreaterThanOrEqual" - "op_LessThan" - "op_GreaterThan" - "op_PipeRight" - "op_PipeRight2" - "op_PipeRight3" - "op_PipeLeft" - "op_PipeLeft2" - "op_PipeLeft3" - "op_Dereference" - "op_ComposeRight" - "op_ComposeLeft" - "op_TypedQuotationUnicode" - "op_ChevronsBar" - "op_Quotation" - "op_QuotationUntyped" - "op_AdditionAssignment" - "op_SubtractionAssignment" - "op_MultiplyAssignment" - "op_DivisionAssignment" - "op_Range" - "op_RangeStep" - "op_Dynamic" - "op_DynamicAssignment" - "op_ArrayLookup" - "op_ArrayAssign" ] |> Set.ofList + Set.ofList + [ + "op_Nil" + "op_ColonColon" + "op_Addition" + "op_Splice" + "op_SpliceUntyped" + "op_Increment" + "op_Decrement" + "op_Subtraction" + "op_Multiply" + "op_Exponentiation" + "op_Division" + "op_Append" + "op_Concatenate" + "op_Modulus" + "op_BitwiseAnd" + "op_BitwiseOr" + "op_ExclusiveOr" + "op_LeftShift" + "op_LogicalNot" + "op_RightShift" + "op_UnaryPlus" + "op_UnaryNegation" + "op_AddressOf" + "op_IntegerAddressOf" + "op_BooleanAnd" + "op_BooleanOr" + "op_LessThanOrEqual" + "op_Equality" + "op_Inequality" + "op_GreaterThanOrEqual" + "op_LessThan" + "op_GreaterThan" + "op_PipeRight" + "op_PipeRight2" + "op_PipeRight3" + "op_PipeLeft" + "op_PipeLeft2" + "op_PipeLeft3" + "op_Dereference" + "op_ComposeRight" + "op_ComposeLeft" + "op_TypedQuotationUnicode" + "op_ChevronsBar" + "op_Quotation" + "op_QuotationUntyped" + "op_AdditionAssignment" + "op_SubtractionAssignment" + "op_MultiplyAssignment" + "op_DivisionAssignment" + "op_Range" + "op_RangeStep" + "op_Dynamic" + "op_DynamicAssignment" + "op_ArrayLookup" + "op_ArrayAssign" + ] /// Operator identifiers can be made up of "op_" followed by a sequence of operators from this list. let operators = @@ -116,7 +119,7 @@ module AstInfo = if Seq.isEmpty str then true else - let operator = operators |> List.tryFind (fun op -> str.StartsWith(op)) + let operator = List.tryFind (fun (op: string) -> str.StartsWith(op)) operators match operator with | Some(operator) -> str.Substring(operator.Length) |> isSequenceOfOperators @@ -124,7 +127,7 @@ module AstInfo = /// Is an identifier an operator overload? let isOperator (identifier:string) = - if operatorIdentifiers |> Set.contains identifier then + if Set.contains identifier operatorIdentifiers then true else if identifier.StartsWith("op_") && identifier.Length > 3 then diff --git a/src/FSharpLint.Core/Framework/HintParser.fs b/src/FSharpLint.Core/Framework/HintParser.fs index 19a02bdd5..0744a1127 100644 --- a/src/FSharpLint.Core/Framework/HintParser.fs +++ b/src/FSharpLint.Core/Framework/HintParser.fs @@ -226,7 +226,7 @@ module HintParser = | HintExpr(Expression.FunctionApplication(exprs)) | HintExpr(Expression.Tuple(exprs)) | HintExpr(Expression.List(exprs)) - | HintExpr(Expression.Array(exprs)) -> exprs |> List.map HintExpr + | HintExpr(Expression.Array(exprs)) -> List.map HintExpr exprs | HintExpr(Expression.If(ifCond, bodyExpr, Some(elseExpr))) -> [HintExpr ifCond; HintExpr bodyExpr; HintExpr elseExpr] | HintExpr(Expression.If(ifCond, bodyExpr, None)) -> @@ -241,7 +241,7 @@ module HintParser = | HintPat(Pattern.Or(lhs, rhs)) -> [HintPat lhs; HintPat rhs] | HintPat(Pattern.Array(patterns)) | HintPat(Pattern.List(patterns)) - | HintPat(Pattern.Tuple(patterns)) -> patterns |> List.map HintPat + | HintPat(Pattern.Tuple(patterns)) -> List.map HintPat patterns | HintPat(Pattern.Parentheses(pattern)) -> [HintPat pattern] | HintPat(Pattern.Variable(_)) | HintPat(Pattern.Identifier(_)) @@ -301,7 +301,7 @@ module HintParser = depthFirstTraversal hint.MatchedNode 0 - (nodes |> Seq.toList, hint) + (Seq.toList nodes, hint) type private HintList = (HintNode * int) list * Hint @@ -480,16 +480,19 @@ module HintParser = char(System.Convert.ToInt32(dec, 10)) let private escapeMap = - [ ('"', '\"') - ('\\', '\\') - ('\'', '\'') - ('n', '\n') - ('t', '\t') - ('b', '\b') - ('r', '\r') - ('a', '\a') - ('f', '\f') - ('v', '\v') ] |> Map.ofList + Map.ofList + [ + ('"', '\"') + ('\\', '\\') + ('\'', '\'') + ('n', '\n') + ('t', '\t') + ('b', '\b') + ('r', '\r') + ('a', '\a') + ('f', '\f') + ('v', '\v') + ] let private pescapechar: Parser = skipChar '\\' @@ -828,7 +831,7 @@ module HintParser = .>> skipString "then" .>>. pexpression .>>. opt (skipString "else" >>. pexpression) - |>> fun ((condition, expr), elseExpr) -> Expression.If(condition, expr, elseExpr |> Option.map Expression.Else) + |>> fun ((condition, expr), elseExpr) -> Expression.If(condition, expr, Option.map Expression.Else elseExpr) let plambda: Parser = let plambdastart: Parser = @@ -847,7 +850,7 @@ module HintParser = let! body = plambdaend return Expression.Lambda - (arguments |> List.map (Expression.LambdaArg >> LambdaArg), + (List.map (Expression.LambdaArg >> LambdaArg) arguments, LambdaBody(Expression.LambdaBody(body))) } diff --git a/src/FSharpLint.Core/Framework/ParseFile.fs b/src/FSharpLint.Core/Framework/ParseFile.fs index 8f92780f8..ac4208a36 100644 --- a/src/FSharpLint.Core/Framework/ParseFile.fs +++ b/src/FSharpLint.Core/Framework/ParseFile.fs @@ -45,10 +45,13 @@ module ParseFile = match checkFileAnswer with | FSharpCheckFileAnswer.Succeeded(typeCheckResults) -> - { Text = source - Ast = parseResults.ParseTree - TypeCheckResults = Some(typeCheckResults) - File = file } |> Success + Success + { + Text = source + Ast = parseResults.ParseTree + TypeCheckResults = Some(typeCheckResults) + File = file + } | FSharpCheckFileAnswer.Aborted -> Failed(AbortedTypeCheck) let getProjectOptionsFromScript (checker:FSharpChecker) file (source:string) = diff --git a/src/FSharpLint.Core/Framework/Suppression.fs b/src/FSharpLint.Core/Framework/Suppression.fs index 6a5f1b316..22fe49dfa 100644 --- a/src/FSharpLint.Core/Framework/Suppression.fs +++ b/src/FSharpLint.Core/Framework/Suppression.fs @@ -29,7 +29,7 @@ let private extractRules (rules:Set) (str:string) = /// Parses a given file to find lines containing rule suppressions. let parseSuppressionInfo (rules:Set) (lines:string list) = - let rules = rules |> Set.map (fun rule -> rule.ToLowerInvariant()) + let rules = Set.map (fun (rule: String) -> rule.ToLowerInvariant()) rules let choose lineNum line = let matched = Regex.Match (line, ".*fsharplint:([a-z\-]+)\s*(.*)$") @@ -77,7 +77,7 @@ let isSuppressed (rule:String) (line:int) (lineSuppressions:LineSuppression list Set.union disabledRules rules else disabledRules - lineSuppression.Suppressions |> List.fold innerFold disabledRules + List.fold innerFold disabledRules lineSuppression.Suppressions let disabledRules = lineSuppressions diff --git a/src/FSharpLint.Core/Framework/Utilities.fs b/src/FSharpLint.Core/Framework/Utilities.fs index 55945c6fb..188f4145a 100644 --- a/src/FSharpLint.Core/Framework/Utilities.fs +++ b/src/FSharpLint.Core/Framework/Utilities.fs @@ -37,7 +37,7 @@ module ExpressionUtilities = let getSymbolFromIdent (checkFile:FSharpCheckFileResults option) expr = match (checkFile, expr) with | Some(checkFile), Identifier(ident, range) -> - let identNames = ident |> List.map (fun identifier -> identifier.idText) + let identNames = List.map (fun (identifier: Ident) -> identifier.idText) ident checkFile.GetSymbolUseAtLocation( range.StartLine, @@ -81,7 +81,7 @@ module ExpressionUtilities = /// Converts a LongIdentWithDots to a String. let longIdentWithDotsToString (lidwd: SynLongIdent) = - lidwd.LongIdent |> longIdentToString + longIdentToString lidwd.LongIdent /// Tries to find the source code within a given range. let tryFindTextOfRange (range:Range) (text:string) = @@ -112,7 +112,7 @@ module ExpressionUtilities = /// Converts a list of type args to its string representation. let typeArgsToString (text:string) (typeArgs:SynType list) = - let typeStrings = typeArgs |> List.choose (synTypeToString text) + let typeStrings = List.choose (synTypeToString text) typeArgs if typeStrings.Length = typeArgs.Length then typeStrings |> String.concat "," |> Some else None diff --git a/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs b/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs index 521515201..f169e846b 100644 --- a/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs +++ b/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs @@ -36,19 +36,20 @@ let rec checkExpression (expression: SynExpr) (range: range) = match elseExpr with | Some elseExpression -> - checkThen - |> Array.append (checkExpression elseExpression range) + Array.append (checkExpression elseExpression range) checkThen | None -> checkThen | SynExpr.App (_, _, SynExpr.Ident failwithId, _, _) when failwithId.idText = "failwith" || failwithId.idText = "failwithf" || failwithId.idText = "raise" -> - { Range = range - Message = Resources.GetString "RulesAsyncExceptionWithoutReturn" - SuggestedFix = None - TypeChecks = List.Empty } - |> Array.singleton + Array.singleton + { + Range = range + Message = Resources.GetString "RulesAsyncExceptionWithoutReturn" + SuggestedFix = None + TypeChecks = List.Empty + } | SynExpr.App (_, _, funcExpr, _, range) -> checkExpression funcExpr range | SynExpr.LetOrUse (_, _, _, body, range, _) -> @@ -65,9 +66,13 @@ let runner args = | _ -> Array.empty let rule = - { Name = "AsyncExceptionWithoutReturn" - Identifier = Identifiers.AsyncExceptionWithoutReturn - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "AsyncExceptionWithoutReturn" + Identifier = Identifiers.AsyncExceptionWithoutReturn + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs b/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs index 3e985568f..545f9fbae 100644 --- a/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs +++ b/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs @@ -10,12 +10,13 @@ open FSharpLint.Framework.Rules let runner (args: AstNodeRuleParams) = let errors range suggestedFix = - { - Range = range - Message = String.Format(Resources.GetString ("RulesAvoidSinglePipeOperator")) - SuggestedFix = suggestedFix - TypeChecks = List.Empty - } |> Array.singleton + Array.singleton + { + Range = range + Message = String.Format(Resources.GetString ("RulesAvoidSinglePipeOperator")) + SuggestedFix = suggestedFix + TypeChecks = List.Empty + } let rec checkExpr (expr: SynExpr) (outerArgExpr: SynExpr) (range: FSharp.Compiler.Text.range) (parentList: AstNode list): WarningDetails array = let checkParentPiped (expr: AstNode) = @@ -74,7 +75,13 @@ let runner (args: AstNodeRuleParams) = let rule = - { Name = "AvoidSinglePipeOperator" - Identifier = Identifiers.AvoidSinglePipeOperator - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "AvoidSinglePipeOperator" + Identifier = Identifiers.AvoidSinglePipeOperator + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/AvoidTooShortNames.fs b/src/FSharpLint.Core/Rules/Conventions/AvoidTooShortNames.fs index b54fb0ad5..5c7f04171 100644 --- a/src/FSharpLint.Core/Rules/Conventions/AvoidTooShortNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/AvoidTooShortNames.fs @@ -59,7 +59,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = | AstNode.Expression(SynExpr.Lambda(_, _, lambdaArgs, _, _, _, _)) -> let lambdaIdent = FunctionReimplementation.getLambdaParamIdent lambdaArgs match lambdaIdent with - | Some ident -> (ident, ident.idText, None) |> Array.singleton + | Some ident -> Array.singleton (ident, ident.idText, None) | None -> Array.empty | AstNode.Match(SynMatchClause(namePattern, _, _, _, _, _)) -> getParameterWithBelowMinimumLength [namePattern] @@ -75,10 +75,10 @@ let private getIdentifiers (args:AstNodeRuleParams) = result | _ -> Array.empty | SynPat.Named(SynIdent(identifier, _), _, _, _) when isIdentifierTooShort identifier.idText -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | _ -> Array.empty | AstNode.Field(SynField(_, _, Some identifier, _, _, _, _, _, _)) when isIdentifierTooShort identifier.idText -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | AstNode.TypeDefinition(SynTypeDefn(componentInfo, _typeDef, _, _, _, _)) -> let checkTypes types = seq { @@ -93,19 +93,23 @@ let private getIdentifiers (args:AstNodeRuleParams) = | Some types -> checkTypes types.TyparDecls |> Array.ofSeq | None -> Array.empty | AstNode.Type(SynType.Var(SynTypar(id, _, _), _)) when isIdentifierTooShort id.idText -> - (id, id.idText, None) |> Array.singleton + Array.singleton (id, id.idText, None) | _ -> Array.empty let runner (args:AstNodeRuleParams) = getIdentifiers args |> Array.collect (fun (identifier, idText, typeCheck) -> let suggestions = checkIdentifier identifier idText - suggestions |> Array.map (fun suggestion -> { suggestion with TypeChecks = Option.toList typeCheck })) + Array.map (fun suggestion -> { suggestion with TypeChecks = Option.toList typeCheck }) suggestions) let rule = - { Name = "AvoidTooShortNames" - Identifier = Identifiers.AvoidTooShortNames - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "AvoidTooShortNames" + Identifier = Identifiers.AvoidTooShortNames + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs index c0a68a0bd..81e78db32 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs @@ -29,17 +29,15 @@ let private checkForNamedPatternEqualsConstant (args:AstNodeRuleParams) pattern ExpressionUtilities.tryFindTextOfRange constRange args.FileContent |> Option.bind (fun constText -> - - lazy (Some { FromText = text; FromRange = fromRange; ToText = $"{constText} as {ident.idText}"}) - |> Some + Some (lazy (Some { FromText = text; FromRange = fromRange; ToText = $"{constText} as {ident.idText}"})) ) - ) - { Range = fromRange - Message = Resources.GetString("RulesFavourAsKeyword") - SuggestedFix = suggestedFix - TypeChecks = List.Empty } |> Array.singleton + Array.singleton + { Range = fromRange + Message = Resources.GetString("RulesFavourAsKeyword") + SuggestedFix = suggestedFix + TypeChecks = List.Empty } | _ -> Array.empty | _ -> Array.empty @@ -52,7 +50,7 @@ let private runner (args:AstNodeRuleParams) = | _ -> Array.empty let rule = - { Name = "FavourAsKeyword" - Identifier = Identifiers.FavourAsKeyword - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { Name = "FavourAsKeyword" + Identifier = Identifiers.FavourAsKeyword + RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs index 5e41504ec..4a40f86fa 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourIgnoreOverLetWild.fs @@ -16,12 +16,13 @@ let private checkForBindingToAWildcard pattern range fileContent (expr: SynExpr) match ExpressionUtilities.tryFindTextOfRange expr.Range fileContent with | Some exprText -> if findWildAndIgnoreParens pattern then - { Range = range - Message = Resources.GetString("RulesFavourIgnoreOverLetWildError") - SuggestedFix = Some (lazy (Some({ FromRange = letBindingRange - FromText = fileContent - ToText = sprintf "(%s) |> ignore" exprText }))) - TypeChecks = List.Empty } |> Array.singleton + Array.singleton + { Range = range + Message = Resources.GetString("RulesFavourIgnoreOverLetWildError") + SuggestedFix = Some (lazy (Some({ FromRange = letBindingRange + FromText = fileContent + ToText = sprintf "(%s) |> ignore" exprText }))) + TypeChecks = List.Empty } else Array.empty | None -> Array.empty @@ -44,7 +45,13 @@ let private runner (args:AstNodeRuleParams) = /// Checks if any code uses 'let _ = ...' and suggests to use the ignore function. let rule = - { Name = "FavourIgnoreOverLetWild" - Identifier = Identifiers.FavourIgnoreOverLetWild - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FavourIgnoreOverLetWild" + Identifier = Identifiers.FavourIgnoreOverLetWild + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs index c4516ba55..ce5bec3cf 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/FavourTypedIgnore.fs @@ -52,9 +52,13 @@ let private runner (args: AstNodeRuleParams) = /// Checks if any code uses untyped ignore let rule = - { Name = "FavourTypedIgnore" - Identifier = Identifiers.FavourTypedIgnore - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FavourTypedIgnore" + Identifier = Identifiers.FavourTypedIgnore + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs index 7888fe48d..87821f70f 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/TupleOfWildcards.fs @@ -14,7 +14,7 @@ let private checkTupleOfWildcards fileContents pattern identifier identifierRang | _ -> false let constructorString numberOfWildcards = - let constructorName = identifier |> String.concat "." + let constructorName = String.concat "." identifier let arguments = Array.create numberOfWildcards "_" |> String.concat ", " if numberOfWildcards = 1 then $"%s{constructorName} _" @@ -29,13 +29,13 @@ let private checkTupleOfWildcards fileContents pattern identifier identifierRang let error = String.Format(errorFormat, refactorFrom, refactorTo) let suggestedFix = lazy( Some { SuggestedFix.FromRange = identifierRange; FromText = fileContents; ToText = refactorTo }) - { - Range = range - Message = error - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = range + Message = error + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } | _ -> Array.empty let private isTupleMemberArgs breadcrumbs tupleRange = @@ -65,7 +65,13 @@ let private runner (args:AstNodeRuleParams) = | _ -> Array.empty let rule = - { Name = "TupleOfWildcards" - Identifier = Identifiers.TupleOfWildcards - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "TupleOfWildcards" + Identifier = Identifiers.TupleOfWildcards + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs index 904f05af5..9b9190b71 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs @@ -63,8 +63,13 @@ let private runner (args:AstNodeRuleParams) = Array.empty let rule = - { Name = "UselessBinding" - Identifier = Identifiers.UselessBinding - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule - + AstNodeRule + { + Name = "UselessBinding" + Identifier = Identifiers.UselessBinding + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs index 9e22a0aa3..db0a4b854 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/WildcardNamedWithAsPattern.fs @@ -14,10 +14,11 @@ let private checkForWildcardNamedWithAsPattern fileContents pattern = let suggestedFix = lazy( Some { FromRange = range; FromText = fileContents; ToText = identifier.idText }) - { Range = range - Message = Resources.GetString("RulesWildcardNamedWithAsPattern") - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } |> Array.singleton + Array.singleton + { Range = range + Message = Resources.GetString("RulesWildcardNamedWithAsPattern") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty } | _ -> Array.empty let private runner (args:AstNodeRuleParams) = @@ -27,8 +28,13 @@ let private runner (args:AstNodeRuleParams) = | _ -> Array.empty let rule = - { Name = "WildcardNamedWithAsPattern" - Identifier = Identifiers.WildcardNamedWithAsPattern - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule - + AstNodeRule + { + Name = "WildcardNamedWithAsPattern" + Identifier = Identifiers.WildcardNamedWithAsPattern + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs index d528bc2fb..6114ff2f6 100644 --- a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs +++ b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs @@ -131,13 +131,12 @@ let private countBooleanOperators expression = | SynExpr.MatchBang(_, _, clauses, _, _) | SynExpr.MatchLambda(_, _, clauses, _, _) | SynExpr.Match(_, _, clauses, _, _) -> - clauses |> List.sumBy (fun matchClause -> - match matchClause with - | SynMatchClause(_, whenExprOpt, _, _, _, _) -> - match whenExprOpt with - | Some whenExpr -> - countOperators 0 whenExpr - | None -> 0) + List.sumBy (fun matchClause -> + match matchClause with + | SynMatchClause(_, whenExprOpt, _, _, _, _) -> + match whenExprOpt with + | Some whenExpr -> countOperators 0 whenExpr + | None -> 0) clauses | _ -> count // kick off the calculation @@ -181,7 +180,7 @@ let runner (config:Config) (args:AstNodeRuleParams) : WarningDetails[] = | SynExpr.MatchBang(_, _, clauses, _, _) | SynExpr.MatchLambda(_, _, clauses, _, _) | SynExpr.Match(_, _, clauses, _, _) -> - let numCases = clauses |> List.sumBy countCasesInMatchClause // determine the number of cases in the match expression + let numCases = List.sumBy countCasesInMatchClause clauses // determine the number of cases in the match expression bindingStack.IncrComplexityOfCurrentScope (numCases + countBooleanOperators expression) // include the number of boolean operators in any when expressions, if applicable | _ -> () | _ -> () @@ -199,7 +198,7 @@ let runner (config:Config) (args:AstNodeRuleParams) : WarningDetails[] = let ret = match warningDetails with | Some warning -> warning::fromStack | None -> fromStack - ret |> List.toArray + List.toArray ret else Array.empty @@ -211,8 +210,13 @@ let cleanup () = /// Generator function for a rule instance. let rule config = - { Name = "CyclomaticComplexity" - Identifier = Identifiers.CyclomaticComplexity - RuleConfig = { AstNodeRuleConfig.Runner = runner config - Cleanup = cleanup } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "CyclomaticComplexity" + Identifier = Identifiers.CyclomaticComplexity + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = cleanup + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs b/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs index 774d19568..f51fd88dd 100644 --- a/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs +++ b/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs @@ -44,7 +44,7 @@ let runner (args: AstNodeRuleParams) = | _ -> Array.empty let rule = - { Name = "EnsureTailCallDiagnosticsInRecursiveFunctions" - Identifier = Identifiers.EnsureTailCallDiagnosticsInRecursiveFunctions - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { Name = "EnsureTailCallDiagnosticsInRecursiveFunctions" + Identifier = Identifiers.EnsureTailCallDiagnosticsInRecursiveFunctions + RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } diff --git a/src/FSharpLint.Core/Rules/Conventions/FavourConsistentThis.fs b/src/FSharpLint.Core/Rules/Conventions/FavourConsistentThis.fs index 8dfaf0f3a..4a4d800a1 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FavourConsistentThis.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FavourConsistentThis.fs @@ -26,11 +26,11 @@ let runner (config: Config) args = | head::_ when isNotConsistent head.idText symbol -> let suggestedFix = lazy(Some({ FromRange = head.idRange; FromText = head.idText; ToText = symbol })) let error = - { Range = range - Message = String.Format(Resources.GetString "RulesFavourConsistentThis", config.Symbol) - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } - |> Array.singleton + Array.singleton + { Range = range + Message = String.Format(Resources.GetString "RulesFavourConsistentThis", config.Symbol) + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty } error | _ -> Array.empty else @@ -39,7 +39,13 @@ let runner (config: Config) args = | _ -> Array.empty let rule config = - { Name = "FavourConsistentThis" - Identifier = Identifiers.FavourConsistentThis - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FavourConsistentThis" + Identifier = Identifiers.FavourConsistentThis + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs b/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs index 23323c31b..1441950e9 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs @@ -86,7 +86,13 @@ let runner args = | _ -> Array.empty let rule = - { Name = "FavourNonMutablePropertyInitialization" - Identifier = Identifiers.FavourNonMutablePropertyInitialization - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FavourNonMutablePropertyInitialization" + Identifier = Identifiers.FavourNonMutablePropertyInitialization + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/FavourReRaise.fs b/src/FSharpLint.Core/Rules/Conventions/FavourReRaise.fs index b0274c300..b1dfc2d2d 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FavourReRaise.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FavourReRaise.fs @@ -9,11 +9,11 @@ open FSharpLint.Framework.Rules let private runner (args: AstNodeRuleParams) = let generateError suggestedFix range = - { Range = range - Message = Resources.GetString "RulesFavourReRaise" - SuggestedFix = Some suggestedFix - TypeChecks = List.empty } - |> Array.singleton + Array.singleton + { Range = range + Message = Resources.GetString "RulesFavourReRaise" + SuggestedFix = Some suggestedFix + TypeChecks = List.empty } let rec checkExpr (expr) maybeIdent = match expr with @@ -44,9 +44,13 @@ let private runner (args: AstNodeRuleParams) = | _ -> Array.empty let rule = - { Name = "FavourReRaise" - Identifier = Identifiers.FavourReRaise - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FavourReRaise" + Identifier = Identifiers.FavourReRaise + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs b/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs index 2b1c2a087..0ba6790fa 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs @@ -22,7 +22,7 @@ let private getStaticEmptyErrorMessage (range:FSharp.Compiler.Text.Range) (empt let formatError errorName = Resources.GetString errorName - errorMessageKey |> formatError + formatError errorMessageKey let private generateError (fileContents: string) (range:FSharp.Compiler.Text.Range) (emptyLiteralType: EmptyLiteralType) = let suggestedFix = lazy( @@ -32,11 +32,11 @@ let private generateError (fileContents: string) (range:FSharp.Compiler.Text.Ran | EmptyListLiteral -> "List.Empty" | EmptyArrayLiteral -> "Array.empty" Some({ FromRange = range; FromText = fileContents; ToText = replacementText })) - { Range = range - Message = getStaticEmptyErrorMessage range emptyLiteralType - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } - |> Array.singleton + Array.singleton + { Range = range + Message = getStaticEmptyErrorMessage range emptyLiteralType + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty } let private runner (args: AstNodeRuleParams) = match args.AstNode with @@ -66,9 +66,13 @@ let private runner (args: AstNodeRuleParams) = let rule = - { Name = "FavourStaticEmptyFields" - Identifier = Identifiers.FavourStaticEmptyFields - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FavourStaticEmptyFields" + Identifier = Identifiers.FavourStaticEmptyFields + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs index 003f929c6..3be3ec9bb 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/CanBeReplacedWithComposition.fs @@ -65,16 +65,23 @@ let private validateLambdaCannotBeReplacedWithComposition fileContents _ lambda let suggestedFix = lazy( Some { FromRange = range; FromText = fileContents; ToText = String.Join(" >> ", funcStrings) }) - { Range = range - Message = Resources.GetString("RulesCanBeReplacedWithComposition") - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } |> Array.singleton + Array.singleton + { Range = range + Message = Resources.GetString("RulesCanBeReplacedWithComposition") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty } let runner (args:AstNodeRuleParams) = Helper.FunctionReimplementation.checkLambda args (validateLambdaCannotBeReplacedWithComposition args.FileContent) let rule = - { Name = "CanBeReplacedWithComposition" - Identifier = Identifiers.CanBeReplacedWithComposition - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "CanBeReplacedWithComposition" + Identifier = Identifiers.CanBeReplacedWithComposition + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs index 97d5cbb37..60bb0c259 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FunctionReimplementation/ReimplementsFunction.fs @@ -55,7 +55,13 @@ let runner (args:AstNodeRuleParams) = Helper.FunctionReimplementation.checkLambda args validateLambdaIsNotPointless let rule = - { Name = "ReimplementsFunction" - Identifier = Identifiers.ReimplementsFunction - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "ReimplementsFunction" + Identifier = Identifiers.ReimplementsFunction + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/ActivePatternNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/ActivePatternNames.fs index c53bde0c7..703b07647 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/ActivePatternNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/ActivePatternNames.fs @@ -11,13 +11,13 @@ let private getValueOrFunctionIdents _ pattern = | SynPat.LongIdent(longIdent, _, _, _, _, _) -> match List.tryLast longIdent.LongIdent with | Some ident when isActivePattern ident -> - ident |> Array.singleton + Array.singleton ident | _ -> Array.empty | SynPat.Named(SynIdent(ident, _), _, _, _) | SynPat.OptionalVal(ident, _) -> if isActivePattern ident then - ident |> Array.singleton + Array.singleton ident else Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/EnumCasesNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/EnumCasesNames.fs index b0d5c260a..ab043c5d0 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/EnumCasesNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/EnumCasesNames.fs @@ -8,7 +8,7 @@ open FSharpLint.Rules.Helper.Naming let private getIdentifiers (args:AstNodeRuleParams) = match args.AstNode with | AstNode.EnumCase(SynEnumCase(_, SynIdent(identifier, _), _, _, _, _)) -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | _ -> Array.empty let rule config = diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/ExceptionNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/ExceptionNames.fs index 3c7531ef0..8c892152c 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/ExceptionNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/ExceptionNames.fs @@ -10,7 +10,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = | AstNode.ExceptionRepresentation(SynExceptionDefnRepr.SynExceptionDefnRepr(_, unionCase, _, _, _, _)) -> match unionCase with | SynUnionCase(_, SynIdent(identifier, _), _, _, _, _, _) -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | _ -> Array.empty let rule config = diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/GenericTypesNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/GenericTypesNames.fs index 12c6fa5ab..1ee9e79d3 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/GenericTypesNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/GenericTypesNames.fs @@ -20,7 +20,7 @@ let private getIdentifiers (args: AstNodeRuleParams) = | Some types -> checkTypes types.TyparDecls |> Array.ofSeq | None -> Array.empty | AstNode.Type(SynType.Var(SynTypar(id, _, _), _)) -> - (id, id.idText, None) |> Array.singleton + Array.singleton (id, id.idText, None) | _ -> Array.empty let rule config = diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/InterfaceNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/InterfaceNames.fs index 831b4eff2..c1c8c60d8 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/InterfaceNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/InterfaceNames.fs @@ -19,7 +19,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = match List.tryLast identifier with | Some typeIdentifier -> if not (isMeasureType attrs) && isInterface typeDef then - (typeIdentifier, typeIdentifier.idText, None) |> Array.singleton + Array.singleton (typeIdentifier, typeIdentifier.idText, None) else Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/InternalValuesNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/InternalValuesNames.fs index 7fd9872f1..eeeaa46e5 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/InternalValuesNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/InternalValuesNames.fs @@ -21,8 +21,7 @@ let private getValueOrFunctionIdents typeChecker accessControlLevel pattern = | Some ident when not (isActivePattern ident) && singleIdentifier -> let checkNotUnionCase = checkNotUnionCase ident if accessControlLevel = AccessControlLevel.Internal then - (ident, ident.idText, Some checkNotUnionCase) - |> Array.singleton + Array.singleton (ident, ident.idText, Some checkNotUnionCase) else Array.empty | None | Some _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs index e303d2ce1..2d8df210c 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/LiteralNames.fs @@ -11,7 +11,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = if isLiteral attributes then let rec getLiteralIdents = function | SynPat.Named(SynIdent(identifier, _), _, _, _) -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | SynPat.Paren(pat, _) -> getLiteralIdents pat | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/MeasureTypeNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/MeasureTypeNames.fs index f4dd87ac7..a743f4dab 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/MeasureTypeNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/MeasureTypeNames.fs @@ -19,7 +19,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = match List.tryLast identifier with | Some typeIdentifier -> if isMeasureType attrs then - (typeIdentifier, typeIdentifier.idText, None) |> Array.singleton + Array.singleton (typeIdentifier, typeIdentifier.idText, None) else Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/MemberNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/MemberNames.fs index 2e29ee179..be36e192b 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/MemberNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/MemberNames.fs @@ -13,14 +13,13 @@ let private getMemberIdents _ = function // Ignore members prefixed with op_, they are a special case used for operator overloading. Array.empty | None -> Array.empty - | Some ident -> (ident, ident.idText, None) |> Array.singleton + | Some ident -> Array.singleton (ident, ident.idText, None) | _ -> Array.empty let private isImplementingInterface parents = - parents - |> List.exists (function + List.exists (function | AstNode.MemberDefinition (SynMemberDefn.Interface _) -> true - | _ -> false) + | _ -> false) parents let private getIdentifiers (args:AstNodeRuleParams) = match args.AstNode with @@ -36,7 +35,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = | AstNode.MemberDefinition(memberDef) -> match memberDef with | SynMemberDefn.AbstractSlot(SynValSig(_, SynIdent(identifier, _), _, _, _, _, _, _, _, _, _, _), _, _, _) -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | _ -> Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs index 02ea75b93..44e9e4b67 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs @@ -40,11 +40,11 @@ module QuickFixes = else String.Empty let toPascalCase (ident:Ident) = lazy( - let pascalCaseIdent = ident.idText |> mapFirstChar Char.ToUpper + let pascalCaseIdent = mapFirstChar Char.ToUpper ident.idText Some { FromText = ident.idText; FromRange = ident.idRange; ToText = pascalCaseIdent }) let toCamelCase (ident:Ident) = lazy( - let camelCaseIdent = ident.idText |> mapFirstChar Char.ToLower + let camelCaseIdent = mapFirstChar Char.ToLower ident.idText Some { FromText = ident.idText; FromRange = ident.idRange; ToText = camelCaseIdent }) [] @@ -128,23 +128,22 @@ let private checkIdentifierPart (config:NamingConfig) (identifier:Ident) (idText | _ -> None let prefixError = - config.Prefix - |> Option.bind (fun prefix -> + Option.bind (fun prefix -> prefixRule prefix idText - |> Option.map (formatError2 prefix >> tryAddFix (QuickFixes.addPrefix prefix))) + |> Option.map (formatError2 prefix >> tryAddFix (QuickFixes.addPrefix prefix))) config.Prefix let suffixError = - config.Suffix - |> Option.bind (fun suffix -> + Option.bind (fun suffix -> suffixRule suffix idText - |> Option.map (formatError2 suffix >> tryAddFix (QuickFixes.addSuffix suffix))) + |> Option.map (formatError2 suffix >> tryAddFix (QuickFixes.addSuffix suffix))) config.Suffix - [| - casingError - underscoresError - prefixError - suffixError - |] |> Array.choose id + Array.choose id + [| + casingError + underscoresError + prefixError + suffixError + |] let private checkIdentifier (namingConfig:NamingConfig) (identifier:Ident) (idText:string) = if notOperator idText && isNotDoubleBackTickedIdent identifier then @@ -164,7 +163,7 @@ let toAstNodeRule (namingRule:RuleMetadata) = namingRule.RuleConfig.GetIdentifiersToCheck args |> Array.collect (fun (identifier, idText, typeCheck) -> let suggestions = checkIdentifier namingRule.RuleConfig.Config identifier idText - suggestions |> Array.map (fun suggestion -> { suggestion with TypeChecks = Option.toList typeCheck })) + Array.map (fun suggestion -> { suggestion with TypeChecks = Option.toList typeCheck }) suggestions) { RuleMetadata.Name = namingRule.Name @@ -344,8 +343,7 @@ let rec getPatternIdents<'Item> (accessibility:AccessControlLevel) (getIdents:Ge let accessibility = checkAccessibility accessibility access getIdents accessibility pattern | SynPat.Or(p1, p2, _, _) -> - [|p1; p2|] - |> Array.collect (getPatternIdents accessibility getIdents false) + Array.collect (getPatternIdents accessibility getIdents false) [|p1; p2|] | SynPat.Paren(pat, _) -> getPatternIdents accessibility getIdents false pat | SynPat.Ands(pats, _) @@ -386,6 +384,6 @@ let getFunctionIdents (pattern:SynPat) = match pattern with | SynPat.LongIdent (longIdent, _, _, SynArgPats.Pats _, _, _) -> match List.tryLast longIdent.LongIdent with - | Some ident -> (ident, ident.idText, None) |> Array.singleton + | Some ident -> Array.singleton (ident, ident.idText, None) | None -> Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/ParameterNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/ParameterNames.fs index e42eebb81..e34a105ef 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/ParameterNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/ParameterNames.fs @@ -9,7 +9,7 @@ open FSharpLint.Rules.Helper.Naming let private getMemberIdents _ = function | SynPat.Named(SynIdent(ident, _), _, _, _) | SynPat.OptionalVal(ident, _) -> - (ident, ident.idText, None) |> Array.singleton + Array.singleton (ident, ident.idText, None) | _ -> Array.empty let private getValueOrFunctionIdents typeChecker _accessibility pattern = @@ -22,11 +22,11 @@ let private getValueOrFunctionIdents typeChecker _accessibility pattern = | SynPat.Named(SynIdent(ident, _), _, _, _) | SynPat.OptionalVal(ident, _) when not (isActivePattern ident) -> let checkNotUnionCase = checkNotUnionCase ident - (ident, ident.idText, Some checkNotUnionCase) |> Array.singleton + Array.singleton (ident, ident.idText, Some checkNotUnionCase) | SynPat.LongIdent(SynLongIdent([ident], _, _), _, _, SynArgPats.Pats([]), _, _) when not (isActivePattern ident) -> // Handle constructor parameters that are represented as LongIdent (e.g., PascalCase parameters) let checkNotUnionCase = checkNotUnionCase ident - (ident, ident.idText, Some checkNotUnionCase) |> Array.singleton + Array.singleton (ident, ident.idText, Some checkNotUnionCase) | _ -> Array.empty let private getIdentifiers (args:AstNodeRuleParams) = diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/PrivateValuesNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/PrivateValuesNames.fs index 7dc808e5a..a871265ea 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/PrivateValuesNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/PrivateValuesNames.fs @@ -21,8 +21,7 @@ let private getValueOrFunctionIdents typeChecker accessibility pattern = | Some ident when not (isActivePattern ident) && singleIdentifier -> let checkNotUnionCase = checkNotUnionCase ident if accessibility = AccessControlLevel.Private then - (ident, ident.idText, Some checkNotUnionCase) - |> Array.singleton + Array.singleton (ident, ident.idText, Some checkNotUnionCase) else Array.empty | None | Some _ -> Array.empty @@ -42,11 +41,11 @@ let private getIdentifiers (args:AstNodeRuleParams) = else Array.empty | AstNode.Expression(SynExpr.For(_, _, identifier, _, _, _, _, _, _)) -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | AstNode.Match(SynMatchClause(pattern, _, _, _, _, _)) -> match pattern with | SynPat.Named(SynIdent(identifier, _), isThis, _, _) when not isThis -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | SynPat.As(_lshPat, rhsPat, _) -> getPatternIdents AccessControlLevel.Private (getValueOrFunctionIdents args.CheckInfo) false rhsPat | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/PublicValuesNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/PublicValuesNames.fs index 64166e1b1..774dc3651 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/PublicValuesNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/PublicValuesNames.fs @@ -25,8 +25,7 @@ let private getValueOrFunctionIdents typeChecker accessControlLevel pattern = | Some ident when singleIdentifier -> let checkNotUnionCase = checkNotUnionCase ident if accessControlLevel = AccessControlLevel.Public && isNotActivePattern ident then - (ident, ident.idText, Some checkNotUnionCase) - |> Array.singleton + Array.singleton (ident, ident.idText, Some checkNotUnionCase) else Array.empty | None | Some _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/RecordFieldNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/RecordFieldNames.fs index 797542383..18fe5876a 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/RecordFieldNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/RecordFieldNames.fs @@ -10,8 +10,7 @@ let private getIdentifiers (args:AstNodeRuleParams) = | AstNode.TypeSimpleRepresentation (SynTypeDefnSimpleRepr.Record (recordFields=recordFields)) -> recordFields |> List.choose (fun (SynField (idOpt=idOpt)) -> - idOpt - |> Option.map (fun identifier -> (identifier, identifier.idText, None))) + Option.map (fun (identifier: Ident) -> (identifier, identifier.idText, None)) idOpt) |> List.toArray | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/UnionCasesNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/UnionCasesNames.fs index a34e3e92b..15e0328d6 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/UnionCasesNames.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/UnionCasesNames.fs @@ -8,7 +8,7 @@ open FSharpLint.Rules.Helper.Naming let private getIdentifiers (args:AstNodeRuleParams) = match args.AstNode with | AstNode.UnionCase(SynUnionCase(_, SynIdent(identifier, _), _, _, _, _, _)) -> - (identifier, identifier.idText, None) |> Array.singleton + Array.singleton (identifier, identifier.idText, None) | _ -> Array.empty let rule config = diff --git a/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs b/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs index 28e20dbee..48a791b7e 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NestedStatements.fs @@ -136,8 +136,13 @@ let cleanup () = skipToIndex <- None let rule config = - { Name = "NestedStatements" - Identifier = Identifiers.NestedStatements - RuleConfig = { AstNodeRuleConfig.Runner = runner config - Cleanup = cleanup } } - |> AstNodeRule + AstNodeRule + { + Name = "NestedStatements" + Identifier = Identifiers.NestedStatements + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = cleanup + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs index 93420df70..977655aee 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs @@ -22,54 +22,55 @@ type private Replacement = | Function of functionName:string let private partialFunctionIdentifiers = - [ - // Option - ("Option.get", PatternMatch) + Map.ofList + [ + // Option + ("Option.get", PatternMatch) - // Map - ("Map.find", Function "Map.tryFind") - ("Map.findKey", Function "Map.tryFindKey") + // Map + ("Map.find", Function "Map.tryFind") + ("Map.findKey", Function "Map.tryFindKey") - // Array - ("Array.exactlyOne", Function "Array.tryExactlyOne") - ("Array.get", Function "Array.tryItem") - ("Array.item", Function "Array.tryItem") - ("Array.find", Function "Array.tryFind") - ("Array.findIndex", Function "Array.tryFindIndex") - ("Array.findBack", Function "Array.tryFindBack") - ("Array.head", Function "Array.tryHead") - ("Array.last", Function "Array.tryLast") - ("Array.tail", Function "FSharpx.Collections.Seq.tryHeadTail") - ("Array.reduce", Function "Array.fold") - ("Array.reduceBack", Function "Array.foldBack") - ("Array.pick", Function "Array.tryPick") + // Array + ("Array.exactlyOne", Function "Array.tryExactlyOne") + ("Array.get", Function "Array.tryItem") + ("Array.item", Function "Array.tryItem") + ("Array.find", Function "Array.tryFind") + ("Array.findIndex", Function "Array.tryFindIndex") + ("Array.findBack", Function "Array.tryFindBack") + ("Array.head", Function "Array.tryHead") + ("Array.last", Function "Array.tryLast") + ("Array.tail", Function "FSharpx.Collections.Seq.tryHeadTail") + ("Array.reduce", Function "Array.fold") + ("Array.reduceBack", Function "Array.foldBack") + ("Array.pick", Function "Array.tryPick") - // Seq - ("Seq.exactlyOne", Function "Seq.tryExactlyOne") - ("Seq.item", Function "Seq.tryItem") - ("Seq.find", Function "Seq.tryFind") - ("Seq.findIndex", Function "Seq.tryFindIndex") - ("Seq.findBack", Function "Seq.tryFindBack") - ("Seq.head", Function "Seq.tryHead") - ("Seq.last", Function "Seq.tryLast") - ("Seq.tail", Function "FSharpx.Collections.Seq.tryHeadTail") - ("Seq.reduce", Function "Seq.fold") - ("Seq.reduceBack", Function "Seq.foldBack") - ("Seq.pick", Function "Seq.tryPick") + // Seq + ("Seq.exactlyOne", Function "Seq.tryExactlyOne") + ("Seq.item", Function "Seq.tryItem") + ("Seq.find", Function "Seq.tryFind") + ("Seq.findIndex", Function "Seq.tryFindIndex") + ("Seq.findBack", Function "Seq.tryFindBack") + ("Seq.head", Function "Seq.tryHead") + ("Seq.last", Function "Seq.tryLast") + ("Seq.tail", Function "FSharpx.Collections.Seq.tryHeadTail") + ("Seq.reduce", Function "Seq.fold") + ("Seq.reduceBack", Function "Seq.foldBack") + ("Seq.pick", Function "Seq.tryPick") - // List - ("List.exactlyOne", Function "List.tryExactlyOne") - ("List.item", Function "List.tryItem") - ("List.find", Function "List.tryFind") - ("List.findIndex", Function "List.tryFindIndex") - ("List.findBack", Function "List.tryFindBack") - ("List.head", Function "List.tryHead") - ("List.last", Function "List.tryLast") - ("List.tail", Function "FSharpx.Collections.Seq.tryHeadTail") - ("List.reduce", Function "List.fold") - ("List.reduceBack", Function "List.foldBack") - ("List.pick", Function "List.tryPick") - ] |> Map.ofList + // List + ("List.exactlyOne", Function "List.tryExactlyOne") + ("List.item", Function "List.tryItem") + ("List.find", Function "List.tryFind") + ("List.findIndex", Function "List.tryFindIndex") + ("List.findBack", Function "List.tryFindBack") + ("List.head", Function "List.tryHead") + ("List.last", Function "List.tryLast") + ("List.tail", Function "FSharpx.Collections.Seq.tryHeadTail") + ("List.reduce", Function "List.fold") + ("List.reduceBack", Function "List.foldBack") + ("List.pick", Function "List.tryPick") + ] /// List of tuples (fully qualified instance member name, namespace, argument compiled type name, replacement strategy) let private partialInstanceMemberIdentifiers = @@ -125,13 +126,13 @@ let rec private tryFindTypedExpression (range: Range) (expression: FSharpExpr) = | FSharpExprPatterns.AddressSet(lvalueExpr, rvalueExpr) -> tryFindTypedExpression range lvalueExpr |> Option.orElse (tryFindTypedExpression range rvalueExpr) | FSharpExprPatterns.Application(funcExpr, _typeArgs, argExprs) -> - (funcExpr :: argExprs) |> tryFindFirst + tryFindFirst (funcExpr :: argExprs) | FSharpExprPatterns.Call(objExprOpt, _memberOrFunc, _typeArgs1, _typeArgs2, argExprs) -> - (List.append (Option.toList objExprOpt) argExprs) |> tryFindFirst + tryFindFirst (List.append (Option.toList objExprOpt) argExprs) | FSharpExprPatterns.Coerce(_targetType, inpExpr) -> tryFindTypedExpression range inpExpr | FSharpExprPatterns.FastIntegerForLoop(startExpr, limitExpr, consumeExpr, _isUp, _, _) -> - [ startExpr; limitExpr; consumeExpr ] |> tryFindFirst + tryFindFirst [ startExpr; limitExpr; consumeExpr ] | FSharpExprPatterns.ILAsm(_asmCode, _typeArgs, argExprs) -> tryFindFirst argExprs | FSharpExprPatterns.ILFieldGet (objExprOpt, _fieldType, _fieldName) -> @@ -139,7 +140,7 @@ let rec private tryFindTypedExpression (range: Range) (expression: FSharpExpr) = | FSharpExprPatterns.ILFieldSet (objExprOpt, _fieldType, _fieldName, valueExpr) -> objExprOpt |> Option.bind (tryFindTypedExpression range) |> Option.orElse (tryFindTypedExpression range valueExpr) | FSharpExprPatterns.IfThenElse (guardExpr, thenExpr, elseExpr) -> - [ guardExpr; thenExpr; elseExpr ] |> tryFindFirst + tryFindFirst [ guardExpr; thenExpr; elseExpr ] | FSharpExprPatterns.Lambda(_lambdaVar, bodyExpr) -> tryFindTypedExpression range bodyExpr | FSharpExprPatterns.Let((_bindingVar, bindingExpr, _), bodyExpr) -> @@ -232,15 +233,15 @@ let private getTypedExpressionForRange (checkFile:FSharpCheckFileResults) (range let private matchesBuiltinFSharpType (typeName: string) (fsharpType: FSharpType) : Option = let matchingPartialInstanceMember = - partialInstanceMemberIdentifiers - |> List.tryFind (fun (memberName, _, _, _) -> memberName.Split('.').[0] = typeName) + List.tryFind (fun (memberName: string, _, _, _) -> memberName.Split('.').[0] = typeName) partialInstanceMemberIdentifiers match matchingPartialInstanceMember with | Some(_, typeNamespace, compiledTypeName, _) -> - (fsharpType.HasTypeDefinition - && fsharpType.TypeDefinition.Namespace = typeNamespace - && fsharpType.TypeDefinition.CompiledName = compiledTypeName) - |> Some + Some( + fsharpType.HasTypeDefinition + && fsharpType.TypeDefinition.Namespace = typeNamespace + && fsharpType.TypeDefinition.CompiledName = compiledTypeName + ) | None -> None let private isNonStaticInstanceMemberCall (checkFile:FSharpCheckFileResults) names lineText (range: Range) :(Option) = @@ -328,8 +329,7 @@ let private isNonStaticInstanceMemberCall (checkFile:FSharpCheckFileResults) nam | _ -> None | _ -> None - (partialInstanceMemberIdentifiers - |> List.map map) + List.map map partialInstanceMemberIdentifiers match List.tryFind(fun (typeCheck:Option) -> typeCheck.IsSome) typeChecks with | None -> None | Some instanceMember -> instanceMember @@ -407,13 +407,13 @@ let private runner (config:Config) (args:AstNodeRuleParams) = match checkPartialIdentifier with | Some partialIdent -> - partialIdent |> Array.singleton + Array.singleton partialIdent | _ -> let lineText = args.Lines.[range.EndLine - 1] let nonStaticInstanceMemberTypeCheckResult = isNonStaticInstanceMemberCall checkInfo identifier lineText range match nonStaticInstanceMemberTypeCheckResult with | Some warningDetails -> - warningDetails |> Array.singleton + Array.singleton warningDetails | _ -> Array.Empty() | (Ast.Expression(SynExpr.DotGet(expr, _, SynLongIdent(_identifiers, _, _), _range)), Some checkInfo) -> let originalRange = expr.Range @@ -423,8 +423,13 @@ let private runner (config:Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "NoPartialFunctions" - Identifier = Identifiers.NoPartialFunctions - RuleConfig = { AstNodeRuleConfig.Runner = runner config - Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "NoPartialFunctions" + Identifier = Identifiers.NoPartialFunctions + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs index 8123f9824..fba0c3c51 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfBooleanOperatorsInCondition.fs @@ -39,13 +39,13 @@ let private validateCondition (maxBooleanOperators:int) condition = if numberOfBooleanOperators > maxBooleanOperators then let errorFormatString = Resources.GetString("RulesNumberOfItemsBooleanConditionsError") let error = String.Format(errorFormatString, maxBooleanOperators) - { - Range = condition.Range - Message = error - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = condition.Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty @@ -63,7 +63,13 @@ let private runner (config:Helper.NumberOfItems.Config) (args:AstNodeRuleParams) | _ -> Array.empty let rule config = - { Name = "MaxNumberOfBooleanOperatorsInCondition" - Identifier = Identifiers.MaxNumberOfBooleanOperatorsInCondition - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "MaxNumberOfBooleanOperatorsInCondition" + Identifier = Identifiers.MaxNumberOfBooleanOperatorsInCondition + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs index 84e379a4b..36d792651 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfFunctionParameters.fs @@ -13,13 +13,13 @@ let private validateFunction (maxParameters:int) (constructorArguments:SynArgPat when List.length parameters > maxParameters -> let errorFormatString = Resources.GetString("RulesNumberOfItemsFunctionError") let error = String.Format(errorFormatString, maxParameters) - { - Range = parameters.[maxParameters].Range - Message = error - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = parameters.[maxParameters].Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } | _ -> Array.empty let private runner (config:Helper.NumberOfItems.Config) (args:AstNodeRuleParams) = @@ -29,7 +29,13 @@ let private runner (config:Helper.NumberOfItems.Config) (args:AstNodeRuleParams) | _ -> Array.empty let rule config = - { Name = "MaxNumberOfFunctionParameters" - Identifier = Identifiers.MaxNumberOfFunctionParameters - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "MaxNumberOfFunctionParameters" + Identifier = Identifiers.MaxNumberOfFunctionParameters + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs index 9e19c2201..39208d1fc 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfItemsInTuple.fs @@ -24,13 +24,13 @@ let private validateTuple (maxItems:int) (items:SynExpr list) = if List.length items > maxItems then let errorFormatString = Resources.GetString("RulesNumberOfItemsTupleError") let error = String.Format(errorFormatString, maxItems) - { - Range = items.[maxItems].Range - Message = error - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = items.[maxItems].Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty @@ -45,7 +45,13 @@ let runner (config:Helper.NumberOfItems.Config) (args:AstNodeRuleParams) = Array.empty let rule config = - { Name = "MaxNumberOfItemsInTuple" - Identifier = Identifiers.MaxNumberOfItemsInTuple - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "MaxNumberOfItemsInTuple" + Identifier = Identifiers.MaxNumberOfItemsInTuple + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs index f9a5e02ba..8f855e53d 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NumberOfItems/MaxNumberOfMembers.fs @@ -19,26 +19,24 @@ let private getMembers (members:SynMemberDefn list) = | SynMemberDefn.AutoProperty(_, _, _, _, _, _, _, _, SynValSigAccess.GetSet (access, _, _), _, _, _) -> isPublic access | _ -> false - members - |> List.filter isPublicMember + List.filter isPublicMember members let private validateType (maxMembers:int) members typeRepresentation = let members = match typeRepresentation with | SynTypeDefnRepr.Simple(_) | SynTypeDefnRepr.Exception(_) -> members - | SynTypeDefnRepr.ObjectModel(_, members, _) -> members - |> getMembers + | SynTypeDefnRepr.ObjectModel(_, members, _) -> getMembers members if List.length members > maxMembers then let errorFormatString = Resources.GetString("RulesNumberOfItemsClassMembersError") let error = String.Format(errorFormatString, maxMembers) - { - Range = members.[maxMembers].Range - Message = error - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = members.[maxMembers].Range + Message = error + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty @@ -49,7 +47,13 @@ let private runner (config:Helper.NumberOfItems.Config) (args:AstNodeRuleParams) | _ -> Array.empty let rule config = - { Name = "MaxNumberOfMembers" - Identifier = Identifiers.MaxNumberOfMembers - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "MaxNumberOfMembers" + Identifier = Identifiers.MaxNumberOfMembers + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs index 937dabfb1..619a6cd4a 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithBadUsage.fs @@ -52,11 +52,13 @@ let private runner (args: AstNodeRuleParams) = | NullMessage -> "consider using a non-null error messages as parameter" let error = - { Range = range - Message = String.Format(Resources.GetString "RulesFailwithBadUsage", message) - SuggestedFix = suggestedFix - TypeChecks = List.Empty } - |> Array.singleton + Array.singleton + { + Range = range + Message = String.Format(Resources.GetString "RulesFailwithBadUsage", message) + SuggestedFix = suggestedFix + TypeChecks = List.Empty + } error @@ -127,9 +129,13 @@ let private runner (args: AstNodeRuleParams) = let cleanup () = failwithMessages <- Set.empty let rule = - { Name = "FailwithBadUsage" - Identifier = Identifiers.FailwithBadUsage - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = cleanup } } - |> AstNodeRule + AstNodeRule + { + Name = "FailwithBadUsage" + Identifier = Identifiers.FailwithBadUsage + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = cleanup + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithWithSingleArgument.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithWithSingleArgument.fs index 0290bc040..3fd44fdaf 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithWithSingleArgument.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithWithSingleArgument.fs @@ -5,7 +5,13 @@ open FSharpLint.Framework.Rules let runner = Helper.RaiseWithTooManyArguments.checkRaiseWithTooManyArgs "failwith" 1 "FailwithWithSingleArgument" let rule = - { Name = "FailwithWithSingleArgument" - Identifier = Identifiers.FailwithWithSingleArgument - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FailwithWithSingleArgument" + Identifier = Identifiers.FailwithWithSingleArgument + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs index 976eda47f..33a104cd1 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/FailwithfWithArgumentsMatchingFormatString.fs @@ -16,19 +16,26 @@ let private runner (args:AstNodeRuleParams) = match expressions with | SynExpr.Ident(ident)::SynExpr.Const(SynConst.String(formatString, _, _), _)::arguments when ident.idText = "failwithf" && List.length arguments = formatString.Replace("%%", String.Empty).Split('%').Length -> - { - Range = range - Message = Resources.GetString "FailwithfWithArgumentsMatchingFormatString" - SuggestedFix = None - TypeChecks = List.Empty - } |> Array.singleton + Array.singleton + { + Range = range + Message = Resources.GetString "FailwithfWithArgumentsMatchingFormatString" + SuggestedFix = None + TypeChecks = List.Empty + } | _ -> Array.empty | _ -> Array.empty | _ -> Array.empty let rule = - { Name = "FailwithfWithArgumentsMatchingFormatString" - Identifier = Identifiers.FailwithfWithArgumentsMatchingFormattingString - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "FailwithfWithArgumentsMatchingFormatString" + Identifier = Identifiers.FailwithfWithArgumentsMatchingFormattingString + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidArgWithTwoArguments.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidArgWithTwoArguments.fs index 1803e0629..db0f7a835 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidArgWithTwoArguments.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidArgWithTwoArguments.fs @@ -5,7 +5,13 @@ open FSharpLint.Framework.Rules let runner = Helper.RaiseWithTooManyArguments.checkRaiseWithTooManyArgs "invalidArg" 2 "InvalidArgWithTwoArguments" let rule = - { Name = "InvalidArgWithTwoArguments" - Identifier = Identifiers.InvalidOpWithSingleArgument - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "InvalidArgWithTwoArguments" + Identifier = Identifiers.InvalidOpWithSingleArgument + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidOpWithSingleArgument.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidOpWithSingleArgument.fs index 9c19ebdc3..9f0d05f87 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidOpWithSingleArgument.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/InvalidOpWithSingleArgument.fs @@ -5,7 +5,13 @@ open FSharpLint.Framework.Rules let runner = Helper.RaiseWithTooManyArguments.checkRaiseWithTooManyArgs "invalidOp" 1 "RulesInvalidOpWithSingleArgument" let rule = - { Name = "InvalidOpWithSingleArgument" - Identifier = Identifiers.InvalidOpWithSingleArgument - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "InvalidOpWithSingleArgument" + Identifier = Identifiers.InvalidOpWithSingleArgument + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/NullArgWithSingleArgument.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/NullArgWithSingleArgument.fs index 84b172b83..91565e58c 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/NullArgWithSingleArgument.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/NullArgWithSingleArgument.fs @@ -5,7 +5,13 @@ open FSharpLint.Framework.Rules let runner = Helper.RaiseWithTooManyArguments.checkRaiseWithTooManyArgs "nullArg" 1 "RulesNullArgWithSingleArgument" let rule = - { Name = "NullArgWithSingleArgument" - Identifier = Identifiers.NullArgWithSingleArgument - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "NullArgWithSingleArgument" + Identifier = Identifiers.NullArgWithSingleArgument + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithSingleArgument.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithSingleArgument.fs index 8a2894c8d..e20fef9c9 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithSingleArgument.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithSingleArgument.fs @@ -5,7 +5,13 @@ open FSharpLint.Framework.Rules let runner = Helper.RaiseWithTooManyArguments.checkRaiseWithTooManyArgs "raise" 1 "RulesRaiseWithSingleArgument" let rule = - { Name = "RaiseWithSingleArgument" - Identifier = Identifiers.RaiseWithSingleArgument - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "RaiseWithSingleArgument" + Identifier = Identifiers.RaiseWithSingleArgument + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs index ebdd95236..668de639e 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RaiseWithTooManyArguments/RaiseWithTooManyArgumentsHelper.fs @@ -19,12 +19,13 @@ let checkRaiseWithTooManyArgs (raiseType:string) (count:int) (ruleName:string) ( | FuncApp(expressions, range) -> match expressions with | RaiseWithTooManyArgs raiseType count -> - { - Range = range - Message = Resources.GetString ruleName - SuggestedFix = None - TypeChecks = List.Empty - } |> Array.singleton + Array.singleton + { + Range = range + Message = Resources.GetString ruleName + SuggestedFix = None + TypeChecks = List.Empty + } | _ -> Array.empty | _ -> Array.empty | _ -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs b/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs index 0f3a51917..834ba4ac0 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RecursiveAsyncFunction.fs @@ -43,13 +43,13 @@ let checkRecursiveAsyncFunction (args:AstNodeRuleParams) (range:Range) (doBangEx ToText = "return!" })) - { - Range = range - Message = Resources.GetString("RulesConventionsRecursiveAsyncFunctionError") - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty - } - |> Some + Some + { + Range = range + Message = Resources.GetString("RulesConventionsRecursiveAsyncFunctionError") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } match doBangExpr with | SynExpr.App (funcExpr=(SynExpr.Ident callerIdent)) -> @@ -75,7 +75,13 @@ let runner args = | _ -> Array.empty let rule = - { Name = "RecursiveAsyncFunction" - Identifier = Identifiers.RecursiveAsyncFunction - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "RecursiveAsyncFunction" + Identifier = Identifiers.RecursiveAsyncFunction + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs index 3a4322581..b05d28c9f 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs @@ -19,16 +19,16 @@ let private implementsIDisposable (fsharpType:FSharpType) = false let private doesNotImplementIDisposable (checkFile:FSharpCheckFileResults) (ident: SynLongIdent) = - let names = ident.LongIdent |> List.map (fun identifier -> identifier.idText) + let names = List.map (fun (identifier: Ident) -> identifier.idText) ident.LongIdent let symbol = checkFile.GetSymbolUseAtLocation(ident.Range.StartLine, ident.Range.EndColumn, String.Empty, names) match symbol with | Some(symbol) when (symbol.Symbol :? FSharpMemberOrFunctionOrValue) -> let ctor = symbol.Symbol :?> FSharpMemberOrFunctionOrValue - ctor.DeclaringEntity - |> Option.exists (fun ctorForType -> - Seq.forall (implementsIDisposable >> not) ctorForType.AllInterfaces) + Option.exists + (fun (ctorForType: FSharpEntity) -> Seq.forall (implementsIDisposable >> not) ctorForType.AllInterfaces) + ctor.DeclaringEntity | Some symbol when (symbol.Symbol :? FSharpEntity) -> let ctor = symbol.Symbol :?> FSharpEntity Seq.forall (implementsIDisposable >> not) ctor.AllInterfaces @@ -47,20 +47,26 @@ let runner args = match args.AstNode, args.CheckInfo with | AstNode.Expression(SynExpr.New(_, SynType.LongIdent(identifier), _, range)), Some checkInfo | AstNode.Expression(SynExpr.New(_, SynType.App(SynType.LongIdent(identifier), _, _, _, _, _, _), _, range)), Some checkInfo -> - { - Range = range - Message = Resources.GetString("RulesRedundantNewKeyword") - SuggestedFix = Some(generateFix args.FileContent range) - TypeChecks = - [ - fun () -> doesNotImplementIDisposable checkInfo identifier - ] - } - |> Array.singleton + Array.singleton + { + Range = range + Message = Resources.GetString("RulesRedundantNewKeyword") + SuggestedFix = Some(generateFix args.FileContent range) + TypeChecks = + [ + fun () -> doesNotImplementIDisposable checkInfo identifier + ] + } | _ -> Array.empty let rule = - { Name = "RedundantNewKeyword" - Identifier = Identifiers.RedundantNewKeyword - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "RedundantNewKeyword" + Identifier = Identifiers.RedundantNewKeyword + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInClass.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInClass.fs index 0c7e92bb6..9e2dedadd 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInClass.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInClass.fs @@ -14,7 +14,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInClass" - Identifier = Identifiers.MaxLinesInClass - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInClass" + Identifier = Identifiers.MaxLinesInClass + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInConstructor.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInConstructor.fs index 9f7fad7ea..5113d487c 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInConstructor.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInConstructor.fs @@ -14,7 +14,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInConstructor" - Identifier = Identifiers.MaxLinesInConstructor - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInConstructor" + Identifier = Identifiers.MaxLinesInConstructor + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInEnum.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInEnum.fs index dd2b692f1..1c3ed64ec 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInEnum.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInEnum.fs @@ -17,7 +17,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInEnum" - Identifier = Identifiers.MaxLinesInEnum - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInEnum" + Identifier = Identifiers.MaxLinesInEnum + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInFunction.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInFunction.fs index 61809da86..641f3b08d 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInFunction.fs @@ -14,7 +14,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInFunction" - Identifier = Identifiers.MaxLinesInFunction - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInFunction" + Identifier = Identifiers.MaxLinesInFunction + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInLambdaFunction.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInLambdaFunction.fs index 435675986..5259cc815 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInLambdaFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInLambdaFunction.fs @@ -11,7 +11,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInLambdaFunction" - Identifier = Identifiers.MaxLinesInLambdaFunction - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInLambdaFunction" + Identifier = Identifiers.MaxLinesInLambdaFunction + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMatchLambdaFunction.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMatchLambdaFunction.fs index fa16e3c67..6defc3b46 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMatchLambdaFunction.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMatchLambdaFunction.fs @@ -11,7 +11,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInMatchLambdaFunction" - Identifier = Identifiers.MaxLinesInMatchLambdaFunction - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInMatchLambdaFunction" + Identifier = Identifiers.MaxLinesInMatchLambdaFunction + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMember.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMember.fs index 1504c90b6..9ac8cc1d7 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMember.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInMember.fs @@ -14,7 +14,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInMember" - Identifier = Identifiers.MaxLinesInMember - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInMember" + Identifier = Identifiers.MaxLinesInMember + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInModule.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInModule.fs index 90650eec2..2187a5500 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInModule.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInModule.fs @@ -11,7 +11,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInModule" - Identifier = Identifiers.MaxLinesInModule - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInModule" + Identifier = Identifiers.MaxLinesInModule + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInProperty.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInProperty.fs index 70189f93b..2abc11c11 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInProperty.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInProperty.fs @@ -14,7 +14,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInProperty" - Identifier = Identifiers.MaxLinesInProperty - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInProperty" + Identifier = Identifiers.MaxLinesInProperty + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInRecord.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInRecord.fs index 191c9ca30..a97d65572 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInRecord.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInRecord.fs @@ -17,7 +17,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInRecord" - Identifier = Identifiers.MaxLinesInRecord - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInRecord" + Identifier = Identifiers.MaxLinesInRecord + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInUnion.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInUnion.fs index ca67265eb..5a9cd5813 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInUnion.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInUnion.fs @@ -17,7 +17,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInUnion" - Identifier = Identifiers.MaxLinesInUnion - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInUnion" + Identifier = Identifiers.MaxLinesInUnion + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInValue.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInValue.fs index 5a2fcebbb..abdcf89cf 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInValue.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInValue.fs @@ -14,7 +14,13 @@ let runner (config:Helper.SourceLength.Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "MaxLinesInValue" - Identifier = Identifiers.MaxLinesInValue - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "MaxLinesInValue" + Identifier = Identifiers.MaxLinesInValue + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs index 2ae9eec42..bfa26d6eb 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs @@ -73,13 +73,13 @@ let checkSourceLengthRule (config:Config) range fileContents errorName = let skipResult = sourceCodeLines.Length - commentLinesCount - blankLinesCount if skipResult > config.MaxLines then - { - Range = range - Message = error errorName config.MaxLines skipResult - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = range + Message = error errorName config.MaxLines skipResult + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty | None -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs index 69a85df50..8a8bbb0da 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs @@ -15,24 +15,21 @@ let rec private isImmutableValueExpression (args: AstNodeRuleParams) (expression let exists memberDef = match memberDef with | SynMemberDefn.LetBindings (bindings, _, _, _) -> - bindings - |> List.exists (fun (SynBinding (_, _, _, isMutable, _, _, _, headPat, _, _, _, _, _)) -> + List.exists (fun (SynBinding (_, _, _, isMutable, _, _, _, headPat, _, _, _, _, _)) -> match headPat with | SynPat.Named (SynIdent(bindingIdent, _), _, _, _) when isMutable -> bindingIdent.idText = ident.idText - | _ -> false) + | _ -> false) bindings | _ -> false match args.GetParents args.NodeIndex with | TypeDefinition (SynTypeDefn (_, SynTypeDefnRepr.ObjectModel (_, members, _), _, _, _, _)) :: _ -> - members - |> List.exists exists + List.exists exists members | _ -> false not isMutableVariable | SynExpr.ArrayOrList (_, elements, _) -> - elements - |> List.forall (isImmutableValueExpression args) + List.forall (isImmutableValueExpression args) elements | SynExpr.ArrayOrListComputed (_, innerExpr, _) -> isImmutableValueExpression args innerExpr || isImmutableSequentialExpression args innerExpr @@ -101,18 +98,22 @@ let private runner (args: AstNodeRuleParams) = ToText = $"val {memberName.idText}" } | _ -> None) - { Range = memberRange - Message = Resources.GetString "RulesSuggestUseAutoProperty" - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty } - |> Array.singleton + Array.singleton + { Range = memberRange + Message = Resources.GetString "RulesSuggestUseAutoProperty" + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty } | _ -> Array.empty | _ -> Array.empty let rule = - { Name = "SuggestUseAutoProperty" - Identifier = Identifiers.SuggestUseAutoProperty - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "SuggestUseAutoProperty" + Identifier = Identifiers.SuggestUseAutoProperty + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs index 29b7fb823..6647e458c 100644 --- a/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs @@ -69,9 +69,13 @@ let runner (args: AstNodeRuleParams) = | _ -> Array.empty let rule = - { Name = "UnneededRecKeyword" - Identifier = Identifiers.UnneededRecKeyword - RuleConfig = - { AstNodeRuleConfig.Runner = runner - Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "UnneededRecKeyword" + Identifier = Identifiers.UnneededRecKeyword + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs b/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs index c270f4ce4..283b2f4b1 100644 --- a/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs +++ b/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs @@ -42,7 +42,13 @@ let runner (args: AstNodeRuleParams) = Array.empty let rule = - { Name = "UsedUnderscorePrefixedElements" - Identifier = Identifiers.UsedUnderscorePrefixedElements - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "UsedUnderscorePrefixedElements" + Identifier = Identifiers.UsedUnderscorePrefixedElements + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs index c9f1ac0d3..e0d57603c 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs @@ -20,23 +20,23 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa let clauseIndentation = ExpressionUtilities.getLeadingSpaces firstClause.Range args.FileContent if isLambda then if clauseIndentation <> matchStartIndentation + args.GlobalConfig.numIndentationSpaces then + Some + { + Range = firstClause.Range + Message = Resources.GetString("RulesFormattingLambdaPatternMatchClauseIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } + else + None + elif clauseIndentation <> matchStartIndentation then + Some { Range = firstClause.Range - Message = Resources.GetString("RulesFormattingLambdaPatternMatchClauseIndentationError") + Message = Resources.GetString("RulesFormattingPatternMatchClauseIndentationError") SuggestedFix = None TypeChecks = List.Empty } - |> Some - else - None - elif clauseIndentation <> matchStartIndentation then - { - Range = firstClause.Range - Message = Resources.GetString("RulesFormattingPatternMatchClauseIndentationError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some else None @@ -50,13 +50,13 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa let consistentIndentationErrors = let choose (clauseOneSpaces: int) (clauseTwo: SynMatchClause) (clauseTwoSpaces: int) = if clauseOneSpaces <> clauseTwoSpaces then - { - Range = clauseTwo.Range - Message = Resources.GetString("RulesFormattingPatternMatchClauseSameIndentationError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = clauseTwo.Range + Message = Resources.GetString("RulesFormattingPatternMatchClauseSameIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -66,16 +66,22 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa |> Array.pairwise |> Array.choose (fun ((_, clauseOneSpaces), (clauseTwo, clauseTwoSpaces)) -> choose clauseOneSpaces clauseTwo clauseTwoSpaces) - [| - indentationLevelError |> Option.toArray - consistentIndentationErrors - |] - |> Array.concat + Array.concat + [| + Option.toArray indentationLevelError + consistentIndentationErrors + |] let runner (config:Config) (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args (check config) let rule config = - { Name = "PatternMatchClauseIndentation" - Identifier = Identifiers.PatternMatchClauseIndentation - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "PatternMatchClauseIndentation" + Identifier = Identifiers.PatternMatchClauseIndentation + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs index 5e910aa52..770b55521 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClausesOnNewLine.fs @@ -11,13 +11,13 @@ open FSharpLint.Rules.Helper let check args _ (clauses:SynMatchClause list) _ = let choose (clauseOne: SynMatchClause) (clauseTwo: SynMatchClause) = if clauseOne.Range.EndLine = clauseTwo.Range.StartLine then - { - Range = clauseTwo.Range - Message = Resources.GetString("RulesFormattingPatternMatchClausesOnNewLineError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = clauseTwo.Range + Message = Resources.GetString("RulesFormattingPatternMatchClausesOnNewLineError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -29,7 +29,13 @@ let check args _ (clauses:SynMatchClause list) _ = let runner (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args check let rule = - { Name = "PatternMatchClausesOnNewLine" - Identifier = Identifiers.PatternMatchClausesOnNewLine - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "PatternMatchClausesOnNewLine" + Identifier = Identifiers.PatternMatchClausesOnNewLine + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs index 8cf8da643..a380f98a8 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs @@ -18,13 +18,13 @@ let check (args:AstNodeRuleParams) _ (clauses:SynMatchClause list) _ = |> Option.map (fun expr -> expr.Range.EndLine) |> Option.defaultValue pat.Range.EndLine if expr.Range.StartLine <> matchPatternEndLine && exprIndentation <> clauseIndentation + args.GlobalConfig.numIndentationSpaces then - { - Range = expr.Range - Message = Resources.GetString("RulesFormattingMatchExpressionIndentationError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = expr.Range + Message = Resources.GetString("RulesFormattingMatchExpressionIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -35,7 +35,13 @@ let check (args:AstNodeRuleParams) _ (clauses:SynMatchClause list) _ = let runner (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args check let rule = - { Name = "PatternMatchExpressionIndentation" - Identifier = Identifiers.PatternMatchExpressionIndentation - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "PatternMatchExpressionIndentation" + Identifier = Identifiers.PatternMatchExpressionIndentation + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs index 0f1d31076..d40a08cc9 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchOrClausesOnNewLine.fs @@ -11,13 +11,13 @@ open FSharpLint.Rules.Helper let check args _ (clauses:SynMatchClause list) _ = let choose (clauseOne: SynPat) (clauseTwo: SynPat) = if clauseOne.Range.EndLine = clauseTwo.Range.StartLine then - { - Range = clauseTwo.Range - Message = Resources.GetString("RulesFormattingPatternMatchOrClausesOnNewLineError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = clauseTwo.Range + Message = Resources.GetString("RulesFormattingPatternMatchOrClausesOnNewLineError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -33,7 +33,13 @@ let check args _ (clauses:SynMatchClause list) _ = let runner (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args check let rule = - { Name = "PatternMatchOrClausesOnNewLine" - Identifier = Identifiers.PatternMatchOrClausesOnNewLine - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "PatternMatchOrClausesOnNewLine" + Identifier = Identifiers.PatternMatchOrClausesOnNewLine + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs index c1a4979e3..71d7110ca 100644 --- a/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/Spacing/ClassMemberSpacing.fs @@ -26,13 +26,13 @@ let checkClassMemberSpacing (args:AstNodeRuleParams) (members:SynMemberDefns) = (Position.mkPos (memberOne.Range.EndLine + 1) 0) (Position.mkPos (memberTwo.Range.StartLine + endOffset) 0) - { - Range = intermediateRange - Message = Resources.GetString("RulesFormattingClassMemberSpacingError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = intermediateRange + Message = Resources.GetString("RulesFormattingClassMemberSpacingError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -50,7 +50,13 @@ let runner args = | _ -> Array.empty let rule = - { Name = "ClassMemberSpacing" - Identifier = Identifiers.ClassMemberSpacing - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "ClassMemberSpacing" + Identifier = Identifiers.ClassMemberSpacing + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs index 6957f8e6c..08a140e6a 100644 --- a/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/Spacing/ModuleDeclSpacing.fs @@ -23,13 +23,13 @@ let checkModuleDeclSpacing (args:AstNodeRuleParams) synModuleOrNamespace = String.Empty (Position.mkPos (declOne.Range.EndLine + 1) 0) (Position.mkPos (declTwo.Range.StartLine + endOffset) 0) - { - Range = intermediateRange - Message = Resources.GetString("RulesFormattingModuleDeclSpacingError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = intermediateRange + Message = Resources.GetString("RulesFormattingModuleDeclSpacingError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -47,7 +47,13 @@ let runner args = | _ -> Array.empty let rule = - { Name = "ModuleDeclSpacing" - Identifier = Identifiers.ModuleDeclSpacing - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "ModuleDeclSpacing" + Identifier = Identifiers.ModuleDeclSpacing + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs index 751d6c7fc..beda74140 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleCommaSpacing.fs @@ -16,23 +16,23 @@ let checkTupleCommaSpacing (args:AstNodeRuleParams) (tupleExprs:SynExpr list) tu let commaRange = Range.mkRange String.Empty expr.Range.End nextExpr.Range.Start let map commaText = lazy - ({ - FromRange = commaRange - FromText = commaText - ToText = ", " - } - |> Some) + (Some + { + FromRange = commaRange + FromText = commaText + ToText = ", " + }) let suggestedFix = ExpressionUtilities.tryFindTextOfRange commaRange args.FileContent |> Option.map map - { - Range = commaRange - Message = Resources.GetString("RulesFormattingTupleCommaSpacingError") - SuggestedFix = suggestedFix - TypeChecks = List.Empty - } - |> Some + Some + { + Range = commaRange + Message = Resources.GetString("RulesFormattingTupleCommaSpacingError") + SuggestedFix = suggestedFix + TypeChecks = List.Empty + } else None @@ -44,7 +44,13 @@ let checkTupleCommaSpacing (args:AstNodeRuleParams) (tupleExprs:SynExpr list) tu let runner (args:AstNodeRuleParams) = TupleFormatting.isActualTuple args checkTupleCommaSpacing let rule = - { Name = "TupleCommaSpacing" - Identifier = Identifiers.TupleCommaSpacing - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "TupleCommaSpacing" + Identifier = Identifiers.TupleCommaSpacing + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs index daed91dab..d90b024b1 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs @@ -14,13 +14,13 @@ open FSharpLint.Rules.Helper let checkTupleIndentation _ (tupleExprs:SynExpr list) _ _ = let choose (expr: SynExpr) (nextExpr: SynExpr) = if expr.Range.StartColumn <> nextExpr.Range.StartColumn then - { - Range = Range.mkRange "" expr.Range.Start nextExpr.Range.End - Message = Resources.GetString("RulesFormattingTupleIndentationError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = Range.mkRange "" expr.Range.Start nextExpr.Range.End + Message = Resources.GetString("RulesFormattingTupleIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -34,7 +34,13 @@ let checkTupleIndentation _ (tupleExprs:SynExpr list) _ _ = let runner (args:AstNodeRuleParams) = TupleFormatting.isActualTuple args checkTupleIndentation let rule = - { Name = "TupleIndentation" - Identifier = Identifiers.TupleIndentation - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "TupleIndentation" + Identifier = Identifiers.TupleIndentation + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs index f2a4966c6..d6a3e6af2 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs @@ -12,12 +12,12 @@ let checkTupleHasParentheses (args:AstNodeRuleParams) _ range parentNode = let map text = let suggestedFix = lazy - ({ - FromRange = range - FromText = text - ToText = $"({text})" - } - |> Some) + (Some + { + FromRange = range + FromText = text + ToText = $"({text})" + }) { Range = range @@ -37,7 +37,13 @@ let checkTupleHasParentheses (args:AstNodeRuleParams) _ range parentNode = let runner (args:AstNodeRuleParams) = TupleFormatting.isActualTuple args checkTupleHasParentheses let rule = - { Name = "TupleParentheses" - Identifier = Identifiers.TupleParentheses - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "TupleParentheses" + Identifier = Identifiers.TupleParentheses + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs b/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs index 0a9145df5..01b51ad1a 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs @@ -34,15 +34,15 @@ let checkTypePrefixing (typePrefixingConfig: CheckTypePrefixingConfig) = let suggestedFix = lazy( (ExpressionUtilities.tryFindTextOfRange typePrefixingConfig.Range typePrefixingConfig.Args.FileContent, typePrefixingConfig.TypeArgs) ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = typePrefixingConfig.Range; ToText = $"{typeName}<{typeArgs}>" })) - { - Range = typePrefixingConfig.Range - Message = Resources.GetString("RulesFormattingGenericPrefixError") - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty - } - |> Some + Some + { + Range = typePrefixingConfig.Range + Message = Resources.GetString("RulesFormattingGenericPrefixError") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } - match lid |> longIdentWithDotsToString with + match longIdentWithDotsToString lid with | "list" | "List" | "option" @@ -56,13 +56,13 @@ let checkTypePrefixing (typePrefixingConfig: CheckTypePrefixingConfig) = let suggestedFix = lazy( (ExpressionUtilities.tryFindTextOfRange typePrefixingConfig.Range typePrefixingConfig.Args.FileContent, typePrefixingConfig.TypeArgs) ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = typePrefixingConfig.Range; ToText = $"{typeArgs} {typeName}" })) - { - Range = typePrefixingConfig.Range - Message = String.Format(recommendPostfixErrMsg.Value, typeName) - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty - } - |> Some + Some + { + Range = typePrefixingConfig.Range + Message = String.Format(recommendPostfixErrMsg.Value, typeName) + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } else if typePrefixingConfig.IsPostfix && typePrefixingConfig.Config.Mode = Mode.Always then prefixSuggestion typeName @@ -74,13 +74,13 @@ let checkTypePrefixing (typePrefixingConfig: CheckTypePrefixingConfig) = let suggestedFix = lazy( (ExpressionUtilities.tryFindTextOfRange typePrefixingConfig.Range typePrefixingConfig.Args.FileContent, typePrefixingConfig.TypeArgs) ||> Option.map2 (fun fromText typeArgs -> { FromText = fromText; FromRange = typePrefixingConfig.Range; ToText = $"{typeArgs} []" })) - { - Range = typePrefixingConfig.Range - Message = Resources.GetString("RulesFormattingF#ArrayPostfixError") - SuggestedFix = Some suggestedFix - TypeChecks = List.Empty - } - |> Some + Some + { + Range = typePrefixingConfig.Range + Message = Resources.GetString("RulesFormattingF#ArrayPostfixError") + SuggestedFix = Some suggestedFix + TypeChecks = List.Empty + } | typeName -> match (typePrefixingConfig.IsPostfix, typePrefixingConfig.Config.Mode) with @@ -89,11 +89,14 @@ let checkTypePrefixing (typePrefixingConfig: CheckTypePrefixingConfig) = | true, _ -> prefixSuggestion typeName | false, Mode.Never -> - { Range = typePrefixingConfig.Range - Message = String.Format(recommendPostfixErrMsg.Value, typeName) - // TODO - SuggestedFix = None - TypeChecks = List.Empty } |> Some + Some + { + Range = typePrefixingConfig.Range + Message = String.Format(recommendPostfixErrMsg.Value, typeName) + // TODO + SuggestedFix = None + TypeChecks = List.Empty + } | false, _ -> None | _ -> @@ -114,17 +117,23 @@ let runner (config:Config) args = } |> Option.toArray | AstNode.Type (SynType.Array (1, _elementType, range)) when config.Mode = Mode.Always -> - { Range = range - Message = Resources.GetString("RulesFormattingF#ArrayPrefixError") - SuggestedFix = None - TypeChecks = List.Empty } - |> Array.singleton + Array.singleton + { Range = range + Message = Resources.GetString("RulesFormattingF#ArrayPrefixError") + SuggestedFix = None + TypeChecks = List.Empty } | _ -> Array.empty let rule config = - { Name = "TypePrefixing" - Identifier = Identifiers.TypePrefixing - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "TypePrefixing" + Identifier = Identifiers.TypePrefixing + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs index fa39ce49d..683e436a9 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TypedItemSpacing.fs @@ -55,8 +55,10 @@ let private checkRange (config:Config) (args:AstNodeRuleParams) (range:Range) = let spacesBeforeString = " " |> String.replicate expectedSpacesBefore let spacesAfterString = " " |> String.replicate expectedSpacesAfter let suggestedFix = lazy( - { FromRange = range; FromText = text; ToText = $"{trimmedOtherText}{spacesBeforeString}:{spacesAfterString}{trimmedTypeText}" } - |> Some) + Some { FromRange = range; + FromText = text; + ToText = $"{trimmedOtherText}{spacesBeforeString}:{spacesAfterString}{trimmedTypeText}" } + ) let errorFormatString = Resources.GetString("RulesFormattingTypedItemSpacingError") Some { @@ -83,7 +85,13 @@ let runner (config:Config) (args:AstNodeRuleParams) = | _ -> Array.empty let rule config = - { Name = "TypedItemSpacing" - Identifier = Identifiers.TypedItemSpacing - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule \ No newline at end of file + AstNodeRule + { + Name = "TypedItemSpacing" + Identifier = Identifiers.TypedItemSpacing + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs index 6770a39ce..5a4aa75bd 100644 --- a/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/UnionDefinitionIndentation.fs @@ -8,7 +8,7 @@ open FSharpLint.Framework.Ast open FSharpLint.Framework.Rules let getUnionCaseStartColumn (SynUnionCase (attrs, _, _, _, _, range, _)) = - match attrs |> List.tryHead with + match List.tryHead attrs with | Some attr -> // startcolumn of the attributes now includes the `[<` starter sigil, so we can just use it! attr.Range.StartColumn @@ -24,26 +24,26 @@ let checkUnionDefinitionIndentation (args:AstNodeRuleParams) typeDefnRepr typeDe | firstCase :: _ -> let indentationLevelError = if getUnionCaseStartColumn firstCase - 2 <> typeDefnStartColumn + args.GlobalConfig.numIndentationSpaces then - { - Range = firstCase.Range - Message = Resources.GetString("RulesFormattingUnionDefinitionIndentationError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = firstCase.Range + Message = Resources.GetString("RulesFormattingUnionDefinitionIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } else None let consistentIndentationErrors = let choose caseOne caseTwo = if getUnionCaseStartColumn caseOne <> getUnionCaseStartColumn caseTwo then - { - Range = caseTwo.Range - Message = Resources.GetString("RulesFormattingUnionDefinitionSameIndentationError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = caseTwo.Range + Message = Resources.GetString("RulesFormattingUnionDefinitionSameIndentationError") + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -52,11 +52,11 @@ let checkUnionDefinitionIndentation (args:AstNodeRuleParams) typeDefnRepr typeDe |> Array.pairwise |> Array.choose (fun (caseOne, caseTwo) -> choose caseOne caseTwo) - [| - indentationLevelError |> Option.toArray - consistentIndentationErrors - |] - |> Array.concat + Array.concat + [| + Option.toArray indentationLevelError + consistentIndentationErrors + |] | _ -> Array.empty let runner args = @@ -70,7 +70,13 @@ let runner args = Array.empty let rule = - { Name = "UnionDefinitionIndentation" - Identifier = Identifiers.UnionDefinitionIndentation - RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "UnionDefinitionIndentation" + Identifier = Identifiers.UnionDefinitionIndentation + RuleConfig = + { + AstNodeRuleConfig.Runner = runner + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index 8403f6331..fc88e1cfd 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -69,10 +69,9 @@ let private matchLambdaArguments (hintArgs:HintParser.LambdaArg list) (actualArg |> List.map matchLambdaArgument let allArgsMatch = - matches - |> List.forall (function + List.forall (function | LambdaArgumentMatch.NoMatch -> false - | _ -> true) + | _ -> true) matches if allArgsMatch then matches @@ -186,7 +185,7 @@ module private MatchExpression = let ident = identAsDecompiledOpName ident Some(Expression.Identifier([ident])) | AstNode.Expression(SynExpr.LongIdent(_, ident, _, _)) -> - let identifier = ident.LongIdent |> List.map (fun ident -> ident.idText) + let identifier = List.map (fun (ident: Ident) -> ident.idText) ident.LongIdent Some(Expression.Identifier(identifier)) | AstNode.Expression(SynExpr.Const(constant, _)) -> matchConst constant |> Option.map Expression.Constant @@ -257,7 +256,7 @@ module private MatchExpression = let arguments = { arguments with Expression = expr } match arguments.Hint with - | Expression.Variable(variable) when arguments.LambdaArguments |> Map.containsKey variable -> + | Expression.Variable(variable) when Map.containsKey variable arguments.LambdaArguments -> match expr with | AstNode.Expression(ExpressionUtilities.Identifier([identifier], _)) when identifier.idText = arguments.LambdaArguments.[variable] -> @@ -301,7 +300,7 @@ module private MatchExpression = and private matchFunctionApplication arguments = match (arguments.Expression, arguments.Hint) with | FuncApp(exprs, _), Expression.FunctionApplication(hintExprs) -> - let expressions = exprs |> List.map AstNode.Expression + let expressions = List.map AstNode.Expression exprs doExpressionsMatch expressions hintExprs arguments | _ -> NoMatch @@ -397,7 +396,7 @@ module private MatchPattern = let private matchPattern = function | SynPat.LongIdent(ident, _, _, _, _, _) -> - let identifier = ident.LongIdent |> List.map (fun ident -> ident.idText) + let identifier = List.map (fun (ident: Ident) -> ident.idText) (ident.LongIdent) Some(Pattern.Identifier(identifier)) | SynPat.Const(constant, _) -> matchConst constant |> Option.map Pattern.Constant @@ -542,7 +541,7 @@ module private FormatHint = each) |> String.concat "." | HintExpr(Expression.FunctionApplication(expressions)) -> - expressions |> surroundExpressionsString (HintExpr >> toString) String.Empty String.Empty " " + surroundExpressionsString (HintExpr >> toString) String.Empty String.Empty " " expressions | HintExpr(Expression.InfixOperator(operator, leftHint, rightHint)) -> $"{toString (HintExpr leftHint)} {opToString operator} {toString (HintExpr rightHint)}" | HintPat(Pattern.Cons(leftHint, rightHint)) -> @@ -562,17 +561,17 @@ module private FormatHint = | HintExpr(Expression.LambdaBody(body)) -> toString (HintExpr body) | HintExpr(Expression.Tuple(expressions)) -> - expressions |> surroundExpressionsString (HintExpr >> toString) "(" ")" "," + surroundExpressionsString (HintExpr >> toString) "(" ")" "," expressions | HintExpr(Expression.List(expressions)) -> - expressions |> surroundExpressionsString (HintExpr >> toString) "[" "]" ";" + surroundExpressionsString (HintExpr >> toString) "[" "]" ";" expressions | HintExpr(Expression.Array(expressions)) -> - expressions |> surroundExpressionsString (HintExpr >> toString) "[|" "|]" ";" + surroundExpressionsString (HintExpr >> toString) "[|" "|]" ";" expressions | HintPat(Pattern.Tuple(expressions)) -> - expressions |> surroundExpressionsString (HintPat >> toString) "(" ")" "," + surroundExpressionsString (HintPat >> toString) "(" ")" "," expressions | HintPat(Pattern.List(expressions)) -> - expressions |> surroundExpressionsString (HintPat >> toString) "[" "]" ";" + surroundExpressionsString (HintPat >> toString) "[" "]" ";" expressions | HintPat(Pattern.Array(expressions)) -> - expressions |> surroundExpressionsString (HintPat >> toString) "[|" "|]" ";" + surroundExpressionsString (HintPat >> toString) "[|" "|]" ";" expressions | HintExpr(Expression.If(cond, expr, None)) -> $"if {toString (HintExpr cond)} then {toString (HintExpr expr)}" | HintExpr(Expression.If(cond, expr, Some(elseExpr))) -> @@ -652,13 +651,13 @@ let private getMethodParameters (checkFile:FSharpCheckFileResults) (methodIdent: methodIdent.Range.StartLine, methodIdent.Range.EndColumn, String.Empty, - methodIdent.LongIdent |> List.map (fun ident -> ident.idText)) + List.map (fun (ident: Ident) -> ident.idText) methodIdent.LongIdent) match symbol with | Some(symbol) when (symbol.Symbol :? FSharpMemberOrFunctionOrValue) -> let symbol = symbol.Symbol :?> FSharpMemberOrFunctionOrValue - if symbol.IsMember then symbol.CurriedParameterGroups |> Seq.tryHead + if symbol.IsMember then Seq.tryHead symbol.CurriedParameterGroups else None | _ -> None @@ -679,7 +678,7 @@ let private (|RequiresCheck|CanBeReplaced|CannotBeReplaced|) (breadcrumbs, range match filterParens breadcrumbs with | AstNode.Expression(SynExpr.Tuple(_, exprs, _, _))::AstNode.Expression(SynExpr.App(ExprAtomicFlag.Atomic, _, SynExpr.DotGet(_, _, methodIdent, _), _, _))::_ | AstNode.Expression(SynExpr.Tuple(_, exprs, _, _))::AstNode.Expression(SynExpr.App(ExprAtomicFlag.Atomic, _, SynExpr.LongIdent(_, methodIdent, _, _), _, _))::_ -> - match exprs |> List.tryFindIndex (fun expr -> expr.Range = range) with + match List.tryFindIndex (fun (expr: SynExpr) -> expr.Range = range) exprs with | Some(index) -> RequiresCheck(index, methodIdent) | None -> CannotBeReplaced | AstNode.Expression(SynExpr.App(ExprAtomicFlag.Atomic, _, SynExpr.DotGet(_, _, methodIdent, _), _, _))::_ @@ -761,7 +760,13 @@ let private runner (config:Config) (args:AstNodeRuleParams) = result let rule config = - { Name = "Hints" - Identifier = Identifiers.Hints - RuleConfig = { AstNodeRuleConfig.Runner = runner config; Cleanup = ignore } } - |> AstNodeRule + AstNodeRule + { + Name = "Hints" + Identifier = Identifiers.Hints + RuleConfig = + { + AstNodeRuleConfig.Runner = runner config + Cleanup = ignore + } + } diff --git a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs index 11b2d82b6..0c08b48eb 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs @@ -28,10 +28,10 @@ let private isMatch iIndex jIndex (nodeArray:AbstractSyntaxArray.Node []) = if numChildrenI = numChildrenJ then let numChildren = numChildrenI - { 0..numChildren } |> Seq.forall (fun child -> + Seq.forall (fun child -> iIndex + child < nodeArray.Length && jIndex + child < nodeArray.Length && - nodeArray.[iIndex + child].Hashcode = nodeArray.[jIndex + child].Hashcode) + nodeArray.[iIndex + child].Hashcode = nodeArray.[jIndex + child].Hashcode) { 0..numChildren } else false let inline private isParen (node:AbstractSyntaxArray.Node) = @@ -41,7 +41,7 @@ let inline private isParen (node:AbstractSyntaxArray.Node) = /// Compares the hint trie against a given location in the abstract syntax array. let rec checkTrie index trie (nodeArray:AbstractSyntaxArray.Node []) (boundVariables:Dictionary<_, _>) notify = - trie.MatchedHint |> List.iter notify + List.iter notify trie.MatchedHint if index < nodeArray.Length then let node = nodeArray.[index] @@ -66,6 +66,5 @@ let rec checkTrie index trie (nodeArray:AbstractSyntaxArray.Node []) (boundVaria | true, _ -> () | None -> checkTrie (index + node.NumberOfChildren + 1) trie nodeArray boundVariables notify - trie.Edges.AnyMatch - |> List.iter (fun (var, trie) -> collect var trie) + List.iter (fun (var, trie) -> collect var trie) trie.Edges.AnyMatch diff --git a/src/FSharpLint.Core/Rules/Typography/Indentation.fs b/src/FSharpLint.Core/Rules/Typography/Indentation.fs index 5d6b3af95..a9d9372bf 100644 --- a/src/FSharpLint.Core/Rules/Typography/Indentation.fs +++ b/src/FSharpLint.Core/Rules/Typography/Indentation.fs @@ -34,16 +34,15 @@ module ContextBuilder = let private createAbsoluteAndOffsetOverrides expectedIndentation (rangeToUpdate:Range) = let absoluteOverride = (rangeToUpdate.StartLine, (true, expectedIndentation)) let relativeOverrides = - [(rangeToUpdate.StartLine + 1)..rangeToUpdate.EndLine] - |> List.map (fun offsetLine -> - (offsetLine, (false, expectedIndentation))) + List.map (fun offsetLine -> + (offsetLine, (false, expectedIndentation))) [(rangeToUpdate.StartLine + 1)..rangeToUpdate.EndLine] (absoluteOverride::relativeOverrides) let rec private collectRecordFields = function | (SynExpr.Record ( _, _, fields, _)) -> let subRecords = fields - |> List.choose (fun (SynExprRecordField(_, _, expr, _)) -> expr |> Option.map collectRecordFields) + |> List.choose (fun (SynExprRecordField(_, _, expr, _)) -> Option.map collectRecordFields expr) |> List.concat fields::subRecords | _ -> @@ -53,10 +52,13 @@ module ContextBuilder = match ranges with | (first::others) -> let expectedIndentation = first.StartColumn - others - |> List.collect (fun other -> - [ for lineNumber=other.StartLine to other.EndLine do - yield (lineNumber, (true, expectedIndentation)) ]) + List.collect + (fun (other: Range) -> + [ + for lineNumber = other.StartLine to other.EndLine do + yield (lineNumber, (true, expectedIndentation)) + ]) + others | _ -> List.Empty let private indentationOverridesForNode (node:AstNode) = @@ -144,37 +146,37 @@ let checkIndentation (expectedSpaces:int) (line:string) (lineNumber:int) (indent | (true, expectedIndentation) -> if numLeadingSpaces <> expectedIndentation then let errorString = Resources.GetString("RulesTypographyOverridenIndentationError") - { - Range = range - Message = errorString - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = range + Message = errorString + SuggestedFix = None + TypeChecks = List.Empty + } else None | (false, indentationOffset) -> if (numLeadingSpaces - indentationOffset) % expectedSpaces <> 0 then let errorFormatString = Resources.GetString("RulesTypographyOverridenIndentationError") - { - Range = range - Message = String.Format(errorFormatString, expectedSpaces) - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = range + Message = String.Format(errorFormatString, expectedSpaces) + SuggestedFix = None + TypeChecks = List.Empty + } else None elif numLeadingSpaces % expectedSpaces <> 0 then let errorFormatString = Resources.GetString("RulesTypographyIndentationError") - { - Range = range - Message = String.Format(errorFormatString, expectedSpaces) - SuggestedFix = None - TypeChecks = List.Empty - } - |> Some + Some + { + Range = range + Message = String.Format(errorFormatString, expectedSpaces) + SuggestedFix = None + TypeChecks = List.Empty + } else None @@ -183,7 +185,9 @@ let runner context args = |> Option.toArray let rule = - { Name = "Indentation" - Identifier = Identifiers.Indentation - RuleConfig = { Runner = runner } } - |> IndentationRule \ No newline at end of file + IndentationRule + { + Name = "Indentation" + Identifier = Identifiers.Indentation + RuleConfig = { Runner = runner } + } diff --git a/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs b/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs index 93d562902..27dc5202d 100644 --- a/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs +++ b/src/FSharpLint.Core/Rules/Typography/MaxCharactersOnLine.fs @@ -15,18 +15,23 @@ let checkMaxCharactersOnLine (config:Config) (args:LineRuleParams) = if lineLength > maxCharacters then let range = Range.mkRange String.Empty (Position.mkPos args.LineNumber (maxCharacters + 1)) (Position.mkPos args.LineNumber lineLength) let errorFormatString = Resources.GetString("RulesTypographyLineLengthError") - { - Range = range - Message = String.Format(errorFormatString, (maxCharacters + 1)) - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = range + Message = String.Format(errorFormatString, (maxCharacters + 1)) + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty let rule config = - { Name = "MaxCharactersOnLine" - Identifier = Identifiers.MaxCharactersOnLine - RuleConfig = { LineRuleConfig.Runner = checkMaxCharactersOnLine config } } - |> LineRule \ No newline at end of file + LineRule + { + Name = "MaxCharactersOnLine" + Identifier = Identifiers.MaxCharactersOnLine + RuleConfig = + { + LineRuleConfig.Runner = checkMaxCharactersOnLine config + } + } diff --git a/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs b/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs index e7d6b6352..daafcdf0b 100644 --- a/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs +++ b/src/FSharpLint.Core/Rules/Typography/MaxLinesInFile.fs @@ -12,14 +12,14 @@ type Config = { MaxLinesInFile:int } let private checkNumberOfLinesInFile numberOfLines line maxLines = if numberOfLines > maxLines then let errorFormatString = Resources.GetString("RulesTypographyFileLengthError") - { - Range = - Range.mkRange "" (Position.mkPos (maxLines + 1) 0) (Position.mkPos numberOfLines (String.length line)) - Message = String.Format(errorFormatString, (maxLines + 1)) - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = + Range.mkRange "" (Position.mkPos (maxLines + 1) 0) (Position.mkPos numberOfLines (String.length line)) + Message = String.Format(errorFormatString, (maxLines + 1)) + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty @@ -30,7 +30,12 @@ let checkMaxLinesInFile (config:Config) (args:LineRuleParams) = Array.empty let rule config = - { Name = "MaxLinesInFile" - Identifier = Identifiers.MaxLinesInFile - RuleConfig = { LineRuleConfig.Runner = checkMaxLinesInFile config } } - |> LineRule \ No newline at end of file + LineRule + { + Name = "MaxLinesInFile" + Identifier = Identifiers.MaxLinesInFile + RuleConfig = + { + LineRuleConfig.Runner = checkMaxLinesInFile config + } + } diff --git a/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs b/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs index 92e7d31dd..3c3b5b7c0 100644 --- a/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs +++ b/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs @@ -18,7 +18,7 @@ module ContextBuilder = current let private isInLiteralString literalStrings range = - literalStrings |> Seq.exists (fun (_, literalRange) -> ExpressionUtilities.rangeContainsOtherRange literalRange range) + Seq.exists (fun (_, literalRange) -> ExpressionUtilities.rangeContainsOtherRange literalRange range) literalStrings let checkNoTabCharacters literalStrings (args:LineRuleParams) = let indexOfTab = args.Line.IndexOf('\t') @@ -26,25 +26,28 @@ let checkNoTabCharacters literalStrings (args:LineRuleParams) = if indexOfTab >= 0 then let range = Range.mkRange String.Empty (Position.mkPos args.LineNumber indexOfTab) (Position.mkPos args.LineNumber (indexOfTab + 1)) if isInLiteralString literalStrings range |> not then - { Range = range - Message = Resources.GetString("RulesTypographyTabCharacterError") - SuggestedFix = - Some( - lazy - (Some( - { FromRange = range - FromText = "\t" - ToText = String.replicate args.GlobalConfig.numIndentationSpaces " " } - )) - ) - TypeChecks = List.Empty } |> Array.singleton + Array.singleton + { Range = range + Message = Resources.GetString("RulesTypographyTabCharacterError") + SuggestedFix = + Some( + lazy + (Some( + { FromRange = range + FromText = "\t" + ToText = String.replicate args.GlobalConfig.numIndentationSpaces " " } + )) + ) + TypeChecks = List.Empty } else Array.empty else Array.empty let rule = - { Name = "NoTabCharacters" - Identifier = Identifiers.NoTabCharacters - RuleConfig = { Runner = checkNoTabCharacters } } - |> NoTabCharactersRule \ No newline at end of file + NoTabCharactersRule + { + Name = "NoTabCharacters" + Identifier = Identifiers.NoTabCharacters + RuleConfig = { Runner = checkNoTabCharacters } + } diff --git a/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs b/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs index 3fdcf035c..c66207aeb 100644 --- a/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs +++ b/src/FSharpLint.Core/Rules/Typography/TrailingNewLineInFile.fs @@ -9,18 +9,23 @@ open FSharp.Compiler.Text let checkTrailingNewLineInFile (args:LineRuleParams) = if args.IsLastLine && args.FileContent.EndsWith("\n") then let pos = Position.mkPos args.LineNumber 0 - { - Range = Range.mkRange "" pos pos - Message = Resources.GetString("RulesTypographyTrailingLineError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = Range.mkRange "" pos pos + Message = Resources.GetString("RulesTypographyTrailingLineError") + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty let rule = - { Name = "TrailingNewLineInFile" - Identifier = Identifiers.TrailingNewLineInFile - RuleConfig = { LineRuleConfig.Runner = checkTrailingNewLineInFile } } - |> LineRule \ No newline at end of file + LineRule + { + Name = "TrailingNewLineInFile" + Identifier = Identifiers.TrailingNewLineInFile + RuleConfig = + { + LineRuleConfig.Runner = checkTrailingNewLineInFile + } + } diff --git a/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs b/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs index a6252cac4..ea01f8224 100644 --- a/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs +++ b/src/FSharpLint.Core/Rules/Typography/TrailingWhitespaceOnLine.fs @@ -17,7 +17,7 @@ let private isSymbol character = [ '>';'<';'+';'-';'*';'=';'~';'%';'&';'|';'@' '#';'^';'!';'?';'/';'.';':';',';'(';')';'[';']';'{';'}' ] - symbols |> List.exists ((=) character) + List.exists ((=) character) symbols let private doesStringNotEndWithWhitespace (config:Config) (str:string) = match (config.NumberOfSpacesAllowed, config.OneSpaceAllowedAfterOperator) with @@ -47,18 +47,23 @@ let checkTrailingWhitespaceOnLine (config:Config) (args:LineRuleParams) = if stringEndsWithWhitespace then let whitespaceLength = lengthOfWhitespaceOnEnd line let range = Range.mkRange String.Empty (Position.mkPos lineNumber (line.Length - whitespaceLength)) (Position.mkPos lineNumber line.Length) - { - Range = range - Message = Resources.GetString("RulesTypographyTrailingWhitespaceError") - SuggestedFix = None - TypeChecks = List.Empty - } - |> Array.singleton + Array.singleton + { + Range = range + Message = Resources.GetString("RulesTypographyTrailingWhitespaceError") + SuggestedFix = None + TypeChecks = List.Empty + } else Array.empty let rule config = - { Name = "TrailingWhitespaceOnLine" - Identifier = Identifiers.TrailingWhitespaceOnLine - RuleConfig = { LineRuleConfig.Runner = checkTrailingWhitespaceOnLine config } } - |> LineRule \ No newline at end of file + LineRule + { + Name = "TrailingWhitespaceOnLine" + Identifier = Identifiers.TrailingWhitespaceOnLine + RuleConfig = + { + LineRuleConfig.Runner = checkTrailingWhitespaceOnLine config + } + } diff --git a/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs b/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs index 8b59e9c44..34ba45144 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestAbstractSyntaxArray.fs @@ -37,49 +37,49 @@ type TestAst() = member _.``Flatten with right pipe adds lhs to end of function application.``() = match generateAst "x |> List.map (fun x -> x)" |> astToExpr |> Expression with | FuncApp(expressions, _) -> - Assert.AreEqual(["LongIdent"; "Lambda"; "Ident"], expressions |> List.map astNodeName) + Assert.AreEqual(["LongIdent"; "Lambda"; "Ident"], List.map astNodeName expressions) | _ -> Assert.Fail() [] member _.``Flatten with left pipe adds rhs to end of function application.``() = match generateAst "List.map (fun x -> x) <| x" |> astToExpr |> Expression with | FuncApp(expressions, _) -> - Assert.AreEqual(["LongIdent"; "Lambda"; "Ident"], expressions |> List.map astNodeName) + Assert.AreEqual(["LongIdent"; "Lambda"; "Ident"], List.map astNodeName expressions) | _ -> Assert.Fail() [] member _.``Flatten with right pipe adds lhs to end of function application no matter the number of arguments on rhs.``() = match generateAst "x |> List.map (fun x -> x) 1" |> astToExpr |> Expression with | FuncApp(expressions, _) -> - Assert.AreEqual(["LongIdent"; "Lambda"; "Const"; "Ident"], expressions |> List.map astNodeName) + Assert.AreEqual(["LongIdent"; "Lambda"; "Const"; "Ident"], List.map astNodeName expressions) | _ -> Assert.Fail() [] member _.``Flatten with binary operator on lhs of right pipe.``() = match generateAst "x::[] |> List.map (fun x -> x)" |> astToExpr |> Expression with | FuncApp(expressions, _) -> - Assert.AreEqual(["LongIdent"; "Lambda"; "App"], expressions |> List.map astNodeName) + Assert.AreEqual(["LongIdent"; "Lambda"; "App"], List.map astNodeName expressions) | _ -> Assert.Fail() [] member _.``Flatten with function application on lhs of right pipe.``() = match generateAst "foo x |> List.map (fun x -> x)" |> astToExpr |> Expression with | FuncApp(expressions, _) -> - Assert.AreEqual(["LongIdent"; "Lambda"; "App"], expressions |> List.map astNodeName) + Assert.AreEqual(["LongIdent"; "Lambda"; "App"], List.map astNodeName expressions) | _ -> Assert.Fail() [] member _.``Flatten with multiple right pipes.``() = match generateAst "x |> foo |> List.map (fun x -> x)" |> astToExpr |> Expression with | FuncApp(expressions, _) -> - Assert.AreEqual(["LongIdent"; "Lambda"; "App"], expressions |> List.map astNodeName) + Assert.AreEqual(["LongIdent"; "Lambda"; "App"], List.map astNodeName expressions) | _ -> Assert.Fail() [] member _.``Flatten with multiple left pipes.``() = match generateAst "List.map (fun x -> x) <| 1 <| x" |> astToExpr |> Expression with | FuncApp(expressions, _) -> - Assert.AreEqual(["LongIdent"; "Lambda"; "Const"; "Ident"], expressions |> List.map astNodeName) + Assert.AreEqual(["LongIdent"; "Lambda"; "Const"; "Ident"], List.map astNodeName expressions) | _ -> Assert.Fail() [] diff --git a/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs b/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs index 65e97a43e..877d3c38d 100644 --- a/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs +++ b/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs @@ -86,18 +86,16 @@ let private matchExpression len = /// Generates a body of code containing a match expression with multiple combined patterns. let private matchExpressionWithCombinedPatterns len = let patterns = Seq.map (sprintf "| \"%d\"") [| 1..len-1 |] |> String.concat NewLine - $"""match "dummyString" with + makeProgram "f()" $"""match "dummyString" with {patterns} | _ -> ()""" - |> makeProgram "f()" /// Generates a body of code containing a match function with multiple patterns. let private matchFunction len = - $""" function + makeProgram "f" $""" function {(Seq.map (fun index -> (sprintf " | \"%d\"" index)) [| 1..len-1 |] |> String.concat NewLine)} | _ -> () f "dummyString" """ - |> makeProgram "f" /// Generates a computational expression with a match! expression containing multiple patterns. let private matchBang len = diff --git a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs index 3ba92e914..44fa93e72 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs @@ -26,7 +26,7 @@ type TestAstNodeRuleBase (rule:Rule) = | AstNodeRule rule -> rule | _ -> failwithf "TestAstNodeRuleBase only accepts AstNodeRules" - let globalConfig = globalConfig |> Option.defaultValue GlobalRuleConfig.Default + let globalConfig = Option.defaultValue GlobalRuleConfig.Default globalConfig match parseResults with | ParseFileResult.Success parseInfo -> @@ -51,6 +51,6 @@ type TestAstNodeRuleBase (rule:Rule) = rule.RuleConfig.Cleanup() - suggestions |> Array.iter this.PostSuggestion + Array.iter this.PostSuggestion suggestions | _ -> failwithf "Failed to parse" \ No newline at end of file diff --git a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs index 65d70c400..eed9ebd52 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs @@ -49,7 +49,7 @@ type TestHintMatcherBase () = | Rules.AstNodeRule rule -> rule | _ -> failwithf "TestHintMatcherBase only accepts AstNodeRules" - let globalConfig = globalConfig |> Option.defaultValue GlobalRuleConfig.Default + let globalConfig = Option.defaultValue GlobalRuleConfig.Default globalConfig match parseResults with | ParseFileResult.Success parseInfo -> @@ -70,6 +70,6 @@ type TestHintMatcherBase () = SyntaxArray = syntaxArray } |> fst - suggestions |> Array.iter this.PostSuggestion + Array.iter this.PostSuggestion suggestions | _ -> failwithf "Failed to parse" \ No newline at end of file diff --git a/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs index 96f66da98..6d5696772 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestIndentationRule.fs @@ -15,7 +15,7 @@ type TestIndentationRuleBase (rule:Rule) = let checker = FSharpChecker.Create(keepAssemblyContents=true) let sourceText = SourceText.ofString input - let fileName = fileName |> Option.defaultValue "Test.fsx" + let fileName = Option.defaultValue "Test.fsx" fileName let projectOptions, _ = checker.GetProjectOptionsFromScript(fileName, sourceText) |> Async.RunSynchronously let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions @@ -26,7 +26,7 @@ type TestIndentationRuleBase (rule:Rule) = | IndentationRule rule -> rule | _ -> failwithf "TestIndentationRuleBase only accepts IndentationRules" - let globalConfig = globalConfig |> Option.defaultValue GlobalRuleConfig.Default + let globalConfig = Option.defaultValue GlobalRuleConfig.Default globalConfig let lines = input.Split "\n" diff --git a/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs index 56d9fa3f3..5b39acd5a 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestLineRule.fs @@ -15,13 +15,13 @@ type TestLineRuleBase (rule:Rule) = let checker = FSharpChecker.Create(keepAssemblyContents=true) let sourceText = SourceText.ofString input - let fileName = fileName |> Option.defaultValue "Test.fsx" + let fileName = Option.defaultValue "Test.fsx" fileName let projectOptions, _ = checker.GetProjectOptionsFromScript(fileName, sourceText) |> Async.RunSynchronously let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions let parseResults = checker.ParseFile("test.fsx", sourceText, parsingOptions) |> Async.RunSynchronously - let globalConfig = globalConfig |> Option.defaultValue GlobalRuleConfig.Default + let globalConfig = Option.defaultValue GlobalRuleConfig.Default globalConfig let rule = match rule with diff --git a/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs index 69d860708..6a7882dbd 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestNoTabCharactersRule.fs @@ -15,7 +15,7 @@ type TestNoTabCharactersRuleBase (rule:Rule) = let checker = FSharpChecker.Create(keepAssemblyContents=true) let sourceText = SourceText.ofString input - let fileName = fileName |> Option.defaultValue "Test.fsx" + let fileName = Option.defaultValue "Test.fsx" fileName let projectOptions, _ = checker.GetProjectOptionsFromScript(fileName, sourceText) |> Async.RunSynchronously let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions @@ -26,7 +26,7 @@ type TestNoTabCharactersRuleBase (rule:Rule) = | NoTabCharactersRule rule -> rule | _ -> failwithf "TestNoTabCharactersRuleBase only accepts NoTabCharactersRules" - let globalConfig = globalConfig |> Option.defaultValue GlobalRuleConfig.Default + let globalConfig = Option.defaultValue GlobalRuleConfig.Default globalConfig let lines = input.Split "\n" diff --git a/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs index d8178b3b7..2d03f1f77 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs @@ -48,7 +48,7 @@ type TestRuleBase () = // prevent tests from passing if errors exist, just not on the line being checked member _.NoErrorsExist = - suggestions |> Seq.isEmpty + Seq.isEmpty suggestions member _.ErrorsExist = suggestions |> Seq.isEmpty |> not @@ -80,7 +80,7 @@ type TestRuleBase () = |> Seq.choose (fun linterSuggestion -> linterSuggestion.Details.SuggestedFix) |> Seq.tryHead - match firstSuggestedFix |> Option.bind (fun suggestedFix -> suggestedFix.Value) with + match Option.bind (fun (suggestedFix: Lazy>) -> suggestedFix.Value) firstSuggestedFix with | Some(fix) -> let startIndex = ExpressionUtilities.findPos fix.FromRange.Start source let endIndex = ExpressionUtilities.findPos fix.FromRange.End source diff --git a/tests/FSharpLint.Core.Tests/TestUtils.fs b/tests/FSharpLint.Core.Tests/TestUtils.fs index 7b01cf42f..1a26a61cf 100644 --- a/tests/FSharpLint.Core.Tests/TestUtils.fs +++ b/tests/FSharpLint.Core.Tests/TestUtils.fs @@ -34,7 +34,7 @@ match !memoizedResult with | Some(result) -> result | None -> - let text = performanceTestSourceFile |> File.ReadAllText + let text = File.ReadAllText performanceTestSourceFile let result = (generateAst text, text) memoizedResult := Some(result) result diff --git a/tests/FSharpLint.FunctionalTest/TestApi.fs b/tests/FSharpLint.FunctionalTest/TestApi.fs index d72f87d1e..8af626b7b 100644 --- a/tests/FSharpLint.FunctionalTest/TestApi.fs +++ b/tests/FSharpLint.FunctionalTest/TestApi.fs @@ -38,7 +38,7 @@ module TestApi = [] member _.``Performance of linting an existing file``() = let text = File.ReadAllText sourceFile - let tree = text |> generateAst + let tree = generateAst text let fileInfo = { Ast = tree; Source = text; TypeCheckResults = None } let stopwatch = Stopwatch.StartNew() From 632f0e8037ab28e78049c740c06abbc708e61748 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Mon, 18 Dec 2023 15:14:10 +0330 Subject: [PATCH 34/48] build: explain skipping NoPartialFunctions rule Because running it on Configuration.fs file causes a bug in FSharp.Compiler. Putting fsharplint:disable NoPartialFunctions at the top of the file doesn't help, as the rule is still run, just errors from that rules are supressed. --- build.fsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.fsx b/build.fsx index bd7937be5..af596ed1e 100644 --- a/build.fsx +++ b/build.fsx @@ -293,6 +293,8 @@ Target.create "SelfCheck" (fun _ -> "maxNumberOfFunctionParameters" "maxNumberOfMembers" "maxNumberOfBooleanOperatorsInCondition" + // Running NoPartialFunctions on this file causes a bug in FSharp.Compiler, so skip it for now + // "noPartialFunctions" ] let jsonObj = JObject.Parse fsharplintJsonText From 74fdc0e8207ac83300c68ab5f8e66ab77737c8d0 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 8 Feb 2024 12:26:04 +0330 Subject: [PATCH 35/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index af596ed1e..cfca7a8a0 100644 --- a/build.fsx +++ b/build.fsx @@ -295,6 +295,7 @@ Target.create "SelfCheck" (fun _ -> "maxNumberOfBooleanOperatorsInCondition" // Running NoPartialFunctions on this file causes a bug in FSharp.Compiler, so skip it for now // "noPartialFunctions" + "suggestUseAutoProperty" ] let jsonObj = JObject.Parse fsharplintJsonText From 21e5416ca20d80d4bc3ce35eb73ae84e3a095056 Mon Sep 17 00:00:00 2001 From: webwarrior-ws Date: Wed, 30 Jul 2025 11:57:34 +0200 Subject: [PATCH 36/48] Core,Tests: fix FSharpLint warnings --- tests/FSharpLint.Console.Tests/TestApp.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharpLint.Console.Tests/TestApp.fs b/tests/FSharpLint.Console.Tests/TestApp.fs index 322a39cab..e200f9c2b 100644 --- a/tests/FSharpLint.Console.Tests/TestApp.fs +++ b/tests/FSharpLint.Console.Tests/TestApp.fs @@ -15,7 +15,7 @@ type TemporaryFile(fileContent : string, extension) = do File.WriteAllText(filename, fileContent) - member _.FileName = filename + member val FileName = filename interface System.IDisposable with member _.Dispose() = From 35ae87fc92d444c0eba517f8e21d12d37445aa02 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 8 Feb 2024 12:26:44 +0330 Subject: [PATCH 37/48] build: run FSharpLint with 1 extra rule --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index cfca7a8a0..2a6cd0851 100644 --- a/build.fsx +++ b/build.fsx @@ -296,6 +296,7 @@ Target.create "SelfCheck" (fun _ -> // Running NoPartialFunctions on this file causes a bug in FSharp.Compiler, so skip it for now // "noPartialFunctions" "suggestUseAutoProperty" + "maxLinesInFile" ] let jsonObj = JObject.Parse fsharplintJsonText From 00fb0570e88088f967b635400e1dcbfdf649e89b Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 8 Feb 2024 13:01:51 +0330 Subject: [PATCH 38/48] Core: fix FSharpLint warning Fixing the warning for MaxLinesInFile rule: ``` ========== Linting C:\Users\PC\source\repos\FSharpLint\src\FSharpLint.Core\Framework\HintParser.fs ========== File suggested to be less than 1001 lines long. Error on line 1001 starting at column 0 ^ See https://fsprojects.github.io/FSharpLint/how-tos/rules/FL0062.html -------------------------------------------------------------------------------- ``` --- src/FSharpLint.Core/FSharpLint.Core.fsproj | 2 + src/FSharpLint.Core/Framework/HintParser.fs | 382 +----------------- .../Framework/HintParserTypes.fs | 73 ++++ .../Framework/HintParserUtilities.fs | 324 +++++++++++++++ .../Rules/Hints/HintMatcher.fs | 5 +- .../Framework/TestFuzzyHintMatcher.fs | 2 +- .../Framework/TestHintParser.fs | 3 +- .../Rules/TestHintMatcherBase.fs | 2 +- 8 files changed, 407 insertions(+), 386 deletions(-) create mode 100644 src/FSharpLint.Core/Framework/HintParserTypes.fs create mode 100644 src/FSharpLint.Core/Framework/HintParserUtilities.fs diff --git a/src/FSharpLint.Core/FSharpLint.Core.fsproj b/src/FSharpLint.Core/FSharpLint.Core.fsproj index ff228aaa4..5d82e3356 100644 --- a/src/FSharpLint.Core/FSharpLint.Core.fsproj +++ b/src/FSharpLint.Core/FSharpLint.Core.fsproj @@ -18,6 +18,8 @@ + + diff --git a/src/FSharpLint.Core/Framework/HintParser.fs b/src/FSharpLint.Core/Framework/HintParser.fs index 0744a1127..e7e8b068d 100644 --- a/src/FSharpLint.Core/Framework/HintParser.fs +++ b/src/FSharpLint.Core/Framework/HintParser.fs @@ -3,390 +3,10 @@ open System open FParsec open FSharp.Compiler.Tokenization +open HintParserTypes module HintParser = - type Constant = - | Byte of byte - | Bytes of byte[] - | Char of char - | Decimal of decimal - | Double of double - | Int16 of int16 - | Int32 of int32 - | Int64 of int64 - | IntPtr of nativeint - | SByte of sbyte - | Single of single - | UInt16 of uint16 - | UInt32 of uint32 - | UInt64 of uint64 - | UIntPtr of unativeint - | UserNum of bigint * char - | String of string - | Unit - | Bool of bool - - [] - type Pattern = - | Cons of Pattern * Pattern - | Or of Pattern * Pattern - | Wildcard - | Variable of char - | Identifier of string list - | Constant of Constant - | Parentheses of Pattern - | Tuple of Pattern list - | List of Pattern list - | Array of Pattern list - | Null - - [] - type Expression = - | FunctionApplication of Expression list - | InfixOperator of operatorIdentifier:Expression * Expression * Expression - | PrefixOperator of operatorIdentifier:Expression * Expression - | AddressOf of singleAmpersand:bool * Expression - | Wildcard - | Variable of char - | Identifier of string list - | Constant of Constant - | Parentheses of Expression - | Lambda of LambdaArg list * LambdaBody - | LambdaBody of Expression - | LambdaArg of Expression - | Tuple of Expression list - | List of Expression list - | Array of Expression list - | If of cond:Expression * body:Expression * ``else``:Expression option - | Else of Expression - | Null - and LambdaArg = LambdaArg of Expression - and LambdaBody = LambdaBody of Expression - - type HintNode = - | HintPat of Pattern - | HintExpr of Expression - - type Suggestion = - | Expr of Expression - | Message of string - - type Hint = - { MatchedNode:HintNode - Suggestion:Suggestion } - - /// Provides a way of creating a single list from any number of hint ASTs. - /// Means we can simply iterate over a single list for each node in the F# tree - /// when matching hints rather than check each hint AST for each node. - module MergeSyntaxTrees = - - open System.Collections.Generic - - type SyntaxHintNode = - | Identifier = 1uy - | Null = 2uy - | Expression = 3uy - | FuncApp = 4uy - | Unit = 5uy - | AddressOf = 6uy - - | If = 10uy - | Else = 11uy - - | Lambda = 20uy - | LambdaArg = 21uy - | LambdaBody = 22uy - - | ArrayOrList = 30uy - | Tuple = 31uy - - | Variable = 40uy - | Wildcard = 41uy - - | ConstantBool = 51uy - | ConstantByte = 52uy - | ConstantChar = 53uy - | ConstantDecimal = 54uy - | ConstantDouble = 55uy - | ConstantInt16 = 56uy - | ConstantInt32 = 57uy - | ConstantInt64 = 58uy - | ConstantIntPtr = 59uy - | ConstantSByte = 60uy - | ConstantSingle = 61uy - | ConstantString = 62uy - | ConstantUInt16 = 63uy - | ConstantUInt32 = 64uy - | ConstantUInt64 = 65uy - | ConstantUIntPtr = 66uy - | ConstantBytes = 67uy - | ConstantUserNum = 68uy - - | Cons = 101uy - | And = 102uy - | Or = 103uy - - [] - type Node = - { Edges:Edges - MatchedHint:Hint list } - and [] Edges = - { Lookup:Dictionary - AnyMatch:(char option * Node) list } - - override this.Equals(other) = - match other with - | :? Edges as rhs -> - let getList dict = Seq.toList dict |> List.map (fun (dictItems:KeyValuePair<_, _>) -> (dictItems.Key, dictItems.Value)) - - this.AnyMatch = rhs.AnyMatch && - this.Lookup.Count = rhs.Lookup.Count && - getList this.Lookup = getList rhs.Lookup - | _ -> false - - override this.GetHashCode() = hash (this.AnyMatch, hash this.Lookup) - - static member Empty = { Lookup = Dictionary<_, _>(); AnyMatch = List.Empty } - - let private getConstKey = function - | Constant.Unit -> SyntaxHintNode.Unit - | Constant.Bool(_) -> SyntaxHintNode.ConstantBool - | Constant.Byte(_) -> SyntaxHintNode.ConstantByte - | Constant.Bytes(_) -> SyntaxHintNode.ConstantBytes - | Constant.Char(_) -> SyntaxHintNode.ConstantChar - | Constant.Decimal(_) -> SyntaxHintNode.ConstantDecimal - | Constant.Double(_) -> SyntaxHintNode.ConstantDouble - | Constant.Int16(_) -> SyntaxHintNode.ConstantInt16 - | Constant.Int32(_) -> SyntaxHintNode.ConstantInt32 - | Constant.Int64(_) -> SyntaxHintNode.ConstantInt64 - | Constant.IntPtr(_) -> SyntaxHintNode.ConstantIntPtr - | Constant.SByte(_) -> SyntaxHintNode.ConstantSByte - | Constant.Single(_) -> SyntaxHintNode.ConstantSingle - | Constant.String(_) -> SyntaxHintNode.ConstantString - | Constant.UInt16(_) -> SyntaxHintNode.ConstantUInt16 - | Constant.UInt32(_) -> SyntaxHintNode.ConstantUInt32 - | Constant.UInt64(_) -> SyntaxHintNode.ConstantUInt64 - | Constant.UIntPtr(_) -> SyntaxHintNode.ConstantUIntPtr - | Constant.UserNum(_) -> SyntaxHintNode.ConstantUserNum - - let rec private getExprKey = function - | Expression.FunctionApplication(_) - | Expression.InfixOperator(_) - | Expression.PrefixOperator(_) -> SyntaxHintNode.FuncApp - | Expression.AddressOf(_) -> SyntaxHintNode.AddressOf - | Expression.Parentheses(expr) -> getExprKey expr - | Expression.Lambda(_) -> SyntaxHintNode.Lambda - | Expression.LambdaArg(_) -> SyntaxHintNode.LambdaArg - | Expression.LambdaBody(_) -> SyntaxHintNode.LambdaBody - | Expression.Tuple(_) -> SyntaxHintNode.Tuple - | Expression.Constant(constant) -> getConstKey constant - | Expression.List(_) - | Expression.Array(_) -> SyntaxHintNode.ArrayOrList - | Expression.If(_) -> SyntaxHintNode.If - | Expression.Else(_) -> SyntaxHintNode.Else - | Expression.Identifier(_) -> SyntaxHintNode.Identifier - | Expression.Null -> SyntaxHintNode.Null - | Expression.Wildcard -> SyntaxHintNode.Wildcard - | Expression.Variable(_) -> SyntaxHintNode.Variable - - let rec private getPatternKey = function - | Pattern.Cons(_) -> SyntaxHintNode.Cons - | Pattern.Or(_) -> SyntaxHintNode.Or - | Pattern.Wildcard -> SyntaxHintNode.Wildcard - | Pattern.Variable(_) -> SyntaxHintNode.Variable - | Pattern.Identifier(_) -> SyntaxHintNode.Identifier - | Pattern.Constant(constant) -> getConstKey constant - | Pattern.Parentheses(pattern) -> getPatternKey pattern - | Pattern.Tuple(_) -> SyntaxHintNode.Tuple - | Pattern.List(_) - | Pattern.Array(_) -> SyntaxHintNode.ArrayOrList - | Pattern.Null -> SyntaxHintNode.Null - - let rec private getKey = function - | HintExpr(expr) -> getExprKey expr - | HintPat(pattern) -> getPatternKey pattern - - let rec private getChildren = function - | HintExpr(Expression.Parentheses(expr)) -> getChildren <| HintExpr expr - | HintExpr(Expression.Lambda(args, LambdaBody(body))) -> - [ for LambdaArg(arg) in args -> HintExpr arg - yield HintExpr body ] - | HintExpr(Expression.LambdaArg(arg)) -> - [HintExpr arg] - | HintExpr(Expression.LambdaBody(body)) -> - [HintExpr body] - | HintExpr(Expression.InfixOperator(Expression.Identifier(["::"]) as ident, lhs, rhs)) -> - [HintExpr ident; HintExpr (Expression.Tuple([lhs; rhs]))] - | HintExpr(Expression.InfixOperator(ident, lhs, rhs)) -> - [HintExpr ident; HintExpr lhs; HintExpr rhs] - | HintExpr(Expression.PrefixOperator(ident, expr)) -> - [HintExpr ident; HintExpr expr] - | HintExpr(Expression.AddressOf(_, expr)) -> [HintExpr expr] - | HintExpr(Expression.FunctionApplication(exprs)) - | HintExpr(Expression.Tuple(exprs)) - | HintExpr(Expression.List(exprs)) - | HintExpr(Expression.Array(exprs)) -> List.map HintExpr exprs - | HintExpr(Expression.If(ifCond, bodyExpr, Some(elseExpr))) -> - [HintExpr ifCond; HintExpr bodyExpr; HintExpr elseExpr] - | HintExpr(Expression.If(ifCond, bodyExpr, None)) -> - [HintExpr ifCond; HintExpr bodyExpr] - | HintExpr(Expression.Else(expression)) -> [HintExpr expression] - | HintExpr(Expression.Identifier(_)) - | HintExpr(Expression.Constant(_)) - | HintExpr(Expression.Null) - | HintExpr(Expression.Wildcard) - | HintExpr(Expression.Variable(_)) -> List.Empty - | HintPat(Pattern.Cons(lhs, rhs)) - | HintPat(Pattern.Or(lhs, rhs)) -> [HintPat lhs; HintPat rhs] - | HintPat(Pattern.Array(patterns)) - | HintPat(Pattern.List(patterns)) - | HintPat(Pattern.Tuple(patterns)) -> List.map HintPat patterns - | HintPat(Pattern.Parentheses(pattern)) -> [HintPat pattern] - | HintPat(Pattern.Variable(_)) - | HintPat(Pattern.Identifier(_)) - | HintPat(Pattern.Constant(_)) - | HintPat(Pattern.Wildcard) - | HintPat(Pattern.Null) -> List.Empty - - let private getConstantHashCode = function - | Constant.Bool value -> hash value - | Constant.Byte value -> hash value - | Constant.Bytes value -> hash value - | Constant.Char value -> hash value - | Constant.Decimal value -> hash value - | Constant.Double value -> hash value - | Constant.Int16 value -> hash value - | Constant.Int32 value -> hash value - | Constant.Int64 value -> hash value - | Constant.IntPtr value -> hash value - | Constant.SByte value -> hash value - | Constant.Single value -> hash value - | Constant.String value -> hash value - | Constant.UInt16 value -> hash value - | Constant.UInt32 value -> hash value - | Constant.UInt64 value -> hash value - | Constant.UIntPtr value -> hash value - | Constant.UserNum(intValue, charValue) -> hash (intValue, charValue) - | _ -> 0 - - let private getIdentifierHashCode = function - | identifier when (List.isEmpty >> not) identifier -> - identifier - |> Seq.last - |> ExpressionUtilities.identAsCompiledOpName - |> hash - | _ -> 0 - - let rec private getHashCode node = - match node with - | HintExpr(Expression.Identifier(identifier)) - | HintPat(Pattern.Identifier(identifier)) -> getIdentifierHashCode identifier - | HintExpr(Expression.Constant(constant)) - | HintPat(Pattern.Constant(constant)) -> getConstantHashCode constant - | HintExpr(Expression.Parentheses(expr)) -> getHashCode <| HintExpr expr - | HintPat(Pattern.Parentheses(expr)) -> getHashCode <| HintPat expr - | _ -> 0 - - let private hintToList (hint:Hint) = - let nodes = Queue<_>() - - let rec depthFirstTraversal expr depth = - let children = getChildren expr - - nodes.Enqueue(expr, depth) - - for child in children do - depthFirstTraversal child (depth + 1) - - depthFirstTraversal hint.MatchedNode 0 - - (Seq.toList nodes, hint) - - type private HintList = (HintNode * int) list * Hint - - type private TransposedNode = - | HintNode of key:HintNode * depth:int * rest:HintList - | EndOfHint of Hint - - /// Gets the head of each given list - let private transposeHead hintLists = - let rec transposeHead builtList = function - | (((key, depth)::tail), hint)::rest -> - let restOfHintList = (tail, hint) - let next = HintNode(key, depth, restOfHintList)::builtList - transposeHead next rest - | ([], hint)::rest -> - let next = EndOfHint(hint)::builtList - transposeHead next rest - | [] -> builtList - - transposeHead List.Empty hintLists - - let isAnyMatch = function - | ((SyntaxHintNode.Wildcard | SyntaxHintNode.Variable), _, _, _) -> true - | _ -> false - - let getHints items = items |> Seq.map (fun (_, _, _, hint) -> hint) |> Seq.toList - - let mergeHints hints = - let rec getEdges transposed = - let map = Dictionary<_, _>() - - transposed - |> List.choose (function - | HintNode(expr, depth, rest) -> Some(getKey expr, expr, depth, rest) - | EndOfHint(_) -> None) - |> List.filter (isAnyMatch >> not) - |> Seq.groupBy (fun (key, expr, _, _) -> Utilities.hash2 key (getHashCode expr)) - |> Seq.iter (fun (hashcode, items) -> map.Add(hashcode, mergeHints (getHints items))) - - let anyMatches = - transposed - |> List.choose (function - | HintNode(expr, depth, rest) -> - match (getKey expr, expr) with - | (SyntaxHintNode.Wildcard as key), HintExpr(Expression.Wildcard) - | (SyntaxHintNode.Wildcard as key), HintPat(Pattern.Wildcard) - | (SyntaxHintNode.Variable as key), HintExpr(Expression.Variable(_)) - | (SyntaxHintNode.Variable as key), HintPat(Pattern.Variable(_)) -> - Some(key, expr, depth, rest) - | _ -> None - | EndOfHint(_) -> None) - |> Seq.groupBy (fun (_, expr, _, _) -> expr) - |> Seq.choose - (fun (expr, items) -> - match expr with - | HintPat(Pattern.Wildcard) - | HintExpr(Expression.Wildcard) -> Some(None, mergeHints (getHints items)) - | HintPat(Pattern.Variable(var)) - | HintExpr(Expression.Variable(var)) -> Some(Some(var), mergeHints (getHints items)) - | _ -> None) - |> Seq.toList - - { Lookup = map - AnyMatch = anyMatches } - - and mergeHints hints = - let transposed = transposeHead hints - - let edges = getEdges transposed - - let matchedHints = - transposed - |> Seq.choose (function - | HintNode(_) -> None - | EndOfHint(hint) -> Some(hint)) - |> Seq.toList - - { Edges = edges - MatchedHint = matchedHints } - - let transposed = - hints |> List.map hintToList |> transposeHead - - getEdges transposed - let charListToString charList = Seq.fold (fun concatenatedString charElement -> concatenatedString + charElement.ToString()) String.Empty charList diff --git a/src/FSharpLint.Core/Framework/HintParserTypes.fs b/src/FSharpLint.Core/Framework/HintParserTypes.fs new file mode 100644 index 000000000..dee79cee3 --- /dev/null +++ b/src/FSharpLint.Core/Framework/HintParserTypes.fs @@ -0,0 +1,73 @@ +namespace FSharpLint.Framework + +module HintParserTypes = + + type Constant = + | Byte of byte + | Bytes of byte[] + | Char of char + | Decimal of decimal + | Double of double + | Int16 of int16 + | Int32 of int32 + | Int64 of int64 + | IntPtr of nativeint + | SByte of sbyte + | Single of single + | UInt16 of uint16 + | UInt32 of uint32 + | UInt64 of uint64 + | UIntPtr of unativeint + | UserNum of bigint * char + | String of string + | Unit + | Bool of bool + + [] + type Pattern = + | Cons of Pattern * Pattern + | Or of Pattern * Pattern + | Wildcard + | Variable of char + | Identifier of string list + | Constant of Constant + | Parentheses of Pattern + | Tuple of Pattern list + | List of Pattern list + | Array of Pattern list + | Null + + [] + type Expression = + | FunctionApplication of Expression list + | InfixOperator of operatorIdentifier:Expression * Expression * Expression + | PrefixOperator of operatorIdentifier:Expression * Expression + | AddressOf of singleAmpersand:bool * Expression + | Wildcard + | Variable of char + | Identifier of string list + | Constant of Constant + | Parentheses of Expression + | Lambda of LambdaArg list * LambdaBody + | LambdaBody of Expression + | LambdaArg of Expression + | Tuple of Expression list + | List of Expression list + | Array of Expression list + | If of cond:Expression * body:Expression * ``else``:Expression option + | Else of Expression + | Null + and LambdaArg = LambdaArg of Expression + and LambdaBody = LambdaBody of Expression + + type HintNode = + | HintPat of Pattern + | HintExpr of Expression + + type Suggestion = + | Expr of Expression + | Message of string + + type Hint = + { MatchedNode:HintNode + Suggestion:Suggestion } diff --git a/src/FSharpLint.Core/Framework/HintParserUtilities.fs b/src/FSharpLint.Core/Framework/HintParserUtilities.fs new file mode 100644 index 000000000..c4a946483 --- /dev/null +++ b/src/FSharpLint.Core/Framework/HintParserUtilities.fs @@ -0,0 +1,324 @@ +namespace FSharpLint.Framework + +open HintParserTypes + +/// Provides a way of creating a single list from any number of hint ASTs. +/// Means we can simply iterate over a single list for each node in the F# tree +/// when matching hints rather than check each hint AST for each node. +module MergeSyntaxTrees = + + open System.Collections.Generic + + type SyntaxHintNode = + | Identifier = 1uy + | Null = 2uy + | Expression = 3uy + | FuncApp = 4uy + | Unit = 5uy + | AddressOf = 6uy + + | If = 10uy + | Else = 11uy + + | Lambda = 20uy + | LambdaArg = 21uy + | LambdaBody = 22uy + + | ArrayOrList = 30uy + | Tuple = 31uy + + | Variable = 40uy + | Wildcard = 41uy + + | ConstantBool = 51uy + | ConstantByte = 52uy + | ConstantChar = 53uy + | ConstantDecimal = 54uy + | ConstantDouble = 55uy + | ConstantInt16 = 56uy + | ConstantInt32 = 57uy + | ConstantInt64 = 58uy + | ConstantIntPtr = 59uy + | ConstantSByte = 60uy + | ConstantSingle = 61uy + | ConstantString = 62uy + | ConstantUInt16 = 63uy + | ConstantUInt32 = 64uy + | ConstantUInt64 = 65uy + | ConstantUIntPtr = 66uy + | ConstantBytes = 67uy + | ConstantUserNum = 68uy + + | Cons = 101uy + | And = 102uy + | Or = 103uy + + [] + type Node = + { Edges: Edges; MatchedHint: Hint list } + + and [] Edges = + { + Lookup: Dictionary + AnyMatch: (char option * Node) list + } + + override this.Equals(other) = + match other with + | :? Edges as rhs -> + let getList dict = + Seq.toList dict + |> List.map (fun (dictItems: KeyValuePair<_, _>) -> (dictItems.Key, dictItems.Value)) + + this.AnyMatch = rhs.AnyMatch + && this.Lookup.Count = rhs.Lookup.Count + && getList this.Lookup = getList rhs.Lookup + | _ -> false + + override this.GetHashCode() = hash (this.AnyMatch, hash this.Lookup) + + static member Empty = + { + Lookup = Dictionary<_, _>() + AnyMatch = List.Empty + } + + let private getConstKey = + function + | Constant.Unit -> SyntaxHintNode.Unit + | Constant.Bool(_) -> SyntaxHintNode.ConstantBool + | Constant.Byte(_) -> SyntaxHintNode.ConstantByte + | Constant.Bytes(_) -> SyntaxHintNode.ConstantBytes + | Constant.Char(_) -> SyntaxHintNode.ConstantChar + | Constant.Decimal(_) -> SyntaxHintNode.ConstantDecimal + | Constant.Double(_) -> SyntaxHintNode.ConstantDouble + | Constant.Int16(_) -> SyntaxHintNode.ConstantInt16 + | Constant.Int32(_) -> SyntaxHintNode.ConstantInt32 + | Constant.Int64(_) -> SyntaxHintNode.ConstantInt64 + | Constant.IntPtr(_) -> SyntaxHintNode.ConstantIntPtr + | Constant.SByte(_) -> SyntaxHintNode.ConstantSByte + | Constant.Single(_) -> SyntaxHintNode.ConstantSingle + | Constant.String(_) -> SyntaxHintNode.ConstantString + | Constant.UInt16(_) -> SyntaxHintNode.ConstantUInt16 + | Constant.UInt32(_) -> SyntaxHintNode.ConstantUInt32 + | Constant.UInt64(_) -> SyntaxHintNode.ConstantUInt64 + | Constant.UIntPtr(_) -> SyntaxHintNode.ConstantUIntPtr + | Constant.UserNum(_) -> SyntaxHintNode.ConstantUserNum + + let rec private getExprKey = + function + | Expression.FunctionApplication(_) + | Expression.InfixOperator(_) + | Expression.PrefixOperator(_) -> SyntaxHintNode.FuncApp + | Expression.AddressOf(_) -> SyntaxHintNode.AddressOf + | Expression.Parentheses(expr) -> getExprKey expr + | Expression.Lambda(_) -> SyntaxHintNode.Lambda + | Expression.LambdaArg(_) -> SyntaxHintNode.LambdaArg + | Expression.LambdaBody(_) -> SyntaxHintNode.LambdaBody + | Expression.Tuple(_) -> SyntaxHintNode.Tuple + | Expression.Constant(constant) -> getConstKey constant + | Expression.List(_) + | Expression.Array(_) -> SyntaxHintNode.ArrayOrList + | Expression.If(_) -> SyntaxHintNode.If + | Expression.Else(_) -> SyntaxHintNode.Else + | Expression.Identifier(_) -> SyntaxHintNode.Identifier + | Expression.Null -> SyntaxHintNode.Null + | Expression.Wildcard -> SyntaxHintNode.Wildcard + | Expression.Variable(_) -> SyntaxHintNode.Variable + + let rec private getPatternKey = + function + | Pattern.Cons(_) -> SyntaxHintNode.Cons + | Pattern.Or(_) -> SyntaxHintNode.Or + | Pattern.Wildcard -> SyntaxHintNode.Wildcard + | Pattern.Variable(_) -> SyntaxHintNode.Variable + | Pattern.Identifier(_) -> SyntaxHintNode.Identifier + | Pattern.Constant(constant) -> getConstKey constant + | Pattern.Parentheses(pattern) -> getPatternKey pattern + | Pattern.Tuple(_) -> SyntaxHintNode.Tuple + | Pattern.List(_) + | Pattern.Array(_) -> SyntaxHintNode.ArrayOrList + | Pattern.Null -> SyntaxHintNode.Null + + let rec private getKey = + function + | HintExpr(expr) -> getExprKey expr + | HintPat(pattern) -> getPatternKey pattern + + let rec private getChildren = + function + | HintExpr(Expression.Parentheses(expr)) -> getChildren <| HintExpr expr + | HintExpr(Expression.Lambda(args, LambdaBody(body))) -> + [ for LambdaArg(arg) in args -> HintExpr arg + yield HintExpr body ] + | HintExpr(Expression.LambdaArg(arg)) -> [ HintExpr arg ] + | HintExpr(Expression.LambdaBody(body)) -> [ HintExpr body ] + | HintExpr(Expression.InfixOperator(Expression.Identifier([ "::" ]) as ident, lhs, rhs)) -> + [ HintExpr ident; HintExpr(Expression.Tuple([ lhs; rhs ])) ] + | HintExpr(Expression.InfixOperator(ident, lhs, rhs)) -> [ HintExpr ident; HintExpr lhs; HintExpr rhs ] + | HintExpr(Expression.PrefixOperator(ident, expr)) -> [ HintExpr ident; HintExpr expr ] + | HintExpr(Expression.AddressOf(_, expr)) -> [ HintExpr expr ] + | HintExpr(Expression.FunctionApplication(exprs)) + | HintExpr(Expression.Tuple(exprs)) + | HintExpr(Expression.List(exprs)) + | HintExpr(Expression.Array(exprs)) -> List.map HintExpr exprs + | HintExpr(Expression.If(ifCond, bodyExpr, Some(elseExpr))) -> + [ HintExpr ifCond; HintExpr bodyExpr; HintExpr elseExpr ] + | HintExpr(Expression.If(ifCond, bodyExpr, None)) -> [ HintExpr ifCond; HintExpr bodyExpr ] + | HintExpr(Expression.Else(expression)) -> [ HintExpr expression ] + | HintExpr(Expression.Identifier(_)) + | HintExpr(Expression.Constant(_)) + | HintExpr(Expression.Null) + | HintExpr(Expression.Wildcard) + | HintExpr(Expression.Variable(_)) -> List.Empty + | HintPat(Pattern.Cons(lhs, rhs)) + | HintPat(Pattern.Or(lhs, rhs)) -> [ HintPat lhs; HintPat rhs ] + | HintPat(Pattern.Array(patterns)) + | HintPat(Pattern.List(patterns)) + | HintPat(Pattern.Tuple(patterns)) -> List.map HintPat patterns + | HintPat(Pattern.Parentheses(pattern)) -> [ HintPat pattern ] + | HintPat(Pattern.Variable(_)) + | HintPat(Pattern.Identifier(_)) + | HintPat(Pattern.Constant(_)) + | HintPat(Pattern.Wildcard) + | HintPat(Pattern.Null) -> List.Empty + + let private getConstantHashCode = + function + | Constant.Bool value -> hash value + | Constant.Byte value -> hash value + | Constant.Bytes value -> hash value + | Constant.Char value -> hash value + | Constant.Decimal value -> hash value + | Constant.Double value -> hash value + | Constant.Int16 value -> hash value + | Constant.Int32 value -> hash value + | Constant.Int64 value -> hash value + | Constant.IntPtr value -> hash value + | Constant.SByte value -> hash value + | Constant.Single value -> hash value + | Constant.String value -> hash value + | Constant.UInt16 value -> hash value + | Constant.UInt32 value -> hash value + | Constant.UInt64 value -> hash value + | Constant.UIntPtr value -> hash value + | Constant.UserNum(intValue, charValue) -> hash (intValue, charValue) + | _ -> 0 + + let private getIdentifierHashCode = + function + | identifier when (List.isEmpty >> not) identifier -> + match (Seq.tryLast identifier) with + | Some value -> value |> ExpressionUtilities.identAsCompiledOpName |> hash + | None -> failwith "There's no last element in identifier." + | _ -> 0 + + let rec private getHashCode node = + match node with + | HintExpr(Expression.Identifier(identifier)) + | HintPat(Pattern.Identifier(identifier)) -> getIdentifierHashCode identifier + | HintExpr(Expression.Constant(constant)) + | HintPat(Pattern.Constant(constant)) -> getConstantHashCode constant + | HintExpr(Expression.Parentheses(expr)) -> getHashCode <| HintExpr expr + | HintPat(Pattern.Parentheses(expr)) -> getHashCode <| HintPat expr + | _ -> 0 + + let private hintToList (hint: Hint) = + let nodes = Queue<_>() + + let rec depthFirstTraversal expr depth = + let children = getChildren expr + + nodes.Enqueue(expr, depth) + + for child in children do + depthFirstTraversal child (depth + 1) + + depthFirstTraversal hint.MatchedNode 0 + + (Seq.toList nodes, hint) + + type private HintList = (HintNode * int) list * Hint + + type private TransposedNode = + | HintNode of key: HintNode * depth: int * rest: HintList + | EndOfHint of Hint + + /// Gets the head of each given list + let private transposeHead hintLists = + let rec transposeHead builtList = + function + | (((key, depth) :: tail), hint) :: rest -> + let restOfHintList = (tail, hint) + let next = HintNode(key, depth, restOfHintList) :: builtList + transposeHead next rest + | ([], hint) :: rest -> + let next = EndOfHint(hint) :: builtList + transposeHead next rest + | [] -> builtList + + transposeHead List.Empty hintLists + + let isAnyMatch = + function + | ((SyntaxHintNode.Wildcard | SyntaxHintNode.Variable), _, _, _) -> true + | _ -> false + + let getHints items = + items |> Seq.map (fun (_, _, _, hint) -> hint) |> Seq.toList + + let mergeHints hints = + let rec getEdges transposed = + let map = Dictionary<_, _>() + + transposed + |> List.choose (function + | HintNode(expr, depth, rest) -> Some(getKey expr, expr, depth, rest) + | EndOfHint(_) -> None) + |> List.filter (isAnyMatch >> not) + |> Seq.groupBy (fun (key, expr, _, _) -> Utilities.hash2 key (getHashCode expr)) + |> Seq.iter (fun (hashcode, items) -> map.Add(hashcode, mergeHints (getHints items))) + + let anyMatches = + transposed + |> List.choose (function + | HintNode(expr, depth, rest) -> + match (getKey expr, expr) with + | (SyntaxHintNode.Wildcard as key), HintExpr(Expression.Wildcard) + | (SyntaxHintNode.Wildcard as key), HintPat(Pattern.Wildcard) + | (SyntaxHintNode.Variable as key), HintExpr(Expression.Variable(_)) + | (SyntaxHintNode.Variable as key), HintPat(Pattern.Variable(_)) -> Some(key, expr, depth, rest) + | _ -> None + | EndOfHint(_) -> None) + |> Seq.groupBy (fun (_, expr, _, _) -> expr) + |> Seq.choose (fun (expr, items) -> + match expr with + | HintPat(Pattern.Wildcard) + | HintExpr(Expression.Wildcard) -> Some(None, mergeHints (getHints items)) + | HintPat(Pattern.Variable(var)) + | HintExpr(Expression.Variable(var)) -> Some(Some(var), mergeHints (getHints items)) + | _ -> None) + |> Seq.toList + + { Lookup = map; AnyMatch = anyMatches } + + and mergeHints hints = + let transposed = transposeHead hints + + let edges = getEdges transposed + + let matchedHints = + transposed + |> Seq.choose (function + | HintNode(_) -> None + | EndOfHint(hint) -> Some(hint)) + |> Seq.toList + + { + Edges = edges + MatchedHint = matchedHints + } + + let transposed = hints |> List.map hintToList |> transposeHead + + getEdges transposed diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index fc88e1cfd..7bbad1452 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -13,6 +13,7 @@ open FSharpLint.Framework.Ast open FSharpLint.Framework.ExpressionUtilities open FSharpLint.Framework.HintParser open FSharpLint.Framework.Rules +open FSharpLint.Framework.HintParserTypes type ToStringConfig = { @@ -60,7 +61,7 @@ type private LambdaMatch = | Match of Map | NoMatch -let private matchLambdaArguments (hintArgs:HintParser.LambdaArg list) (actualArgs:SynSimplePats list) = +let private matchLambdaArguments (hintArgs:HintParserTypes.LambdaArg list) (actualArgs:SynSimplePats list) = if List.length hintArgs <> List.length actualArgs then LambdaMatch.NoMatch else @@ -693,7 +694,7 @@ let private (|SuggestingReplacementOfLambda|OtherSuggestion|) = function let [] private MaxBreadcrumbs = 6 let private suggestions = ResizeArray() -let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParser.Hint) = +let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParserTypes.Hint) = let breadcrumbs = args.GetParents MaxBreadcrumbs match (args.AstNode, hint.MatchedNode) with | AstNode.Expression(SynExpr.Paren(_)), HintExpr(_) diff --git a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs index 21c2451fd..9286305a9 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs @@ -6,7 +6,7 @@ open FSharpLint.Rules.Helper.Hints open FSharpLint.Framework open FSharpLint.Framework.AbstractSyntaxArray open FSharpLint.Framework.HintParser -open FSharpLint.Framework.HintParser.MergeSyntaxTrees +open FSharpLint.Framework.MergeSyntaxTrees open NUnit.Framework open FParsec open TestUtils diff --git a/tests/FSharpLint.Core.Tests/Framework/TestHintParser.fs b/tests/FSharpLint.Core.Tests/Framework/TestHintParser.fs index 54f19dc4e..ebf96bed2 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestHintParser.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestHintParser.fs @@ -6,7 +6,8 @@ open NUnit.Framework open FSharpLint.Framework open FSharpLint.Framework.HintParser open FParsec -open MergeSyntaxTrees +open FSharpLint.Framework.MergeSyntaxTrees +open FSharpLint.Framework.HintParserTypes open System.Collections.Generic [] diff --git a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs index eed9ebd52..e81a14b06 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs @@ -6,7 +6,7 @@ open FSharp.Compiler.CodeAnalysis open FSharpLint.Application open FSharpLint.Framework open FSharpLint.Framework.HintParser -open FSharpLint.Framework.HintParser.MergeSyntaxTrees +open FSharpLint.Framework.MergeSyntaxTrees open FSharpLint.Framework.ParseFile open FSharpLint.Rules From a605197da28b7c3744e67515ace8d60e773a2840 Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Wed, 13 Aug 2025 14:42:14 +0200 Subject: [PATCH 39/48] Core(fsharplinit.json): enable rule by default This rule was introduced in v0.24.2 and was meant to be enabled by default, as explained in the documentation and in a blog-post of mine[1]. However we didn't realised about this mistake until now, but it's a good time to do it now given that this PR is making FSharpLint's own codebase respect even more of its own rules. [1] https://knocte.blogspot.com/2024/03/safety-shouldnt-be-opt-in.html --- src/FSharpLint.Core/fsharplint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharpLint.Core/fsharplint.json b/src/FSharpLint.Core/fsharplint.json index 24e13511f..162b6bd42 100644 --- a/src/FSharpLint.Core/fsharplint.json +++ b/src/FSharpLint.Core/fsharplint.json @@ -331,7 +331,7 @@ "additionalPartials": [] } }, - "ensureTailCallDiagnosticsInRecursiveFunctions": { "enabled": false }, + "ensureTailCallDiagnosticsInRecursiveFunctions": { "enabled": true }, "favourAsKeyword": { "enabled": true }, "hints": { "add": [ From c3ed7f056041527fd80d3590d8a05410602fbfe8 Mon Sep 17 00:00:00 2001 From: webwarrior-ws Date: Wed, 30 Jul 2025 13:20:50 +0200 Subject: [PATCH 40/48] Core: fix FSharpLint tail call warnings By converting the functions to tail-recursive using continuation-passing style. And silence them for functions that are very hard to convert to tail-recursive. --- src/FSharpLint.Core/Framework/AstInfo.fs | 1 + .../Framework/HintParserUtilities.fs | 1 + src/FSharpLint.Core/Framework/Utilities.fs | 2 + .../AsyncExceptionWithoutReturn.fs | 115 ++++++++------ .../FavourNonMutablePropertyInitialization.fs | 70 +++++---- .../Rules/Conventions/Naming/NamingHelper.fs | 70 +++++---- .../Rules/Conventions/NoPartialFunctions.fs | 3 + .../Conventions/SuggestUseAutoProperty.fs | 47 ++++-- .../Rules/Hints/HintMatcher.fs | 144 ++++++++++++------ .../Rules/Hints/HintsHelper.fs | 4 +- 10 files changed, 285 insertions(+), 172 deletions(-) diff --git a/src/FSharpLint.Core/Framework/AstInfo.fs b/src/FSharpLint.Core/Framework/AstInfo.fs index 6064a4029..62bfd7c3e 100644 --- a/src/FSharpLint.Core/Framework/AstInfo.fs +++ b/src/FSharpLint.Core/Framework/AstInfo.fs @@ -115,6 +115,7 @@ module AstInfo = "LBrack" "RBrack" ] + [] let rec isSequenceOfOperators (str:string) = if Seq.isEmpty str then true diff --git a/src/FSharpLint.Core/Framework/HintParserUtilities.fs b/src/FSharpLint.Core/Framework/HintParserUtilities.fs index c4a946483..7749eed7b 100644 --- a/src/FSharpLint.Core/Framework/HintParserUtilities.fs +++ b/src/FSharpLint.Core/Framework/HintParserUtilities.fs @@ -213,6 +213,7 @@ module MergeSyntaxTrees = | None -> failwith "There's no last element in identifier." | _ -> 0 + [] let rec private getHashCode node = match node with | HintExpr(Expression.Identifier(identifier)) diff --git a/src/FSharpLint.Core/Framework/Utilities.fs b/src/FSharpLint.Core/Framework/Utilities.fs index 188f4145a..e79cc4f76 100644 --- a/src/FSharpLint.Core/Framework/Utilities.fs +++ b/src/FSharpLint.Core/Framework/Utilities.fs @@ -11,6 +11,8 @@ module Utilities = let () path1 path2 = System.IO.Path.Combine(path1, path2) + let returnEmptyArray () = Array.empty + module Dictionary = open System.Collections.Generic diff --git a/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs b/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs index f169e846b..0684c4d27 100644 --- a/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs +++ b/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs @@ -6,63 +6,78 @@ open FSharpLint.Framework open FSharpLint.Framework.Suggestion open FSharpLint.Framework.Ast open FSharpLint.Framework.Rules +open FSharpLint.Framework.Utilities -let rec checkExpression (expression: SynExpr) (range: range) = - match expression with - | SynExpr.Sequential (_, _, firstExpression, secondExpression, _, _) -> - let result = checkExpression firstExpression range - Array.append result (checkExpression secondExpression secondExpression.Range) - | SynExpr.Paren (innerExpression, _, _, range) -> checkExpression innerExpression range - | SynExpr.While (_, _, innerExpression, range) -> checkExpression innerExpression range - | SynExpr.For (_, _, _, _, _, _, _, innerExpression, range) -> checkExpression innerExpression range - | SynExpr.ForEach (_, _, _, _, _, _, innerExpression, range) -> checkExpression innerExpression range - | SynExpr.Match (_, _, clauses, range, _) -> - clauses - |> List.map (fun (SynMatchClause (_, _, clause, range, _, _)) -> checkExpression clause range) - |> List.toArray - |> Array.concat - | SynExpr.Do (innerExpression, range) -> checkExpression innerExpression range - | SynExpr.TryWith (tryExpression, withCases, tryRange, _, _, _) -> - withCases - |> List.map (fun (SynMatchClause (_, _, withCase, withRange, _, _)) -> checkExpression withCase withRange) - |> List.toArray - |> Array.concat - |> Array.append (checkExpression tryExpression tryRange) - | SynExpr.TryFinally (tryExpression, finallyExpr, range, _, _, _) -> - checkExpression finallyExpr range - |> Array.append (checkExpression tryExpression range) - | SynExpr.IfThenElse (_, thenExpr, elseExpr, _, _, range, _) -> - let checkThen = checkExpression thenExpr range - - match elseExpr with - | Some elseExpression -> - Array.append (checkExpression elseExpression range) checkThen - | None -> checkThen - | SynExpr.App (_, _, SynExpr.Ident failwithId, _, _) when - failwithId.idText = "failwith" - || failwithId.idText = "failwithf" - || failwithId.idText = "raise" - -> - Array.singleton - { - Range = range - Message = Resources.GetString "RulesAsyncExceptionWithoutReturn" - SuggestedFix = None - TypeChecks = List.Empty - } - | SynExpr.App (_, _, funcExpr, _, range) -> - checkExpression funcExpr range - | SynExpr.LetOrUse (_, _, _, body, range, _) -> - checkExpression body range - | _ -> Array.empty - +[] +let rec checkExpression (expression: SynExpr) (range: range) (continuation: unit -> array) = + Array.append + (match expression with + | SynExpr.Sequential (_, _, firstExpression, secondExpression, _, _) -> + checkExpression + firstExpression + range + (fun () -> (checkExpression secondExpression secondExpression.Range returnEmptyArray)) + | SynExpr.Paren (innerExpression, _, _, range) -> checkExpression innerExpression range returnEmptyArray + | SynExpr.While (_, _, innerExpression, range) -> checkExpression innerExpression range returnEmptyArray + | SynExpr.For (_, _, _, _, _, _, _, innerExpression, range) -> checkExpression innerExpression range returnEmptyArray + | SynExpr.ForEach (_, _, _, _, _, _, innerExpression, range) -> checkExpression innerExpression range returnEmptyArray + | SynExpr.Match (_, _, clauses, range, _) -> + let subExpressions = clauses |> List.map (fun (SynMatchClause (_, _, clause, range, _, _)) -> clause, range) + checkMultipleExpressions subExpressions returnEmptyArray + | SynExpr.Do (innerExpression, range) -> checkExpression innerExpression range returnEmptyArray + | SynExpr.TryWith (tryExpression, withCases, tryRange, _, _, _) -> + let subExpressions = + withCases |> List.map (fun (SynMatchClause (_, _, withCase, withRange, _, _)) -> withCase, withRange) + checkMultipleExpressions subExpressions (fun () -> checkExpression tryExpression tryRange returnEmptyArray) + | SynExpr.TryFinally (tryExpression, finallyExpr, range, _, _, _) -> + checkExpression tryExpression range (fun () -> checkExpression finallyExpr range returnEmptyArray) + | SynExpr.IfThenElse (_, thenExpr, elseExpr, _, _, range, _) -> + checkExpression + thenExpr + range + (fun () -> + match elseExpr with + | Some elseExpression -> + checkExpression elseExpression range returnEmptyArray + | None -> Array.empty) + + | SynExpr.App (_, _, SynExpr.Ident failwithId, _, _) when + failwithId.idText = "failwith" + || failwithId.idText = "failwithf" + || failwithId.idText = "raise" + -> + Array.singleton + { + Range = range + Message = Resources.GetString "RulesAsyncExceptionWithoutReturn" + SuggestedFix = None + TypeChecks = List.Empty + } + | SynExpr.App (_, _, funcExpr, _, range) -> + checkExpression funcExpr range returnEmptyArray + | SynExpr.LetOrUse (_, _, _, body, range, _) -> + checkExpression body range returnEmptyArray + | _ -> Array.empty) + (continuation ()) +and [] checkMultipleExpressions (expressions: list) (continuation: unit -> array) = + match expressions with + | (expression, range) :: tail -> + checkExpression + expression + range + (fun () -> + checkMultipleExpressions + tail + continuation) + | [] -> + continuation () let runner args = match args.AstNode with | AstNode.Expression ( SynExpr.App (_, _, (SynExpr.Ident compExprName), (SynExpr.ComputationExpr (_, innerExpression, _)), range) - ) when compExprName.idText = "async" -> checkExpression innerExpression range + ) when compExprName.idText = "async" -> checkExpression innerExpression range returnEmptyArray | _ -> Array.empty let rule = diff --git a/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs b/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs index 1441950e9..cf1986321 100644 --- a/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs +++ b/src/FSharpLint.Core/Rules/Conventions/FavourNonMutablePropertyInitialization.fs @@ -5,6 +5,7 @@ open FSharpLint.Framework.Suggestion open FSharp.Compiler.Syntax open FSharpLint.Framework.Ast open FSharpLint.Framework.Rules +open FSharpLint.Framework.Utilities open System let private getWarningDetails (ident: Ident) = @@ -32,57 +33,62 @@ let private extraInstanceMethod (app:SynExpr) (instanceMethodCalls: List | _ -> instanceMethodCalls | _ -> instanceMethodCalls +[] let rec private extraFromBindings (bindings: List) (classInstances: List) = match bindings with | SynBinding(_, _, _, _, _, _, _, SynPat.Named(SynIdent(ident, _), _, _, _), _, _expression, _, _, _)::rest -> extraFromBindings rest (ident.idText::classInstances) | _ -> classInstances -let rec private processLetBinding (instanceNames: Set) (body: SynExpr) : array = - match body with - | SynExpr.LongIdentSet(SynLongIdent(identifiers, _, _), _, _) -> - match identifiers with - | [instanceIdent; propertyIdent] when Set.contains instanceIdent.idText instanceNames -> - getWarningDetails propertyIdent - | _ -> Array.empty - | SynExpr.Sequential(_, _, expr1, expr2, _, _) -> - let instanceNames = - Set.difference +[] +let rec private processLetBinding (instanceNames: Set) (body: SynExpr) (continuation: unit -> array) : array = + Array.append + (match body with + | SynExpr.LongIdentSet(SynLongIdent(identifiers, _, _), _, _) -> + match identifiers with + | [instanceIdent; propertyIdent] when Set.contains instanceIdent.idText instanceNames -> + getWarningDetails propertyIdent + | _ -> Array.empty + | SynExpr.Sequential(_, _, expr1, expr2, _, _) -> + let instanceNames = + Set.difference + instanceNames + (extraInstanceMethod expr1 List.empty |> Set.ofList) + processLetBinding instanceNames - (extraInstanceMethod expr1 List.empty |> Set.ofList) - Array.append - (processLetBinding instanceNames expr1) - (processLetBinding instanceNames expr2) - | _ -> Array.empty + expr1 + (fun () -> processLetBinding instanceNames expr2 returnEmptyArray) + | _ -> Array.empty) + (continuation()) -and processExpression (expression: SynExpr) : array = - match expression with - | SynExpr.LetOrUse(_, _, bindings, body, _, _) -> - let instanceNames = extraFromBindings bindings List.Empty |> Set.ofList - processLetBinding instanceNames body - | SynExpr.Sequential(_, _, expr1, expr2, _, _) -> - Array.append - (processExpression expr1) - (processExpression expr2) - | _ -> Array.empty +and [] processExpression (expression: SynExpr) (continuation: unit -> array) : array = + Array.append + (match expression with + | SynExpr.LetOrUse(_, _, bindings, body, _, _) -> + let instanceNames = extraFromBindings bindings List.Empty |> Set.ofList + processLetBinding instanceNames body returnEmptyArray + | SynExpr.Sequential(_, _, expr1, expr2, _, _) -> + processExpression expr1 (fun () -> processExpression expr2 returnEmptyArray) + | _ -> Array.empty) + (continuation()) let runner args = match args.AstNode with | Binding(SynBinding(_, _, _, _, _, _, _, _, _, SynExpr.LetOrUse(_, _, bindings, body, _, _), _, _, _)) -> let instanceNames = extraFromBindings bindings List.Empty |> Set.ofList - processLetBinding instanceNames body + processLetBinding instanceNames body returnEmptyArray | Match(SynMatchClause(_, _, expr, _, _, _)) -> - processExpression expr + processExpression expr returnEmptyArray | Lambda(lambda, _) -> - processExpression lambda.Body + processExpression lambda.Body returnEmptyArray | Expression(SynExpr.TryWith(tryExpr, _, _, _, _, _)) -> - processExpression tryExpr + processExpression tryExpr returnEmptyArray | Expression(SynExpr.TryFinally(tryExpr, finallyExpr, _, _, _, _)) -> Array.append - (processExpression tryExpr) - (processExpression finallyExpr) + (processExpression tryExpr returnEmptyArray) + (processExpression finallyExpr returnEmptyArray) | Expression(SynExpr.ComputationExpr(_, expr, _)) -> - processExpression expr + processExpression expr returnEmptyArray | _ -> Array.empty let rule = diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs index 44e9e4b67..fe8c2fc06 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs @@ -8,6 +8,7 @@ open FSharpLint.Framework.Ast open FSharpLint.Framework.AstInfo open FSharpLint.Framework.Rules open FSharpLint.Framework.Suggestion +open FSharpLint.Framework.Utilities open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols @@ -310,9 +311,14 @@ let isImplicitModule (SynModuleOrNamespace.SynModuleOrNamespace(longIdent, _, mo type GetIdents<'Item> = AccessControlLevel -> SynPat -> 'Item [] -/// Recursively get all identifiers from pattern using provided getIdents function and collect them into array. -/// accessibility parameter is passed to getIdents, and can be narrowed down along the way (see checkAccessibility). -let rec getPatternIdents<'Item> (accessibility:AccessControlLevel) (getIdents:GetIdents<'Item>) argsAreParameters (pattern:SynPat) = +[] +let rec private innerGetPatternIdents<'Item> (accessibility:AccessControlLevel) + (getIdents:GetIdents<'Item>) + argsAreParameters + (pattern:SynPat) + (continuation: unit -> array<'Item>) = + (continuation()) + |> Array.append <| match pattern with | SynPat.LongIdent(_, _, _, args, access, _) -> let identAccessibility = checkAccessibility accessibility access @@ -322,36 +328,31 @@ let rec getPatternIdents<'Item> (accessibility:AccessControlLevel) (getIdents:Ge | SynArgPats.NamePatPairs(pats, _, _) -> pats.IsEmpty | SynArgPats.Pats(pats) -> pats.IsEmpty - let argSuggestions = - match args with + let idents = + // Only check if expecting args as parameters e.g. function - otherwise is a DU pattern. + if hasNoArgs || argsAreParameters then + getIdents identAccessibility pattern + else + Array.empty + + Array.append + idents + (match args with | SynArgPats.NamePatPairs(pats, _, _) -> - pats - |> List.toArray - |> Array.collect (fun(_, _, synPat) -> getPatternIdents AccessControlLevel.Private getIdents false synPat) + innerGetAllPatternIdents AccessControlLevel.Private getIdents (pats |> List.map (fun(_, _, synPat) -> synPat)) | SynArgPats.Pats(pats) -> - pats - |> List.toArray - |> Array.collect (getPatternIdents AccessControlLevel.Private getIdents false) - - // Only check if expecting args as parameters e.g. function - otherwise is a DU pattern. - if hasNoArgs || argsAreParameters then - getIdents identAccessibility pattern - |> Array.append argSuggestions - else - argSuggestions + innerGetAllPatternIdents AccessControlLevel.Private getIdents pats) | SynPat.Named(_, _, access, _) -> let accessibility = checkAccessibility accessibility access getIdents accessibility pattern | SynPat.Or(p1, p2, _, _) -> - Array.collect (getPatternIdents accessibility getIdents false) [|p1; p2|] + innerGetAllPatternIdents accessibility getIdents [p1; p2] | SynPat.Paren(pat, _) -> - getPatternIdents accessibility getIdents false pat + innerGetPatternIdents accessibility getIdents false pat returnEmptyArray | SynPat.Ands(pats, _) | SynPat.Tuple(_, pats, _, _) | SynPat.ArrayOrList(_, pats, _) -> - pats - |> List.toArray - |> Array.collect (getPatternIdents accessibility getIdents false) + innerGetAllPatternIdents accessibility getIdents pats | SynPat.Record(_) | SynPat.IsInst(_) | SynPat.QuoteExpr(_) @@ -364,13 +365,24 @@ let rec getPatternIdents<'Item> (accessibility:AccessControlLevel) (getIdents:Ge | SynPat.InstanceMember(_) | SynPat.FromParseError(_) -> Array.empty | SynPat.As(lhsPat, rhsPat, _) -> - Array.append - (getPatternIdents accessibility getIdents false lhsPat) - (getPatternIdents accessibility getIdents false rhsPat) + innerGetPatternIdents accessibility getIdents false lhsPat + (fun () -> innerGetPatternIdents accessibility getIdents false rhsPat returnEmptyArray) | SynPat.ListCons(lhs, rhs, _, _) -> - Array.append - (getPatternIdents accessibility getIdents false lhs) - (getPatternIdents accessibility getIdents false rhs) + innerGetPatternIdents accessibility getIdents false lhs + (fun () -> innerGetPatternIdents accessibility getIdents false rhs returnEmptyArray) + +and [] innerGetAllPatternIdents (accessibility: AccessControlLevel) + (getIdents: GetIdents<'Item>) + (patterns: list): array<'Item> = + match patterns with + | head::tail -> + innerGetPatternIdents accessibility getIdents false head (fun () -> innerGetAllPatternIdents accessibility getIdents tail) + | [] -> Array.empty + +/// Recursively get all identifiers from pattern using provided getIdents function and collect them into array. +/// accessibility parameter is passed to getIdents, and can be narrowed down along the way (see checkAccessibility). +let getPatternIdents<'Item> (accessibility:AccessControlLevel) (getIdents:GetIdents<'Item>) argsAreParameters (pattern:SynPat) = + innerGetPatternIdents accessibility getIdents argsAreParameters pattern returnEmptyArray let isNested args nodeIndex = let parent = args.SyntaxArray.[nodeIndex].ParentIndex diff --git a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs index 977655aee..999a90340 100644 --- a/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs +++ b/src/FSharpLint.Core/Rules/Conventions/NoPartialFunctions.fs @@ -114,6 +114,8 @@ let private checkIfPartialIdentifier (config:Config) (identifier:string) (range: TypeChecks = List.Empty }) +// not a tail-recursive function +// fsharplint:disable EnsureTailCallDiagnosticsInRecursiveFunctions let rec private tryFindTypedExpression (range: Range) (expression: FSharpExpr) = let tryFindFirst exprs = exprs |> Seq.choose (tryFindTypedExpression range) |> Seq.tryHead @@ -208,6 +210,7 @@ let rec private tryFindTypedExpression (range: Range) (expression: FSharpExpr) = | FSharpExprPatterns.WhileLoop(guardExpr, bodyExpr, _) -> tryFindTypedExpression range guardExpr |> Option.orElse (tryFindTypedExpression range bodyExpr) | _ -> None +// fsharplint:enable EnsureTailCallDiagnosticsInRecursiveFunctions let private getTypedExpressionForRange (checkFile:FSharpCheckFileResults) (range: Range) = let expressions = diff --git a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs index 8a8bbb0da..2abeea3ec 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs @@ -6,10 +6,12 @@ open FSharpLint.Framework open FSharpLint.Framework.Suggestion open FSharpLint.Framework.Ast open FSharpLint.Framework.Rules +open FSharpLint.Framework.Utilities -let rec private isImmutableValueExpression (args: AstNodeRuleParams) (expression: SynExpr) = +[] +let rec private isImmutableValueExpression (args: AstNodeRuleParams) (expression: SynExpr) (continuation: bool -> bool) = match expression with - | SynExpr.Const (_constant, _range) -> true + | SynExpr.Const (_constant, _range) -> continuation true | SynExpr.Ident ident -> let isMutableVariable = let exists memberDef = @@ -27,21 +29,40 @@ let rec private isImmutableValueExpression (args: AstNodeRuleParams) (expression List.exists exists members | _ -> false - not isMutableVariable + not isMutableVariable |> continuation | SynExpr.ArrayOrList (_, elements, _) -> - List.forall (isImmutableValueExpression args) elements + areImmutableAllValueExpressions args elements id | SynExpr.ArrayOrListComputed (_, innerExpr, _) -> - isImmutableValueExpression args innerExpr - || isImmutableSequentialExpression args innerExpr - | _ -> false + isImmutableValueExpression + args + innerExpr + (fun prevResult -> prevResult || isImmutableSequentialExpression args innerExpr id) + | _ -> continuation false + +and [] areImmutableAllValueExpressions (args: AstNodeRuleParams) (expressions: list) (continuation: bool -> bool) = + match expressions with + | head::tail -> + areImmutableAllValueExpressions + args + tail + (fun prevResult -> + isImmutableValueExpression args head (fun prevResult2 -> prevResult2 && prevResult)) + | [] -> continuation true -and isImmutableSequentialExpression args expression = +and [] isImmutableSequentialExpression args expression (continuation: bool -> bool) = match expression with | SynExpr.Sequential (_, _, expr1, expr2, _, _) -> - isImmutableValueExpression args expr1 - && (isImmutableSequentialExpression args expr2 - || isImmutableValueExpression args expr2) - | _ -> false + isImmutableValueExpression + args + expr1 + (fun prevResult -> + isImmutableSequentialExpression args expr2 + (fun prevResult2 -> + isImmutableValueExpression args expr2 + (fun prevResult3 -> prevResult && prevResult2 || prevResult3) + ) + ) + | _ -> continuation false let private hasStructAttribute node = match node with @@ -83,7 +104,7 @@ let private runner (args: AstNodeRuleParams) = match expr, argPats with | _, SynArgPats.Pats pats when pats.Length > 0 -> // non-property member Array.empty - | expression, _ when isImmutableValueExpression args expression -> + | expression, _ when isImmutableValueExpression args expression id -> match args.GetParents args.NodeIndex with | parentNode :: _ when hasStructAttribute parentNode -> Array.empty diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index 7bbad1452..24030523b 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -216,6 +216,8 @@ module private MatchExpression = | Match of (unit -> bool) list | NoMatch + let internal returnEmptyMatch () = Match List.Empty + let private (&&~) lhs rhs = match (lhs, rhs) with | Match(asyncLhs), Match(asyncRhs) -> Match(asyncLhs @ asyncRhs) @@ -252,10 +254,12 @@ module private MatchExpression = | _ -> Match(List.Empty) | _ -> Match(List.Empty) - let rec matchHintExpr arguments = + [] + let rec matchHintExpr (continuation: unit -> HintMatch) arguments = let expr = removeParens arguments.Expression let arguments = { arguments with Expression = expr } + (continuation ()) &&~ match arguments.Hint with | Expression.Variable(variable) when Map.containsKey variable arguments.LambdaArguments -> match expr with @@ -276,7 +280,7 @@ module private MatchExpression = if matchExpr expr = Some(arguments.Hint) then Match(List.Empty) else NoMatch | Expression.Parentheses(hint) -> - arguments.SubHint(expr, hint) |> matchHintExpr + arguments.SubHint(expr, hint) |> matchHintExpr returnEmptyMatch | Expression.Tuple(_) -> matchTuple arguments | Expression.List(_) -> @@ -298,99 +302,123 @@ module private MatchExpression = | Expression.LambdaBody(_) -> NoMatch | Expression.Else(_) -> NoMatch - and private matchFunctionApplication arguments = + and [] private matchFunctionApplication arguments = match (arguments.Expression, arguments.Hint) with | FuncApp(exprs, _), Expression.FunctionApplication(hintExprs) -> let expressions = List.map AstNode.Expression exprs doExpressionsMatch expressions hintExprs arguments | _ -> NoMatch - and private doExpressionsMatch expressions hintExpressions (arguments:Arguments) = + and [] private doExpressionsMatch expressions hintExpressions (arguments:Arguments) = if List.length expressions = List.length hintExpressions then - (expressions, hintExpressions) - ||> List.map2 (fun expr hint -> arguments.SubHint(expr, hint) |> matchHintExpr) - |> List.fold (&&~) (Match(List.Empty)) + let subHints = + (expressions, hintExpressions) + ||> List.map2 (fun expr hint -> arguments.SubHint(expr, hint)) + + let rec innerDoExpressionsMatch args: HintMatch = + match args with + | head::tail -> + head |> matchHintExpr (fun () -> innerDoExpressionsMatch tail) + | [] -> Match(List.Empty) + + innerDoExpressionsMatch subHints else NoMatch - and private matchIf arguments = + and [] private matchIf arguments = match (arguments.Expression, arguments.Hint) with | (AstNode.Expression(SynExpr.IfThenElse(cond, expr, None, _, _, _, _)), Expression.If(hintCond, hintExpr, None)) -> - arguments.SubHint(Expression cond, hintCond) |> matchHintExpr &&~ - (arguments.SubHint(Expression expr, hintExpr) |> matchHintExpr) + matchHintExpr + (fun () -> (arguments.SubHint(Expression expr, hintExpr) |> matchHintExpr returnEmptyMatch)) + (arguments.SubHint(Expression cond, hintCond)) | (AstNode.Expression(SynExpr.IfThenElse(cond, expr, Some(elseExpr), _, _, _, _)), Expression.If(hintCond, hintExpr, Some(Expression.Else(hintElseExpr)))) -> - arguments.SubHint(Expression cond, hintCond) |> matchHintExpr &&~ - (arguments.SubHint(Expression expr, hintExpr) |> matchHintExpr) &&~ - (arguments.SubHint(Expression elseExpr, hintElseExpr) |> matchHintExpr) + matchHintExpr + (fun () -> + matchHintExpr + (fun () -> arguments.SubHint(Expression expr, hintExpr) |> matchHintExpr returnEmptyMatch) + (arguments.SubHint(Expression elseExpr, hintElseExpr))) + (arguments.SubHint(Expression cond, hintCond)) + | _ -> NoMatch - and matchLambda arguments = + and [] matchLambda arguments = match (arguments.Expression, arguments.Hint) with | Lambda({ Arguments = args; Body = body }, _), Expression.Lambda(lambdaArgs, LambdaBody(Expression.LambdaBody(lambdaBody))) -> match matchLambdaArguments lambdaArgs args with | LambdaMatch.Match(lambdaArguments) -> - matchHintExpr { arguments.SubHint(AstNode.Expression(body), lambdaBody) with LambdaArguments = lambdaArguments } + matchHintExpr + returnEmptyMatch + { arguments.SubHint(AstNode.Expression(body), lambdaBody) with LambdaArguments = lambdaArguments } | LambdaMatch.NoMatch -> NoMatch | _ -> NoMatch - and private matchTuple arguments = + and [] private matchTuple arguments = match (arguments.Expression, arguments.Hint) with | AstNode.Expression(SynExpr.Tuple(_, expressions, _, _)), Expression.Tuple(hintExpressions) -> let expressions = List.map AstNode.Expression expressions doExpressionsMatch expressions hintExpressions arguments | _ -> NoMatch - and private matchList arguments = + and [] private matchList arguments = match (arguments.Expression, arguments.Hint) with | AstNode.Expression(SynExpr.ArrayOrList(false, expressions, _)), Expression.List(hintExpressions) -> let expressions = List.map AstNode.Expression expressions doExpressionsMatch expressions hintExpressions arguments | AstNode.Expression(SynExpr.ArrayOrListComputed(false, expression, _)), Expression.List([hintExpression]) -> - arguments.SubHint(AstNode.Expression(expression), hintExpression) |> matchHintExpr + arguments.SubHint(AstNode.Expression(expression), hintExpression) |> matchHintExpr returnEmptyMatch | _ -> NoMatch - and private matchArray arguments = + and [] private matchArray arguments = match (arguments.Expression, arguments.Hint) with | AstNode.Expression(SynExpr.ArrayOrList(true, expressions, _)), Expression.Array(hintExpressions) -> let expressions = List.map AstNode.Expression expressions doExpressionsMatch expressions hintExpressions arguments | AstNode.Expression(SynExpr.ArrayOrListComputed(true, expression, _)), Expression.Array([hintExpression]) -> - arguments.SubHint(AstNode.Expression(expression), hintExpression) |> matchHintExpr + arguments.SubHint(AstNode.Expression(expression), hintExpression) |> matchHintExpr returnEmptyMatch | _ -> NoMatch - and private matchInfixOperation arguments = + and [] private matchInfixOperation arguments = match (arguments.Expression, arguments.Hint) with | (AstNode.Expression(SynExpr.App(_, true, (ExpressionUtilities.Identifier(_) as opExpr), SynExpr.Tuple(_, [leftExpr; rightExpr], _, _), _)), Expression.InfixOperator(op, left, right)) -> - arguments.SubHint(AstNode.Expression(opExpr), op) |> matchHintExpr &&~ - (arguments.SubHint(AstNode.Expression(rightExpr), right) |> matchHintExpr) &&~ - (arguments.SubHint(AstNode.Expression(leftExpr), left) |> matchHintExpr) + matchHintExpr + (fun () -> + matchHintExpr + (fun () -> arguments.SubHint(AstNode.Expression(rightExpr), right) |> matchHintExpr returnEmptyMatch) + (arguments.SubHint(AstNode.Expression(leftExpr), left))) + (arguments.SubHint(AstNode.Expression(opExpr), op)) | (AstNode.Expression(SynExpr.App(_, _, infixExpr, rightExpr, _)), Expression.InfixOperator(op, left, right)) -> match removeParens <| AstNode.Expression(infixExpr) with | AstNode.Expression(SynExpr.App(_, true, opExpr, leftExpr, _)) -> - arguments.SubHint(AstNode.Expression(opExpr), op) |> matchHintExpr &&~ - (arguments.SubHint(AstNode.Expression(leftExpr), left) |> matchHintExpr) &&~ - (arguments.SubHint(AstNode.Expression(rightExpr), right) |> matchHintExpr) &&~ - notPropertyInitialisationOrNamedParameter arguments leftExpr opExpr + matchHintExpr + (fun () -> + matchHintExpr + (fun () -> + matchHintExpr + (fun () -> notPropertyInitialisationOrNamedParameter arguments leftExpr opExpr) + (arguments.SubHint(AstNode.Expression(rightExpr), right))) + (arguments.SubHint(AstNode.Expression(leftExpr), left))) + (arguments.SubHint(AstNode.Expression(opExpr), op)) | _ -> NoMatch | _ -> NoMatch - and private matchPrefixOperation arguments = + and [] private matchPrefixOperation arguments = match (arguments.Expression, arguments.Hint) with | (AstNode.Expression(SynExpr.App(_, _, opExpr, rightExpr, _)), Expression.PrefixOperator(Expression.Identifier([op]), expr)) -> - arguments.SubHint(AstNode.Expression(opExpr), Expression.Identifier([op])) |> matchHintExpr &&~ - (arguments.SubHint(AstNode.Expression(rightExpr), expr) |> matchHintExpr) + matchHintExpr + (fun () -> arguments.SubHint(AstNode.Expression(rightExpr), expr) |> matchHintExpr returnEmptyMatch) + (arguments.SubHint(AstNode.Expression(opExpr), Expression.Identifier([op]))) | _ -> NoMatch - and private matchAddressOf arguments = + and [] private matchAddressOf arguments = match (arguments.Expression, arguments.Hint) with | AstNode.Expression(SynExpr.AddressOf(synSingleAmp, addrExpr, _, _)), Expression.AddressOf(singleAmp, expr) when synSingleAmp = singleAmp -> - arguments.SubHint(AstNode.Expression(addrExpr), expr) |> matchHintExpr + arguments.SubHint(AstNode.Expression(addrExpr), expr) |> matchHintExpr returnEmptyMatch | _ -> NoMatch module private MatchPattern = @@ -410,9 +438,13 @@ module private MatchPattern = | SynPat.Paren(pattern, _) -> removeParens pattern | pat -> pat - let rec matchHintPattern (pattern, hint) = + let internal returnTrue () = true + + [] + let rec matchHintPattern (continuation: unit -> bool) (pattern, hint) = let pattern = removeParens pattern + (continuation ()) && match hint with | Pattern.Variable(_) | Pattern.Wildcard -> @@ -426,7 +458,7 @@ module private MatchPattern = | Pattern.Or(_) -> matchOrPattern (pattern, hint) | Pattern.Parentheses(hint) -> - matchHintPattern (pattern, hint) + matchHintPattern returnTrue (pattern, hint) | Pattern.Tuple(_) -> matchTuple (pattern, hint) | Pattern.List(_) -> @@ -434,38 +466,52 @@ module private MatchPattern = | Pattern.Array(_) -> matchArray (pattern, hint) - and private doPatternsMatch patterns hintExpressions = - (List.length patterns = List.length hintExpressions) - && (patterns, hintExpressions) ||> List.forall2 (fun pattern hint -> matchHintPattern (pattern, hint)) + and [] private doPatternsMatch patterns hintExpressions = + if List.length patterns = List.length hintExpressions then + let rec innerDoPatternsMatch lst = + match lst with + | (pattern, hintExpression) :: tail -> + matchHintPattern + (fun () -> innerDoPatternsMatch tail) + (pattern, hintExpression) + | [] -> true + + innerDoPatternsMatch (List.zip patterns hintExpressions) + else + false - and private matchList (pattern, hint) = + and [] private matchList (pattern, hint) = match (pattern, hint) with | SynPat.ArrayOrList(false, patterns, _), Pattern.List(hintExpressions) -> doPatternsMatch patterns hintExpressions | _ -> false - and private matchArray (pattern, hint) = + and [] private matchArray (pattern, hint) = match (pattern, hint) with | SynPat.ArrayOrList(true, patterns, _), Pattern.Array(hintExpressions) -> doPatternsMatch patterns hintExpressions | _ -> false - and private matchTuple (pattern, hint) = + and [] private matchTuple (pattern, hint) = match (pattern, hint) with | SynPat.Tuple(_, patterns, _, _), Pattern.Tuple(hintExpressions) -> doPatternsMatch patterns hintExpressions | _ -> false - and private matchConsPattern (pattern, hint) = + and [] private matchConsPattern (pattern, hint) = match (pattern, hint) with | Cons(leftPattern, rightPattern), Pattern.Cons(left, right) -> - matchHintPattern (leftPattern, left) && matchHintPattern (rightPattern, right) + matchHintPattern + (fun () -> matchHintPattern returnTrue (rightPattern, right)) + (leftPattern, left) | _ -> false - and private matchOrPattern (pattern, hint) = + and [] private matchOrPattern (pattern, hint) = match (pattern, hint) with | SynPat.Or(leftPattern, rightPattern, _, _), Pattern.Or(left, right) -> - matchHintPattern (leftPattern, left) && matchHintPattern (rightPattern, right) + matchHintPattern + (fun () -> matchHintPattern returnTrue (rightPattern, right)) + (leftPattern, left) | _ -> false module private FormatHint = @@ -504,6 +550,9 @@ module private FormatHint = Debug.Assert(false, $"Expected operator to be an expression identifier, but was {expression.ToString()}") String.Empty + // very hard to turn into tail-recursive form because of the way it operates + // (convert sub-expressions to strings and then combine them) + // fsharplint:disable EnsureTailCallDiagnosticsInRecursiveFunctions let rec toString (config: ToStringConfig) = let toString hintNode = toString @@ -597,6 +646,7 @@ module private FormatHint = arguments |> List.map (fun (LambdaArg expr) -> exprToString expr) |> String.concat " " + // fsharplint:enable EnsureTailCallDiagnosticsInRecursiveFunctions type HintErrorConfig = { @@ -699,7 +749,7 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParserTypes.Hin match (args.AstNode, hint.MatchedNode) with | AstNode.Expression(SynExpr.Paren(_)), HintExpr(_) | AstNode.Pattern(SynPat.Paren(_)), HintPat(_) -> () - | AstNode.Pattern(pattern), HintPat(hintPattern) when MatchPattern.matchHintPattern (pattern, hintPattern) -> + | AstNode.Pattern(pattern), HintPat(hintPattern) when MatchPattern.matchHintPattern MatchPattern.returnTrue (pattern, hintPattern) -> hintError { TypeChecks = List.Empty @@ -719,7 +769,7 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParserTypes.Hin MatchExpression.FSharpCheckFileResults = args.CheckInfo MatchExpression.Breadcrumbs = breadcrumbs } - match MatchExpression.matchHintExpr arguments with + match MatchExpression.matchHintExpr MatchExpression.returnEmptyMatch arguments with | MatchExpression.Match(typeChecks) -> let suggest checks = hintError diff --git a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs index 0c08b48eb..e9a96c1f9 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintsHelper.fs @@ -39,6 +39,8 @@ let inline private isParen (node:AbstractSyntaxArray.Node) = | AstNode.Expression(SynExpr.Paren(_)) -> true | _ -> false +// hard to turn into tail-recursive form +// fsharplint:disable EnsureTailCallDiagnosticsInRecursiveFunctions /// Compares the hint trie against a given location in the abstract syntax array. let rec checkTrie index trie (nodeArray:AbstractSyntaxArray.Node []) (boundVariables:Dictionary<_, _>) notify = List.iter notify trie.MatchedHint @@ -67,4 +69,4 @@ let rec checkTrie index trie (nodeArray:AbstractSyntaxArray.Node []) (boundVaria | None -> checkTrie (index + node.NumberOfChildren + 1) trie nodeArray boundVariables notify List.iter (fun (var, trie) -> collect var trie) trie.Edges.AnyMatch - +// fsharplint:enable EnsureTailCallDiagnosticsInRecursiveFunctions From bca8db73ec6a1256161f68ee0561e62756e45c80 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 7 Feb 2024 16:55:55 +0330 Subject: [PATCH 41/48] build: refactoring for rule activation This refactoring activates all rules by default and only deactivates the specified ones. --- build.fsx | 65 +++++++++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/build.fsx b/build.fsx index 2a6cd0851..f2db82349 100644 --- a/build.fsx +++ b/build.fsx @@ -264,48 +264,41 @@ Target.create "SelfCheck" (fun _ -> let fsharplintJsonDir = Path.Combine("src", "FSharpLint.Core", "fsharplint.json") let fsharplintJsonText = File.ReadAllText fsharplintJsonDir - let recommendedRules = - [ - "recursiveAsyncFunction" - (* - "nestedStatements" // not enable for now - "cyclomaticComplexity" rule is too complex and we can enable it later - *) - "avoidSinglePipeOperator" - "maxLinesInLambdaFunction" - "maxLinesInMatchLambdaFunction" - "maxLinesInValue" - "maxLinesInFunction" - "maxLinesInMember" - "maxLinesInConstructor" - "maxLinesInProperty" - "maxLinesInModule" - "maxLinesInRecord" - "maxLinesInEnum" - "maxLinesInUnion" - "maxLinesInClass" - "favourTypedIgnore" - "favourStaticEmptyFields" - "favourConsistentThis" - "avoidTooShortNames" - "asyncExceptionWithoutReturn" - "maxNumberOfItemsInTuple" - "maxNumberOfFunctionParameters" - "maxNumberOfMembers" - "maxNumberOfBooleanOperatorsInCondition" + let excludedRules = + [ + "typedItemSpacing" + "typePrefixing" + "unionDefinitionIndentation" + "moduleDeclSpacing" + "classMemberSpacing" + "tupleCommaSpacing" + "tupleIndentation" + "tupleParentheses" + "patternMatchClausesOnNewLine" + "patternMatchOrClausesOnNewLine" + "patternMatchClauseIndentation" + "patternMatchExpressionIndentation" + // rule is too complex and we can enable it later + "cyclomaticComplexity" + "unnestedFunctionNames" + "nestedFunctionNames" + "indentation" + "maxCharactersOnLine" + "trailingWhitespaceOnLine" + "trailingNewLineInFile" + // not enable for now + "nestedStatements" // Running NoPartialFunctions on this file causes a bug in FSharp.Compiler, so skip it for now - // "noPartialFunctions" - "suggestUseAutoProperty" - "maxLinesInFile" + "noPartialFunctions" ] let jsonObj = JObject.Parse fsharplintJsonText - for key in recommendedRules do - let token = jsonObj.SelectToken key + for pair in jsonObj do + let isRule = (jsonObj.SelectToken pair.Key).SelectToken("enabled") - if not (isNull token) then - token.SelectToken("enabled").Replace(JValue true) |> ignore + if not (isNull isRule) && not (List.contains pair.Key excludedRules) then + isRule.Replace(JValue true) |> ignore File.WriteAllText(fsharplintJsonDir, jsonObj.ToString()) From 6cc56af8f8d6d34043ebc8ad09c81791ab0af7ad Mon Sep 17 00:00:00 2001 From: webwarrior-ws Date: Wed, 13 Aug 2025 13:06:22 +0200 Subject: [PATCH 42/48] build.fsx: use System.Text.Json Instead of Newtonsoft.Json, given that FSharpLint has moved away already from Newtonsoft. --- build.fsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/build.fsx b/build.fsx index f2db82349..a067175ea 100644 --- a/build.fsx +++ b/build.fsx @@ -36,10 +36,10 @@ open Fake.IO.FileSystemOperators open Fake.IO.Globbing.Operators open Fake.Core.TargetOperators open Fake.Api -open Newtonsoft.Json.Linq open System open System.IO +open System.Text.Json.Nodes Target.initEnvironment() @@ -292,15 +292,16 @@ Target.create "SelfCheck" (fun _ -> "noPartialFunctions" ] - let jsonObj = JObject.Parse fsharplintJsonText + let jsonObj = JsonObject.Parse fsharplintJsonText - for pair in jsonObj do - let isRule = (jsonObj.SelectToken pair.Key).SelectToken("enabled") + for pair in jsonObj.AsObject() do + if pair.Value.GetValueKind() = Text.Json.JsonValueKind.Object then + match pair.Value.AsObject().TryGetPropertyValue("enabled") with + | true, isRule when not (List.contains pair.Key excludedRules) -> + isRule.AsValue().ReplaceWith true + | _ -> () - if not (isNull isRule) && not (List.contains pair.Key excludedRules) then - isRule.Replace(JValue true) |> ignore - - File.WriteAllText(fsharplintJsonDir, jsonObj.ToString()) + File.WriteAllText(fsharplintJsonDir, jsonObj.ToJsonString()) printfn "Now re-running self-check with more rules enabled..." runLinter ()) From 16281e2c2c68e94b7e7da59a2e013e3748d9cad4 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 8 Feb 2024 13:46:46 +0330 Subject: [PATCH 43/48] tests: refactoring for DRY principle --- tests/FSharpLint.Benchmarks/Benchmark.fs | 3 +-- tests/FSharpLint.FunctionalTest/TestApi.fs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/FSharpLint.Benchmarks/Benchmark.fs b/tests/FSharpLint.Benchmarks/Benchmark.fs index 4bec7ca83..63f5e703c 100644 --- a/tests/FSharpLint.Benchmarks/Benchmark.fs +++ b/tests/FSharpLint.Benchmarks/Benchmark.fs @@ -6,6 +6,7 @@ open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Text open FSharpLint.Application.Lint open FSharpLint.Framework +open FSharpLint.Framework.Utilities type Benchmark () = @@ -23,8 +24,6 @@ type Benchmark () = parseResults.ParseTree - let () basePath relativePath = Path.Combine(basePath, relativePath) - let basePath = ".." ".." ".." ".." ".." ".." ".." ".." let sourceFile = basePath "TypeChecker.fs" diff --git a/tests/FSharpLint.FunctionalTest/TestApi.fs b/tests/FSharpLint.FunctionalTest/TestApi.fs index 8af626b7b..d7fe3282b 100644 --- a/tests/FSharpLint.FunctionalTest/TestApi.fs +++ b/tests/FSharpLint.FunctionalTest/TestApi.fs @@ -8,8 +8,7 @@ module TestApi = open FSharpLint.Application.Lint open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Text - - let () basePath relativePath = Path.Combine(basePath, relativePath) + open FSharpLint.Framework.Utilities let basePath = TestContext.CurrentContext.TestDirectory ".." ".." ".." ".." ".." From 628b1786e7f913ecd87e42a45ab7f195c536a6cb Mon Sep 17 00:00:00 2001 From: webwarrior-ws Date: Wed, 13 Aug 2025 14:46:27 +0200 Subject: [PATCH 44/48] Core: rename some funcs and params To address PR review. --- src/FSharpLint.Core/Prelude.fs | 12 ++++++------ .../Rules/Conventions/Binding/UselessBinding.fs | 2 +- .../Conventions/UsedUnderscorePrefixedElements.fs | 4 ++-- .../PatternMatchClauseIndentation.fs | 4 ++-- .../PatternMatchExpressionIndentation.fs | 4 ++-- .../Formatting/TupleFormatting/TupleParentheses.fs | 4 ++-- .../Rules/Typography/NoTabCharacters.fs | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/FSharpLint.Core/Prelude.fs b/src/FSharpLint.Core/Prelude.fs index 23a525c3b..98ba09480 100644 --- a/src/FSharpLint.Core/Prelude.fs +++ b/src/FSharpLint.Core/Prelude.fs @@ -4,11 +4,11 @@ namespace FSharpLint.Core module Prelude = module Async = - let combine operation firstAsync secondAsync = async { - let! firstOperation = firstAsync - let! secondOperation = secondAsync + let combine operation job1 job2 = async { + let! firstOperation = job1 + let! secondOperation = job2 return operation firstOperation secondOperation } - let map operation xAsync = async { - let! xAsyncArg = xAsync - return operation xAsyncArg } \ No newline at end of file + let map operation job = async { + let! jobResult = job + return operation jobResult } diff --git a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs index 9b9190b71..380457eb2 100644 --- a/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs +++ b/src/FSharpLint.Core/Rules/Conventions/Binding/UselessBinding.fs @@ -19,7 +19,7 @@ let private checkForUselessBinding (checkInfo:FSharpCheckFileResults option) pat let isNotMutable (symbol:FSharpSymbolUse) = match symbol.Symbol with - | :? FSharpMemberOrFunctionOrValue as fSharpMemberOrFunctionOrValue -> not fSharpMemberOrFunctionOrValue.IsMutable + | :? FSharpMemberOrFunctionOrValue as fsharpElement -> not fsharpElement.IsMutable | _ -> true let checkNotMutable (ident:Ident) = fun () -> diff --git a/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs b/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs index 283b2f4b1..513db8f9a 100644 --- a/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs +++ b/src/FSharpLint.Core/Rules/Conventions/UsedUnderscorePrefixedElements.fs @@ -13,7 +13,7 @@ open FSharpLint.Framework.Rules let runner (args: AstNodeRuleParams) = // hack to only run rule once if args.NodeIndex = 0 then - let choose (usage: FSharpSymbolUse) = + let processSymbolUse (usage: FSharpSymbolUse) = match usage.Symbol with | :? FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue as symbol -> let conditions = @@ -35,7 +35,7 @@ let runner (args: AstNodeRuleParams) = match args.CheckInfo with | Some checkResults -> checkResults.GetAllUsesOfAllSymbolsInFile() - |> Seq.choose choose + |> Seq.choose processSymbolUse |> Seq.toArray | None -> Array.empty else diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs index e0d57603c..1e921c4ce 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchClauseIndentation.fs @@ -16,7 +16,7 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa let indentationLevelError = - let bind (firstClause: SynMatchClause) = + let processClause (firstClause: SynMatchClause) = let clauseIndentation = ExpressionUtilities.getLeadingSpaces firstClause.Range args.FileContent if isLambda then if clauseIndentation <> matchStartIndentation + args.GlobalConfig.numIndentationSpaces then @@ -45,7 +45,7 @@ let check (config:Config) (args:AstNodeRuleParams) matchExprRange (clauses:SynMa else clauses |> List.tryHead - |> Option.bind bind + |> Option.bind processClause let consistentIndentationErrors = let choose (clauseOneSpaces: int) (clauseTwo: SynMatchClause) (clauseTwoSpaces: int) = diff --git a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs index a380f98a8..b398fbd45 100644 --- a/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs +++ b/src/FSharpLint.Core/Rules/Formatting/PatternMatchFormatting/PatternMatchExpressionIndentation.fs @@ -9,7 +9,7 @@ open FSharpLint.Framework.Rules open FSharpLint.Rules.Helper let check (args:AstNodeRuleParams) _ (clauses:SynMatchClause list) _ = - let choose clause = + let processClause clause = let (SynMatchClause (pat, guard, expr, _, _, _)) = clause let clauseIndentation = ExpressionUtilities.getLeadingSpaces clause.Range args.FileContent let exprIndentation = ExpressionUtilities.getLeadingSpaces expr.Range args.FileContent @@ -30,7 +30,7 @@ let check (args:AstNodeRuleParams) _ (clauses:SynMatchClause list) _ = clauses |> List.toArray - |> Array.choose choose + |> Array.choose processClause let runner (args:AstNodeRuleParams) = PatternMatchFormatting.isActualPatternMatch args check diff --git a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs index d6a3e6af2..d388940b5 100644 --- a/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs +++ b/src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleParentheses.fs @@ -9,7 +9,7 @@ open FSharpLint.Framework.Rules open FSharpLint.Rules.Helper let checkTupleHasParentheses (args:AstNodeRuleParams) _ range parentNode = - let map text = + let processText text = let suggestedFix = lazy (Some @@ -31,7 +31,7 @@ let checkTupleHasParentheses (args:AstNodeRuleParams) _ range parentNode = Array.empty | _ -> ExpressionUtilities.tryFindTextOfRange range args.FileContent - |> Option.map map + |> Option.map processText |> Option.toArray let runner (args:AstNodeRuleParams) = TupleFormatting.isActualTuple args checkTupleHasParentheses diff --git a/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs b/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs index 3c3b5b7c0..4fa34d427 100644 --- a/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs +++ b/src/FSharpLint.Core/Rules/Typography/NoTabCharacters.fs @@ -18,7 +18,7 @@ module ContextBuilder = current let private isInLiteralString literalStrings range = - Seq.exists (fun (_, literalRange) -> ExpressionUtilities.rangeContainsOtherRange literalRange range) literalStrings + Seq.exists (fun (_, literalRange) -> ExpressionUtilities.rangeContainsOtherRange literalRange range) literalStrings let checkNoTabCharacters literalStrings (args:LineRuleParams) = let indexOfTab = args.Line.IndexOf('\t') From c5388d43875f1ceb5154b0af0c0f0a83a89d1387 Mon Sep 17 00:00:00 2001 From: webwarrior-ws Date: Wed, 13 Aug 2025 14:48:39 +0200 Subject: [PATCH 45/48] tests: add *why* & re-enable rule after To address PR review. Also include previous commit in .git-blame-ignore-revs since it's only renames. --- .git-blame-ignore-revs | 8 +++++++- .../Framework/TestFuzzyHintMatcher.fs | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 9c8817e4a..9785438c9 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -3,4 +3,10 @@ # that they are unlikely to be what you are interested in when blaming. # Like formatting with Fantomas # https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view -# Add formatting commits here + +# Console,Core,Tests: fix FSharpLint warning (Fixing the warning for AvoidTooShortNames rule.) +e9410e83af1de4d76230b0e8d44ae6a99fac6d7b + +# Core: rename some funcs and params +628b1786e7f913ecd87e42a45ab7f195c536a6cb + diff --git a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs index 9286305a9..01de9df97 100644 --- a/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs +++ b/tests/FSharpLint.Core.Tests/Framework/TestFuzzyHintMatcher.fs @@ -11,8 +11,6 @@ open NUnit.Framework open FParsec open TestUtils -// fsharplint:disable MaxLinesInValue MaxLinesInMember - let possibleMatches (syntaxArray:AbstractSyntaxArray.Node []) (hintTrie:Edges) notify = for i = 0 to syntaxArray.Length - 1 do let node = syntaxArray.[i] @@ -29,6 +27,8 @@ type TestAst() = | Success(hint, _, _) -> hint | Failure(message, _, _) -> failwith message + // List of hints is quite big and would trigger MaxLinesInValue and MaxLinesInMember rules. + // fsharplint:disable MaxLinesInValue MaxLinesInMember [] [] member _.``Performance of matching fuzzy matching hints``() = @@ -149,6 +149,7 @@ type TestAst() = stopwatch.Stop() Assert.Less(stopwatch.ElapsedMilliseconds, 50) fprintf TestContext.Out "Iterated array in %d milliseconds." stopwatch.ElapsedMilliseconds + // fsharplint:enable MaxLinesInValue MaxLinesInMember [] [] From 7fdbff085289434d835821a354aaf2b6f0e619ba Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Wed, 13 Aug 2025 18:41:02 +0200 Subject: [PATCH 46/48] build.fsx: improve comments about excluded rules --- build.fsx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/build.fsx b/build.fsx index a067175ea..0bfdba7ff 100644 --- a/build.fsx +++ b/build.fsx @@ -266,30 +266,36 @@ Target.create "SelfCheck" (fun _ -> let excludedRules = [ + // Formatting rules (maybe mark them as DEPRECATED soon, recommending the use of `fantomas` instead) "typedItemSpacing" - "typePrefixing" "unionDefinitionIndentation" "moduleDeclSpacing" "classMemberSpacing" "tupleCommaSpacing" "tupleIndentation" - "tupleParentheses" "patternMatchClausesOnNewLine" "patternMatchOrClausesOnNewLine" "patternMatchClauseIndentation" "patternMatchExpressionIndentation" - // rule is too complex and we can enable it later - "cyclomaticComplexity" - "unnestedFunctionNames" - "nestedFunctionNames" "indentation" "maxCharactersOnLine" - "trailingWhitespaceOnLine" "trailingNewLineInFile" - // not enable for now + "trailingWhitespaceOnLine" + + // TODO: investigate if useful + "tupleParentheses" + + // TODO: we should enable at some point + "typePrefixing" + "unnestedFunctionNames" + "nestedFunctionNames" "nestedStatements" + // Running NoPartialFunctions on this file causes a bug in FSharp.Compiler, so skip it for now "noPartialFunctions" + + // rule is too complex, we can enable it later + "cyclomaticComplexity" ] let jsonObj = JsonObject.Parse fsharplintJsonText From 27f4222080aa44ffdb3adaeb70d3b28860397c27 Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Wed, 13 Aug 2025 18:47:02 +0200 Subject: [PATCH 47/48] build: run FSharpLint with 1 extra rule --- build.fsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.fsx b/build.fsx index 0bfdba7ff..ebdc6b542 100644 --- a/build.fsx +++ b/build.fsx @@ -282,9 +282,6 @@ Target.create "SelfCheck" (fun _ -> "trailingNewLineInFile" "trailingWhitespaceOnLine" - // TODO: investigate if useful - "tupleParentheses" - // TODO: we should enable at some point "typePrefixing" "unnestedFunctionNames" From 54ab0a3ba682aba827b5b4cc2d64420d9bcdd865 Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Wed, 13 Aug 2025 19:17:31 +0200 Subject: [PATCH 48/48] Core,Tests: apply TupleParentheses rule suggestions --- .../AsyncExceptionWithoutReturn.fs | 4 +-- .../Conventions/AvoidSinglePipeOperator.fs | 2 +- .../Rules/Conventions/CyclomaticComplexity.fs | 6 ++--- ...TailCallDiagnosticsInRecursiveFunctions.fs | 2 +- .../Rules/Conventions/RedundantNewKeyword.fs | 2 +- .../Conventions/SuggestUseAutoProperty.fs | 2 +- .../Rules/Conventions/UnneededRecKeyword.fs | 2 +- .../Rules/Conventions/CyclomaticComplexity.fs | 26 +++++++++---------- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs b/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs index 0684c4d27..978ed38ef 100644 --- a/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs +++ b/src/FSharpLint.Core/Rules/Conventions/AsyncExceptionWithoutReturn.fs @@ -22,12 +22,12 @@ let rec checkExpression (expression: SynExpr) (range: range) (continuation: unit | SynExpr.For (_, _, _, _, _, _, _, innerExpression, range) -> checkExpression innerExpression range returnEmptyArray | SynExpr.ForEach (_, _, _, _, _, _, innerExpression, range) -> checkExpression innerExpression range returnEmptyArray | SynExpr.Match (_, _, clauses, range, _) -> - let subExpressions = clauses |> List.map (fun (SynMatchClause (_, _, clause, range, _, _)) -> clause, range) + let subExpressions = clauses |> List.map (fun (SynMatchClause (_, _, clause, range, _, _)) -> (clause, range)) checkMultipleExpressions subExpressions returnEmptyArray | SynExpr.Do (innerExpression, range) -> checkExpression innerExpression range returnEmptyArray | SynExpr.TryWith (tryExpression, withCases, tryRange, _, _, _) -> let subExpressions = - withCases |> List.map (fun (SynMatchClause (_, _, withCase, withRange, _, _)) -> withCase, withRange) + withCases |> List.map (fun (SynMatchClause (_, _, withCase, withRange, _, _)) -> (withCase, withRange)) checkMultipleExpressions subExpressions (fun () -> checkExpression tryExpression tryRange returnEmptyArray) | SynExpr.TryFinally (tryExpression, finallyExpr, range, _, _, _) -> checkExpression tryExpression range (fun () -> checkExpression finallyExpr range returnEmptyArray) diff --git a/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs b/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs index 545f9fbae..956722d78 100644 --- a/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs +++ b/src/FSharpLint.Core/Rules/Conventions/AvoidSinglePipeOperator.fs @@ -46,7 +46,7 @@ let runner (args: AstNodeRuleParams) = let suggestedFix = lazy( let maybeFuncText = ExpressionUtilities.tryFindTextOfRange outerArgExpr.Range args.FileContent let maybeArgText = ExpressionUtilities.tryFindTextOfRange argExpr.Range args.FileContent - match maybeFuncText, maybeArgText with + match (maybeFuncText, maybeArgText) with | Some(funcText), Some(argText) -> let replacementText = sprintf "%s %s" funcText argText Some { FromText=args.FileContent; FromRange=range; ToText=replacementText } diff --git a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs index 6114ff2f6..917797e79 100644 --- a/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs +++ b/src/FSharpLint.Core/Rules/Conventions/CyclomaticComplexity.fs @@ -32,8 +32,8 @@ type private BindingScopeComparer() = member this.Compare(left, right) = let leftStart = left.Binding.RangeOfBindingWithoutRhs.Start let rightStart = right.Binding.RangeOfBindingWithoutRhs.Start - let leftTuple : ValueTuple = leftStart.Line, leftStart.Column, left.Complexity - let rightTuple : ValueTuple = rightStart.Line, rightStart.Column, right.Complexity + let leftTuple : ValueTuple = (leftStart.Line, leftStart.Column, left.Complexity) + let rightTuple : ValueTuple = (rightStart.Line, rightStart.Column, right.Complexity) leftTuple.CompareTo rightTuple /// A two-tiered stack-like structure for containing BindingScopes. @@ -190,7 +190,7 @@ let runner (config:Config) (args:AstNodeRuleParams) : WarningDetails[] = let fromStack = bindingStack |> Seq.sortBy (fun scope -> // sort by order of start position, for reporting let pos = scope.Binding.RangeOfBindingWithRhs.Start - pos.Column, pos.Line) + (pos.Column, pos.Line)) |> Seq.map (fun scope -> // transform into WarningDetails let errMsg = String.Format(Resources.GetString("RulesCyclomaticComplexityError"), scope.Complexity, config.MaxComplexity) { Range = scope.Binding.RangeOfBindingWithRhs; Message = errMsg; SuggestedFix = None; TypeChecks = List.Empty }) diff --git a/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs b/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs index f51fd88dd..e6c25343a 100644 --- a/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs +++ b/src/FSharpLint.Core/Rules/Conventions/EnsureTailCallDiagnosticsInRecursiveFunctions.fs @@ -19,7 +19,7 @@ let private emitWarning (func: UnneededRecKeyword.RecursiveFunctionInfo) = TypeChecks = list.Empty } let runner (args: AstNodeRuleParams) = - match args.AstNode, args.CheckInfo with + match (args.AstNode, args.CheckInfo) with | UnneededRecKeyword.RecursiveFunctions(funcs), Some checkInfo -> let processFunction functionInfo = if UnneededRecKeyword.functionIsCalledInOneOf checkInfo functionInfo funcs then diff --git a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs index b05d28c9f..4ab45e080 100644 --- a/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/RedundantNewKeyword.fs @@ -44,7 +44,7 @@ let private generateFix (text:string) range = lazy( let runner args = - match args.AstNode, args.CheckInfo with + match (args.AstNode, args.CheckInfo) with | AstNode.Expression(SynExpr.New(_, SynType.LongIdent(identifier), _, range)), Some checkInfo | AstNode.Expression(SynExpr.New(_, SynType.App(SynType.LongIdent(identifier), _, _, _, _, _, _), _, range)), Some checkInfo -> Array.singleton diff --git a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs index 2abeea3ec..f98b6ce5c 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SuggestUseAutoProperty.fs @@ -101,7 +101,7 @@ let private runner (args: AstNodeRuleParams) = memberRange ) ) when memberFlags.IsInstance -> - match expr, argPats with + match (expr, argPats) with | _, SynArgPats.Pats pats when pats.Length > 0 -> // non-property member Array.empty | expression, _ when isImmutableValueExpression args expression id -> diff --git a/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs b/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs index 6647e458c..38a65f7f6 100644 --- a/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs +++ b/src/FSharpLint.Core/Rules/Conventions/UnneededRecKeyword.fs @@ -56,7 +56,7 @@ let private emitWarning (func: RecursiveFunctionInfo) = TypeChecks = list.Empty } let runner (args: AstNodeRuleParams) = - match args.AstNode, args.CheckInfo with + match (args.AstNode, args.CheckInfo) with | RecursiveFunctions(funcs), Some checkInfo -> funcs |> List.choose diff --git a/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs b/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs index 877d3c38d..e73c208fe 100644 --- a/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs +++ b/tests/FSharpLint.Core.Tests/Rules/Conventions/CyclomaticComplexity.fs @@ -135,18 +135,18 @@ type TestConventionsCyclomaticComplexity() = static member private FailureCasesSource = seq { let num = MaxComplexity + 1 - let errorLocation = 2, 4 - yield ifElseExpressions num, errorLocation - yield forExpressions num, errorLocation - yield foreachExpressions num, errorLocation - yield whileExpressions num, errorLocation - yield matchExpression num, errorLocation - yield matchExpressionWithCombinedPatterns num, errorLocation - yield matchFunction num, errorLocation - yield matchBang num, errorLocation - yield ifThenExpressionWithMultipleAndConditionals num, errorLocation - yield ifThenExpressionWithMultipleOrConditionals num, errorLocation - yield whileWithBooleanOperatorsInConditionExpressions num, errorLocation + let errorLocation = (2, 4) + yield (ifElseExpressions num, errorLocation) + yield (forExpressions num, errorLocation) + yield (foreachExpressions num, errorLocation) + yield (whileExpressions num, errorLocation) + yield (matchExpression num, errorLocation) + yield (matchExpressionWithCombinedPatterns num, errorLocation) + yield (matchFunction num, errorLocation) + yield (matchBang num, errorLocation) + yield (ifThenExpressionWithMultipleAndConditionals num, errorLocation) + yield (ifThenExpressionWithMultipleOrConditionals num, errorLocation) + yield (whileWithBooleanOperatorsInConditionExpressions num, errorLocation) } |> Seq.map (fun (x, y) -> [| box x; box y |]) /// Verifies that no cyclomatic complexity over-maximum flags are raised on source that has cyclomatic complexity <= maxComplexity. @@ -254,4 +254,4 @@ let f() = let f (str: string) = match str with""" + NewLine + matchClauses this.Parse code - Assert.AreEqual(1, this.ErrorRanges.Length) \ No newline at end of file + Assert.AreEqual(1, this.ErrorRanges.Length)