From 1347ebd53ba8e2b1c42e8408c3227a673f2795c9 Mon Sep 17 00:00:00 2001 From: Tuomas Hietanen Date: Wed, 29 Oct 2025 11:20:31 +0000 Subject: [PATCH] FL0065: Fix for false-positive detection of boolean arguments --- .../Rules/Hints/HintMatcher.fs | 38 +++++++++++-------- .../Rules/Hints/HintMatcher.fs | 35 +++++++++++++++++ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs index 24030523b..f1ab830c6 100644 --- a/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs +++ b/src/FSharpLint.Core/Rules/Hints/HintMatcher.fs @@ -229,30 +229,35 @@ module private MatchExpression = match (leftExpr, opExpr) with | ExpressionUtilities.Identifier([ident], _), ExpressionUtilities.Identifier([opIdent], _) when opIdent.idText = "op_Equality" -> match arguments.FSharpCheckFileResults with - | Some(checkFile) -> - let checkSymbol () = - let symbolUse = - checkFile.GetSymbolUseAtLocation( - ident.idRange.StartLine, ident.idRange.EndColumn, String.Empty, [ident.idText]) - - match symbolUse with - | Some(symbolUse) -> + | Some checkFile -> + let symbolUse = + checkFile.GetSymbolUseAtLocation( + ident.idRange.StartLine, ident.idRange.EndColumn, String.Empty, [ident.idText]) + + match symbolUse with + | Some symbolUse -> + let checkSymbol () = match symbolUse.Symbol with | :? FSharpParameter | :? FSharpField -> false | :? FSharpMemberOrFunctionOrValue as element -> not element.IsProperty | _ -> true - | None -> true - checkSymbol - |> List.singleton - |> Match + checkSymbol + |> List.singleton + |> Match + | None -> + // Symbol resolution failed, fall back to breadcrumb checking + match filterParens arguments.Breadcrumbs with + | PossiblyInMethod + | PossiblyInConstructor -> NoMatch + | _ -> Match List.Empty | None -> /// Check if in `new` expr or function application (either could be a constructor). match filterParens arguments.Breadcrumbs with | PossiblyInMethod | PossiblyInConstructor -> NoMatch - | _ -> Match(List.Empty) - | _ -> Match(List.Empty) + | _ -> Match List.Empty + | _ -> Match List.Empty [] let rec matchHintExpr (continuation: unit -> HintMatch) arguments = @@ -386,7 +391,10 @@ module private MatchExpression = matchHintExpr (fun () -> matchHintExpr - (fun () -> arguments.SubHint(AstNode.Expression(rightExpr), right) |> matchHintExpr returnEmptyMatch) + (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)) | (AstNode.Expression(SynExpr.App(_, _, infixExpr, rightExpr, _)), diff --git a/tests/FSharpLint.Core.Tests/Rules/Hints/HintMatcher.fs b/tests/FSharpLint.Core.Tests/Rules/Hints/HintMatcher.fs index fc4627025..311bd5c4b 100644 --- a/tests/FSharpLint.Core.Tests/Rules/Hints/HintMatcher.fs +++ b/tests/FSharpLint.Core.Tests/Rules/Hints/HintMatcher.fs @@ -754,6 +754,41 @@ do this.AssertNoWarnings() + /// Regression test for: https://github.com/fsprojects/FSharpLint/issues/492 + [] + member this.``Named parameter in atomic static method call should not be treated as infix operation``() = + this.SetConfig(["x = true ===> x"]) + + this.Parse """ +module Goat + +type Foo() = + static member Create(keepAssemblyContents: bool) = Foo() + +do + let foo = Foo.Create(keepAssemblyContents = true) + () +""" + + this.AssertNoWarnings() + + /// Regression test for: https://github.com/fsprojects/FSharpLint/issues/492 + [] + member this.``Named parameter in FSharpChecker.Create should not be treated as infix operation``() = + this.SetConfig(["x = true ===> x"]) + + this.Parse """ +module Goat + +open FSharp.Compiler.CodeAnalysis + +do + let checker = FSharpChecker.Create(keepAssemblyContents = true) + () +""" + + this.AssertNoWarnings() + /// Regression test for: https://github.com/fsprojects/FSharpLint/pull/194#issuecomment-268560761 [] member this.``Lambdas in hint suggestions must be surrounded with parentheses.``() =