Skip to content

Commit

Permalink
Optimize empty string compares (#16435)
Browse files Browse the repository at this point in the history
* use String.IsNullOrEmpty() or .Length = 0 for checks of empty strings

* To be on the safe side and for consistency reasons: Always use String.IsNullOrEmpty
  • Loading branch information
dawedawe committed Dec 14, 2023
1 parent f9b22ce commit b846403
Show file tree
Hide file tree
Showing 25 changed files with 94 additions and 65 deletions.
2 changes: 1 addition & 1 deletion src/Compiler/AbstractIL/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ type ILTypeRef =
member tref.AddQualifiedNameExtension basic =
let sco = tref.Scope.QualifiedName

if sco = "" then
if String.IsNullOrEmpty(sco) then
basic
else
String.concat ", " [ basic; sco ]
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/AbstractIL/ilwrite.fs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ let GetBytesAsBlobIdx cenv (bytes: byte[]) =
else cenv.blobs.FindOrAddSharedEntry bytes

let GetStringHeapIdx cenv s =
if s = "" then 0
if String.IsNullOrEmpty(s) then 0
else cenv.strings.FindOrAddSharedEntry s

let GetGuidIdx cenv info = cenv.guids.FindOrAddSharedEntry info
Expand Down
8 changes: 4 additions & 4 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2495,7 +2495,7 @@ module TcExceptionDeclarations =

let TcExnSignature (cenv: cenv) envInitial parent tpenv (SynExceptionSig(exnRepr=core; members=aug), scopem) =
match core with
| SynExceptionDefnRepr(caseName = SynUnionCase(ident = SynIdent(ident, _))) when ident.idText = "" ->
| SynExceptionDefnRepr(caseName = SynUnionCase(ident = SynIdent(ident, _))) when String.IsNullOrEmpty(ident.idText) ->
[], [], None, envInitial
| _ ->
let g = cenv.g
Expand Down Expand Up @@ -4306,7 +4306,7 @@ module TcDeclarations =
// Convert auto properties to let bindings in the pre-list
let rec preAutoProps memb =
match memb with
| SynMemberDefn.AutoProperty(ident = id) when id.idText = "" -> []
| SynMemberDefn.AutoProperty(ident = id) when String.IsNullOrEmpty(id.idText) -> []
| SynMemberDefn.AutoProperty(attributes=Attributes attribs; isStatic=isStatic; ident=id; typeOpt=tyOpt; propKind=propKind; xmlDoc=xmlDoc; synExpr=synExpr; range=mWholeAutoProp) ->
// Only the keep the field-targeted attributes
let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> true | _ -> false)
Expand Down Expand Up @@ -4334,7 +4334,7 @@ module TcDeclarations =
// Convert auto properties to member bindings in the post-list
let rec postAutoProps memb =
match memb with
| SynMemberDefn.AutoProperty(ident = id) when id.idText = "" -> []
| SynMemberDefn.AutoProperty(ident = id) when String.IsNullOrEmpty(id.idText) -> []
| SynMemberDefn.AutoProperty(attributes=Attributes attribs; isStatic=isStatic; ident=id; typeOpt=tyOpt; propKind=propKind; memberFlags=memberFlags; memberFlagsForSet=memberFlagsForSet; xmlDoc=xmlDoc; accessibility=access; trivia = { GetSetKeywords = mGetSetOpt }) ->
let mMemberPortion = id.idRange
// Only the keep the non-field-targeted attributes
Expand Down Expand Up @@ -5073,7 +5073,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
return ([], [], []), env, env

| SynModuleDecl.Exception (SynExceptionDefn(SynExceptionDefnRepr(caseName = SynUnionCase(ident = SynIdent(id, _))) as exnRepr, withKeyword, ms, mExDefn), m) ->
if id.idText = "" then
if String.IsNullOrEmpty(id.idText) then
return ([], [], []), env, env
else
let edef = SynExceptionDefn(exnRepr, withKeyword, desugarGetSetMembers ms, mExDefn)
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/Checking/CheckFormatStrings.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

module internal FSharp.Compiler.CheckFormatStrings

open System
open System.Text
open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
Expand Down Expand Up @@ -375,7 +376,7 @@ let parseFormatStringInternal
failwith (FSComp.SR.forFormatInvalidForInterpolated3())
else
let dotnetAlignment = match widthValue with None -> "" | Some w -> "," + (if info.leftJustify then "-" else "") + string w
let dotnetNumberFormat = match fmt[i+1..i2-1] with "" -> "" | s -> ":" + s
let dotnetNumberFormat = match fmt[i+1..i2-1] with s when String.IsNullOrEmpty(s) -> "" | s -> ":" + s
appendToDotnetFormatString ("{" + string dotnetFormatStringInterpolationHoleCount + dotnetAlignment + dotnetNumberFormat + "}")
dotnetFormatStringInterpolationHoleCount <- dotnetFormatStringInterpolationHoleCount + 1
i2+1
Expand Down
11 changes: 6 additions & 5 deletions src/Compiler/Checking/InfoReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/// Select members from a type by name, searching the type hierarchy if needed
module internal FSharp.Compiler.InfoReader

open System
open System.Collections.Concurrent
open System.Collections.Generic
open Internal.Utilities.Library
Expand Down Expand Up @@ -1097,14 +1098,14 @@ let GetXmlDocSigOfEntityRef infoReader m (eref: EntityRef) =
else
let ccuFileName = libFileOfEntityRef eref
let m = eref.Deref
if m.XmlDocSig = "" then
if String.IsNullOrEmpty(m.XmlDocSig) then
m.XmlDocSig <- XmlDocSigOfEntity eref
Some (ccuFileName, m.XmlDocSig)

let GetXmlDocSigOfScopedValRef g (tcref: TyconRef) (vref: ValRef) =
let ccuFileName = libFileOfEntityRef tcref
let v = vref.Deref
if v.XmlDocSig = "" && v.HasDeclaringEntity then
if String.IsNullOrEmpty(v.XmlDocSig) && v.HasDeclaringEntity then
let ap = buildAccessPath vref.DeclaringEntity.CompilationPathOpt
let path =
if vref.DeclaringEntity.IsModule then
Expand All @@ -1118,14 +1119,14 @@ let GetXmlDocSigOfScopedValRef g (tcref: TyconRef) (vref: ValRef) =
let GetXmlDocSigOfRecdFieldRef (rfref: RecdFieldRef) =
let tcref = rfref.TyconRef
let ccuFileName = libFileOfEntityRef tcref
if rfref.RecdField.XmlDocSig = "" then
if String.IsNullOrEmpty(rfref.RecdField.XmlDocSig) then
rfref.RecdField.XmlDocSig <- XmlDocSigOfProperty [tcref.CompiledRepresentationForNamedType.FullName; rfref.RecdField.LogicalName]
Some (ccuFileName, rfref.RecdField.XmlDocSig)

let GetXmlDocSigOfUnionCaseRef (ucref: UnionCaseRef) =
let tcref = ucref.TyconRef
let ccuFileName = libFileOfEntityRef tcref
if ucref.UnionCase.XmlDocSig = "" then
if String.IsNullOrEmpty(ucref.UnionCase.XmlDocSig) then
ucref.UnionCase.XmlDocSig <- XmlDocSigOfUnionCase [tcref.CompiledRepresentationForNamedType.FullName; ucref.CaseName]
Some (ccuFileName, ucref.UnionCase.XmlDocSig)

Expand Down Expand Up @@ -1171,7 +1172,7 @@ let GetXmlDocSigOfValRef g (vref: ValRef) =
if not vref.IsLocalRef then
let ccuFileName = vref.nlr.Ccu.FileName
let v = vref.Deref
if v.XmlDocSig = "" && v.HasDeclaringEntity then
if String.IsNullOrEmpty(v.XmlDocSig) && v.HasDeclaringEntity then
v.XmlDocSig <- XmlDocSigOfVal g false vref.DeclaringEntity.CompiledRepresentationForNamedType.Name v
Some (ccuFileName, v.XmlDocSig)
else
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Checking/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ module internal PrintUtilities =
else s)

let pathText = trimPathByDisplayEnv denv path
if pathText = "" then tyconTextL else leftL (tagUnknownEntity pathText) ^^ tyconTextL
if String.IsNullOrEmpty(pathText) then tyconTextL else leftL (tagUnknownEntity pathText) ^^ tyconTextL

let layoutBuiltinAttribute (denv: DisplayEnv) (attrib: BuiltinAttribInfo) =
let tcref = attrib.TyconRef
Expand Down Expand Up @@ -2793,7 +2793,7 @@ let minimalStringsOfTwoTypes denv ty1 ty2 =
let denv = denv.SetOpenPaths []
let denv = { denv with includeStaticParametersInTypeNames=true }
let makeName t =
let assemblyName = PrintTypes.layoutAssemblyName denv t |> function | null | "" -> "" | name -> sprintf " (%s)" name
let assemblyName = PrintTypes.layoutAssemblyName denv t |> fun name -> if String.IsNullOrEmpty(name) then "" else sprintf " (%s)" name
sprintf "%s%s" (stringOfTy denv t) assemblyName

(makeName ty1, makeName ty2, stringOfTyparConstraints denv tpcs)
Expand Down
7 changes: 4 additions & 3 deletions src/Compiler/CodeGen/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module internal FSharp.Compiler.IlxGen

open FSharp.Compiler.IlxGenSupport

open System
open System.IO
open System.Reflection
open System.Collections.Generic
Expand Down Expand Up @@ -420,7 +421,7 @@ let CompLocForFixedPath fragName qname (CompPath(sref, cpath)) =
let ns = List.map fst ns
let ns = textOfPath ns
let encl = t |> List.map (fun (s, _) -> s)
let ns = if ns = "" then None else Some ns
let ns = if String.IsNullOrEmpty(ns) then None else Some ns

{
QualifiedNameOfFile = fragName
Expand Down Expand Up @@ -2833,7 +2834,7 @@ and GenExprPreSteps (cenv: cenv) (cgbuf: CodeGenBuffer) eenv expr sequel =
match expr with
| Expr.Sequential((DebugPointExpr g debugPointName) as dpExpr, codeExpr, NormalSeq, m) ->
match cenv.namedDebugPointsForInlinedCode.TryGetValue({ Range = m; Name = debugPointName }) with
| false, _ when debugPointName = "" -> CG.EmitDebugPoint cgbuf m
| false, _ when String.IsNullOrEmpty(debugPointName) -> CG.EmitDebugPoint cgbuf m
| false, _ ->
// printfn $"---- Unfound debug point {debugPointName} at {m}"
// for KeyValue(k,v) in cenv.namedDebugPointsForInlinedCode do
Expand Down Expand Up @@ -8614,7 +8615,7 @@ and GenMarshal cenv attribs =
let safeArrayUserDefinedSubType =
// the argument is a System.Type obj, but it's written to MD as a UTF8 string
match decoder.FindTypeName "SafeArrayUserDefinedSubType" "" with
| "" -> None
| x when String.IsNullOrEmpty(x) -> None
| res ->
if
(safeArraySubType = ILNativeVariant.IDispatch)
Expand Down
8 changes: 5 additions & 3 deletions src/Compiler/Driver/CompilerDiagnostics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -896,9 +896,11 @@ type Exception with
[ knownReturnType; genericParametersMessage; argsMessage ]
|> List.choose id
|> String.concat (nl + nl)
|> function
| "" -> nl
| result -> nl + nl + result + nl + nl
|> fun result ->
if String.IsNullOrEmpty(result) then
nl
else
nl + nl + result + nl + nl

match failure with
| NoOverloadsFound(methodName, overloads, _) ->
Expand Down
16 changes: 8 additions & 8 deletions src/Compiler/Driver/CompilerOptions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ let compilerOptionUsage (CompilerOption(s, tag, spec, _, _)) =
| OptionFloat _ -> sprintf "--%s:%s" s tag
| OptionRest _ -> sprintf "--%s ..." s
| OptionGeneral _ ->
if tag = "" then
if String.IsNullOrEmpty(tag) then
sprintf "%s" s
else
sprintf "%s:%s" s tag (* still being decided *)
Expand Down Expand Up @@ -270,7 +270,7 @@ let ParseCompilerOptions (collectOtherArgument: string -> unit, blocks: Compiler
let optArgs = String.Join(":", opts[1..])

let opt =
if option = "" then
if String.IsNullOrEmpty(option) then
""
// if it doesn't start with a '-' or '/', reject outright
elif option[0] <> '-' && option[0] <> '/' then
Expand Down Expand Up @@ -298,13 +298,13 @@ let ParseCompilerOptions (collectOtherArgument: string -> unit, blocks: Compiler
opt, token, optArgs

let getOptionArg compilerOption (argString: string) =
if argString = "" then
if String.IsNullOrEmpty(argString) then
errorR (Error(FSComp.SR.buildOptionRequiresParameter (compilerOptionUsage compilerOption), rangeCmdArgs))

argString

let getOptionArgList compilerOption (argString: string) =
if argString = "" then
if String.IsNullOrEmpty(argString) then
errorR (Error(FSComp.SR.buildOptionRequiresParameter (compilerOptionUsage compilerOption), rangeCmdArgs))
[]
else
Expand Down Expand Up @@ -375,19 +375,19 @@ let ParseCompilerOptions (collectOtherArgument: string -> unit, blocks: Compiler
reportDeprecatedOption d
f blocks
t
| CompilerOption(s, _, OptionUnit f, d, _) :: _ when optToken = s && argString = "" ->
| CompilerOption(s, _, OptionUnit f, d, _) :: _ when optToken = s && String.IsNullOrEmpty(argString) ->
reportDeprecatedOption d
f ()
t
| CompilerOption(s, _, OptionSwitch f, d, _) :: _ when getSwitchOpt optToken = s && argString = "" ->
| CompilerOption(s, _, OptionSwitch f, d, _) :: _ when getSwitchOpt optToken = s && String.IsNullOrEmpty(argString) ->
reportDeprecatedOption d
f (getSwitch opt)
t
| CompilerOption(s, _, OptionSet f, d, _) :: _ when optToken = s && argString = "" ->
| CompilerOption(s, _, OptionSet f, d, _) :: _ when optToken = s && String.IsNullOrEmpty(argString) ->
reportDeprecatedOption d
f.Value <- true
t
| CompilerOption(s, _, OptionClear f, d, _) :: _ when optToken = s && argString = "" ->
| CompilerOption(s, _, OptionClear f, d, _) :: _ when optToken = s && String.IsNullOrEmpty(argString) ->
reportDeprecatedOption d
f.Value <- false
t
Expand Down
17 changes: 10 additions & 7 deletions src/Compiler/Driver/CreateILModule.fs
Original file line number Diff line number Diff line change
Expand Up @@ -584,19 +584,22 @@ module MainModuleBuilder =
[ resource ]

// a user cannot specify both win32res and win32manifest
if not (tcConfig.win32manifest = "") && not (tcConfig.win32res = "") then
if
not (String.IsNullOrEmpty(tcConfig.win32manifest))
&& not (String.IsNullOrEmpty(tcConfig.win32res))
then
error (Error(FSComp.SR.fscTwoResourceManifests (), rangeCmdArgs))

let win32Manifest =
// use custom manifest if provided
if not (tcConfig.win32manifest = "") then
if not (String.IsNullOrEmpty(tcConfig.win32manifest)) then
tcConfig.win32manifest

// don't embed a manifest if target is not an exe, if manifest is specifically excluded, if another native resource is being included, or if running on mono
elif
not (tcConfig.target.IsExe)
|| not (tcConfig.includewin32manifest)
|| not (tcConfig.win32res = "")
|| not (String.IsNullOrEmpty(tcConfig.win32res))
then
""
// otherwise, include the default manifest
Expand All @@ -618,9 +621,9 @@ module MainModuleBuilder =
[
for av in assemblyVersionResources assemblyVersion do
ILNativeResource.Out av
if not (tcConfig.win32res = "") then
if not (String.IsNullOrEmpty(tcConfig.win32res)) then
ILNativeResource.Out(FileSystem.OpenFileForReadShim(tcConfig.win32res).ReadAllBytes())
if tcConfig.includewin32manifest && not (win32Manifest = "") then
if tcConfig.includewin32manifest && not (String.IsNullOrEmpty(win32Manifest)) then
ILNativeResource.Out
[|
yield! ResFileFormat.ResFileHeader()
Expand All @@ -631,8 +634,8 @@ module MainModuleBuilder =
))
|]
if
tcConfig.win32res = ""
&& tcConfig.win32icon <> ""
String.IsNullOrEmpty(tcConfig.win32res)
&& not (String.IsNullOrEmpty(tcConfig.win32icon))
&& tcConfig.target <> CompilerTarget.Dll
then
use ms = new MemoryStream()
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Driver/fsc.fs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ module InterfaceFileWriter =
let writeAllToSameFile declaredImpls =
/// Use a UTF-8 Encoding with no Byte Order Mark
let os =
if tcConfig.printSignatureFile = "" then
if String.IsNullOrEmpty(tcConfig.printSignatureFile) then
Console.Out
else
FileSystem
Expand Down
5 changes: 2 additions & 3 deletions src/Compiler/Facilities/CompilerLocation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ module internal FSharpEnvironment =
let FSharpCoreLibRunningVersion =
try
match versionOf<Unit> with
| null -> None
| "" -> None
| s when String.IsNullOrEmpty(s) -> None
| s -> Some(s)
with _ ->
None
Expand Down Expand Up @@ -184,7 +183,7 @@ module internal FSharpEnvironment =
| None -> ()
| Some(p: string) ->
match Path.GetDirectoryName(p) with
| s when s = "" || isNull s || Path.GetFileName(p) = "packages" || s = p -> ()
| s when String.IsNullOrEmpty(s) || Path.GetFileName(p) = "packages" || s = p -> ()
| parentDir -> yield! searchParentDirChain (Some parentDir) assemblyName

for p in searchToolPaths path compilerToolPaths do
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Interactive/fsi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -933,12 +933,12 @@ type DiagnosticsLogger with

/// Get the directory name from a string, with some defaults if it doesn't have one
let internal directoryName (s: string) =
if s = "" then
if String.IsNullOrEmpty(s) then
"."
else
match Path.GetDirectoryName s with
| null -> if FileSystem.IsPathRootedShim s then s else "."
| res -> if res = "" then "." else res
| res -> if String.IsNullOrEmpty(res) then "." else res

//----------------------------------------------------------------------------
// cmd line - state for options
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Service/FSharpCheckerResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2252,7 +2252,7 @@ type internal TypeCheckInfo
| Some itemRange ->
let projectDir =
FileSystem.GetDirectoryNameShim(
if projectFileName = "" then
if String.IsNullOrEmpty(projectFileName) then
mainInputFileName
else
projectFileName
Expand Down
6 changes: 5 additions & 1 deletion src/Compiler/Service/ServiceAnalysis.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace FSharp.Compiler.EditorServices

open System
open System.Collections.Generic
open System.Runtime.CompilerServices
open Internal.Utilities.Library
Expand Down Expand Up @@ -332,7 +333,10 @@ module SimplifyNames =
- partialName.PartialIdent.Length
- (getPlidLength partialName.QualifyingIdents)

if partialName.PartialIdent = "" || List.isEmpty partialName.QualifyingIdents then
if
String.IsNullOrEmpty(partialName.PartialIdent)
|| List.isEmpty partialName.QualifyingIdents
then
None
else
Some(symbolUse, partialName.QualifyingIdents, plidStartCol, partialName.PartialIdent))
Expand Down
Loading

0 comments on commit b846403

Please sign in to comment.