Skip to content

Commit

Permalink
FavourNestedFunctions: implement rule
Browse files Browse the repository at this point in the history
Implemented FavourNestedFunctions rule. Added rule text message
to Text.resx.

Fixes fsprojects#638
  • Loading branch information
webwarrior-ws committed Dec 21, 2023
1 parent f6e0fba commit 62375ea
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
57 changes: 56 additions & 1 deletion src/FSharpLint.Core/Rules/Conventions/FavourNestedFunctions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,63 @@ open FSharpLint.Framework.Rules
open FSharpLint.Framework
open FSharpLint.Framework.Suggestion

let private (|FunctionDeclaration|_|) (declaration: SynModuleDecl) =
match declaration with
| SynModuleDecl.Let(_, [ SynBinding(_, _, _, _, _, _, _, headPat, _, expr, _, _) ], _) ->
match headPat with
| SynPat.LongIdent(LongIdentWithDots([ident], _), _, _, _, accessibility, _) ->
Some(ident, expr, accessibility)
| _ -> None
| _ -> None

let runner (args: AstNodeRuleParams) =
failwith "Not yet implemeted"
match args.AstNode with
| AstNode.ModuleOrNamespace(SynModuleOrNamespace(_, _, _kind, declarations, _, _, _, _)) ->
let privateFunctionIdentifiers =
declarations
|> List.toArray
|> Array.choose
(fun declaration ->
match declaration with
| FunctionDeclaration(ident, _body, Some(SynAccess.Private)) ->
Some ident
| _ -> None)

match args.CheckInfo with
| Some checkInfo when privateFunctionIdentifiers.Length > 0 ->
let otherFunctionBodies =
declarations
|> List.choose
(fun declaration ->
match declaration with
| FunctionDeclaration(ident, body, _)
when not(Array.exists (fun (each: Ident) -> each.idText = ident.idText) privateFunctionIdentifiers) ->
Some body
| _ -> None)

privateFunctionIdentifiers
|> Array.choose
(fun currFunctionIdentifier ->
match ExpressionUtilities.getSymbolFromIdent args.CheckInfo (SynExpr.Ident currFunctionIdentifier) with
| Some symbolUse ->
let numberOfOtherFunctionsCurrFunctionIsUsedIn =
otherFunctionBodies
|> List.filter (fun funcBody ->
checkInfo.GetUsesOfSymbolInFile symbolUse.Symbol
|> Array.exists (fun usage -> ExpressionUtilities.rangeContainsOtherRange funcBody.Range usage.Range))
|> List.length
if numberOfOtherFunctionsCurrFunctionIsUsedIn = 1 then
Some {
Range = currFunctionIdentifier.idRange
WarningDetails.Message = Resources.GetString "RulesFavourNestedFunctions"
SuggestedFix = None
TypeChecks = List.Empty
}
else
None
| None -> None)
| _ -> Array.empty
| _ -> Array.empty

let rule =
{ Name = "FavourNestedFunctions"
Expand Down
3 changes: 3 additions & 0 deletions src/FSharpLint.Core/Text.resx
Original file line number Diff line number Diff line change
Expand Up @@ -354,4 +354,7 @@
<data name="RulesSuggestUseAutoProperty" xml:space="preserve">
<value>Consider using auto-properties via the 'val' keyword.</value>
</data>
<data name="RulesFavourNestedFunctions" xml:space="preserve">
<value>Prefer using local functions over private module-level functions</value>
</data>
</root>

0 comments on commit 62375ea

Please sign in to comment.