Skip to content
7 changes: 5 additions & 2 deletions src/FSharpLint.Core/Application/Configuration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,11 @@ let constructRuleWithConfig rule ruleConfig =

let constructTypePrefixingRuleWithConfig rule (ruleConfig: RuleConfig<TypePrefixing.Config>) =
if ruleConfig.Enabled then
let config = ruleConfig.Config |> Option.defaultValue { Mode = TypePrefixing.Mode.Hybrid }
Some(rule config)
match ruleConfig.Config with
| Some { Mode = TypePrefixing.Mode.Hybrid } | None ->
Some(rule { TypePrefixing.Config.Mode = TypePrefixing.Mode.HybridWeak })
| Some config ->
Some(rule config)
else
None

Expand Down
13 changes: 10 additions & 3 deletions src/FSharpLint.Core/Rules/Formatting/TypePrefixing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ open FSharpLint.Framework.Rules
open FSharpLint.Framework.ExpressionUtilities

type Mode =
| Hybrid = 0
| HybridWeak = 0
| Always = 1
| Never = 2
| HybridStrict = 3

/// obsolete: use HybridStrict or HybridWeak instead (default: HybridWeak)
| Hybrid = 128

[<RequireQualifiedAccess>]
type Config = { Mode: Mode }
Expand All @@ -38,7 +42,7 @@ let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName t
| "Ref" as typeName ->

// Prefer postfix.
if not isPostfix && config.Mode <> Mode.Always
if not isPostfix && (config.Mode = Mode.HybridStrict || config.Mode = Mode.Never)
then
let suggestedFix = lazy(
(ExpressionUtilities.tryFindTextOfRange range args.FileContent, typeArgs)
Expand All @@ -53,7 +57,7 @@ let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName t
else
None

| "array" when config.Mode <> Mode.Always ->
| "array" when config.Mode = Mode.HybridStrict || config.Mode = Mode.Never ->
// Prefer special postfix (e.g. int []).
let suggestedFix = lazy(
(ExpressionUtilities.tryFindTextOfRange range args.FileContent, typeArgs)
Expand All @@ -63,6 +67,9 @@ let checkTypePrefixing (config:Config) (args:AstNodeRuleParams) range typeName t
SuggestedFix = Some suggestedFix
TypeChecks = [] } |> Some

| "array" when config.Mode = Mode.HybridWeak ->
None

| typeName ->
match (isPostfix, config.Mode) with
| true, Mode.Never ->
Expand Down
2 changes: 1 addition & 1 deletion src/FSharpLint.Core/fsharplint.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"typePrefixing": {
"enabled": false,
"config": {
"mode": "Hybrid"
"mode": "HybridWeak"
}
},
"unionDefinitionIndentation": { "enabled": false },
Expand Down
105 changes: 105 additions & 0 deletions tests/FSharpLint.Console.Tests/TestApp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,108 @@ type TestConsoleApplication() =

Assert.AreEqual(-1, returnCode)
Assert.AreEqual(set ["Use prefix syntax for generic type."], errors)

[<Test>]
member __.``TypePrefixing rule Hybrid mode should still work (after it gets renamed to HybridWeak)``() =
let fileContent = """
{
"typePrefixing": {
"enabled": true,
"config": {
"mode": "Hybrid"
}
}
}
"""
use config = new TemporaryFile(fileContent, "json")

let input = """
module Program

type X = int Generic
"""

let (returnCode, errors) = main [| "lint"; "--lint-config"; config.FileName; input |]

Assert.AreEqual(-1, returnCode)
Assert.AreEqual(set ["Use prefix syntax for generic type."], errors)

[<Test>]
member __.``TypePrefixing rule HybridStrict mode should complain about List<Foo>``() =
let fileContent = """
{
"typePrefixing": {
"enabled": true,
"config": {
"mode": "HybridStrict"
}
}
}
"""
use config = new TemporaryFile(fileContent, "json")

let input = """
module Program

type X = List<int>
"""

let (returnCode, errors) = main [| "lint"; "--lint-config"; config.FileName; input |]

Assert.AreEqual(-1, returnCode, "Return code of HybridStrict against List<Foo> should not be zero")
Assert.AreNotEqual(0, errors.Count, "Number of errors for HybridStrict mode against List<Foo> should not be zero")
Assert.AreEqual("Use postfix syntax for F# type List.", errors.MaximumElement)

[<Test>]
member __.``TypePrefixing rule HybridStrict mode should complain about array<Foo>``() =
let fileContent = """
{
"typePrefixing": {
"enabled": true,
"config": {
"mode": "HybridStrict"
}
}
}
"""
use config = new TemporaryFile(fileContent, "json")

let input = """
module Program

type X = array<int>
"""

let (returnCode, errors) = main [| "lint"; "--lint-config"; config.FileName; input |]

Assert.AreEqual(-1, returnCode, "Return code of HybridStrict against array<Foo> should not be zero")
Assert.AreNotEqual(0, errors.Count, "Number of errors for HybridStrict mode against array<Foo> should not be zero")
Assert.AreEqual("Use special postfix syntax for F# type array.", errors.MaximumElement)

[<Test>]
member __.``TypePrefixing rule HybridWeak mode should not complain about List<Foo>``() =
let fileContent = """
{
"typePrefixing": {
"enabled": true,
"config": {
"mode": "HybridWeak"
}
}
}
"""
use config = new TemporaryFile(fileContent, "json")

let input = """
module Program

type X = List<int>
"""

let (returnCode, errors) = main [| "lint"; "--lint-config"; config.FileName; input |]

Assert.AreEqual(0, returnCode)
if errors.Count = 0 then
Assert.AreEqual(0, errors.Count, "Return code of HybridWeak against List<Foo> should not be zero (=success; no suggestions)")
else
Assert.AreEqual(0, errors.Count, "No errors should happen, but we got at least one: " + errors.MaximumElement)
118 changes: 116 additions & 2 deletions tests/FSharpLint.Core.Tests/Rules/Formatting/TypePrefixing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ open FSharpLint.Rules
open FSharpLint.Rules.TypePrefixing

[<TestFixture>]
type TestFormattingHybridTypePrefixing() =
inherit TestAstNodeRuleBase.TestAstNodeRuleBase(TypePrefixing.rule { Config.Mode = Mode.Hybrid })
type TestFormattingHybridStrictTypePrefixing() =
inherit TestAstNodeRuleBase.TestAstNodeRuleBase(TypePrefixing.rule { Config.Mode = Mode.HybridStrict })

[<Test>]
member this.``Error for F# List type prefix syntax``() =
Expand Down Expand Up @@ -238,6 +238,120 @@ type T = Generic<int>
this.Parse source
Assert.AreEqual(expected, this.ApplyQuickFix source)

[<TestFixture>]
type TestFormattingHybridWeakTypePrefixing() =
inherit TestAstNodeRuleBase.TestAstNodeRuleBase(TypePrefixing.rule { Config.Mode = Mode.HybridWeak })

[<Test>]
member this.``Ignore F# List type prefix syntax``() =
this.Parse """
module Program

type T = list<int>
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore for F# List type postfix syntax``() =
this.Parse """
module Program

type T = int list
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore F# Option type prefix syntax``() =
this.Parse """
module Program

type T = Option<int>
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore F# Option type postfix syntax``() =
this.Parse """
module Program

type T = int option
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore F# ref type prefix syntax``() =
this.Parse """
module Program

type T = ref<int>
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore F# ref type postfix syntax``() =
this.Parse """
module Program

type T = int ref
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore F# array type prefix syntax``() =
this.Parse """
module Program

type T = array<int>
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore F# array type standard postfix syntax``() =
this.Parse """
module Program

type T = int array
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Ignore F# array type special postfix syntax``() =
this.Parse """
module Program

type T = int []
"""

Assert.IsTrue this.NoErrorsExist

[<Test>]
member this.``Error for generic type postfix syntax``() =
this.Parse """
module Program

type X = int Generic
"""

Assert.IsTrue(this.ErrorExistsAt(4, 9))

[<Test>]
member this.``No error for generic type prefix syntax``() =
this.Parse """
module Program

type X = Generic<int>
"""

Assert.IsTrue this.NoErrorsExist

[<TestFixture>]
type TestFormattingAlwaysTypePrefixing() =
inherit TestAstNodeRuleBase.TestAstNodeRuleBase(TypePrefixing.rule { Config.Mode = Mode.Always })
Expand Down