diff --git a/src/FSharpLint.Core/FSharpLint.Core.fsproj b/src/FSharpLint.Core/FSharpLint.Core.fsproj
index c445f1374..9c2f7bf85 100644
--- a/src/FSharpLint.Core/FSharpLint.Core.fsproj
+++ b/src/FSharpLint.Core/FSharpLint.Core.fsproj
@@ -80,9 +80,9 @@
+
-
diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/AsynchronousFunctionNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/AsynchronousFunctionNames.fs
index b585015f8..c71d3fc51 100644
--- a/src/FSharpLint.Core/Rules/Conventions/Naming/AsynchronousFunctionNames.fs
+++ b/src/FSharpLint.Core/Rules/Conventions/Naming/AsynchronousFunctionNames.fs
@@ -5,6 +5,7 @@ open FSharpLint.Framework
open FSharpLint.Framework.Suggestion
open FSharpLint.Framework.Ast
open FSharpLint.Framework.Rules
+open Helper.Naming.Asynchronous
open FSharp.Compiler.Syntax
let runner (args: AstNodeRuleParams) =
@@ -18,7 +19,8 @@ let runner (args: AstNodeRuleParams) =
}
match args.AstNode with
- | AstNode.Binding (SynBinding (_, _, _, _, _, _, _, SynPat.LongIdent(funcIdent, _, _, _, (None | Some(SynAccess.Public _)), identRange), returnInfo, _, _, _, _)) ->
+ | AstNode.Binding (SynBinding (_, _, _, _, attributes, _, _, SynPat.LongIdent(funcIdent, _, _, _, (None | Some(SynAccess.Public _)), identRange), returnInfo, _, _, _, _))
+ when not <| Helper.Naming.isAttribute "Obsolete" attributes ->
let parents = args.GetParents args.NodeIndex
let hasEnclosingFunctionOrMethod =
parents
@@ -32,21 +34,21 @@ let runner (args: AstNodeRuleParams) =
Array.empty
else
match returnInfo with
- | Some SynchronousFunctionNames.ReturnsAsync ->
+ | Some ReturnsAsync ->
match funcIdent with
- | SynchronousFunctionNames.HasAsyncPrefix _ ->
+ | HasAsyncPrefix _ ->
Array.empty
- | SynchronousFunctionNames.HasAsyncSuffix name
- | SynchronousFunctionNames.HasNoAsyncPrefixOrSuffix name ->
- let nameWithAsync = SynchronousFunctionNames.asyncSuffixOrPrefix + name
+ | HasAsyncSuffix name
+ | HasNoAsyncPrefixOrSuffix name ->
+ let nameWithAsync = asyncSuffixOrPrefix + name
emitWarning identRange nameWithAsync "Async"
- | Some SynchronousFunctionNames.ReturnsTask ->
+ | Some ReturnsTask ->
match funcIdent with
- | SynchronousFunctionNames.HasAsyncSuffix _ ->
+ | HasAsyncSuffix _ ->
Array.empty
- | SynchronousFunctionNames.HasAsyncPrefix name
- | SynchronousFunctionNames.HasNoAsyncPrefixOrSuffix name ->
- let nameWithAsync = name + SynchronousFunctionNames.asyncSuffixOrPrefix
+ | HasAsyncPrefix name
+ | HasNoAsyncPrefixOrSuffix name ->
+ let nameWithAsync = name + asyncSuffixOrPrefix
emitWarning identRange nameWithAsync "Task"
| None ->
// TODO: get type using typed tree in args.CheckInfo
diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs
index 0d10e6f86..1f8f99e78 100644
--- a/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs
+++ b/src/FSharpLint.Core/Rules/Conventions/Naming/NamingHelper.fs
@@ -464,3 +464,27 @@ let getFunctionIdents (pattern:SynPat) =
| Some ident -> Array.singleton (ident, ident.idText, None)
| None -> Array.empty
| _ -> Array.empty
+
+module Asynchronous =
+ let asyncSuffixOrPrefix = "Async"
+
+ let (|HasAsyncPrefix|HasAsyncSuffix|HasNoAsyncPrefixOrSuffix|) (pattern: SynLongIdent) =
+ match List.tryLast pattern.LongIdent with
+ | Some name ->
+ if name.idText.StartsWith(asyncSuffixOrPrefix, StringComparison.InvariantCultureIgnoreCase) then
+ HasAsyncPrefix name.idText
+ elif name.idText.EndsWith asyncSuffixOrPrefix then
+ HasAsyncSuffix name.idText
+ else
+ HasNoAsyncPrefixOrSuffix name.idText
+ | _ -> HasNoAsyncPrefixOrSuffix String.Empty
+
+ let (|ReturnsTask|ReturnsAsync|ReturnsNonAsync|) (returnInfo: SynBindingReturnInfo) =
+ match returnInfo with
+ | SynBindingReturnInfo(SynType.LongIdent(SynLongIdent(typeIdent, _, _)), _, _, _)
+ | SynBindingReturnInfo(SynType.App(SynType.LongIdent(SynLongIdent(typeIdent, _, _)), _, _, _, _, _, _), _, _, _) ->
+ match List.tryLast typeIdent with
+ | Some ident when ident.idText = "Async" -> ReturnsAsync
+ | Some ident when ident.idText = "Task" -> ReturnsTask
+ | _ -> ReturnsNonAsync
+ | _ -> ReturnsNonAsync
diff --git a/src/FSharpLint.Core/Rules/Conventions/Naming/SynchronousFunctionNames.fs b/src/FSharpLint.Core/Rules/Conventions/Naming/SynchronousFunctionNames.fs
index 073fb1497..e0e28c556 100644
--- a/src/FSharpLint.Core/Rules/Conventions/Naming/SynchronousFunctionNames.fs
+++ b/src/FSharpLint.Core/Rules/Conventions/Naming/SynchronousFunctionNames.fs
@@ -5,32 +5,12 @@ open FSharpLint.Framework
open FSharpLint.Framework.Suggestion
open FSharpLint.Framework.Ast
open FSharpLint.Framework.Rules
+open Helper.Naming.Asynchronous
open FSharp.Compiler.Syntax
open FSharp.Compiler.Symbols
let asyncSuffixOrPrefix = "Async"
-let (|HasAsyncPrefix|HasAsyncSuffix|HasNoAsyncPrefixOrSuffix|) (pattern: SynLongIdent) =
- match List.tryLast pattern.LongIdent with
- | Some name ->
- if name.idText.StartsWith(asyncSuffixOrPrefix, StringComparison.InvariantCultureIgnoreCase) then
- HasAsyncPrefix name.idText
- elif name.idText.EndsWith asyncSuffixOrPrefix then
- HasAsyncSuffix name.idText
- else
- HasNoAsyncPrefixOrSuffix name.idText
- | _ -> HasNoAsyncPrefixOrSuffix String.Empty
-
-let (|ReturnsTask|ReturnsAsync|ReturnsNonAsync|) (returnInfo: SynBindingReturnInfo) =
- match returnInfo with
- | SynBindingReturnInfo(SynType.LongIdent(SynLongIdent(typeIdent, _, _)), _, _, _)
- | SynBindingReturnInfo(SynType.App(SynType.LongIdent(SynLongIdent(typeIdent, _, _)), _, _, _, _, _, _), _, _, _) ->
- match List.tryLast typeIdent with
- | Some ident when ident.idText = "Async" -> ReturnsAsync
- | Some ident when ident.idText = "Task" -> ReturnsTask
- | _ -> ReturnsNonAsync
- | _ -> ReturnsNonAsync
-
let runner (args: AstNodeRuleParams) =
let emitWarning range (newFunctionName: string) =
Array.singleton
@@ -42,7 +22,8 @@ let runner (args: AstNodeRuleParams) =
}
match args.AstNode with
- | AstNode.Binding (SynBinding (_, _, _, _, _, _, _, SynPat.LongIdent(funcIdent, _, _, _, _, identRange), returnInfo, _, _, _, _)) ->
+ | AstNode.Binding (SynBinding (_, _, _, _, attributes, _, _, SynPat.LongIdent(funcIdent, _, _, _, _, identRange), returnInfo, _, _, _, _))
+ when not <| Helper.Naming.isAttribute "Obsolete" attributes ->
match returnInfo with
| Some ReturnsNonAsync ->
match funcIdent with
diff --git a/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/AsynchronousFunctionNames.fs b/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/AsynchronousFunctionNames.fs
index a8ccafa52..4ccd41dc4 100644
--- a/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/AsynchronousFunctionNames.fs
+++ b/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/AsynchronousFunctionNames.fs
@@ -135,3 +135,41 @@ type Foo() =
"""
Assert.IsTrue this.NoErrorsExist
+
+ []
+ member this.``Functions returning Async or Task with [] attribute should not give violations``() =
+ this.Parse """
+module Foo =
+ []
+ let Foo(): Async =
+ async { return 1 }
+
+ []
+ let Bar(): Task =
+ null
+
+ []
+ let Baz(): Task =
+ null
+"""
+
+ Assert.IsTrue this.NoErrorsExist
+
+ []
+ member this.``Methods returning Async or Task with [] attribute should not give violations``() =
+ this.Parse """
+type Foo() =
+ []
+ member this.Foo(): Async =
+ async { return 1 }
+
+ []
+ member this.Bar(): Task =
+ null
+
+ []
+ member this.Baz(): Task =
+ null
+"""
+
+ Assert.IsTrue this.NoErrorsExist
diff --git a/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/SynchronousFunctionNames.fs b/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/SynchronousFunctionNames.fs
index 78438bbba..191abec13 100644
--- a/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/SynchronousFunctionNames.fs
+++ b/tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/SynchronousFunctionNames.fs
@@ -171,3 +171,41 @@ type Foo() =
"""
Assert.IsTrue this.NoErrorsExist
+
+ []
+ member this.``Non-asynchronous functions marked with [] attribute should not give violations``() =
+ this.Parse """
+module Foo =
+ []
+ let AsyncBar(): int =
+ 1
+
+ []
+ let BarAsync(): int =
+ 1
+
+ []
+ let private AsyncBar(): int =
+ 1
+"""
+
+ Assert.IsTrue this.NoErrorsExist
+
+ []
+ member this.``Non-asynchronous methods marked with [] attribute should not give violations``() =
+ this.Parse """
+type Foo() =
+ []
+ member this.AsyncBar(): int =
+ 1
+
+ []
+ member this.BarAsync(): int =
+ 1
+
+ []
+ member private this.AsyncBar(): int =
+ 1
+"""
+
+ Assert.IsTrue this.NoErrorsExist