-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* FavourAsKeyword: add rule and config * FavourAsKeyword: add docs * FavourAsKeyword: add tests * FavourAsKeyword: add rule to fsharplint.json * FavourAsKeyword: refactor tests * FavourAsKeyword: refactor error message text
- Loading branch information
1 parent
77dbfd3
commit 873d145
Showing
10 changed files
with
155 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- | ||
title: FL0086 | ||
category: how-to | ||
hide_menu: true | ||
--- | ||
|
||
# FavourAsKeyword (FL0086) | ||
|
||
*Introduced in `0.24.3`* | ||
|
||
## Cause | ||
|
||
A named pattern is used just to be compared in the guard against a constant expression e.g. `match something with | bar when bar = "baz" -> ()` | ||
|
||
## Rationale | ||
|
||
The named pattern can be changed to an as pattern that uses a constant pattern, improving the pattern matching exhaustiveness check | ||
|
||
## How To Fix | ||
|
||
Remove the guard and replace the named pattern with the as pattern using a constant pattern, e.g. change `match something with | bar when bar = "baz" -> ()` to `match something with | "baz" as bar -> ()` | ||
|
||
## Rule Settings | ||
|
||
{ | ||
"favourAsKeyword": { | ||
"enabled": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
src/FSharpLint.Core/Rules/Conventions/Binding/FavourAsKeyword.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
module FSharpLint.Rules.FavourAsKeyword | ||
|
||
open System | ||
open FSharpLint.Framework | ||
open FSharpLint.Framework.Suggestion | ||
open FSharp.Compiler.Syntax | ||
open FSharp.Compiler.Text | ||
open FSharpLint.Framework.Ast | ||
open FSharpLint.Framework.Rules | ||
|
||
let private checkForNamedPatternEqualsConstant (args:AstNodeRuleParams) pattern whenExpr (range:Range) = | ||
let patternIdent = | ||
match pattern with | ||
| SynPat.Named(SynIdent.SynIdent(ident, _), _, _, _) -> Some(ident.idText) | ||
| _ -> None | ||
|
||
|
||
match whenExpr with | ||
| SynExpr.App(_, _, funcExpr, SynExpr.Const(_, constRange), _) -> | ||
match funcExpr with | ||
| 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 suggestedFix = | ||
ExpressionUtilities.tryFindTextOfRange fromRange args.FileContent | ||
|> Option.bind (fun text -> | ||
|
||
ExpressionUtilities.tryFindTextOfRange constRange args.FileContent | ||
|> Option.bind (fun constText -> | ||
|
||
lazy (Some { FromText = text; FromRange = fromRange; ToText = constText + " as " + ident.idText}) | ||
|> Some | ||
) | ||
|
||
) | ||
|
||
{ Range = fromRange | ||
Message = Resources.GetString("RulesFavourAsKeyword") | ||
SuggestedFix = suggestedFix | ||
TypeChecks = [] } |> Array.singleton | ||
|
||
| _ -> Array.empty | ||
| _ -> Array.empty | ||
|
||
let private runner (args:AstNodeRuleParams) = | ||
match args.AstNode with | ||
| AstNode.Match(SynMatchClause.SynMatchClause(pat, Some(whenExpr), _, range, _, _)) -> | ||
checkForNamedPatternEqualsConstant args pat whenExpr range | ||
|
||
| _ -> Array.empty | ||
|
||
let rule = | ||
{ Name = "FavourAsKeyword" | ||
Identifier = Identifiers.FavourAsKeyword | ||
RuleConfig = { AstNodeRuleConfig.Runner = runner; Cleanup = ignore } } | ||
|> AstNodeRule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
tests/FSharpLint.Core.Tests/Rules/Binding/FavourAsKeyword.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
module FSharpLint.Core.Tests.Rules.Binding.FavourAsKeyword | ||
|
||
open NUnit.Framework | ||
open FSharpLint.Rules | ||
|
||
[<TestFixture>] | ||
type TestBindingFavourAsKeyword() = | ||
inherit TestAstNodeRuleBase.TestAstNodeRuleBase(FavourAsKeyword.rule) | ||
|
||
[<Test>] | ||
member this.FavourAsKeywordShouldQuickFix() = | ||
let source = """ | ||
module Program | ||
match "" with | ||
| bar when bar = "baz" -> () | ||
""" | ||
|
||
this.Parse(source) | ||
|
||
let expected = """ | ||
module Program | ||
match "" with | ||
| "baz" as bar -> () | ||
""" | ||
|
||
Assert.AreEqual(expected, this.ApplyQuickFix source) | ||
|
||
|
||
[<Test>] | ||
member this.FavourAsKeywordShouldProduceError() = | ||
this.Parse """ | ||
module Program | ||
match "" with | ||
| bar when bar = "baz" -> () | ||
""" | ||
|
||
this.AssertErrorWithMessageExists("Prefer using the 'as' pattern to match a constant and bind it to a variable.") | ||
|
||
|
||
[<Test>] | ||
member this.FavourAsKeywordShouldNotProduceError() = | ||
this.Parse """ | ||
module Program | ||
match "" with | ||
| "baz" as bar -> () | ||
""" | ||
|
||
Assert.IsTrue(this.NoErrorsExist) | ||
|