Skip to content

Commit c847d49

Browse files
github-actions[bot]Repo AssistCopilotdsyme
authored
[Repo Assist] Use explicit StringComparison.Ordinal for string comparisons (fixes #742) (#1670)
* Use explicit StringComparison.Ordinal for string operations throughout codebase Fixes all cases of String.StartsWith, String.EndsWith, String.Contains and String.IndexOf (with string argument) that were missing an explicit StringComparison argument, as identified in issue #742. Changes: - Use StringComparison.Ordinal for all StartsWith/EndsWith comparisons on ASCII/code identifiers and syntax strings - Replace String.Contains with IndexOf(char) for single-char literals (netstandard2.0 compatible) or IndexOf(string, StringComparison.Ordinal) for variable string arguments - Replace ToLower() with ToLowerInvariant() in HtmlParser Files changed: - src/FSharp.Data.Runtime.Utilities/StructuralTypes.fs - src/FSharp.Data.Runtime.Utilities/StructuralInference.fs - src/FSharp.Data.Runtime.Utilities/NameUtils.fs - src/FSharp.Data.Xml.Core/XmlRuntime.fs - src/FSharp.Data.Xml.Core/XmlInference.fs - src/FSharp.Data.Http/Http.fs - src/FSharp.Data.DesignTime/Xml/XmlGenerator.fs - src/FSharp.Data.Csv.Core/CsvRuntime.fs - src/FSharp.Data.Json.Core/JsonSchema.fs - src/FSharp.Data.Html.Core/HtmlOperations.fs - src/FSharp.Data.Html.Core/HtmlParser.fs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * ci: trigger CI checks --------- Co-authored-by: Repo Assist <repo-assist@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Don Syme <dsyme@users.noreply.github.com>
1 parent 49d4888 commit c847d49

11 files changed

Lines changed: 44 additions & 23 deletions

File tree

src/FSharp.Data.Csv.Core/CsvRuntime.fs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ type CsvFile<'RowType>
382382
let probablyTabSeparated =
383383
parsedCsvLines.ColumnCount < 2
384384
&& noSeparatorsSpecified
385-
&& fst parsedCsvLines.FirstLine |> Array.exists (fun c -> c.Contains "\t")
385+
&& fst parsedCsvLines.FirstLine |> Array.exists (fun c -> c.IndexOf('\t') >= 0)
386386

387387
let parsedCsvLines =
388388
if probablyTabSeparated then
@@ -474,7 +474,11 @@ type CsvFile<'RowType>
474474
|> writeLine (fun item ->
475475
let item = item |> nullSafeguard
476476

477-
if item.Contains separator || item.Contains quote || item.Contains "\n" then
477+
if
478+
item.IndexOf(separator, StringComparison.Ordinal) >= 0
479+
|| item.IndexOf(quote, StringComparison.Ordinal) >= 0
480+
|| item.IndexOf('\n') >= 0
481+
then
478482
writer.Write quote
479483
writer.Write(item.Replace(quote, doubleQuote))
480484
writer.Write quote

src/FSharp.Data.DesignTime/Xml/XmlGenerator.fs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,8 @@ module internal XmlTypeBuilder =
441441
[ for child in children ->
442442

443443
let isCollectionName parentName childName =
444-
parentName = NameUtils.pluralize childName || parentName.StartsWith childName
444+
parentName = NameUtils.pluralize childName
445+
|| parentName.StartsWith(childName, StringComparison.Ordinal)
445446

446447
let child =
447448
match child with
@@ -495,9 +496,9 @@ module internal XmlTypeBuilder =
495496
let convFunc = ReflectionHelpers.makeDelegate result.Converter typeof<XmlElement>
496497

497498
let isCollectionName =
498-
names.[0].EndsWith "List"
499-
|| names.[0].EndsWith "Array"
500-
|| names.[0].EndsWith "Collection"
499+
names.[0].EndsWith("List", StringComparison.Ordinal)
500+
|| names.[0].EndsWith("Array", StringComparison.Ordinal)
501+
|| names.[0].EndsWith("Collection", StringComparison.Ordinal)
501502

502503
let name =
503504
makeUnique (
@@ -527,7 +528,12 @@ module internal XmlTypeBuilder =
527528
let convFunc = ReflectionHelpers.makeDelegate result.Converter typeof<XmlElement>
528529
let name = makeUnique names.[names.Length - 1]
529530

530-
if result.ConvertedType.Name.StartsWith "FSharpOption`1" then
531+
if
532+
result.ConvertedType.Name.StartsWith(
533+
"FSharpOption`1",
534+
StringComparison.Ordinal
535+
)
536+
then
531537
nameWithNS,
532538
ProvidedProperty(
533539
name,

src/FSharp.Data.Html.Core/HtmlOperations.fs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,15 @@ module HtmlNode =
352352
selectElements' FilterLevel.Root selectedNodes t
353353

354354
| OpenAttribute _ :: AttributeName(_, name) :: EndWith _ :: AttributeValue(_, value) :: CloseAttribute _ :: t ->
355-
let selectedNodes = filterByAttr level acc name (fun v -> v.EndsWith value)
355+
let selectedNodes =
356+
filterByAttr level acc name (fun v -> v.EndsWith(value, StringComparison.Ordinal))
357+
356358
selectElements' FilterLevel.Root selectedNodes t
357359

358360
| OpenAttribute _ :: AttributeName(_, name) :: StartWith _ :: AttributeValue(_, value) :: CloseAttribute _ :: t ->
359-
let selectedNodes = filterByAttr level acc name (fun v -> v.StartsWith value)
361+
let selectedNodes =
362+
filterByAttr level acc name (fun v -> v.StartsWith(value, StringComparison.Ordinal))
363+
360364
selectElements' FilterLevel.Root selectedNodes t
361365

362366
| OpenAttribute _ :: AttributeName(_, name) :: AttributeContainsPrefix _ :: AttributeValue(_, value) :: CloseAttribute _ :: t ->

src/FSharp.Data.Html.Core/HtmlParser.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,12 @@ module internal HtmlParser =
177177
x.Tokens <- result :: x.Tokens
178178

179179
member x.IsFormattedTag =
180-
match x.CurrentTagName().ToLower() with
180+
match x.CurrentTagName().ToLowerInvariant() with
181181
| "pre" -> true
182182
| _ -> false
183183

184184
member x.IsScriptTag =
185-
match x.CurrentTagName().ToLower() with
185+
match x.CurrentTagName().ToLowerInvariant() with
186186
| "script"
187187
| "style" -> true
188188
| _ -> false

src/FSharp.Data.Http/Http.fs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,7 +1740,7 @@ module internal HttpHelpers =
17401740
| "origin" -> req.Headers.["Origin"] <- value
17411741
| "pragma" -> req.Headers.[HeaderEnum.Pragma] <- value
17421742
| "range" ->
1743-
if not (value.StartsWith("bytes=")) then
1743+
if not (value.StartsWith("bytes=", StringComparison.Ordinal)) then
17441744
failwithf "Invalid value for the Range header (%O)" value
17451745

17461746
let bytes = value.Substring("bytes=".Length).Split('-')
@@ -1821,15 +1821,17 @@ module internal HttpHelpers =
18211821
let isText (mimeType: string) =
18221822
let mimeType = mimeType.Trim()
18231823

1824-
mimeType.StartsWith "text/"
1824+
mimeType.StartsWith("text/", StringComparison.Ordinal)
18251825
|| mimeType = HttpContentTypes.Json
18261826
|| mimeType = HttpContentTypes.Xml
18271827
|| mimeType = HttpContentTypes.JavaScript
18281828
|| mimeType = HttpContentTypes.JsonRpc
18291829
|| mimeType = "application/ecmascript"
18301830
|| mimeType = "application/xml-dtd"
1831-
|| mimeType.StartsWith "application/" && mimeType.EndsWith "+xml"
1832-
|| mimeType.StartsWith "application/" && mimeType.EndsWith "+json"
1831+
|| mimeType.StartsWith("application/", StringComparison.Ordinal)
1832+
&& mimeType.EndsWith("+xml", StringComparison.Ordinal)
1833+
|| mimeType.StartsWith("application/", StringComparison.Ordinal)
1834+
&& mimeType.EndsWith("+json", StringComparison.Ordinal)
18331835

18341836
mimeType.Split([| ';' |], StringSplitOptions.RemoveEmptyEntries)
18351837
|> Array.exists isText
@@ -2009,7 +2011,7 @@ type Http private () =
20092011
| [] -> url
20102012
| query ->
20112013
url
2012-
+ if url.Contains "?" then "&" else "?"
2014+
+ if url.IndexOf('?') >= 0 then "&" else "?"
20132015
+ String.concat "&" [ for k, v in query -> Uri.EscapeDataString k + "=" + Uri.EscapeDataString v ]
20142016

20152017
static member private InnerRequest

src/FSharp.Data.Json.Core/JsonSchema.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ module JsonSchema =
319319
// This is a simplified implementation - a complete one would handle JSON pointers properly
320320
let rec resolveRef (refPath: string) =
321321
match refPath with
322-
| path when path.StartsWith("#/") ->
322+
| path when path.StartsWith("#/", StringComparison.Ordinal) ->
323323
// Handle local references like "#/definitions/Point"
324324
let parts = path.Substring(2).Split('/')
325325

src/FSharp.Data.Runtime.Utilities/NameUtils.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ let uniqueGenerator (niceName: string -> string) =
117117
lastLetterPos <- lastLetterPos - 1
118118

119119
if lastLetterPos = name.Length - 1 then
120-
if name.Contains " " then
120+
if name.IndexOf(' ') >= 0 then
121121
name <- name + " 2"
122122
else
123123
name <- name + "2"

src/FSharp.Data.Runtime.Utilities/StructuralInference.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ let parseUnitOfMeasure (provider: IUnitsOfMeasureProvider) (str: string) =
413413
uomTransformations
414414
|> List.collect (fun (suffixes, trans) -> suffixes |> List.map (fun suffix -> suffix, trans))
415415
|> List.tryPick (fun (suffix, trans) ->
416-
if str.EndsWith suffix then
416+
if str.EndsWith(suffix, StringComparison.Ordinal) then
417417
let baseUnitStr = str.[.. str.Length - suffix.Length - 1]
418418
let baseUnit = provider.SI baseUnitStr
419419

src/FSharp.Data.Runtime.Utilities/StructuralTypes.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ type internal InferedTypeTag with
178178
/// Parses code returned by 'Code' member (to be used in provided code)
179179
static member ParseCode(str: string) =
180180
match str with
181-
| s when s.StartsWith("Record@") -> Record(Some(s.Substring("Record@".Length)))
181+
| s when s.StartsWith("Record@", StringComparison.Ordinal) -> Record(Some(s.Substring("Record@".Length)))
182182
| "Record" -> Record None
183183
| "Json" -> Json
184184
| "Number" -> Number

src/FSharp.Data.Xml.Core/XmlInference.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ let getInferedTypeFromValue unitsOfMeasureProvider inferenceMode cultureInfo (el
4545
| InferedType.Primitive(t, _, optional, _) when
4646
t = typeof<string>
4747
&& let v = (element.Value).TrimStart() in
48-
v.StartsWith "{" || v.StartsWith "["
48+
49+
v.StartsWith("{", StringComparison.Ordinal)
50+
|| v.StartsWith("[", StringComparison.Ordinal)
4951
->
5052
try
5153
match JsonValue.Parse(element.Value) with

0 commit comments

Comments
 (0)