Nullable: System.Resources (#23830)
authorKrzysztof Wicher <mordotymoja@gmail.com>
Wed, 10 Apr 2019 04:53:50 +0000 (21:53 -0700)
committerGitHub <noreply@github.com>
Wed, 10 Apr 2019 04:53:50 +0000 (21:53 -0700)
* nullable: system.resources

* apply feedback

* apply another feedback

* fix SR.cs after rebase

15 files changed:
src/System.Private.CoreLib/Common/System/SR.cs
src/System.Private.CoreLib/shared/System/Resources/FastResourceComparer.cs
src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs
src/System.Private.CoreLib/shared/System/Resources/IResourceGroveler.cs
src/System.Private.CoreLib/shared/System/Resources/IResourceReader.cs
src/System.Private.CoreLib/shared/System/Resources/ManifestBasedResourceGroveler.cs
src/System.Private.CoreLib/shared/System/Resources/ResourceFallbackManager.cs
src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs
src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs
src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs
src/System.Private.CoreLib/shared/System/Resources/ResourceSet.cs
src/System.Private.CoreLib/shared/System/Resources/RuntimeResourceSet.cs
src/System.Private.CoreLib/shared/System/Resources/SatelliteContractVersionAttribute.cs
src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs
src/System.Private.CoreLib/src/System/Text/StringBuilder.CoreCLR.cs

index 40c6a5a..f8657db 100644 (file)
@@ -125,7 +125,7 @@ namespace System
                 {
                     ResourceManager = new ResourceManager(SR.ResourceType);
                 }
-                string s = ResourceManager.GetString(key, null);
+                string? s = ResourceManager.GetString(key, null);
                 _currentlyLoading.RemoveAt(_currentlyLoading.Count - 1); // Pop
 
                 Debug.Assert(s != null, "Managed resource string lookup failed.  Was your resource name misspelled?  Did you rebuild mscorlib after adding a resource to resources.txt?  Debug this w/ cordbg and bug whoever owns the code that called SR.GetResourceString.  Resource name was: \"" + key + "\"");
index 6b813a0..51058c5 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
@@ -21,7 +22,7 @@ using System.Diagnostics;
 
 namespace System.Resources
 {
-    internal sealed class FastResourceComparer : IComparer, IEqualityComparer, IComparer<string>, IEqualityComparer<string>
+    internal sealed class FastResourceComparer : IComparer, IEqualityComparer, IComparer<string?>, IEqualityComparer<string?> // TODO-NULLABLE: IEqualityComparer.GetHashCode does not accept nulls but Equals does
     {
         internal static readonly FastResourceComparer Default = new FastResourceComparer();
 
@@ -32,8 +33,9 @@ namespace System.Resources
             return FastResourceComparer.HashFunction(s);
         }
 
-        public int GetHashCode(string key)
+        public int GetHashCode(string? key) // TODO-NULLABLE: argument should be non-nullable but IEqualityComparer.Equals accepts null
         {
+            Debug.Assert(key != null, "TODO-NULLABLE");
             return FastResourceComparer.HashFunction(key);
         }
 
@@ -52,29 +54,29 @@ namespace System.Resources
         }
 
         // Compares Strings quickly in a case-sensitive way
-        public int Compare(object a, object b)
+        public int Compare(object? a, object? b)
         {
             if (a == b) return 0;
-            string sa = (string)a;
-            string sb = (string)b;
+            string? sa = (string?)a;
+            string? sb = (string?)b;
             return string.CompareOrdinal(sa, sb);
         }
 
-        public int Compare(string a, string b)
+        public int Compare(string? a, string? b)
         {
             return string.CompareOrdinal(a, b);
         }
 
-        public bool Equals(string a, string b)
+        public bool Equals(string? a, string? b)
         {
             return string.Equals(a, b);
         }
 
-        public new bool Equals(object a, object b)
+        public new bool Equals(object? a, object? b)
         {
             if (a == b) return true;
-            string sa = (string)a;
-            string sb = (string)b;
+            string? sa = (string?)a;
+            string? sb = (string?)b;
             return string.Equals(sa, sb);
         }
 
index 216ebb1..8021494 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 **
@@ -34,12 +35,12 @@ namespace System.Resources
         // Consider modifying IResourceGroveler interface (hence this method signature) when we figure out 
         // serialization compat story for moving ResourceManager members to either file-based or 
         // manifest-based classes. Want to continue tightening the design to get rid of unused params.
-        public ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary<string, ResourceSet> localResourceSets, bool tryParents, bool createIfNotExists)
+        public ResourceSet? GrovelForResourceSet(CultureInfo culture, Dictionary<string, ResourceSet> localResourceSets, bool tryParents, bool createIfNotExists)
         {
             Debug.Assert(culture != null, "culture shouldn't be null; check caller");
 
-            string fileName = null;
-            ResourceSet rs = null;
+            string? fileName = null;
+            ResourceSet? rs = null;
 
             // Don't use Assembly manifest, but grovel on disk for a file.
             // Create new ResourceSet, if a file exists on disk for it.
@@ -72,8 +73,7 @@ namespace System.Resources
         // constructor, we'll look there first.  If it couldn't be found in the module
         // diretory or the module dir wasn't provided, look in the current
         // directory.
-
-        private string FindResourceFile(CultureInfo culture, string fileName)
+        private string? FindResourceFile(CultureInfo culture, string fileName)
         {
             Debug.Assert(culture != null, "culture shouldn't be null; check caller");
             Debug.Assert(fileName != null, "fileName shouldn't be null; check caller");
index b954db9..8029e8e 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
@@ -23,7 +24,7 @@ namespace System.Resources
 {
     internal interface IResourceGroveler
     {
-        ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary<string, ResourceSet> localResourceSets, bool tryParents,
+        ResourceSet? GrovelForResourceSet(CultureInfo culture, Dictionary<string, ResourceSet> localResourceSets, bool tryParents,
             bool createIfNotExists);
     }
 }
index 543a5a6..56b691f 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
index 485417d..bea782a 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
@@ -51,14 +52,14 @@ namespace System.Resources
             _mediator = mediator;
         }
 
-        public ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary<string, ResourceSet> localResourceSets, bool tryParents, bool createIfNotExists)
+        public ResourceSet? GrovelForResourceSet(CultureInfo culture, Dictionary<string, ResourceSet> localResourceSets, bool tryParents, bool createIfNotExists)
         {
             Debug.Assert(culture != null, "culture shouldn't be null; check caller");
             Debug.Assert(localResourceSets != null, "localResourceSets shouldn't be null; check caller");
 
-            ResourceSet rs = null;
-            Stream stream = null;
-            Assembly satellite = null;
+            ResourceSet? rs = null;
+            Stream? stream = null;
+            Assembly? satellite = null;
 
             // 1. Fixups for ultimate fallbacks
             CultureInfo lookForCulture = UltimateFallbackFixup(culture);
@@ -106,6 +107,7 @@ namespace System.Resources
             // 4a. Found a stream; create a ResourceSet if possible
             if (createIfNotExists && stream != null && rs == null)
             {
+                Debug.Assert(satellite != null, "satellite should not be null when stream is set");
                 rs = CreateResourceSet(stream, satellite);
             }
             else if (stream == null && tryParents)
@@ -127,6 +129,7 @@ namespace System.Resources
 
             // If our neutral resources were written in this culture AND we know the main assembly
             // does NOT contain neutral resources, don't probe for this satellite.
+            Debug.Assert(_mediator.NeutralResourcesCulture != null);
             if (lookForCulture.Name == _mediator.NeutralResourcesCulture.Name &&
                 _mediator.FallbackLoc == UltimateResourceFallbackLocation.MainAssembly)
             {
@@ -197,7 +200,7 @@ namespace System.Resources
                 if (bytes == ResourceManager.MagicNumber)
                 {
                     int resMgrHeaderVersion = br.ReadInt32();
-                    string readerTypeName = null, resSetTypeName = null;
+                    string? readerTypeName = null, resSetTypeName = null;
                     if (resMgrHeaderVersion == ResourceManager.HeaderVersionNumber)
                     {
                         br.ReadInt32();  // We don't want the number of bytes to skip.
@@ -222,7 +225,7 @@ namespace System.Resources
                     {
                         // resMgrHeaderVersion is older than this ResMgr version.
                         // We should add in backwards compatibility support here.
-
+                        Debug.Assert(_mediator.MainAssembly != null);
                         throw new NotSupportedException(SR.Format(SR.NotSupported_ObsoleteResourcesFile, _mediator.MainAssembly.GetName().Name));
                     }
 
@@ -292,7 +295,7 @@ namespace System.Resources
                 args[1] = assembly;
                 try
                 {
-                    ResourceSet rs = null;
+                    ResourceSet? rs = null;
                     // Add in a check for a constructor taking in an assembly first.
                     try
                     {
@@ -314,12 +317,12 @@ namespace System.Resources
             }
         }
 
-        private Stream GetManifestResourceStream(Assembly satellite, string fileName)
+        private Stream? GetManifestResourceStream(Assembly satellite, string fileName)
         {
             Debug.Assert(satellite != null, "satellite shouldn't be null; check caller");
             Debug.Assert(fileName != null, "fileName shouldn't be null; check caller");
 
-            Stream stream = satellite.GetManifestResourceStream(_mediator.LocationInfo, fileName);
+            Stream? stream = satellite.GetManifestResourceStream(_mediator.LocationInfo, fileName);
             if (stream == null)
             {
                 stream = CaseInsensitiveManifestResourceStreamLookup(satellite, fileName);
@@ -332,19 +335,19 @@ namespace System.Resources
         // case-insensitive lookup rules.  Yes, this is slow.  The metadata
         // dev lead refuses to make all assembly manifest resource lookups case-insensitive,
         // even optionally case-insensitive.
-        private Stream CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, string name)
+        private Stream? CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, string name)
         {
             Debug.Assert(satellite != null, "satellite shouldn't be null; check caller");
             Debug.Assert(name != null, "name shouldn't be null; check caller");
 
-            string nameSpace = _mediator.LocationInfo?.Namespace;
+            string? nameSpace = _mediator.LocationInfo?.Namespace;
 
             char c = Type.Delimiter;
             string resourceName = nameSpace != null && name != null ?
                 string.Concat(nameSpace, new ReadOnlySpan<char>(ref c, 1), name) :
                 string.Concat(nameSpace, name);
 
-            string canonicalName = null;
+            string? canonicalName = null;
             foreach (string existingName in satellite.GetManifestResourceNames())
             {
                 if (string.Equals(existingName, resourceName, StringComparison.InvariantCultureIgnoreCase))
@@ -368,15 +371,16 @@ namespace System.Resources
             return satellite.GetManifestResourceStream(canonicalName);
         }
 
-        private Assembly GetSatelliteAssembly(CultureInfo lookForCulture)
+        private Assembly? GetSatelliteAssembly(CultureInfo lookForCulture)
         {
+            Debug.Assert(_mediator.MainAssembly != null);
             if (!_mediator.LookedForSatelliteContractVersion)
             {
                 _mediator.SatelliteContractVersion = _mediator.ObtainSatelliteContractVersion(_mediator.MainAssembly);
                 _mediator.LookedForSatelliteContractVersion = true;
             }
 
-            Assembly satellite = null;
+            Assembly? satellite = null;
 
             // Look up the satellite assembly, but don't let problems
             // like a partially signed satellite assembly stop us from
@@ -431,6 +435,7 @@ namespace System.Resources
 
         private void HandleSatelliteMissing()
         {
+            Debug.Assert(_mediator.MainAssembly != null);
             string satAssemName = _mediator.MainAssembly.GetName().Name + ".resources.dll";
             if (_mediator.SatelliteContractVersion != null)
             {
@@ -447,6 +452,7 @@ namespace System.Resources
             }
             satAssemName += ", PublicKeyToken=" + publicKeyTok;
 
+            Debug.Assert(_mediator.NeutralResourcesCulture != null);
             string missingCultureName = _mediator.NeutralResourcesCulture.Name;
             if (missingCultureName.Length == 0)
             {
@@ -457,6 +463,7 @@ namespace System.Resources
 
         private void HandleResourceStreamMissing(string fileName)
         {
+            Debug.Assert(_mediator.BaseName != null);
             // Keep people from bothering me about resources problems
             if (_mediator.MainAssembly == typeof(object).Assembly && _mediator.BaseName.Equals(System.CoreLib.Name))
             {
@@ -473,6 +480,7 @@ namespace System.Resources
             if (_mediator.LocationInfo != null && _mediator.LocationInfo.Namespace != null)
                 resName = _mediator.LocationInfo.Namespace + Type.Delimiter;
             resName += fileName;
+            Debug.Assert(_mediator.MainAssembly != null);
             throw new MissingManifestResourceException(SR.Format(SR.MissingManifestResource_NoNeutralAsm, resName, _mediator.MainAssembly.GetName().Name));
         }
     }
index 8268f32..7319793 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
@@ -27,10 +28,10 @@ namespace System.Resources
     internal class ResourceFallbackManager : IEnumerable<CultureInfo>
     {
         private CultureInfo m_startingCulture;
-        private CultureInfo m_neutralResourcesCulture;
+        private CultureInfo? m_neutralResourcesCulture;
         private bool m_useParents;
 
-        internal ResourceFallbackManager(CultureInfo startingCulture, CultureInfo neutralResourcesCulture, bool useParents)
+        internal ResourceFallbackManager(CultureInfo? startingCulture, CultureInfo? neutralResourcesCulture, bool useParents)
         {
             if (startingCulture != null)
             {
index 1a89d56..a389dc8 100644 (file)
@@ -2,7 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-
+#nullable enable
 using System;
 using System.IO;
 using System.Globalization;
@@ -23,12 +23,12 @@ namespace System.Resources
 {
     public partial class ResourceManager
     {
-        private WindowsRuntimeResourceManagerBase _WinRTResourceManager;
-        private PRIExceptionInfo _PRIExceptionInfo;
+        private WindowsRuntimeResourceManagerBase? _WinRTResourceManager;
+        private PRIExceptionInfo? _PRIExceptionInfo;
         private bool _PRIInitialized;
         private bool _useUapResourceManagement;
 
-        private string GetStringFromPRI(string stringName, CultureInfo culture, string neutralResourcesCulture)
+        private string? GetStringFromPRI(string stringName, CultureInfo? culture, string? neutralResourcesCulture)
         {
             Debug.Assert(_useUapResourceManagement);
             Debug.Assert(_WinRTResourceManager != null);
@@ -42,7 +42,7 @@ namespace System.Resources
                 culture = null;
             }
 
-            string startingCulture = culture?.Name;
+            string? startingCulture = culture?.Name;
 
             if (_PRIInitialized == false)
             {
@@ -118,7 +118,7 @@ namespace System.Resources
 #else // ENABLE_WINRT
             foreach (var attrib in resourcesAssembly.GetCustomAttributes())
             {
-                AssemblyMetadataAttribute meta = attrib as AssemblyMetadataAttribute;
+                AssemblyMetadataAttribute? meta = attrib as AssemblyMetadataAttribute;
                 if (meta != null && meta.Key.Equals(".NETFrameworkAssembly"))
                 {
                     return false;
@@ -147,13 +147,14 @@ namespace System.Resources
                 return;
 #endif
 
+            Debug.Assert(MainAssembly != null);
             if (!ShouldUseUapResourceManagement(MainAssembly))
                 return;
 
             _useUapResourceManagement = true;
 
             // If we have the type information from the ResourceManager(Type) constructor, we use it. Otherwise, we use BaseNameField.
-            string reswFilename = _locationInfo == null ? BaseNameField : _locationInfo.FullName;
+            string? reswFilename = _locationInfo == null ? BaseNameField : _locationInfo.FullName;
 
             // The only way this can happen is if a class inherited from ResourceManager and
             // did not set the BaseNameField before calling the protected ResourceManager() constructor.
index b770bd7..09d4092 100644 (file)
@@ -2,7 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-
+#nullable enable
 using System.IO;
 using System.Globalization;
 using System.Reflection;
@@ -95,20 +95,20 @@ namespace System.Resources
     {
         internal class CultureNameResourceSetPair
         {
-            public string lastCultureName;
-            public ResourceSet lastResourceSet;
+            public string? lastCultureName;
+            public ResourceSet? lastResourceSet;
         }
 
-        protected string BaseNameField;
-        protected Assembly MainAssembly;    // Need the assembly manifest sometimes.
+        protected string? BaseNameField;
+        protected Assembly? MainAssembly;    // Need the assembly manifest sometimes.
 
-        private Dictionary<string, ResourceSet> _resourceSets;
-        private string _moduleDir;          // For assembly-ignorant directory location
-        private Type _locationInfo;         // For Assembly or type-based directory layout
-        private Type _userResourceSet;      // Which ResourceSet instance to create
-        private CultureInfo _neutralResourcesCulture;  // For perf optimizations.
+        private Dictionary<string, ResourceSet>? _resourceSets;
+        private string? _moduleDir;          // For assembly-ignorant directory location
+        private Type? _locationInfo;         // For Assembly or type-based directory layout
+        private Type? _userResourceSet;      // Which ResourceSet instance to create
+        private CultureInfo? _neutralResourcesCulture;  // For perf optimizations.
 
-        private CultureNameResourceSetPair _lastUsedResourceCache;
+        private CultureNameResourceSetPair? _lastUsedResourceCache;
 
         private bool _ignoreCase;   // Whether case matters in GetString & GetObject
 
@@ -118,10 +118,10 @@ namespace System.Resources
         // satellite for the neutral resources.
         private UltimateResourceFallbackLocation _fallbackLoc;
         // Version number of satellite assemblies to look for.  May be null.
-        private Version _satelliteContractVersion;
+        private Version? _satelliteContractVersion;
         private bool _lookedForSatelliteContractVersion;
 
-        private IResourceGroveler _resourceGroveler;
+        private IResourceGroveler _resourceGroveler = null!;
 
         public static readonly int MagicNumber = unchecked((int)0xBEEFCACE);  // If only hex had a K...
 
@@ -168,7 +168,7 @@ namespace System.Resources
         //
         // Note: System.Windows.Forms uses this method at design time.
         // 
-        private ResourceManager(string baseName, string resourceDir, Type usingResourceSet)
+        private ResourceManager(string baseName, string resourceDir, Type? userResourceSet)
         {
             if (null == baseName)
                 throw new ArgumentNullException(nameof(baseName));
@@ -178,7 +178,7 @@ namespace System.Resources
             BaseNameField = baseName;
 
             _moduleDir = resourceDir;
-            _userResourceSet = usingResourceSet;
+            _userResourceSet = userResourceSet;
             _resourceSets = new Dictionary<string, ResourceSet>();
             _lastUsedResourceCache = new CultureNameResourceSetPair();
             _useManifest = false;
@@ -202,7 +202,7 @@ namespace System.Resources
             CommonAssemblyInit();
         }
 
-        public ResourceManager(string baseName, Assembly assembly, Type usingResourceSet)
+        public ResourceManager(string baseName, Assembly assembly, Type? usingResourceSet)
         {
             if (null == baseName)
                 throw new ArgumentNullException(nameof(baseName));
@@ -252,11 +252,12 @@ namespace System.Resources
             ResourceManagerMediator mediator = new ResourceManagerMediator(this);
             _resourceGroveler = new ManifestBasedResourceGroveler(mediator);
 
+            Debug.Assert(MainAssembly != null);
             _neutralResourcesCulture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(MainAssembly, out _fallbackLoc);
         }
 
         // Gets the base name for the ResourceManager.
-        public virtual string BaseName
+        public virtual string? BaseName
         {
             get { return BaseNameField; }
         }
@@ -293,6 +294,7 @@ namespace System.Resources
         // creating a new ResourceManager isn't quite the correct behavior.
         public virtual void ReleaseAllResources()
         {
+            Debug.Assert(_resourceSets != null);
             Dictionary<string, ResourceSet> localResourceSets = _resourceSets;
 
             // If any calls to Close throw, at least leave ourselves in a
@@ -340,7 +342,7 @@ namespace System.Resources
 
         // WARNING: This function must be kept in sync with ResourceFallbackManager.GetEnumerator()
         // Return the first ResourceSet, based on the first culture ResourceFallbackManager would return
-        internal ResourceSet GetFirstResourceSet(CultureInfo culture)
+        internal ResourceSet? GetFirstResourceSet(CultureInfo culture)
         {
             // Logic from ResourceFallbackManager.GetEnumerator()
             if (_neutralResourcesCulture != null && culture.Name == _neutralResourcesCulture.Name)
@@ -358,8 +360,8 @@ namespace System.Resources
             }
 
             // Look in the ResourceSet table
-            Dictionary<string, ResourceSet> localResourceSets = _resourceSets;
-            ResourceSet rs = null;
+            Dictionary<string, ResourceSet>? localResourceSets = _resourceSets;
+            ResourceSet? rs = null;
             if (localResourceSets != null)
             {
                 lock (localResourceSets)
@@ -393,12 +395,12 @@ namespace System.Resources
         // if it hasn't yet been loaded and if parent CultureInfos should be 
         // loaded as well for resource inheritance.
         //         
-        public virtual ResourceSet GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
+        public virtual ResourceSet? GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
         {
             if (null == culture)
                 throw new ArgumentNullException(nameof(culture));
 
-            Dictionary<string, ResourceSet> localResourceSets = _resourceSets;
+            Dictionary<string, ResourceSet>? localResourceSets = _resourceSets;
             ResourceSet rs;
             if (localResourceSets != null)
             {
@@ -412,10 +414,12 @@ namespace System.Resources
             if (_useManifest && culture.HasInvariantCultureName)
             {
                 string fileName = GetResourceFileName(culture);
+                Debug.Assert(MainAssembly != null);
                 Stream stream = MainAssembly.GetManifestResourceStream(_locationInfo, fileName);
                 if (createIfNotExists && stream != null)
                 {
                     rs = ((ManifestBasedResourceGroveler)_resourceGroveler).CreateResourceSet(stream, MainAssembly);
+                    Debug.Assert(localResourceSets != null);
                     AddResourceSet(localResourceSets, culture.Name, ref rs);
                     return rs;
                 }
@@ -428,13 +432,14 @@ namespace System.Resources
         // for getting a resource set lives.  Access to it is controlled by
         // threadsafe methods such as GetResourceSet, GetString, & GetObject.  
         // This will take a minimal number of locks.
-        protected virtual ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
+        protected virtual ResourceSet? InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
         {
             Debug.Assert(culture != null, "culture != null");
+            Debug.Assert(_resourceSets != null);
 
             Dictionary<string, ResourceSet> localResourceSets = _resourceSets;
-            ResourceSet rs = null;
-            CultureInfo foundCulture = null;
+            ResourceSet? rs = null;
+            CultureInfo? foundCulture = null;
             lock (localResourceSets)
             {
                 if (localResourceSets.TryGetValue(culture.Name, out rs))
@@ -483,7 +488,7 @@ namespace System.Resources
                 // that had resources.
                 foreach (CultureInfo updateCultureInfo in mgr)
                 {
-                    AddResourceSet(localResourceSets, updateCultureInfo.Name, ref rs);
+                    AddResourceSet(localResourceSets, updateCultureInfo.Name, ref rs!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34874
 
                     // stop when we've added current or reached invariant (top of chain)
                     if (updateCultureInfo == foundCulture)
@@ -526,7 +531,7 @@ namespace System.Resources
             }
         }
 
-        protected static Version GetSatelliteContractVersion(Assembly a)
+        protected static Version? GetSatelliteContractVersion(Assembly a)
         {
             // Ensure that the assembly reference is not null
             if (a == null)
@@ -534,7 +539,7 @@ namespace System.Resources
                 throw new ArgumentNullException(nameof(a), SR.ArgumentNull_Assembly);
             }
 
-            string v = a.GetCustomAttribute<SatelliteContractVersionAttribute>()?.Version;
+            string? v = a.GetCustomAttribute<SatelliteContractVersionAttribute>()?.Version;
             if (v == null)
             {
                 // Return null. The calling code will use the assembly version instead to avoid potential type
@@ -589,16 +594,16 @@ namespace System.Resources
         // current thread's CultureInfo, and if not found, all parent CultureInfos.
         // Returns null if the resource wasn't found.
         // 
-        public virtual string GetString(string name)
+        public virtual string? GetString(string name)
         {
-            return GetString(name, (CultureInfo)null);
+            return GetString(name, (CultureInfo?)null);
         }
 
         // Looks up a resource value for a particular name.  Looks in the 
         // specified CultureInfo, and if not found, all parent CultureInfos.
         // Returns null if the resource wasn't found.
         // 
-        public virtual string GetString(string name, CultureInfo culture)
+        public virtual string? GetString(string name, CultureInfo? culture)
         {
             if (null == name)
                 throw new ArgumentNullException(nameof(name));
@@ -607,6 +612,7 @@ namespace System.Resources
             if (_useUapResourceManagement)
             {
                 // Throws WinRT hresults.
+                Debug.Assert(_neutralResourcesCulture != null);
                 return GetStringFromPRI(name, culture, _neutralResourcesCulture.Name);
             }
 #endif
@@ -616,11 +622,11 @@ namespace System.Resources
                 culture = CultureInfo.CurrentUICulture;
             }
 
-            ResourceSet last = GetFirstResourceSet(culture);
+            ResourceSet? last = GetFirstResourceSet(culture);
 
             if (last != null)
             {
-                string value = last.GetString(name, _ignoreCase);
+                string? value = last.GetString(name, _ignoreCase);
                 if (value != null)
                     return value;
             }
@@ -631,13 +637,13 @@ namespace System.Resources
             ResourceFallbackManager mgr = new ResourceFallbackManager(culture, _neutralResourcesCulture, true);
             foreach (CultureInfo currentCultureInfo in mgr)
             {
-                ResourceSet rs = InternalGetResourceSet(currentCultureInfo, true, true);
+                ResourceSet? rs = InternalGetResourceSet(currentCultureInfo, true, true);
                 if (rs == null)
                     break;
 
                 if (rs != last)
                 {
-                    string value = rs.GetString(name, _ignoreCase);
+                    string? value = rs.GetString(name, _ignoreCase);
                     if (value != null)
                     {
                         // update last used ResourceSet
@@ -663,20 +669,20 @@ namespace System.Resources
         // current thread's CultureInfo, and if not found, all parent CultureInfos.
         // Returns null if the resource wasn't found.
         // 
-        public virtual object GetObject(string name)
+        public virtual object? GetObject(string name)
         {
-            return GetObject(name, (CultureInfo)null, true);
+            return GetObject(name, (CultureInfo?)null, true);
         }
 
         // Looks up a resource value for a particular name.  Looks in the 
         // specified CultureInfo, and if not found, all parent CultureInfos.
         // Returns null if the resource wasn't found.
-        public virtual object GetObject(string name, CultureInfo culture)
+        public virtual object? GetObject(string name, CultureInfo culture)
         {
             return GetObject(name, culture, true);
         }
 
-        private object GetObject(string name, CultureInfo culture, bool wrapUnmanagedMemStream)
+        private object? GetObject(string name, CultureInfo? culture, bool wrapUnmanagedMemStream)
         {
             if (null == name)
                 throw new ArgumentNullException(nameof(name));
@@ -686,10 +692,10 @@ namespace System.Resources
                 culture = CultureInfo.CurrentUICulture;
             }
 
-            ResourceSet last = GetFirstResourceSet(culture);
+            ResourceSet? last = GetFirstResourceSet(culture);
             if (last != null)
             {
-                object value = last.GetObject(name, _ignoreCase);
+                object? value = last.GetObject(name, _ignoreCase);
 
                 if (value != null)
                 {
@@ -707,13 +713,13 @@ namespace System.Resources
 
             foreach (CultureInfo currentCultureInfo in mgr)
             {
-                ResourceSet rs = InternalGetResourceSet(currentCultureInfo, true, true);
+                ResourceSet? rs = InternalGetResourceSet(currentCultureInfo, true, true);
                 if (rs == null)
                     break;
 
                 if (rs != last)
                 {
-                    object value = rs.GetObject(name, _ignoreCase);
+                    object? value = rs.GetObject(name, _ignoreCase);
                     if (value != null)
                     {
                         // update the last used ResourceSet
@@ -739,15 +745,15 @@ namespace System.Resources
             return null;
         }
 
-        public UnmanagedMemoryStream GetStream(string name)
+        public UnmanagedMemoryStream? GetStream(string name)
         {
-            return GetStream(name, (CultureInfo)null);
+            return GetStream(name, (CultureInfo?)null);
         }
 
-        public UnmanagedMemoryStream GetStream(string name, CultureInfo culture)
+        public UnmanagedMemoryStream? GetStream(string name, CultureInfo? culture)
         {
-            object obj = GetObject(name, culture, false);
-            UnmanagedMemoryStream ums = obj as UnmanagedMemoryStream;
+            object? obj = GetObject(name, culture, false);
+            UnmanagedMemoryStream? ums = obj as UnmanagedMemoryStream;
             if (ums == null && obj != null)
                 throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotStream_Name, name));
             return ums;
@@ -767,28 +773,28 @@ namespace System.Resources
             }
 
             // NEEDED ONLY BY FILE-BASED
-            internal string ModuleDir
+            internal string? ModuleDir
             {
                 get { return _rm._moduleDir; }
             }
 
             // NEEDED BOTH BY FILE-BASED  AND ASSEMBLY-BASED
-            internal Type LocationInfo
+            internal Type? LocationInfo
             {
                 get { return _rm._locationInfo; }
             }
 
-            internal Type UserResourceSet
+            internal Type? UserResourceSet
             {
                 get { return _rm._userResourceSet; }
             }
 
-            internal string BaseNameField
+            internal string? BaseNameField
             {
                 get { return _rm.BaseNameField; }
             }
 
-            internal CultureInfo NeutralResourcesCulture
+            internal CultureInfo? NeutralResourcesCulture
             {
                 get { return _rm._neutralResourcesCulture; }
                 set { _rm._neutralResourcesCulture = value; }
@@ -806,13 +812,13 @@ namespace System.Resources
                 set { _rm._lookedForSatelliteContractVersion = value; }
             }
 
-            internal Version SatelliteContractVersion
+            internal Version? SatelliteContractVersion
             {
                 get { return _rm._satelliteContractVersion; }
                 set { _rm._satelliteContractVersion = value; }
             }
 
-            internal Version ObtainSatelliteContractVersion(Assembly a)
+            internal Version? ObtainSatelliteContractVersion(Assembly a)
             {
                 return ResourceManager.GetSatelliteContractVersion(a);
             }
@@ -823,14 +829,14 @@ namespace System.Resources
                 set { _rm._fallbackLoc = value; }
             }
 
-            internal Assembly MainAssembly
+            internal Assembly? MainAssembly
             {
                 get { return _rm.MainAssembly; }
             }
 
             // this is weird because we have BaseNameField accessor above, but we're sticking
             // with it for compat.
-            internal string BaseName
+            internal string? BaseName
             {
                 get { return _rm.BaseName; }
             }
index 7170a98..c8b34f8 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
@@ -41,10 +42,10 @@ namespace System.Resources
 
     internal struct ResourceLocator
     {
-        internal object _value;  // Can be null.  Consider WeakReference instead?
+        internal object? _value;  // Can be null.  Consider WeakReference instead?
         internal int _dataPos;
 
-        internal ResourceLocator(int dataPos, object value)
+        internal ResourceLocator(int dataPos, object? value)
         {
             _dataPos = dataPos;
             _value = value;
@@ -58,7 +59,7 @@ namespace System.Resources
 
         // Allows adding in profiling data in a future version, or a special
         // resource profiling build.  We could also use WeakReference.
-        internal object Value
+        internal object? Value
         {
             get { return _value; }
             set { _value = value; }
@@ -82,7 +83,7 @@ namespace System.Resources
         // Used by RuntimeResourceSet and this class's enumerator.  Maps
         // resource name to a value, a ResourceLocator, or a 
         // LooselyLinkedManifestResource.
-        internal Dictionary<string, ResourceLocator> _resCache;
+        internal Dictionary<string, ResourceLocator>? _resCache;
         private long _nameSectionOffset;  // Offset to name section of file.
         private long _dataSectionOffset;  // Offset to Data section of file.
 
@@ -91,26 +92,26 @@ namespace System.Resources
         // we're given an UnmanagedMemoryStream referring to the mmap'ed portion
         // of the assembly.  The pointers here are pointers into that block of
         // memory controlled by the OS's loader.
-        private int[] _nameHashes;    // hash values for all names.
+        private int[]? _nameHashes;    // hash values for all names.
         private unsafe int* _nameHashesPtr;  // In case we're using UnmanagedMemoryStream
-        private int[] _namePositions; // relative locations of names
+        private int[]? _namePositions; // relative locations of names
         private unsafe int* _namePositionsPtr;  // If we're using UnmanagedMemoryStream
-        private Type[] _typeTable;    // Lazy array of Types for resource values.
-        private int[] _typeNamePositions;  // To delay initialize type table
+        private Type?[] _typeTable = null!;    // Lazy array of Types for resource values.
+        private int[] _typeNamePositions = null!;  // To delay initialize type table
         private int _numResources;    // Num of resources files, in case arrays aren't allocated.
 
         private readonly bool _permitDeserialization;  // can deserialize BinaryFormatted resources
-        private object _binaryFormatter; // binary formatter instance to use for deserializing
+        private object? _binaryFormatter; // binary formatter instance to use for deserializing
 
         // statics used to dynamically call into BinaryFormatter
         // When successfully located s_binaryFormatterType will point to the BinaryFormatter type
         // and s_deserializeMethod will point to an unbound delegate to the deserialize method.
         private static Type s_binaryFormatterType;
-        private static Func<object, Stream, object> s_deserializeMethod;
+        private static Func<object?, Stream, object> s_deserializeMethod;
 
         // We'll include a separate code path that uses UnmanagedMemoryStream to
         // avoid allocating String objects and the like.
-        private UnmanagedMemoryStream _ums;
+        private UnmanagedMemoryStream? _ums;
 
         // Version number of .resources file, for compatibility
         private int _version;
@@ -188,11 +189,11 @@ namespace System.Resources
                     // Close the stream in a thread-safe way.  This fix means 
                     // that we may call Close n times, but that's safe.
                     BinaryReader copyOfStore = _store;
-                    _store = null;
+                    _store = null!; // TODO-NULLABLE: dispose should not null this out
                     if (copyOfStore != null)
                         copyOfStore.Close();
                 }
-                _store = null;
+                _store = null!; // TODO-NULLABLE: dispose should not null this out
                 _namePositions = null;
                 _nameHashes = null;
                 _ums = null;
@@ -222,24 +223,34 @@ namespace System.Resources
         private unsafe int GetNameHash(int index)
         {
             Debug.Assert(index >= 0 && index < _numResources, "Bad index into hash array.  index: " + index);
-            Debug.Assert((_ums == null && _nameHashes != null && _nameHashesPtr == null) ||
-                            (_ums != null && _nameHashes == null && _nameHashesPtr != null), "Internal state mangled.");
+
             if (_ums == null)
+            {
+                Debug.Assert(_nameHashes != null && _nameHashesPtr == null, "Internal state mangled.");
                 return _nameHashes[index];
+            }
             else
+            {
+                Debug.Assert(_nameHashes == null && _nameHashesPtr != null, "Internal state mangled.");
                 return ReadUnalignedI4(&_nameHashesPtr[index]);
+            }
         }
 
         private unsafe int GetNamePosition(int index)
         {
             Debug.Assert(index >= 0 && index < _numResources, "Bad index into name position array.  index: " + index);
-            Debug.Assert((_ums == null && _namePositions != null && _namePositionsPtr == null) ||
-                            (_ums != null && _namePositions == null && _namePositionsPtr != null), "Internal state mangled.");
             int r;
             if (_ums == null)
+            {
+                Debug.Assert(_namePositions != null && _namePositionsPtr == null, "Internal state mangled.");
                 r = _namePositions[index];
+            }
             else
+            {
+                Debug.Assert(_namePositions == null && _namePositionsPtr != null, "Internal state mangled.");
                 r = ReadUnalignedI4(&_namePositionsPtr[index]);
+            }
+
             if (r < 0 || r > _dataSectionOffset - _nameSectionOffset)
             {
                 throw new FormatException(SR.Format(SR.BadImageFormat_ResourcesNameInvalidOffset, r));
@@ -412,7 +423,7 @@ namespace System.Resources
                     if (_ums.Position > _ums.Length - byteLen)
                         throw new BadImageFormatException(SR.Format(SR.BadImageFormat_ResourcesIndexTooLong, index));
 
-                    string s = null;
+                    string? s = null;
                     char* charPtr = (char*)_ums.PositionPointer;
 
                     s = new string(charPtr, 0, byteLen / 2);
@@ -450,7 +461,7 @@ namespace System.Resources
         // This is used in the enumerator.  The enumerator iterates from 0 to n
         // of our resources and this returns the resource value for a particular
         // index.  The parameter is NOT a virtual offset.
-        private object GetValueForNameIndex(int index)
+        private object? GetValueForNameIndex(int index)
         {
             Debug.Assert(_store != null, "ResourceReader is closed!");
             long nameVA = GetNamePosition(index);
@@ -476,11 +487,11 @@ namespace System.Resources
         // from that location.
         // Anyone who calls LoadObject should make sure they take a lock so 
         // no one can cause us to do a seek in here.
-        internal string LoadString(int pos)
+        internal string? LoadString(int pos)
         {
             Debug.Assert(_store != null, "ResourceReader is closed!");
             _store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
-            string s = null;
+            string? s = null;
             int typeIndex = _store.Read7BitEncodedInt();
             if (_version == 1)
             {
@@ -509,7 +520,7 @@ namespace System.Resources
         }
 
         // Called from RuntimeResourceSet
-        internal object LoadObject(int pos)
+        internal object? LoadObject(int pos)
         {
             if (_version == 1)
                 return LoadObjectV1(pos);
@@ -517,11 +528,11 @@ namespace System.Resources
             return LoadObjectV2(pos, out typeCode);
         }
 
-        internal object LoadObject(int pos, out ResourceTypeCode typeCode)
+        internal object? LoadObject(int pos, out ResourceTypeCode typeCode)
         {
             if (_version == 1)
             {
-                object o = LoadObjectV1(pos);
+                object? o = LoadObjectV1(pos);
                 typeCode = (o is string) ? ResourceTypeCode.String : ResourceTypeCode.StartOfUserTypes;
                 return o;
             }
@@ -532,7 +543,7 @@ namespace System.Resources
         // from that location.
         // Anyone who calls LoadObject should make sure they take a lock so 
         // no one can cause us to do a seek in here.
-        internal object LoadObjectV1(int pos)
+        internal object? LoadObjectV1(int pos)
         {
             Debug.Assert(_store != null, "ResourceReader is closed!");
             Debug.Assert(_version == 1, ".resources file was not a V1 .resources file!");
@@ -553,7 +564,7 @@ namespace System.Resources
             }
         }
 
-        private object _LoadObjectV1(int pos)
+        private object? _LoadObjectV1(int pos)
         {
             _store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
             int typeIndex = _store.Read7BitEncodedInt();
@@ -607,7 +618,7 @@ namespace System.Resources
             }
         }
 
-        internal object LoadObjectV2(int pos, out ResourceTypeCode typeCode)
+        internal object? LoadObjectV2(int pos, out ResourceTypeCode typeCode)
         {
             Debug.Assert(_store != null, "ResourceReader is closed!");
             Debug.Assert(_version >= 2, ".resources file was not a V2 (or higher) .resources file!");
@@ -628,7 +639,7 @@ namespace System.Resources
             }
         }
 
-        private object _LoadObjectV2(int pos, out ResourceTypeCode typeCode)
+        private object? _LoadObjectV2(int pos, out ResourceTypeCode typeCode)
         {
             _store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
             typeCode = (ResourceTypeCode)_store.Read7BitEncodedInt();
@@ -793,7 +804,7 @@ namespace System.Resources
                    MethodInfo binaryFormatterDeserialize = s_binaryFormatterType.GetMethod("Deserialize", new Type[] { typeof(Stream) });
 
                     // create an unbound delegate that can accept a BinaryFormatter instance as object
-                    return (Func<object, Stream, object>)typeof(ResourceReader)
+                    return (Func<object?, Stream, object>)typeof(ResourceReader)
                             .GetMethod(nameof(CreateUntypedDelegate), BindingFlags.NonPublic | BindingFlags.Static)
                             .MakeGenericMethod(s_binaryFormatterType)
                             .Invoke(null, new object[] { binaryFormatterDeserialize });
@@ -1030,7 +1041,7 @@ namespace System.Resources
                 }
             }
             Debug.Assert(_typeTable[typeIndex] != null, "Should have found a type!");
-            return _typeTable[typeIndex];
+            return _typeTable[typeIndex]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644
         }
 
         public void GetResourceData(string resourceName, out string resourceType, out byte[] resourceData)
@@ -1192,7 +1203,7 @@ namespace System.Resources
                     if (_reader._resCache == null) throw new InvalidOperationException(SR.ResourceReaderIsClosed);
 
                     string key;
-                    object value = null;
+                    object? value = null;
                     lock (_reader)
                     { // locks should be taken in the same order as in RuntimeResourceSet.GetObject to avoid deadlock
                         lock (_reader._resCache)
@@ -1221,7 +1232,7 @@ namespace System.Resources
                 }
             }
 
-            public object Value
+            public object? Value
             {
                 get
                 {
index 2d33f3a..7d993d8 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 **
@@ -14,6 +15,7 @@
 ===========================================================*/
 
 using System.Collections;
+using System.Diagnostics;
 using System.IO;
 using System.Reflection;
 
@@ -27,10 +29,10 @@ namespace System.Resources
     //
     public class ResourceSet : IDisposable, IEnumerable
     {
-        protected IResourceReader Reader;
-        internal Hashtable Table;
+        protected IResourceReader Reader = null!;
+        internal Hashtable? Table; // TODO-NULLABLE: should not be nulled out in Dispose
 
-        private Hashtable _caseInsensitiveTable;  // For case-insensitive lookups.
+        private Hashtable? _caseInsensitiveTable;  // For case-insensitive lookups.
 
         protected ResourceSet()
         {
@@ -95,12 +97,12 @@ namespace System.Resources
             if (disposing)
             {
                 // Close the Reader in a thread-safe way.
-                IResourceReader copyOfReader = Reader;
-                Reader = null;
+                IResourceReader? copyOfReader = Reader;
+                Reader = null!; // TODO-NULLABLE: should not be nulled out in the Dispose
                 if (copyOfReader != null)
                     copyOfReader.Close();
             }
-            Reader = null;
+            Reader = null!; // TODO-NULLABLE: should not be nulled out in the Dispose
             _caseInsensitiveTable = null;
             Table = null;
         }
@@ -139,7 +141,7 @@ namespace System.Resources
 
         private IDictionaryEnumerator GetEnumeratorHelper()
         {
-            Hashtable copyOfTable = Table;  // Avoid a race with Dispose
+            Hashtable? copyOfTable = Table;  // Avoid a race with Dispose
             if (copyOfTable == null)
                 throw new ObjectDisposedException(null, SR.ObjectDisposed_ResourceSet);
             return copyOfTable.GetEnumerator();
@@ -147,12 +149,12 @@ namespace System.Resources
 
         // Look up a string value for a resource given its name.
         // 
-        public virtual string GetString(string name)
+        public virtual string? GetString(string name)
         {
-            object obj = GetObjectInternal(name);
+            object? obj = GetObjectInternal(name);
             try
             {
-                return (string)obj;
+                return (string?)obj;
             }
             catch (InvalidCastException)
             {
@@ -160,16 +162,16 @@ namespace System.Resources
             }
         }
 
-        public virtual string GetString(string name, bool ignoreCase)
+        public virtual string? GetString(string name, bool ignoreCase)
         {
-            object obj;
-            string s;
+            object? obj;
+            string? s;
 
             // Case-sensitive lookup
             obj = GetObjectInternal(name);
             try
             {
-                s = (string)obj;
+                s = (string?)obj;
             }
             catch (InvalidCastException)
             {
@@ -186,7 +188,7 @@ namespace System.Resources
             obj = GetCaseInsensitiveObjectInternal(name);
             try
             {
-                return (string)obj;
+                return (string?)obj;
             }
             catch (InvalidCastException)
             {
@@ -196,14 +198,14 @@ namespace System.Resources
 
         // Look up an object value for a resource given its name.
         // 
-        public virtual object GetObject(string name)
+        public virtual object? GetObject(string name)
         {
             return GetObjectInternal(name);
         }
 
-        public virtual object GetObject(string name, bool ignoreCase)
+        public virtual object? GetObject(string name, bool ignoreCase)
         {
-            object obj = GetObjectInternal(name);
+            object? obj = GetObjectInternal(name);
 
             if (obj != null || !ignoreCase)
                 return obj;
@@ -213,22 +215,24 @@ namespace System.Resources
 
         protected virtual void ReadResources()
         {
+            Debug.Assert(Table != null);
+            Debug.Assert(Reader != null);
             IDictionaryEnumerator en = Reader.GetEnumerator();
             while (en.MoveNext())
             {
-                object value = en.Value;
+                object? value = en.Value;
                 Table.Add(en.Key, value);
             }
             // While technically possible to close the Reader here, don't close it
             // to help with some WinRes lifetime issues.
         }
 
-        private object GetObjectInternal(string name)
+        private object? GetObjectInternal(string name)
         {
             if (name == null)
                 throw new ArgumentNullException(nameof(name));
 
-            Hashtable copyOfTable = Table;  // Avoid a race with Dispose
+            Hashtable? copyOfTable = Table;  // Avoid a race with Dispose
 
             if (copyOfTable == null)
                 throw new ObjectDisposedException(null, SR.ObjectDisposed_ResourceSet);
@@ -236,14 +240,14 @@ namespace System.Resources
             return copyOfTable[name];
         }
 
-        private object GetCaseInsensitiveObjectInternal(string name)
+        private object? GetCaseInsensitiveObjectInternal(string name)
         {
-            Hashtable copyOfTable = Table;  // Avoid a race with Dispose
+            Hashtable? copyOfTable = Table;  // Avoid a race with Dispose
 
             if (copyOfTable == null)
                 throw new ObjectDisposedException(null, SR.ObjectDisposed_ResourceSet);
 
-            Hashtable caseTable = _caseInsensitiveTable;  // Avoid a race condition with Close
+            Hashtable? caseTable = _caseInsensitiveTable;  // Avoid a race condition with Close
             if (caseTable == null)
             {
                 caseTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
index 210fff7..c2d27d2 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
@@ -173,19 +174,19 @@ namespace System.Resources
         // for arbitrarily long times, since the object is usually a string
         // literal that will live for the lifetime of the appdomain.  The
         // value is a ResourceLocator instance, which might cache the object.
-        private Dictionary<string, ResourceLocator> _resCache;
+        private Dictionary<string, ResourceLocator>? _resCache; // TODO-NULLABLE: should not be nulled out in Dispose
 
 
         // For our special load-on-demand reader, cache the cast.  The 
         // RuntimeResourceSet's implementation knows how to treat this reader specially.
-        private ResourceReader _defaultReader;
+        private ResourceReader? _defaultReader; // TODO-NULLABLE: should not be nulled out in Dispose
 
         // This is a lookup table for case-insensitive lookups, and may be null.
         // Consider always using a case-insensitive resource cache, as we don't
         // want to fill this out if we can avoid it.  The problem is resource
         // fallback will somewhat regularly cause us to look up resources that 
         // don't exist.
-        private Dictionary<string, ResourceLocator> _caseInsensitiveTable;
+        private Dictionary<string, ResourceLocator>? _caseInsensitiveTable;
 
         // If we're not using our custom reader, then enumerate through all
         // the resources once, adding them into the table.
@@ -256,36 +257,36 @@ namespace System.Resources
         }
 
 
-        public override string GetString(string key)
+        public override string? GetString(string key)
         {
-            object o = GetObject(key, false, true);
-            return (string)o;
+            object? o = GetObject(key, false, true);
+            return (string?)o;
         }
 
-        public override string GetString(string key, bool ignoreCase)
+        public override string? GetString(string key, bool ignoreCase)
         {
-            object o = GetObject(key, ignoreCase, true);
-            return (string)o;
+            object? o = GetObject(key, ignoreCase, true);
+            return (string?)o;
         }
 
-        public override object GetObject(string key)
+        public override object? GetObject(string key)
         {
             return GetObject(key, false, false);
         }
 
-        public override object GetObject(string key, bool ignoreCase)
+        public override object? GetObject(string key, bool ignoreCase)
         {
             return GetObject(key, ignoreCase, false);
         }
 
-        private object GetObject(string key, bool ignoreCase, bool isString)
+        private object? GetObject(string key, bool ignoreCase, bool isString)
         {
             if (key == null)
                 throw new ArgumentNullException(nameof(key));
             if (Reader == null || _resCache == null)
                 throw new ObjectDisposedException(null, SR.ObjectDisposed_ResourceSet);
 
-            object value = null;
+            object? value = null;
             ResourceLocator resLocation;
 
             lock (Reader)
@@ -361,7 +362,10 @@ namespace System.Resources
                             ResourceLocator resLoc = new ResourceLocator(-1, entry.Value);
                             _resCache.Add(readKey, resLoc);
                             if (ignoreCase)
+                            {
+                                Debug.Assert(_caseInsensitiveTable != null);
                                 _caseInsensitiveTable.Add(readKey, resLoc);
+                            }
                         }
                         // Only close the reader if it is NOT our default one,
                         // since we need it around to resolve ResourceLocators.
@@ -371,6 +375,7 @@ namespace System.Resources
                     else
                     {
                         Debug.Assert(ignoreCase, "This should only happen for case-insensitive lookups");
+                        Debug.Assert(_caseInsensitiveTable != null);
                         ResourceReader.ResourceEnumerator en = _defaultReader.GetEnumeratorInternal();
                         while (en.MoveNext())
                         {
@@ -383,7 +388,7 @@ namespace System.Resources
                     }
                     _haveReadFromReader = true;
                 }
-                object obj = null;
+                object? obj = null;
                 bool found = false;
                 bool keyInWrongCase = false;
                 if (_defaultReader != null)
@@ -396,6 +401,7 @@ namespace System.Resources
                 }
                 if (!found && ignoreCase)
                 {
+                    Debug.Assert(_caseInsensitiveTable != null);
                     if (_caseInsensitiveTable.TryGetValue(key, out resLocation))
                     {
                         found = true;
@@ -410,16 +416,17 @@ namespace System.Resources
         // The last parameter indicates whether the lookup required a 
         // case-insensitive lookup to succeed, indicating we shouldn't add 
         // the ResourceLocation to our case-sensitive cache.
-        private object ResolveResourceLocator(ResourceLocator resLocation, string key, Dictionary<string, ResourceLocator> copyOfCache, bool keyInWrongCase)
+        private object? ResolveResourceLocator(ResourceLocator resLocation, string key, Dictionary<string, ResourceLocator> copyOfCache, bool keyInWrongCase)
         {
             // We need to explicitly resolve loosely linked manifest
             // resources, and we need to resolve ResourceLocators with null objects.
-            object value = resLocation.Value;
+            object? value = resLocation.Value;
             if (value == null)
             {
                 ResourceTypeCode typeCode;
                 lock (Reader)
                 {
+                    Debug.Assert(_defaultReader != null);
                     value = _defaultReader.LoadObject(resLocation.DataPosition, out typeCode);
                 }
                 if (!keyInWrongCase && ResourceLocator.CanCache(typeCode))
index 017cc17..c11ec0a 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 /*============================================================
 **
 ** 
index 8791865..9955336 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 using System.Globalization;
 using System.Reflection;
 
@@ -12,7 +13,7 @@ namespace System.Resources
         // Internal version of GetSatelliteAssembly that avoids throwing FileNotFoundException
         private static Assembly InternalGetSatelliteAssembly(Assembly mainAssembly,
                                                              CultureInfo culture,
-                                                             Version version)
+                                                             Version? version)
         {
             return ((RuntimeAssembly)mainAssembly).InternalGetSatelliteAssembly(culture, version, throwOnFileNotFound: false);
         }
index 63afe45..8434707 100644 (file)
@@ -2,6 +2,9 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
+using System.Diagnostics;
+
 namespace System.Text
 {
     public partial class StringBuilder
@@ -113,7 +116,7 @@ namespace System.Text
 
             bool isLastChunk = true;
             byte* dstPtr = (byte*)dest.ToPointer();
-            StringBuilder currentSrc = FindChunkForByte(len);
+            StringBuilder? currentSrc = FindChunkForByte(len);
 
             do
             {
@@ -132,6 +135,7 @@ namespace System.Text
                         Buffer.Memcpy(dstPtr + chunkOffsetInBytes, srcPtr, chunkLengthInBytes);
                     }
                 }
+
                 currentSrc = currentSrc.m_ChunkPrevious;
             }
             while (currentSrc != null);