diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 4896ad695..ac93bd8f5 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -1,36 +1,36 @@
-{
-  "version": 1,
-  "isRoot": true,
-  "tools": {
-    "fake-cli": {
-      "version": "5.23.0",
-      "commands": [
-        "fake"
-      ]
-    },
-    "paket": {
-      "version": "7.2.1",
-      "commands": [
-        "paket"
-      ]
-    },
-    "octonav": {
-      "version": "0.0.1",
-      "commands": [
-        "octonav"
-      ]
-    },
-    "dotnet-reportgenerator-globaltool": {
-      "version": "5.0.2",
-      "commands": [
-        "reportgenerator"
-      ]
-    },
-    "fantomas": {
-      "version": "6.1.0",
-      "commands": [
-        "fantomas"
-      ]
-    }
-  }
-}
+{
+  "version": 1,
+  "isRoot": true,
+  "tools": {
+    "fake-cli": {
+      "version": "5.23.0",
+      "commands": [
+        "fake"
+      ]
+    },
+    "paket": {
+      "version": "7.2.1",
+      "commands": [
+        "paket"
+      ]
+    },
+    "octonav": {
+      "version": "0.0.1",
+      "commands": [
+        "octonav"
+      ]
+    },
+    "dotnet-reportgenerator-globaltool": {
+      "version": "5.0.2",
+      "commands": [
+        "reportgenerator"
+      ]
+    },
+    "fantomas": {
+      "version": "6.2.0",
+      "commands": [
+        "fantomas"
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
index c68f8a32f..319a5a0c3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -17,7 +17,7 @@ insert_final_newline = ignore
 [*.md]
 trim_trailing_whitespace = false
 
-[*.fs, *.fsx]
+[*.{fs,fsx}]
 indent_size = 2
 fsharp_max_array_or_list_width=80
 fsharp_max_dot_get_expression_width=80
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a1dc7cf2b..23b2b5848 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,9 +16,9 @@ on:
 jobs:
   build:
     env:
-      TEST_TIMEOUT_MINUTES: 30
+      TEST_TIMEOUT_MINUTES: 40
       FSAC_TEST_DEFAULT_TIMEOUT : 120000 #ms, individual test timeouts
-    timeout-minutes: 30 # we have a locking issue, so cap the runs at ~20m to account for varying build times, etc
+    timeout-minutes: 40 # we have a locking issue, so cap the runs at ~20m to account for varying build times, etc
     strategy:
       matrix:
         os: [windows-latest, macos-latest, ubuntu-latest]
diff --git a/src/FsAutoComplete.Core/AdaptiveExtensions.fs b/src/FsAutoComplete.Core/AdaptiveExtensions.fs
index d44d1da52..614869b24 100644
--- a/src/FsAutoComplete.Core/AdaptiveExtensions.fs
+++ b/src/FsAutoComplete.Core/AdaptiveExtensions.fs
@@ -42,8 +42,7 @@ module AdaptiveExtensions =
 
 
 module Utils =
-  let cheapEqual (a: 'T) (b: 'T) =
-    ShallowEqualityComparer<'T>.Instance.Equals(a, b)
+  let cheapEqual (a: 'T) (b: 'T) = ShallowEqualityComparer<'T>.Instance.Equals(a, b)
 
 /// <summary>
 /// Maps and calls dispose before mapping of new values. Useful for cleaning up callbacks like AddMarkingCallback for tracing purposes.
@@ -75,8 +74,7 @@ module AVal =
   /// <summary>
   /// Maps and calls dispose before mapping of new values. Useful for cleaning up callbacks like AddMarkingCallback for tracing purposes.
   /// </summary>
-  let mapDisposableTuple mapper value =
-    MapDisposableTupleVal(mapper, value) :> aval<_>
+  let mapDisposableTuple mapper value = MapDisposableTupleVal(mapper, value) :> aval<_>
 
   /// <summary>
   /// Calls a mapping function which creates additional dependencies to be tracked.
@@ -124,14 +122,12 @@ module AVal =
 
     /// <summary>Creates an observable on the aval that will be executed whenever the avals value changed.</summary>
     /// <param name="aval">The aval to get out-of-date information from.</param>
-    let onValueChangedWeak (aval: #aval<_>) =
-      Observable.Create(fun (obs: IObserver<_>) -> aval.AddCallback(obs.OnNext))
+    let onValueChangedWeak (aval: #aval<_>) = Observable.Create(fun (obs: IObserver<_>) -> aval.AddCallback(obs.OnNext))
 
 module ASet =
   /// Creates an amap with the keys from the set and the values given by mapping and
   /// adaptively applies the given mapping function to all elements and returns a new amap containing the results.
-  let mapAtoAMap mapper src =
-    src |> ASet.mapToAMap mapper |> AMap.mapA (fun _ v -> v)
+  let mapAtoAMap mapper src = src |> ASet.mapToAMap mapper |> AMap.mapA (fun _ v -> v)
 
 module AMap =
   open FSharp.Data.Traceable
@@ -476,8 +472,7 @@ module AsyncAVal =
   /// <summary>
   /// Creates a constant async adaptive value always holding the given value.
   /// </summary>
-  let constant (value: 'a) =
-    ConstantVal(Task.FromResult value) :> asyncaval<_>
+  let constant (value: 'a) = ConstantVal(Task.FromResult value) :> asyncaval<_>
 
   /// <summary>
   /// Creates a constant async adaptive value always holding the task.
diff --git a/src/FsAutoComplete.Core/CodeGeneration.fs b/src/FsAutoComplete.Core/CodeGeneration.fs
index 0e3c5ecd3..f9ee73987 100644
--- a/src/FsAutoComplete.Core/CodeGeneration.fs
+++ b/src/FsAutoComplete.Core/CodeGeneration.fs
@@ -99,11 +99,9 @@ module CodeGenerationUtils =
       for _ in 0 .. count - 1 do
         x.WriteLine ""
 
-    member __.Indent i =
-      indentWriter.Indent <- indentWriter.Indent + i
+    member __.Indent i = indentWriter.Indent <- indentWriter.Indent + i
 
-    member __.Unindent i =
-      indentWriter.Indent <- max 0 (indentWriter.Indent - i)
+    member __.Unindent i = indentWriter.Indent <- max 0 (indentWriter.Indent - i)
 
     member __.Dump() = indentWriter.InnerWriter.ToString()
 
@@ -210,8 +208,7 @@ module CodeGenerationUtils =
       let revd = List.rev xs
       Some(List.rev revd.Tail, revd.Head)
 
-  let bracket (str: string) =
-    if str.Contains(" ") then "(" + str + ")" else str
+  let bracket (str: string) = if str.Contains(" ") then "(" + str + ")" else str
 
   let formatType ctx (typ: FSharpType) =
     let genericDefinition =
@@ -364,8 +361,7 @@ module CodeGenerationUtils =
     else
       displayName
 
-  let isEventMember (m: FSharpMemberOrFunctionOrValue) =
-    m.IsEvent || hasAttribute<CLIEventAttribute> m.Attributes
+  let isEventMember (m: FSharpMemberOrFunctionOrValue) = m.IsEvent || hasAttribute<CLIEventAttribute> m.Attributes
 
   /// Rename a given argument if the identifier has been used
 
@@ -446,8 +442,7 @@ module CodeGenerationUtils =
 
         writer.Unindent ctx.Indentation
 
-    let memberPrefix (m: FSharpMemberOrFunctionOrValue) =
-      if m.IsDispatchSlot then "override " else "member "
+    let memberPrefix (m: FSharpMemberOrFunctionOrValue) = if m.IsDispatchSlot then "override " else "member "
 
     match m with
     | MemberInfo.PropertyGetSet(getter, setter) ->
@@ -588,8 +583,7 @@ module CodeGenerationUtils =
   /// Use this hack when FCS doesn't return enough information on .NET properties and events.
   /// we use this to filter out the 'meta' members in favor of providing the underlying members for template generation
   /// eg: a property _also_ has the relevant get/set members, so we don't need them.
-  let isSyntheticMember (m: FSharpMemberOrFunctionOrValue) =
-    m.IsProperty || m.IsEventAddMethod || m.IsEventRemoveMethod
+  let isSyntheticMember (m: FSharpMemberOrFunctionOrValue) = m.IsProperty || m.IsEventAddMethod || m.IsEventRemoveMethod
 
   let isAbstractNonVirtualMember (m: FSharpMemberOrFunctionOrValue) =
     // is an abstract member
@@ -733,8 +727,7 @@ module CodeGenerationUtils =
     | _ -> lastValidToken
 
   /// The code below is responsible for handling the code generation and determining the insert position
-  let getLineIdent (lineStr: string) =
-    lineStr.Length - lineStr.TrimStart(' ').Length
+  let getLineIdent (lineStr: string) = lineStr.Length - lineStr.TrimStart(' ').Length
 
   let formatMembersAt
     startColumn
diff --git a/src/FsAutoComplete.Core/Commands.fs b/src/FsAutoComplete.Core/Commands.fs
index 3fd723e8e..a70c78151 100644
--- a/src/FsAutoComplete.Core/Commands.fs
+++ b/src/FsAutoComplete.Core/Commands.fs
@@ -66,8 +66,7 @@ module private Result =
 
 module AsyncResult =
 
-  let inline mapErrorRes ar : Async<CoreResponse<'a>> =
-    AsyncResult.foldResult id CoreResponse.ErrorRes ar
+  let inline mapErrorRes ar : Async<CoreResponse<'a>> = AsyncResult.foldResult id CoreResponse.ErrorRes ar
 
   let recoverCancellationGeneric (ar: Async<Result<'t, exn>>) recoverInternal =
     AsyncResult.foldResult id recoverInternal ar
@@ -584,8 +583,7 @@ module Commands =
         | false, None -> currentIndex, false, acc
 
       // Signature looks like <T> is Async<unit>
-      let inline removeSignPrefix (s: String) =
-        s.Split(" is ") |> Array.tryLast |> Option.defaultValue ""
+      let inline removeSignPrefix (s: String) = s.Split(" is ") |> Array.tryLast |> Option.defaultValue ""
 
       let hints =
         Array.init ((contents: ISourceText).GetLineCount()) (fun line -> (contents: ISourceText).GetLineString line)
@@ -697,8 +695,7 @@ module Commands =
         //TODO: unite with `CodeFix/ResolveNamespace`
         //TODO: Handle Nearest AND TopLevel. Currently it's just Nearest (vs. ResolveNamespace -> TopLevel) (#789)
 
-        let detectIndentation (line: string) =
-          line |> Seq.takeWhile ((=) ' ') |> Seq.length
+        let detectIndentation (line: string) = line |> Seq.takeWhile ((=) ' ') |> Seq.length
 
         // adjust line
         let pos =
@@ -1683,8 +1680,7 @@ type Commands
   member x.TryGetFileCheckerOptionsWithLinesAndLineStr(file: string<LocalPath>, pos) =
     state.TryGetFileCheckerOptionsWithLinesAndLineStr(file, pos)
 
-  member x.TryGetFileCheckerOptionsWithLines(file: string<LocalPath>) =
-    state.TryGetFileCheckerOptionsWithLines file
+  member x.TryGetFileCheckerOptionsWithLines(file: string<LocalPath>) = state.TryGetFileCheckerOptionsWithLines file
 
   member x.TryGetFileVersion = state.TryGetFileVersion
 
@@ -1967,8 +1963,7 @@ type Commands
     includeExternal
     =
     async {
-      let getAllSymbols () =
-        if includeExternal then tyRes.GetAllEntities true else []
+      let getAllSymbols () = if includeExternal then tyRes.GetAllEntities true else []
 
       let! res = tyRes.TryGetCompletions pos lineStr filter getAllSymbols
 
@@ -2180,11 +2175,9 @@ type Commands
 
         let summarySection = "/// <summary></summary>"
 
-        let parameterSection (name, _type) =
-          $"/// <param name=\"%s{name}\"></param>"
+        let parameterSection (name, _type) = $"/// <param name=\"%s{name}\"></param>"
 
-        let genericArg name =
-          $"/// <typeparam name=\"'%s{name}\"></typeparam>"
+        let genericArg name = $"/// <typeparam name=\"'%s{name}\"></typeparam>"
 
         let returnsSection = "/// <returns></returns>"
 
@@ -2261,15 +2254,13 @@ type Commands
                 return usages |> Seq.map (fun u -> u.Range)
           }
 
-      let tryGetFileSource symbolFile =
-        state.TryGetFileSource symbolFile |> Async.singleton
+      let tryGetFileSource symbolFile = state.TryGetFileSource symbolFile |> Async.singleton
 
       let tryGetProjectOptionsForFsproj (fsprojPath: string<LocalPath>) =
         state.ProjectController.GetProjectOptionsForFsproj(UMX.untag fsprojPath)
         |> Async.singleton
 
-      let getAllProjectOptions () =
-        state.ProjectController.ProjectOptions |> Seq.map snd |> Async.singleton
+      let getAllProjectOptions () = state.ProjectController.ProjectOptions |> Seq.map snd |> Async.singleton
 
       return!
         Commands.symbolUseWorkspace
@@ -2301,14 +2292,11 @@ type Commands
     }
 
   member x.SymbolImplementationProject (tyRes: ParseAndCheckResults) (pos: Position) lineStr =
-    let getProjectOptions filePath =
-      state.GetProjectOptions' filePath |> Async.singleton
+    let getProjectOptions filePath = state.GetProjectOptions' filePath |> Async.singleton
 
-    let getUsesOfSymbol (filePath, opts, sym: FSharpSymbol) =
-      checker.GetUsesOfSymbol(filePath, opts, sym)
+    let getUsesOfSymbol (filePath, opts, sym: FSharpSymbol) = checker.GetUsesOfSymbol(filePath, opts, sym)
 
-    let getAllProjects () =
-      state.FSharpProjectOptions |> Seq.toList |> Async.singleton
+    let getAllProjects () = state.FSharpProjectOptions |> Seq.toList |> Async.singleton
 
     Commands.symbolImplementationProject getProjectOptions getUsesOfSymbol getAllProjects tyRes pos lineStr
     |> x.AsCancellable tyRes.FileName
@@ -2469,8 +2457,7 @@ type Commands
       match tyResOpt with
       | None -> ()
       | Some tyRes ->
-        let getSourceLine lineNo =
-          (source :> ISourceText).GetLineString(lineNo - 1)
+        let getSourceLine lineNo = (source :> ISourceText).GetLineString(lineNo - 1)
 
         let! simplified = SimplifyNames.getSimplifiableNames (tyRes.GetCheckResults, getSourceLine)
         let simplified = Array.ofSeq simplified
@@ -2513,8 +2500,7 @@ type Commands
     let version = Version.info ()
     version.GitSha
 
-  member __.Quit() =
-    async { return [ CoreResponse.InfoRes "quitting..." ] }
+  member __.Quit() = async { return [ CoreResponse.InfoRes "quitting..." ] }
 
   member x.ScopesForFile(file: string<LocalPath>) =
     let getParseResultsForFile file =
@@ -2567,8 +2553,7 @@ type Commands
   member __.SetWorkspaceRoot(root: string option) = workspaceRoot <- root
   // linterConfiguration <- Lint.loadConfiguration workspaceRoot linterConfigFileRelativePath
 
-  member __.SetLinterConfigRelativePath(relativePath: string option) =
-    linterConfigFileRelativePath <- relativePath
+  member __.SetLinterConfigRelativePath(relativePath: string option) = linterConfigFileRelativePath <- relativePath
   // linterConfiguration <- Lint.loadConfiguration workspaceRoot linterConfigFileRelativePath
 
   // member __.FSharpLiterate (file: string<LocalPath>) =
diff --git a/src/FsAutoComplete.Core/CompilerServiceInterface.fs b/src/FsAutoComplete.Core/CompilerServiceInterface.fs
index e4540034d..8b1b3d1b3 100644
--- a/src/FsAutoComplete.Core/CompilerServiceInterface.fs
+++ b/src/FsAutoComplete.Core/CompilerServiceInterface.fs
@@ -103,8 +103,7 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelRefe
         "mscorlib" ]
       |> List.map (fun p -> p + ".dll")
 
-    let containsBadRef (s: string) =
-      badRefs |> List.exists (fun r -> s.EndsWith r)
+    let containsBadRef (s: string) = badRefs |> List.exists (fun r -> s.EndsWith r)
 
     fun (projOptions: FSharpProjectOptions) ->
       { projOptions with
@@ -122,8 +121,7 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelRefe
     { projectOptions with
         SourceFiles = files }
 
-  let (|Reference|_|) (opt: string) =
-    if opt.StartsWith "-r:" then Some(opt.[3..]) else None
+  let (|Reference|_|) (opt: string) = if opt.StartsWith "-r:" then Some(opt.[3..]) else None
 
   /// ensures that all file paths are absolute before being sent to the compiler, because compilation of scripts fails with relative paths
   let resolveRelativeFilePaths (projectOptions: FSharpProjectOptions) =
diff --git a/src/FsAutoComplete.Core/DocumentationFormatter.fs b/src/FsAutoComplete.Core/DocumentationFormatter.fs
index c7d985781..a1788ebf8 100644
--- a/src/FsAutoComplete.Core/DocumentationFormatter.fs
+++ b/src/FsAutoComplete.Core/DocumentationFormatter.fs
@@ -167,11 +167,9 @@ module DocumentationFormatter =
         }
         |> String.concat ""
 
-      let typeConstraint (tc: FSharpType) =
-        sprintf ":> %s" (tc |> format displayContext |> fst)
+      let typeConstraint (tc: FSharpType) = sprintf ":> %s" (tc |> format displayContext |> fst)
 
-      let enumConstraint (ec: FSharpType) =
-        sprintf "enum<%s>" (ec |> format displayContext |> fst)
+      let enumConstraint (ec: FSharpType) = sprintf "enum<%s>" (ec |> format displayContext |> fst)
 
       let delegateConstraint (tc: FSharpGenericParameterDelegateConstraint) =
         sprintf
@@ -485,8 +483,7 @@ module DocumentationFormatter =
         with _ ->
           "Unknown"
 
-    let formatName (parameter: FSharpParameter) =
-      parameter.Name |> Option.defaultValue parameter.DisplayName
+    let formatName (parameter: FSharpParameter) = parameter.Name |> Option.defaultValue parameter.DisplayName
 
     let isDelegate =
       match func.EnclosingEntitySafe with
diff --git a/src/FsAutoComplete.Core/DotnetNewTemplate.fs b/src/FsAutoComplete.Core/DotnetNewTemplate.fs
index da1a3e67f..8fcdeb91c 100644
--- a/src/FsAutoComplete.Core/DotnetNewTemplate.fs
+++ b/src/FsAutoComplete.Core/DotnetNewTemplate.fs
@@ -118,8 +118,7 @@ module DotnetNewTemplate =
 
             ] } ]
 
-  let isMatch (filterstr: string) (x: string) =
-    x.ToLower().Contains(filterstr.ToLower())
+  let isMatch (filterstr: string) (x: string) = x.ToLower().Contains(filterstr.ToLower())
 
   let nameMatch (filterstr: string) (x: string) = x.ToLower() = filterstr.ToLower()
 
diff --git a/src/FsAutoComplete.Core/FileSystem.fs b/src/FsAutoComplete.Core/FileSystem.fs
index a4b5de9c9..5d37badc3 100644
--- a/src/FsAutoComplete.Core/FileSystem.fs
+++ b/src/FsAutoComplete.Core/FileSystem.fs
@@ -247,8 +247,7 @@ type NamedText(fileName: string<LocalPath>, str: string) =
 
       Ok(builder.ToString())
 
-  member private x.GetLineUnsafe(pos: FSharp.Compiler.Text.Position) =
-    (x :> ISourceText).GetLineString(pos.Line - 1)
+  member private x.GetLineUnsafe(pos: FSharp.Compiler.Text.Position) = (x :> ISourceText).GetLineString(pos.Line - 1)
 
   /// Provides safe access to a line of the file via FCS-provided Position
   member x.GetLine(pos: FSharp.Compiler.Text.Position) : string option =
@@ -399,11 +398,9 @@ type NamedText(fileName: string<LocalPath>, str: string) =
 
     loop start
 
-  member x.WalkForward(start, terminal, condition) =
-    x.Walk(start, x.NextPos, terminal, condition)
+  member x.WalkForward(start, terminal, condition) = x.Walk(start, x.NextPos, terminal, condition)
 
-  member x.WalkBackwards(start, terminal, condition) =
-    x.Walk(start, x.PrevPos, terminal, condition)
+  member x.WalkBackwards(start, terminal, condition) = x.Walk(start, x.PrevPos, terminal, condition)
 
 
   /// Provides line-by-line access to the underlying text.
@@ -473,11 +470,9 @@ type NamedText(fileName: string<LocalPath>, str: string) =
     member x.Item
       with get (pos: FSharp.Compiler.Text.Position) = x.Item pos
 
-    member x.WalkForward(start, terminal, condition) =
-      x.WalkForward(start, terminal, condition)
+    member x.WalkForward(start, terminal, condition) = x.WalkForward(start, terminal, condition)
 
-    member x.WalkBackwards(start, terminal, condition) =
-      x.WalkBackwards(start, terminal, condition)
+    member x.WalkBackwards(start, terminal, condition) = x.WalkBackwards(start, terminal, condition)
 
 module RoslynSourceText =
   open Microsoft.CodeAnalysis.Text
@@ -486,8 +481,7 @@ module RoslynSourceText =
   [<RequireQualifiedAccess>]
   module Hash =
     /// (From Roslyn) This is how VB Anonymous Types combine hash values for fields.
-    let combine (newKey: int) (currentKey: int) =
-      (currentKey * (int 0xA5555529)) + newKey
+    let combine (newKey: int) (currentKey: int) = (currentKey * (int 0xA5555529)) + newKey
 
     let combineValues (values: seq<'T>) =
       (0, values) ||> Seq.fold (fun hash value -> combine (value.GetHashCode()) hash)
@@ -686,8 +680,7 @@ module RoslynSourceText =
             else
               (0, 0)
 
-          member _.GetSubTextString(start, length) =
-            sourceText.GetSubText(TextSpan(start, length)).ToString()
+          member _.GetSubTextString(start, length) = sourceText.GetSubText(TextSpan(start, length)).ToString()
 
           member _.SubTextEquals(target, startIndex) =
             if startIndex < 0 || startIndex >= sourceText.Length then
@@ -813,8 +806,7 @@ type FileSystem(actualFs: IFileSystem, tryFindFile: string<LocalPath> -> Volatil
   ///
   /// either the first char is '/', or the first char is a drive identifier followed by ':'
   let isWindowsStyleRootedPath (p: string) =
-    let isAlpha (c: char) =
-      (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+    let isAlpha (c: char) = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
 
     (p.Length >= 1 && p.[0] = '/')
     || (p.Length >= 2 && isAlpha p.[0] && p.[1] = ':')
@@ -882,8 +874,7 @@ type FileSystem(actualFs: IFileSystem, tryFindFile: string<LocalPath> -> Volatil
     member _.GetCreationTimeShim p = actualFs.GetCreationTimeShim p
     member _.GetDirectoryNameShim p = actualFs.GetDirectoryNameShim p
 
-    member _.GetFullFilePathInDirectoryShim dir f =
-      actualFs.GetFullFilePathInDirectoryShim dir f
+    member _.GetFullFilePathInDirectoryShim dir f = actualFs.GetFullFilePathInDirectoryShim dir f
 
     member _.OpenFileForReadShim(filePath: string, useMemoryMappedFile, shouldShadowCopy) =
       filePath
diff --git a/src/FsAutoComplete.Core/InlayHints.fs b/src/FsAutoComplete.Core/InlayHints.fs
index 215f5101f..fccc5568f 100644
--- a/src/FsAutoComplete.Core/InlayHints.fs
+++ b/src/FsAutoComplete.Core/InlayHints.fs
@@ -86,8 +86,7 @@ let private getArgumentsFor (state: FsAutoComplete.State, p: ParseAndCheckResult
     | _ -> return! None
   }
 
-let private isSignatureFile (f: string<LocalPath>) =
-  System.IO.Path.GetExtension(UMX.untag f) = ".fsi"
+let private isSignatureFile (f: string<LocalPath>) = System.IO.Path.GetExtension(UMX.untag f) = ".fsi"
 
 type private FSharp.Compiler.CodeAnalysis.FSharpParseFileResults with
   // duplicates + extends the logic in FCS to match bindings of the form `let x: int = 12`
@@ -168,8 +167,7 @@ module private ShouldCreate =
 
 
   [<return: Struct>]
-  let private (|StartsWith|_|) (v: string) (fullName: string) =
-    if fullName.StartsWith v then ValueSome() else ValueNone
+  let private (|StartsWith|_|) (v: string) (fullName: string) = if fullName.StartsWith v then ValueSome() else ValueNone
   // doesn't differentiate between modules, types, namespaces
   // -> is just for documentation in code
   [<return: Struct>]
@@ -223,8 +221,7 @@ module private ShouldCreate =
       | _ -> false
     | _ -> false
 
-  let inline private hasName (p: FSharpParameter) =
-    not (String.IsNullOrEmpty p.DisplayName) && p.DisplayName <> "````"
+  let inline private hasName (p: FSharpParameter) = not (String.IsNullOrEmpty p.DisplayName) && p.DisplayName <> "````"
 
   let inline private isMeaningfulName (p: FSharpParameter) = p.DisplayName.Length > 2
 
diff --git a/src/FsAutoComplete.Core/Lexer.fs b/src/FsAutoComplete.Core/Lexer.fs
index cc7d503b3..63e71c50b 100644
--- a/src/FsAutoComplete.Core/Lexer.fs
+++ b/src/FsAutoComplete.Core/Lexer.fs
@@ -79,17 +79,13 @@ module Lexer =
 
     loop FSharpTokenizerLexState.Initial []
 
-  let inline private isIdentifier t =
-    t.CharClass = FSharpTokenCharKind.Identifier
+  let inline private isIdentifier t = t.CharClass = FSharpTokenCharKind.Identifier
 
-  let inline private isOperator t =
-    t.CharClass = FSharpTokenCharKind.Operator
+  let inline private isOperator t = t.CharClass = FSharpTokenCharKind.Operator
 
-  let inline private isKeyword t =
-    t.ColorClass = FSharpTokenColorKind.Keyword
+  let inline private isKeyword t = t.ColorClass = FSharpTokenColorKind.Keyword
 
-  let inline private isPunctuation t =
-    t.ColorClass = FSharpTokenColorKind.Punctuation
+  let inline private isPunctuation t = t.ColorClass = FSharpTokenColorKind.Punctuation
 
   let inline private (|GenericTypeParameterPrefix|StaticallyResolvedTypeParameterPrefix|ActivePattern|Other|)
     (
@@ -318,8 +314,7 @@ module Lexer =
     else
       getSymbol 0 col lineStr lookupType [||] |> Option.bind tryGetLexerSymbolIslands
 
-  let findLongIdents (col, lineStr) =
-    findIdents col lineStr SymbolLookupKind.Fuzzy
+  let findLongIdents (col, lineStr) = findIdents col lineStr SymbolLookupKind.Fuzzy
 
   let findLongIdentsAndResidue (col, lineStr: string) =
     let lineStr = lineStr.Substring(0, System.Math.Max(0, col))
diff --git a/src/FsAutoComplete.Core/ParseAndCheckResults.fs b/src/FsAutoComplete.Core/ParseAndCheckResults.fs
index 4c820231d..3efd8b93f 100644
--- a/src/FsAutoComplete.Core/ParseAndCheckResults.fs
+++ b/src/FsAutoComplete.Core/ParseAndCheckResults.fs
@@ -732,8 +732,7 @@ type ParseAndCheckResults
     with _ ->
       []
 
-  member __.GetAllSymbolUsesInFile() =
-    checkResults.GetAllUsesOfAllSymbolsInFile()
+  member __.GetAllSymbolUsesInFile() = checkResults.GetAllUsesOfAllSymbolsInFile()
 
   member __.GetSemanticClassification = checkResults.GetSemanticClassification None
   member __.GetAST = parseResults.ParseTree
diff --git a/src/FsAutoComplete.Core/SignatureFormatter.fs b/src/FsAutoComplete.Core/SignatureFormatter.fs
index 1e4554aa2..cd0dfe201 100644
--- a/src/FsAutoComplete.Core/SignatureFormatter.fs
+++ b/src/FsAutoComplete.Core/SignatureFormatter.fs
@@ -38,8 +38,7 @@ module SignatureFormatter =
         "Microsoft.FSharp.Core.CompilerServices.MeasureInverse`1"
         "Microsoft.FSharp.Core.CompilerServices.MeasureProduct`2" ]
 
-  let private isMeasureType (t: FSharpEntity) =
-    Set.contains t.FullName measureTypeNames
+  let private isMeasureType (t: FSharpEntity) = Set.contains t.FullName measureTypeNames
 
   let rec formatFSharpType (context: FSharpDisplayContext) (typ: FSharpType) : string =
     let context = context.WithPrefixGenericParameters()
@@ -124,11 +123,9 @@ module SignatureFormatter =
         }
         |> String.concat ""
 
-      let typeConstraint (tc: FSharpType) =
-        sprintf ":> %s" (formatFSharpType displayContext tc)
+      let typeConstraint (tc: FSharpType) = sprintf ":> %s" (formatFSharpType displayContext tc)
 
-      let enumConstraint (ec: FSharpType) =
-        sprintf "enum<%s>" (formatFSharpType displayContext ec)
+      let enumConstraint (ec: FSharpType) = sprintf "enum<%s>" (formatFSharpType displayContext ec)
 
       let delegateConstraint (tc: FSharpGenericParameterDelegateConstraint) =
         sprintf
@@ -447,8 +444,7 @@ module SignatureFormatter =
         with _ ->
           "Unknown"
 
-    let formatName (parameter: FSharpParameter) =
-      parameter.Name |> Option.defaultValue parameter.DisplayName
+    let formatName (parameter: FSharpParameter) = parameter.Name |> Option.defaultValue parameter.DisplayName
 
     let isDelegate =
       match func.EnclosingEntitySafe with
@@ -712,8 +708,7 @@ module SignatureFormatter =
     else typeDisplay + typeTip ()
 
   let footerForType (entity: FSharpSymbolUse) =
-    let formatFooter (fullName, assyName) =
-      $"Full name: %s{fullName}{nl}Assembly: %s{assyName}"
+    let formatFooter (fullName, assyName) = $"Full name: %s{fullName}{nl}Assembly: %s{assyName}"
 
     let valFooterData =
       try
diff --git a/src/FsAutoComplete.Core/Sourcelink.fs b/src/FsAutoComplete.Core/Sourcelink.fs
index f5b1f0aae..97f746799 100644
--- a/src/FsAutoComplete.Core/Sourcelink.fs
+++ b/src/FsAutoComplete.Core/Sourcelink.fs
@@ -17,8 +17,7 @@ let private embeddedSourceGuid = System.Guid "0E8A571B-6926-466E-B4AD-8AB04611F5
 
 let private httpClient = new System.Net.Http.HttpClient()
 
-let private toHex (bytes: byte[]) =
-  System.BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant()
+let private toHex (bytes: byte[]) = System.BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant()
 
 /// left hand side of sourcelink document mapping, represents a static or partially-static repo root path
 [<Measure>]
diff --git a/src/FsAutoComplete.Core/TestAdapter.fs b/src/FsAutoComplete.Core/TestAdapter.fs
index 498bbc046..3b7a07f4c 100644
--- a/src/FsAutoComplete.Core/TestAdapter.fs
+++ b/src/FsAutoComplete.Core/TestAdapter.fs
@@ -83,8 +83,7 @@ let getExpectoTests (ast: ParsedInput) : TestAdapterEntry<range> list =
     || str.EndsWith "ftestTheoryTask"
     || str.EndsWith "ptestTheoryTask"
 
-  let isExpectoListName (str: string) =
-    str.EndsWith "testList" || str.EndsWith "ftestList" || str.EndsWith "ptestList"
+  let isExpectoListName (str: string) = str.EndsWith "testList" || str.EndsWith "ftestList" || str.EndsWith "ptestList"
 
   let (|Case|List|NotExpecto|) =
     function
diff --git a/src/FsAutoComplete.Core/TipFormatter.fs b/src/FsAutoComplete.Core/TipFormatter.fs
index d0c3ce2bc..ffc2bfeb3 100644
--- a/src/FsAutoComplete.Core/TipFormatter.fs
+++ b/src/FsAutoComplete.Core/TipFormatter.fs
@@ -45,8 +45,7 @@ module private Section =
       |> String.concat nl
       |> addSection name
 
-  let fromOption (name: string) (content: string option) =
-    if content.IsNone then "" else addSection name content.Value
+  let fromOption (name: string) (content: string option) = if content.IsNone then "" else addSection name content.Value
 
   let fromList (name: string) (content: string seq) =
     if Seq.isEmpty content then
@@ -73,8 +72,7 @@ module private Format =
     { TagName: string
       Formatter: TagInfo -> string option }
 
-  let private extractTextFromQuote (quotedText: string) =
-    quotedText.Substring(1, quotedText.Length - 2)
+  let private extractTextFromQuote (quotedText: string) = quotedText.Substring(1, quotedText.Length - 2)
 
 
   let extractMemberText (text: string) =
@@ -531,11 +529,9 @@ module private Format =
           None
       | _ -> None
 
-    let tryGetDescription (text: string) =
-      tryGetInnerTextOnNonVoidElement text "description"
+    let tryGetDescription (text: string) = tryGetInnerTextOnNonVoidElement text "description"
 
-    let tryGetTerm (text: string) =
-      tryGetInnerTextOnNonVoidElement text "term"
+    let tryGetTerm (text: string) = tryGetInnerTextOnNonVoidElement text "term"
 
     let rec extractItemList (res: ItemList list) (text: string) =
       match Regex.Match(text, tagPattern "item", RegexOptions.IgnoreCase) with
@@ -749,8 +745,7 @@ type private XmlDocMember(doc: XmlDocument, indentationSize: int, columnOffset:
     |> Seq.map (fun node -> Format.extractMemberText node.Attributes.[0].InnerText, node)
     |> Seq.toList
 
-  let readRemarks (doc: XmlDocument) =
-    doc.DocumentElement.GetElementsByTagName "remarks" |> Seq.cast<XmlNode>
+  let readRemarks (doc: XmlDocument) = doc.DocumentElement.GetElementsByTagName "remarks" |> Seq.cast<XmlNode>
 
   let rawSummary = doc.DocumentElement.ChildNodes.[0]
   let rawParameters = readChildren "param" doc
@@ -776,8 +771,7 @@ type private XmlDocMember(doc: XmlDocument, indentationSize: int, columnOffset:
       |> List.contains node.ParentNode.Name
       |> not)
 
-  let readNamedContentAsKvPair (key, content) =
-    KeyValuePair(key, readContentForTooltip content)
+  let readNamedContentAsKvPair (key, content) = KeyValuePair(key, readContentForTooltip content)
 
   let summary = readContentForTooltip rawSummary
 
diff --git a/src/FsAutoComplete.Core/TypedAstPatterns.fs b/src/FsAutoComplete.Core/TypedAstPatterns.fs
index 47c5c9b34..a787c07f0 100644
--- a/src/FsAutoComplete.Core/TypedAstPatterns.fs
+++ b/src/FsAutoComplete.Core/TypedAstPatterns.fs
@@ -381,16 +381,13 @@ module SymbolPatterns =
     else
       None
 
-  let (|Record|_|) (e: FSharpEntity) =
-    if e.IsFSharpRecord then Some() else None
+  let (|Record|_|) (e: FSharpEntity) = if e.IsFSharpRecord then Some() else None
 
-  let (|UnionType|_|) (e: FSharpEntity) =
-    if e.IsFSharpUnion then Some() else None
+  let (|UnionType|_|) (e: FSharpEntity) = if e.IsFSharpUnion then Some() else None
 
   let (|Delegate|_|) (e: FSharpEntity) = if e.IsDelegate then Some() else None
 
-  let (|FSharpException|_|) (e: FSharpEntity) =
-    if e.IsFSharpExceptionDeclaration then Some() else None
+  let (|FSharpException|_|) (e: FSharpEntity) = if e.IsFSharpExceptionDeclaration then Some() else None
 
   let (|Interface|_|) (e: FSharpEntity) = if e.IsInterface then Some() else None
 
@@ -420,26 +417,22 @@ module SymbolPatterns =
   let (|ByRef|_|) (e: FSharpEntity) = if e.IsByRef then Some() else None
   let (|Array|_|) (e: FSharpEntity) = if e.IsArrayType then Some() else None
 
-  let (|FSharpModule|_|) (entity: FSharpEntity) =
-    if entity.IsFSharpModule then Some() else None
+  let (|FSharpModule|_|) (entity: FSharpEntity) = if entity.IsFSharpModule then Some() else None
 
-  let (|Namespace|_|) (entity: FSharpEntity) =
-    if entity.IsNamespace then Some() else None
+  let (|Namespace|_|) (entity: FSharpEntity) = if entity.IsNamespace then Some() else None
 
   let (|ProvidedAndErasedType|_|) (entity: FSharpEntity) = None
 
   let (|Enum|_|) (entity: FSharpEntity) = if entity.IsEnum then Some() else None
 
-  let (|Tuple|_|) (ty: FSharpType option) =
-    ty |> Option.bind (fun ty -> if ty.IsTupleType then Some() else None)
+  let (|Tuple|_|) (ty: FSharpType option) = ty |> Option.bind (fun ty -> if ty.IsTupleType then Some() else None)
 
   let (|RefCell|_|) (ty: FSharpType) =
     match getAbbreviatedType ty with
     | TypeWithDefinition def when def.IsFSharpRecord && def.FullName = "Microsoft.FSharp.Core.FSharpRef`1" -> Some()
     | _ -> None
 
-  let (|FunctionType|_|) (ty: FSharpType) =
-    if ty.IsFunctionType then Some() else None
+  let (|FunctionType|_|) (ty: FSharpType) = if ty.IsFunctionType then Some() else None
 
   let (|Pattern|_|) (symbol: FSharpSymbol) =
     match symbol with
@@ -520,8 +513,7 @@ module SymbolPatterns =
       | _ -> None
     | _ -> None
 
-  let (|ExtensionMember|_|) (func: FSharpMemberOrFunctionOrValue) =
-    if func.IsExtensionMember then Some() else None
+  let (|ExtensionMember|_|) (func: FSharpMemberOrFunctionOrValue) = if func.IsExtensionMember then Some() else None
 
   let (|Event|_|) (func: FSharpMemberOrFunctionOrValue) = if func.IsEvent then Some() else None
 
diff --git a/src/FsAutoComplete.Core/TypedAstUtils.fs b/src/FsAutoComplete.Core/TypedAstUtils.fs
index bd2e234e9..ec5dc2b35 100644
--- a/src/FsAutoComplete.Core/TypedAstUtils.fs
+++ b/src/FsAutoComplete.Core/TypedAstUtils.fs
@@ -34,11 +34,9 @@ module TypedAstUtils =
     | Some name when name = typeof<'T>.Name -> true
     | _ -> false
 
-  let hasAttribute<'T> (attributes: seq<FSharpAttribute>) =
-    attributes |> Seq.exists isAttribute<'T>
+  let hasAttribute<'T> (attributes: seq<FSharpAttribute>) = attributes |> Seq.exists isAttribute<'T>
 
-  let tryGetAttribute<'T> (attributes: seq<FSharpAttribute>) =
-    attributes |> Seq.tryFind isAttribute<'T>
+  let tryGetAttribute<'T> (attributes: seq<FSharpAttribute>) = attributes |> Seq.tryFind isAttribute<'T>
 
   let hasModuleSuffixAttribute (entity: FSharpEntity) =
     entity.Attributes
@@ -67,8 +65,7 @@ module TypedAstUtils =
 
   let private UnnamedUnionFieldRegex = Regex("^Item(\d+)?$", RegexOptions.Compiled)
 
-  let isUnnamedUnionCaseField (field: FSharpField) =
-    UnnamedUnionFieldRegex.IsMatch(field.Name)
+  let isUnnamedUnionCaseField (field: FSharpField) = UnnamedUnionFieldRegex.IsMatch(field.Name)
 
 [<AutoOpen>]
 module TypedAstExtensionHelpers =
diff --git a/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs b/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs
index 84ee01ce2..3c455d582 100644
--- a/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs
+++ b/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs
@@ -76,8 +76,7 @@ let private posIsInLhsOfClause (pos: Position) (clause: SynMatchClause) =
     Range.rangeContainsPos (Range.unionRanges guardExpr.Range patternRange) pos
 
 let private tryFindPatternMatchExprInParsedInput (pos: Position) (parsedInput: ParsedInput) =
-  let inline getIfPosInRange range f =
-    if Range.rangeContainsPos range pos then f () else None
+  let inline getIfPosInRange range f = if Range.rangeContainsPos range pos then f () else None
 
   let rec walkImplFileInput (ParsedImplFileInput(contents = moduleOrNamespaceList)) =
     List.tryPick walkSynModuleOrNamespace moduleOrNamespaceList
diff --git a/src/FsAutoComplete.Core/UntypedAstUtils.fs b/src/FsAutoComplete.Core/UntypedAstUtils.fs
index 029fe8c2c..440d0477e 100644
--- a/src/FsAutoComplete.Core/UntypedAstUtils.fs
+++ b/src/FsAutoComplete.Core/UntypedAstUtils.fs
@@ -4,8 +4,7 @@ module Syntax =
   open FSharp.Compiler.Syntax
 
   /// A pattern that collects all attributes from a `SynAttributes` into a single flat list
-  let (|AllAttrs|) (attrs: SynAttributes) =
-    attrs |> List.collect (fun attrList -> attrList.Attributes)
+  let (|AllAttrs|) (attrs: SynAttributes) = attrs |> List.collect (fun attrList -> attrList.Attributes)
 
   /// An recursive pattern that collect all sequential expressions to avoid StackOverflowException
   let rec (|Sequentials|_|) =
@@ -571,12 +570,10 @@ module UntypedAstUtils =
   type internal ShortIdent = string
   type internal Idents = ShortIdent[]
 
-  let internal longIdentToArray (longIdent: LongIdent) : Idents =
-    longIdent |> Seq.map string |> Seq.toArray
+  let internal longIdentToArray (longIdent: LongIdent) : Idents = longIdent |> Seq.map string |> Seq.toArray
 
   /// matches if the range contains the position
-  let (|ContainsPos|_|) pos range =
-    if Range.rangeContainsPos range pos then Some() else None
+  let (|ContainsPos|_|) pos range = if Range.rangeContainsPos range pos then Some() else None
 
   /// Active pattern that matches an ident on a given name by the ident's `idText`
   let (|Ident|_|) ofName =
diff --git a/src/FsAutoComplete.Core/Utils.fs b/src/FsAutoComplete.Core/Utils.fs
index dfd2b1f9b..b3fbe2663 100644
--- a/src/FsAutoComplete.Core/Utils.fs
+++ b/src/FsAutoComplete.Core/Utils.fs
@@ -129,8 +129,7 @@ let inline isSignatureFile (fileName: ReadOnlySpan<char>) = fileName.EndsWith ".
 /// </summary>
 let isFsharpFile (fileName: ReadOnlySpan<char>) = fileName.EndsWith ".fs"
 
-let inline internal isFileWithFSharpI fileName =
-  isAScript fileName || isSignatureFile fileName || isFsharpFile fileName
+let inline internal isFileWithFSharpI fileName = isAScript fileName || isSignatureFile fileName || isFsharpFile fileName
 
 
 /// <summary>
@@ -157,8 +156,7 @@ let inline internal normalizePathI (file: ReadOnlySpan<char>) : string<LocalPath
 
 let inline normalizePath (file: string) : string<LocalPath> = normalizePathI file
 
-let inline combinePaths path1 (path2: string) =
-  Path.Combine(path1, path2.TrimStart [| '\\'; '/' |])
+let inline combinePaths path1 (path2: string) = Path.Combine(path1, path2.TrimStart [| '\\'; '/' |])
 
 let inline (</>) path1 path2 = combinePaths path1 path2
 
@@ -203,8 +201,7 @@ module Result =
     | ValueNone -> Error(recover ())
 
   /// ensure the condition is true before continuing
-  let inline guard condition errorValue =
-    if condition () then Ok() else Error errorValue
+  let inline guard condition errorValue = if condition () then Ok() else Error errorValue
 
 [<RequireQualifiedAccess>]
 module Async =
@@ -354,8 +351,7 @@ module Array =
   let startsWith (prefix: _[]) (whole: _[]) = isSubArray prefix whole 0
 
   /// Returns true if one array has trailing elements equal to another's.
-  let endsWith (suffix: _[]) (whole: _[]) =
-    isSubArray suffix whole (whole.Length - suffix.Length)
+  let endsWith (suffix: _[]) (whole: _[]) = isSubArray suffix whole (whole.Length - suffix.Length)
 
   /// Returns a new array with an element replaced with a given value.
   let replace index value (array: _[]) =
@@ -404,8 +400,7 @@ module Array =
 module List =
 
   ///Returns the greatest of all elements in the list that is less than the threshold
-  let maxUnderThreshold nmax =
-    List.maxBy (fun n -> if n > nmax then 0 else n)
+  let maxUnderThreshold nmax = List.maxBy (fun n -> if n > nmax then 0 else n)
 
   /// Groups a tupled list by the first item to produce a list of values
   let groupByFst (tupledItems: ('Key * 'Value) list) =
@@ -648,8 +643,7 @@ let chooseByPrefix (prefix: string) (s: string) =
   else
     None
 
-let chooseByPrefix2 prefixes (s: string) =
-  prefixes |> List.tryPick (fun prefix -> chooseByPrefix prefix s)
+let chooseByPrefix2 prefixes (s: string) = prefixes |> List.tryPick (fun prefix -> chooseByPrefix prefix s)
 
 let splitByPrefix (prefix: string) (s: string) =
   if s.StartsWith(prefix) then
@@ -657,8 +651,7 @@ let splitByPrefix (prefix: string) (s: string) =
   else
     None
 
-let splitByPrefix2 prefixes (s: string) =
-  prefixes |> List.tryPick (fun prefix -> splitByPrefix prefix s)
+let splitByPrefix2 prefixes (s: string) = prefixes |> List.tryPick (fun prefix -> splitByPrefix prefix s)
 
 [<AutoOpen>]
 module Patterns =
@@ -735,8 +728,7 @@ type Debounce<'a>(timeout, fn) as x =
   member val Timeout = timeout with get, set
 
 module Indentation =
-  let inline get (line: string) =
-    line.Length - line.AsSpan().Trim(' ').Length
+  let inline get (line: string) = line.Length - line.AsSpan().Trim(' ').Length
 
 
 type FSharpSymbol with
diff --git a/src/FsAutoComplete.Logging/FsLibLog.fs b/src/FsAutoComplete.Logging/FsLibLog.fs
index a937ecaca..ffcbb5bd6 100644
--- a/src/FsAutoComplete.Logging/FsLibLog.fs
+++ b/src/FsAutoComplete.Logging/FsLibLog.fs
@@ -72,8 +72,7 @@ module Types =
 
     member buf.Peep() = contents.[count - 1]
 
-    member buf.Top(n) =
-      [ for x in contents.[max 0 (count - n) .. count - 1] -> x ] |> List.rev
+    member buf.Top(n) = [ for x in contents.[max 0 (count - n) .. count - 1] -> x ] |> List.rev
 
     member buf.Push(x) =
       buf.Ensure(count + 1)
@@ -132,8 +131,7 @@ module Types =
       /// </summary>
       /// <param name="logConfig">A function to configure a log</param>
       /// <returns><see langword="true"/>  if the log message was logged</returns>
-      member logger.fatal'(logConfig: Log -> Log) =
-        Log.StartLogLevel LogLevel.Fatal |> logConfig |> logger.fromLog
+      member logger.fatal'(logConfig: Log -> Log) = Log.StartLogLevel LogLevel.Fatal |> logConfig |> logger.fromLog
 
       /// <summary>
       /// Logs a fatal log message given a log configurer.
@@ -146,8 +144,7 @@ module Types =
       /// </summary>
       /// <param name="logConfig">A function to configure a log</param>
       /// <returns><see langword="true"/>  if the log message was logged</returns>
-      member logger.error'(logConfig: Log -> Log) =
-        Log.StartLogLevel LogLevel.Error |> logConfig |> logger.fromLog
+      member logger.error'(logConfig: Log -> Log) = Log.StartLogLevel LogLevel.Error |> logConfig |> logger.fromLog
 
       /// <summary>
       /// Logs an error log message given a log configurer.
@@ -160,8 +157,7 @@ module Types =
       /// </summary>
       /// <param name="logConfig">A function to configure a log</param>
       /// <returns><see langword="true"/>  if the log message was logged</returns>
-      member logger.warn'(logConfig: Log -> Log) =
-        Log.StartLogLevel LogLevel.Warn |> logConfig |> logger.fromLog
+      member logger.warn'(logConfig: Log -> Log) = Log.StartLogLevel LogLevel.Warn |> logConfig |> logger.fromLog
 
       /// <summary>
       /// Logs a warn log message given a log configurer.
@@ -174,8 +170,7 @@ module Types =
       /// </summary>
       /// <param name="logConfig">A function to configure a log</param>
       /// <returns><see langword="true"/>  if the log message was logged</returns>
-      member logger.info'(logConfig: Log -> Log) =
-        Log.StartLogLevel LogLevel.Info |> logConfig |> logger.fromLog
+      member logger.info'(logConfig: Log -> Log) = Log.StartLogLevel LogLevel.Info |> logConfig |> logger.fromLog
 
       /// <summary>
       /// Logs an info log message given a log configurer.
@@ -188,8 +183,7 @@ module Types =
       /// </summary>
       /// <param name="logConfig">A function to configure a log</param>
       /// <returns><see langword="true"/>  if the log message was logged</returns>
-      member logger.debug'(logConfig: Log -> Log) =
-        Log.StartLogLevel LogLevel.Debug |> logConfig |> logger.fromLog
+      member logger.debug'(logConfig: Log -> Log) = Log.StartLogLevel LogLevel.Debug |> logConfig |> logger.fromLog
 
       /// <summary>
       /// Logs a debug log message given a log configurer.
@@ -202,8 +196,7 @@ module Types =
       /// </summary>
       /// <param name="logConfig">A function to configure a log</param>
       /// <returns><see langword="true"/>  if the log message was logged</returns>
-      member logger.trace'(logConfig: Log -> Log) =
-        Log.StartLogLevel LogLevel.Trace |> logConfig |> logger.fromLog
+      member logger.trace'(logConfig: Log -> Log) = Log.StartLogLevel LogLevel.Trace |> logConfig |> logger.fromLog
 
       /// <summary>
       /// Logs a trace log message given a log configurer.
@@ -236,8 +229,7 @@ module Types =
     /// <param name="messageThunk">The function that generates a message to add to a Log.</param>
     /// <param name="log">The log to amend.</param>
     /// <returns>The amended log.</returns>
-    let setMessageThunk (messageThunk: unit -> string) (log: Log) =
-      { log with Message = Some messageThunk }
+    let setMessageThunk (messageThunk: unit -> string) (log: Log) = { log with Message = Some messageThunk }
 
     /// <summary>
     /// Amends a <see cref="T:FsLibLog.Types.Log">Log</see> with a parameter.
@@ -323,8 +315,7 @@ module Types =
     let private formatterRegex =
       Regex(@"(?<!{){(?<number>\d+)(?<columnFormat>:(?<format>[^}]+))?}(?!})", RegexOptions.Compiled)
 
-    let private isAnObject value =
-      Convert.GetTypeCode(value) = TypeCode.Object
+    let private isAnObject value = Convert.GetTypeCode(value) = TypeCode.Object
 
     /// <summary>
     /// Amends a <see cref="T:FsLibLog.Types.Log">Log</see> with a given interpolated string. This will generate a message template from a special syntax within the interpolation. The syntax for the interplated string is <code> $"I want to log {myVariable:MyLogVariableName}". </code>
@@ -428,8 +419,7 @@ module Operators =
   /// <param name="key">The name for the parameter.</param>
   /// <param name="value">The value for the parameter.</param>
   /// <returns>The amended log with the parameter added.</returns>
-  let (>>!+) log (key, value) =
-    log >> Log.addContextDestructured key value
+  let (>>!+) log (key, value) = log >> Log.addContextDestructured key value
 
   /// <summary>
   /// Amends a Log with an exn. Handles nulls.
@@ -665,8 +655,7 @@ module Providers =
     // This has to be set from usercode for this to light up
     let mutable private microsoftLoggerFactory: ILoggerFactory option = None
 
-    let setMicrosoftLoggerFactory (factory: ILoggerFactory) =
-      microsoftLoggerFactory <- Option.ofObj factory
+    let setMicrosoftLoggerFactory (factory: ILoggerFactory) = microsoftLoggerFactory <- Option.ofObj factory
 
     let getLogFactoryType =
       lazy (Type.GetType("Microsoft.Extensions.Logging.ILoggerFactory, Microsoft.Extensions.Logging.Abstractions"))
@@ -1058,8 +1047,7 @@ module LogProvider =
   /// </summary>
   /// <param name="quotation">The quotation to generate a logger name from.</param>
   /// <returns></returns>
-  let getLoggerByQuotation (quotation: Quotations.Expr) =
-    getModuleType quotation |> getLoggerByType
+  let getLoggerByQuotation (quotation: Quotations.Expr) = getModuleType quotation |> getLoggerByType
 
 
 type LogProvider =
diff --git a/src/FsAutoComplete/CodeFixes/AddMissingXmlDocumentation.fs b/src/FsAutoComplete/CodeFixes/AddMissingXmlDocumentation.fs
index 7e5c38fa3..9412c68d8 100644
--- a/src/FsAutoComplete/CodeFixes/AddMissingXmlDocumentation.fs
+++ b/src/FsAutoComplete/CodeFixes/AddMissingXmlDocumentation.fs
@@ -58,8 +58,7 @@ let private tryGetCommentsAndSymbolPos input pos =
     input,
     { new SyntaxVisitorBase<_>() with
 
-        member _.VisitBinding(_, defaultTraverse, synBinding) =
-          handleSynBinding defaultTraverse synBinding
+        member _.VisitBinding(_, defaultTraverse, synBinding) = handleSynBinding defaultTraverse synBinding
 
         member _.VisitLetOrUse(_, _, defaultTraverse, bindings, _) =
           bindings |> List.tryPick (handleSynBinding defaultTraverse)
@@ -107,8 +106,7 @@ let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix =
 
       let parameterSection (name, _type) = $" <param name=\"%s{name}\"></param>"
 
-      let genericArg name =
-        $" <typeparam name=\"'%s{name}\"></typeparam>"
+      let genericArg name = $" <typeparam name=\"'%s{name}\"></typeparam>"
 
       let returnsSection = " <returns></returns>"
 
diff --git a/src/FsAutoComplete/CodeFixes/AdjustConstant.fs b/src/FsAutoComplete/CodeFixes/AdjustConstant.fs
new file mode 100644
index 000000000..d4778be7e
--- /dev/null
+++ b/src/FsAutoComplete/CodeFixes/AdjustConstant.fs
@@ -0,0 +1,1670 @@
+module FsAutoComplete.CodeFix.AdjustConstant
+
+open System
+open FsToolkit.ErrorHandling
+open FsAutoComplete.CodeFix.Types
+open Ionide.LanguageServerProtocol.Types
+open FsAutoComplete
+open FsAutoComplete.LspHelpers
+open FSharp.Compiler.Syntax
+open System.Runtime.CompilerServices
+open FSharp.Compiler.Text.Range
+open Microsoft.FSharp.Core.LanguagePrimitives
+
+/// If `true`: enable `debugFix`es which show parsed `XXXConstant`s.
+///
+/// Note: As constant, because F# doesn't have `#define`
+[<Literal>]
+let private DEBUG = false
+
+let inline private unreachable () = invalidOp "unreachable"
+
+/// Returns `SynConst` and its range at passed `pos`
+///
+/// Note:
+/// When `SynConst.Measure`:
+/// * returns contained constant when `pos` inside contained constant
+/// * otherwise `SynConst.Measure` when on other parts of `Measure` constant (`<km>`)
+///
+/// Note:
+/// Might be erroneous Constant -> containing `value` is then default (`0`).
+/// Check by comparing returned range with existing Diagnostics.
+let private tryFindConstant ast pos =
+  let rec findConst range constant =
+    match constant with
+    | SynConst.Measure(constant, constantRange, _) when rangeContainsPos constantRange pos ->
+      findConst constantRange constant
+    | _ -> (range, constant)
+
+  SyntaxTraversal.Traverse(
+    pos,
+    ast,
+    { new SyntaxVisitorBase<_>() with
+        member _.VisitExpr(_, _, defaultTraverse, expr) =
+          match expr with
+          //                                     without: matches when `pos` in comment after constant
+          | SynExpr.Const(constant, range) when rangeContainsPos range pos -> findConst range constant |> Some
+          | _ -> defaultTraverse expr
+
+        member _.VisitEnumDefn(_, cases, _) =
+          cases
+          |> List.tryPick (fun (SynEnumCase(valueExpr = expr)) ->
+            let rec tryFindConst (expr: SynExpr) =
+              match expr with
+              | SynExpr.Const(constant, range) when rangeContainsPos range pos -> findConst range constant |> Some
+              | SynExpr.Paren(expr = expr) -> tryFindConst expr
+              | SynExpr.App(funcExpr = funcExpr) when rangeContainsPos funcExpr.Range pos -> tryFindConst funcExpr
+              | SynExpr.App(argExpr = argExpr) when rangeContainsPos argExpr.Range pos -> tryFindConst argExpr
+              | _ -> None
+
+            tryFindConst expr)
+
+        member _.VisitPat(_, defaultTraverse, synPat) =
+          match synPat with
+          | SynPat.Const(constant, range) when rangeContainsPos range pos -> findConst range constant |> Some
+          | _ -> defaultTraverse synPat }
+  )
+
+/// Computes the absolute of `n`
+///
+/// Unlike `abs` or `Math.Abs` this here handles `MinValue` and does not throw `OverflowException`.
+type private Int =
+  static member inline abs(n: sbyte) : byte = if n >= 0y then byte n else byte (0y - n)
+
+  static member inline abs(n: int16) : uint16 = if n >= 0s then uint16 n else uint16 (0s - n)
+
+  static member inline abs(n: int32) : uint32 = if n >= 0l then uint32 n else uint32 (0l - n)
+
+  static member inline abs(n: int64) : uint64 =
+    if n >= 0L then
+      uint64 n
+    else
+      // unchecked subtraction -> wrapping/modular negation
+      // -> Negates all numbers -- with the exception of `Int64.MinValue`:
+      //        `0L - Int64.MinValue = Int64.MinValue`
+      //        BUT: converting `Int64.MinValue` to `UInt64` produces correct absolute of `Int64.MinValue`
+      uint64 (0L - n)
+
+  static member inline abs(n: nativeint) : unativeint = if n >= 0n then unativeint n else unativeint (0n - n)
+
+type private Offset = int
+
+/// Range inside a **single** line inside a source text.
+///
+/// Invariant: `Start.Line = End.Line` (-> `Range.inSingleLine`)
+type private RangeInLine = Range
+
+module private Range =
+  let inline inSingleLine (range: Range) = range.Start.Line = range.End.Line
+
+type private Range with
+
+  member inline range.Length = range.End.Character - range.Start.Character
+
+  member inline range.SpanIn(text: ReadOnlySpan<char>) =
+    assert (Range.inSingleLine range)
+    text.Slice(range.Start.Character, range.Length)
+
+/// Range inside some element list. Range is specified via Offsets inside that list.
+/// In Practice: Range inside `RangeInLine`
+///
+/// Similar to `System.Range` -- except it doesn't support indexing from the end.
+/// -> Some operations are easier to use (`Length` because it doesn't require length of container)
+///
+/// Unlike `LSP.Range`: just Offsets, not Positions (Line & Character)
+[<IsReadOnly; Struct>]
+[<StructuredFormatDisplay("{DisplayText}")>]
+type private ORange =
+  { Start: Offset
+    End: Offset }
+
+  member r.DisplayText = r.ToString()
+  override r.ToString() = $"{r.Start}..{r.End}"
+
+  member inline r.Length = r.End - r.Start
+  member inline r.IsEmpty = r.Start = r.End
+
+  member inline r.ToRangeFrom(pos: Position) : Range =
+    { Start =
+        { Line = pos.Line
+          Character = pos.Character + r.Start }
+      End =
+        { Line = pos.Line
+          Character = pos.Character + r.End } }
+
+  member inline r.ToRangeInside(range: Range) : Range =
+    assert (Range.inSingleLine range)
+    assert (r.Length <= range.Length)
+    r.ToRangeFrom(range.Start)
+
+  member inline r.ShiftBy(d: Offset) = { Start = r.Start + d; End = r.End + d }
+  /// Note: doesn't care about `Line`, only `Character`
+  member inline private r.ShiftToStartOf(pos: Position) : ORange = r.ShiftBy(pos.Character)
+
+  member inline private r.ShiftInside(range: Range) : ORange =
+    assert (Range.inSingleLine range)
+    assert (r.Length <= range.Length)
+    r.ShiftToStartOf(range.Start)
+
+  member inline r.SpanIn(str: String) = str.AsSpan(r.Start, r.Length)
+  member inline r.SpanIn(s: ReadOnlySpan<_>) = s.Slice(r.Start, r.Length)
+
+  member inline r.SpanIn(parent: Range, s: ReadOnlySpan<_>) = r.ShiftInside(parent).SpanIn(s)
+
+  member inline r.SpanIn(parent: Range, s: String) = r.ShiftInside(parent).SpanIn(s)
+
+  member inline r.EmptyAtStart = { Start = r.Start; End = r.Start }
+  member inline r.EmptyAtEnd = { Start = r.End; End = r.End }
+
+  /// Assumes: `range` is inside single line
+  static member inline CoverAllOf(range: Range) =
+    assert (Range.inSingleLine range)
+    { Start = 0; End = range.Length }
+
+  static member inline CoverAllOf(text: ReadOnlySpan<_>) = { Start = 0; End = text.Length }
+
+module private ORange =
+  /// Returns range that contains `range1` as well as `range2` with their extrema as border.
+  ///
+  /// Note: if there's a gap between `range1` and `range2` that gap is included in output range:
+  ///       `union (1..3) (7..9) = 1..9`
+  let inline union (range1: ORange) (range2: ORange) =
+    { Start = min range1.Start range2.Start
+      End = max range1.End range2.End }
+
+  /// Split `range` after `length` counting from the front.
+  ///
+  /// Example:
+  /// ```fsharp
+  /// let range = { Start = 0; End = 10 }
+  /// let (left, right) = range |> ORange.splitFront 4
+  /// assert(left = { Start = 0; End = 4 })
+  /// assert(right = { Start = 4; End = 10 })
+  /// ```
+  ///
+  /// Note: Tuple instead of `ValueTuple` (`struct`) for better inlining.
+  ///       Check when used: Tuple should not actually be created!
+  let inline splitFront length (range: ORange) =
+    ({ range with
+        End = range.Start + length },
+     { range with
+         Start = range.Start + length })
+
+  /// Split `range` after `length` counting from the back.
+  ///
+  /// Example:
+  /// ```fsharp
+  /// let range = { Start = 0; End = 10 }
+  /// let (left, right) = range |> ORange.splitAfter 4
+  /// assert(left = { Start = 0; End = 6 })
+  /// assert(right = { Start = 6; End = 10 })
+  /// ```
+  let inline splitBack length (range: ORange) =
+    ({ range with End = range.End - length },
+     { range with
+         Start = range.End - length })
+
+  /// Adjusts `Start` by `+ dStart`
+  let inline adjustStart dStart (range: ORange) =
+    { range with
+        Start = range.Start + dStart }
+
+  /// Adjusts `End` by `- dEnd`
+  let inline adjustEnd dEnd (range: ORange) = { range with End = range.End - dEnd }
+
+  /// Adjusts `Start` by `+ dStart` and `End` by `- dEnd`
+  let inline adjust (dStart, dEnd) (range: ORange) =
+    { Start = range.Start + dStart
+      End = range.End - dEnd }
+
+[<Extension>]
+type private Extensions() =
+  /// Returns `-1` if no matching element
+  [<Extension>]
+  static member inline TryFindIndex(span: ReadOnlySpan<_>, [<InlineIfLambda>] f) =
+    let mutable idx = -1
+    let mutable i = 0
+
+    while idx < 0 && i < span.Length do
+      if f (span[i]) then idx <- i else i <- i + 1
+
+    idx
+
+  [<Extension>]
+  static member inline Count(span: ReadOnlySpan<_>, [<InlineIfLambda>] f) =
+    let mutable count = 0
+
+    for c in span do
+      if f c then
+        count <- count + 1
+
+    count
+
+module private Parse =
+  /// Note: LHS does not include position with `f(char) = true`, but instead is first on RHS
+  let inline until (text: ReadOnlySpan<char>, range: ORange, [<InlineIfLambda>] f) =
+    let text = range.SpanIn text
+    let i = text.TryFindIndex(f)
+
+    if i < 0 then
+      range, range.EmptyAtEnd
+    else
+      range |> ORange.splitFront i
+
+  let inline while' (text: ReadOnlySpan<char>, range: ORange, [<InlineIfLambda>] f) =
+    until (text, range, (fun c -> not (f c)))
+
+  let inline if' (text: ReadOnlySpan<char>, range: ORange, [<InlineIfLambda>] f) =
+    let text = range.SpanIn text
+
+    if text.IsEmpty then range.EmptyAtStart, range
+    elif f text[0] then range |> ORange.splitFront 1
+    else range.EmptyAtStart, range
+
+/// Helper functions to splat tuples. With inlining: prevent tuple creation
+module private Tuple =
+  let inline splatR value (a, b) = (value, a, b)
+  let inline splatL (a, b) value = (a, b, value)
+
+module private Char =
+  let inline isDigitOrUnderscore c = Char.IsDigit c || c = '_'
+
+  let inline isHexDigitOrUnderscore c = isDigitOrUnderscore c || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
+
+  let inline isSingleQuote c = c = '\''
+
+[<RequireQualifiedAccess>]
+type CharFormat =
+  /// `ç`
+  | Char
+  /// `\231`
+  | Decimal
+  /// `\xE7`
+  | Hexadecimal
+  /// `\u00E7`
+  | Utf16Hexadecimal
+  /// `\U000000E7`
+  | Utf32Hexadecimal
+
+type private CharConstant =
+  {
+    Range: Range
+
+    Value: char
+    Format: CharFormat
+    Constant: SynConst
+    ValueRange: ORange
+
+    /// `B` suffix
+    /// Only when Byte
+    SuffixRange: ORange
+  }
+
+  member c.IsByte = not c.SuffixRange.IsEmpty
+
+module private CharConstant =
+  let inline isAsciiByte (text: ReadOnlySpan<char>) = text.EndsWith "'B"
+
+  /// `'a'`, `'\n'`, `'\231'`, `'\xE7'`, `'\u00E7'`, `'\U000000E7'`
+  ///
+  /// Can have `B` suffix (-> byte, otherwise normal char)
+  let parse (lineStr: ReadOnlySpan<char>, constRange: RangeInLine, constant: SynConst, value: char) =
+    let text = constRange.SpanIn(lineStr)
+    let range = ORange.CoverAllOf constRange
+
+    assert (text[0] = '\'')
+
+    let suffixLength =
+      if text.EndsWith "B" then
+        assert (text.EndsWith "'B")
+        1
+      else
+        assert (text.EndsWith "'")
+        0
+
+    let valueRange = ORange.adjust (1, 1 + suffixLength) range
+    let suffixRange = ORange.adjustStart (-suffixLength) range.EmptyAtEnd
+
+    let format =
+      let valueStr = valueRange.SpanIn(text)
+
+      if valueStr.Length > 2 && valueStr[0] = '\\' then
+        match valueStr[1] with
+        | 'x' -> CharFormat.Hexadecimal
+        | 'u' -> CharFormat.Utf16Hexadecimal
+        | 'U' -> CharFormat.Utf32Hexadecimal
+        | c when Char.IsDigit c -> CharFormat.Decimal
+        | _ -> CharFormat.Char
+      else
+        CharFormat.Char
+
+    { Range = constRange
+      Value = value
+      Format = format
+      Constant = constant
+      ValueRange = valueRange
+      SuffixRange = suffixRange }
+
+type private Sign =
+  | Negative
+  | Positive
+
+module private Sign =
+  /// Returns `Positive` in case of no sign
+  let inline parse (text: ReadOnlySpan<char>, range: ORange) =
+    let text = range.SpanIn text
+
+    if text.IsEmpty then
+      Positive, range.EmptyAtStart, range
+    elif text[0] = '-' then
+      Tuple.splatR Negative (range |> ORange.splitFront 1)
+    elif text[0] = '+' then
+      Tuple.splatR Positive (range |> ORange.splitFront 1)
+    else
+      Positive, range.EmptyAtStart, range
+
+[<RequireQualifiedAccess>]
+type Base =
+  /// No prefix
+  | Decimal
+  /// `0x`
+  | Hexadecimal
+  /// `0o`
+  | Octal
+  /// `0b`
+  | Binary
+
+module private Base =
+  /// Returns `Decimal` in case of no base
+  let inline parse (text: ReadOnlySpan<char>, range: ORange) =
+    let text = range.SpanIn(text)
+
+    if text.Length > 2 && text[0] = '0' then
+      match text[1] with
+      | 'x'
+      | 'X' -> Tuple.splatR Base.Hexadecimal (range |> ORange.splitFront 2)
+      | 'o'
+      | 'O' -> Tuple.splatR Base.Octal (range |> ORange.splitFront 2)
+      | 'b'
+      | 'B' -> Tuple.splatR Base.Binary (range |> ORange.splitFront 2)
+      | _ -> Base.Decimal, range.EmptyAtStart, range
+    else
+      Base.Decimal, range.EmptyAtStart, range
+
+/// Int Constant (without ASCII byte form)
+/// or Float Constant in Hex/Oct/Bin form
+/// or `UserNum` Constant (`bigint`) (always Dec form)
+///
+/// * optional sign: `+` `-`
+/// * optional base: `0` + [`x` `X` `o` `O` `b` `B`]
+/// * required digits
+///   * optional underscores inside
+/// * optional suffix
+type private IntConstant =
+  { Range: Range
+
+    Sign: Sign
+    SignRange: ORange
+
+    Base: Base
+    BaseRange: ORange
+
+    Constant: SynConst
+    ValueRange: ORange
+
+    SuffixRange: ORange }
+
+module private IntConstant =
+  /// Note: Does not handle ASCII byte. Check with `CharConstant.isAsciiByte` and then parse with `CharConstant.parse`
+  let parse (lineStr: ReadOnlySpan<char>, constRange: RangeInLine, constant: SynConst) =
+    let text = constRange.SpanIn(lineStr)
+    assert (not (CharConstant.isAsciiByte text))
+
+    let range = ORange.CoverAllOf(text)
+    let sign, signRange, range = Sign.parse (text, range)
+    let base', baseRange, range = Base.parse (text, range)
+
+    let valueRange, suffixRange =
+      Parse.while' (text, range, Char.isHexDigitOrUnderscore)
+
+    { Range = constRange
+      Sign = sign
+      SignRange = signRange
+      Base = base'
+      BaseRange = baseRange
+      Constant = constant
+      ValueRange = valueRange
+      SuffixRange = suffixRange }
+
+[<RequireQualifiedAccess>]
+type private FloatValue =
+  | Float of float
+  | Float32 of float32
+  | Decimal of decimal
+
+  static member from(f: float) = FloatValue.Float f
+  static member from(f: float32) = FloatValue.Float32 f
+  static member from(d: decimal) = FloatValue.Decimal d
+
+/// Float Constant (without Hex/Oct/Bin form -- just Decimal & Scientific)
+///
+/// Includes `float32`, `float`, `decimal`
+type private FloatConstant =
+  {
+    Range: Range
+
+    /// Note: Leading sign, not exponent sign
+    Sign: Sign
+    SignRange: ORange
+
+    Constant: SynConst
+    Value: FloatValue
+    /// Part before decimal separator (`.`)
+    ///
+    /// Note: Cannot be empty
+    IntRange: ORange
+    /// Part after decimal separator (`.`)
+    ///
+    /// Note: empty when no decimal
+    DecimalRange: ORange
+    /// Exponent Part without `e` or sign
+    ///
+    /// Note: empty when no exponent
+    ExponentRange: ORange
+
+    SuffixRange: ORange
+  }
+
+  member c.IsScientific = not c.ExponentRange.IsEmpty
+  member c.ValueRange = ORange.union c.IntRange c.ExponentRange
+
+module private FloatConstant =
+  let inline isIntFloat (text: ReadOnlySpan<char>) = text.EndsWith "lf" || text.EndsWith "LF"
+
+  /// Note: Does not handle Hex/Oct/Bin form (`lf` or `LF` suffix). Check with `FloatConstant.isIntFloat` and then parse with `IntConstant.parse`
+  let parse (lineStr: ReadOnlySpan<char>, constRange: RangeInLine, constant: SynConst, value: FloatValue) =
+    let text = constRange.SpanIn(lineStr)
+    assert (not (isIntFloat text))
+
+    let range = ORange.CoverAllOf(text)
+    let sign, signRange, range = Sign.parse (text, range)
+    let intRange, range = Parse.while' (text, range, Char.isDigitOrUnderscore)
+
+    let decimalRange, range =
+      let sepRange, range = Parse.if' (text, range, (fun c -> c = '.'))
+
+      if sepRange.IsEmpty then
+        range.EmptyAtStart, range
+      else
+        Parse.while' (text, range, Char.isDigitOrUnderscore)
+
+    let exponentRange, suffixRange =
+      let eRange, range = Parse.if' (text, range, (fun c -> c = 'e' || c = 'E'))
+
+      if eRange.IsEmpty then
+        range.EmptyAtStart, range
+      else
+        let _, _, range = Sign.parse (text, range)
+        Parse.while' (text, range, Char.isDigitOrUnderscore)
+
+    { Range = constRange
+      Sign = sign
+      SignRange = signRange
+      Constant = constant
+      Value = value
+      IntRange = intRange
+      DecimalRange = decimalRange
+      ExponentRange = exponentRange
+      SuffixRange = suffixRange }
+
+// Titles in extra modules (instead with their corresponding fix)
+// to exposed titles to Unit Tests while keeping fixes private.
+module Title =
+  let removeDigitSeparators = "Remove group separators"
+  let replaceWith = sprintf "Replace with `%s`"
+
+  module Int =
+    module Convert =
+      let toDecimal = "Convert to decimal"
+      let toHexadecimal = "Convert to hexadecimal"
+      let toOctal = "Convert to octal"
+      let toBinary = "Convert to binary"
+
+      module SpecialCase =
+        /// `0b1111_1101y = -3y = -0b0000_0011y`
+        let extractMinusFromNegativeConstant = "Extract `-` (constant is negative)"
+        /// `-0b0000_0011y = -3y = 0b1111_1101y`
+        let integrateExplicitMinus = "Integrate `-` into constant"
+
+        /// `-0b1111_1101y = -(-3y) = 3y = 0b0000_0011y`
+        let useImplicitPlusInPositiveConstantWithMinusSign =
+          "Use implicit `+` (constant is positive)"
+
+        /// `-0b1000_0000y = -(-128y) = -128y = 0b1000_0000y`
+        /// -> Negative values have one more value than positive ones! -> `-MinValue = MinValue`
+        let removeExplicitMinusWithMinValue = "Remove adverse `-` (`-MinValue = MinValue`)"
+
+    module Separate =
+      let decimal3 = "Separate thousands (3)"
+      let hexadecimal4 = "Separate words (4)"
+      let hexadecimal2 = "Separate bytes (2)"
+      let octal3 = "Separate digit groups (3)"
+      let binary4 = "Separate nibbles (4)"
+      let binary8 = "Separate bytes (8)"
+
+  module Float =
+    module Separate =
+      let all3 = "Separate digit groups (3)"
+
+  module Char =
+    module Convert =
+      let toChar = sprintf "Convert to `%s`"
+      let toDecimal = sprintf "Convert to `%s`"
+      let toHexadecimal = sprintf "Convert to `%s`"
+      let toUtf16Hexadecimal = sprintf "Convert to `%s`"
+      let toUtf32Hexadecimal = sprintf "Convert to `%s`"
+
+let inline private mkFix doc title edits =
+  { Title = title
+    File = doc
+    Edits = edits
+    Kind = FixKind.Refactor
+    SourceDiagnostic = None }
+
+
+module private DigitGroup =
+  let removeFix (doc: TextDocumentIdentifier) (lineStr: String) (constantRange: Range) (localRange: ORange) =
+    let text = localRange.SpanIn(constantRange, lineStr)
+
+    if text.Contains '_' then
+      let replacement = text.ToString().Replace("_", "")
+
+      mkFix
+        doc
+        Title.removeDigitSeparators
+        [| { Range = localRange.ToRangeInside constantRange
+             NewText = replacement } |]
+      |> List.singleton
+    else
+      []
+
+  type Direction =
+    /// thousands -> left of `.`
+    | RightToLeft
+    /// thousandth -> right of `.`
+    | LeftToRight
+
+  let addSeparator (n: String) (groupSize: int) (dir: Direction) =
+    let mutable res = n.ToString()
+
+    match dir with
+    | RightToLeft ->
+      // counting in reverse (from last to first)
+      // starting at `1` and not `0`: never insert in last position
+      for i in 1 .. (n.Length - 1) do
+        if i % groupSize = 0 then
+          res <- res.Insert(n.Length - i, "_")
+    | LeftToRight ->
+      // grouping from first to last
+      // but insert must happen last to first (because insert at index)
+      for i = (n.Length - 1) downto 1 do
+        if i % groupSize = 0 then
+          res <- res.Insert(i, "_")
+
+    res
+
+module private Format =
+  module Char =
+    /// Returns `None` for "invisible" chars (`Char.IsControl`)
+    /// -- with the exception of some chars that can be represented via escape sequence
+    ///
+    /// See: [F# Reference](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/strings#remarks)
+    let tryAsChar (c: char) =
+      match c with
+      | '\a' -> Some "\\a"
+      | '\b' -> Some "\\b"
+      | '\f' -> Some "\\f"
+      | '\n' -> Some "\\n"
+      | '\r' -> Some "\\r"
+      | '\t' -> Some "\\t"
+      | '\v' -> Some "\\v"
+      | '\\' -> Some "\\"
+      // Note: double quotation marks can be escaped -- but don't have to be.
+      //       We're emitting unescaped quotations: `'"'` and not `'\"'`
+      | '\"' -> Some "\""
+      | '\'' -> Some "\\\'"
+      | _ when Char.IsControl c -> None
+      | c -> Some(string c)
+
+    let inline asChar (c: char) = tryAsChar c |> Option.defaultValue (string c)
+
+    let inline asDecimal (c: char) = $"\\%03i{uint16 c}"
+    let inline asHexadecimal (c: char) = $"\\x%02X{uint16 c}"
+    let inline asUtf16Hexadecimal (c: char) = $"\\u%04X{uint16 c}"
+    let inline asUtf32Hexadecimal (c: char) = $"\\U%08X{uint c}"
+
+  module Int =
+    let inline asDecimalUnsigned n = $"%u{n}"
+    let inline asDecimalSigned n = $"%i{n}"
+    /// Unsigned: no explicit `-` sign,
+    ///           but sign gets directly encoding in hex representation (1st bit)
+    let inline asHexadecimalUnsigned n = $"0x%X{n}"
+
+    /// Signed: explicit `-` sign when negative and sign bit `0`
+    ///         -> when negative: `-abs(n)`
+    let inline asHexadecimalSigned (n, abs) =
+      if n >= GenericZero then
+        asHexadecimalUnsigned n
+      else
+        let absValue = abs n
+        $"-0x%X{absValue}"
+
+    let inline asOctalUnsigned n = $"0o%o{n}"
+
+    let inline asOctalSigned (n, abs) =
+      if n >= GenericZero then
+        asHexadecimalUnsigned n
+      else
+        let absValue = abs n
+        $"-0o%o{absValue}"
+
+    let inline asBinaryUnsigned n = $"0b%B{n}"
+
+    let inline asBinarySigned (n, abs) =
+      if n >= GenericZero then
+        asBinaryUnsigned n
+      else
+        let absValue = abs n
+        $"-0b%B{absValue}"
+
+module private CommonFixes =
+  open FSharp.Compiler.Symbols
+
+  /// Adding a sign might lead to invalid code:
+  /// ```fsharp
+  /// let value = 5y+0b1010_0101y
+  ///
+  /// // => Convert to decimal
+  ///
+  /// // without space:
+  /// let value = 5y+-91y
+  /// //            ^^
+  /// //            The type 'sbyte' does not support the operator '+-'
+  ///
+  /// // with space:
+  /// let value = 5y+ -91y
+  /// ```
+  ///
+  /// -> Prepend space if leading sign in `replacement` and operator char immediately in front (in `lineStr`)
+  let prependSpaceIfNecessary (range: Range) (lineStr: string) (replacement: string) =
+    if
+      (replacement.StartsWith "-" || replacement.StartsWith "+")
+      && range.Start.Character > 0
+      && "!$%&*+-./<=>?@^|~".Contains(lineStr[range.Start.Character - 1])
+    then
+      " " + replacement
+    else
+      replacement
+
+  /// Returns:
+  /// * `None`: unhandled `SynConst`
+  /// * `Some`:
+  ///   * Simple Name of Constant Type: `SynConst.Double _` -> `Double`
+  ///   * `FSharpType` matching `constant` type
+  ///     * Note: `None` if cannot find corresponding Entity/Type. Most likely an error inside this function!
+  let tryGetFSharpType (parseAndCheck: ParseAndCheckResults) (constant: SynConst) =
+    option {
+      //Enhancement: cache? Must be by project. How to detect changes?
+
+      let! name =
+        match constant with
+        | SynConst.Bool _ -> Some <| nameof (System.Boolean)
+        | SynConst.Char _ -> Some <| nameof (System.Char)
+        | SynConst.Byte _ -> Some <| nameof (System.Byte)
+        | SynConst.SByte _ -> Some <| nameof (System.SByte)
+        | SynConst.Int16 _ -> Some <| nameof (System.Int16)
+        | SynConst.UInt16 _ -> Some <| nameof (System.UInt16)
+        | SynConst.Int32 _ -> Some <| nameof (System.Int32)
+        | SynConst.UInt32 _ -> Some <| nameof (System.UInt32)
+        | SynConst.Int64 _ -> Some <| nameof (System.Int64)
+        | SynConst.UInt64 _ -> Some <| nameof (System.UInt64)
+        | SynConst.IntPtr _ -> Some <| nameof (System.IntPtr)
+        | SynConst.UIntPtr _ -> Some <| nameof (System.UIntPtr)
+        | SynConst.Single _ -> Some <| nameof (System.Single)
+        | SynConst.Double _ -> Some <| nameof (System.Double)
+        | SynConst.Decimal _ -> Some <| nameof (System.Decimal)
+        | _ -> None
+
+      let isSystemAssembly (assembly: FSharpAssembly) =
+        match assembly.SimpleName with
+        // dotnet core
+        | "System.Runtime"
+        // .net framework
+        | "mscorlib"
+        // .net standard
+        | "netstandard" -> true
+        | _ -> false
+
+      let assemblies =
+        parseAndCheck.GetCheckResults.ProjectContext.GetReferencedAssemblies()
+
+      let ty =
+        assemblies
+        |> Seq.filter (isSystemAssembly)
+        |> Seq.tryPick (fun system -> system.Contents.FindEntityByPath [ "System"; name ])
+        |> Option.map (fun ent -> ent.AsType())
+
+      // Note: `ty` should never be `None`: we're only looking up standard dotnet types -- which should always be available.
+      //       But `isSystemAssembly` might not handle all possible assemblies with default types -> keep it safe and return `option`
+
+      return (name, ty)
+    }
+
+  /// Fix that replaces `constantRange` with `propertyName` on type of `constant`.
+  ///
+  /// Example:
+  /// `constant = SynConst.Double _` and `fieldName = "MinValue"`
+  /// -> replaces `constantRange` with `Double.MinValue`
+  ///
+  /// Tries to detect if leading `System.` is necessary (`System` is not `open`).
+  /// If cannot detect: Puts `System.` in front
+  let replaceWithNamedConstantFix
+    doc
+    (pos: FcsPos)
+    (lineStr: String)
+    (parseAndCheck: ParseAndCheckResults)
+    (constant: SynConst)
+    (constantRange: Range)
+    (fieldName: string)
+    (mkTitle: string -> string)
+    =
+    option {
+      let! (tyName, ty) = tryGetFSharpType parseAndCheck constant
+
+      let propCall =
+        ty
+        |> Option.bind (fun ty ->
+          parseAndCheck.GetCheckResults.GetDisplayContextForPos pos
+          |> Option.map (fun displayContext -> $"{ty.Format displayContext}.{fieldName}"))
+        |> Option.defaultWith (fun _ -> $"System.{tyName}.{fieldName}")
+
+      let title = mkTitle $"{tyName}.{fieldName}"
+
+      let edits =
+        [| { Range = constantRange
+             NewText = propCall } |]
+
+      return mkFix doc title edits |> List.singleton
+    }
+    |> Option.defaultValue []
+
+
+  /// Replaces float with `infinity` etc.
+  let replaceFloatWithNameFix
+    doc
+    (pos: FcsPos)
+    (lineStr: String)
+    (parseAndCheck: ParseAndCheckResults)
+    (constant: SynConst)
+    (constantRange: Range)
+    (constantValue: FloatValue)
+    =
+    let mkFix value =
+      let title = Title.replaceWith value
+      let replacement = prependSpaceIfNecessary constantRange lineStr value
+
+      let edits =
+        [| { Range = constantRange
+             NewText = replacement } |]
+
+      mkFix doc title edits |> List.singleton
+
+    match constantValue with
+    | FloatValue.Float value ->
+      if Double.IsPositiveInfinity value then
+        mkFix "infinity"
+      elif Double.IsNegativeInfinity value then
+        mkFix "-infinity"
+      elif Double.IsNaN value then
+        mkFix "nan"
+      elif value = System.Double.MaxValue then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Double.MaxValue))
+          Title.replaceWith
+      elif value = System.Double.MinValue then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Double.MinValue))
+          Title.replaceWith
+      elif value = System.Double.Epsilon then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Double.Epsilon))
+          Title.replaceWith
+      else
+        []
+    | FloatValue.Float32 value ->
+      if Single.IsPositiveInfinity value then
+        mkFix "infinityf"
+      elif Single.IsNegativeInfinity value then
+        mkFix "-infinityf"
+      elif Single.IsNaN value then
+        mkFix "nanf"
+      elif value = System.Single.MaxValue then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Single.MaxValue))
+          Title.replaceWith
+      elif value = System.Single.MinValue then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Single.MinValue))
+          Title.replaceWith
+      elif value = System.Single.Epsilon then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Single.Epsilon))
+          Title.replaceWith
+      else
+        []
+    | FloatValue.Decimal value ->
+      if value = System.Decimal.MaxValue then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Decimal.MaxValue))
+          Title.replaceWith
+      elif value = System.Decimal.MinValue then
+        replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant
+          constantRange
+          (nameof (Decimal.MinValue))
+          Title.replaceWith
+      else
+        []
+
+module private CharFix =
+  let private debugFix doc (lineStr: String) (constant: CharConstant) =
+    let data =
+      let full = constant.Range.SpanIn(lineStr).ToString()
+      let value = constant.ValueRange.SpanIn(full).ToString()
+      let suffix = constant.SuffixRange.SpanIn(full).ToString()
+
+      let c =
+        constant.Value
+        |> Format.Char.tryAsChar
+        |> Option.defaultWith (fun _ -> Format.Char.asUtf16Hexadecimal constant.Value)
+
+      $"%A{value} (%A{constant.Format}, %A{c}) %A{suffix} (%A{full}, %A{constant})"
+
+    mkFix doc data [||]
+
+  let convertToOtherFormatFixes doc (lineStr: String) (constant: CharConstant) =
+    [ let mkFix' title replacement =
+        let edits =
+          [| { Range = constant.ValueRange.ToRangeInside constant.Range
+               NewText = replacement } |]
+
+        mkFix doc title edits
+
+      if constant.Format <> CharFormat.Char then
+        match Format.Char.tryAsChar constant.Value with
+        | None -> () // Don't convert to "invisible" char
+        | Some value -> mkFix' (Title.Char.Convert.toChar value) value
+      // `\x` & `\U` currently not supported for byte char
+      // TODO: allow byte once support was added
+      if constant.Format <> CharFormat.Decimal && int constant.Value <= 255 then
+        let value = Format.Char.asDecimal constant.Value
+        mkFix' (Title.Char.Convert.toDecimal value) value
+
+      if
+        not constant.IsByte
+        && constant.Format <> CharFormat.Hexadecimal
+        && int constant.Value <= 0xFF
+      then
+        let value = Format.Char.asHexadecimal constant.Value
+        mkFix' (Title.Char.Convert.toHexadecimal value) value
+
+      if constant.Format <> CharFormat.Utf16Hexadecimal then
+        let value = Format.Char.asUtf16Hexadecimal constant.Value
+        mkFix' (Title.Char.Convert.toUtf16Hexadecimal value) value
+
+      if not constant.IsByte && constant.Format <> CharFormat.Utf32Hexadecimal then
+        let value = Format.Char.asUtf32Hexadecimal constant.Value
+        mkFix' (Title.Char.Convert.toUtf32Hexadecimal value) value
+
+      if constant.IsByte then
+        // convert to int representation
+        let mkFix' title replacement =
+          let edits =
+            [| { Range = constant.Range
+                 NewText = replacement + "uy" } |]
+
+          mkFix doc title edits
+
+        let value = byte constant.Value
+        mkFix' Title.Int.Convert.toDecimal (Format.Int.asDecimalUnsigned value)
+        mkFix' Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned value)
+        mkFix' Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned value)
+        mkFix' Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned value) ]
+
+  let all doc (lineStr: String) (error: bool) (constant: CharConstant) =
+    [ if not error then
+        yield! convertToOtherFormatFixes doc lineStr constant
+
+      if DEBUG then
+        debugFix doc lineStr constant ]
+
+module private IntFix =
+  let private debugFix doc (lineStr: String) (constant: IntConstant) =
+    let data =
+      let full = constant.Range.SpanIn(lineStr).ToString()
+
+      let value = constant.ValueRange.SpanIn(full).ToString()
+      let suffix = constant.SuffixRange.SpanIn(full).ToString()
+      $"%A{constant.Sign} %A{constant.Base} %A{value} %A{suffix} (%A{constant.Constant}) (%A{full}, %A{constant})"
+
+    mkFix doc data [||]
+
+  let convertToOtherBaseFixes doc (lineStr: string) (constant: IntConstant) =
+    let mkFixKeepExistingSign title replacement =
+      let range = ORange.union constant.BaseRange constant.ValueRange
+
+      let edits =
+        [| { Range = range.ToRangeInside constant.Range
+             NewText = replacement } |]
+
+      mkFix doc title edits
+
+    let mkFixReplaceExistingSign title (replacement: string) =
+      let localRange = ORange.union constant.SignRange constant.ValueRange
+      let range = localRange.ToRangeInside constant.Range
+      let replacement = CommonFixes.prependSpaceIfNecessary range lineStr replacement
+      let edits = [| { Range = range; NewText = replacement } |]
+      mkFix doc title edits
+
+    let inline mkIntFixes (value: 'int, abs: 'int -> 'uint, minValue: 'int) =
+      [ if constant.Base = Base.Decimal then
+          // easy case: no special cases: `-` is always explicit, value always matches explicit sign
+          // -> just convert absolute value and keep existing sign
+
+          // but obviously there are no easy cases...:
+          // special case: MinValue: `-128y = -0b1000_000y = 0b1000_0000y`
+          //    -> technical `-0b1000_0000y` is correct -- but misleading (`-` AND negative bit) -> remove `-`
+          if value = minValue then
+            mkFixReplaceExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned value)
+            mkFixReplaceExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned value)
+            mkFixReplaceExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned value)
+          else
+            let absValue = abs value
+            mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned absValue)
+            mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned absValue)
+            mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned absValue)
+
+        elif value = GenericZero || (value > GenericZero && constant.Sign = Positive) then
+          // easy case: implicit or explicit `+` sign matches value
+          // -> just convert absolute value and keep existing sign
+          // additional special case handled here: keep `-` for exactly `0`
+          let absValue =
+            assert (value >= GenericZero)
+            value
+
+          if
+            (assert (constant.Base <> Base.Decimal)
+             true)
+          then
+            mkFixKeepExistingSign Title.Int.Convert.toDecimal (Format.Int.asDecimalUnsigned absValue)
+
+          if constant.Base <> Base.Hexadecimal then
+            mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned absValue)
+
+          if constant.Base <> Base.Octal then
+            mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned absValue)
+
+          if constant.Base <> Base.Binary then
+            mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned absValue)
+
+        elif value > GenericZero && constant.Sign = Negative then
+          // explicit `-`, but value is Positive
+          // -> first sign bit is set (-> negative) and then negated with explicit `-`
+          // Example: `-0b1000_0001y = -(-127y) = 127y`
+          //
+          // Quick Fixes:
+          // * Adjust number in same base to use implicit `+`
+          // * Change to decimal while remove explicit `-` (Decimal MUST match sign)
+          // * Change to other bases while keeping explicit `-` (-> keep bits intact)
+
+          if true then // `if` for grouping. Gets removed by compiler.
+            let title =
+              Title.Int.Convert.SpecialCase.useImplicitPlusInPositiveConstantWithMinusSign
+
+            let absValue =
+              assert (value >= GenericZero)
+              value
+
+            let replacement =
+              match constant.Base with
+              | Base.Decimal -> unreachable ()
+              | Base.Hexadecimal -> Format.Int.asHexadecimalUnsigned absValue
+              | Base.Octal -> Format.Int.asOctalUnsigned absValue
+              | Base.Binary -> Format.Int.asBinaryUnsigned absValue
+
+            mkFixReplaceExistingSign title replacement
+
+          if
+            (assert (constant.Base <> Base.Decimal)
+             true)
+          then
+            let absValue =
+              assert (value >= GenericZero)
+              value
+
+            mkFixReplaceExistingSign Title.Int.Convert.toDecimal (Format.Int.asDecimalUnsigned absValue)
+
+          // keep `-` sign -> value after base-prefix must be negative
+          let negativeValue = -value
+
+          if constant.Base <> Base.Hexadecimal then
+            mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned negativeValue)
+
+          if constant.Base <> Base.Octal then
+            mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned negativeValue)
+
+          if constant.Base <> Base.Binary then
+            mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned negativeValue)
+
+        elif value = minValue then
+          // special case: `MinValue`: there's no corresponding `abs` in same type:
+          //               There's no `128y` matching `MinValue = -128y`
+
+          // Note: we already handled `0` above
+          //       -> if we're here we KNOW `value` & `minValue` MUST be signed and cannot be unsigned!
+          assert (minValue <> GenericZero)
+
+          if constant.Sign = Negative then
+            // `-0b1000_0000y = -(-128y) = `-128y`
+            // Note: Because no `+128y` and not decimal, we KNOW sign is not necessary
+            let title = Title.Int.Convert.SpecialCase.removeExplicitMinusWithMinValue
+
+            mkFix
+              doc
+              title
+              [| { Range = constant.SignRange.ToRangeInside constant.Range
+                   NewText = "" } |]
+
+          if
+            (assert (constant.Base <> Base.Decimal)
+             true)
+          then
+            mkFixReplaceExistingSign Title.Int.Convert.toDecimal (Format.Int.asDecimalSigned value)
+
+          if constant.Base <> Base.Hexadecimal then
+            mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned value)
+
+          if constant.Base <> Base.Octal then
+            mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned value)
+
+          if constant.Base <> Base.Binary then
+            mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned value)
+
+        elif value < GenericZero && constant.Sign = Positive then
+          if true then
+            let title = Title.Int.Convert.SpecialCase.extractMinusFromNegativeConstant
+
+            let replacement =
+              match constant.Base with
+              | Base.Decimal -> unreachable ()
+              | Base.Hexadecimal -> Format.Int.asHexadecimalSigned (value, abs)
+              | Base.Octal -> Format.Int.asOctalSigned (value, abs)
+              | Base.Binary -> Format.Int.asBinarySigned (value, abs)
+
+            mkFixReplaceExistingSign title replacement
+
+          if
+            (assert (constant.Base <> Base.Decimal)
+             true)
+          then
+            mkFixReplaceExistingSign Title.Int.Convert.toDecimal (Format.Int.asDecimalSigned value)
+
+          // keep bits intact -> don't add any `-`
+          if constant.Base <> Base.Hexadecimal then
+            mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned value)
+
+          if constant.Base <> Base.Octal then
+            mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned value)
+
+          if constant.Base <> Base.Binary then
+            mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned value)
+
+        elif value < GenericZero then
+          assert (constant.Sign = Negative)
+
+          if true then
+            let title = Title.Int.Convert.SpecialCase.integrateExplicitMinus
+
+            let replacement =
+              match constant.Base with
+              | Base.Decimal -> unreachable ()
+              | Base.Hexadecimal -> Format.Int.asHexadecimalUnsigned value
+              | Base.Octal -> Format.Int.asOctalUnsigned value
+              | Base.Binary -> Format.Int.asBinaryUnsigned value
+
+            mkFixReplaceExistingSign title replacement
+
+          // keep `-` intact
+          let absValue = abs value
+
+          if
+            (assert (constant.Base <> Base.Decimal)
+             true)
+          then
+            mkFixKeepExistingSign Title.Int.Convert.toDecimal (Format.Int.asDecimalUnsigned absValue)
+
+          if constant.Base <> Base.Hexadecimal then
+            mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned absValue)
+
+          if constant.Base <> Base.Octal then
+            mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned absValue)
+
+          if constant.Base <> Base.Binary then
+            mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned absValue)
+
+        else
+          // unreachable()
+          () ]
+
+    let inline mkUIntFixes (value: 'uint) =
+      [ if constant.Base <> Base.Decimal then
+          mkFixKeepExistingSign Title.Int.Convert.toDecimal (Format.Int.asDecimalUnsigned value)
+        if constant.Base <> Base.Hexadecimal then
+          mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned value)
+        if constant.Base <> Base.Octal then
+          mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned value)
+        if constant.Base <> Base.Binary then
+          mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned value) ]
+
+    let mkByteFixes (value: byte) =
+      [ yield! mkUIntFixes value
+
+        // convert to char (`'a'B`)
+        if value < 128uy then
+          let inline asByteChar charValue = $"'{charValue}'B"
+
+          let mkFix title replacement =
+            let edits =
+              [| { Range = constant.Range
+                   NewText = replacement } |]
+
+            mkFix doc title edits
+
+          let byteChar = char value
+
+          match Format.Char.tryAsChar byteChar with
+          | None -> ()
+          | Some value ->
+            let value = value |> asByteChar
+            mkFix (Title.Char.Convert.toChar value) value
+
+          let value = Format.Char.asDecimal byteChar |> asByteChar
+          mkFix (Title.Char.Convert.toDecimal value) value
+          // Currently not supported by F#
+          // let value = Format.Char.asHexadecimal byteChar |> asByteChar
+          // mkFix (Title.Char.Convert.toHexadecimal value) value
+          let value = Format.Char.asUtf16Hexadecimal byteChar |> asByteChar
+          mkFix (Title.Char.Convert.toUtf16Hexadecimal value) value
+        // Currently not supported by F#
+        // let value = Format.Char.asUtf32Hexadecimal byteChar |> asByteChar
+        // mkFix (Title.Char.Convert.toUtf32Hexadecimal value) value
+        ]
+
+    let inline mkFloatFixes (value: 'float, getBits: 'float -> 'uint) =
+      [ assert (constant.Base <> Base.Decimal)
+
+        // value without explicit sign
+        let specified = if constant.Sign = Negative then -value else value
+
+        if constant.Base <> Base.Hexadecimal then
+          mkFixKeepExistingSign Title.Int.Convert.toHexadecimal (Format.Int.asHexadecimalUnsigned (getBits specified))
+
+        if constant.Base <> Base.Octal then
+          mkFixKeepExistingSign Title.Int.Convert.toOctal (Format.Int.asOctalUnsigned (getBits specified))
+
+        if constant.Base <> Base.Binary then
+          mkFixKeepExistingSign Title.Int.Convert.toBinary (Format.Int.asBinaryUnsigned (getBits specified))
+
+        // `0b1...lf`
+        if value < GenericZero && constant.Sign = Positive then
+          let title = Title.Int.Convert.SpecialCase.extractMinusFromNegativeConstant
+          let posValue = abs value
+          assert (posValue >= GenericZero)
+
+          let replacement =
+            match constant.Base with
+            | Base.Decimal -> unreachable ()
+            | Base.Hexadecimal -> Format.Int.asHexadecimalUnsigned (getBits posValue)
+            | Base.Octal -> Format.Int.asOctalUnsigned (getBits posValue)
+            | Base.Binary -> Format.Int.asBinaryUnsigned (getBits posValue)
+
+          mkFixReplaceExistingSign title ("-" + replacement)
+        // `-0b0....lf`
+        elif value < GenericZero && constant.Sign = Negative then
+          let title = Title.Int.Convert.SpecialCase.integrateExplicitMinus
+
+          let replacement =
+            match constant.Base with
+            | Base.Decimal -> unreachable ()
+            | Base.Hexadecimal -> Format.Int.asHexadecimalUnsigned (getBits value)
+            | Base.Octal -> Format.Int.asOctalUnsigned (getBits value)
+            | Base.Binary -> Format.Int.asBinaryUnsigned (getBits value)
+
+          mkFixReplaceExistingSign title replacement
+        // `-0b1...lf`
+        elif value > GenericZero && constant.Sign = Negative then
+          let title =
+            Title.Int.Convert.SpecialCase.useImplicitPlusInPositiveConstantWithMinusSign
+
+          let replacement =
+            match constant.Base with
+            | Base.Decimal -> unreachable ()
+            | Base.Hexadecimal -> Format.Int.asHexadecimalUnsigned (getBits value)
+            | Base.Octal -> Format.Int.asOctalUnsigned (getBits value)
+            | Base.Binary -> Format.Int.asBinaryUnsigned (getBits value)
+
+          mkFixReplaceExistingSign title replacement ]
+
+    match constant.Constant with
+    | SynConst.SByte value -> mkIntFixes (value, Int.abs, SByte.MinValue)
+    | SynConst.Byte value -> mkByteFixes value
+    | SynConst.Int16 value -> mkIntFixes (value, Int.abs, Int16.MinValue)
+    | SynConst.UInt16 value -> mkUIntFixes value
+    | SynConst.Int32 value -> mkIntFixes (value, Int.abs, Int32.MinValue)
+    | SynConst.UInt32 value -> mkUIntFixes value
+    | SynConst.Int64 value -> mkIntFixes (value, Int.abs, Int64.MinValue)
+    | SynConst.UInt64 value -> mkUIntFixes value
+    | SynConst.IntPtr value -> mkIntFixes (value, Int.abs, Int64.MinValue)
+    | SynConst.UIntPtr value -> mkUIntFixes value
+
+    | SynConst.Single value -> mkFloatFixes (value, BitConverter.SingleToUInt32Bits)
+    | SynConst.Double value -> mkFloatFixes (value, BitConverter.DoubleToUInt64Bits)
+
+    | _ -> []
+
+
+  let padBinaryWithZerosFixes doc (lineStr: String) (constant: IntConstant) =
+    match constant.Base with
+    | Base.Binary ->
+      let bits =
+        match constant.Constant with
+        | SynConst.Byte _ -> 8
+        | SynConst.SByte _ -> 8
+        | SynConst.Int16 _ -> 16
+        | SynConst.UInt16 _ -> 16
+        | SynConst.Int32 _ -> 32
+        | SynConst.UInt32 _ -> 32
+        | SynConst.Int64 _ -> 64
+        | SynConst.UInt64 _ -> 64
+        | SynConst.IntPtr _ -> 64
+        | SynConst.UIntPtr _ -> 64
+        | _ -> -1
+
+      if bits > 0 then
+        let digits = constant.ValueRange.SpanIn(constant.Range, lineStr)
+        let nDigits = digits.Count(fun c -> c <> '_')
+
+        let padTo (length: int) =
+          if nDigits < length && length <= bits then
+            let toAdd = length - nDigits
+            let zeros = String('0', toAdd)
+
+            let edits =
+              [| { Range = constant.ValueRange.EmptyAtStart.ToRangeInside(constant.Range)
+                   NewText = zeros } |]
+
+            mkFix doc $"Pad with `0`s to `{length}` bits" edits |> Some
+          else
+            None
+
+        // pad to 4,8,16 bits
+        [ 4; 8; 16 ] |> List.choose padTo
+      else
+        []
+    | _ -> []
+
+  /// Separates digit groups with `_`.
+  let separateDigitGroupsFix doc (lineStr: String) (constant: IntConstant) =
+    let n = constant.ValueRange.SpanIn(constant.Range, lineStr)
+
+    if n.Contains '_' then
+      // don't change existing groups
+      []
+    else
+      let n = n.ToString()
+
+      let tryMkFix title groupSize =
+        if n.Length > groupSize then
+          [| { Range = constant.ValueRange.ToRangeInside(constant.Range)
+               NewText = DigitGroup.addSeparator n groupSize DigitGroup.RightToLeft } |]
+          |> mkFix doc title
+          |> List.singleton
+        else
+          List.empty
+
+      match constant.Base with
+      | Base.Decimal -> [ yield! tryMkFix Title.Int.Separate.decimal3 3 ]
+      | Base.Hexadecimal ->
+        [ yield! tryMkFix Title.Int.Separate.hexadecimal4 4
+          yield! tryMkFix Title.Int.Separate.hexadecimal2 2 ]
+      | Base.Octal -> [ yield! tryMkFix Title.Int.Separate.octal3 3 ]
+      | Base.Binary ->
+        [ yield! tryMkFix Title.Int.Separate.binary4 4
+          yield! tryMkFix Title.Int.Separate.binary8 8 ]
+
+  /// Removes or adds digit group separators (`_`)
+  let digitGroupFixes doc (lineStr: String) (constant: IntConstant) =
+    match DigitGroup.removeFix doc lineStr constant.Range constant.ValueRange with
+    | [] -> separateDigitGroupsFix doc lineStr constant
+    | fix -> fix
+
+  let private replaceIntWithNameFix
+    doc
+    (pos: FcsPos)
+    (lineStr: String)
+    (parseAndCheck: ParseAndCheckResults)
+    (constant: IntConstant)
+    =
+    // Cannot use following because `Min/MaxValue` are Fields, not Properties (`get_Min/MaxValue`)
+    // let inline private isMax<'int when 'int : equality and 'int:(static member MaxValue: 'int)> value =
+    //   value = 'int.MaxValue
+    // let inline private isMin<'int when 'int : equality and 'int:(static member MinValue: 'int)> value =
+    //   value = 'int.MinValue
+    let inline replaceWithExtremum value minValue maxValue =
+      if value = maxValue then
+        CommonFixes.replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant.Constant
+          constant.Range
+          "MaxValue"
+          Title.replaceWith
+      //                   don't replace uint `0`
+      elif value = minValue && value <> GenericZero then
+        CommonFixes.replaceWithNamedConstantFix
+          doc
+          pos
+          lineStr
+          parseAndCheck
+          constant.Constant
+          constant.Range
+          "MinValue"
+          Title.replaceWith
+      else
+        []
+
+    match constant.Constant with
+    | SynConst.SByte value -> replaceWithExtremum value SByte.MinValue SByte.MaxValue
+    | SynConst.Byte value -> replaceWithExtremum value Byte.MinValue Byte.MaxValue
+    | SynConst.Int16 value -> replaceWithExtremum value Int16.MinValue Int16.MaxValue
+    | SynConst.UInt16 value -> replaceWithExtremum value UInt16.MinValue UInt16.MaxValue
+    | SynConst.Int32 value -> replaceWithExtremum value Int32.MinValue Int32.MaxValue
+    | SynConst.UInt32 value -> replaceWithExtremum value UInt32.MinValue UInt32.MaxValue
+    | SynConst.Int64 value -> replaceWithExtremum value Int64.MinValue Int64.MaxValue
+    | SynConst.UInt64 value -> replaceWithExtremum value UInt64.MinValue UInt64.MaxValue
+    | SynConst.IntPtr value -> replaceWithExtremum value Int64.MinValue Int64.MaxValue
+    | SynConst.UIntPtr value -> replaceWithExtremum value UInt64.MinValue UInt64.MaxValue
+
+    | SynConst.Single value ->
+      CommonFixes.replaceFloatWithNameFix
+        doc
+        pos
+        lineStr
+        parseAndCheck
+        constant.Constant
+        constant.Range
+        (FloatValue.from value)
+    | SynConst.Double value ->
+      CommonFixes.replaceFloatWithNameFix
+        doc
+        pos
+        lineStr
+        parseAndCheck
+        constant.Constant
+        constant.Range
+        (FloatValue.from value)
+    | SynConst.Decimal value -> replaceWithExtremum value Decimal.MinValue Decimal.MaxValue
+
+    | _ -> []
+
+  let all
+    doc
+    (pos: FcsPos)
+    (lineStr: String)
+    (parseAndCheck: ParseAndCheckResults)
+    (error: bool)
+    (constant: IntConstant)
+    =
+    [ if not error then
+        yield! convertToOtherBaseFixes doc lineStr constant
+        yield! replaceIntWithNameFix doc pos lineStr parseAndCheck constant
+
+      yield! digitGroupFixes doc lineStr constant
+      yield! padBinaryWithZerosFixes doc lineStr constant
+
+      if DEBUG then
+        debugFix doc lineStr constant ]
+
+module private FloatFix =
+  let private debugFix doc (lineStr: String) (constant: FloatConstant) =
+    let data =
+      let full = constant.Range.SpanIn(lineStr).ToString()
+
+      let intPart =
+        if constant.IntRange.IsEmpty then
+          "∅"
+        else
+          constant.IntRange.SpanIn(full).ToString()
+
+      let decPart =
+        if constant.DecimalRange.IsEmpty then
+          "∅"
+        else
+          constant.DecimalRange.SpanIn(full).ToString()
+
+      let expPart =
+        if constant.ExponentRange.IsEmpty then
+          "∅"
+        else
+          constant.ExponentRange.SpanIn(full).ToString()
+
+      let suffix = constant.SuffixRange.SpanIn(full).ToString()
+
+      let format = if constant.IsScientific then "scientific" else "decimal"
+
+      $"%A{constant.Sign} %A{intPart}.%A{decPart}e%A{expPart}%A{suffix} (%s{format}) (%A{full}, %A{constant.Value})"
+
+    mkFix doc data [||]
+
+  /// Separates digit groups with `_`.
+  let separateDigitGroupsFix doc (lineStr: String) (constant: FloatConstant) =
+    let text = constant.Range.SpanIn(lineStr)
+
+    if text.Contains '_' then
+      []
+    else
+      let edits =
+        [| if constant.IntRange.Length > 3 then
+             let range = constant.IntRange.ToRangeInside constant.Range
+             let n = range.SpanIn(lineStr).ToString()
+
+             { Range = range
+               NewText = DigitGroup.addSeparator n 3 DigitGroup.RightToLeft }
+           if constant.DecimalRange.Length > 3 then
+             let range = constant.DecimalRange.ToRangeInside constant.Range
+             let n = range.SpanIn(lineStr).ToString()
+
+             { Range = range
+               NewText = DigitGroup.addSeparator n 3 DigitGroup.LeftToRight }
+           if constant.ExponentRange.Length > 3 then
+             let range = constant.ExponentRange.ToRangeInside constant.Range
+             let n = range.SpanIn(lineStr).ToString()
+
+             { Range = range
+               NewText = DigitGroup.addSeparator n 3 DigitGroup.RightToLeft } |]
+
+      match edits with
+      | [||] -> []
+      | _ -> mkFix doc Title.Float.Separate.all3 edits |> List.singleton
+
+  /// Removes or adds digit group separators (`_`)
+  let digitGroupFixes doc (lineStr: String) (constant: FloatConstant) =
+    match DigitGroup.removeFix doc lineStr constant.Range constant.ValueRange with
+    | [] -> separateDigitGroupsFix doc lineStr constant
+    | fix -> fix
+
+  let all
+    doc
+    (pos: FcsPos)
+    (lineStr: String)
+    (parseAndCheck: ParseAndCheckResults)
+    (error: bool)
+    (constant: FloatConstant)
+    =
+    [ if not error then
+        // Note: `infinity` & co don't get parsed as `SynConst`, but instead as `Ident`
+        //       -> `constant` is always actual float value, not named
+        yield!
+          CommonFixes.replaceFloatWithNameFix
+            doc
+            pos
+            lineStr
+            parseAndCheck
+            constant.Constant
+            constant.Range
+            constant.Value
+
+      yield! digitGroupFixes doc lineStr constant
+
+      if DEBUG then
+        debugFix doc lineStr constant ]
+
+
+/// CodeFixes for number-based Constant to:
+/// * Convert between bases & forms
+/// * Add digit group separators
+/// * Replace with name (like `infinity` or `TYPE.MinValue`)
+/// * Integrate/Extract Minus (Hex/Oct/Bin -> sign bit vs. explicit `-` sign)
+let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix =
+  fun (codeActionParams) ->
+    asyncResult {
+      let filePath = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath
+      let fcsPos = protocolPosToPos codeActionParams.Range.Start
+      let! (parseAndCheck, lineStr, sourceText) = getParseResultsForFile filePath fcsPos
+
+      match tryFindConstant parseAndCheck.GetAST fcsPos with
+      | None -> return []
+      | Some(range, constant) ->
+        let range = fcsRangeToLsp range
+        // We don't want any "convert to other base" fix for faulty constant:
+        //   With error `SynConst value` falls back to its default value.
+        //   For example: `let v = 12345uy` -> `SynConst.Byte 0`
+        // But we might allow "Separate digit groups" fix
+        let error =
+          codeActionParams.Context.Diagnostics
+          |> Array.exists (fun diag ->
+            diag.Severity = Some DiagnosticSeverity.Error
+            &&
+            // Note: Only care about error when const is error, not any outer error
+            diag.Range = range)
+
+        let doc: TextDocumentIdentifier = codeActionParams.TextDocument
+
+        /// Note: does NOT handle `byte` in ASCII format -- in fact it doesn't even check.
+        ///       -> match ASCII `byte` BEFORE this! (-> `CharConstant.isAsciiByte`)
+        let (|IntConstant|_|) constant =
+          match constant with
+          | SynConst.Byte _
+          | SynConst.SByte _
+          | SynConst.Int16 _
+          | SynConst.UInt16 _
+          | SynConst.Int32 _
+          | SynConst.UInt32 _
+          | SynConst.Int64 _
+          | SynConst.UInt64 _
+          | SynConst.IntPtr _
+          | SynConst.UIntPtr _ ->
+            assert (not (CharConstant.isAsciiByte (range.SpanIn(lineStr))))
+            IntConstant.parse (lineStr, range, constant) |> Some
+          | _ -> None
+
+        /// Note: does NOT handle Hex/Oct/Bin formats -- in fact it doesn't even check.
+        ///       -> match Hex/Oct/Bin BEFORE this! (-> `FloatConstant.isIntFloat`)
+        let (|FloatConstant|_|) constant =
+          let parse value =
+            assert (not (FloatConstant.isIntFloat (range.SpanIn(lineStr))))
+            FloatConstant.parse (lineStr, range, constant, value) |> Some
+
+          match constant with
+          | SynConst.Single value -> FloatValue.from value |> parse
+          | SynConst.Double value -> FloatValue.from value |> parse
+          | SynConst.Decimal value -> FloatValue.from value |> parse
+          | _ -> None
+
+        return
+          match constant with
+          | SynConst.Char value ->
+            let constant = CharConstant.parse (lineStr, range, constant, value)
+            CharFix.all doc lineStr error constant
+          | SynConst.Byte value when CharConstant.isAsciiByte (range.SpanIn(lineStr)) ->
+            let constant = CharConstant.parse (lineStr, range, constant, char value)
+            CharFix.all doc lineStr error constant
+          | IntConstant constant -> IntFix.all doc fcsPos lineStr parseAndCheck error constant
+          | SynConst.UserNum(_, _) ->
+            let constant = IntConstant.parse (lineStr, range, constant)
+            IntFix.all doc fcsPos lineStr parseAndCheck error constant
+          | SynConst.Single _
+          | SynConst.Double _ when FloatConstant.isIntFloat (range.SpanIn(lineStr)) ->
+            let constant = IntConstant.parse (lineStr, range, constant)
+            IntFix.all doc fcsPos lineStr parseAndCheck error constant
+          | FloatConstant constant -> FloatFix.all doc fcsPos lineStr parseAndCheck error constant
+          | _ -> []
+    }
diff --git a/src/FsAutoComplete/CodeFixes/AdjustConstant.fsi b/src/FsAutoComplete/CodeFixes/AdjustConstant.fsi
new file mode 100644
index 000000000..fc6a655f9
--- /dev/null
+++ b/src/FsAutoComplete/CodeFixes/AdjustConstant.fsi
@@ -0,0 +1,70 @@
+module FsAutoComplete.CodeFix.AdjustConstant
+
+open FsAutoComplete.CodeFix.Types
+open Ionide.LanguageServerProtocol.Types
+
+[<RequireQualifiedAccess>]
+type CharFormat =
+  /// `ç`
+  | Char
+  /// `\231`
+  | Decimal
+  /// `\xE7`
+  | Hexadecimal
+  /// `\u00E7`
+  | Utf16Hexadecimal
+  /// `\U000000E7`
+  | Utf32Hexadecimal
+
+[<RequireQualifiedAccess>]
+type Base =
+  /// No prefix
+  | Decimal
+  /// `0x`
+  | Hexadecimal
+  /// `0o`
+  | Octal
+  /// `0b`
+  | Binary
+
+module Title =
+  val removeDigitSeparators: string
+  val replaceWith: (string -> string)
+
+  module Int =
+    module Convert =
+      val toDecimal: string
+      val toHexadecimal: string
+      val toOctal: string
+      val toBinary: string
+
+      module SpecialCase =
+        val extractMinusFromNegativeConstant: string
+        val integrateExplicitMinus: string
+        val useImplicitPlusInPositiveConstantWithMinusSign: string
+        val removeExplicitMinusWithMinValue: string
+
+    module Separate =
+      val decimal3: string
+      val hexadecimal4: string
+      val hexadecimal2: string
+      val octal3: string
+      val binary4: string
+      val binary8: string
+
+  module Float =
+    module Separate =
+      val all3: string
+
+  module Char =
+    module Convert =
+      val toChar: (string -> string)
+      val toDecimal: (string -> string)
+      val toHexadecimal: (string -> string)
+      val toUtf16Hexadecimal: (string -> string)
+      val toUtf32Hexadecimal: (string -> string)
+
+val fix:
+  getParseResultsForFile: GetParseResultsForFile ->
+  codeActionParams: CodeActionParams ->
+    Async<Result<Fix list, string>>
diff --git a/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs b/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs
index 357362c13..f8b59b266 100644
--- a/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs
+++ b/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs
@@ -93,8 +93,7 @@ let fix
           let previousLine = docLine - 1
           let insertionPointIsNotOutOfBoundsOfTheFile = docLine > 0
 
-          let theThereAreOtherOpensInThisModule () =
-            text.GetLineString(previousLine).Contains "open "
+          let theThereAreOtherOpensInThisModule () = text.GetLineString(previousLine).Contains "open "
 
           if insertionPointIsNotOutOfBoundsOfTheFile && theThereAreOtherOpensInThisModule () then
             text.GetLineString(previousLine).Split("open") |> Seq.head |> Seq.length // inherit the previous opens whitespace
diff --git a/src/FsAutoComplete/CommandResponse.fs b/src/FsAutoComplete/CommandResponse.fs
index 55d3b1404..5d37eb21a 100644
--- a/src/FsAutoComplete/CommandResponse.fs
+++ b/src/FsAutoComplete/CommandResponse.fs
@@ -522,8 +522,7 @@ module CommandResponse =
             OutputType = typ
             Generics = generics } }
 
-  let help (serialize: Serializer) (data: string) =
-    serialize { Kind = "help"; Data = data }
+  let help (serialize: Serializer) (data: string) = serialize { Kind = "help"; Data = data }
 
   let fsdn (serialize: Serializer) (functions: string list) =
     let data = { FsdnResponse.Functions = functions }
diff --git a/src/FsAutoComplete/JsonSerializer.fs b/src/FsAutoComplete/JsonSerializer.fs
index b2584f010..ecba41b6c 100644
--- a/src/FsAutoComplete/JsonSerializer.fs
+++ b/src/FsAutoComplete/JsonSerializer.fs
@@ -11,8 +11,7 @@ module private JsonSerializerConverters =
   type OptionConverter() =
     inherit JsonConverter()
 
-    override x.CanConvert(t) =
-      t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<option<_>>
+    override x.CanConvert(t) = t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<option<_>>
 
     override x.WriteJson(writer, value, serializer) =
       let value =
@@ -129,8 +128,6 @@ module private JsonSerializerConverters =
 
 module JsonSerializer =
 
-  let writeJson (o: obj) =
-    JsonConvert.SerializeObject(o, JsonSerializerConverters.jsonConverters)
+  let writeJson (o: obj) = JsonConvert.SerializeObject(o, JsonSerializerConverters.jsonConverters)
 
-  let readJson<'T> (s: string) =
-    JsonConvert.DeserializeObject<'T>(s, JsonSerializerConverters.jsonConverters)
+  let readJson<'T> (s: string) = JsonConvert.DeserializeObject<'T>(s, JsonSerializerConverters.jsonConverters)
diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs
index e78015382..a7eb9fc1a 100644
--- a/src/FsAutoComplete/LspHelpers.fs
+++ b/src/FsAutoComplete/LspHelpers.fs
@@ -19,16 +19,14 @@ type FcsPos = FSharp.Compiler.Text.Position
 module FcsPos = FSharp.Compiler.Text.Position
 
 module FcsPos =
-  let subtractColumn (pos: FcsPos) (column: int) =
-    FcsPos.mkPos pos.Line (pos.Column - column)
+  let subtractColumn (pos: FcsPos) (column: int) = FcsPos.mkPos pos.Line (pos.Column - column)
 
 [<AutoOpen>]
 module Conversions =
   module Lsp = Ionide.LanguageServerProtocol.Types
 
   /// convert an LSP position to a compiler position
-  let protocolPosToPos (pos: Lsp.Position) : FcsPos =
-    FcsPos.mkPos (pos.Line + 1) (pos.Character)
+  let protocolPosToPos (pos: Lsp.Position) : FcsPos = FcsPos.mkPos (pos.Line + 1) (pos.Character)
 
   let protocolPosToRange (pos: Lsp.Position) : Lsp.Range = { Start = pos; End = pos }
 
@@ -201,8 +199,7 @@ module internal GlyphConversions =
 
     let completionItemSet = defaultArg completionItemSet defaultSet
 
-    let bestAvailable (possible: 'kind[]) =
-      possible |> Array.tryFind (fun x -> Array.contains x completionItemSet)
+    let bestAvailable (possible: 'kind[]) = possible |> Array.tryFind (fun x -> Array.contains x completionItemSet)
 
     let unionCases = FSharpType.GetUnionCases(typeof<FSharpGlyph>)
     let cache = Dictionary<FSharpGlyph, 'kind option>(unionCases.Length)
@@ -347,8 +344,7 @@ module Workspace =
     | WorkspacePeekFoundSolutionItemKind.Folder folder -> folder.Items |> List.collect foldFsproj
     | WorkspacePeekFoundSolutionItemKind.MsbuildFormat msbuild -> [ item.Name, msbuild ]
 
-  let countProjectsInSln (sln: WorkspacePeekFoundSolution) =
-    sln.Items |> List.map foldFsproj |> List.sumBy List.length
+  let countProjectsInSln (sln: WorkspacePeekFoundSolution) = sln.Items |> List.map foldFsproj |> List.sumBy List.length
 
 module SigantureData =
   let formatSignature typ parms : string =
diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
index 49cd59c15..93fa2dd73 100644
--- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
+++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
@@ -69,8 +69,7 @@ type LoadedProject =
     LanguageVersion: LanguageVersionShim }
 
   interface IEquatable<LoadedProject> with
-    member x.Equals(other) =
-      x.FSharpProjectOptions = other.FSharpProjectOptions
+    member x.Equals(other) = x.FSharpProjectOptions = other.FSharpProjectOptions
 
   override x.GetHashCode() = x.FSharpProjectOptions.GetHashCode()
 
@@ -293,8 +292,7 @@ type AdaptiveFSharpLspServer
     let fileName = Path.GetFileName filePathUntag
 
 
-    let inline getSourceLine lineNo =
-      (source: ISourceText).GetLineString(lineNo - 1)
+    let inline getSourceLine lineNo = (source: ISourceText).GetLineString(lineNo - 1)
 
     let checkUnusedOpens =
       async {
@@ -717,8 +715,7 @@ type AdaptiveFSharpLspServer
 
   let (|ProjectAssetsFile|_|) (props: list<Types.Property>) = tryFindProp "ProjectAssetsFile" props
 
-  let (|BaseIntermediateOutputPath|_|) (props: list<Types.Property>) =
-    tryFindProp "BaseIntermediateOutputPath" props
+  let (|BaseIntermediateOutputPath|_|) (props: list<Types.Property>) = tryFindProp "BaseIntermediateOutputPath" props
 
   let (|MSBuildAllProjects|_|) (props: list<Types.Property>) =
     tryFindProp "MSBuildAllProjects" props
@@ -1036,14 +1033,11 @@ type AdaptiveFSharpLspServer
     resetCancellationToken filePath
     transact (fun () -> textChanges.AddOrElse(filePath, adder, updater))
 
-  let isFileOpen file =
-    openFiles |> AMap.tryFindA file |> AVal.map (Option.isSome)
+  let isFileOpen file = openFiles |> AMap.tryFindA file |> AVal.map (Option.isSome)
 
-  let findFileInOpenFiles file =
-    openFilesWithChanges |> AMap.tryFindA file
+  let findFileInOpenFiles file = openFilesWithChanges |> AMap.tryFindA file
 
-  let forceFindOpenFile filePath =
-    findFileInOpenFiles filePath |> AVal.force
+  let forceFindOpenFile filePath = findFileInOpenFiles filePath |> AVal.force
 
   let forceFindOpenFileOrRead file =
     asyncOption {
@@ -1137,8 +1131,7 @@ type AdaptiveFSharpLspServer
         |> Async.parallel75
     }
 
-  let forceFindSourceText filePath =
-    forceFindOpenFileOrRead filePath |> AsyncResult.map (fun f -> f.Source)
+  let forceFindSourceText filePath = forceFindOpenFileOrRead filePath |> AsyncResult.map (fun f -> f.Source)
 
 
   let openFilesToChangesAndProjectOptions =
@@ -1225,8 +1218,7 @@ type AdaptiveFSharpLspServer
 
       Commands.calculateNamespaceInsert (fun () -> Some ast) d pos getline)
 
-  let getAutoCompleteNamespacesByDeclName name =
-    autoCompleteNamespaces |> AMap.tryFind name
+  let getAutoCompleteNamespacesByDeclName name = autoCompleteNamespaces |> AMap.tryFind name
 
 
   /// <summary>Gets Parse and Check results of a given file while also handling other concerns like Progress, Logging, Eventing.</summary>
@@ -1389,11 +1381,9 @@ type AdaptiveFSharpLspServer
 
       })
 
-  let getParseResults filePath =
-    openFilesToParsedResults |> AMapAsync.tryFindAndFlatten filePath
+  let getParseResults filePath = openFilesToParsedResults |> AMapAsync.tryFindAndFlatten filePath
 
-  let getTypeCheckResults filePath =
-    openFilesToCheckedFilesResults |> AMapAsync.tryFindAndFlatten (filePath)
+  let getTypeCheckResults filePath = openFilesToCheckedFilesResults |> AMapAsync.tryFindAndFlatten (filePath)
 
   let getRecentTypeCheckResults filePath =
     openFilesToRecentCheckedFilesResults |> AMapAsync.tryFindAndFlatten (filePath)
@@ -1483,8 +1473,7 @@ type AdaptiveFSharpLspServer
 
     }
 
-  let getDeclarations filename =
-    openFilesToDeclarations |> AMapAsync.tryFindAndFlatten filename
+  let getDeclarations filename = openFilesToDeclarations |> AMapAsync.tryFindAndFlatten filename
 
   let getFilePathAndPosition (p: ITextDocumentPositionParams) =
     let filePath = p.GetFilePath() |> Utils.normalizePath
@@ -1546,8 +1535,7 @@ type AdaptiveFSharpLspServer
               return! None
           }
 
-        member x.ParseFileInProject(file) =
-          forceGetParseResults file |> Async.map (Option.ofResult) }
+        member x.ParseFileInProject(file) = forceGetParseResults file |> Async.map (Option.ofResult) }
 
   let getDependentProjectsOfProjects ps =
     let projectSnapshot = forceLoadProjects ()
@@ -1715,8 +1703,7 @@ type AdaptiveFSharpLspServer
     let getUnionPatternMatchCases tyRes pos sourceText line =
       Commands.getUnionPatternMatchCases tryFindUnionDefinitionFromPos tyRes pos sourceText line
 
-    let unionCaseStubReplacements (config) () =
-      Map.ofList [ "$1", config.UnionCaseStubGenerationBody ]
+    let unionCaseStubReplacements (config) () = Map.ofList [ "$1", config.UnionCaseStubGenerationBody ]
 
 
     let implementInterfaceConfig config () : ImplementInterface.Config =
@@ -1724,8 +1711,7 @@ type AdaptiveFSharpLspServer
         MethodBody = config.InterfaceStubGenerationMethodBody
         IndentationSize = config.IndentationSize }
 
-    let recordStubReplacements config () =
-      Map.ofList [ "$1", config.RecordStubGenerationBody ]
+    let recordStubReplacements config () = Map.ofList [ "$1", config.RecordStubGenerationBody ]
 
     let tryFindRecordDefinitionFromPos =
       RecordStubGenerator.tryFindRecordDefinitionFromPos codeGenServer
@@ -1835,7 +1821,8 @@ type AdaptiveFSharpLspServer
          UseTripleQuotedInterpolation.fix tryGetParseResultsForFile getRangeText
          RenameParamToMatchSignature.fix tryGetParseResultsForFile
          RemovePatternArgument.fix tryGetParseResultsForFile
-         ToInterpolatedString.fix tryGetParseResultsForFile getLanguageVersion |])
+         ToInterpolatedString.fix tryGetParseResultsForFile getLanguageVersion
+         AdjustConstant.fix tryGetParseResultsForFile |])
 
   let forgetDocument (uri: DocumentUri) =
     async {
@@ -2192,8 +2179,7 @@ type AdaptiveFSharpLspServer
     Helpers.ignoreNotification
 
   interface IFSharpLspServer with
-    override x.Shutdown() =
-      (x :> System.IDisposable).Dispose() |> async.Return
+    override x.Shutdown() = (x :> System.IDisposable).Dispose() |> async.Return
 
     override _.Initialize(p: InitializeParams) =
       asyncResult {
@@ -3392,6 +3378,11 @@ type AdaptiveFSharpLspServer
                 try
                   return! codeFix codeActionParams
                 with e ->
+                  logger.error (
+                    Log.setMessage "Exception in CodeFix: {error}"
+                    >> Log.addContextDestructured "error" (e.ToString())
+                  )
+
                   return Ok []
               })
             |> Async.parallel75
diff --git a/src/FsAutoComplete/LspServers/Common.fs b/src/FsAutoComplete/LspServers/Common.fs
index 4d38f4fe7..999489c1a 100644
--- a/src/FsAutoComplete/LspServers/Common.fs
+++ b/src/FsAutoComplete/LspServers/Common.fs
@@ -31,8 +31,7 @@ open Fantomas.Client.Contracts
 open Fantomas.Client.LSPFantomasService
 
 module Result =
-  let ofStringErr r =
-    r |> Result.mapError JsonRpc.Error.InternalErrorMessage
+  let ofStringErr r = r |> Result.mapError JsonRpc.Error.InternalErrorMessage
 
   let ofCoreResponse (r: CoreResponse<'a>) =
     match r with
@@ -43,8 +42,7 @@ module Result =
 module AsyncResult =
   let ofCoreResponse (ar: Async<CoreResponse<'a>>) = ar |> Async.map Result.ofCoreResponse
 
-  let ofStringErr (ar: Async<Result<'a, string>>) =
-    ar |> AsyncResult.mapError JsonRpc.Error.InternalErrorMessage
+  let ofStringErr (ar: Async<Result<'a, string>>) = ar |> AsyncResult.mapError JsonRpc.Error.InternalErrorMessage
 
 
 
@@ -54,8 +52,7 @@ type DiagnosticMessage =
 
 /// a type that handles bookkeeping for sending file diagnostics.  It will debounce calls and handle sending diagnostics via the configured function when safe
 type DiagnosticCollection(sendDiagnostics: DocumentUri -> Diagnostic[] -> Async<unit>) =
-  let send uri (diags: Map<string, Diagnostic[]>) =
-    Map.toArray diags |> Array.collect snd |> sendDiagnostics uri
+  let send uri (diags: Map<string, Diagnostic[]>) = Map.toArray diags |> Array.collect snd |> sendDiagnostics uri
 
   let agents =
     System.Collections.Concurrent.ConcurrentDictionary<DocumentUri, MailboxProcessor<DiagnosticMessage> *
@@ -147,8 +144,7 @@ module Async =
 
   let rec logger = LogProvider.getLoggerByQuotation <@ logger @>
 
-  let inline logCancelled e =
-    logger.trace (Log.setMessage "Operation Cancelled" >> Log.addExn e)
+  let inline logCancelled e = logger.trace (Log.setMessage "Operation Cancelled" >> Log.addExn e)
 
 
   let withCancellation (ct: CancellationToken) (a: Async<'a>) : Async<'a> =
diff --git a/src/FsAutoComplete/LspServers/FSharpLspClient.fs b/src/FsAutoComplete/LspServers/FSharpLspClient.fs
index 8997528b6..fe05c265e 100644
--- a/src/FsAutoComplete/LspServers/FSharpLspClient.fs
+++ b/src/FsAutoComplete/LspServers/FSharpLspClient.fs
@@ -19,32 +19,23 @@ type FSharpLspClient(sendServerNotification: ClientNotificationSender, sendServe
 
   member val ClientCapabilities: ClientCapabilities option = None with get, set
 
-  override __.WindowShowMessage(p) =
-    sendServerNotification "window/showMessage" (box p) |> Async.Ignore
+  override __.WindowShowMessage(p) = sendServerNotification "window/showMessage" (box p) |> Async.Ignore
 
-  override __.WindowShowMessageRequest(p) =
-    sendServerRequest.Send "window/showMessageRequest" (box p)
+  override __.WindowShowMessageRequest(p) = sendServerRequest.Send "window/showMessageRequest" (box p)
 
-  override __.WindowLogMessage(p) =
-    sendServerNotification "window/logMessage" (box p) |> Async.Ignore
+  override __.WindowLogMessage(p) = sendServerNotification "window/logMessage" (box p) |> Async.Ignore
 
-  override __.TelemetryEvent(p) =
-    sendServerNotification "telemetry/event" (box p) |> Async.Ignore
+  override __.TelemetryEvent(p) = sendServerNotification "telemetry/event" (box p) |> Async.Ignore
 
-  override __.ClientRegisterCapability(p) =
-    sendServerRequest.Send "client/registerCapability" (box p)
+  override __.ClientRegisterCapability(p) = sendServerRequest.Send "client/registerCapability" (box p)
 
-  override __.ClientUnregisterCapability(p) =
-    sendServerRequest.Send "client/unregisterCapability" (box p)
+  override __.ClientUnregisterCapability(p) = sendServerRequest.Send "client/unregisterCapability" (box p)
 
-  override __.WorkspaceWorkspaceFolders() =
-    sendServerRequest.Send "workspace/workspaceFolders" ()
+  override __.WorkspaceWorkspaceFolders() = sendServerRequest.Send "workspace/workspaceFolders" ()
 
-  override __.WorkspaceConfiguration(p) =
-    sendServerRequest.Send "workspace/configuration" (box p)
+  override __.WorkspaceConfiguration(p) = sendServerRequest.Send "workspace/configuration" (box p)
 
-  override __.WorkspaceApplyEdit(p) =
-    sendServerRequest.Send "workspace/applyEdit" (box p)
+  override __.WorkspaceApplyEdit(p) = sendServerRequest.Send "workspace/applyEdit" (box p)
 
   override __.WorkspaceSemanticTokensRefresh() =
     sendServerNotification "workspace/semanticTokens/refresh" () |> Async.Ignore
@@ -63,8 +54,7 @@ type FSharpLspClient(sendServerNotification: ClientNotificationSender, sendServe
   member __.NotifyCancelledRequest(p: PlainNotification) =
     sendServerNotification "fsharp/notifyCancel" (box p) |> Async.Ignore
 
-  member __.NotifyFileParsed(p: PlainNotification) =
-    sendServerNotification "fsharp/fileParsed" (box p) |> Async.Ignore
+  member __.NotifyFileParsed(p: PlainNotification) = sendServerNotification "fsharp/fileParsed" (box p) |> Async.Ignore
 
   member __.NotifyDocumentAnalyzed(p: DocumentAnalyzedNotification) =
     sendServerNotification "fsharp/documentAnalyzed" (box p) |> Async.Ignore
@@ -180,12 +170,10 @@ type ServerProgressReport(lspClient: FSharpLspClient, ?token: ProgressToken) =
     }
 
   interface IAsyncDisposable with
-    member x.DisposeAsync() =
-      task { do! x.End () (CancellationToken.None) } |> ValueTask
+    member x.DisposeAsync() = task { do! x.End () (CancellationToken.None) } |> ValueTask
 
   interface IDisposable with
-    member x.Dispose() =
-      (x :> IAsyncDisposable).DisposeAsync() |> ignore
+    member x.Dispose() = (x :> IAsyncDisposable).DisposeAsync() |> ignore
 
 
 open System.Diagnostics.Tracing
@@ -197,11 +185,9 @@ open Ionide.ProjInfo.Logging
 /// <summary>listener for the the events generated from the fsc ActivitySource</summary>
 type ProgressListener(lspClient: FSharpLspClient, traceNamespace: string array) =
 
-  let isOneOf list string =
-    list |> Array.exists (fun f -> f string)
+  let isOneOf list string = list |> Array.exists (fun f -> f string)
 
-  let strEquals (other: string) (this: string) =
-    this.Equals(other, StringComparison.InvariantCultureIgnoreCase)
+  let strEquals (other: string) (this: string) = this.Equals(other, StringComparison.InvariantCultureIgnoreCase)
 
   let strContains (substring: string) (str: string) = str.Contains(substring)
 
@@ -324,8 +310,7 @@ type ProgressListener(lspClient: FSharpLspClient, traceNamespace: string array)
   do ActivitySource.AddActivityListener listener
 
   interface IDisposable with
-    member this.Dispose() : unit =
-      (this :> IAsyncDisposable).DisposeAsync() |> ignore
+    member this.Dispose() : unit = (this :> IAsyncDisposable).DisposeAsync() |> ignore
 
   interface IAsyncDisposable with
     member this.DisposeAsync() : ValueTask =
diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs
index b11db9eee..a55b50f5c 100644
--- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs
+++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs
@@ -1071,13 +1071,11 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient, sourceTextFactory
             MethodBody = config.InterfaceStubGenerationMethodBody
             IndentationSize = config.IndentationSize }
 
-        let unionCaseStubReplacements () =
-          Map.ofList [ "$1", config.UnionCaseStubGenerationBody ]
+        let unionCaseStubReplacements () = Map.ofList [ "$1", config.UnionCaseStubGenerationBody ]
 
         let getUnionCaseStubReplacements () = unionCaseStubReplacements ()
 
-        let recordStubReplacements () =
-          Map.ofList [ "$1", config.RecordStubGenerationBody ]
+        let recordStubReplacements () = Map.ofList [ "$1", config.RecordStubGenerationBody ]
 
         let getRecordStubReplacements () = recordStubReplacements ()
 
@@ -2875,8 +2873,7 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient, sourceTextFactory
           return success (Some hints)
         })
 
-    override x.Dispose() =
-      (x :> ILspServer).Shutdown() |> Async.Start
+    override x.Dispose() = (x :> ILspServer).Shutdown() |> Async.Start
 
     member this.WorkDoneProgessCancel(arg1: ProgressToken) : Async<unit> = failwith "Not Implemented"
 
diff --git a/src/FsAutoComplete/Parser.fs b/src/FsAutoComplete/Parser.fs
index b771ab182..42cd730b2 100644
--- a/src/FsAutoComplete/Parser.fs
+++ b/src/FsAutoComplete/Parser.fs
@@ -257,8 +257,7 @@ module Parser =
       let hasMinLevel (minLevel: LogEventLevel) (e: LogEvent) = e.Level >= minLevel
 
       // will use later when a mapping-style config of { "category": "minLevel" } is established
-      let excludeByLevelWhenCategory category level event =
-        isCategory category event || not (hasMinLevel level event)
+      let excludeByLevelWhenCategory category level event = isCategory category event || not (hasMinLevel level event)
 
       let args = ctx.ParseResult
 
diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AdjustConstantTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AdjustConstantTests.fs
new file mode 100644
index 000000000..a8100bb4d
--- /dev/null
+++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AdjustConstantTests.fs
@@ -0,0 +1,1591 @@
+module private FsAutoComplete.Tests.CodeFixTests.AdjustConstantTests
+
+open System
+open Expecto
+open Helpers
+open Utils.ServerTests
+open Utils.Server
+open Utils.CursorbasedTests
+open FsAutoComplete.CodeFix
+open FsAutoComplete.CodeFix.AdjustConstant
+open Utils.Tests
+open Utils.TextEdit
+open Utils.CursorbasedTests.CodeFix
+open Ionide.LanguageServerProtocol.Types
+
+module private ConvertIntToOtherBase =
+  let baseOf (str: String) =
+    if str.Contains "0b" then Base.Binary
+    elif str.Contains "0x" then Base.Hexadecimal
+    elif str.Contains "0o" then Base.Octal
+    else Base.Decimal
+
+  let selectIntCodeFix (base': Base) =
+    match base' with
+    | Base.Decimal -> Title.Int.Convert.toDecimal
+    | Base.Hexadecimal -> Title.Int.Convert.toHexadecimal
+    | Base.Octal -> Title.Int.Convert.toOctal
+    | Base.Binary -> Title.Int.Convert.toBinary
+    |> CodeFix.withTitle
+  /// empty `expected`: no corresponding fix
+  let private checkBase
+    doc
+    (source: String, cursor: Range)
+    base'
+    expected
+    =
+    let name = 
+      if String.IsNullOrWhiteSpace expected then
+        $"cannot convert to {base'}"
+      else
+        $"can convert to {base'}"
+    testCaseAsync name (async {
+      let! (doc, diags) = doc
+      let expected =
+        if String.IsNullOrWhiteSpace expected then
+          ExpectedResult.NotApplicable
+        else
+          ExpectedResult.After expected
+      do! checkFixAt 
+            (doc, diags) 
+            (source, cursor) 
+            Diagnostics.acceptAll
+            (selectIntCodeFix base')
+            expected
+    })
+  /// empty `expectedXXX`: there should be no corresponding Fix
+  let check
+    server
+    name
+    (beforeWithCursor: String)
+    (expectedDecimal: String)
+    (expectedHexadecimal: String)
+    (expectedOctal: String)
+    (expectedBinary: String)
+    =
+    let (cursor, source) = Cursor.assertExtractRange beforeWithCursor
+    documentTestList name server (Server.createUntitledDocument source) (fun doc -> [
+      checkBase doc (source, cursor) Base.Decimal expectedDecimal
+      checkBase doc (source, cursor) Base.Hexadecimal expectedHexadecimal
+      checkBase doc (source, cursor) Base.Octal expectedOctal
+      checkBase doc (source, cursor) Base.Binary expectedBinary
+    ])
+  /// Checks all combinations of base': Can convert from any base to all others but not to self
+  /// 
+  /// `template`: without cursor, but with `{number}` marker: number gets inserted here and cursor placed at end
+  /// 
+  /// empty `valueXXX`: there should be no corresponding Fix
+  let private checkAll
+    server
+    name
+    (template: String)
+    (decimalNumber: String)
+    (hexadecimalNumber: String)
+    (octalNumber: String)
+    (binaryNumber: String)
+    =
+    let applyTemplate cursor number =
+      let number =
+        if cursor then
+          number + "$0"
+        else
+          number
+      template.Replace("{number}", number)
+
+    testList name [
+      let data = [(Base.Decimal, decimalNumber); (Base.Hexadecimal, hexadecimalNumber); (Base.Octal, octalNumber); (Base.Binary, binaryNumber)]
+      let valueOf (base') = 
+        data
+        |> List.find (fun (b,_) -> b = base')
+        |> snd
+      for (base', value) in data do
+        if String.IsNullOrEmpty value then
+          ()
+        else
+          let mkExpected (b) =
+            if base' = b || String.IsNullOrEmpty (valueOf b) then 
+              ""
+            else
+              applyTemplate false (valueOf b)
+          check server $"can convert from {base'}"
+            (applyTemplate true value)
+            (mkExpected Base.Decimal)
+            (mkExpected Base.Hexadecimal)
+            (mkExpected Base.Octal)
+            (mkExpected Base.Binary)
+    ]
+
+  type private Journey =
+    | JustDestination of string
+    | JustSource of string
+    | InOut of string
+    | Neither
+  module private Journey =
+    let source =
+      function
+      | JustSource value | InOut value -> Some value
+      | JustDestination _ | Neither -> None
+    let destination =
+      function
+      | JustDestination value | InOut value -> Some value
+      | JustSource _ | Neither -> None
+  let private checkAllJourneys
+    server
+    name
+    (template: String)
+    (decimalNumber: Journey)
+    (hexadecimalNumber: Journey)
+    (octalNumber: Journey)
+    (binaryNumber: Journey)
+    =
+    let applyTemplate cursor number =
+      let number = if cursor then number + "$0" else number
+      template.Replace("{number}", number)
+
+    testList name [
+      let data = [(Base.Decimal, decimalNumber); (Base.Hexadecimal, hexadecimalNumber); (Base.Octal, octalNumber); (Base.Binary, binaryNumber)]
+
+      for (base', j) in data do
+        match j |> Journey.source with
+        | None -> ()
+        | Some value ->
+
+          let mkExpected b =
+            if base' = b then
+              ""
+            else
+              data 
+              |> List.find (fst >> (=) b) 
+              |> snd 
+              |> Journey.destination
+              |> Option.map (applyTemplate false)
+              |> Option.defaultValue ""
+
+          check server $"can convert from {base'}"
+            (applyTemplate true value)
+            (mkExpected Base.Decimal)
+            (mkExpected Base.Hexadecimal)
+            (mkExpected Base.Octal)
+            (mkExpected Base.Binary)
+    ]
+
+  let tests state =
+    serverTestList "Convert int-number to other bases" state defaultConfigDto None (fun server -> [
+      checkAll server "can convert simple number"
+        "let n = {number}"
+        "123"
+        "0x7B"
+        "0o173"
+        "0b1111011"
+      checkAll server "can convert simple negative number"
+        "let n = {number}"
+        "-123"
+        "-0x7B"
+        "-0o173"
+        "-0b1111011"
+      checkAll server "can convert 0"
+        "let n = {number}"
+        "0"
+        "0x0"
+        "0o0"
+        "0b0"
+      checkAll server "can convert 1"
+        "let n = {number}"
+        "1"
+        "0x1"
+        "0o1"
+        "0b1"
+      checkAll server "can convert -1"
+        "let n = {number}"
+        "-1"
+        "-0x1"
+        "-0o1"
+        "-0b1"
+
+      testList "extrema" [
+        // Note regarding negative `MinValue`:
+        //   Only decimal has `-` sign -- all other should not.
+        //   While `-0b1000_0000y` is valid -- it has basically two minus signs: one `-` and one minus bit.
+        //   The Quick Fix removes that `-` sign when converting from decimal to other base.
+        //   However: it does NOT remove the `-` sign when it already exists for a non-decimal base:
+        //   `-0b1000_0000y` becomes `-0x80y`, while `0b1000_0000y` becomes `0x80y`
+        testList "sbyte" [
+          checkAll server "can convert MaxValue"
+            "let n = {number} = System.SByte.MaxValue"
+            "127y"
+            "0x7Fy"
+            "0o177y"
+            "0b1111111y"
+          checkAll server "can convert MinValue (no `-`)"
+            "let n = {number} = System.SByte.MinValue"
+            "-128y"
+            "0x80y"
+            "0o200y"
+            "0b10000000y"
+          checkAllJourneys server "can convert MinValue (keep `-`)"
+            "let n = {number} = System.SByte.MinValue"
+            (JustDestination "-128y")
+            (InOut "-0x80y")
+            (InOut "-0o200y")
+            (InOut "-0b10000000y")
+        ]
+        testList "byte" [
+          checkAll server "can convert MaxValue"
+            "let n = {number} = System.Byte.MaxValue"
+            "255uy"
+            "0xFFuy"
+            "0o377uy"
+            "0b11111111uy"
+          checkAll server "can convert MinValue"
+            "let n = {number} = System.Byte.MinValue"
+            "0uy"
+            "0x0uy"
+            "0o0uy"
+            "0b0uy"
+        ]
+
+        testList "uint64" [
+          checkAll server "can convert MaxValue"
+            "let n = {number} = System.UInt64.MaxValue"
+            "18446744073709551615UL"
+            "0xFFFFFFFFFFFFFFFFUL"
+            "0o1777777777777777777777UL"
+            "0b1111111111111111111111111111111111111111111111111111111111111111UL"
+          checkAll server "can convert MinValue"
+            "let n = {number} = System.UInt64.MinValue"
+            "0UL"
+            "0x0UL"
+            "0o0UL"
+            "0b0UL"
+        ]
+        testList "int64" [
+          // let value = Int64.MinValue in sprintf "\"%i\"\n\"0x%X\"\n\"0o%o\"\n\"0b%B\"" value value value value;;
+          checkAll server "can convert MaxValue"
+            "let n = {number} = System.Int64.MaxValue"
+            "9223372036854775807UL"
+            "0x7FFFFFFFFFFFFFFFUL"
+            "0o777777777777777777777UL"
+            "0b111111111111111111111111111111111111111111111111111111111111111UL"
+          checkAll server "can convert MinValue (no `-`)"
+            "let n = {number} = System.Int64.MinValue"
+            "-9223372036854775808L"
+            "0x8000000000000000L"
+            "0o1000000000000000000000L"
+            "0b1000000000000000000000000000000000000000000000000000000000000000L"
+          checkAllJourneys server "can convert MinValue (keep `-`)"
+            "let n = {number} = System.Int64.MinValue"
+            (JustDestination "-9223372036854775808L")
+            (InOut "-0x8000000000000000L")
+            (InOut "-0o1000000000000000000000L")
+            (InOut "-0b1000000000000000000000000000000000000000000000000000000000000000L")
+        ]
+
+        testList "int (without suffix)" [
+          checkAll server "can convert Int64.MaxValue"
+            "let n = {number} = Int32.MaxValue"
+            "2147483647"
+            "0x7FFFFFFF"
+            "0o17777777777"
+            "0b1111111111111111111111111111111"
+          checkAll server "can convert System.Int32.MinValue"
+            "let n = {number} = System.Int32.MinValue"
+            "-2147483648"
+            "0x80000000"
+            "0o20000000000"
+            "0b10000000000000000000000000000000"
+          checkAllJourneys server "can convert MinValue (keep `-`)"
+            "let n = {number} = System.Int32.MinValue"
+            (JustDestination "-2147483648")
+            (InOut "-0x80000000")
+            (InOut "-0o20000000000")
+            (InOut "-0b10000000000000000000000000000000")
+        ]
+      ]
+
+      testList "types" [
+        let suffixes = [
+          ("sbyte", ["y"])
+          ("byte", ["uy"])
+          ("int16", ["s"])
+          ("uint16", ["us"])
+          ("int32", [""; "l"])
+          ("uint32", ["u"; "ul"])
+          ("nativeint", ["n"])
+          ("unativeint", ["un"])
+          ("int64", ["L"])
+          ("uint64", ["UL"])
+        ]
+
+        for (name, suffixes) in suffixes do
+          testList $"can convert {name}" [
+            for suffix in suffixes do
+              testList $"with suffix {suffix}" [
+                checkAll server $"with value 123"
+                  $"let n = {{number}}{suffix}"
+                  "123"
+                  "0x7B"
+                  "0o173"
+                  "0b1111011"
+                  
+                if not (name.StartsWith "u") && name <> "byte" then
+                  checkAll server $"with value -123"
+                    $"let n = {{number}}{suffix}"
+                    "123"
+                    "0x7B"
+                    "0o173"
+                    "0b1111011"
+              ]
+          ]
+
+        testCaseAsync "does not trigger for bigint" <|
+          CodeFix.checkNotApplicable server
+            "let n = 9999999999999999999999999999$0I"
+            Diagnostics.acceptAll
+            (selectIntCodeFix Base.Hexadecimal)
+      ]
+
+      testList "sign shenanigans" [
+        testList "keep unnecessary sign" [
+          checkAll server "keep + in +123"
+            "let n = {number}"
+            "+123"
+            "+0x7B"
+            "+0o173"
+            "+0b1111011"
+          checkAll server "keep + in +0"
+            "let n = {number}"
+            "+0"
+            "+0x0"
+            "+0o0"
+            "+0b0"
+          checkAll server "keep - in -0"
+            "let n = {number}"
+            "-0"
+            "-0x0"
+            "-0o0"
+            "-0b0"
+          checkAllJourneys server "keep + in +(-123)"
+            "let n = {number}"
+            (JustDestination "-123")
+            (InOut "+0xFFFFFF85")
+            (InOut "+0o37777777605")
+            (InOut "+0b11111111111111111111111110000101")
+        ]
+
+        testList "explicit sign and actual sign do not match" [
+          testList "keep explicit `-` in positive constant" [
+            // Hex/Oct/Bin have sign bit, but can additional have explicit `-` sign
+            checkAllJourneys server "keep - in -(-123)"
+              "let n = {number}"
+              (JustDestination "123")
+              (InOut "-0xFFFFFF85")
+              (InOut "-0o37777777605")
+              (InOut "-0b11111111111111111111111110000101")
+          ] 
+          testList "keep explicit `+` in negative constant" [
+            checkAllJourneys server "keep + in +(-123)"
+              "let n = {number}"
+              (JustDestination "-123")
+              (InOut "+0xFFFFFF85")
+              (InOut "+0o37777777605")
+              (InOut "+0b11111111111111111111111110000101")
+          ]
+        ]
+      ]
+
+      testList "locations" [
+        check server "can convert in math expression"
+          "let n = max (123 + 456$0 / 13 * 17 - 9) (456 - 123)"
+          ""
+          "let n = max (123 + 0x1C8 / 13 * 17 - 9) (456 - 123)"
+          "let n = max (123 + 0o710 / 13 * 17 - 9) (456 - 123)"
+          "let n = max (123 + 0b111001000 / 13 * 17 - 9) (456 - 123)"
+        check server "can convert inside member"
+          """
+          type T() =
+            member _.DoStuff(arg: int) =
+              arg + 3 * 456$0 / 3
+          """
+          ""
+          """
+          type T() =
+            member _.DoStuff(arg: int) =
+              arg + 3 * 0x1C8 / 3
+          """
+          """
+          type T() =
+            member _.DoStuff(arg: int) =
+              arg + 3 * 0o710 / 3
+          """
+          """
+          type T() =
+            member _.DoStuff(arg: int) =
+              arg + 3 * 0b111001000 / 3
+          """
+        testList "can convert in enum" [
+          check server "just value"
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = 456$0
+              | Gamma = 789
+            """
+            ""
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = 0x1C8
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = 0o710
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = 0b111001000
+              | Gamma = 789
+            """
+          check server "in parens"
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (456$0)
+              | Gamma = 789
+            """
+            ""
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (0x1C8)
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (0o710)
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (0b111001000)
+              | Gamma = 789
+            """
+          check server "in app (lhs)"
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (456$0 >>> 2)
+              | Gamma = 789
+            """
+            ""
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (0x1C8 >>> 2)
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (0o710 >>> 2)
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (0b111001000 >>> 2)
+              | Gamma = 789
+            """
+          check server "in app (rhs)"
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (1 <<< 456$0)
+              | Gamma = 789
+            """
+            ""
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (1 <<< 0x1C8)
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (1 <<< 0o710)
+              | Gamma = 789
+            """
+            """
+            type MyEnum =
+              | Alpha = 123
+              | Beta = (1 <<< 0b111001000)
+              | Gamma = 789
+            """
+        ]
+        check server "can convert in pattern"
+          """
+          let f arg =
+            match arg with
+            | 123 -> 1
+            | 456$0 -> 2
+            | 789 -> 3
+            | _ -> -1
+          """
+          ""
+          """
+          let f arg =
+            match arg with
+            | 123 -> 1
+            | 0x1C8 -> 2
+            | 789 -> 3
+            | _ -> -1
+          """
+          """
+          let f arg =
+            match arg with
+            | 123 -> 1
+            | 0o710 -> 2
+            | 789 -> 3
+            | _ -> -1
+          """
+          """
+          let f arg =
+            match arg with
+            | 123 -> 1
+            | 0b111001000 -> 2
+            | 789 -> 3
+            | _ -> -1
+          """
+        check server "can convert with measure"
+          """
+          [<Measure>] type km 
+          let n = 456$0<km>
+          """
+          ""
+          """
+          [<Measure>] type km 
+          let n = 0x1C8<km>
+          """
+          """
+          [<Measure>] type km 
+          let n = 0o710<km>
+          """
+          """
+          [<Measure>] type km 
+          let n = 0b111001000<km>
+          """
+      ]
+          
+      checkAllJourneys server "does not trigger for invalid int"
+        // Value for invalid `SynConst` is always `0` -> cannot convert
+        "let n = {number}"
+        (JustSource "1099511627775")
+        (JustSource "0xFFFFFFFFFF")
+        (JustSource "0o17777777777777")
+        (JustSource "0b1111111111111111111111111111111111111111")
+
+      testCaseAsync "does not trigger on comment after constant" <|
+        CodeFix.checkNotApplicable server
+          "let n = 123 // some$0 comment"
+          Diagnostics.acceptAll
+          (selectIntCodeFix Base.Hexadecimal)
+
+      testList "different upper-lower-cases in bases" [
+        testList "hexadecimal" [
+          testCaseAsync "0x" <|
+            CodeFix.checkApplicable server
+              "let n = 0x123$0"
+              Diagnostics.acceptAll
+              (selectIntCodeFix Base.Decimal)
+          testCaseAsync "0X" <|
+            CodeFix.checkApplicable server
+              "let n = 0X123$0"
+              Diagnostics.acceptAll
+              (selectIntCodeFix Base.Decimal)
+        ]
+        testList "octal" [
+          testCaseAsync "0o" <|
+            CodeFix.checkApplicable server
+              "let n = 0o443$0"
+              Diagnostics.acceptAll
+              (selectIntCodeFix Base.Decimal)
+          testCaseAsync "0O" <|
+            CodeFix.checkApplicable server
+              "let n = 0O443$0"
+              Diagnostics.acceptAll
+              (selectIntCodeFix Base.Decimal)
+        ]
+        testList "binary" [
+          testCaseAsync "0b" <|
+            CodeFix.checkApplicable server
+              "let n = 0b100100011$0"
+              Diagnostics.acceptAll
+              (selectIntCodeFix Base.Decimal)
+          testCaseAsync "0B" <|
+            CodeFix.checkApplicable server
+              "let n = 0B100100011$0"
+              Diagnostics.acceptAll
+              (selectIntCodeFix Base.Decimal)
+        ]
+      ]
+    ])
+
+  module Float =
+    let tests state =
+      serverTestList "Convert float-number in Hex/Oct/Bin to other bases" state defaultConfigDto None (fun server -> [
+        // Note: No Decimal: cannot be represented as Hex/Oct/Bin
+
+        let checkAll 
+          server
+          name template
+          (hexadecimalNumber: String)
+          (octalNumber: String)
+          (binaryNumber: String)
+          =
+          checkAllJourneys server name template
+            (Neither)
+            (InOut hexadecimalNumber)
+            (InOut octalNumber)
+            (InOut binaryNumber)
+
+        testList "can convert pi" [
+          // let value = Math.PI in let bits = BitConverter.DoubleToUInt64Bits(value) in [ $"0x%X{bits}LF"; $"0o%o{bits}LF"; $"0b%B{bits}LF" ];;
+          checkAll server "float"
+            "let n = {number}"
+            "0x400921FB54442D18LF"
+            "0o400111037552421026430LF"
+            "0b100000000001001001000011111101101010100010001000010110100011000LF"
+          // let value = MathF.PI in let bits = BitConverter.SingleToUInt32Bits(value) in [ $"0x%X{bits}lf"; $"0o%o{bits}lf"; $"0b%B{bits}lf" ];;
+          checkAll server "float32"
+            "let n = {number}"
+            "0x40490FDBlf"
+            "0o10022207733lf"
+            "0b1000000010010010000111111011011lf"
+        ]
+        testList "can convert 0" [
+          checkAll server "float"
+            "let n = {number}"
+            "0x0LF"
+            "0o0LF"
+            "0b0LF"
+          checkAll server "float32"
+            "let n = {number}"
+            "0x0lf"
+            "0o0lf"
+            "0b0lf"
+        ]
+        testList "can convert -pi" [
+          checkAll server "float"
+            "let n = {number}"
+            "0xC00921FB54442D18LF"
+            "0o1400111037552421026430LF"
+            "0b1100000000001001001000011111101101010100010001000010110100011000LF"
+          checkAll server "float32"
+            "let n = {number}"
+            "0xC0490FDBlf"
+            "0o30022207733lf"
+            "0b11000000010010010000111111011011lf"
+
+          testList "keep existing `-`" [
+            checkAll server "float"
+              "let n = {number}"
+              "-0x400921FB54442D18LF"
+              "-0o400111037552421026430LF"
+              "-0b100000000001001001000011111101101010100010001000010110100011000LF"
+            checkAll server "float32"
+              "let n = {number}"
+              "-0x40490FDBlf"
+              "-0o10022207733lf"
+              "-0b1000000010010010000111111011011lf"
+          ]
+        ]
+
+        testList "can convert MaxValue" [
+          checkAll server "float"
+            "let n = {number}"
+            "0x7FEFFFFFFFFFFFFFLF"
+            "0o777577777777777777777LF"
+            "0b111111111101111111111111111111111111111111111111111111111111111LF"
+          checkAll server "float32"
+            "let n = {number}"
+            "0x7F7FFFFFlf"
+            "0o17737777777lf"
+            "0b1111111011111111111111111111111lf"
+        ]
+        testList "can convert MinValue" [
+          checkAll server "float"
+            "let n = {number}"
+            "0xFFEFFFFFFFFFFFFFLF"
+            "0o1777577777777777777777LF"
+            "0b1111111111101111111111111111111111111111111111111111111111111111LF"
+          checkAll server "float32"
+            "let n = {number}"
+            "0xFF7FFFFFlf"
+            "0o37737777777lf"
+            "0b11111111011111111111111111111111lf"
+          
+          testList "keep existing `-`" [
+            // Note: unlike int numbers: float is symmetric: `MinValue = - MaxValue` -> just negative bit changed
+            checkAll server "float"
+              "let n = {number}"
+              "-0x7FEFFFFFFFFFFFFFLF"
+              "-0o777577777777777777777LF"
+              "-0b111111111101111111111111111111111111111111111111111111111111111LF"
+            checkAll server "float32"
+              "let n = {number}"
+              "-0x7F7FFFFFlf"
+              "-0o17737777777lf"
+              "-0b1111111011111111111111111111111lf"
+          ]
+        ]
+
+        testList "can convert nan" [
+          // `nan`, `nanf`
+          checkAll server "float - nan"
+            "let n = {number}"
+            "0xFFF8000000000000LF"
+            "0o1777700000000000000000LF"
+            "0b1111111111111000000000000000000000000000000000000000000000000000LF"
+          checkAll server "float32 - nanf"
+            "let n = {number}"
+            "0xFFC00000lf"
+            "0o37760000000lf"
+            "0b11111111110000000000000000000000lf"
+
+          // `nan` that are different from default F# `nan` (-> tests above)
+          checkAll server "float - different nan"
+            "let n = {number}"
+            "0xFFF800C257000000LF"
+            "0o1777700014112700000000LF"
+            "0b1111111111111000000000001100001001010111000000000000000000000000LF"
+          checkAll server "float32 -- different nan"
+            "let n = {number}"
+            "0xFFC00000lf"
+            "0o37760000000lf"
+            "0b11111111110000000000000000000000lf"
+
+        ]
+        testList "can convert infinity" [
+          testList "+" [
+            checkAll server "float"
+              "let n = {number}"
+              "0x7FF0000000000000LF"
+              "0o777600000000000000000LF"
+              "0b111111111110000000000000000000000000000000000000000000000000000LF"
+            checkAll server "float32"
+              "let n = {number}"
+              "0x7F800000lf"
+              "0o17740000000lf"
+              "0b1111111100000000000000000000000lf"
+          ]
+          testList "-" [
+            checkAll server "float"
+              "let n = {number}"
+              "0xFFF0000000000000LF"
+              "0o1777600000000000000000LF"
+              "0b1111111111110000000000000000000000000000000000000000000000000000LF"
+            checkAll server "float32"
+              "let n = {number}"
+              "0xFF800000lf"
+              "0o37740000000lf"
+              "0b11111111100000000000000000000000lf"
+          ]
+        ]
+      ])
+
+module private ConvertCharToOtherForm =
+  let private tryExtractChar (title: String) =
+    let (start, fin) = "Convert to `", "`"
+    if title.StartsWith start && title.EndsWith fin then
+      let c = title.Substring(start.Length, title.Length - start.Length - fin.Length).ToString()
+      let c =
+        if c.Length > 3 && c.StartsWith "'" && c.EndsWith "'B" then
+          // byte char (only when converting from int to char representation. Otherwise no `B` suffix in title)
+          c.Substring(1, c.Length - 2)
+        else
+          c
+      c
+      |> Some
+    else
+      None
+  let private extractFormat (char: String) =
+    if char.StartsWith "\\u" then
+      CharFormat.Utf16Hexadecimal
+    elif char.StartsWith "\\U" then
+      CharFormat.Utf32Hexadecimal
+    elif char.StartsWith "\\x" then
+      CharFormat.Hexadecimal
+    elif char.Length >= 2 && char[0] = '\\' && Char.IsDigit char[1] then
+      CharFormat.Decimal
+    else
+      CharFormat.Char
+  let private tryExtractCharAndFormat (title: String) =
+    tryExtractChar title
+    |> Option.map (fun c -> c, extractFormat c)
+    
+  let selectCharCodeFix (format: CharFormat) =
+    let f (a: CodeAction) =
+      a.Title
+      |> tryExtractCharAndFormat 
+      |> Option.map (snd >> (=) format)
+      |> Option.defaultValue false
+    CodeFix.matching f
+
+  let private checkFormat
+    doc
+    (source: String, cursor: Range)
+    (format: CharFormat)
+    expected
+    =
+    let name = 
+      if String.IsNullOrWhiteSpace expected then
+        $"cannot convert to {format}"
+      else
+        $"can convert to {format}"
+    testCaseAsync name (async {
+      let! (doc, diags) = doc
+      let expected =
+        if String.IsNullOrWhiteSpace expected then
+          ExpectedResult.NotApplicable
+        else
+          ExpectedResult.After expected
+      do! checkFixAt
+            (doc, diags) 
+            (source, cursor) 
+            Diagnostics.acceptAll
+            (selectCharCodeFix (format))
+            expected
+    })
+
+  let check
+    server
+    name
+    (beforeWithCursor: String)
+    (expectedChar: String)
+    (expectedDecimal: String)
+    (expectedHexadecimal: String)
+    (expectedUtf16Hexadecimal: String)
+    (expectedUtf32Hexadecimal: String)
+    =
+    let (cursor, source) = Cursor.assertExtractRange beforeWithCursor
+    documentTestList name server (Server.createUntitledDocument source) (fun doc -> [
+      checkFormat doc (source, cursor) (CharFormat.Char) expectedChar
+      checkFormat doc (source, cursor) (CharFormat.Decimal) expectedDecimal
+      checkFormat doc (source, cursor) (CharFormat.Hexadecimal) expectedHexadecimal
+      checkFormat doc (source, cursor) (CharFormat.Utf16Hexadecimal) expectedUtf16Hexadecimal
+      checkFormat doc (source, cursor) (CharFormat.Utf32Hexadecimal) expectedUtf32Hexadecimal
+    ])
+  /// in `template`: use `{char}` as placeholder
+  let private checkAll
+    server
+    name
+    (template: String)
+    (charValue: String)
+    (decimalValue: String)
+    (hexadecimalValue: String)
+    (utf16HexadecimalValue: String)
+    (utf32HexadecimalValue: String)
+    =
+    let applyTemplate cursor number =
+      let number =
+        if cursor then
+          number + "$0"
+        else
+          number
+      template.Replace("{char}", number)
+
+    testList name [
+      let data = [
+        CharFormat.Char, charValue
+        CharFormat.Decimal, decimalValue
+        CharFormat.Hexadecimal, hexadecimalValue
+        CharFormat.Utf16Hexadecimal, utf16HexadecimalValue
+        CharFormat.Utf32Hexadecimal, utf32HexadecimalValue
+      ]
+      let valueOf (format) = 
+        data
+        |> List.find (fun (b,_) -> b = format)
+        |> snd
+      for (format, value) in data do
+        if String.IsNullOrEmpty value then
+          ()
+        else
+          let mkExpected (f) =
+            if format = f || String.IsNullOrEmpty (valueOf f) then 
+              ""
+            else
+              applyTemplate false (valueOf f)
+          check server $"can convert from {format}"
+            (applyTemplate true value)
+            (mkExpected CharFormat.Char)
+            (mkExpected CharFormat.Decimal)
+            (mkExpected CharFormat.Hexadecimal)
+            (mkExpected CharFormat.Utf16Hexadecimal)
+            (mkExpected CharFormat.Utf32Hexadecimal)
+    ]
+      
+  let tests state =
+    serverTestList "Convert char" state defaultConfigDto None (fun server -> [
+      checkAll server "can convert ç"
+        "let c = '{char}'"
+        "ç"
+        "\\231"
+        "\\xE7"
+        "\\u00E7"
+        "\\U000000E7"
+      checkAll server "can convert \\n"
+        "let c = '{char}'"
+        "\\n"
+        "\\010"
+        "\\x0A"
+        "\\u000A"
+        "\\U0000000A"
+      checkAll server "can convert \\000 except to char"
+        "let c = '{char}'"
+        ""
+        "\\000"
+        "\\x00"
+        "\\u0000"
+        "\\U00000000"
+
+      checkAll server "can convert \\u2248 only to formats that are big enough"
+        "let c = '{char}'"
+        "≈"
+        ""
+        ""
+        "\\u2248"
+        "\\U00002248"
+
+      checkAll server "can convert single quotation mark"
+        "let c = '{char}'"
+        "\\\'"
+        "\\039"
+        "\\x27"
+        "\\u0027"
+        "\\U00000027"
+      
+      checkAll server "can convert unescaped double quotation mark"
+        "let c = '{char}'"
+        "\""
+        "\\034"
+        "\\x22"
+        "\\u0022"
+        "\\U00000022"
+      // Note: Just check from `'"` to number forms. 
+      //       Other directions produce unescaped quotation mark
+      //       -> Handled in test above
+      check server "can convert escaped double quotation mark"
+        "let c = '\"$0'"
+        "" 
+        "let c = '\\034'"
+        "let c = '\\x22'"
+        "let c = '\\u0022'"
+        "let c = '\\U00000022'"
+
+      testList "byte" [
+        let checkAll
+          server
+          name
+          (template: String)
+          (charValue: String)
+          (decimalValue: String)
+          (hexadecimalValue: String)
+          (utf16HexadecimalValue: String)
+          (utf32HexadecimalValue: String)
+          =
+          // Note: `\x` & `\U` are currently not supported for byte char
+          //TODO: change once supported was added
+          checkAll server name template
+            charValue
+            decimalValue
+            ""
+            utf16HexadecimalValue
+            ""
+
+        checkAll server "can convert f"
+          "let c = '{char}'B"
+          "f"
+          "\\102"
+          "\\x66"
+          "\\u0066"
+          "\\U00000066"
+        checkAll server "can convert \\n"
+          "let c = '{char}'B"
+          "\\n"
+          "\\010"
+          "\\x0A"
+          "\\u000A"
+          "\\U0000000A"
+        checkAll server "can convert \\000 except to char"
+          "let c = '{char}'B"
+          ""
+          "\\000"
+          "\\x00"
+          "\\u0000"
+          "\\U00000000"
+        check server "does not trigger for char outside of byte range"
+          "let c = 'ç$0'B"
+          "" "" "" "" ""
+      ]
+    ])
+
+module private ConvertByteBetweenIntAndChar =
+  let tests state =
+    serverTestList "Convert Byte between Int And Char" state defaultConfigDto None (fun server -> [
+      let template = sprintf "let c = %s"
+      let charTemplate (c: string) = template $"'%s{c}'B"
+      ConvertCharToOtherForm.check server "can convert from int to char"
+        (template "102$0uy")
+        (charTemplate "f")
+        (charTemplate "\\102")
+        ""// (charTemplate "\\x66")
+        (charTemplate "\\u0066")
+        ""// (charTemplate "\\U00000066")
+
+      let template = sprintf "let c = %s"
+      let intTemplate (c: string) = template $"%s{c}uy"
+      ConvertIntToOtherBase.check server "can convert from char to int"
+        (template "'f$0'B")
+        (intTemplate "102")
+        (intTemplate "0x66")
+        (intTemplate "0o146")
+        (intTemplate "0b1100110")
+
+      testCaseAsync "cannot convert from int > 127 to char" <|
+        CodeFix.checkNotApplicable server
+          "let c = 250$0uy"
+          Diagnostics.acceptAll
+          (ConvertCharToOtherForm.selectCharCodeFix CharFormat.Char)
+      testCaseAsync "cannot convert from char > 127 to int" <|
+        CodeFix.checkNotApplicable server
+          "let c = 'ú$0'B;"
+          Diagnostics.acceptAll
+          (ConvertIntToOtherBase.selectIntCodeFix Base.Decimal)
+    ])
+
+module private AddDigitGroupSeparator =
+  let private intTests state =
+    serverTestList "To int numbers" state defaultConfigDto None (fun server -> [
+      testCaseAsync "can add separator to long decimal int" <|
+        CodeFix.check server
+          "let value = 1234567890$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+          "let value = 1_234_567_890"
+      testCaseAsync "cannot add separator short decimal int" <|
+        CodeFix.checkNotApplicable server
+          "let value = 123$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+      testCaseAsync "cannot add separator to decimal int with existing separator" <|
+        CodeFix.checkNotApplicable server
+          "let value = 123456789_0$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+      testCaseAsync "can add separator to long negative decimal int" <|
+        CodeFix.check server
+          "let value = -1234567890$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+          "let value = -1_234_567_890"
+      testCaseAsync "can add separator to decimal int with leading zeros" <|
+        CodeFix.check server
+          "let value = 0000000090$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+          "let value = 0_000_000_090"
+      testCaseAsync "can add separator to too-long decimal int" <|
+        CodeFix.check server
+          "let value = 12345678901234567890$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+          "let value = 12_345_678_901_234_567_890"
+      testCaseAsync "can add separator to long decimal int64" <|
+        CodeFix.check server
+          "let value = 12345678901234567L$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+          "let value = 12_345_678_901_234_567L"
+
+      testList "can add separator to hexadecimal int" [
+        testCaseAsync "words" <|
+          CodeFix.check server
+            "let value = 0x1234578$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Separate.hexadecimal4)
+            "let value = 0x123_4578"
+        testCaseAsync "bytes" <|
+          CodeFix.check server
+            "let value = 0x1234578$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Separate.hexadecimal2)
+            "let value = 0x1_23_45_78"
+      ]
+      testCaseAsync "can add separator to octal int" <|
+        CodeFix.check server
+          "let value = 0o1234567$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.octal3)
+          "let value = 0o1_234_567"
+      testList "can add separator to binary int" [
+        testCaseAsync "nibbles" <|
+          CodeFix.check server
+            "let value = 0b1010101010101010101$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Separate.binary4)
+            "let value = 0b101_0101_0101_0101_0101"
+        testCaseAsync "bytes" <|
+          CodeFix.check server
+            "let value = 0b1010101010101010101$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Separate.binary8)
+            "let value = 0b101_01010101_01010101"
+      ]
+      testCaseAsync "can add separator to bigint" <|
+        CodeFix.check server
+          "let value = 9999999999999999999999999999$0I"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+          "let value = 9_999_999_999_999_999_999_999_999_999I"
+
+      testCaseAsync "does not trigger for short number" <|
+        CodeFix.checkNotApplicable server
+          "let value = 123$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Int.Separate.decimal3)
+    ])
+
+  let private floatTests state =
+    serverTestList "To float numbers" state defaultConfigDto None (fun server -> [
+      testCaseAsync "can add separator to X.X float" <|
+        CodeFix.check server
+          "let value = 1234567.01234567$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567.012_345_67"
+      testCaseAsync "can add separator to X.XeX float" <|
+        CodeFix.check server
+          "let value = 1234567.01234567e12345678$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567.012_345_67e12_345_678"
+      testCaseAsync "can add separator to X. float" <|
+        CodeFix.check server
+          "let value = 1234567.$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567."
+      testCaseAsync "can add separator to XeX float" <|
+        CodeFix.check server
+          "let value = 1234567e12345678$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567e12_345_678"
+
+      testCaseAsync "can add separator to float32" <|
+        CodeFix.check server
+          "let value = 1234567.01234567f$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567.012_345_67f"
+      testCaseAsync "can add separator to decimal" <|
+        CodeFix.check server
+          "let value = 1234567.01234567m$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567.012_345_67m"
+
+      testCaseAsync "keep sign" <|
+        CodeFix.check server
+          "let value = -1234567.01234567e12345678$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = -1_234_567.012_345_67e12_345_678"
+      testCaseAsync "keep sign for exponent" <|
+        CodeFix.check server
+          "let value = 1234567.01234567e+12345678$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567.012_345_67e+12_345_678"
+
+      testCaseAsync "cannot add separator when existing separator" <|
+        CodeFix.checkNotApplicable server
+          "let value = 1234567.0123_4567$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+
+      testCaseAsync "does not trigger for short number" <|
+        CodeFix.checkNotApplicable server
+          "let value = 123.012e123$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+
+      testCaseAsync "can add separator to just decimal part when other parts are too short" <|
+        CodeFix.check server
+          "let value = 123.01234567e+123$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 123.012_345_67e+123"
+      testCaseAsync "can add separator to just int part when other parts are too short" <|
+        CodeFix.check server
+          "let value = 1234567.012e+123$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 1_234_567.012e+123"
+      testCaseAsync "can add separator to just exponent part when other parts are too short" <|
+        CodeFix.check server
+          "let value = 123.012e+1234567$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 123.012e+1_234_567"
+      testCaseAsync "can add separator to decimal & exponent parts when int part is too short" <|
+        CodeFix.check server
+          "let value = 123.012345678e+1234567$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle Title.Float.Separate.all3)
+          "let value = 123.012_345_678e+1_234_567"
+    ])
+
+  let tests state =
+    testList "Add Digit Group Separator" [
+      intTests state
+      floatTests state
+    ]
+
+module private ReplaceWithName =
+  /// Note: `System` is `open`
+  let checkReplaceWith server tyName value fieldName =
+    let replacement = $"{tyName}.{fieldName}"
+    CodeFix.check server
+      $"open System\nlet value = {value}$0"
+      Diagnostics.acceptAll
+      (CodeFix.withTitle (Title.replaceWith replacement))
+      $"open System\nlet value = {replacement}"
+  let checkCannotReplaceWith server tyName value fieldName =
+    let replacement = $"{tyName}.{fieldName}"
+    CodeFix.checkNotApplicable server
+      $"open System\nlet value = {value}$0"
+      Diagnostics.acceptAll
+      (CodeFix.withTitle (Title.replaceWith replacement))
+
+  let private intTests state =
+    serverTestList "Replace Int" state defaultConfigDto None (fun server -> [
+      let checkReplaceWith = checkReplaceWith server
+      let checkCannotReplaceWith = checkCannotReplaceWith server
+
+      /// Formats with suffix
+      let inline format value = sprintf "%A" value
+
+      testList "can replace SByte" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.SByte) (format SByte.MaxValue) (nameof System.SByte.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.SByte) (format SByte.MinValue) (nameof(System.SByte.MinValue))
+      ]
+      testList "can replace Byte" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.Byte) (format Byte.MaxValue) (nameof System.Byte.MaxValue)
+        testCaseAsync "not with MinValue" <|
+          checkCannotReplaceWith (nameof System.Byte) (format Byte.MinValue) (nameof(System.Byte.MinValue))
+      ]
+      testList "can replace Int16" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.Int16) (format Int16.MaxValue) (nameof System.Int16.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.Int16) (format Int16.MinValue) (nameof(System.Int16.MinValue))
+      ]
+      testList "can replace UInt16" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.UInt16) (format UInt16.MaxValue) (nameof System.UInt16.MaxValue)
+        testCaseAsync "not with MinValue" <|
+          checkCannotReplaceWith (nameof System.UInt16) (format UInt16.MinValue) (nameof(System.UInt16.MinValue))
+      ]
+      testList "can replace Int32" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.Int32) (format Int32.MaxValue) (nameof System.Int32.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.Int32) (format Int32.MinValue) (nameof(System.Int32.MinValue))
+      ]
+      testList "can replace UInt32" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.UInt32) (format UInt32.MaxValue) (nameof System.UInt32.MaxValue)
+        testCaseAsync "not with MinValue" <|
+          checkCannotReplaceWith (nameof System.UInt32) (format UInt32.MinValue) (nameof(System.UInt32.MinValue))
+      ]
+      testList "can replace NativeInt" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.IntPtr) (format IntPtr.MaxValue) (nameof System.IntPtr.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.IntPtr) (format IntPtr.MinValue) (nameof(System.IntPtr.MinValue))
+      ]
+      testList "can replace UNativeInt" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.UIntPtr) (format UIntPtr.MaxValue) (nameof System.UIntPtr.MaxValue)
+        testCaseAsync "not with MinValue" <|
+          checkCannotReplaceWith (nameof System.UIntPtr) (format UIntPtr.MinValue) (nameof(System.UIntPtr.MinValue))
+      ]
+      testList "can replace Int64" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.Int64) (format Int64.MaxValue) (nameof System.Int64.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.Int64) (format Int64.MinValue) (nameof(System.Int64.MinValue))
+      ]
+      testList "can replace UInt64" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.UInt64) (format UInt64.MaxValue) (nameof System.UInt64.MaxValue)
+        testCaseAsync "not with MinValue" <|
+          checkCannotReplaceWith (nameof System.UInt64) (format UInt64.MinValue) (nameof(System.UInt64.MinValue))
+      ]
+
+      testCaseAsync "Emit leading System if System not open" <|
+        CodeFix.check server
+          $"let value = {format Int32.MaxValue}$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle (Title.replaceWith "Int32.MaxValue"))
+          $"let value = System.Int32.MaxValue"
+    ])
+
+  let private floatTests state =
+    serverTestList "Replace Float" state defaultConfigDto None (fun server -> [
+      // Beware of rounding in number printing!
+      // For example:
+      // ```fsharp
+      // > Double.MaxValue;;
+      // val it: float = 1.797693135e+308
+      // > 1.797693135e+308;;
+      // val it: float = infinity
+
+      // > Double.MaxValue.ToString();;
+      // val it: string = "1.7976931348623157E+308"
+      // ```
+
+      let checkReplaceWith = checkReplaceWith server
+      let checkCannotReplaceWith = checkCannotReplaceWith server
+      let checkReplaceWith' value name =
+        CodeFix.check server
+          $"let value = {value}$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle (Title.replaceWith name))
+          $"let value = {name}"
+
+      testList "can replace float" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.Double) "1.7976931348623157E+308" (nameof System.Double.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.Double) "-1.7976931348623157E+308" (nameof System.Double.MinValue)
+        testCaseAsync "with Epsilon" <|
+          checkReplaceWith (nameof System.Double) "5E-324" (nameof System.Double.Epsilon)
+        testCaseAsync "with infinity" <|
+          checkReplaceWith' "123456789e123456789" "infinity"
+        testCaseAsync "with infinity (int)" <|
+          checkReplaceWith' "0x7FF0000000000000LF" "infinity"
+        testCaseAsync "with -infinity" <|
+          checkReplaceWith' "-123456789e123456789" "-infinity"
+        testCaseAsync "with -infinity (int)" <|
+          checkReplaceWith' "0o1777600000000000000000LF" "-infinity"
+        testCaseAsync "with nan (int)" <|
+          checkReplaceWith' "0b1111111111111000000100010001010010010010001000100010001000100100LF" "nan"
+      ]
+      testList "can replace float32" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.Single) "3.4028235E+38f" (nameof System.Single.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.Single) "-3.4028235E+38f" (nameof System.Single.MinValue)
+        testCaseAsync "with Epsilon" <|
+          checkReplaceWith (nameof System.Single) "1.401298464e-45f" (nameof System.Single.Epsilon)
+        testCaseAsync "with infinity" <|
+          checkReplaceWith' "123456789e123456789f" "infinityf"
+        testCaseAsync "with infinity (int)" <|
+          checkReplaceWith' "0x7F800000lf" "infinityf"
+        testCaseAsync "with -infinity" <|
+          checkReplaceWith' "-123456789e123456789f" "-infinityf"
+        testCaseAsync "with -infinity (int)" <|
+          checkReplaceWith' "0o37740000000lf" "-infinityf"
+        testCaseAsync "with nan (int)" <|
+          checkReplaceWith' "0b1111111101001000100100100100100lf" "nanf"
+      ]
+
+      testCaseAsync "Emit leading System if System not open" <|
+        CodeFix.check server
+          $"let value = 1.7976931348623157E+308$0"
+          Diagnostics.acceptAll
+          (CodeFix.withTitle (Title.replaceWith "Double.MaxValue"))
+          $"let value = System.Double.MaxValue"
+
+      testList "can replace decimal" [
+        testCaseAsync "with MaxValue" <|
+          checkReplaceWith (nameof System.Decimal) "79228162514264337593543950335m" (nameof System.Decimal.MaxValue)
+        testCaseAsync "with MinValue" <|
+          checkReplaceWith (nameof System.Decimal) "-79228162514264337593543950335m" (nameof System.Decimal.MinValue)
+      ]
+
+    ])
+  let tests state = 
+    testList "Replace With Name" [
+      intTests state
+      floatTests state
+    ]
+
+module SignHelpers =
+  let tests state =
+    serverTestList "Sign Helpers" state defaultConfigDto None (fun server -> [
+      testList "extract `-`" [
+        testCaseAsync "from bin int" <|
+          CodeFix.check server
+            "let value = 0b10000101y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.extractMinusFromNegativeConstant)
+            "let value = -0b1111011y"
+        testCaseAsync "from hex int" <|
+          CodeFix.check server
+            "let value = 0x85y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.extractMinusFromNegativeConstant)
+            "let value = -0x7By"
+        testCaseAsync "from oct int" <|
+          CodeFix.check server
+            "let value = 0o205y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.extractMinusFromNegativeConstant)
+            "let value = -0o173y"
+        testCaseAsync "does not trigger for decimal int" <|
+          CodeFix.checkNotApplicable server
+            "let value = -123y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.extractMinusFromNegativeConstant)
+      ]
+      testList "integrate `-`" [
+        testCaseAsync "into bin int" <|
+          CodeFix.check server
+            "let value = -0b1111011y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.integrateExplicitMinus)
+            "let value = 0b10000101y"
+        testCaseAsync "into hex int" <|
+          CodeFix.check server
+            "let value = -0x7By$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.integrateExplicitMinus)
+            "let value = 0x85y"
+        testCaseAsync "into oct int" <|
+          CodeFix.check server
+            "let value = -0o173y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.integrateExplicitMinus)
+            "let value = 0o205y"
+        testCaseAsync "does not trigger for decimal int" <|
+          CodeFix.checkNotApplicable server
+            "let value = -123y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.integrateExplicitMinus)
+      ]
+
+      testList "MinValue" [
+        testCaseAsync "can remove explicit `-`" <|
+          CodeFix.check server
+            "let value = -0b10000000y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.removeExplicitMinusWithMinValue)
+            "let value = 0b10000000y"
+        testCaseAsync "does not trigger for decimal int" <|
+          CodeFix.checkNotApplicable server
+            "let value = -127y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.removeExplicitMinusWithMinValue)
+      ]
+
+      testList "use implicit `+`" [
+        testCaseAsync "can change to positive" <|
+          CodeFix.check server
+            "let value = -0b1111_1101y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.useImplicitPlusInPositiveConstantWithMinusSign)
+            "let value = 0b11y"
+      ]
+
+      testList "ensure valid sign" [
+        // QuickFixes might add sign which might lead to invalid code:
+        // ```fsharp
+        // //             -91y
+        // let value = 5y+0b1010_0101y
+
+        // // => Convert to decimal
+
+        // let value = 5y+-91y
+        // //            ^^
+        // //            The type 'sbyte' does not support the operator '+-'
+        // ```
+        //
+        // -> insert space before sign if necessary
+
+        testCaseAsync "add space when new `-` sign immediately after `+`" <|
+          CodeFix.check server
+            "let value = 5y+0b1010_0101y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.toDecimal)
+            "let value = 5y+ -91y"
+        testCaseAsync "don't add space when `-` with space before" <|
+          CodeFix.check server
+            "let value = 5y+ 0b1010_0101y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.toDecimal)
+            "let value = 5y+ -91y"
+        testCaseAsync "don't add space when new `-` sign immediately after `(`" <|
+          CodeFix.check server
+            "let value = 5y+(0b1010_0101y$0)"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.toDecimal)
+            "let value = 5y+(-91y)"
+        testCaseAsync "add space when new `-` sign immediately after `<|`" <|
+          CodeFix.check server
+            "let value = max 5y <|0b1010_0101y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.toDecimal)
+            "let value = max 5y <| -91y"
+        testCaseAsync "don't add space when no new `-` sign" <|
+          CodeFix.check server
+            "let value = 5y+0b1011011y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.toDecimal)
+            "let value = 5y+91y"
+
+        testCaseAsync "add space when convert to other base" <|
+          CodeFix.check server
+            "let value = 5y+0b1010_0101y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.toDecimal)
+            "let value = 5y+ -91y"
+        testCaseAsync "add space when extract `-`" <|
+          CodeFix.check server
+            "let value = 5y+0b10000101y$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle Title.Int.Convert.SpecialCase.extractMinusFromNegativeConstant)
+            "let value = 5y+ -0b1111011y"
+
+        testCaseAsync "add space when convert to `-infinity`" <|
+          CodeFix.check server
+            "let value = 5.0+0o1777600000000000000000LF$0"
+            Diagnostics.acceptAll
+            (CodeFix.withTitle (Title.replaceWith "-infinity"))
+            "let value = 5.0+ -infinity"
+      ]
+    ])
+
+let tests state =
+  testList (nameof AdjustConstant) [
+    ConvertIntToOtherBase.tests state
+    ConvertIntToOtherBase.Float.tests state
+    ConvertCharToOtherForm.tests state
+    ConvertByteBetweenIntAndChar.tests state
+    
+    ReplaceWithName.tests state
+    SignHelpers.tests state
+
+    AddDigitGroupSeparator.tests state
+  ]
diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
index 9230d36a8..ab2d0093e 100644
--- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
+++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
@@ -3304,51 +3304,50 @@ let private removePatternArgumentTests state =
         let (None) = None
         """ ])
 
-let tests state =
-  testList
-    "CodeFix-tests"
-    [ HelpersTests.tests
-
-      AddExplicitTypeAnnotationTests.tests state
-      ToInterpolatedStringTests.tests state
-      ToInterpolatedStringTests.unavailableTests state
-      addMissingEqualsToTypeDefinitionTests state
-      addMissingFunKeywordTests state
-      addMissingInstanceMemberTests state
-      addMissingRecKeywordTests state
-      addMissingXmlDocumentationTests state
-      addNewKeywordToDisposableConstructorInvocationTests state
-      addTypeToIndeterminateValueTests state
-      changeDerefBangToValueTests state
-      changeDowncastToUpcastTests state
-      changeEqualsInFieldTypeToColonTests state
-      changePrefixNegationToInfixSubtractionTests state
-      changeRefCellDerefToNotTests state
-      changeTypeOfNameToNameOfTests state
-      convertBangEqualsToInequalityTests state
-      convertCSharpLambdaToFSharpLambdaTests state
-      convertDoubleEqualsToSingleEqualsTests state
-      convertInvalidRecordToAnonRecordTests state
-      convertPositionalDUToNamedTests state
-      convertTripleSlashCommentToXmlTaggedDocTests state
-      addPrivateAccessModifierTests state
-      GenerateAbstractClassStubTests.tests state
-      generateRecordStubTests state
-      generateUnionCasesTests state
-      generateXmlDocumentationTests state
-      ImplementInterfaceTests.tests state
-      makeDeclarationMutableTests state
-      makeOuterBindingRecursiveTests state
-      removeRedundantQualifierTests state
-      removeUnnecessaryReturnOrYieldTests state
-      removeUnusedBindingTests state
-      removeUnusedOpensTests state
-      RenameParamToMatchSignatureTests.tests state
-      renameUnusedValue state
-      replaceWithSuggestionTests state
-      resolveNamespaceTests state
-      useMutationWhenValueIsMutableTests state
-      useTripleQuotedInterpolationTests state
-      wrapExpressionInParenthesesTests state
-      removeRedundantAttributeSuffixTests state
-      removePatternArgumentTests state ]
+let tests state = testList "CodeFix-tests" [ 
+  HelpersTests.tests
+  AddExplicitTypeAnnotationTests.tests state
+  AdjustConstantTests.tests state
+  ToInterpolatedStringTests.tests state
+  ToInterpolatedStringTests.unavailableTests state
+  addMissingEqualsToTypeDefinitionTests state
+  addMissingFunKeywordTests state
+  addMissingInstanceMemberTests state
+  addMissingRecKeywordTests state
+  addMissingXmlDocumentationTests state
+  addNewKeywordToDisposableConstructorInvocationTests state
+  addTypeToIndeterminateValueTests state
+  changeDerefBangToValueTests state
+  changeDowncastToUpcastTests state
+  changeEqualsInFieldTypeToColonTests state
+  changePrefixNegationToInfixSubtractionTests state
+  changeRefCellDerefToNotTests state
+  changeTypeOfNameToNameOfTests state
+  convertBangEqualsToInequalityTests state
+  convertCSharpLambdaToFSharpLambdaTests state
+  convertDoubleEqualsToSingleEqualsTests state
+  convertInvalidRecordToAnonRecordTests state
+  convertPositionalDUToNamedTests state
+  convertTripleSlashCommentToXmlTaggedDocTests state
+  addPrivateAccessModifierTests state
+  GenerateAbstractClassStubTests.tests state
+  generateRecordStubTests state
+  generateUnionCasesTests state
+  generateXmlDocumentationTests state
+  ImplementInterfaceTests.tests state
+  makeDeclarationMutableTests state
+  makeOuterBindingRecursiveTests state
+  removeRedundantQualifierTests state
+  removeUnnecessaryReturnOrYieldTests state
+  removeUnusedBindingTests state
+  removeUnusedOpensTests state
+  RenameParamToMatchSignatureTests.tests state
+  renameUnusedValue state
+  replaceWithSuggestionTests state
+  resolveNamespaceTests state
+  useMutationWhenValueIsMutableTests state
+  useTripleQuotedInterpolationTests state
+  wrapExpressionInParenthesesTests state
+  removeRedundantAttributeSuffixTests state
+  removePatternArgumentTests state
+]
