diff --git a/src/Compiler/Checking/CheckFormatStrings.fs b/src/Compiler/Checking/CheckFormatStrings.fs index e32d073cbd..db54212774 100644 --- a/src/Compiler/Checking/CheckFormatStrings.fs +++ b/src/Compiler/Checking/CheckFormatStrings.fs @@ -58,7 +58,7 @@ let escapeDotnetFormatString str = [] let (|PrefixedBy|_|) (prefix: string) (str: string) = - if str.StartsWith prefix then + if str.StartsWithOrdinal(prefix) then ValueSome prefix.Length else ValueNone @@ -370,7 +370,7 @@ let parseFormatStringInternal // type checker. They should always have '(...)' after for format string. let requireAndSkipInterpolationHoleFormat i = if i < len && fmt[i] = '(' then - let i2 = fmt.IndexOf(")", i+1) + let i2 = fmt.IndexOfOrdinal(")", i+1) if i2 = -1 then failwith (FSComp.SR.forFormatInvalidForInterpolated3()) else diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 3c0f68c285..6bc57f606c 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -1713,7 +1713,7 @@ and SolveMemberConstraint (csenv: ConstraintSolverEnv) ignoreUnresolvedOverload None let anonRecdPropSearch = - let isGetProp = nm.StartsWith "get_" + let isGetProp = nm.StartsWithOrdinal("get_") if not isRigid && isGetProp && memFlags.IsInstance then let propName = nm[4..] let props = diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 4878c66511..5aed55cba0 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -538,7 +538,7 @@ type CalledMeth<'T> // Detect the special case where an indexer setter using param aray takes 'value' argument after ParamArray arguments let isIndexerSetter = match pinfoOpt with - | Some pinfo when pinfo.HasSetter && minfo.LogicalName.StartsWith "set_" && (List.concat fullCurriedCalledArgs).Length >= 2 -> true + | Some pinfo when pinfo.HasSetter && minfo.LogicalName.StartsWithOrdinal("set_") && (List.concat fullCurriedCalledArgs).Length >= 2 -> true | _ -> false let argSetInfos = diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index d3d2ca9c59..1c2d8370b2 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -55,7 +55,7 @@ module internal PrintUtilities = let comment str = wordL (tagText (sprintf "(* %s *)" str)) - let isDiscard (name: string) = name.StartsWith("_") + let isDiscard (name: string) = name.StartsWithOrdinal("_") let ensureFloat (s: string) = if String.forall (fun c -> Char.IsDigit c || c = '-') s then diff --git a/src/Compiler/Checking/SignatureHash.fs b/src/Compiler/Checking/SignatureHash.fs index 77a9ede414..156f64c5bd 100644 --- a/src/Compiler/Checking/SignatureHash.fs +++ b/src/Compiler/Checking/SignatureHash.fs @@ -476,7 +476,7 @@ let calculateHashOfImpliedSignature g observer (expr: ModuleOrNamespaceContents) let rec hashModuleOrNameSpaceBinding (monb: ModuleOrNamespaceBinding) = match monb with - | ModuleOrNamespaceBinding.Binding b when b.Var.LogicalName.StartsWith("doval@") -> 0 + | ModuleOrNamespaceBinding.Binding b when b.Var.LogicalName.StartsWithOrdinal("doval@") -> 0 | ModuleOrNamespaceBinding.Binding b -> HashTastMemberOrVals.hashValOrMemberNoInst (g, observer) (mkLocalValRef b.Var) | ModuleOrNamespaceBinding.Module(moduleInfo, contents) -> hashSingleModuleOrNameSpaceIncludingName (moduleInfo, contents) diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 56bb6d953c..d7fd858d95 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -812,7 +812,7 @@ type MethInfo = member x.IsUnionCaseTester = let tcref = x.ApparentEnclosingTyconRef tcref.IsUnionTycon && - x.LogicalName.StartsWith("get_Is") && + x.LogicalName.StartsWithOrdinal("get_Is") && match x.ArbitraryValRef with | Some v -> v.IsImplied | None -> false diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 540b969520..b214d41b5d 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -2694,7 +2694,7 @@ let CodeGenThen (cenv: cenv) mgbuf (entryPointInfo, methodName, eenv, alreadyUse match selfArgOpt with | Some selfArg when selfArg.LogicalName <> "this" - && not (selfArg.LogicalName.StartsWith("_")) + && not (selfArg.LogicalName.StartsWithOrdinal("_")) && not cenv.options.localOptimizationsEnabled -> let ilTy = selfArg.Type |> GenType cenv m eenv.tyenv diff --git a/src/Compiler/DependencyManager/DependencyProvider.fs b/src/Compiler/DependencyManager/DependencyProvider.fs index 329dd9bd29..858cf84fc1 100644 --- a/src/Compiler/DependencyManager/DependencyProvider.fs +++ b/src/Compiler/DependencyManager/DependencyProvider.fs @@ -612,7 +612,7 @@ type DependencyProvider let managers = RegisteredDependencyManagers compilerTools (Option.ofString outputDir) reportError - match managers |> Seq.tryFind (fun kv -> path.StartsWith(kv.Value.Key + ":")) with + match managers |> Seq.tryFind (fun kv -> path.StartsWithOrdinal(kv.Value.Key + ":")) with | None -> let err, msg = this.CreatePackageManagerUnknownError(compilerTools, outputDir, path.Split(':').[0], reportError) diff --git a/src/Compiler/DependencyManager/NativeDllResolveHandler.fs b/src/Compiler/DependencyManager/NativeDllResolveHandler.fs index 12aa28c48c..8a3161a89d 100644 --- a/src/Compiler/DependencyManager/NativeDllResolveHandler.fs +++ b/src/Compiler/DependencyManager/NativeDllResolveHandler.fs @@ -8,6 +8,7 @@ open System.IO open System.Reflection open System.Runtime.InteropServices open Internal.Utilities +open Internal.Utilities.Library open Internal.Utilities.FSharpEnvironment open FSharp.Compiler.IO @@ -88,7 +89,7 @@ type internal NativeDllResolveHandlerCoreClr(nativeProbingRoots: NativeResolutio let isRooted = Path.IsPathRooted name let useSuffix s = - not (name.Contains(s + ".") || name.EndsWith(s)) // linux devs often append version # to libraries I.e mydll.so.5.3.2 + not (name.Contains(s + ".") || name.EndsWithOrdinal(s)) // linux devs often append version # to libraries I.e mydll.so.5.3.2 let usePrefix = name.IndexOf(Path.DirectorySeparatorChar) = -1 // If name has directory information no add no prefix diff --git a/src/Compiler/Driver/FxResolver.fs b/src/Compiler/Driver/FxResolver.fs index 6f8643c30a..42681600f8 100644 --- a/src/Compiler/Driver/FxResolver.fs +++ b/src/Compiler/Driver/FxResolver.fs @@ -238,7 +238,7 @@ type internal FxResolver dotnetConfig.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) + pattern.Length - let endPos = dotnetConfig.IndexOf("\"", startPos) + let endPos = dotnetConfig.IndexOfOrdinal("\"", startPos) let ver = dotnetConfig[startPos .. endPos - 1] let path = @@ -364,7 +364,7 @@ type internal FxResolver let implDir, warnings = getImplementationAssemblyDir () let version = DirectoryInfo(implDir).Name - if version.StartsWith("x") then + if version.StartsWithOrdinal("x") then // Is running on the desktop (None, None), warnings else @@ -403,7 +403,7 @@ type internal FxResolver | ".NET", "Core" when arr.Length >= 3 -> Some("netcoreapp" + (getTfmNumber arr[2])) | ".NET", "Framework" when arr.Length >= 3 -> - if arr[2].StartsWith("4.8") then + if arr[2].StartsWithOrdinal("4.8") then Some "net48" else Some "net472" @@ -560,7 +560,7 @@ type internal FxResolver dotnetConfig.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) + pattern.Length - let endPos = dotnetConfig.IndexOf("\"", startPos) + let endPos = dotnetConfig.IndexOfOrdinal("\"", startPos) let tfm = dotnetConfig[startPos .. endPos - 1] tfm with _ -> diff --git a/src/Compiler/Facilities/prim-lexing.fs b/src/Compiler/Facilities/prim-lexing.fs index 4aa1d3a79e..5951c8338e 100644 --- a/src/Compiler/Facilities/prim-lexing.fs +++ b/src/Compiler/Facilities/prim-lexing.fs @@ -6,6 +6,7 @@ namespace FSharp.Compiler.Text open System open System.IO +open Internal.Utilities.Library type ISourceText = @@ -97,7 +98,7 @@ type StringText(str: string) = if lastIndex <= startIndex || lastIndex >= str.Length then invalidArg "target" "Too big." - str.IndexOf(target, startIndex, target.Length) <> -1 + str.IndexOfOrdinal(target, startIndex, target.Length) <> -1 member _.Length = str.Length diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 4cec0c7a8d..8e7ad330d8 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -1526,7 +1526,7 @@ let ConvReflectionTypeToILTypeRef (reflectionTy: Type) = let scoref = ILScopeRef.Assembly aref let fullName = reflectionTy.FullName - let index = fullName.IndexOf("[") + let index = fullName.IndexOfOrdinal("[") let fullName = if index = -1 then diff --git a/src/Compiler/Optimize/LowerStateMachines.fs b/src/Compiler/Optimize/LowerStateMachines.fs index 7c4835b346..ef578e8606 100644 --- a/src/Compiler/Optimize/LowerStateMachines.fs +++ b/src/Compiler/Optimize/LowerStateMachines.fs @@ -114,7 +114,7 @@ let isExpandVar g (v: Val) = let isStateMachineBindingVar g (v: Val) = isExpandVar g v || (let nm = v.LogicalName - (nm.StartsWith "builder@" || v.IsMemberThisVal) && + (nm.StartsWithOrdinal("builder@") || v.IsMemberThisVal) && not v.IsCompiledAsTopLevel) type env = @@ -833,7 +833,7 @@ type LowerStateMachine(g: TcGlobals) = |> Result.Ok elif bind.Var.IsCompiledAsTopLevel || not (resBody.resumableVars.FreeLocals.Contains(bind.Var)) || - bind.Var.LogicalName.StartsWith stackVarPrefix then + bind.Var.LogicalName.StartsWithOrdinal(stackVarPrefix) then if sm_verbose then printfn "LetExpr (non-control-flow, rewrite rhs, RepresentBindingAsTopLevelOrLocal)" RepresentBindingAsTopLevelOrLocal bind resBody m |> Result.Ok diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index a1e01d4a58..e1eaddef8a 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -1534,11 +1534,11 @@ let ValueOfExpr expr = let IsMutableStructuralBindingForTupleElement (vref: ValRef) = vref.IsCompilerGenerated && - vref.LogicalName.EndsWith suffixForTupleElementAssignmentTarget + vref.LogicalName.EndsWithOrdinal suffixForTupleElementAssignmentTarget let IsMutableForOutArg (vref: ValRef) = vref.IsCompilerGenerated && - vref.LogicalName.StartsWith(outArgCompilerGeneratedName) + vref.LogicalName.StartsWithOrdinal(outArgCompilerGeneratedName) let IsKnownOnlyMutableBeforeUse (vref: ValRef) = IsMutableStructuralBindingForTupleElement vref || @@ -1672,7 +1672,7 @@ let TryEliminateBinding cenv _env bind e2 _m = not vspec1.IsCompilerGenerated then None elif vspec1.IsFixed then None - elif vspec1.LogicalName.StartsWith stackVarPrefix || + elif vspec1.LogicalName.StartsWithOrdinal stackVarPrefix || vspec1.LogicalName.Contains suffixForVariablesThatMayNotBeEliminated then None else diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 2b23d85a7c..4c3b2dbe25 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -1909,7 +1909,7 @@ type internal TypeCheckInfo | Some(_, lines) -> let lines = lines - |> List.filter (fun line -> not (line.StartsWith("//")) && not (String.IsNullOrEmpty line)) + |> List.filter (fun line -> not (line.StartsWithOrdinal("//")) && not (String.IsNullOrEmpty line)) ToolTipText.ToolTipText [ diff --git a/src/Compiler/Service/SemanticClassification.fs b/src/Compiler/Service/SemanticClassification.fs index 3697d78137..75516028fd 100644 --- a/src/Compiler/Service/SemanticClassification.fs +++ b/src/Compiler/Service/SemanticClassification.fs @@ -75,7 +75,7 @@ module TcResolutionsExtensions = && protectAssemblyExplorationNoReraise false false (fun () -> ExistsHeadTypeInEntireHierarchy g amap range0 ty g.tcref_System_IDisposable) - let isDiscard (str: string) = str.StartsWith("_") + let isDiscard (str: string) = str.StartsWithOrdinal("_") let isValRefDisposable g amap (vref: ValRef) = not (isDiscard vref.DisplayName) diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index ce45dfeac3..1faf0a3b94 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -435,7 +435,7 @@ module UnusedDeclarations = su.IsFromDefinition && su.Symbol.DeclarationLocation.IsSome && (isScript || su.IsPrivateToFile) - && not (su.Symbol.DisplayName.StartsWith "_") + && not (su.Symbol.DisplayName.StartsWithOrdinal "_") && isPotentiallyUnusedDeclaration su.Symbol then Some(su, usages.Contains su.Symbol.DeclarationLocation.Value) diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index 4f25985461..d44395dbcc 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -409,7 +409,10 @@ let opNameQMark = CompileOpName qmark let mkSynOperator (opm: range) (oper: string) = let trivia = - if oper.StartsWith("~") && ((opm.EndColumn - opm.StartColumn) = (oper.Length - 1)) then + if + oper.StartsWithOrdinal("~") + && ((opm.EndColumn - opm.StartColumn) = (oper.Length - 1)) + then // PREFIX_OP token where the ~ was actually absent IdentTrivia.OriginalNotation(string (oper.[1..])) else diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index fa90f06ed5..0bbee0c3e5 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1882,7 +1882,7 @@ type TcGlobals( let memberName = let nm = t.MemberLogicalName let coreName = - if nm.StartsWith "op_" then nm[3..] + if nm.StartsWithOrdinal "op_" then nm[3..] elif nm = "get_Zero" then "GenericZero" elif nm = "get_One" then "GenericOne" else nm diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 76e730eab6..2bccb180db 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -10416,7 +10416,7 @@ let (|SequentialResumableCode|_|) (g: TcGlobals) expr = Some (e1, e2, m, (fun e1 e2 -> Expr.Sequential(e1, e2, NormalSeq, m))) // let __stack_step = e1 in e2 - | Expr.Let(bind, e2, m, _) when bind.Var.CompiledName(g.CompilerGlobalState).StartsWith(stackVarPrefix) -> + | Expr.Let(bind, e2, m, _) when bind.Var.CompiledName(g.CompilerGlobalState).StartsWithOrdinal(stackVarPrefix) -> Some (bind.Expr, e2, m, (fun e1 e2 -> mkLet bind.DebugPoint m bind.Var e1 e2)) | _ -> None diff --git a/src/Compiler/Utilities/PathMap.fs b/src/Compiler/Utilities/PathMap.fs index f11edef6a8..50319ea707 100644 --- a/src/Compiler/Utilities/PathMap.fs +++ b/src/Compiler/Utilities/PathMap.fs @@ -6,6 +6,7 @@ namespace Internal.Utilities open System open System.IO +open Internal.Utilities.Library open FSharp.Compiler.IO type PathMap = PathMap of Map @@ -22,7 +23,7 @@ module internal PathMap = let normalSrc = FileSystem.GetFullPathShim src let oldPrefix = - if normalSrc.EndsWith dirSepStr then + if normalSrc.EndsWithOrdinal dirSepStr then normalSrc else normalSrc + dirSepStr @@ -41,7 +42,7 @@ module internal PathMap = // oldPrefix always ends with a path separator, so there's no need // to check if it was a partial match // e.g. for the map /goo=/bar and file name /goooo - if filePath.StartsWith(oldPrefix, StringComparison.Ordinal) then + if filePath.StartsWithOrdinal oldPrefix then let replacement = replacementPrefix + filePath.Substring(oldPrefix.Length - 1) // Normalize the path separators if used uniformly in the replacement @@ -60,7 +61,7 @@ module internal PathMap = |> Option.defaultValue filePath let applyDir pathMap (dirName: string) : string = - if dirName.EndsWith dirSepStr then + if dirName.EndsWithOrdinal dirSepStr then apply pathMap dirName else let mapped = apply pathMap (dirName + dirSepStr) diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index f6deb3951e..b00398e55e 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -124,6 +124,15 @@ module internal PervasiveAutoOpens = member inline x.EndsWithOrdinalIgnoreCase value = x.EndsWith(value, StringComparison.OrdinalIgnoreCase) + member inline x.IndexOfOrdinal value = + x.IndexOf(value, StringComparison.Ordinal) + + member inline x.IndexOfOrdinal(value, startIndex) = + x.IndexOf(value, startIndex, StringComparison.Ordinal) + + member inline x.IndexOfOrdinal(value, startIndex, count) = + x.IndexOf(value, startIndex, count, StringComparison.Ordinal) + /// Get an initialization hole let getHole (r: _ ref) = match r.Value with diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index fa2f1416d9..a9ee48c4be 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -79,6 +79,12 @@ module internal PervasiveAutoOpens = member inline EndsWithOrdinalIgnoreCase: value: string -> bool + member inline IndexOfOrdinal: value: string -> int + + member inline IndexOfOrdinal: value: string * startIndex: int -> int + + member inline IndexOfOrdinal: value: string * startIndex: int * count: int -> int + type Async with /// Runs the computation synchronously, always starting on the current thread. diff --git a/src/Compiler/Utilities/sformat.fs b/src/Compiler/Utilities/sformat.fs index b4f638e819..40976d23be 100644 --- a/src/Compiler/Utilities/sformat.fs +++ b/src/Compiler/Utilities/sformat.fs @@ -285,7 +285,7 @@ module Layout = #if COMPILER let rec endsWithL (text: string) layout = match layout with - | Leaf(_, s, _) -> s.Text.EndsWith(text) + | Leaf(_, s, _) -> s.Text.EndsWith(text, StringComparison.Ordinal) | Node(_, r, _) -> endsWithL text r | Attr(_, _, l) -> endsWithL text l | ObjLeaf _ -> false @@ -512,7 +512,7 @@ module ReflectUtils = FSharpValue.GetTupleFields obj |> Array.mapi (fun i v -> (v, tyArgs[i])) let tupleType = - if reprty.Name.StartsWith "ValueTuple" then + if reprty.Name.StartsWith("ValueTuple", StringComparison.Ordinal) then TupleType.Value else TupleType.Reference