From 15b8219d20c4cca39dcd5aa70e1b0c380733d584 Mon Sep 17 00:00:00 2001 From: dawe Date: Sun, 5 Nov 2023 19:46:20 +0100 Subject: [PATCH] do ordinal string comparisons faster and more correct as our intent is to do symbolic compares --- src/FsAutoComplete.Core/CodeGeneration.fs | 26 ++-- src/FsAutoComplete.Core/Commands.fs | 9 +- .../CompilerServiceInterface.fs | 14 ++- .../DocumentationFormatter.fs | 22 ++-- src/FsAutoComplete.Core/DotnetNewTemplate.fs | 4 +- src/FsAutoComplete.Core/FCSPatches.fs | 2 +- src/FsAutoComplete.Core/FileSystem.fs | 2 +- src/FsAutoComplete.Core/InlayHints.fs | 13 +- src/FsAutoComplete.Core/Lexer.fs | 5 +- .../ParseAndCheckResults.fs | 4 +- src/FsAutoComplete.Core/SignatureFormatter.fs | 15 ++- src/FsAutoComplete.Core/SignatureHelp.fs | 6 +- src/FsAutoComplete.Core/State.fs | 4 +- src/FsAutoComplete.Core/TestAdapter.fs | 118 +++++++++--------- src/FsAutoComplete.Core/TipFormatter.fs | 11 +- src/FsAutoComplete.Core/TypedAstUtils.fs | 12 +- src/FsAutoComplete.Core/Utils.fs | 17 +-- .../CodeFixes/AdjustConstant.fs | 3 +- ...ConvertTripleSlashCommentToXmlTaggedDoc.fs | 4 +- .../RemoveRedundantAttributeSuffix.fs | 3 +- .../RemoveUnnecessaryReturnOrYield.fs | 9 +- .../CodeFixes/RemoveUnusedBinding.fs | 7 +- .../CodeFixes/RenameParamToMatchSignature.fs | 5 +- .../CodeFixes/ResolveNamespace.fs | 14 ++- .../CodeFixes/ToInterpolatedString.fs | 5 +- src/FsAutoComplete/CommandResponse.fs | 2 +- src/FsAutoComplete/LspHelpers.fs | 9 +- .../LspServers/AdaptiveFSharpLspServer.fs | 7 +- .../LspServers/AdaptiveServerState.fs | 2 +- src/FsAutoComplete/Parser.fs | 4 +- .../CodeFixTests/AdjustConstantTests.fs | 12 +- .../CodeFixTests/Tests.fs | 3 +- .../CompletionTests.fs | 6 +- .../FindReferencesTests.fs | 7 +- test/FsAutoComplete.Tests.Lsp/GoToTests.fs | 6 +- test/FsAutoComplete.Tests.Lsp/Helpers.fs | 2 +- test/FsAutoComplete.Tests.Lsp/Program.fs | 8 +- .../Utils/TextEdit.Tests.fs | 10 +- .../Utils/TextEdit.fs | 8 +- 39 files changed, 251 insertions(+), 169 deletions(-) diff --git a/src/FsAutoComplete.Core/CodeGeneration.fs b/src/FsAutoComplete.Core/CodeGeneration.fs index ec45756d4..a66fa48fd 100644 --- a/src/FsAutoComplete.Core/CodeGeneration.fs +++ b/src/FsAutoComplete.Core/CodeGeneration.fs @@ -302,8 +302,10 @@ module CodeGenerationUtils = let displayName = v.DisplayName if - (v.IsPropertyGetterMethod && displayName.StartsWith("get_")) - || (v.IsPropertySetterMethod && displayName.StartsWith("set_")) + (v.IsPropertyGetterMethod + && displayName.StartsWith("get_", StringComparison.Ordinal)) + || (v.IsPropertySetterMethod + && displayName.StartsWith("set_", StringComparison.Ordinal)) then displayName.[4..] else @@ -328,7 +330,7 @@ module CodeGenerationUtils = (if String.IsNullOrWhiteSpace(args) then "" - elif args.StartsWith("(") then + elif args.StartsWith("(", StringComparison.Ordinal) then args elif v.CurriedParameterGroups.Count > 1 && (not verboseMode) then " " + args @@ -345,7 +347,10 @@ module CodeGenerationUtils = | _, _, ".ctor", _ -> "new" + parArgs // Properties (skipping arguments) | _, true, _, name when v.IsPropertyGetterMethod || v.IsPropertySetterMethod -> - if name.StartsWith("get_") || name.StartsWith("set_") then + if + name.StartsWith("get_", StringComparison.Ordinal) + || name.StartsWith("set_", StringComparison.Ordinal) + then name.[4..] else name @@ -576,14 +581,14 @@ module CodeGenerationUtils = | SynBinding(valData = SynValData(Some mf, _, _); headPat = LongIdentPattern(name, range); trivia = trivia) when mf.MemberKind = SynMemberKind.PropertyGet -> - if name.StartsWith("get_") then + if name.StartsWith("get_", StringComparison.Ordinal) then Some(name, range, trivia.LeadingKeyword.Range) else Some("get_" + name, range, trivia.LeadingKeyword.Range) | SynBinding(valData = SynValData(Some mf, _, _); headPat = LongIdentPattern(name, range); trivia = trivia) when mf.MemberKind = SynMemberKind.PropertySet -> - if name.StartsWith("set_") then + if name.StartsWith("set_", StringComparison.Ordinal) then Some(name, range, trivia.LeadingKeyword.Range) else Some("set_" + name, range, trivia.LeadingKeyword.Range) @@ -594,9 +599,12 @@ module CodeGenerationUtils = let normalizeEventName (m: FSharpMemberOrFunctionOrValue) = let name = m.DisplayName - if name.StartsWith("add_") then name.[4..] - elif name.StartsWith("remove_") then name.[7..] - else name + if name.StartsWith("add_", StringComparison.Ordinal) then + name.[4..] + elif name.StartsWith("remove_", StringComparison.Ordinal) then + name.[7..] + else + name /// Ideally this info should be returned in error symbols from FCS. /// Because it isn't, we implement a crude way of getting member signatures: diff --git a/src/FsAutoComplete.Core/Commands.fs b/src/FsAutoComplete.Core/Commands.fs index 0c2856a17..0130445c6 100644 --- a/src/FsAutoComplete.Core/Commands.fs +++ b/src/FsAutoComplete.Core/Commands.fs @@ -309,7 +309,7 @@ module Commands = if (e.Kind LookupType.Fuzzy) = EntityKind.Attribute - && lastIdent.EndsWith "Attribute" + && lastIdent.EndsWith("Attribute", StringComparison.Ordinal) then yield e.TopRequireQualifiedAccessParent, @@ -706,7 +706,7 @@ module Commands = |> Seq.tryFind (fun l -> let lineStr = getLine l // namespace MUST be top level -> no indentation - lineStr.StartsWith "namespace ") + lineStr.StartsWith("namespace ", StringComparison.Ordinal)) |> function // move to the next line below "namespace" | Some l -> l.IncLine() @@ -1000,7 +1000,10 @@ module Commands = // -> only check if no backticks let newBacktickedName = newName |> PrettyNaming.NormalizeIdentifierBackticks - if newBacktickedName.StartsWith "``" && newBacktickedName.EndsWith "``" then + if + newBacktickedName.StartsWith("``", StringComparison.Ordinal) + && newBacktickedName.EndsWith("``", StringComparison.Ordinal) + then return newBacktickedName elif PrettyNaming.IsIdentifierName newName then return newName diff --git a/src/FsAutoComplete.Core/CompilerServiceInterface.fs b/src/FsAutoComplete.Core/CompilerServiceInterface.fs index a75bf8fb9..d0392fa32 100644 --- a/src/FsAutoComplete.Core/CompilerServiceInterface.fs +++ b/src/FsAutoComplete.Core/CompilerServiceInterface.fs @@ -68,14 +68,14 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize, parallelRefe let toReplace, otherOpts = p.OtherOptions |> Array.partition (fun opt -> - opt.EndsWith "FSharp.Core.dll" - || opt.EndsWith "FSharp.Compiler.Interactive.Settings.dll") + opt.EndsWith("FSharp.Core.dll", StringComparison.Ordinal) + || opt.EndsWith("FSharp.Compiler.Interactive.Settings.dll", StringComparison.Ordinal)) { p with OtherOptions = Array.append otherOpts [| $"-r:%s{fsc.FullName}"; $"-r:%s{fsi.FullName}" |] } let (|StartsWith|_|) (prefix: string) (s: string) = - if s.StartsWith(prefix) then + if s.StartsWith(prefix, StringComparison.Ordinal) then Some(s.[prefix.Length ..]) else None @@ -102,7 +102,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, StringComparison.Ordinal)) fun (projOptions: FSharpProjectOptions) -> { projOptions with @@ -120,7 +120,11 @@ 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:", StringComparison.Ordinal) 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 6220d2cba..2512352cf 100644 --- a/src/FsAutoComplete.Core/DocumentationFormatter.fs +++ b/src/FsAutoComplete.Core/DocumentationFormatter.fs @@ -104,7 +104,7 @@ module DocumentationFormatter = let t = Regex.Replace(org, """<.*>""", "<") [ yield formatShowDocumentationLink t xmlDocSig assemblyName - if t.EndsWith "<" then + if t.EndsWith("<", StringComparison.Ordinal) then yield! renderedGenericArgumentTypes |> Seq.intersperse (", ", 2) yield formatShowDocumentationLink ">" xmlDocSig assemblyName ] @@ -217,7 +217,7 @@ module DocumentationFormatter = let typeList = unionCase.Fields |> Seq.map (fun unionField -> - if unionField.Name.StartsWith "Item" then //TODO: Some better way of detecting default names for the union cases' fields + if unionField.Name.StartsWith("Item", StringComparison.Ordinal) then //TODO: Some better way of detecting default names for the union cases' fields unionField.FieldType |> format displayContext |> fst else @@ -231,7 +231,7 @@ module DocumentationFormatter = unionCase.DisplayName let getFuncSignatureWithIdent displayContext (func: FSharpMemberOrFunctionOrValue) (ident: int) = - let maybeGetter = func.LogicalName.StartsWith "get_" + let maybeGetter = func.LogicalName.StartsWith("get_", StringComparison.Ordinal) let indent = String.replicate ident " " let functionName = @@ -243,7 +243,7 @@ module DocumentationFormatter = |> FSharpKeywords.NormalizeIdentifierBackticks elif func.IsOperatorOrActivePattern then func.DisplayName - elif func.DisplayName.StartsWith "( " then + elif func.DisplayName.StartsWith("( ", StringComparison.Ordinal) then FSharpKeywords.NormalizeIdentifierBackticks func.LogicalName else FSharpKeywords.NormalizeIdentifierBackticks func.DisplayName @@ -416,9 +416,12 @@ module DocumentationFormatter = "new" elif func.IsOperatorOrActivePattern then func.DisplayName - elif func.DisplayName.StartsWith "( " then + elif func.DisplayName.StartsWith("( ", StringComparison.Ordinal) then FSharpKeywords.NormalizeIdentifierBackticks func.LogicalName - elif func.LogicalName.StartsWith "get_" || func.LogicalName.StartsWith "set_" then + elif + func.LogicalName.StartsWith("get_", StringComparison.Ordinal) + || func.LogicalName.StartsWith("set_", StringComparison.Ordinal) + then PrettyNaming.TryChopPropertyName func.DisplayName |> Option.defaultValue func.DisplayName else @@ -536,7 +539,7 @@ module DocumentationFormatter = let prefix = if v.IsMutable then "val mutable" else "val" let name = - (if v.DisplayName.StartsWith "( " then + (if v.DisplayName.StartsWith("( ", StringComparison.Ordinal) then v.LogicalName else v.DisplayName) @@ -782,7 +785,10 @@ module DocumentationFormatter = /// trims the leading 'Microsoft.' from the full name of the symbol member m.SafeFullName = - if m.FullName.StartsWith "Microsoft." && m.Assembly.SimpleName = "FSharp.Core" then + if + m.FullName.StartsWith("Microsoft.", StringComparison.Ordinal) + && m.Assembly.SimpleName = "FSharp.Core" + then m.FullName.Substring "Microsoft.".Length else m.FullName diff --git a/src/FsAutoComplete.Core/DotnetNewTemplate.fs b/src/FsAutoComplete.Core/DotnetNewTemplate.fs index 8fcdeb91c..3ec42f8bc 100644 --- a/src/FsAutoComplete.Core/DotnetNewTemplate.fs +++ b/src/FsAutoComplete.Core/DotnetNewTemplate.fs @@ -61,12 +61,12 @@ module DotnetNewTemplate = let parseTemplateOutput (x: string) = let xs = x.Split(Environment.NewLine) - |> Array.skipWhile (fun n -> not (n.StartsWith "Template")) + |> Array.skipWhile (fun n -> not (n.StartsWith("Template", StringComparison.Ordinal))) |> Array.filter (fun n -> not (n.StartsWith ' ' || String.IsNullOrWhiteSpace n)) let header = xs.[0] let body = xs.[2..] - let nameLength = header.IndexOf("Short") + let nameLength = header.IndexOf("Short", StringComparison.Ordinal) let body = body diff --git a/src/FsAutoComplete.Core/FCSPatches.fs b/src/FsAutoComplete.Core/FCSPatches.fs index e45a8b334..9cbe288f3 100644 --- a/src/FsAutoComplete.Core/FCSPatches.fs +++ b/src/FsAutoComplete.Core/FCSPatches.fs @@ -657,7 +657,7 @@ module LanguageVersionShim = /// A LanguageVersionShim from the parsed "--langversion:" or defaultLanguageVersion let fromFSharpProjectOptions (fpo: FSharpProjectOptions) = fpo.OtherOptions - |> Array.tryFind (fun x -> x.StartsWith("--langversion:")) + |> Array.tryFind (fun x -> x.StartsWith("--langversion:", StringComparison.Ordinal)) |> Option.map (fun x -> x.Split(":")[1]) |> Option.map (fun x -> LanguageVersionShim(x)) |> Option.defaultWith (fun () -> defaultLanguageVersion.Value) diff --git a/src/FsAutoComplete.Core/FileSystem.fs b/src/FsAutoComplete.Core/FileSystem.fs index 1185b8e6e..170e1b739 100644 --- a/src/FsAutoComplete.Core/FileSystem.fs +++ b/src/FsAutoComplete.Core/FileSystem.fs @@ -589,7 +589,7 @@ module Tokenizer = ) : Range voption = match text[range] with | Error _ -> ValueNone - | Ok rangeText when rangeText.EndsWith "``" -> + | Ok rangeText when rangeText.EndsWith("``", StringComparison.Ordinal) -> // find matching opening backticks // backticks cannot contain linebreaks -- even for Active Pattern: diff --git a/src/FsAutoComplete.Core/InlayHints.fs b/src/FsAutoComplete.Core/InlayHints.fs index a46756f6f..d86d58706 100644 --- a/src/FsAutoComplete.Core/InlayHints.fs +++ b/src/FsAutoComplete.Core/InlayHints.fs @@ -148,7 +148,11 @@ module private ShouldCreate = [] - 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, StringComparison.Ordinal) then + ValueSome() + else + ValueNone // doesn't differentiate between modules, types, namespaces // -> is just for documentation in code [] @@ -206,7 +210,8 @@ module private ShouldCreate = let inline private isMeaningfulName (p: FSharpParameter) = p.DisplayName.Length > 2 - let inline private isOperator (func: FSharpMemberOrFunctionOrValue) = func.CompiledName.StartsWith "op_" + let inline private isOperator (func: FSharpMemberOrFunctionOrValue) = + func.CompiledName.StartsWith("op_", StringComparison.Ordinal) /// Doesn't consider lower/upper cases: /// * `areSame "foo" "FOO" = true` @@ -303,7 +308,7 @@ module private ShouldCreate = let inline private doesNotMatchArgumentText (parameterName: string) (userArgumentText: string) = parameterName <> userArgumentText - && not (userArgumentText.StartsWith parameterName) + && not (userArgumentText.StartsWith(parameterName, StringComparison.Ordinal)) let private isParamNamePostfixOfFuncName (func: FSharpMemberOrFunctionOrValue) (paramName: string) = let funcName = func.DisplayName.AsSpan() @@ -374,7 +379,7 @@ type MissingExplicitType with if x.SpecialRules |> List.contains RemoveOptionFromType then // Optional parameter: // `static member F(?a) =` -> `: int`, NOT `: int option` - if typeName.EndsWith " option" then + if typeName.EndsWith(" option", StringComparison.Ordinal) then typeName.Substring(0, typeName.Length - " option".Length) else typeName diff --git a/src/FsAutoComplete.Core/Lexer.fs b/src/FsAutoComplete.Core/Lexer.fs index e7fd16497..5f33322f3 100644 --- a/src/FsAutoComplete.Core/Lexer.fs +++ b/src/FsAutoComplete.Core/Lexer.fs @@ -1,5 +1,6 @@ namespace FsAutoComplete +open System open FSharp.Compiler.Tokenization open FsAutoComplete.Logging open FsAutoComplete.Logging.Types @@ -43,14 +44,14 @@ module Lexer = [] let (|Define|_|) (a: string) = - if a.StartsWith "--define:" then + if a.StartsWith("--define:", StringComparison.Ordinal) then ValueSome(a.[9..]) else ValueNone [] let (|LangVersion|_|) (a: string) = - if a.StartsWith "--langversion:" then + if a.StartsWith("--langversion:", StringComparison.Ordinal) then ValueSome(a.[14..]) else ValueNone diff --git a/src/FsAutoComplete.Core/ParseAndCheckResults.fs b/src/FsAutoComplete.Core/ParseAndCheckResults.fs index feae26dfc..d8027aa20 100644 --- a/src/FsAutoComplete.Core/ParseAndCheckResults.fs +++ b/src/FsAutoComplete.Core/ParseAndCheckResults.fs @@ -163,7 +163,9 @@ type ParseAndCheckResults | FindDeclFailureReason.Unknown r -> r return ResultOrString.Error(sprintf "Could not find declaration. %s" elaboration) - | FindDeclResult.DeclFound range when range.FileName.EndsWith(Range.rangeStartup.FileName) -> + | FindDeclResult.DeclFound range when + range.FileName.EndsWith(Range.rangeStartup.FileName, StringComparison.Ordinal) + -> return ResultOrString.Error "Could not find declaration" | FindDeclResult.DeclFound range when range.FileName = UMX.untag x.FileName -> // decl in same file diff --git a/src/FsAutoComplete.Core/SignatureFormatter.fs b/src/FsAutoComplete.Core/SignatureFormatter.fs index 6892610ca..f00406090 100644 --- a/src/FsAutoComplete.Core/SignatureFormatter.fs +++ b/src/FsAutoComplete.Core/SignatureFormatter.fs @@ -167,7 +167,7 @@ module SignatureFormatter = let typeList = unionCase.Fields |> Seq.map (fun unionField -> - if unionField.Name.StartsWith "Item" then //TODO: Some better way of detecting default names for the union cases' fields + if unionField.Name.StartsWith("Item", StringComparison.Ordinal) then //TODO: Some better way of detecting default names for the union cases' fields formatFSharpType displayContext unionField.FieldType else unionField.Name + ":" ++ (formatFSharpType displayContext unionField.FieldType)) @@ -178,7 +178,7 @@ module SignatureFormatter = unionCase.DisplayName let getFuncSignatureWithIdent displayContext (func: FSharpMemberOrFunctionOrValue) (ident: int) = - let maybeGetter = func.LogicalName.StartsWith "get_" + let maybeGetter = func.LogicalName.StartsWith("get_", StringComparison.Ordinal) let indent = String.replicate ident " " let functionName = @@ -190,7 +190,7 @@ module SignatureFormatter = |> FSharpKeywords.NormalizeIdentifierBackticks elif func.IsOperatorOrActivePattern then $"( {func.DisplayNameCore} )" - elif func.DisplayName.StartsWith "( " then + elif func.DisplayName.StartsWith("( ", StringComparison.Ordinal) then FSharpKeywords.NormalizeIdentifierBackticks func.LogicalName else FSharpKeywords.NormalizeIdentifierBackticks func.DisplayName @@ -377,9 +377,12 @@ module SignatureFormatter = "new" elif func.IsOperatorOrActivePattern then func.DisplayName - elif func.DisplayName.StartsWith "( " then + elif func.DisplayName.StartsWith("( ", StringComparison.Ordinal) then FSharpKeywords.NormalizeIdentifierBackticks func.LogicalName - elif func.LogicalName.StartsWith "get_" || func.LogicalName.StartsWith "set_" then + elif + func.LogicalName.StartsWith("get_", StringComparison.Ordinal) + || func.LogicalName.StartsWith("set_", StringComparison.Ordinal) + then PrettyNaming.TryChopPropertyName func.DisplayName |> Option.defaultValue func.DisplayName else @@ -515,7 +518,7 @@ module SignatureFormatter = let prefix = if v.IsMutable then "val mutable" else "val" let name = - (if v.DisplayName.StartsWith "( " then + (if v.DisplayName.StartsWith("( ", StringComparison.Ordinal) then v.LogicalName else v.DisplayName) diff --git a/src/FsAutoComplete.Core/SignatureHelp.fs b/src/FsAutoComplete.Core/SignatureHelp.fs index 95dca906d..e3f059674 100644 --- a/src/FsAutoComplete.Core/SignatureHelp.fs +++ b/src/FsAutoComplete.Core/SignatureHelp.fs @@ -141,7 +141,11 @@ let private getSignatureHelpForMethod let methods = methodGroup.Methods - do! Option.guard (methods.Length > 0 && not (methodGroup.MethodName.EndsWith("> )"))) + do! + Option.guard ( + methods.Length > 0 + && not (methodGroup.MethodName.EndsWith("> )", StringComparison.Ordinal)) + ) let isStaticArgTip = lines.TryGetChar paramLocations.OpenParenLocation = Some '<' diff --git a/src/FsAutoComplete.Core/State.fs b/src/FsAutoComplete.Core/State.fs index 9c49dbb28..a3c80dbe4 100644 --- a/src/FsAutoComplete.Core/State.fs +++ b/src/FsAutoComplete.Core/State.fs @@ -71,7 +71,9 @@ module ProjInfoExtensions = type FSharpProjectOptions with member x.OutputDll = - x.OtherOptions |> Array.find (fun o -> o.StartsWith("-o:")) |> (fun s -> s[3..]) + x.OtherOptions + |> Array.find (fun o -> o.StartsWith("-o:", StringComparison.Ordinal)) + |> (fun s -> s[3..]) member x.SourceFilesThatThisFileDependsOn(file: string) = let untagged = UMX.untag file diff --git a/src/FsAutoComplete.Core/TestAdapter.fs b/src/FsAutoComplete.Core/TestAdapter.fs index fdd944567..fe75b9a65 100644 --- a/src/FsAutoComplete.Core/TestAdapter.fs +++ b/src/FsAutoComplete.Core/TestAdapter.fs @@ -1,6 +1,6 @@ module FsAutoComplete.TestAdapter - +open System open FSharp.Compiler.Text open FSharp.Compiler.Syntax @@ -44,46 +44,50 @@ let getExpectoTests (ast: ParsedInput) : TestAdapterEntry list = let mutable ident = 0 let isExpectoName (str: string) = - str.EndsWith "testCase" - || str.EndsWith "ftestCase" - || str.EndsWith "ptestCase" - || str.EndsWith "testCaseAsync" - || str.EndsWith "ftestCaseAsync" - || str.EndsWith "ptestCaseAsync" - || str.EndsWith "testCaseTask" - || str.EndsWith "ftestCaseTask" - || str.EndsWith "ptestCaseTask" - || (str.EndsWith "test" - && not (str.EndsWith "failtest") - && not (str.EndsWith "skiptest")) - || str.EndsWith "ftest" - || (str.EndsWith "ptest" && not (str.EndsWith "skiptest")) - || str.EndsWith "testAsync" - || str.EndsWith "ftestAsync" - || str.EndsWith "ptestAsync" - || str.EndsWith "testTask" - || str.EndsWith "ftestTask" - || str.EndsWith "ptestTask" - || str.EndsWith "testProperty" - || str.EndsWith "ptestProperty" - || str.EndsWith "ftestProperty" - || str.EndsWith "testPropertyWithConfig" - || str.EndsWith "ptestPropertyWithConfig" - || str.EndsWith "ftestPropertyWithConfig" - || str.EndsWith "testPropertyWithConfigs" - || str.EndsWith "ptestPropertyWithConfigs" - || str.EndsWith "ftestPropertyWithConfigs" - || str.EndsWith "testTheory" - || str.EndsWith "ftestTheory" - || str.EndsWith "ptestTheory" - || str.EndsWith "testTheoryAsync" - || str.EndsWith "ftestTheoryAsync" - || str.EndsWith "ptestTheoryAsync" - || str.EndsWith "testTheoryTask" - || str.EndsWith "ftestTheoryTask" - || str.EndsWith "ptestTheoryTask" - - let isExpectoListName (str: string) = str.EndsWith "testList" || str.EndsWith "ftestList" || str.EndsWith "ptestList" + str.EndsWith("testCase", StringComparison.Ordinal) + || str.EndsWith("ftestCase", StringComparison.Ordinal) + || str.EndsWith("ptestCase", StringComparison.Ordinal) + || str.EndsWith("testCaseAsync", StringComparison.Ordinal) + || str.EndsWith("ftestCaseAsync", StringComparison.Ordinal) + || str.EndsWith("ptestCaseAsync", StringComparison.Ordinal) + || str.EndsWith("testCaseTask", StringComparison.Ordinal) + || str.EndsWith("ftestCaseTask", StringComparison.Ordinal) + || str.EndsWith("ptestCaseTask", StringComparison.Ordinal) + || (str.EndsWith("test", StringComparison.Ordinal) + && not (str.EndsWith("failtest", StringComparison.Ordinal)) + && not (str.EndsWith("skiptest", StringComparison.Ordinal))) + || str.EndsWith("ftest", StringComparison.Ordinal) + || (str.EndsWith("ptest", StringComparison.Ordinal) + && not (str.EndsWith("skiptest", StringComparison.Ordinal))) + || str.EndsWith("testAsync", StringComparison.Ordinal) + || str.EndsWith("ftestAsync", StringComparison.Ordinal) + || str.EndsWith("ptestAsync", StringComparison.Ordinal) + || str.EndsWith("testTask", StringComparison.Ordinal) + || str.EndsWith("ftestTask", StringComparison.Ordinal) + || str.EndsWith("ptestTask", StringComparison.Ordinal) + || str.EndsWith("testProperty", StringComparison.Ordinal) + || str.EndsWith("ptestProperty", StringComparison.Ordinal) + || str.EndsWith("ftestProperty", StringComparison.Ordinal) + || str.EndsWith("testPropertyWithConfig", StringComparison.Ordinal) + || str.EndsWith("ptestPropertyWithConfig", StringComparison.Ordinal) + || str.EndsWith("ftestPropertyWithConfig", StringComparison.Ordinal) + || str.EndsWith("testPropertyWithConfigs", StringComparison.Ordinal) + || str.EndsWith("ptestPropertyWithConfigs", StringComparison.Ordinal) + || str.EndsWith("ftestPropertyWithConfigs", StringComparison.Ordinal) + || str.EndsWith("testTheory", StringComparison.Ordinal) + || str.EndsWith("ftestTheory", StringComparison.Ordinal) + || str.EndsWith("ptestTheory", StringComparison.Ordinal) + || str.EndsWith("testTheoryAsync", StringComparison.Ordinal) + || str.EndsWith("ftestTheoryAsync", StringComparison.Ordinal) + || str.EndsWith("ptestTheoryAsync", StringComparison.Ordinal) + || str.EndsWith("testTheoryTask", StringComparison.Ordinal) + || str.EndsWith("ftestTheoryTask", StringComparison.Ordinal) + || str.EndsWith("ptestTheoryTask", StringComparison.Ordinal) + + let isExpectoListName (str: string) = + str.EndsWith("testList", StringComparison.Ordinal) + || str.EndsWith("ftestList", StringComparison.Ordinal) + || str.EndsWith("ptestList", StringComparison.Ordinal) let (|Case|List|NotExpecto|) = function @@ -266,16 +270,16 @@ let getNUnitTest (ast: ParsedInput) : TestAdapterEntry list = |> List.exists (fun a -> let str = a.TypeName.LongIdent |> List.last - str.idText.EndsWith "Test" - || str.idText.EndsWith "TestAttribute" - || str.idText.EndsWith "TestCase" - || str.idText.EndsWith "TestCaseAttribute" - || str.idText.EndsWith "TestCaseSource" - || str.idText.EndsWith "TestCaseSourceAttribute" - || str.idText.EndsWith "Theory" - || str.idText.EndsWith "TheoryAttribute" - || str.idText.EndsWith "Property" - || str.idText.EndsWith "PropertyAttribute") + str.idText.EndsWith("Test", StringComparison.Ordinal) + || str.idText.EndsWith("TestAttribute", StringComparison.Ordinal) + || str.idText.EndsWith("TestCase", StringComparison.Ordinal) + || str.idText.EndsWith("TestCaseAttribute", StringComparison.Ordinal) + || str.idText.EndsWith("TestCaseSource", StringComparison.Ordinal) + || str.idText.EndsWith("TestCaseSourceAttribute", StringComparison.Ordinal) + || str.idText.EndsWith("Theory", StringComparison.Ordinal) + || str.idText.EndsWith("TheoryAttribute", StringComparison.Ordinal) + || str.idText.EndsWith("Property", StringComparison.Ordinal) + || str.idText.EndsWith("PropertyAttribute", StringComparison.Ordinal)) let getName = function @@ -444,12 +448,12 @@ let getXUnitTest ast : TestAdapterEntry list = |> List.exists (fun a -> let str = a.TypeName.LongIdent |> List.last - str.idText.EndsWith "Fact" - || str.idText.EndsWith "FactAttribute" - || str.idText.EndsWith "Theory" - || str.idText.EndsWith "TheoryAttribute" - || str.idText.EndsWith "Property" - || str.idText.EndsWith "PropertyAttribute") + str.idText.EndsWith("Fact", StringComparison.Ordinal) + || str.idText.EndsWith("FactAttribute", StringComparison.Ordinal) + || str.idText.EndsWith("Theory", StringComparison.Ordinal) + || str.idText.EndsWith("TheoryAttribute", StringComparison.Ordinal) + || str.idText.EndsWith("Property", StringComparison.Ordinal) + || str.idText.EndsWith("PropertyAttribute", StringComparison.Ordinal)) let getName = function diff --git a/src/FsAutoComplete.Core/TipFormatter.fs b/src/FsAutoComplete.Core/TipFormatter.fs index 296440bcd..6161c445b 100644 --- a/src/FsAutoComplete.Core/TipFormatter.fs +++ b/src/FsAutoComplete.Core/TipFormatter.fs @@ -177,7 +177,9 @@ module private Format = // so render the markdown code block the best way // by avoid empty lines at the beginning or the end let formattedText = - match innerText.StartsWith("\n"), innerText.EndsWith("\n") with + match + innerText.StartsWith("\n", StringComparison.Ordinal), innerText.EndsWith("\n", StringComparison.Ordinal) + with | true, true -> sprintf "```%s%s```" lang innerText | true, false -> sprintf "```%s%s\n```" lang innerText | false, true -> sprintf "```%s\n%s```" lang innerText @@ -733,7 +735,10 @@ type private XmlDocMember(doc: XmlDocument, indentationSize: int, columnOffset: content.Split('\n') |> Array.map (fun line -> - if not (String.IsNullOrWhiteSpace line) && line.StartsWith(tabsOffset) then + if + not (String.IsNullOrWhiteSpace line) + && line.StartsWith(tabsOffset, StringComparison.Ordinal) + then line.Substring(columnOffset + indentationSize) else line) @@ -973,7 +978,7 @@ let private tryGetXmlDocMember (xmlDoc: FSharpXmlDoc) = let rec findIndentationSize (lines: string list) = match lines with | head :: tail -> - let lesserThanIndex = head.IndexOf("<") + let lesserThanIndex = head.IndexOf("<", StringComparison.Ordinal) if lesserThanIndex <> -1 then lesserThanIndex diff --git a/src/FsAutoComplete.Core/TypedAstUtils.fs b/src/FsAutoComplete.Core/TypedAstUtils.fs index 86d417302..dab90c7fa 100644 --- a/src/FsAutoComplete.Core/TypedAstUtils.fs +++ b/src/FsAutoComplete.Core/TypedAstUtils.fs @@ -57,8 +57,8 @@ module TypedAstUtils = |> Option.isSome let isOperator (name: string) = - name.StartsWith "( " - && name.EndsWith " )" + name.StartsWith("( ", StringComparison.Ordinal) + && name.EndsWith(" )", StringComparison.Ordinal) && name.Length > 4 && name.Substring(2, name.Length - 4) |> String.forall (fun c -> c <> ' ' && not (Char.IsLetter c)) @@ -190,10 +190,14 @@ module TypedAstExtensionHelpers = member x.IsConstructor = x.CompiledName = ".ctor" member x.IsOperatorOrActivePattern = - x.CompiledName.StartsWith "op_" + x.CompiledName.StartsWith("op_", StringComparison.Ordinal) || let name = x.DisplayName in - if name.StartsWith "( " && name.EndsWith " )" && name.Length > 4 then + if + name.StartsWith("( ", StringComparison.Ordinal) + && name.EndsWith(" )", StringComparison.Ordinal) + && name.Length > 4 + then name.Substring(2, name.Length - 4) |> String.forall (fun c -> c <> ' ') else false diff --git a/src/FsAutoComplete.Core/Utils.fs b/src/FsAutoComplete.Core/Utils.fs index e49e7196d..f5bb4d3c9 100644 --- a/src/FsAutoComplete.Core/Utils.fs +++ b/src/FsAutoComplete.Core/Utils.fs @@ -445,9 +445,12 @@ module String = let (|StartsWith|_|) (pattern: string) (value: string) = - if String.IsNullOrWhiteSpace value then None - elif value.StartsWith pattern then Some() - else None + if String.IsNullOrWhiteSpace value then + None + elif value.StartsWith(pattern, StringComparison.Ordinal) then + Some() + else + None let split (splitter: char) (s: string) = s.Split([| splitter |], StringSplitOptions.RemoveEmptyEntries) |> List.ofArray @@ -461,7 +464,7 @@ module String = yield line.Value line.Value <- reader.ReadLine() - if str.EndsWith("\n") then + if str.EndsWith("\n", StringComparison.Ordinal) then // last trailing space not returned // http://stackoverflow.com/questions/19365404/stringreader-omits-trailing-linebreak yield String.Empty |] @@ -638,7 +641,7 @@ let inline fail msg = Printf.kprintf Debug.Fail msg let chooseByPrefix (prefix: string) (s: string) = - if s.StartsWith(prefix) then + if s.StartsWith(prefix, StringComparison.Ordinal) then Some(s.Substring(prefix.Length)) else None @@ -646,7 +649,7 @@ let chooseByPrefix (prefix: string) (s: string) = let chooseByPrefix2 prefixes (s: string) = prefixes |> List.tryPick (fun prefix -> chooseByPrefix prefix s) let splitByPrefix (prefix: string) (s: string) = - if s.StartsWith(prefix) then + if s.StartsWith(prefix, StringComparison.Ordinal) then Some(prefix, s.Substring(prefix.Length)) else None @@ -659,7 +662,7 @@ module Patterns = let (|StartsWith|_|) (pat: string) (str: string) = match str with | null -> None - | _ when str.StartsWith pat -> Some str + | _ when str.StartsWith(pat, StringComparison.Ordinal) -> Some str | _ -> None let (|Contains|_|) (pat: string) (str: string) = diff --git a/src/FsAutoComplete/CodeFixes/AdjustConstant.fs b/src/FsAutoComplete/CodeFixes/AdjustConstant.fs index d4778be7e..a5d8edcea 100644 --- a/src/FsAutoComplete/CodeFixes/AdjustConstant.fs +++ b/src/FsAutoComplete/CodeFixes/AdjustConstant.fs @@ -698,7 +698,8 @@ module private CommonFixes = /// -> 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 "+") + (replacement.StartsWith("-", StringComparison.Ordinal) + || replacement.StartsWith("+", StringComparison.Ordinal)) && range.Start.Character > 0 && "!$%&*+-./<=>?@^|~".Contains(lineStr[range.Start.Character - 1]) then diff --git a/src/FsAutoComplete/CodeFixes/ConvertTripleSlashCommentToXmlTaggedDoc.fs b/src/FsAutoComplete/CodeFixes/ConvertTripleSlashCommentToXmlTaggedDoc.fs index 74aeaa0ce..d6ca2bed4 100644 --- a/src/FsAutoComplete/CodeFixes/ConvertTripleSlashCommentToXmlTaggedDoc.fs +++ b/src/FsAutoComplete/CodeFixes/ConvertTripleSlashCommentToXmlTaggedDoc.fs @@ -134,7 +134,7 @@ let private collectCommentContents match currentLine with | None -> acc | Some line -> - let idx = line.IndexOf("///") + let idx = line.IndexOf("///", StringComparison.Ordinal) if idx >= 0 then let existingComment = line.TrimStart().Substring(3).TrimStart() @@ -177,7 +177,7 @@ let fix (getParseResultsForFile: GetParseResultsForFile) (getRangeText: GetRange let origCommentContents = collectCommentContents d.Range.Start d.Range.End sourceText - let indent = lineStr.IndexOf("///") + let indent = lineStr.IndexOf("///", StringComparison.Ordinal) let summaryXmlDoc = wrapInSummary indent origCommentContents let range = diff --git a/src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs b/src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs index 1326e179f..16f371e5e 100644 --- a/src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs +++ b/src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs @@ -1,5 +1,6 @@ module FsAutoComplete.CodeFix.RemoveRedundantAttributeSuffix +open System open FSharp.Compiler.Syntax open FsToolkit.ErrorHandling open FsAutoComplete.CodeFix.Types @@ -26,7 +27,7 @@ let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = attributes.Attributes |> List.choose (fun a -> match List.tryLast a.TypeName.LongIdent with - | Some ident when ident.idText.EndsWith("Attribute") -> Some ident + | Some ident when ident.idText.EndsWith("Attribute", StringComparison.Ordinal) -> Some ident | _ -> None) if List.isEmpty attributesWithRedundantSuffix then diff --git a/src/FsAutoComplete/CodeFixes/RemoveUnnecessaryReturnOrYield.fs b/src/FsAutoComplete/CodeFixes/RemoveUnnecessaryReturnOrYield.fs index f96bb8dcc..51ee491bf 100644 --- a/src/FsAutoComplete/CodeFixes/RemoveUnnecessaryReturnOrYield.fs +++ b/src/FsAutoComplete/CodeFixes/RemoveUnnecessaryReturnOrYield.fs @@ -1,5 +1,6 @@ module FsAutoComplete.CodeFix.RemoveUnnecessaryReturnOrYield +open System open FsToolkit.ErrorHandling open FsAutoComplete.CodeFix.Types open Ionide.LanguageServerProtocol.Types @@ -26,13 +27,13 @@ let fix (getParseResultsForFile: GetParseResultsForFile) (getLineText: GetLineTe let! errorText = getLineText lines diagnostic.Range let! title = - if errorText.StartsWith "return!" then + if errorText.StartsWith("return!", StringComparison.Ordinal) then Ok(title "return!") - elif errorText.StartsWith "yield!" then + elif errorText.StartsWith("yield!", StringComparison.Ordinal) then Ok(title "yield!") - elif errorText.StartsWith "return" then + elif errorText.StartsWith("return", StringComparison.Ordinal) then Ok(title "return") - elif errorText.StartsWith "yield" then + elif errorText.StartsWith("yield", StringComparison.Ordinal) then Ok(title "yield") else Error "unknown start token for remove return or yield codefix" diff --git a/src/FsAutoComplete/CodeFixes/RemoveUnusedBinding.fs b/src/FsAutoComplete/CodeFixes/RemoveUnusedBinding.fs index e49101efb..050d5d4c8 100644 --- a/src/FsAutoComplete/CodeFixes/RemoveUnusedBinding.fs +++ b/src/FsAutoComplete/CodeFixes/RemoveUnusedBinding.fs @@ -1,6 +1,6 @@ module FsAutoComplete.CodeFix.RemoveUnusedBinding - +open System open FsToolkit.ErrorHandling open FsAutoComplete.CodeFix.Navigation open FsAutoComplete.CodeFix.Types @@ -11,7 +11,6 @@ open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Syntax open FSharp.Compiler.Text - let posBetween (range: Range) tester = Position.posGeq tester range.Start // positions on this one are flipped to simulate Pos.posLte, because that doesn't exist && Position.posGeq range.End tester @@ -62,7 +61,9 @@ type FSharpParseFileResults with else // Check if it's an operator match pat with - | SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ])) when id.idText.StartsWith("op_") -> + | SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ])) when + id.idText.StartsWith("op_", StringComparison.Ordinal) + -> if Range.rangeContainsRange id.idRange diagnosticRange then Some(FullBinding binding.RangeOfBindingWithRhs) else diff --git a/src/FsAutoComplete/CodeFixes/RenameParamToMatchSignature.fs b/src/FsAutoComplete/CodeFixes/RenameParamToMatchSignature.fs index 1a724702e..2b6ccaf74 100644 --- a/src/FsAutoComplete/CodeFixes/RenameParamToMatchSignature.fs +++ b/src/FsAutoComplete/CodeFixes/RenameParamToMatchSignature.fs @@ -1,5 +1,6 @@ module FsAutoComplete.CodeFix.RenameParamToMatchSignature +open System open FsToolkit.ErrorHandling open FsAutoComplete.CodeFix.Types open Ionide.LanguageServerProtocol.Types @@ -27,8 +28,8 @@ let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = let head = "The argument names in the signature '" let mid = "' and implementation '" - if msg.StartsWith head then - match msg.IndexOf mid with + if msg.StartsWith(head, StringComparison.Ordinal) then + match msg.IndexOf(mid, StringComparison.Ordinal) with | -1 -> None | i -> msg.Substring(head.Length, i - head.Length) |> Some else diff --git a/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs b/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs index f8b59b266..67d080869 100644 --- a/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs +++ b/src/FsAutoComplete/CodeFixes/ResolveNamespace.fs @@ -1,5 +1,6 @@ module FsAutoComplete.CodeFix.ResolveNamespace +open System open Ionide.LanguageServerProtocol.Types open FsAutoComplete.CodeFix open FsAutoComplete.CodeFix.Types @@ -37,7 +38,10 @@ let fix let line = lines.GetLineString(l - 2) let isImplicitTopLevelModule = - not (line.StartsWith "module" && not (line.EndsWith "=")) + not ( + line.StartsWith("module", StringComparison.Ordinal) + && not (line.EndsWith("=", StringComparison.Ordinal)) + ) if isImplicitTopLevelModule then 1 else l | ScopeKind.TopModule -> 1 @@ -47,7 +51,11 @@ let fix lineNos |> List.mapi (fun i line -> i, lines.GetLineString line) - |> List.choose (fun (i, lineStr) -> if lineStr.StartsWith "namespace" then Some i else None) + |> List.choose (fun (i, lineStr) -> + if lineStr.StartsWith("namespace", StringComparison.Ordinal) then + Some i + else + None) |> List.tryLast match mostRecentNamespaceInScope with @@ -78,7 +86,7 @@ let fix let docLine = insertPoint - 1 let actualOpen = - if name.EndsWith word && name <> word then + if name.EndsWith(word, StringComparison.Ordinal) && name <> word then let prefix = name.Substring(0, name.Length - word.Length).TrimEnd('.') $"%s{ns}.%s{prefix}" diff --git a/src/FsAutoComplete/CodeFixes/ToInterpolatedString.fs b/src/FsAutoComplete/CodeFixes/ToInterpolatedString.fs index c68a89a9f..b834e6a49 100644 --- a/src/FsAutoComplete/CodeFixes/ToInterpolatedString.fs +++ b/src/FsAutoComplete/CodeFixes/ToInterpolatedString.fs @@ -1,5 +1,6 @@ module FsAutoComplete.CodeFix.ToInterpolatedString +open System open System.Text.RegularExpressions open FsToolkit.ErrorHandling open FsAutoComplete.CodeFix.Types @@ -87,7 +88,9 @@ let tryFindSprintfApplication (parseAndCheck: ParseAndCheckResults) (sourceText: parseAndCheck.TryGetSymbolUse functionIdent.idRange.End lineStr |> Option.bind (fun symbolUse -> match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as mfv when mfv.Assembly.QualifiedName.StartsWith("FSharp.Core") -> + | :? FSharpMemberOrFunctionOrValue as mfv when + mfv.Assembly.QualifiedName.StartsWith("FSharp.Core", StringComparison.Ordinal) + -> // Verify the function is from F# Core. Some(functionIdent, mString, xs, mLastArg) | _ -> None)) diff --git a/src/FsAutoComplete/CommandResponse.fs b/src/FsAutoComplete/CommandResponse.fs index 592fe4a7d..cb63a28a3 100644 --- a/src/FsAutoComplete/CommandResponse.fs +++ b/src/FsAutoComplete/CommandResponse.fs @@ -211,7 +211,7 @@ module CommandResponse = static member IsIgnored(e: FSharpDiagnostic) = // FST-1027 support in Fake 5 - e.ErrorNumber = 213 && e.Message.StartsWith "'paket:" + e.ErrorNumber = 213 && e.Message.StartsWith("'paket:", StringComparison.Ordinal) static member OfFSharpError(e: FSharpDiagnostic) = { FileName = e.FileName diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs index 02e15d63c..37a300940 100644 --- a/src/FsAutoComplete/LspHelpers.fs +++ b/src/FsAutoComplete/LspHelpers.fs @@ -146,14 +146,17 @@ module Conversions = let applyQuery (query: string) (info: SymbolInformation) = match query.Split([| '.' |], StringSplitOptions.RemoveEmptyEntries) with | [||] -> false - | [| fullName |] -> info.Name.StartsWith fullName - | [| moduleName; fieldName |] -> info.Name.StartsWith fieldName && info.ContainerName = Some moduleName + | [| fullName |] -> info.Name.StartsWith(fullName, StringComparison.Ordinal) + | [| moduleName; fieldName |] -> + info.Name.StartsWith(fieldName, StringComparison.Ordinal) + && info.ContainerName = Some moduleName | parts -> let containerName = parts.[0 .. (parts.Length - 2)] |> String.concat "." let fieldName = Array.last parts - info.Name.StartsWith fieldName && info.ContainerName = Some containerName + info.Name.StartsWith(fieldName, StringComparison.Ordinal) + && info.ContainerName = Some containerName let getCodeLensInformation (uri: DocumentUri) (typ: string) (topLevel: NavigationTopLevelDeclaration) : CodeLens[] = let map (decl: NavigationItem) : CodeLens = diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs index ebba809ec..149c6fc3f 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -542,7 +542,7 @@ type AdaptiveFSharpLspServer let! lineStr = volatileFile.Source |> tryGetLineStr pos |> Result.ofStringErr - if lineStr.StartsWith "#" then + if lineStr.StartsWith("#", StringComparison.Ordinal) then let completionList = { IsIncomplete = false Items = KeywordList.hashSymbolCompletionItems @@ -737,7 +737,10 @@ type AdaptiveFSharpLspServer | true, s -> CoreResponse.Res(HelpText.Simple(sym, s)) | _ -> let sym = - if sym.StartsWith "``" && sym.EndsWith "``" then + if + sym.StartsWith("``", StringComparison.Ordinal) + && sym.EndsWith("``", StringComparison.Ordinal) + then sym.TrimStart([| '`' |]).TrimEnd([| '`' |]) else sym diff --git a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs index a7af4ec7b..7bb470fb2 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs @@ -777,7 +777,7 @@ type AdaptiveState(lspClient: FSharpLspClient, sourceTextFactory: ISourceTextFac | MSBuildAllProjects v -> yield! v - |> Array.filter (fun x -> x.EndsWith(".props") && isWithinObjFolder x) + |> Array.filter (fun x -> x.EndsWith(".props", StringComparison.Ordinal) && isWithinObjFolder x) |> Array.map (UMX.tag >> projectFileChanges) | _ -> () ] diff --git a/src/FsAutoComplete/Parser.fs b/src/FsAutoComplete/Parser.fs index 9dbfc6bbd..66ce94002 100644 --- a/src/FsAutoComplete/Parser.fs +++ b/src/FsAutoComplete/Parser.fs @@ -138,8 +138,8 @@ module Parser = let dotnetPath = if - Environment.ProcessPath.EndsWith("dotnet") - || Environment.ProcessPath.EndsWith("dotnet.exe") + Environment.ProcessPath.EndsWith("dotnet", StringComparison.Ordinal) + || Environment.ProcessPath.EndsWith("dotnet.exe", StringComparison.Ordinal) then // this is valid when not running as a global tool Some(FileInfo(Environment.ProcessPath)) diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AdjustConstantTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AdjustConstantTests.fs index a8100bb4d..3df6155ed 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AdjustConstantTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AdjustConstantTests.fs @@ -327,7 +327,7 @@ module private ConvertIntToOtherBase = "0o173" "0b1111011" - if not (name.StartsWith "u") && name <> "byte" then + if not (name.StartsWith("u", StringComparison.Ordinal)) && name <> "byte" then checkAll server $"with value -123" $"let n = {{number}}{suffix}" "123" @@ -802,10 +802,10 @@ module private ConvertIntToOtherBase = module private ConvertCharToOtherForm = let private tryExtractChar (title: String) = let (start, fin) = "Convert to `", "`" - if title.StartsWith start && title.EndsWith fin then + if title.StartsWith(start, StringComparison.Ordinal) && title.EndsWith(fin, StringComparison.Ordinal) 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 + if c.Length > 3 && c.StartsWith("'", StringComparison.Ordinal) && c.EndsWith("'B", StringComparison.Ordinal) then // byte char (only when converting from int to char representation. Otherwise no `B` suffix in title) c.Substring(1, c.Length - 2) else @@ -815,11 +815,11 @@ module private ConvertCharToOtherForm = else None let private extractFormat (char: String) = - if char.StartsWith "\\u" then + if char.StartsWith("\\u", StringComparison.Ordinal) then CharFormat.Utf16Hexadecimal - elif char.StartsWith "\\U" then + elif char.StartsWith("\\U", StringComparison.Ordinal) then CharFormat.Utf32Hexadecimal - elif char.StartsWith "\\x" then + elif char.StartsWith("\\x", StringComparison.Ordinal) then CharFormat.Hexadecimal elif char.Length >= 2 && char[0] = '\\' && Char.IsDigit char[1] then CharFormat.Decimal diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs index 3514f875d..9e155a0c1 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs @@ -1,5 +1,6 @@ module FsAutoComplete.Tests.CodeFixTests.Tests +open System open Expecto open Helpers open Utils.ServerTests @@ -2794,7 +2795,7 @@ let private resolveNamespaceTests state = ResolveNamespaces = Some true } serverTestList (nameof ResolveNamespace) state config None (fun server -> - [ let selectCodeFix = CodeFix.matching (fun ca -> ca.Title.StartsWith "open") + [ let selectCodeFix = CodeFix.matching (fun ca -> ca.Title.StartsWith("open", StringComparison.Ordinal)) testCaseAsync "doesn't fail when target not in last line" <| CodeFix.checkApplicable diff --git a/test/FsAutoComplete.Tests.Lsp/CompletionTests.fs b/test/FsAutoComplete.Tests.Lsp/CompletionTests.fs index a4928143d..2c12d3395 100644 --- a/test/FsAutoComplete.Tests.Lsp/CompletionTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CompletionTests.fs @@ -1,13 +1,13 @@ module FsAutoComplete.Tests.Completion -open Expecto +open System open System.IO +open Expecto open Helpers open Ionide.LanguageServerProtocol.Types open FsAutoComplete.Utils open FsAutoComplete.Lsp open FsToolkit.ErrorHandling -open Utils.Server open Helpers.Expecto.ShadowedTimeouts let tests state = @@ -781,7 +781,7 @@ let autoOpenTests state = let (|ContainsOpenAction|_|) (codeActions: CodeAction[]) = codeActions - |> Array.tryFind (fun ca -> ca.Kind = Some "quickfix" && ca.Title.StartsWith "open ") + |> Array.tryFind (fun ca -> ca.Kind = Some "quickfix" && ca.Title.StartsWith("open ", StringComparison.Ordinal)) match! server.TextDocumentCodeAction p with | Error e -> return failtestf "Quick fix Request failed: %A" e diff --git a/test/FsAutoComplete.Tests.Lsp/FindReferencesTests.fs b/test/FsAutoComplete.Tests.Lsp/FindReferencesTests.fs index a242b5f61..87c5165dc 100644 --- a/test/FsAutoComplete.Tests.Lsp/FindReferencesTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/FindReferencesTests.fs @@ -1,7 +1,8 @@ module FsAutoComplete.Tests.FindReferences -open Expecto +open System open System.IO +open Expecto open FsAutoComplete open Helpers open Ionide.LanguageServerProtocol.Types @@ -229,13 +230,13 @@ let private solutionTests state = let refs = Dictionary>() for i in 0..(lines.Length-1) do let line = lines[i].TrimStart() - if line.StartsWith marker then + if line.StartsWith(marker, StringComparison.Ordinal) then let l = line.Substring(marker.Length).Trim() let splits = l.Split([|' '|], 2) let mark = splits[0] let ty = mark[0] let range = - let col = line.IndexOf mark + let col = line.IndexOf(mark, StringComparison.Ordinal) let length = mark.Length let line = i - 1 // marker is line AFTER actual range { diff --git a/test/FsAutoComplete.Tests.Lsp/GoToTests.fs b/test/FsAutoComplete.Tests.Lsp/GoToTests.fs index 41c1d1598..09ebf66c8 100644 --- a/test/FsAutoComplete.Tests.Lsp/GoToTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/GoToTests.fs @@ -1,8 +1,8 @@ module FsAutoComplete.Tests.GoTo - -open Expecto +open System open System.IO +open Expecto open Helpers open Ionide.LanguageServerProtocol.Types open FsToolkit.ErrorHandling @@ -69,7 +69,7 @@ let private gotoTest state = | Result.Error e -> failtestf "Request failed: %A" e | Result.Ok None -> failtest "Request none" | Result.Ok (Some (GotoResult.Multiple _)) -> failtest "Should only get one location" - | Result.Ok (Some (GotoResult.Single r)) when r.Uri.EndsWith("startup") -> + | Result.Ok (Some (GotoResult.Single r)) when r.Uri.EndsWith("startup", StringComparison.Ordinal) -> failtest "Should not generate the startup dummy file" | Result.Ok (Some (GotoResult.Single r)) -> Expect.stringEnds r.Uri ".cs" "should have generated a C# code file" diff --git a/test/FsAutoComplete.Tests.Lsp/Helpers.fs b/test/FsAutoComplete.Tests.Lsp/Helpers.fs index a6da8adbd..13659bad5 100644 --- a/test/FsAutoComplete.Tests.Lsp/Helpers.fs +++ b/test/FsAutoComplete.Tests.Lsp/Helpers.fs @@ -673,7 +673,7 @@ let diagnosticsFromSource (desiredSource: String) = match diags |> Array.choose (fun d -> match d.Source with - | Some s -> if s.StartsWith desiredSource then Some d else None + | Some s -> if s.StartsWith(desiredSource, StringComparison.Ordinal) then Some d else None | None -> None) with | [||] -> None diff --git a/test/FsAutoComplete.Tests.Lsp/Program.fs b/test/FsAutoComplete.Tests.Lsp/Program.fs index 437c073ad..9d50b30ed 100644 --- a/test/FsAutoComplete.Tests.Lsp/Program.fs +++ b/test/FsAutoComplete.Tests.Lsp/Program.fs @@ -142,7 +142,7 @@ let main args = let logLevel = match args - |> Array.tryFind (fun arg -> arg.StartsWith logMarker) + |> Array.tryFind (fun arg -> arg.StartsWith(logMarker, StringComparison.Ordinal)) |> Option.map (fun log -> log.Substring(logMarker.Length)) with | Some ("warn" | "warning") -> Logging.LogLevel.Warn @@ -155,7 +155,7 @@ let main args = let args = args - |> Array.filter (fun arg -> not <| arg.StartsWith logMarker) + |> Array.filter (fun arg -> not <| arg.StartsWith(logMarker, StringComparison.Ordinal)) logLevel, args @@ -173,10 +173,10 @@ let main args = let toExclude = args - |> Array.filter (fun arg -> arg.StartsWith excludeMarker) + |> Array.filter (fun arg -> arg.StartsWith(excludeMarker, StringComparison.Ordinal)) |> Array.collect (fun arg -> arg.Substring(excludeMarker.Length).Split(',')) - let args = args |> Array.filter (fun arg -> not <| arg.StartsWith excludeMarker) + let args = args |> Array.filter (fun arg -> not <| arg.StartsWith(excludeMarker, StringComparison.Ordinal)) toExclude, args diff --git a/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.Tests.fs b/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.Tests.fs index e2af34854..fd9d630a2 100644 --- a/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.Tests.fs +++ b/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.Tests.fs @@ -1,4 +1,6 @@ module Utils.Tests.TextEdit + +open System open Expecto open Expecto.Logging open Expecto.Logging.Message @@ -512,7 +514,7 @@ printfn "$0Result$0=%i$0" b$0 let beforeIndexTests = testList (nameof Cursor.beforeIndex) [ let assertBeforeIndex expected textWithCursor = let textWithCursor = Text.trimTripleQuotation textWithCursor - let idx = textWithCursor.IndexOf Cursor.Marker + let idx = textWithCursor.IndexOf(Cursor.Marker, StringComparison.Ordinal) Expect.isGreaterThanOrEqual "Text has no cursor" (idx, 0) let text = textWithCursor.Remove(idx, Cursor.Marker.Length) @@ -669,7 +671,7 @@ printfn "Result=%i" b$0""" let (pos, text) = assertAndGetTextAndCursor textWithCursor match Cursor.tryIndexOf pos text with | Ok actualIndex -> - let idxInText = textWithCursor.IndexOf Cursor.Marker + let idxInText = textWithCursor.IndexOf(Cursor.Marker, StringComparison.Ordinal) let errorMsg = $"wrong index. Cursor at Postion={{Line={pos.Line};Char={pos.Character}}} or Index={idxInText}" Expect.equal errorMsg expectedIndex actualIndex | Result.Error msg -> failtest $"should have found index. But was error: {msg}" @@ -868,7 +870,7 @@ printfn "Result=%i" b testList "idx |> beforeIndex |> tryIndexOf = idx" [ let value (textWithCursor: string) = - let idx = textWithCursor.IndexOf Cursor.Marker + let idx = textWithCursor.IndexOf(Cursor.Marker, StringComparison.Ordinal) if idx < 0 then failtest "No cursor" let text = textWithCursor.Replace(Cursor.Marker, "") @@ -1259,7 +1261,7 @@ $0printfn "$0Result=%i" b$0 |> Text.lines |> Seq.indexed |> Seq.choose (fun (l, line) -> - match line.IndexOf "incrementNumber" with + match line.IndexOf("incrementNumber", StringComparison.Ordinal) with | -1 -> None | c -> Some (pos l c) ) diff --git a/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.fs b/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.fs index 62372067b..fb06abb78 100644 --- a/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.fs +++ b/test/FsAutoComplete.Tests.Lsp/Utils/TextEdit.fs @@ -1,4 +1,6 @@ module Utils.TextEdit + +open System open Ionide.LanguageServerProtocol.Types open Utils.Utils open Expecto @@ -49,7 +51,7 @@ module Cursor = /// Note: Cursor Position is BEFORE index. /// Note: Index might be `text.Length` (-> Cursor AFTER last char in text) let tryExtractIndex (text: string) = - match text.IndexOf Marker with + match text.IndexOf(Marker, StringComparison.Ordinal) with | -1 -> None | i -> (i, text.Remove(i, Marker.Length)) @@ -65,7 +67,7 @@ module Cursor = let markersInLine = markers |> Array.choose (fun marker -> - match line.IndexOf marker with + match line.IndexOf(marker, StringComparison.Ordinal) with | -1 -> None | column -> Some (marker, column) ) @@ -252,7 +254,7 @@ module Cursors = /// Note: doesn't trim input! let iter (textWithCursors: string) = let rec collect (textsWithSingleCursor) (textWithCursors: string) = - match textWithCursors.IndexOf Cursor.Marker with + match textWithCursors.IndexOf(Cursor.Marker, StringComparison.Ordinal) with | -1 -> textsWithSingleCursor |> List.rev | i -> let textWithSingleCursor =