Skip to content

Commit e8b63ae

Browse files
authored
Merge PR #798 from webwarrior-ws/fix-792
Fix FavourStaticEmptyFields false negatives.
2 parents f84ead9 + 8d901af commit e8b63ae

File tree

6 files changed

+80
-24
lines changed

6 files changed

+80
-24
lines changed

src/FSharpLint.Core/Rules/Conventions/FavourStaticEmptyFields.fs

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,56 @@ let private generateError (fileContents: string) (range:FSharp.Compiler.Text.Ran
3838
SuggestedFix = Some suggestedFix
3939
TypeChecks = List.Empty }
4040

41-
let private runner (args: AstNodeRuleParams) =
42-
match args.AstNode with
43-
| AstNode.Expression(SynExpr.Const (SynConst.String ("", _, range), _)) ->
44-
generateError args.FileContent range EmptyStringLiteral
45-
| AstNode.Expression(SynExpr.ArrayOrList (isArray, [], range)) ->
41+
[<TailCall>]
42+
let rec private processExpressions (errorsSoFar: array<WarningDetails>) (args: AstNodeRuleParams) (expressions: list<SynExpr>) =
43+
match expressions with
44+
| SynExpr.Const(SynConst.String ("", _, range), _) :: tail ->
45+
let errors =
46+
Array.append
47+
errorsSoFar
48+
(generateError args.FileContent range EmptyStringLiteral)
49+
processExpressions errors args tail
50+
| SynExpr.DotIndexedGet(_, indexArgs, _ , _) :: tail ->
51+
processExpressions errorsSoFar args (indexArgs :: tail)
52+
| SynExpr.DotIndexedSet(_, indexArgs, _ , _, _, _) :: tail ->
53+
processExpressions errorsSoFar args (indexArgs :: tail)
54+
| SynExpr.Paren(expr, _, _, _) :: tail ->
55+
processExpressions errorsSoFar args (expr :: tail)
56+
| SynExpr.Tuple(_, expressions, _, _) :: tail ->
57+
processExpressions errorsSoFar args (List.append expressions tail)
58+
| SynExpr.ArrayOrList(isArray, [], range) :: tail ->
4659
let emptyLiteralType =
4760
if isArray then EmptyArrayLiteral else EmptyListLiteral
48-
generateError args.FileContent range emptyLiteralType
49-
| AstNode.Expression(SynExpr.Record(_, _, synExprRecordField, _)) ->
61+
let errors =
62+
Array.append
63+
errorsSoFar
64+
(generateError args.FileContent range emptyLiteralType)
65+
processExpressions errors args tail
66+
| SynExpr.ArrayOrListComputed(_, expr, _) :: tail ->
67+
processExpressions errorsSoFar args (expr :: tail)
68+
| SynExpr.App(_, _, funcExpr, argExpr, _) :: tail ->
69+
processExpressions errorsSoFar args (List.append [ funcExpr; argExpr ] tail)
70+
| SynExpr.AnonRecd(_, _, recordFields, _, _) :: tail ->
71+
let fieldExpressions =
72+
recordFields
73+
|> List.map (fun (_, _, expr) -> expr)
74+
processExpressions errorsSoFar args (List.append fieldExpressions tail)
75+
| SynExpr.Record(_, _, synExprRecordFields, _) :: tail ->
5076
let mapping =
5177
function
52-
| SynExprRecordField(_, _, expr, _) ->
53-
match expr with
54-
| Some(SynExpr.ArrayOrList(isArray, [], range)) ->
55-
let emptyLiteralType = if isArray then EmptyArrayLiteral else EmptyListLiteral
56-
generateError args.FileContent range emptyLiteralType
57-
| Some(SynExpr.Const (SynConst.String ("", _, range), _)) ->
58-
generateError args.FileContent range EmptyStringLiteral
59-
| Some(SynExpr.App(_, _, _, SynExpr.Const (SynConst.String ("", _, range), _), _)) ->
60-
generateError args.FileContent range EmptyStringLiteral
61-
| _ -> Array.empty
62-
synExprRecordField
63-
|> List.map mapping
64-
|> Array.concat
78+
| SynExprRecordField(_, _, expr, _) -> expr
79+
let fieldExpressions =
80+
synExprRecordFields
81+
|> List.choose mapping
82+
processExpressions errorsSoFar args (List.append fieldExpressions tail)
83+
| _ :: tail ->
84+
processExpressions errorsSoFar args tail
85+
| [] -> errorsSoFar
86+
87+
let private runner (args: AstNodeRuleParams) =
88+
match args.AstNode with
89+
| AstNode.Expression(expr) ->
90+
processExpressions Array.empty args (List.singleton expr)
6591
| _ -> Array.empty
6692

6793

src/FSharpLint.Core/Rules/Conventions/SourceLength/MaxLinesInFile.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ let private checkNumberOfLinesInFile numberOfLines line maxLines =
1515
Array.singleton
1616
{
1717
Range =
18-
Range.mkRange "" (Position.mkPos (maxLines + 1) 0) (Position.mkPos numberOfLines (String.length line))
18+
Range.mkRange String.Empty (Position.mkPos (maxLines + 1) 0) (Position.mkPos numberOfLines (String.length line))
1919
Message = String.Format(errorFormatString, (maxLines + 1))
2020
SuggestedFix = None
2121
TypeChecks = List.Empty

src/FSharpLint.Core/Rules/Formatting/TupleFormatting/TupleIndentation.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let checkTupleIndentation _ (tupleExprs:SynExpr list) _ _ =
1616
if expr.Range.StartColumn <> nextExpr.Range.StartColumn then
1717
Some
1818
{
19-
Range = Range.mkRange "" expr.Range.Start nextExpr.Range.End
19+
Range = Range.mkRange String.Empty expr.Range.Start nextExpr.Range.End
2020
Message = Resources.GetString("RulesFormattingTupleIndentationError")
2121
SuggestedFix = None
2222
TypeChecks = List.Empty

src/FSharpLint.Core/Rules/Formatting/Typography/TrailingNewLineInFile.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ let checkTrailingNewLineInFile (args:LineRuleParams) =
1111
let pos = Position.mkPos args.LineNumber 0
1212
Array.singleton
1313
{
14-
Range = Range.mkRange "" pos pos
14+
Range = Range.mkRange String.Empty pos pos
1515
Message = Resources.GetString("RulesTypographyTrailingLineError")
1616
SuggestedFix = None
1717
TypeChecks = List.Empty

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ let private confirmFuzzyMatch (args:AstNodeRuleParams) (hint:HintParserTypes.Hin
770770
|> suggestions.Add
771771
| AstNode.Expression(expr), HintExpr(hintExpr) ->
772772
let arguments =
773-
{ MatchExpression.LambdaArguments = Map.ofList []
773+
{ MatchExpression.LambdaArguments = Map.empty
774774
MatchExpression.MatchedVariables = Dictionary<_, _>()
775775
MatchExpression.Expression = args.AstNode
776776
MatchExpression.Hint = hintExpr

tests/FSharpLint.Core.Tests/Rules/Conventions/FavourStaticEmptyFields.fs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,36 @@ type Person =
118118
Assert.IsTrue this.ErrorsExist
119119
Assert.IsTrue (this.ErrorMsg.Contains "String.Empty")
120120

121+
[<Test>]
122+
member this.FavourStaticEmptyFieldsShouldProduceError13() =
123+
this.Parse """
124+
let foo =
125+
{
126+
Range = Range.mkRange "" pos pos
127+
}"""
128+
129+
Assert.IsTrue this.ErrorsExist
130+
Assert.IsTrue (this.ErrorMsg.Contains "String.Empty")
131+
132+
[<Test>]
133+
member this.FavourStaticEmptyFieldsShouldProduceError14() =
134+
this.Parse """
135+
let foo =
136+
{
137+
Bar = ("a", "")
138+
}"""
139+
140+
Assert.IsTrue this.ErrorsExist
141+
Assert.IsTrue (this.ErrorMsg.Contains "String.Empty")
142+
143+
[<Test>]
144+
member this.FavourStaticEmptyFieldsShouldProduceError15() =
145+
this.Parse """
146+
foo.[""] <- 0"""
147+
148+
Assert.IsTrue this.ErrorsExist
149+
Assert.IsTrue (this.ErrorMsg.Contains "String.Empty")
150+
121151
[<Test>]
122152
member this.FavourStaticEmptyFieldsShouldNotProduceError1() =
123153
this.Parse "let bar = String.Empty"

0 commit comments

Comments
 (0)