@ovatsus wrote:-
Can you please create an issue there with the problems you found? We take care to always either explicitly pass InvariantCulture or use a parameter, if there's still any place using the .Net default of using the current culture it's a bug
Below are my findings. There's nothing terrible, but I know that in a C# project, FxCop / CodeAnalysis would probably complain about all of the following. On the whole, the FSharp.Data project follows the string processing guidelines very well. Apologies in advance for any errors (false reporting of a problem) on my part.
- Use of String.Contains. Suggest to replace with String.IndexOf and specify a StringComparison arg:-
C:\fsharp-FSharp.Data-0d48470\src\Net\Http.fs(657): + if url.Contains "?" then "&" else "?"
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\NameUtils.fs(84): if name.Contains " " then
C:\fsharp-FSharp.Data-0d48470\src\Csv\CsvRuntime.fs(243): fst parsedCsvLines.FirstLine |> Array.exists (fun c -> c.Contains("\t"))
C:\fsharp-FSharp.Data-0d48470\src\Csv\CsvRuntime.fs(307): if item.Contains separator then
C:\fsharp-FSharp.Data-0d48470\src\Freebase\FreebaseRequests.fs(127): if url.Length > 1500 && url.Contains "?" then
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(71): let hasUnitOfMeasure = t.Name.Contains("[")
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(127): | t -> if not t.IsGenericParameter && t.Assembly.FullName.Contains "DesignTime" then " [DESIGNTIME]" else ""
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(220): elif mi.Name.Contains "." && not args.IsEmpty then
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(285): | Value (value, typ) when typ = typeof<string> && (value :?> string).Contains("\\") ->
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(437): if memberInfo.Name.Contains(" ") then
C:\fsharp-FSharp.Data-0d48470\src\Freebase\FreebaseProvider.fs(88): (if domainName.Contains(" ") then domainName+" Domain" else domainName+"Domain") |> tidyName
- Use of String.IndexOf with a string value (not a char value), but without a StringComparison arg:-
C:\fsharp-FSharp.Data-0d48470\src\Net\UriUtils.fs(22): let fragPos = source.IndexOf("#")
C:\fsharp-FSharp.Data-0d48470\src\Net\UriUtils.fs(23): let queryPos = source.IndexOf("?")
C:\fsharp-FSharp.Data-0d48470\src\Net\UriUtils.fs(24): let start = source.IndexOf(uri.Host) + uri.Host.Length
C:\fsharp-FSharp.Data-0d48470\src\Net\Http.fs(623): let firstEqual = cookiePart.IndexOf "="
- Use of String.StartsWith without a StringComparison arg:-
C:\fsharp-FSharp.Data-0d48470\src\Net\Http.fs(482): if not (value.StartsWith("bytes=")) then failwith "Invalid value for the Range header"
C:\fsharp-FSharp.Data-0d48470\src\Net\Http.fs(550): mimeType.StartsWith "text/" ||
C:\fsharp-FSharp.Data-0d48470\src\Net\Http.fs(556): mimeType.StartsWith "application/" && mimeType.EndsWith "+xml"
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\StructuralTypes.fs(140): | s when s.StartsWith("Record@") -> Record(Some(s.Substring("Record@".Length)))
C:\fsharp-FSharp.Data-0d48470\src\Json\JsonRuntime.fs(130): if name.StartsWith "int"
C:\fsharp-FSharp.Data-0d48470\src\Xml\XmlRuntime.fs(102): with _ when text.TrimStart().StartsWith "<" ->
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\AssemblyReplacer.fs(90): if fullName.StartsWith("FSI_") then
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\AssemblyReplacer.fs(98): if asm.FullName.StartsWith "FSI-ASSEMBLY" then
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(64): if fullName.StartsWith "FSI_" then
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(99): elif t.Name.StartsWith "FSharpFunc`" then
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(227): elif mi.Attributes &&& MethodAttributes.SpecialName = MethodAttributes.SpecialName && mi.Name.StartsWith "get_" && args.IsEmpty then
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(369): if lastItem.Name.StartsWith "Tuple`"
C:\fsharp-FSharp.Data-0d48470\src\Xml\XmlInference.fs(37): | InferedType.Primitive(t, _, optional) when inferTypesFromValues && t = typeof<string> && value.TrimStart().StartsWith "{" ->
C:\fsharp-FSharp.Data-0d48470\src\Xml\XmlGenerator.fs(372): if result.ConvertedType.Name.StartsWith "FSharpOption`1" then
C:\fsharp-FSharp.Data-0d48470\src\Freebase\FreebaseProvider.fs(496): if not (domainCategory.DomainCategoryId.Id.StartsWith("/user/")) &&
C:\fsharp-FSharp.Data-0d48470\src\Freebase\FreebaseProvider.fs(497): not (domainCategory.Domains |> Array.forall (fun c -> c.DomainId.Id.StartsWith("/user/"))) then
- Use of String.EndsWith without StringComparison arg:-
C:\fsharp-FSharp.Data-0d48470\src\Net\Http.fs(556): mimeType.StartsWith "application/" && mimeType.EndsWith "+xml"
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\StructuralInference.fs(319): if str.EndsWith suffix then
C:\fsharp-FSharp.Data-0d48470\src\Html\HtmlParser.fs(510): if ((!state.Content).ToString().EndsWith("]]>"))
- Use of StringComparison.InvariantCulture[IgnoreCase]:- (consider replacing with StringComparison.Ordinal[IgnoreCase])
C:\fsharp-FSharp.Data-0d48470\src\Net\UriUtils.fs(136): uri.ToString().EndsWith("%2F", StringComparison.InvariantCulture)
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Helpers.fs(163): |> Array.tryFind (fun (x:string) -> x.EndsWith(asmName + ".dll", StringComparison.InvariantCultureIgnoreCase))
(Microsoft guidance: "Do not use string operations based on StringComparison.InvariantCulture in most cases. One of the few exceptions is when you are persisting linguistically meaningful but culturally agnostic data.")
- String-to-value conversions with no IFormatProvider (aka cultureInfo) arg:-
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\TextConversions.fs(95): |> Double.Parse
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\NameUtils.fs(89): name <- (UInt64.Parse name + 1UL).ToString()
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\NameUtils.fs(92): name <- name.Substring(0, lastLetterPos + 1) + (UInt64.Parse number + 1UL).ToString()
C:\fsharp-FSharp.Data-0d48470\src\Json\JsonValue.fs(227): let codePoint = System.UInt32.Parse(s, NumberStyles.HexNumber) - 0x010000u
C:\fsharp-FSharp.Data-0d48470\src\CommonProviderImplementation\Debug.fs(366): typeNameSuffix.Substring(0, typeNameSuffix.IndexOf('[')) |> Int32.Parse
- Value-to-string conversions with no IFormatProvider (aka cultureInfo) arg:-
C:\fsharp-FSharp.Data-0d48470\src\Net\Http.fs(108): let MaxForwards (count:int) = "Max-Forwards", count.ToString()
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\IO.fs(80): "[" + DateTime.Now.TimeOfDay.ToString() + "] " + str
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\NameUtils.fs(89): name <- (UInt64.Parse name + 1UL).ToString()
C:\fsharp-FSharp.Data-0d48470\src\CommonRuntime\NameUtils.fs(92): name <- name.Substring(0, lastLetterPos + 1) + (UInt64.Parse number + 1UL).ToString()
C:\fsharp-FSharp.Data-0d48470\src\Csv\CsvInference.fs(153): "Column" + (i+1).ToString()
C:\fsharp-FSharp.Data-0d48470\src\Csv\CsvInference.fs(156): | None -> Array.init numberOfColumns (fun i -> "Column" + (i+1).ToString())
C:\fsharp-FSharp.Data-0d48470\src\Freebase\FreebaseProvider.fs(581): | "now" -> DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss")
@ovatsus wrote:-
Below are my findings. There's nothing terrible, but I know that in a C# project, FxCop / CodeAnalysis would probably complain about all of the following. On the whole, the FSharp.Data project follows the string processing guidelines very well. Apologies in advance for any errors (false reporting of a problem) on my part.
(Microsoft guidance: "Do not use string operations based on StringComparison.InvariantCulture in most cases. One of the few exceptions is when you are persisting linguistically meaningful but culturally agnostic data.")