Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: two hybrid modes for TypePrefixing #1

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
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
Loading