From f9b22ce3382fbf6d1cad12f6eedca2e471328430 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 14 Dec 2023 16:30:42 +0100 Subject: [PATCH 1/2] Checker: recover on unresolved type in 'inherit' member (#16429) * Checker: recover when checking 'inherit' members * Add test --- src/Compiler/Checking/CheckDeclarations.fs | 6 +++--- tests/service/Symbols.fs | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 09704614b81..a263eaad8db 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -1334,10 +1334,10 @@ module MutRecBindingChecking = // Phase2B: typecheck the argument to an 'inherits' call and build the new object expr for the inherit-call | Phase2AInherit (synBaseTy, arg, baseValOpt, m) -> - let baseTy, tpenv = TcType cenv NoNewTypars CheckCxs ItemOccurence.Use WarnOnIWSAM.Yes envInstance tpenv synBaseTy - let baseTy = baseTy |> convertToTypeWithMetadataIfPossible g let inheritsExpr, tpenv = - try + try + let baseTy, tpenv = TcType cenv NoNewTypars CheckCxs ItemOccurence.Use WarnOnIWSAM.Yes envInstance tpenv synBaseTy + let baseTy = baseTy |> convertToTypeWithMetadataIfPossible g TcNewExpr cenv envInstance tpenv baseTy (Some synBaseTy.Range) true arg m with RecoverableException e -> errorRecovery e m diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index f4c417c909d..c52865d8804 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -1123,3 +1123,14 @@ let z = builder if symbolUse.Symbol.DisplayName = "builder" then (symbolUse.Range.StartLine, symbolUse.Range.StartColumn), symbolUse.IsFromComputationExpression ] + +module Member = + [] + let ``Inherit 01`` () = + let _, checkResults = getParseAndCheckResults """ +type T() = + inherit Foo() + + let i = 1 +""" + assertHasSymbolUsages ["i"] checkResults From b8464036edc2270c796cb2f1ec07a83184605dbd Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 14 Dec 2023 16:50:02 +0100 Subject: [PATCH 2/2] Optimize empty string compares (#16435) * 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 --- src/Compiler/AbstractIL/il.fs | 2 +- src/Compiler/AbstractIL/ilwrite.fs | 2 +- src/Compiler/Checking/CheckDeclarations.fs | 8 ++++---- src/Compiler/Checking/CheckFormatStrings.fs | 3 ++- src/Compiler/Checking/InfoReader.fs | 11 ++++++----- src/Compiler/Checking/NicePrint.fs | 4 ++-- src/Compiler/CodeGen/IlxGen.fs | 7 ++++--- src/Compiler/Driver/CompilerDiagnostics.fs | 8 +++++--- src/Compiler/Driver/CompilerOptions.fs | 16 ++++++++-------- src/Compiler/Driver/CreateILModule.fs | 17 ++++++++++------- src/Compiler/Driver/fsc.fs | 2 +- src/Compiler/Facilities/CompilerLocation.fs | 5 ++--- src/Compiler/Interactive/fsi.fs | 4 ++-- src/Compiler/Service/FSharpCheckerResults.fs | 2 +- src/Compiler/Service/ServiceAnalysis.fs | 6 +++++- src/Compiler/Service/ServiceNavigation.fs | 18 ++++++++++++++++-- src/Compiler/Symbols/SymbolHelpers.fs | 3 ++- src/Compiler/SyntaxTree/LexFilter.fs | 3 ++- src/Compiler/SyntaxTree/PrettyNaming.fs | 2 +- src/Compiler/SyntaxTree/XmlDoc.fs | 2 +- src/Compiler/TypedTree/TypedTreeOps.fs | 5 +++-- src/Compiler/Utilities/FileSystem.fs | 20 ++++++++++---------- src/Compiler/Utilities/illib.fs | 2 +- src/Compiler/Utilities/sformat.fs | 4 ++-- src/Compiler/Utilities/sr.fs | 3 ++- 25 files changed, 94 insertions(+), 65 deletions(-) diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index 5e475d96193..aa6c4aae69e 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -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 ] diff --git a/src/Compiler/AbstractIL/ilwrite.fs b/src/Compiler/AbstractIL/ilwrite.fs index cd4e1bfe721..5c007513153 100644 --- a/src/Compiler/AbstractIL/ilwrite.fs +++ b/src/Compiler/AbstractIL/ilwrite.fs @@ -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 diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index a263eaad8db..0a860cef0ec 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -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 @@ -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) @@ -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 @@ -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) diff --git a/src/Compiler/Checking/CheckFormatStrings.fs b/src/Compiler/Checking/CheckFormatStrings.fs index e32d073cbd1..7eb4c0355e2 100644 --- a/src/Compiler/Checking/CheckFormatStrings.fs +++ b/src/Compiler/Checking/CheckFormatStrings.fs @@ -2,6 +2,7 @@ module internal FSharp.Compiler.CheckFormatStrings +open System open System.Text open Internal.Utilities.Library open Internal.Utilities.Library.Extras @@ -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 diff --git a/src/Compiler/Checking/InfoReader.fs b/src/Compiler/Checking/InfoReader.fs index 86bbb1b83ca..f81d89a900a 100644 --- a/src/Compiler/Checking/InfoReader.fs +++ b/src/Compiler/Checking/InfoReader.fs @@ -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 @@ -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 @@ -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) @@ -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 diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index d3d2ca9c590..b37ecf518d2 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -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 @@ -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) diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 540b9695201..b8577aa4cdf 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -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 @@ -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 @@ -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 @@ -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) diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 9b4abb8a159..71d24223e14 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -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, _) -> diff --git a/src/Compiler/Driver/CompilerOptions.fs b/src/Compiler/Driver/CompilerOptions.fs index 221d02bcbb2..d1618dd19d6 100644 --- a/src/Compiler/Driver/CompilerOptions.fs +++ b/src/Compiler/Driver/CompilerOptions.fs @@ -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 *) @@ -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 @@ -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 @@ -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 diff --git a/src/Compiler/Driver/CreateILModule.fs b/src/Compiler/Driver/CreateILModule.fs index 7fa60a25957..7bc9be6b373 100644 --- a/src/Compiler/Driver/CreateILModule.fs +++ b/src/Compiler/Driver/CreateILModule.fs @@ -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 @@ -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() @@ -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() diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index d3bfd2e74cc..eab380bae5c 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -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 diff --git a/src/Compiler/Facilities/CompilerLocation.fs b/src/Compiler/Facilities/CompilerLocation.fs index fa49445b769..11f944c5f30 100644 --- a/src/Compiler/Facilities/CompilerLocation.fs +++ b/src/Compiler/Facilities/CompilerLocation.fs @@ -28,8 +28,7 @@ module internal FSharpEnvironment = let FSharpCoreLibRunningVersion = try match versionOf with - | null -> None - | "" -> None + | s when String.IsNullOrEmpty(s) -> None | s -> Some(s) with _ -> None @@ -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 diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 4cec0c7a8d2..924ea6c02e3 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -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 diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 2b23d85a7ce..80a31221270 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -2252,7 +2252,7 @@ type internal TypeCheckInfo | Some itemRange -> let projectDir = FileSystem.GetDirectoryNameShim( - if projectFileName = "" then + if String.IsNullOrEmpty(projectFileName) then mainInputFileName else projectFileName diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index ce45dfeac32..5d47bab60c9 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -2,6 +2,7 @@ namespace FSharp.Compiler.EditorServices +open System open System.Collections.Generic open System.Runtime.CompilerServices open Internal.Utilities.Library @@ -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)) diff --git a/src/Compiler/Service/ServiceNavigation.fs b/src/Compiler/Service/ServiceNavigation.fs index 7f912e07e09..03afe63b373 100755 --- a/src/Compiler/Service/ServiceNavigation.fs +++ b/src/Compiler/Service/ServiceNavigation.fs @@ -377,7 +377,14 @@ module NavigationImpl = | SynModuleDecl.NestedModule(moduleInfo = SynComponentInfo(longId = lid; accessibility = access); decls = decls; range = m) -> // Find let bindings (for the right dropdown) let nested = processNestedDeclarations (decls) - let newBaseName = (if (baseName = "") then "" else baseName + ".") + (textOfLid lid) + + let newBaseName = + (if (String.IsNullOrEmpty(baseName)) then + "" + else + baseName + ".") + + (textOfLid lid) + let other = processNavigationTopLevelDeclarations (newBaseName, decls) let mBody = unionRangesChecked (rangeOfDecls nested) (moduleRange (rangeOfLid lid) other) @@ -587,7 +594,14 @@ module NavigationImpl = | SynModuleSigDecl.NestedModule(moduleInfo = SynComponentInfo(longId = lid; accessibility = access); moduleDecls = decls; range = m) -> // Find let bindings (for the right dropdown) let nested = processNestedSigDeclarations (decls) - let newBaseName = (if baseName = "" then "" else baseName + ".") + (textOfLid lid) + + let newBaseName = + (if String.IsNullOrEmpty(baseName) then + "" + else + baseName + ".") + + (textOfLid lid) + let other = processNavigationTopLevelSigDeclarations (newBaseName, decls) // Get nested modules and types (for the left dropdown) diff --git a/src/Compiler/Symbols/SymbolHelpers.fs b/src/Compiler/Symbols/SymbolHelpers.fs index f3ad450a461..fda64a95282 100644 --- a/src/Compiler/Symbols/SymbolHelpers.fs +++ b/src/Compiler/Symbols/SymbolHelpers.fs @@ -2,6 +2,7 @@ namespace FSharp.Compiler.Symbols +open System open System.IO open Internal.Utilities.Library @@ -875,7 +876,7 @@ module internal SymbolHelpers = // works similar to generation of xml-docs at tastops.fs, probably too similar // TODO: check if this code can be implemented using xml-doc generation functionality let prefix = path.AccessPath |> Seq.map fst |> String.concat "." - let fullName = if prefix = "" then modref.CompiledName else prefix + "." + modref.CompiledName + let fullName = if String.IsNullOrEmpty(prefix) then modref.CompiledName else prefix + "." + modref.CompiledName Some fullName ) #endif diff --git a/src/Compiler/SyntaxTree/LexFilter.fs b/src/Compiler/SyntaxTree/LexFilter.fs index e592960c6ba..3e7dcfa7262 100644 --- a/src/Compiler/SyntaxTree/LexFilter.fs +++ b/src/Compiler/SyntaxTree/LexFilter.fs @@ -4,6 +4,7 @@ /// Implements the offside rule and a couple of other lexical transformations. module internal FSharp.Compiler.LexFilter +open System open System.Collections.Generic open Internal.Utilities.Text.Lexing open FSharp.Compiler @@ -537,7 +538,7 @@ let (|TyparsCloseOp|_|) (txt: string) = | "$" -> Some DOLLAR | "%" -> Some (PERCENT_OP("%") ) | "%%" -> Some (PERCENT_OP("%%")) - | "" -> None + | s when String.IsNullOrEmpty(s) -> None | s -> match List.ofSeq afterAngles with | '=' :: _ diff --git a/src/Compiler/SyntaxTree/PrettyNaming.fs b/src/Compiler/SyntaxTree/PrettyNaming.fs index c34fb57d86e..3000297d866 100755 --- a/src/Compiler/SyntaxTree/PrettyNaming.fs +++ b/src/Compiler/SyntaxTree/PrettyNaming.fs @@ -1034,7 +1034,7 @@ let MangleProvidedTypeName (typeLogicalName, nonDefaultArgs) = let nonDefaultArgsText = nonDefaultArgs |> Array.map mangleStaticStringArg |> String.concat "," - if nonDefaultArgsText = "" then + if String.IsNullOrEmpty(nonDefaultArgsText) then typeLogicalName else typeLogicalName + "," + nonDefaultArgsText diff --git a/src/Compiler/SyntaxTree/XmlDoc.fs b/src/Compiler/SyntaxTree/XmlDoc.fs index 0bfb9c09f48..74135a6ba33 100644 --- a/src/Compiler/SyntaxTree/XmlDoc.fs +++ b/src/Compiler/SyntaxTree/XmlDoc.fs @@ -23,7 +23,7 @@ type XmlDoc(unprocessedLines: string[], range: range) = | lineA :: rest as lines -> let lineAT = lineA.TrimStart([| ' ' |]) - if lineAT = "" then + if String.IsNullOrEmpty(lineAT) then processLines rest elif lineAT.StartsWithOrdinal("<") then lines diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 76e730eab6c..d9ecfe0ca96 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -3,6 +3,7 @@ /// Defines derived expression manipulation and construction functions. module internal FSharp.Compiler.TypedTreeOps +open System open System.CodeDom.Compiler open System.Collections.Generic open System.Collections.Immutable @@ -3178,7 +3179,7 @@ type DisplayEnv = ControlPath (splitNamespace ExtraTopLevelOperatorsName) ] -let (+.+) s1 s2 = if s1 = "" then s2 else s1+"."+s2 +let (+.+) s1 s2 = if String.IsNullOrEmpty(s1) then s2 else s1+"."+s2 let layoutOfPath p = sepListL SepL.dot (List.map (tagNamespace >> wordL) p) @@ -8783,7 +8784,7 @@ let buildAccessPath (cp: CompilationPath option) = System.String.Join(".", ap) | None -> "Extension Type" -let prependPath path name = if path = "" then name else path + "." + name +let prependPath path name = if String.IsNullOrEmpty(path) then name else path + "." + name let XmlDocSigOfVal g full path (v: Val) = let parentTypars, methTypars, cxs, argInfos, retTy, prefix, path, name = diff --git a/src/Compiler/Utilities/FileSystem.fs b/src/Compiler/Utilities/FileSystem.fs index 5b555915e6c..8023eacb942 100644 --- a/src/Compiler/Utilities/FileSystem.fs +++ b/src/Compiler/Utilities/FileSystem.fs @@ -616,16 +616,16 @@ type DefaultFileSystem() as this = default _.IsInvalidPathShim(path: string) = let isInvalidPath (p: string MaybeNull) = - match p with - | Null - | "" -> true - | NonNull p -> p.IndexOfAny(Path.GetInvalidPathChars()) <> -1 + if String.IsNullOrEmpty(p) then + true + else + p.IndexOfAny(Path.GetInvalidPathChars()) <> -1 let isInvalidFilename (p: string MaybeNull) = - match p with - | Null - | "" -> true - | NonNull p -> p.IndexOfAny(Path.GetInvalidFileNameChars()) <> -1 + if String.IsNullOrEmpty(p) then + true + else + p.IndexOfAny(Path.GetInvalidFileNameChars()) <> -1 let isInvalidDirectory (d: string MaybeNull) = match d with @@ -645,7 +645,7 @@ type DefaultFileSystem() as this = default _.GetDirectoryNameShim(path: string) = FileSystemUtils.checkPathForIllegalChars path - if path = "" then + if String.IsNullOrEmpty(path) then "." else match Path.GetDirectoryName(path) with @@ -654,7 +654,7 @@ type DefaultFileSystem() as this = path else "." - | res -> if res = "" then "." else res + | res -> if String.IsNullOrEmpty(res) then "." else res abstract GetLastWriteTimeShim: fileName: string -> DateTime default _.GetLastWriteTimeShim(fileName: string) = File.GetLastWriteTimeUtc fileName diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index f6deb3951ef..1206b390443 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -787,7 +787,7 @@ module String = String digits |> function - | "" -> str, None + | x when String.IsNullOrEmpty(x) -> str, None | index -> str.Substring(0, str.Length - index.Length), Some(int index) /// Splits a string into substrings based on the strings in the array separators diff --git a/src/Compiler/Utilities/sformat.fs b/src/Compiler/Utilities/sformat.fs index b4f638e819f..c9158fc8a36 100644 --- a/src/Compiler/Utilities/sformat.fs +++ b/src/Compiler/Utilities/sformat.fs @@ -279,7 +279,7 @@ module Layout = let isEmptyL layout = match layout with - | Leaf(true, s, true) -> s.Text = "" + | Leaf(true, s, true) -> String.IsNullOrEmpty(s.Text) | _ -> false #if COMPILER @@ -1125,7 +1125,7 @@ module Display = :: layouts match postText with - | "" -> + | _ when String.IsNullOrEmpty(postText) -> //We are done, build a space-delimited layout from the collection of layouts we've accumulated Some(spaceListL (List.rev newLayouts)) diff --git a/src/Compiler/Utilities/sr.fs b/src/Compiler/Utilities/sr.fs index b081dfb6083..840a9f4197c 100644 --- a/src/Compiler/Utilities/sr.fs +++ b/src/Compiler/Utilities/sr.fs @@ -2,6 +2,7 @@ namespace FSharp.Compiler +open System open Microsoft.FSharp.Core open Microsoft.FSharp.Collections open Microsoft.FSharp.Reflection @@ -132,7 +133,7 @@ module internal DiagnosticMessage = // strip any escaped % characters - yes, this will fail if given %%%... let s = s.Replace("%%", "") - if s = "" then + if String.IsNullOrEmpty(s) then 0 else let len = s.Length - 1