From 9a715feffb9c4b39a3f98a03c925aba4e9eafd7d Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 10 Apr 2019 15:47:15 -0400 Subject: [PATCH] Nullable: System (most of it) (#23774) * Nullable: shared\System (most of it) And some other things it touches. * Nullable: src\System (most of it) * Address PR feedback --- src/System.Private.CoreLib/Common/System/SR.cs | 6 +- .../Windows/Advapi32/Interop.RegQueryValueEx.cs | 11 +- src/System.Private.CoreLib/shared/System/Action.cs | 1 + .../shared/System/Activator.RuntimeType.cs | 33 +- .../shared/System/Activator.cs | 17 +- .../shared/System/AppContext.cs | 21 +- .../shared/System/AppDomain.cs | 95 +- .../shared/System/AppDomainSetup.cs | 5 +- .../shared/System/Array.Enumerators.cs | 9 +- .../shared/System/ArraySegment.cs | 43 +- .../shared/System/AssemblyLoadEventArgs.cs | 1 + .../shared/System/AssemblyLoadEventHandler.cs | 3 +- .../shared/System/AsyncCallback.cs | 1 + .../shared/System/AttributeTargets.cs | 1 + .../shared/System/AttributeUsageAttribute.cs | 1 + .../shared/System/BitConverter.cs | 18 +- .../shared/System/Buffer.Unix.cs | 3 +- .../shared/System/Buffer.Windows.cs | 3 +- src/System.Private.CoreLib/shared/System/Buffer.cs | 1 + .../shared/System/CLSCompliantAttribute.cs | 1 + .../shared/System/CharEnumerator.cs | 9 +- .../Collections/Generic/IEqualityComparer.cs | 5 +- .../shared/System/Collections/IEnumerator.cs | 3 +- .../System/Collections/IStructuralEquatable.cs | 3 +- .../shared/System/Convert.Base64.cs | 1 + .../shared/System/Convert.cs | 177 +- .../shared/System/CoreLib.cs | 1 + .../shared/System/CurrentSystemTimeZone.cs | 3 +- src/System.Private.CoreLib/shared/System/DBNull.cs | 33 +- .../shared/System/DateTime.Unix.cs | 1 + .../shared/System/DateTime.cs | 77 +- .../shared/System/DateTimeKind.cs | 1 + .../shared/System/DateTimeOffset.cs | 47 +- .../shared/System/DayOfWeek.cs | 1 + .../shared/System/Decimal.DecCalc.cs | 1 + .../shared/System/Decimal.cs | 55 +- src/System.Private.CoreLib/shared/System/Empty.cs | 1 + src/System.Private.CoreLib/shared/System/Enum.cs | 2 +- .../shared/System/Environment.NoRegistry.cs | 5 +- .../shared/System/Environment.SpecialFolder.cs | 1 + .../System/Environment.SpecialFolderOption.cs | 1 + .../shared/System/Environment.Unix.cs | 31 +- .../shared/System/Environment.Variables.Windows.cs | 7 +- .../shared/System/Environment.Win32.cs | 21 +- .../shared/System/Environment.WinRT.cs | 3 +- .../shared/System/Environment.Windows.cs | 3 +- .../shared/System/Environment.cs | 26 +- .../shared/System/EnvironmentVariableTarget.cs | 3 +- .../shared/System/EventArgs.cs | 1 + .../shared/System/EventHandler.cs | 5 +- .../shared/System/FlagsAttribute.cs | 1 + .../shared/System/FormattableString.cs | 9 +- .../shared/System/Gen2GcCallback.cs | 21 +- .../shared/System/Globalization/DateTimeParse.cs | 18 +- .../System/Globalization/TextElementEnumerator.cs | 2 +- .../shared/System/Globalization/TimeSpanParse.cs | 4 +- .../shared/System/Guid.Unix.cs | 1 + .../shared/System/Guid.Windows.cs | 1 + src/System.Private.CoreLib/shared/System/Guid.cs | 13 +- .../shared/System/HResults.cs | 2 +- .../shared/System/HashCode.cs | 5 +- .../shared/System/IAsyncDisposable.cs | 1 + .../shared/System/ICloneable.cs | 1 + .../shared/System/IComparable.cs | 3 +- .../shared/System/IConvertible.cs | 35 +- .../shared/System/ICustomFormatter.cs | 6 +- .../shared/System/IDisposable.cs | 1 + .../shared/System/IEquatable.cs | 3 +- .../shared/System/IFormatProvider.cs | 5 +- .../shared/System/IFormattable.cs | 5 +- .../shared/System/IO/MemoryStream.cs | 4 +- .../shared/System/IO/Stream.cs | 4 +- .../shared/System/IO/TextReader.cs | 4 +- .../shared/System/IO/TextWriter.cs | 8 +- .../shared/System/IO/UnmanagedMemoryStream.cs | 4 +- .../shared/System/IObservable.cs | 1 + .../shared/System/IObserver.cs | 1 + .../shared/System/IProgress.cs | 1 + src/System.Private.CoreLib/shared/System/Index.cs | 3 +- src/System.Private.CoreLib/shared/System/IntPtr.cs | 3 +- src/System.Private.CoreLib/shared/System/Lazy.cs | 9 +- .../System/LocalAppContextSwitches.Common.cs | 2 +- .../shared/System/LocalAppContextSwitches.cs | 2 +- .../shared/System/LocalDataStoreSlot.cs | 5 +- .../shared/System/MarshalByRefObject.cs | 1 + .../shared/System/Marvin.OrdinalIgnoreCase.cs | 3 +- src/System.Private.CoreLib/shared/System/Marvin.cs | 1 + src/System.Private.CoreLib/shared/System/Math.cs | 1 + src/System.Private.CoreLib/shared/System/MathF.cs | 2 +- .../shared/System/MemoryDebugView.cs | 1 + .../shared/System/MidpointRounding.cs | 1 + .../shared/System/NonSerializedAttribute.cs | 1 + .../shared/System/Nullable.cs | 9 +- .../shared/System/ObsoleteAttribute.cs | 11 +- .../shared/System/OperatingSystem.cs | 7 +- .../shared/System/ParamArrayAttribute.cs | 1 + .../shared/System/ParseNumbers.cs | 1 + .../shared/System/PasteArguments.Unix.cs | 1 + .../shared/System/PasteArguments.Windows.cs | 1 + .../shared/System/PasteArguments.cs | 1 + .../shared/System/PlatformID.cs | 1 + .../shared/System/Progress.cs | 11 +- src/System.Private.CoreLib/shared/System/Random.cs | 1 + src/System.Private.CoreLib/shared/System/Range.cs | 5 +- .../shared/System/ResolveEventArgs.cs | 9 +- .../shared/System/ResolveEventHandler.cs | 3 +- .../System/Resources/FileBasedResourceGroveler.cs | 2 +- .../Resources/ManifestBasedResourceGroveler.cs | 11 +- .../shared/System/Resources/ResourceManager.Uap.cs | 4 +- .../shared/System/Resources/ResourceManager.cs | 2 +- .../shared/System/Resources/ResourceReader.cs | 2 +- .../CompilerServices/ConditionalWeakTable.cs | 2 +- .../CompilerServices/FormattableStringFactory.cs | 13 +- .../Runtime/InteropServices/MemoryMarshal.cs | 2 +- src/System.Private.CoreLib/shared/System/SByte.cs | 55 +- .../shared/System/Security/SecurityElement.cs | 12 +- .../shared/System/SerializableAttribute.cs | 1 + .../shared/System/StringComparer.cs | 49 +- .../shared/System/StringComparison.cs | 1 + .../shared/System/StringSplitOptions.cs | 1 + .../shared/System/Text/EncodingTable.cs | 2 +- .../shared/System/Text/StringBuilder.cs | 2 +- .../shared/System/Text/StringRuneEnumerator.cs | 2 +- .../shared/System/ThreadAttributes.cs | 1 + .../shared/System/ThreadStaticAttribute.cs | 1 + .../shared/System/Threading/ExecutionContext.cs | 2 +- .../shared/System/Threading/Thread.cs | 2 +- .../shared/System/ThrowHelper.cs | 23 +- .../shared/System/TimeSpan.cs | 53 +- .../shared/System/TimeZone.cs | 11 +- .../shared/System/TimeZoneInfo.AdjustmentRule.cs | 5 +- .../shared/System/TimeZoneInfo.StringSerializer.cs | 9 +- .../shared/System/TimeZoneInfo.TransitionTime.cs | 3 +- .../shared/System/TimeZoneInfo.Unix.cs | 79 +- .../shared/System/TimeZoneInfo.Win32.cs | 1978 +++++----- .../shared/System/TimeZoneInfo.cs | 4118 ++++++++++---------- src/System.Private.CoreLib/shared/System/Tuple.cs | 73 +- .../shared/System/TupleExtensions.cs | 1 + .../shared/System/TypeCode.cs | 1 + .../shared/System/UIntPtr.cs | 3 +- .../shared/System/UnhandledExceptionEventArgs.cs | 1 + .../System/UnhandledExceptionEventHandler.cs | 1 + .../shared/System/UnitySerializationHolder.cs | 1 + .../shared/System/ValueTuple.cs | 85 +- .../shared/System/Version.cs | 54 +- src/System.Private.CoreLib/shared/System/Void.cs | 1 + .../src/System/AppContext.CoreCLR.cs | 5 +- .../src/System/ApplicationModel.Windows.cs | 1 + .../src/System/ArgIterator.cs | 5 +- .../src/System/Buffer.CoreCLR.cs | 1 + src/System.Private.CoreLib/src/System/CLRConfig.cs | 1 + src/System.Private.CoreLib/src/System/Char8.cs | 3 +- src/System.Private.CoreLib/src/System/Currency.cs | 1 + .../src/System/DateTime.Unix.CoreCLR.cs | 3 +- .../src/System/DateTime.Windows.cs | 1 + .../src/System/Environment.CoreCLR.cs | 9 +- .../src/System/Exception.CoreCLR.cs | 2 +- src/System.Private.CoreLib/src/System/GC.cs | 4 +- .../src/System/IO/FileLoadException.CoreCLR.cs | 6 +- src/System.Private.CoreLib/src/System/Internal.cs | 1 + .../src/System/Math.CoreCLR.cs | 1 + .../src/System/MathF.CoreCLR.cs | 1 + .../src/System/Reflection/Assembly.CoreCLR.cs | 15 +- .../src/System/Reflection/AssemblyName.cs | 71 +- .../src/System/Reflection/RuntimeAssembly.cs | 123 +- .../ManifestBasedResourceGroveler.CoreCLR.cs | 2 +- .../System/Runtime/CompilerServices/jithelpers.cs | 5 +- .../Runtime/Loader/AssemblyLoadContext.CoreCLR.cs | 14 +- .../src/System/RuntimeArgumentHandle.cs | 4 +- .../src/System/StartupHookProvider.cs | 5 +- .../src/System/StubHelpers.cs | 64 +- .../src/System/TypeLoadException.CoreCLR.cs | 2 +- .../src/System/TypedReference.cs | 9 +- .../src/System/Utf8Extensions.cs | 33 +- .../src/System/Utf8String.Construction.cs | 15 +- .../src/System/Utf8String.Manipulation.cs | 1 + .../src/System/Utf8String.Searching.cs | 1 + .../src/System/Utf8String.cs | 19 +- src/System.Private.CoreLib/src/System/Variant.cs | 11 +- .../src/System/WeakReference.cs | 9 +- .../src/System/WeakReferenceOfT.cs | 3 +- src/System.Private.CoreLib/src/System/__Canon.cs | 1 + .../src/System/__ComObject.cs | 19 +- 183 files changed, 4156 insertions(+), 4047 deletions(-) diff --git a/src/System.Private.CoreLib/Common/System/SR.cs b/src/System.Private.CoreLib/Common/System/SR.cs index f8657db..da03e59 100644 --- a/src/System.Private.CoreLib/Common/System/SR.cs +++ b/src/System.Private.CoreLib/Common/System/SR.cs @@ -29,7 +29,7 @@ namespace System } // Needed for debugger integration - internal static string GetResourceString(string resourceKey) + internal static string? GetResourceString(string resourceKey) { return GetResourceString(resourceKey, string.Empty); } @@ -53,7 +53,7 @@ namespace System private static int _infinitelyRecursingCount; private static bool _resourceManagerInited = false; - private static string InternalGetResourceString(string key) + private static string? InternalGetResourceString(string? key) { if (key == null || key.Length == 0) { @@ -150,7 +150,7 @@ namespace System } } - internal static string Format(IFormatProvider provider, string resourceFormat, params object?[]? args) + internal static string Format(IFormatProvider? provider, string resourceFormat, params object?[]? args) { if (args != null) { diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs index 989d072..f8ad82a 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs @@ -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 #if REGISTRY_ASSEMBLY using Microsoft.Win32.SafeHandles; #else @@ -19,16 +20,16 @@ internal partial class Interop internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string lpValueName, - int[] lpReserved, + int[]? lpReserved, ref int lpType, - [Out] byte[] lpData, + [Out] byte[]? lpData, ref int lpcbData); [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW")] internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string lpValueName, - int[] lpReserved, + int[]? lpReserved, ref int lpType, ref int lpData, ref int lpcbData); @@ -37,7 +38,7 @@ internal partial class Interop internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string lpValueName, - int[] lpReserved, + int[]? lpReserved, ref int lpType, ref long lpData, ref int lpcbData); @@ -46,7 +47,7 @@ internal partial class Interop internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string lpValueName, - int[] lpReserved, + int[]? lpReserved, ref int lpType, [Out] char[] lpData, ref int lpcbData); diff --git a/src/System.Private.CoreLib/shared/System/Action.cs b/src/System.Private.CoreLib/shared/System/Action.cs index 54ca7aa..4c84037 100644 --- a/src/System.Private.CoreLib/shared/System/Action.cs +++ b/src/System.Private.CoreLib/shared/System/Action.cs @@ -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 namespace System { public delegate void Action(); diff --git a/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs b/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs index f328b9c..224abdb 100644 --- a/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs +++ b/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs @@ -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.Reflection; using System.Globalization; using System.Runtime.Remoting; @@ -11,7 +12,7 @@ namespace System { public static partial class Activator { - public static object CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes) + public static object? CreateInstance(Type type, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture, object?[]? activationAttributes) { if (type is null) throw new ArgumentNullException(nameof(type)); @@ -34,7 +35,7 @@ namespace System } [System.Security.DynamicSecurityMethod] - public static ObjectHandle CreateInstance(string assemblyName, string typeName) + public static ObjectHandle? CreateInstance(string assemblyName, string typeName) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return CreateInstanceInternal(assemblyName, @@ -49,7 +50,7 @@ namespace System } [System.Security.DynamicSecurityMethod] - public static ObjectHandle CreateInstance(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes) + public static ObjectHandle? CreateInstance(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture, object?[]? activationAttributes) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return CreateInstanceInternal(assemblyName, @@ -64,7 +65,7 @@ namespace System } [System.Security.DynamicSecurityMethod] - public static ObjectHandle CreateInstance(string assemblyName, string typeName, object[] activationAttributes) + public static ObjectHandle? CreateInstance(string assemblyName, string typeName, object?[]? activationAttributes) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return CreateInstanceInternal(assemblyName, @@ -78,10 +79,10 @@ namespace System ref stackMark); } - public static object CreateInstance(Type type, bool nonPublic) => + public static object? CreateInstance(Type type, bool nonPublic) => CreateInstance(type, nonPublic, wrapExceptions: true); - internal static object CreateInstance(Type type, bool nonPublic, bool wrapExceptions) + internal static object? CreateInstance(Type type, bool nonPublic, bool wrapExceptions) { if (type is null) throw new ArgumentNullException(nameof(type)); @@ -92,25 +93,25 @@ namespace System throw new ArgumentException(SR.Arg_MustBeType, nameof(type)); } - private static ObjectHandle CreateInstanceInternal(string assemblyString, + private static ObjectHandle? CreateInstanceInternal(string assemblyString, string typeName, bool ignoreCase, BindingFlags bindingAttr, - Binder binder, - object[] args, - CultureInfo culture, - object[] activationAttributes, + Binder? binder, + object?[]? args, + CultureInfo? culture, + object?[]? activationAttributes, ref StackCrawlMark stackMark) { - Type type = null; - Assembly assembly = null; + Type? type = null; + Assembly? assembly = null; if (assemblyString == null) { assembly = Assembly.GetExecutingAssembly(ref stackMark); } else { - RuntimeAssembly assemblyFromResolveEvent; + RuntimeAssembly? assemblyFromResolveEvent; AssemblyName assemblyName = RuntimeAssembly.CreateAssemblyName(assemblyString, out assemblyFromResolveEvent); if (assemblyFromResolveEvent != null) { @@ -132,10 +133,10 @@ namespace System if (type == null) { - type = assembly.GetType(typeName, throwOnError: true, ignoreCase); + type = assembly!.GetType(typeName, throwOnError: true, ignoreCase); } - object o = CreateInstance(type, bindingAttr, binder, args, culture, activationAttributes); + object? o = CreateInstance(type, bindingAttr, binder, args, culture, activationAttributes); return o != null ? new ObjectHandle(o) : null; } diff --git a/src/System.Private.CoreLib/shared/System/Activator.cs b/src/System.Private.CoreLib/shared/System/Activator.cs index 203eb23..b4e5ddf 100644 --- a/src/System.Private.CoreLib/shared/System/Activator.cs +++ b/src/System.Private.CoreLib/shared/System/Activator.cs @@ -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.Diagnostics; using System.Globalization; using System.Reflection; @@ -18,36 +19,36 @@ namespace System [DebuggerHidden] [DebuggerStepThrough] - public static object CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture) => + public static object? CreateInstance(Type type, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture) => CreateInstance(type, bindingAttr, binder, args, culture, null); [DebuggerHidden] [DebuggerStepThrough] - public static object CreateInstance(Type type, params object[] args) => + public static object? CreateInstance(Type type, params object?[]? args) => CreateInstance(type, ConstructorDefault, null, args, null, null); [DebuggerHidden] [DebuggerStepThrough] - public static object CreateInstance(Type type, object[] args, object[] activationAttributes) => + public static object? CreateInstance(Type type, object?[]? args, object?[]? activationAttributes) => CreateInstance(type, ConstructorDefault, null, args, null, activationAttributes); [DebuggerHidden] [DebuggerStepThrough] - public static object CreateInstance(Type type) => + public static object? CreateInstance(Type type) => CreateInstance(type, nonPublic: false); - public static ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName) => + public static ObjectHandle? CreateInstanceFrom(string assemblyFile, string typeName) => CreateInstanceFrom(assemblyFile, typeName, false, ConstructorDefault, null, null, null, null); - public static ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName, object[] activationAttributes) => + public static ObjectHandle? CreateInstanceFrom(string assemblyFile, string typeName, object?[]? activationAttributes) => CreateInstanceFrom(assemblyFile, typeName, false, ConstructorDefault, null, null, null, activationAttributes); - public static ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes) + public static ObjectHandle? CreateInstanceFrom(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture, object?[]? activationAttributes) { Assembly assembly = Assembly.LoadFrom(assemblyFile); Type t = assembly.GetType(typeName, true, ignoreCase); - object o = CreateInstance(t, bindingAttr, binder, args, culture, activationAttributes); + object? o = CreateInstance(t, bindingAttr, binder, args, culture, activationAttributes); return o != null ? new ObjectHandle(o) : null; } diff --git a/src/System.Private.CoreLib/shared/System/AppContext.cs b/src/System.Private.CoreLib/shared/System/AppContext.cs index c3994ea..fcda485 100644 --- a/src/System.Private.CoreLib/shared/System/AppContext.cs +++ b/src/System.Private.CoreLib/shared/System/AppContext.cs @@ -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.Collections.Generic; using System.Reflection; using System.Runtime.ExceptionServices; @@ -13,22 +14,22 @@ namespace System { public static partial class AppContext { - private static readonly Dictionary s_dataStore = new Dictionary(); - private static Dictionary s_switches; - private static string s_defaultBaseDirectory; + private static readonly Dictionary s_dataStore = new Dictionary(); + private static Dictionary? s_switches; + private static string? s_defaultBaseDirectory; - public static string BaseDirectory + public static string? BaseDirectory { get { // The value of APP_CONTEXT_BASE_DIRECTORY key has to be a string and it is not allowed to be any other type. // Otherwise the caller will get invalid cast exception - return (string)GetData("APP_CONTEXT_BASE_DIRECTORY") ?? + return (string?)GetData("APP_CONTEXT_BASE_DIRECTORY") ?? (s_defaultBaseDirectory ?? (s_defaultBaseDirectory = GetBaseDirectoryCore())); } } - public static string TargetFrameworkName + public static string? TargetFrameworkName { get { @@ -38,12 +39,12 @@ namespace System } } - public static object GetData(string name) + public static object? GetData(string name) { if (name == null) throw new ArgumentNullException(nameof(name)); - object data; + object? data; lock (s_dataStore) { s_dataStore.TryGetValue(name, out data); @@ -51,7 +52,7 @@ namespace System return data; } - public static void SetData(string name, object data) + public static void SetData(string name, object? data) { if (name == null) throw new ArgumentNullException(nameof(name)); @@ -126,7 +127,7 @@ namespace System Interlocked.CompareExchange(ref s_switches, new Dictionary(), null); } - lock (s_switches) + lock (s_switches!) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { s_switches[switchName] = isEnabled; } diff --git a/src/System.Private.CoreLib/shared/System/AppDomain.cs b/src/System.Private.CoreLib/shared/System/AppDomain.cs index 707f827..be238e3 100644 --- a/src/System.Private.CoreLib/shared/System/AppDomain.cs +++ b/src/System.Private.CoreLib/shared/System/AppDomain.cs @@ -4,6 +4,7 @@ #pragma warning disable CS0067 // events are declared but not used +#nullable enable using System.Diagnostics; using System.IO; using System.Reflection; @@ -24,18 +25,18 @@ namespace System { private static readonly AppDomain s_domain = new AppDomain(); private readonly object _forLock = new object(); - private IPrincipal _defaultPrincipal; + private IPrincipal? _defaultPrincipal; private PrincipalPolicy _principalPolicy = PrincipalPolicy.NoPrincipal; - private Func s_getWindowsPrincipal; - private Func s_getUnauthenticatedPrincipal; + private Func? s_getWindowsPrincipal; + private Func? s_getUnauthenticatedPrincipal; private AppDomain() { } public static AppDomain CurrentDomain => s_domain; - public string BaseDirectory => AppContext.BaseDirectory; + public string? BaseDirectory => AppContext.BaseDirectory; - public string RelativeSearchPath => null; + public string? RelativeSearchPath => null; public AppDomainSetup SetupInformation => new AppDomainSetup(); @@ -47,17 +48,17 @@ namespace System remove { AppContext.UnhandledException -= value; } } - public string DynamicDirectory => null; + public string? DynamicDirectory => null; [ObsoleteAttribute("AppDomain.SetDynamicBase has been deprecated. Please investigate the use of AppDomainSetup.DynamicBase instead. https://go.microsoft.com/fwlink/?linkid=14202")] - public void SetDynamicBase(string path) { } + public void SetDynamicBase(string? path) { } public string FriendlyName { get { - Assembly assembly = Assembly.GetEntryAssembly(); - return assembly != null ? assembly.GetName().Name : "DefaultDomain"; + Assembly? assembly = Assembly.GetEntryAssembly(); + return assembly != null ? assembly.GetName().Name! : "DefaultDomain"; } } @@ -103,7 +104,7 @@ namespace System public int ExecuteAssembly(string assemblyFile) => ExecuteAssembly(assemblyFile, null); - public int ExecuteAssembly(string assemblyFile, string[] args) + public int ExecuteAssembly(string assemblyFile, string?[]? args) { if (assemblyFile == null) { @@ -114,41 +115,41 @@ namespace System return ExecuteAssembly(assembly, args); } - public int ExecuteAssembly(string assemblyFile, string[] args, byte[] hashValue, Configuration.Assemblies.AssemblyHashAlgorithm hashAlgorithm) + public int ExecuteAssembly(string assemblyFile, string?[]? args, byte[]? hashValue, Configuration.Assemblies.AssemblyHashAlgorithm hashAlgorithm) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_CAS); // This api is only meaningful for very specific partial trust/CAS scenarios } - private int ExecuteAssembly(Assembly assembly, string[] args) + private int ExecuteAssembly(Assembly assembly, string?[]? args) { - MethodInfo entry = assembly.EntryPoint; + MethodInfo? entry = assembly.EntryPoint; if (entry == null) { throw new MissingMethodException(SR.Arg_EntryPointNotFoundException); } - object result = entry.Invoke( + object? result = entry.Invoke( obj: null, invokeAttr: BindingFlags.DoNotWrapExceptions, binder: null, - parameters: entry.GetParameters().Length > 0 ? new object[] { args } : null, + parameters: entry.GetParameters().Length > 0 ? new object?[] { args } : null, culture: null); return result != null ? (int)result : 0; } - public int ExecuteAssemblyByName(AssemblyName assemblyName, params string[] args) => + public int ExecuteAssemblyByName(AssemblyName assemblyName, params string?[]? args) => ExecuteAssembly(Assembly.Load(assemblyName), args); public int ExecuteAssemblyByName(string assemblyName) => ExecuteAssemblyByName(assemblyName, null); - public int ExecuteAssemblyByName(string assemblyName, params string[] args) => + public int ExecuteAssemblyByName(string assemblyName, params string?[]? args) => ExecuteAssembly(Assembly.Load(assemblyName), args); - public object GetData(string name) => AppContext.GetData(name); + public object? GetData(string name) => AppContext.GetData(name); - public void SetData(string name, object data) => AppContext.SetData(name, data); + public void SetData(string name, object? data) => AppContext.SetData(name, data); public bool? IsCompatibilitySwitchSet(string value) { @@ -174,7 +175,7 @@ namespace System public Assembly Load(byte[] rawAssembly) => Assembly.Load(rawAssembly); - public Assembly Load(byte[] rawAssembly, byte[] rawSymbolStore) => Assembly.Load(rawAssembly, rawSymbolStore); + public Assembly Load(byte[] rawAssembly, byte[]? rawSymbolStore) => Assembly.Load(rawAssembly, rawSymbolStore); public Assembly Load(AssemblyName assemblyRef) => Assembly.Load(assemblyRef); @@ -211,7 +212,7 @@ namespace System public bool ShadowCopyFiles => false; [ObsoleteAttribute("AppDomain.AppendPrivatePath has been deprecated. Please investigate the use of AppDomainSetup.PrivateBinPath instead. https://go.microsoft.com/fwlink/?linkid=14202")] - public void AppendPrivatePath(string path) { } + public void AppendPrivatePath(string? path) { } [ObsoleteAttribute("AppDomain.ClearPrivatePath has been deprecated. Please investigate the use of AppDomainSetup.PrivateBinPath instead. https://go.microsoft.com/fwlink/?linkid=14202")] public void ClearPrivatePath() { } @@ -220,13 +221,13 @@ namespace System public void ClearShadowCopyPath() { } [ObsoleteAttribute("AppDomain.SetCachePath has been deprecated. Please investigate the use of AppDomainSetup.CachePath instead. https://go.microsoft.com/fwlink/?linkid=14202")] - public void SetCachePath(string path) { } + public void SetCachePath(string? path) { } [ObsoleteAttribute("AppDomain.SetShadowCopyFiles has been deprecated. Please investigate the use of AppDomainSetup.ShadowCopyFiles instead. https://go.microsoft.com/fwlink/?linkid=14202")] public void SetShadowCopyFiles() { } [ObsoleteAttribute("AppDomain.SetShadowCopyPath has been deprecated. Please investigate the use of AppDomainSetup.ShadowCopyDirectories instead. https://go.microsoft.com/fwlink/?linkid=14202")] - public void SetShadowCopyPath(string path) { } + public void SetShadowCopyPath(string? path) { } public Assembly[] GetAssemblies() => AssemblyLoadContext.GetLoadedAssemblies(); @@ -279,7 +280,7 @@ namespace System } } - public ObjectHandle CreateInstance(string assemblyName, string typeName) + public ObjectHandle? CreateInstance(string assemblyName, string typeName) { if (assemblyName == null) { @@ -289,7 +290,7 @@ namespace System return Activator.CreateInstance(assemblyName, typeName); } - public ObjectHandle CreateInstance(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + public ObjectHandle? CreateInstance(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { if (assemblyName == null) { @@ -306,7 +307,7 @@ namespace System activationAttributes); } - public ObjectHandle CreateInstance(string assemblyName, string typeName, object[] activationAttributes) + public ObjectHandle? CreateInstance(string assemblyName, string typeName, object?[]? activationAttributes) { if (assemblyName == null) { @@ -316,15 +317,15 @@ namespace System return Activator.CreateInstance(assemblyName, typeName, activationAttributes); } - public object CreateInstanceAndUnwrap(string assemblyName, string typeName) + public object? CreateInstanceAndUnwrap(string assemblyName, string typeName) { - ObjectHandle oh = CreateInstance(assemblyName, typeName); + ObjectHandle? oh = CreateInstance(assemblyName, typeName); return oh?.Unwrap(); } - public object CreateInstanceAndUnwrap(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + public object? CreateInstanceAndUnwrap(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { - ObjectHandle oh = CreateInstance(assemblyName, + ObjectHandle? oh = CreateInstance(assemblyName, typeName, ignoreCase, bindingAttr, @@ -335,18 +336,18 @@ namespace System return oh?.Unwrap(); } - public object CreateInstanceAndUnwrap(string assemblyName, string typeName, object[] activationAttributes) + public object? CreateInstanceAndUnwrap(string assemblyName, string typeName, object?[]? activationAttributes) { - ObjectHandle oh = CreateInstance(assemblyName, typeName, activationAttributes); + ObjectHandle? oh = CreateInstance(assemblyName, typeName, activationAttributes); return oh?.Unwrap(); } - public ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName) + public ObjectHandle? CreateInstanceFrom(string assemblyFile, string typeName) { return Activator.CreateInstanceFrom(assemblyFile, typeName); } - public ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + public ObjectHandle? CreateInstanceFrom(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { return Activator.CreateInstanceFrom(assemblyFile, typeName, @@ -358,20 +359,20 @@ namespace System activationAttributes); } - public ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName, object[] activationAttributes) + public ObjectHandle? CreateInstanceFrom(string assemblyFile, string typeName, object?[]? activationAttributes) { return Activator.CreateInstanceFrom(assemblyFile, typeName, activationAttributes); } public object CreateInstanceFromAndUnwrap(string assemblyFile, string typeName) { - ObjectHandle oh = CreateInstanceFrom(assemblyFile, typeName); - return oh?.Unwrap(); + ObjectHandle? oh = CreateInstanceFrom(assemblyFile, typeName); + return oh?.Unwrap()!; } - public object CreateInstanceFromAndUnwrap(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + public object? CreateInstanceFromAndUnwrap(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { - ObjectHandle oh = CreateInstanceFrom(assemblyFile, + ObjectHandle? oh = CreateInstanceFrom(assemblyFile, typeName, ignoreCase, bindingAttr, @@ -379,18 +380,18 @@ namespace System args, culture, activationAttributes); - return oh?.Unwrap(); + return oh?.Unwrap()!; } - public object CreateInstanceFromAndUnwrap(string assemblyFile, string typeName, object[] activationAttributes) + public object? CreateInstanceFromAndUnwrap(string assemblyFile, string typeName, object?[]? activationAttributes) { - ObjectHandle oh = CreateInstanceFrom(assemblyFile, typeName, activationAttributes); - return oh?.Unwrap(); + ObjectHandle? oh = CreateInstanceFrom(assemblyFile, typeName, activationAttributes); + return oh?.Unwrap()!; } - public IPrincipal GetThreadPrincipal() + public IPrincipal? GetThreadPrincipal() { - IPrincipal principal = _defaultPrincipal; + IPrincipal? principal = _defaultPrincipal; if (principal == null) { switch (_principalPolicy) @@ -407,7 +408,7 @@ namespace System (Func)mi.CreateDelegate(typeof(Func))); } - principal = s_getUnauthenticatedPrincipal(); + principal = s_getUnauthenticatedPrincipal!(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 break; case PrincipalPolicy.WindowsPrincipal: @@ -423,7 +424,7 @@ namespace System (Func)mi.CreateDelegate(typeof(Func))); } - principal = s_getWindowsPrincipal(); + principal = s_getWindowsPrincipal!(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 break; } } diff --git a/src/System.Private.CoreLib/shared/System/AppDomainSetup.cs b/src/System.Private.CoreLib/shared/System/AppDomainSetup.cs index c278e72..e8d0b9f 100644 --- a/src/System.Private.CoreLib/shared/System/AppDomainSetup.cs +++ b/src/System.Private.CoreLib/shared/System/AppDomainSetup.cs @@ -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 namespace System { #if PROJECTN @@ -10,7 +11,7 @@ namespace System public sealed class AppDomainSetup { internal AppDomainSetup() { } - public string ApplicationBase => AppContext.BaseDirectory; - public string TargetFrameworkName => AppContext.TargetFrameworkName; + public string? ApplicationBase => AppContext.BaseDirectory; + public string? TargetFrameworkName => AppContext.TargetFrameworkName; } } diff --git a/src/System.Private.CoreLib/shared/System/Array.Enumerators.cs b/src/System.Private.CoreLib/shared/System/Array.Enumerators.cs index b9974ec..4547af1 100644 --- a/src/System.Private.CoreLib/shared/System/Array.Enumerators.cs +++ b/src/System.Private.CoreLib/shared/System/Array.Enumerators.cs @@ -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.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -81,7 +82,7 @@ namespace System return !_complete; } - public object Current + public object? Current { get { @@ -136,7 +137,7 @@ namespace System return false; } - public object Current + public object? Current { get { @@ -199,7 +200,7 @@ namespace System } } - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; void IEnumerator.Reset() => _index = -1; @@ -207,4 +208,4 @@ namespace System { } } -} \ No newline at end of file +} diff --git a/src/System.Private.CoreLib/shared/System/ArraySegment.cs b/src/System.Private.CoreLib/shared/System/ArraySegment.cs index b2bd417..58eb506 100644 --- a/src/System.Private.CoreLib/shared/System/ArraySegment.cs +++ b/src/System.Private.CoreLib/shared/System/ArraySegment.cs @@ -13,6 +13,7 @@ ** ===========================================================*/ +#nullable enable using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -32,7 +33,7 @@ namespace System // instantiating another generic type in addition to ArraySegment for new type parameters. public static ArraySegment Empty { get; } = new ArraySegment(new T[0]); - private readonly T[] _array; // Do not rename (binary serialization) + private readonly T[]? _array; // Do not rename (binary serialization) private readonly int _offset; // Do not rename (binary serialization) private readonly int _count; // Do not rename (binary serialization) @@ -43,7 +44,7 @@ namespace System _array = array; _offset = 0; - _count = array.Length; + _count = array!.Length; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } public ArraySegment(T[] array, int offset, int count) @@ -59,7 +60,7 @@ namespace System _count = count; } - public T[] Array => _array; + public T[]? Array => _array; public int Offset => _offset; @@ -74,7 +75,7 @@ namespace System ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } - return _array[_offset + index]; + return _array![_offset + index]; } set { @@ -83,7 +84,7 @@ namespace System ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } - _array[_offset + index] = value; + _array![_offset + index] = value; } } @@ -115,7 +116,7 @@ namespace System public void CopyTo(T[] destination, int destinationIndex) { ThrowInvalidOperationIfDefault(); - System.Array.Copy(_array, _offset, destination, destinationIndex, _count); + System.Array.Copy(_array!, _offset, destination, destinationIndex, _count); } public void CopyTo(ArraySegment destination) @@ -128,10 +129,10 @@ namespace System ThrowHelper.ThrowArgumentException_DestinationTooShort(); } - System.Array.Copy(_array, _offset, destination._array, destination._offset, _count); + System.Array.Copy(_array!, _offset, destination._array!, destination._offset, _count); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is ArraySegment) return Equals((ArraySegment)obj); @@ -153,7 +154,7 @@ namespace System ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } - return new ArraySegment(_array, _offset + index, _count - index); + return new ArraySegment(_array!, _offset + index, _count - index); } public ArraySegment Slice(int index, int count) @@ -165,7 +166,7 @@ namespace System ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } - return new ArraySegment(_array, _offset + index, count); + return new ArraySegment(_array!, _offset + index, count); } public T[] ToArray() @@ -174,11 +175,11 @@ namespace System if (_count == 0) { - return Empty._array; + return Empty._array!; } var array = new T[_count]; - System.Array.Copy(_array, _offset, array, 0, _count); + System.Array.Copy(_array!, _offset, array, 0, _count); return array; } @@ -203,7 +204,7 @@ namespace System if (index < 0 || index >= _count) ThrowHelper.ThrowArgumentOutOfRange_IndexException(); - return _array[_offset + index]; + return _array![_offset + index]; } set @@ -212,7 +213,7 @@ namespace System if (index < 0 || index >= _count) ThrowHelper.ThrowArgumentOutOfRange_IndexException(); - _array[_offset + index] = value; + _array![_offset + index] = value; } } @@ -220,7 +221,7 @@ namespace System { ThrowInvalidOperationIfDefault(); - int index = System.Array.IndexOf(_array, item, _offset, _count); + int index = System.Array.IndexOf(_array!, item, _offset, _count); Debug.Assert(index == -1 || (index >= _offset && index < _offset + _count)); @@ -248,7 +249,7 @@ namespace System if (index < 0 || index >= _count) ThrowHelper.ThrowArgumentOutOfRange_IndexException(); - return _array[_offset + index]; + return _array![_offset + index]; } } #endregion IReadOnlyList @@ -278,7 +279,7 @@ namespace System { ThrowInvalidOperationIfDefault(); - int index = System.Array.IndexOf(_array, item, _offset, _count); + int index = System.Array.IndexOf(_array!, item, _offset, _count); Debug.Assert(index == -1 || (index >= _offset && index < _offset + _count)); @@ -313,7 +314,7 @@ namespace System public struct Enumerator : IEnumerator { - private readonly T[] _array; + private readonly T[]? _array; private readonly int _start; private readonly int _end; // cache Offset + Count, since it's a little slow private int _current; @@ -323,7 +324,7 @@ namespace System Debug.Assert(arraySegment.Array != null); Debug.Assert(arraySegment.Offset >= 0); Debug.Assert(arraySegment.Count >= 0); - Debug.Assert(arraySegment.Offset + arraySegment.Count <= arraySegment.Array.Length); + Debug.Assert(arraySegment.Offset + arraySegment.Count <= arraySegment.Array!.Length); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34792 _array = arraySegment.Array; _start = arraySegment.Offset; @@ -349,11 +350,11 @@ namespace System ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted(); if (_current >= _end) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded(); - return _array[_current]; + return _array![_current]; } } - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; void IEnumerator.Reset() { diff --git a/src/System.Private.CoreLib/shared/System/AssemblyLoadEventArgs.cs b/src/System.Private.CoreLib/shared/System/AssemblyLoadEventArgs.cs index d7e5249..43b32d7 100644 --- a/src/System.Private.CoreLib/shared/System/AssemblyLoadEventArgs.cs +++ b/src/System.Private.CoreLib/shared/System/AssemblyLoadEventArgs.cs @@ -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.Reflection; namespace System diff --git a/src/System.Private.CoreLib/shared/System/AssemblyLoadEventHandler.cs b/src/System.Private.CoreLib/shared/System/AssemblyLoadEventHandler.cs index 752379f..af89e63 100644 --- a/src/System.Private.CoreLib/shared/System/AssemblyLoadEventHandler.cs +++ b/src/System.Private.CoreLib/shared/System/AssemblyLoadEventHandler.cs @@ -2,7 +2,8 @@ // 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 namespace System { - public delegate void AssemblyLoadEventHandler(object sender, AssemblyLoadEventArgs args); + public delegate void AssemblyLoadEventHandler(object? sender, AssemblyLoadEventArgs args); } diff --git a/src/System.Private.CoreLib/shared/System/AsyncCallback.cs b/src/System.Private.CoreLib/shared/System/AsyncCallback.cs index 036d44a..f06749f 100644 --- a/src/System.Private.CoreLib/shared/System/AsyncCallback.cs +++ b/src/System.Private.CoreLib/shared/System/AsyncCallback.cs @@ -10,6 +10,7 @@ ** ===========================================================*/ +#nullable enable namespace System { public delegate void AsyncCallback(IAsyncResult ar); diff --git a/src/System.Private.CoreLib/shared/System/AttributeTargets.cs b/src/System.Private.CoreLib/shared/System/AttributeTargets.cs index c33d19e..dbbade3 100644 --- a/src/System.Private.CoreLib/shared/System/AttributeTargets.cs +++ b/src/System.Private.CoreLib/shared/System/AttributeTargets.cs @@ -5,6 +5,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// +#nullable enable namespace System { // Enum used to indicate all the elements of the diff --git a/src/System.Private.CoreLib/shared/System/AttributeUsageAttribute.cs b/src/System.Private.CoreLib/shared/System/AttributeUsageAttribute.cs index 8a4a0a6..d96e405 100644 --- a/src/System.Private.CoreLib/shared/System/AttributeUsageAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/AttributeUsageAttribute.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +#nullable enable using System.Reflection; namespace System diff --git a/src/System.Private.CoreLib/shared/System/BitConverter.cs b/src/System.Private.CoreLib/shared/System/BitConverter.cs index eedd5af..196725e 100644 --- a/src/System.Private.CoreLib/shared/System/BitConverter.cs +++ b/src/System.Private.CoreLib/shared/System/BitConverter.cs @@ -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. -using System.Diagnostics; +#nullable enable using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -237,7 +237,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) + if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(short)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); @@ -258,7 +258,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) + if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(int)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); @@ -279,7 +279,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) + if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(long)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); @@ -364,11 +364,11 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (startIndex < 0 || startIndex >= value.Length && startIndex > 0) + if (startIndex < 0 || startIndex >= value!.Length && startIndex > 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (length < 0) throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_GenericPositive); - if (startIndex > value.Length - length) + if (startIndex > value!.Length - length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); if (length == 0) @@ -410,7 +410,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - return ToString(value, 0, value.Length); + return ToString(value!, 0, value!.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // Converts an array of bytes into a String. @@ -418,7 +418,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - return ToString(value, startIndex, value.Length - startIndex); + return ToString(value!, startIndex, value!.Length - startIndex); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } /*==================================ToBoolean=================================== @@ -436,7 +436,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (startIndex < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); - if (startIndex > value.Length - 1) + if (startIndex > value!.Length - 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); // differs from other overloads, which throw base ArgumentException return value[startIndex] != 0; diff --git a/src/System.Private.CoreLib/shared/System/Buffer.Unix.cs b/src/System.Private.CoreLib/shared/System/Buffer.Unix.cs index fee3ccb..7de47fd 100644 --- a/src/System.Private.CoreLib/shared/System/Buffer.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Buffer.Unix.cs @@ -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 #if BIT64 using nuint = System.UInt64; #else @@ -23,4 +24,4 @@ namespace System private const nuint MemmoveNativeThreshold = 2048; #endif } -} \ No newline at end of file +} diff --git a/src/System.Private.CoreLib/shared/System/Buffer.Windows.cs b/src/System.Private.CoreLib/shared/System/Buffer.Windows.cs index 4de884d..2609e90 100644 --- a/src/System.Private.CoreLib/shared/System/Buffer.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Buffer.Windows.cs @@ -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 #if BIT64 using nuint = System.UInt64; #else @@ -20,4 +21,4 @@ namespace System private const nuint MemmoveNativeThreshold = 2048; #endif } -} \ No newline at end of file +} diff --git a/src/System.Private.CoreLib/shared/System/Buffer.cs b/src/System.Private.CoreLib/shared/System/Buffer.cs index f2ffaae..da62bc5 100644 --- a/src/System.Private.CoreLib/shared/System/Buffer.cs +++ b/src/System.Private.CoreLib/shared/System/Buffer.cs @@ -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 #if AMD64 || ARM64 || (BIT32 && !ARM) #define HAS_CUSTOM_BLOCKS #endif diff --git a/src/System.Private.CoreLib/shared/System/CLSCompliantAttribute.cs b/src/System.Private.CoreLib/shared/System/CLSCompliantAttribute.cs index d895b5a..9790e93 100644 --- a/src/System.Private.CoreLib/shared/System/CLSCompliantAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/CLSCompliantAttribute.cs @@ -11,6 +11,7 @@ ** =============================================================================*/ +#nullable enable namespace System { [AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)] diff --git a/src/System.Private.CoreLib/shared/System/CharEnumerator.cs b/src/System.Private.CoreLib/shared/System/CharEnumerator.cs index ca60705..0b2caef 100644 --- a/src/System.Private.CoreLib/shared/System/CharEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/CharEnumerator.cs @@ -12,6 +12,7 @@ ** ============================================================*/ +#nullable enable using System.Collections; using System.Collections.Generic; @@ -19,7 +20,7 @@ namespace System { public sealed class CharEnumerator : IEnumerator, IEnumerator, IDisposable, ICloneable { - private string _str; + private string? _str; private int _index; private char _currentElement; @@ -36,7 +37,7 @@ namespace System public bool MoveNext() { - if (_index < (_str.Length - 1)) + if (_index < (_str!.Length - 1)) { _index++; _currentElement = _str[_index]; @@ -54,7 +55,7 @@ namespace System _str = null; } - object IEnumerator.Current + object? IEnumerator.Current // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 { get { return Current; } } @@ -65,7 +66,7 @@ namespace System { if (_index == -1) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); - if (_index >= _str.Length) + if (_index >= _str!.Length) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); return _currentElement; } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs index 543bdb5..7b983a9 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs @@ -2,8 +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. -using System; - +#nullable enable namespace System.Collections.Generic { // The generic IEqualityComparer interface implements methods to if check two objects are equal @@ -12,7 +11,7 @@ namespace System.Collections.Generic public interface IEqualityComparer { bool Equals(T x, T y); - int GetHashCode(T obj); + int GetHashCode(T obj); // TODO-NULLABLE-GENERIC: This generally doesn't accept nulls. } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/IEnumerator.cs b/src/System.Private.CoreLib/shared/System/Collections/IEnumerator.cs index 29a6f47..83d2064 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/IEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/IEnumerator.cs @@ -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; using System.Runtime.InteropServices; @@ -25,7 +26,7 @@ namespace System.Collections // GetCurrent with no intervening calls to MoveNext // will return the same object. // - object Current + object? Current { get; } diff --git a/src/System.Private.CoreLib/shared/System/Collections/IStructuralEquatable.cs b/src/System.Private.CoreLib/shared/System/Collections/IStructuralEquatable.cs index 1784da5..9fba683 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/IStructuralEquatable.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/IStructuralEquatable.cs @@ -2,11 +2,12 @@ // 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 namespace System.Collections { public interface IStructuralEquatable { - bool Equals(object other, IEqualityComparer comparer); + bool Equals(object? other, IEqualityComparer comparer); int GetHashCode(IEqualityComparer comparer); } } diff --git a/src/System.Private.CoreLib/shared/System/Convert.Base64.cs b/src/System.Private.CoreLib/shared/System/Convert.Base64.cs index 332f3b9..aef0cde 100644 --- a/src/System.Private.CoreLib/shared/System/Convert.Base64.cs +++ b/src/System.Private.CoreLib/shared/System/Convert.Base64.cs @@ -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.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/System.Private.CoreLib/shared/System/Convert.cs b/src/System.Private.CoreLib/shared/System/Convert.cs index 2bc0179..03b1bcc 100644 --- a/src/System.Private.CoreLib/shared/System/Convert.cs +++ b/src/System.Private.CoreLib/shared/System/Convert.cs @@ -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; using System.Globalization; using System.Threading; @@ -157,7 +158,7 @@ namespace System // the object does not implement IConvertible), the result is TypeCode.Object. // Otherwise, the result is the type code of the object, as determined by // the object's implementation of IConvertible. - public static TypeCode GetTypeCode(object value) + public static TypeCode GetTypeCode(object? value) { if (value == null) return TypeCode.Empty; if (value is IConvertible temp) @@ -169,7 +170,7 @@ namespace System // Returns true if the given object is a database null. This operation // corresponds to "value.GetTypeCode() == TypeCode.DBNull". - public static bool IsDBNull(object value) + public static bool IsDBNull(object? value) { if (value == System.DBNull.Value) return true; return value is IConvertible convertible ? convertible.GetTypeCode() == TypeCode.DBNull : false; @@ -187,12 +188,12 @@ namespace System // object already has the given type code, in which case the object is // simply returned. Otherwise, the appropriate ToXXX() is invoked on the // object's implementation of IConvertible. - public static object ChangeType(object value, TypeCode typeCode) + public static object? ChangeType(object? value, TypeCode typeCode) { return ChangeType(value, typeCode, CultureInfo.CurrentCulture); } - public static object ChangeType(object value, TypeCode typeCode, IFormatProvider provider) + public static object? ChangeType(object? value, TypeCode typeCode, IFormatProvider? provider) { if (value == null && (typeCode == TypeCode.Empty || typeCode == TypeCode.String || typeCode == TypeCode.Object)) { @@ -250,7 +251,7 @@ namespace System } } - internal static object DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) + internal static object DefaultToType(IConvertible value, Type targetType, IFormatProvider? provider) { Debug.Assert(value != null, "[Convert.DefaultToType]value!=null"); if (targetType == null) @@ -306,12 +307,12 @@ namespace System throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, value.GetType().FullName, targetType.FullName)); } - public static object ChangeType(object value, Type conversionType) + public static object? ChangeType(object? value, Type conversionType) { return ChangeType(value, conversionType, CultureInfo.CurrentCulture); } - public static object ChangeType(object value, Type conversionType, IFormatProvider provider) + public static object? ChangeType(object? value, Type conversionType, IFormatProvider? provider) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { if (conversionType is null) { @@ -391,12 +392,12 @@ namespace System private static void ThrowUInt64OverflowException() { throw new OverflowException(SR.Overflow_UInt64); } // Conversions to Boolean - public static bool ToBoolean(object value) + public static bool ToBoolean(object? value) { return value == null ? false : ((IConvertible)value).ToBoolean(null); } - public static bool ToBoolean(object value, IFormatProvider provider) + public static bool ToBoolean(object? value, IFormatProvider? provider) { return value == null ? false : ((IConvertible)value).ToBoolean(provider); } @@ -459,14 +460,14 @@ namespace System return value != 0; } - public static bool ToBoolean(string value) + public static bool ToBoolean(string? value) { if (value == null) return false; return bool.Parse(value); } - public static bool ToBoolean(string value, IFormatProvider provider) + public static bool ToBoolean(string? value, IFormatProvider? provider) { if (value == null) return false; @@ -499,12 +500,12 @@ namespace System // Conversions to Char - public static char ToChar(object value) + public static char ToChar(object? value) { return value == null ? (char)0 : ((IConvertible)value).ToChar(null); } - public static char ToChar(object value, IFormatProvider provider) + public static char ToChar(object? value, IFormatProvider? provider) { return value == null ? (char)0 : ((IConvertible)value).ToChar(provider); } @@ -578,7 +579,7 @@ namespace System return ToChar(value, null); } - public static char ToChar(string value, IFormatProvider provider) + public static char ToChar(string value, IFormatProvider? provider) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -622,13 +623,13 @@ namespace System // Conversions to SByte [CLSCompliant(false)] - public static sbyte ToSByte(object value) + public static sbyte ToSByte(object? value) { return value == null ? (sbyte)0 : ((IConvertible)value).ToSByte(null); } [CLSCompliant(false)] - public static sbyte ToSByte(object value, IFormatProvider provider) + public static sbyte ToSByte(object? value, IFormatProvider? provider) { return value == null ? (sbyte)0 : ((IConvertible)value).ToSByte(provider); } @@ -720,7 +721,7 @@ namespace System } [CLSCompliant(false)] - public static sbyte ToSByte(string value) + public static sbyte ToSByte(string? value) { if (value == null) return 0; @@ -728,7 +729,7 @@ namespace System } [CLSCompliant(false)] - public static sbyte ToSByte(string value, IFormatProvider provider) + public static sbyte ToSByte(string value, IFormatProvider? provider) { return sbyte.Parse(value, NumberStyles.Integer, provider); } @@ -744,12 +745,12 @@ namespace System // Conversions to Byte - public static byte ToByte(object value) + public static byte ToByte(object? value) { return value == null ? (byte)0 : ((IConvertible)value).ToByte(null); } - public static byte ToByte(object value, IFormatProvider provider) + public static byte ToByte(object? value, IFormatProvider? provider) { return value == null ? (byte)0 : ((IConvertible)value).ToByte(provider); } @@ -831,14 +832,14 @@ namespace System return decimal.ToByte(decimal.Round(value, 0)); } - public static byte ToByte(string value) + public static byte ToByte(string? value) { if (value == null) return 0; return byte.Parse(value, CultureInfo.CurrentCulture); } - public static byte ToByte(string value, IFormatProvider provider) + public static byte ToByte(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -856,12 +857,12 @@ namespace System // Conversions to Int16 - public static short ToInt16(object value) + public static short ToInt16(object? value) { return value == null ? (short)0 : ((IConvertible)value).ToInt16(null); } - public static short ToInt16(object value, IFormatProvider provider) + public static short ToInt16(object? value, IFormatProvider? provider) { return value == null ? (short)0 : ((IConvertible)value).ToInt16(provider); } @@ -941,14 +942,14 @@ namespace System return decimal.ToInt16(decimal.Round(value, 0)); } - public static short ToInt16(string value) + public static short ToInt16(string? value) { if (value == null) return 0; return short.Parse(value, CultureInfo.CurrentCulture); } - public static short ToInt16(string value, IFormatProvider provider) + public static short ToInt16(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -967,13 +968,13 @@ namespace System // Conversions to UInt16 [CLSCompliant(false)] - public static ushort ToUInt16(object value) + public static ushort ToUInt16(object? value) { return value == null ? (ushort)0 : ((IConvertible)value).ToUInt16(null); } [CLSCompliant(false)] - public static ushort ToUInt16(object value, IFormatProvider provider) + public static ushort ToUInt16(object? value, IFormatProvider? provider) { return value == null ? (ushort)0 : ((IConvertible)value).ToUInt16(provider); } @@ -1065,7 +1066,7 @@ namespace System } [CLSCompliant(false)] - public static ushort ToUInt16(string value) + public static ushort ToUInt16(string? value) { if (value == null) return 0; @@ -1073,7 +1074,7 @@ namespace System } [CLSCompliant(false)] - public static ushort ToUInt16(string value, IFormatProvider provider) + public static ushort ToUInt16(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -1091,12 +1092,12 @@ namespace System // Conversions to Int32 - public static int ToInt32(object value) + public static int ToInt32(object? value) { return value == null ? 0 : ((IConvertible)value).ToInt32(null); } - public static int ToInt32(object value, IFormatProvider provider) + public static int ToInt32(object? value, IFormatProvider? provider) { return value == null ? 0 : ((IConvertible)value).ToInt32(provider); } @@ -1194,14 +1195,14 @@ namespace System return decimal.ToInt32(decimal.Round(value, 0)); } - public static int ToInt32(string value) + public static int ToInt32(string? value) { if (value == null) return 0; return int.Parse(value, CultureInfo.CurrentCulture); } - public static int ToInt32(string value, IFormatProvider provider) + public static int ToInt32(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -1220,13 +1221,13 @@ namespace System // Conversions to UInt32 [CLSCompliant(false)] - public static uint ToUInt32(object value) + public static uint ToUInt32(object? value) { return value == null ? 0 : ((IConvertible)value).ToUInt32(null); } [CLSCompliant(false)] - public static uint ToUInt32(object value, IFormatProvider provider) + public static uint ToUInt32(object? value, IFormatProvider? provider) { return value == null ? 0 : ((IConvertible)value).ToUInt32(provider); } @@ -1323,7 +1324,7 @@ namespace System } [CLSCompliant(false)] - public static uint ToUInt32(string value) + public static uint ToUInt32(string? value) { if (value == null) return 0; @@ -1331,7 +1332,7 @@ namespace System } [CLSCompliant(false)] - public static uint ToUInt32(string value, IFormatProvider provider) + public static uint ToUInt32(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -1349,12 +1350,12 @@ namespace System // Conversions to Int64 - public static long ToInt64(object value) + public static long ToInt64(object? value) { return value == null ? 0 : ((IConvertible)value).ToInt64(null); } - public static long ToInt64(object value, IFormatProvider provider) + public static long ToInt64(object? value, IFormatProvider? provider) { return value == null ? 0 : ((IConvertible)value).ToInt64(provider); } @@ -1431,14 +1432,14 @@ namespace System return decimal.ToInt64(decimal.Round(value, 0)); } - public static long ToInt64(string value) + public static long ToInt64(string? value) { if (value == null) return 0; return long.Parse(value, CultureInfo.CurrentCulture); } - public static long ToInt64(string value, IFormatProvider provider) + public static long ToInt64(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -1456,13 +1457,13 @@ namespace System // Conversions to UInt64 [CLSCompliant(false)] - public static ulong ToUInt64(object value) + public static ulong ToUInt64(object? value) { return value == null ? 0 : ((IConvertible)value).ToUInt64(null); } [CLSCompliant(false)] - public static ulong ToUInt64(object value, IFormatProvider provider) + public static ulong ToUInt64(object? value, IFormatProvider? provider) { return value == null ? 0 : ((IConvertible)value).ToUInt64(provider); } @@ -1551,7 +1552,7 @@ namespace System } [CLSCompliant(false)] - public static ulong ToUInt64(string value) + public static ulong ToUInt64(string? value) { if (value == null) return 0; @@ -1559,7 +1560,7 @@ namespace System } [CLSCompliant(false)] - public static ulong ToUInt64(string value, IFormatProvider provider) + public static ulong ToUInt64(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -1577,12 +1578,12 @@ namespace System // Conversions to Single - public static float ToSingle(object value) + public static float ToSingle(object? value) { return value == null ? 0 : ((IConvertible)value).ToSingle(null); } - public static float ToSingle(object value, IFormatProvider provider) + public static float ToSingle(object? value, IFormatProvider? provider) { return value == null ? 0 : ((IConvertible)value).ToSingle(provider); } @@ -1651,14 +1652,14 @@ namespace System return (float)value; } - public static float ToSingle(string value) + public static float ToSingle(string? value) { if (value == null) return 0; return float.Parse(value, CultureInfo.CurrentCulture); } - public static float ToSingle(string value, IFormatProvider provider) + public static float ToSingle(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -1681,12 +1682,12 @@ namespace System // Conversions to Double - public static double ToDouble(object value) + public static double ToDouble(object? value) { return value == null ? 0 : ((IConvertible)value).ToDouble(null); } - public static double ToDouble(object value, IFormatProvider provider) + public static double ToDouble(object? value, IFormatProvider? provider) { return value == null ? 0 : ((IConvertible)value).ToDouble(provider); } @@ -1756,14 +1757,14 @@ namespace System return (double)value; } - public static double ToDouble(string value) + public static double ToDouble(string? value) { if (value == null) return 0; return double.Parse(value, CultureInfo.CurrentCulture); } - public static double ToDouble(string value, IFormatProvider provider) + public static double ToDouble(string? value, IFormatProvider? provider) { if (value == null) return 0; @@ -1785,12 +1786,12 @@ namespace System // Conversions to Decimal - public static decimal ToDecimal(object value) + public static decimal ToDecimal(object? value) { return value == null ? 0 : ((IConvertible)value).ToDecimal(null); } - public static decimal ToDecimal(object value, IFormatProvider provider) + public static decimal ToDecimal(object? value, IFormatProvider? provider) { return value == null ? 0 : ((IConvertible)value).ToDecimal(provider); } @@ -1854,14 +1855,14 @@ namespace System return (decimal)value; } - public static decimal ToDecimal(string value) + public static decimal ToDecimal(string? value) { if (value == null) return 0m; return decimal.Parse(value, CultureInfo.CurrentCulture); } - public static decimal ToDecimal(string value, IFormatProvider provider) + public static decimal ToDecimal(string? value, IFormatProvider? provider) { if (value == null) return 0m; @@ -1893,24 +1894,24 @@ namespace System return value; } - public static DateTime ToDateTime(object value) + public static DateTime ToDateTime(object? value) { return value == null ? DateTime.MinValue : ((IConvertible)value).ToDateTime(null); } - public static DateTime ToDateTime(object value, IFormatProvider provider) + public static DateTime ToDateTime(object? value, IFormatProvider? provider) { return value == null ? DateTime.MinValue : ((IConvertible)value).ToDateTime(provider); } - public static DateTime ToDateTime(string value) + public static DateTime ToDateTime(string? value) { if (value == null) return new DateTime(0); return DateTime.Parse(value, CultureInfo.CurrentCulture); } - public static DateTime ToDateTime(string value, IFormatProvider provider) + public static DateTime ToDateTime(string? value, IFormatProvider? provider) { if (value == null) return new DateTime(0); @@ -1991,12 +1992,12 @@ namespace System // Conversions to String - public static string ToString(object value) + public static string? ToString(object? value) { return ToString(value, null); } - public static string ToString(object value, IFormatProvider provider) + public static string? ToString(object? value, IFormatProvider? provider) { if (value is IConvertible ic) return ic.ToString(provider); @@ -2010,7 +2011,7 @@ namespace System return value.ToString(); } - public static string ToString(bool value, IFormatProvider provider) + public static string ToString(bool value, IFormatProvider? provider) { return value.ToString(); } @@ -2020,7 +2021,7 @@ namespace System return char.ToString(value); } - public static string ToString(char value, IFormatProvider provider) + public static string ToString(char value, IFormatProvider? provider) { return value.ToString(); } @@ -2032,7 +2033,7 @@ namespace System } [CLSCompliant(false)] - public static string ToString(sbyte value, IFormatProvider provider) + public static string ToString(sbyte value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2042,7 +2043,7 @@ namespace System return value.ToString(CultureInfo.CurrentCulture); } - public static string ToString(byte value, IFormatProvider provider) + public static string ToString(byte value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2052,7 +2053,7 @@ namespace System return value.ToString(CultureInfo.CurrentCulture); } - public static string ToString(short value, IFormatProvider provider) + public static string ToString(short value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2064,7 +2065,7 @@ namespace System } [CLSCompliant(false)] - public static string ToString(ushort value, IFormatProvider provider) + public static string ToString(ushort value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2074,7 +2075,7 @@ namespace System return value.ToString(CultureInfo.CurrentCulture); } - public static string ToString(int value, IFormatProvider provider) + public static string ToString(int value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2086,7 +2087,7 @@ namespace System } [CLSCompliant(false)] - public static string ToString(uint value, IFormatProvider provider) + public static string ToString(uint value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2096,7 +2097,7 @@ namespace System return value.ToString(CultureInfo.CurrentCulture); } - public static string ToString(long value, IFormatProvider provider) + public static string ToString(long value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2108,7 +2109,7 @@ namespace System } [CLSCompliant(false)] - public static string ToString(ulong value, IFormatProvider provider) + public static string ToString(ulong value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2118,7 +2119,7 @@ namespace System return value.ToString(CultureInfo.CurrentCulture); } - public static string ToString(float value, IFormatProvider provider) + public static string ToString(float value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2128,7 +2129,7 @@ namespace System return value.ToString(CultureInfo.CurrentCulture); } - public static string ToString(double value, IFormatProvider provider) + public static string ToString(double value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2138,7 +2139,7 @@ namespace System return value.ToString(CultureInfo.CurrentCulture); } - public static string ToString(decimal value, IFormatProvider provider) + public static string ToString(decimal value, IFormatProvider? provider) { return value.ToString(provider); } @@ -2148,17 +2149,17 @@ namespace System return value.ToString(); } - public static string ToString(DateTime value, IFormatProvider provider) + public static string ToString(DateTime value, IFormatProvider? provider) { return value.ToString(provider); } - public static string ToString(string value) + public static string? ToString(string? value) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return value; } - public static string ToString(string value, IFormatProvider provider) + public static string? ToString(string? value, IFormatProvider? provider) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return value; // avoid the null check } @@ -2171,7 +2172,7 @@ namespace System // be 2, 8, 10, or 16. If base is 16, the number may be preceded // by 0x; any other leading or trailing characters cause an error. // - public static byte ToByte(string value, int fromBase) + public static byte ToByte(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { @@ -2194,7 +2195,7 @@ namespace System // by 0x; any other leading or trailing characters cause an error. // [CLSCompliant(false)] - public static sbyte ToSByte(string value, int fromBase) + public static sbyte ToSByte(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { @@ -2219,7 +2220,7 @@ namespace System // be 2, 8, 10, or 16. If fromBase is 16, the number may be preceded // by 0x; any other leading or trailing characters cause an error. // - public static short ToInt16(string value, int fromBase) + public static short ToInt16(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { @@ -2245,7 +2246,7 @@ namespace System // by 0x; any other leading or trailing characters cause an error. // [CLSCompliant(false)] - public static ushort ToUInt16(string value, int fromBase) + public static ushort ToUInt16(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { @@ -2267,7 +2268,7 @@ namespace System // be 2, 8, 10, or 16. If fromBase is 16, the number may be preceded // by 0x; any other leading or trailing characters cause an error. // - public static int ToInt32(string value, int fromBase) + public static int ToInt32(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { @@ -2283,7 +2284,7 @@ namespace System // by 0x; any other leading or trailing characters cause an error. // [CLSCompliant(false)] - public static uint ToUInt32(string value, int fromBase) + public static uint ToUInt32(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { @@ -2298,7 +2299,7 @@ namespace System // be 2, 8, 10, or 16. If fromBase is 16, the number may be preceded // by 0x; any other leading or trailing characters cause an error. // - public static long ToInt64(string value, int fromBase) + public static long ToInt64(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { @@ -2314,7 +2315,7 @@ namespace System // by 0x; any other leading or trailing characters cause an error. // [CLSCompliant(false)] - public static ulong ToUInt64(string value, int fromBase) + public static ulong ToUInt64(string? value, int fromBase) { if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16) { diff --git a/src/System.Private.CoreLib/shared/System/CoreLib.cs b/src/System.Private.CoreLib/shared/System/CoreLib.cs index 9c5d1c1..9e18412 100644 --- a/src/System.Private.CoreLib/shared/System/CoreLib.cs +++ b/src/System.Private.CoreLib/shared/System/CoreLib.cs @@ -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 namespace System { // This class is used to define the name of the base class library diff --git a/src/System.Private.CoreLib/shared/System/CurrentSystemTimeZone.cs b/src/System.Private.CoreLib/shared/System/CurrentSystemTimeZone.cs index 207da21..5b5fdd6 100644 --- a/src/System.Private.CoreLib/shared/System/CurrentSystemTimeZone.cs +++ b/src/System.Private.CoreLib/shared/System/CurrentSystemTimeZone.cs @@ -17,6 +17,7 @@ ** ============================================================*/ +#nullable enable using System.Collections; using System.Globalization; @@ -148,7 +149,7 @@ namespace System private static DaylightTime CreateDaylightChanges(int year) { - DaylightTime currentDaylightChanges = null; + DaylightTime? currentDaylightChanges = null; if (TimeZoneInfo.Local.SupportsDaylightSavingTime) { diff --git a/src/System.Private.CoreLib/shared/System/DBNull.cs b/src/System.Private.CoreLib/shared/System/DBNull.cs index 3cee2b1..5d2a12e 100644 --- a/src/System.Private.CoreLib/shared/System/DBNull.cs +++ b/src/System.Private.CoreLib/shared/System/DBNull.cs @@ -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.Runtime.Serialization; namespace System @@ -30,7 +31,7 @@ namespace System return string.Empty; } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { return string.Empty; } @@ -40,77 +41,77 @@ namespace System return TypeCode.DBNull; } - bool IConvertible.ToBoolean(IFormatProvider provider) + bool IConvertible.ToBoolean(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - char IConvertible.ToChar(IFormatProvider provider) + char IConvertible.ToChar(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - sbyte IConvertible.ToSByte(IFormatProvider provider) + sbyte IConvertible.ToSByte(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - byte IConvertible.ToByte(IFormatProvider provider) + byte IConvertible.ToByte(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - short IConvertible.ToInt16(IFormatProvider provider) + short IConvertible.ToInt16(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - ushort IConvertible.ToUInt16(IFormatProvider provider) + ushort IConvertible.ToUInt16(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - int IConvertible.ToInt32(IFormatProvider provider) + int IConvertible.ToInt32(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - uint IConvertible.ToUInt32(IFormatProvider provider) + uint IConvertible.ToUInt32(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - long IConvertible.ToInt64(IFormatProvider provider) + long IConvertible.ToInt64(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - ulong IConvertible.ToUInt64(IFormatProvider provider) + ulong IConvertible.ToUInt64(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - float IConvertible.ToSingle(IFormatProvider provider) + float IConvertible.ToSingle(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - double IConvertible.ToDouble(IFormatProvider provider) + double IConvertible.ToDouble(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - decimal IConvertible.ToDecimal(IFormatProvider provider) + decimal IConvertible.ToDecimal(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - DateTime IConvertible.ToDateTime(IFormatProvider provider) + DateTime IConvertible.ToDateTime(IFormatProvider? provider) { throw new InvalidCastException(SR.InvalidCast_FromDBNull); } - object IConvertible.ToType(Type type, IFormatProvider provider) + object IConvertible.ToType(Type type, IFormatProvider? provider) { return Convert.DefaultToType((IConvertible)this, type, provider); } diff --git a/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs b/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs index 6cf0181..f5d1a8f 100644 --- a/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs @@ -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 namespace System { public readonly partial struct DateTime diff --git a/src/System.Private.CoreLib/shared/System/DateTime.cs b/src/System.Private.CoreLib/shared/System/DateTime.cs index a94171f..deb2da2 100644 --- a/src/System.Private.CoreLib/shared/System/DateTime.cs +++ b/src/System.Private.CoreLib/shared/System/DateTime.cs @@ -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; using System.Diagnostics; using System.Threading; @@ -623,7 +624,7 @@ namespace System // occurs. Null is considered less than any instance. // // Returns a value less than zero if this object - public int CompareTo(object value) + public int CompareTo(object? value) { if (value == null) return 1; if (!(value is DateTime)) @@ -709,7 +710,7 @@ namespace System // is equal to the value of this DateTime. Returns false // otherwise. // - public override bool Equals(object value) + public override bool Equals(object? value) { if (value is DateTime) { @@ -1205,20 +1206,20 @@ namespace System // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTime Parse(string s, IFormatProvider provider) + public static DateTime Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None)); } - public static DateTime Parse(string s, IFormatProvider provider, DateTimeStyles styles) + public static DateTime Parse(string s, IFormatProvider? provider, DateTimeStyles styles) { DateTimeFormatInfo.ValidateStyles(styles, nameof(styles)); if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles)); } - public static DateTime Parse(ReadOnlySpan s, IFormatProvider provider = null, DateTimeStyles styles = DateTimeStyles.None) + public static DateTime Parse(ReadOnlySpan s, IFormatProvider? provider = null, DateTimeStyles styles = DateTimeStyles.None) { DateTimeFormatInfo.ValidateStyles(styles, nameof(styles)); return DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles); @@ -1228,7 +1229,7 @@ namespace System // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTime ParseExact(string s, string format, IFormatProvider provider) + public static DateTime ParseExact(string s, string format, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format); @@ -1239,7 +1240,7 @@ namespace System // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTime ParseExact(string s, string format, IFormatProvider provider, DateTimeStyles style) + public static DateTime ParseExact(string s, string format, IFormatProvider? provider, DateTimeStyles style) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); @@ -1247,20 +1248,20 @@ namespace System return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style)); } - public static DateTime ParseExact(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None) + public static DateTime ParseExact(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style = DateTimeStyles.None) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); return DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style); } - public static DateTime ParseExact(string s, string[] formats, IFormatProvider provider, DateTimeStyles style) + public static DateTime ParseExact(string s, string[] formats, IFormatProvider? provider, DateTimeStyles style) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style); } - public static DateTime ParseExact(ReadOnlySpan s, string[] formats, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None) + public static DateTime ParseExact(ReadOnlySpan s, string[] formats, IFormatProvider? provider, DateTimeStyles style = DateTimeStyles.None) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style); @@ -1393,22 +1394,22 @@ namespace System return DateTimeFormat.Format(this, null, null); } - public string ToString(string format) + public string ToString(string? format) { return DateTimeFormat.Format(this, format, null); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { return DateTimeFormat.Format(this, null, provider); } - public string ToString(string format, IFormatProvider provider) + public string ToString(string? format, IFormatProvider? provider) { return DateTimeFormat.Format(this, format, provider); } - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider provider = null) => + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) => DateTimeFormat.TryFormat(this, destination, out charsWritten, format, provider); public DateTime ToUniversalTime() @@ -1416,7 +1417,7 @@ namespace System return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime); } - public static bool TryParse(string s, out DateTime result) + public static bool TryParse(string? s, out DateTime result) { if (s == null) { @@ -1431,7 +1432,7 @@ namespace System return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result); } - public static bool TryParse(string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result) + public static bool TryParse(string? s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result) { DateTimeFormatInfo.ValidateStyles(styles, nameof(styles)); @@ -1444,13 +1445,13 @@ namespace System return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result); } - public static bool TryParse(ReadOnlySpan s, IFormatProvider provider, DateTimeStyles styles, out DateTime result) + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result) { DateTimeFormatInfo.ValidateStyles(styles, nameof(styles)); return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result); } - public static bool TryParseExact(string s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(string? s, string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); @@ -1463,13 +1464,13 @@ namespace System return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(string s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(string? s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); @@ -1482,7 +1483,7 @@ namespace System return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(ReadOnlySpan s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(ReadOnlySpan s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); @@ -1557,7 +1558,7 @@ namespace System // Returns a string array containing all of the known date and time options for the // using the information provided by IFormatProvider. The strings returned are properly formatted date and // time strings for the current instance of DateTime. - public string[] GetDateTimeFormats(IFormatProvider provider) + public string[] GetDateTimeFormats(IFormatProvider? provider) { return (DateTimeFormat.GetAllDateTimes(this, DateTimeFormatInfo.GetInstance(provider))); } @@ -1574,7 +1575,7 @@ namespace System // Returns a string array containing all of the date and time options for the // given format format and given culture. The strings returned are properly formatted date and // time strings for the current instance of DateTime. - public string[] GetDateTimeFormats(char format, IFormatProvider provider) + public string[] GetDateTimeFormats(char format, IFormatProvider? provider) { return (DateTimeFormat.GetAllDateTimes(this, format, DateTimeFormatInfo.GetInstance(provider))); } @@ -1589,77 +1590,77 @@ namespace System } - bool IConvertible.ToBoolean(IFormatProvider provider) + bool IConvertible.ToBoolean(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Boolean")); } - char IConvertible.ToChar(IFormatProvider provider) + char IConvertible.ToChar(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Char")); } - sbyte IConvertible.ToSByte(IFormatProvider provider) + sbyte IConvertible.ToSByte(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "SByte")); } - byte IConvertible.ToByte(IFormatProvider provider) + byte IConvertible.ToByte(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Byte")); } - short IConvertible.ToInt16(IFormatProvider provider) + short IConvertible.ToInt16(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Int16")); } - ushort IConvertible.ToUInt16(IFormatProvider provider) + ushort IConvertible.ToUInt16(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "UInt16")); } - int IConvertible.ToInt32(IFormatProvider provider) + int IConvertible.ToInt32(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Int32")); } - uint IConvertible.ToUInt32(IFormatProvider provider) + uint IConvertible.ToUInt32(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "UInt32")); } - long IConvertible.ToInt64(IFormatProvider provider) + long IConvertible.ToInt64(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Int64")); } - ulong IConvertible.ToUInt64(IFormatProvider provider) + ulong IConvertible.ToUInt64(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "UInt64")); } - float IConvertible.ToSingle(IFormatProvider provider) + float IConvertible.ToSingle(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Single")); } - double IConvertible.ToDouble(IFormatProvider provider) + double IConvertible.ToDouble(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Double")); } - decimal IConvertible.ToDecimal(IFormatProvider provider) + decimal IConvertible.ToDecimal(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Decimal")); } - DateTime IConvertible.ToDateTime(IFormatProvider provider) + DateTime IConvertible.ToDateTime(IFormatProvider? provider) { return this; } - object IConvertible.ToType(Type type, IFormatProvider provider) + object IConvertible.ToType(Type type, IFormatProvider? provider) { return Convert.DefaultToType((IConvertible)this, type, provider); } diff --git a/src/System.Private.CoreLib/shared/System/DateTimeKind.cs b/src/System.Private.CoreLib/shared/System/DateTimeKind.cs index 33c9bd9..1f2ce00 100644 --- a/src/System.Private.CoreLib/shared/System/DateTimeKind.cs +++ b/src/System.Private.CoreLib/shared/System/DateTimeKind.cs @@ -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 namespace System { // This enum is used to indentify DateTime instances in cases when they are known to be in local time, diff --git a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs index 6fc5dfc..4052d55 100644 --- a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs +++ b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs @@ -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.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; @@ -489,7 +490,7 @@ namespace System // argument must be another DateTimeOffset, or otherwise an exception // occurs. Null is considered less than any instance. // - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { if (obj == null) return 1; if (!(obj is DateTimeOffset)) @@ -519,7 +520,7 @@ namespace System // is equal to the value of this DateTimeOffset. Returns false // otherwise. // - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is DateTimeOffset) { @@ -655,13 +656,13 @@ namespace System // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTimeOffset Parse(string input, IFormatProvider formatProvider) + public static DateTimeOffset Parse(string input, IFormatProvider? formatProvider) { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); - return Parse(input, formatProvider, DateTimeStyles.None); + return Parse(input!, formatProvider, DateTimeStyles.None); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } - public static DateTimeOffset Parse(string input, IFormatProvider formatProvider, DateTimeStyles styles) + public static DateTimeOffset Parse(string input, IFormatProvider? formatProvider, DateTimeStyles styles) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); @@ -674,7 +675,7 @@ namespace System return new DateTimeOffset(dateResult.Ticks, offset); } - public static DateTimeOffset Parse(ReadOnlySpan input, IFormatProvider formatProvider = null, DateTimeStyles styles = DateTimeStyles.None) + public static DateTimeOffset Parse(ReadOnlySpan input, IFormatProvider? formatProvider = null, DateTimeStyles styles = DateTimeStyles.None) { styles = ValidateStyles(styles, nameof(styles)); DateTime dateResult = DateTimeParse.Parse(input, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset); @@ -685,18 +686,18 @@ namespace System // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTimeOffset ParseExact(string input, string format, IFormatProvider formatProvider) + public static DateTimeOffset ParseExact(string input, string format, IFormatProvider? formatProvider) { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format); - return ParseExact(input, format, formatProvider, DateTimeStyles.None); + return ParseExact(input!, format!, formatProvider, DateTimeStyles.None); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // Constructs a DateTimeOffset from a string. The string must specify a // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTimeOffset ParseExact(string input, string format, IFormatProvider formatProvider, DateTimeStyles styles) + public static DateTimeOffset ParseExact(string input, string format, IFormatProvider? formatProvider, DateTimeStyles styles) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); @@ -711,14 +712,14 @@ namespace System return new DateTimeOffset(dateResult.Ticks, offset); } - public static DateTimeOffset ParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider formatProvider, DateTimeStyles styles = DateTimeStyles.None) + public static DateTimeOffset ParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider? formatProvider, DateTimeStyles styles = DateTimeStyles.None) { styles = ValidateStyles(styles, nameof(styles)); DateTime dateResult = DateTimeParse.ParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset); return new DateTimeOffset(dateResult.Ticks, offset); } - public static DateTimeOffset ParseExact(string input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles) + public static DateTimeOffset ParseExact(string input, string[] formats, IFormatProvider? formatProvider, DateTimeStyles styles) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); @@ -732,7 +733,7 @@ namespace System return new DateTimeOffset(dateResult.Ticks, offset); } - public static DateTimeOffset ParseExact(ReadOnlySpan input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles = DateTimeStyles.None) + public static DateTimeOffset ParseExact(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, DateTimeStyles styles = DateTimeStyles.None) { styles = ValidateStyles(styles, nameof(styles)); DateTime dateResult = DateTimeParse.ParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset); @@ -800,22 +801,22 @@ namespace System return DateTimeFormat.Format(ClockDateTime, null, null, Offset); } - public string ToString(string format) + public string ToString(string? format) { return DateTimeFormat.Format(ClockDateTime, format, null, Offset); } - public string ToString(IFormatProvider formatProvider) + public string ToString(IFormatProvider? formatProvider) { return DateTimeFormat.Format(ClockDateTime, null, formatProvider, Offset); } - public string ToString(string format, IFormatProvider formatProvider) + public string ToString(string? format, IFormatProvider? formatProvider) { return DateTimeFormat.Format(ClockDateTime, format, formatProvider, Offset); } - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider formatProvider = null) => + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? formatProvider = null) => DateTimeFormat.TryFormat(ClockDateTime, destination, out charsWritten, format, formatProvider, Offset); public DateTimeOffset ToUniversalTime() @@ -823,7 +824,7 @@ namespace System return new DateTimeOffset(UtcDateTime); } - public static bool TryParse(string input, out DateTimeOffset result) + public static bool TryParse(string? input, out DateTimeOffset result) { TimeSpan offset; DateTime dateResult; @@ -843,7 +844,7 @@ namespace System return parsed; } - public static bool TryParse(string input, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result) + public static bool TryParse(string? input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) @@ -863,7 +864,7 @@ namespace System return parsed; } - public static bool TryParse(ReadOnlySpan input, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result) + public static bool TryParse(ReadOnlySpan input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); bool parsed = DateTimeParse.TryParse(input, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset); @@ -871,7 +872,7 @@ namespace System return parsed; } - public static bool TryParseExact(string input, string format, IFormatProvider formatProvider, DateTimeStyles styles, + public static bool TryParseExact(string? input, string? format, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -894,7 +895,7 @@ namespace System } public static bool TryParseExact( - ReadOnlySpan input, ReadOnlySpan format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result) + ReadOnlySpan input, ReadOnlySpan format, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); bool parsed = DateTimeParse.TryParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset); @@ -902,7 +903,7 @@ namespace System return parsed; } - public static bool TryParseExact(string input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles, + public static bool TryParseExact(string? input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -925,7 +926,7 @@ namespace System } public static bool TryParseExact( - ReadOnlySpan input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result) + ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); bool parsed = DateTimeParse.TryParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset); diff --git a/src/System.Private.CoreLib/shared/System/DayOfWeek.cs b/src/System.Private.CoreLib/shared/System/DayOfWeek.cs index f67d10e..19cb69a 100644 --- a/src/System.Private.CoreLib/shared/System/DayOfWeek.cs +++ b/src/System.Private.CoreLib/shared/System/DayOfWeek.cs @@ -11,6 +11,7 @@ ** ============================================================*/ +#nullable enable namespace System { public enum DayOfWeek diff --git a/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs b/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs index 342aec9..04eb9aa 100644 --- a/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs +++ b/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs @@ -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.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/shared/System/Decimal.cs b/src/System.Private.CoreLib/shared/System/Decimal.cs index eb8c4cd..6f2a0a1 100644 --- a/src/System.Private.CoreLib/shared/System/Decimal.cs +++ b/src/System.Private.CoreLib/shared/System/Decimal.cs @@ -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.Buffers.Binary; using System.Diagnostics; using System.Globalization; @@ -345,7 +346,7 @@ namespace System // null is considered to be less than any instance. // If object is not of type Decimal, this method throws an ArgumentException. // - public int CompareTo(object value) + public int CompareTo(object? value) { if (value == null) return 1; @@ -373,7 +374,7 @@ namespace System // if the given object is a boxed Decimal and its value is equal to the // value of this Decimal. Returns false otherwise. // - public override bool Equals(object value) + public override bool Equals(object? value) { if (value is decimal) { @@ -421,22 +422,22 @@ namespace System return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo); } - public string ToString(string format) + public string ToString(string? format) { return Number.FormatDecimal(this, format, NumberFormatInfo.CurrentInfo); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { return Number.FormatDecimal(this, null, NumberFormatInfo.GetInstance(provider)); } - public string ToString(string format, IFormatProvider provider) + public string ToString(string? format, IFormatProvider? provider) { return Number.FormatDecimal(this, format, NumberFormatInfo.GetInstance(provider)); } - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider provider = null) + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) { return Number.TryFormatDecimal(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); } @@ -461,26 +462,26 @@ namespace System return Number.ParseDecimal(s, style, NumberFormatInfo.CurrentInfo); } - public static decimal Parse(string s, IFormatProvider provider) + public static decimal Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); } - public static decimal Parse(string s, NumberStyles style, IFormatProvider provider) + public static decimal Parse(string s, NumberStyles style, IFormatProvider? provider) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider)); } - public static decimal Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Number, IFormatProvider provider = null) + public static decimal Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Number, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string s, out decimal result) + public static bool TryParse(string? s, out decimal result) { if (s == null) { @@ -496,7 +497,7 @@ namespace System return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out decimal result) + public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out decimal result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); @@ -509,7 +510,7 @@ namespace System return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } - public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out decimal result) + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out decimal result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; @@ -1048,77 +1049,77 @@ namespace System return TypeCode.Decimal; } - bool IConvertible.ToBoolean(IFormatProvider provider) + bool IConvertible.ToBoolean(IFormatProvider? provider) { return Convert.ToBoolean(this); } - char IConvertible.ToChar(IFormatProvider provider) + char IConvertible.ToChar(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Decimal", "Char")); } - sbyte IConvertible.ToSByte(IFormatProvider provider) + sbyte IConvertible.ToSByte(IFormatProvider? provider) { return Convert.ToSByte(this); } - byte IConvertible.ToByte(IFormatProvider provider) + byte IConvertible.ToByte(IFormatProvider? provider) { return Convert.ToByte(this); } - short IConvertible.ToInt16(IFormatProvider provider) + short IConvertible.ToInt16(IFormatProvider? provider) { return Convert.ToInt16(this); } - ushort IConvertible.ToUInt16(IFormatProvider provider) + ushort IConvertible.ToUInt16(IFormatProvider? provider) { return Convert.ToUInt16(this); } - int IConvertible.ToInt32(IFormatProvider provider) + int IConvertible.ToInt32(IFormatProvider? provider) { return Convert.ToInt32(this); } - uint IConvertible.ToUInt32(IFormatProvider provider) + uint IConvertible.ToUInt32(IFormatProvider? provider) { return Convert.ToUInt32(this); } - long IConvertible.ToInt64(IFormatProvider provider) + long IConvertible.ToInt64(IFormatProvider? provider) { return Convert.ToInt64(this); } - ulong IConvertible.ToUInt64(IFormatProvider provider) + ulong IConvertible.ToUInt64(IFormatProvider? provider) { return Convert.ToUInt64(this); } - float IConvertible.ToSingle(IFormatProvider provider) + float IConvertible.ToSingle(IFormatProvider? provider) { return Convert.ToSingle(this); } - double IConvertible.ToDouble(IFormatProvider provider) + double IConvertible.ToDouble(IFormatProvider? provider) { return Convert.ToDouble(this); } - decimal IConvertible.ToDecimal(IFormatProvider provider) + decimal IConvertible.ToDecimal(IFormatProvider? provider) { return this; } - DateTime IConvertible.ToDateTime(IFormatProvider provider) + DateTime IConvertible.ToDateTime(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Decimal", "DateTime")); } - object IConvertible.ToType(Type type, IFormatProvider provider) + object IConvertible.ToType(Type type, IFormatProvider? provider) { return Convert.DefaultToType((IConvertible)this, type, provider); } diff --git a/src/System.Private.CoreLib/shared/System/Empty.cs b/src/System.Private.CoreLib/shared/System/Empty.cs index 186b920..64c54dc 100644 --- a/src/System.Private.CoreLib/shared/System/Empty.cs +++ b/src/System.Private.CoreLib/shared/System/Empty.cs @@ -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 namespace System { #if CORERT diff --git a/src/System.Private.CoreLib/shared/System/Enum.cs b/src/System.Private.CoreLib/shared/System/Enum.cs index 52ae290..2f6ea1e 100644 --- a/src/System.Private.CoreLib/shared/System/Enum.cs +++ b/src/System.Private.CoreLib/shared/System/Enum.cs @@ -664,7 +664,7 @@ namespace System Type underlyingType = GetUnderlyingType(enumType); try { - result = ToObject(enumType, Convert.ChangeType(value.ToString(), underlyingType, CultureInfo.InvariantCulture)); + result = ToObject(enumType, Convert.ChangeType(value.ToString(), underlyingType, CultureInfo.InvariantCulture)!); return true; } catch (FormatException) diff --git a/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs b/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs index 427d29d..4ba66bd 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs @@ -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.Diagnostics; using System.Collections; using Microsoft.Win32; @@ -12,9 +13,9 @@ namespace System { // Systems without the Windows registry pretend that it's always empty. - private static string GetEnvironmentVariableFromRegistry(string variable, bool fromMachine) => null; + private static string? GetEnvironmentVariableFromRegistry(string variable, bool fromMachine) => null; - private static void SetEnvironmentVariableFromRegistry(string variable, string value, bool fromMachine) { } + private static void SetEnvironmentVariableFromRegistry(string variable, string? value, bool fromMachine) { } private static IDictionary GetEnvironmentVariablesFromRegistry(bool fromMachine) => new Hashtable(); } diff --git a/src/System.Private.CoreLib/shared/System/Environment.SpecialFolder.cs b/src/System.Private.CoreLib/shared/System/Environment.SpecialFolder.cs index ae2add7..5e7d054 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.SpecialFolder.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.SpecialFolder.cs @@ -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 namespace System { public static partial class Environment diff --git a/src/System.Private.CoreLib/shared/System/Environment.SpecialFolderOption.cs b/src/System.Private.CoreLib/shared/System/Environment.SpecialFolderOption.cs index 929e3d9..05972a7 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.SpecialFolderOption.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.SpecialFolderOption.cs @@ -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 namespace System { public static partial class Environment diff --git a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs index 00b5029..e5a630b 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs @@ -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.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -15,7 +16,7 @@ namespace System { public static partial class Environment { - private static Func s_directoryCreateDirectory; + private static Func? s_directoryCreateDirectory; private static string CurrentDirectoryCore { @@ -34,7 +35,7 @@ namespace System if (name[lastPos] == '%') { string key = name.Substring(lastPos + 1, pos - lastPos - 1); - string value = GetEnvironmentVariable(key); + string? value = GetEnvironmentVariable(key); if (value != null) { result.Append(value); @@ -81,7 +82,7 @@ namespace System Type dirType = Type.GetType("System.IO.Directory, System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true); MethodInfo mi = dirType.GetTypeInfo().GetDeclaredMethod("CreateDirectory"); return (Func)mi.CreateDelegate(typeof(Func)); - }); + })!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 createDirectory(path); return path; @@ -104,7 +105,7 @@ namespace System // All other paths are based on the XDG Base Directory Specification: // https://specifications.freedesktop.org/basedir-spec/latest/ - string home = null; + string? home = null; try { home = PersistedFiles.GetHomeDirectory(); @@ -137,7 +138,7 @@ namespace System case SpecialFolder.LocalApplicationData: // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." - string data = GetEnvironmentVariable("XDG_DATA_HOME"); + string? data = GetEnvironmentVariable("XDG_DATA_HOME"); if (string.IsNullOrEmpty(data) || data[0] != '/') { data = Path.Combine(home, ".local", "share"); @@ -181,7 +182,7 @@ namespace System { // "$XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored." // "If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used." - string config = GetEnvironmentVariable("XDG_CONFIG_HOME"); + string? config = GetEnvironmentVariable("XDG_CONFIG_HOME"); if (string.IsNullOrEmpty(config) || config[0] != '/') { config = Path.Combine(home, ".config"); @@ -195,7 +196,7 @@ namespace System Debug.Assert(!string.IsNullOrEmpty(key), $"Expected non-empty key"); Debug.Assert(!string.IsNullOrEmpty(fallback), $"Expected non-empty fallback"); - string envPath = GetEnvironmentVariable(key); + string? envPath = GetEnvironmentVariable(key); if (!string.IsNullOrEmpty(envPath) && envPath[0] == '/') { return envPath; @@ -366,12 +367,12 @@ namespace System get { // First try with a buffer that should suffice for 99% of cases. - string username; + string? username; const int BufLen = Interop.Sys.Passwd.InitialBufferSize; byte* stackBuf = stackalloc byte[BufLen]; if (TryGetUserNameFromPasswd(stackBuf, BufLen, out username)) { - return username; + return username ?? string.Empty; } // Fallback to heap allocations if necessary, growing the buffer until @@ -385,7 +386,7 @@ namespace System { if (TryGetUserNameFromPasswd(buf, heapBuf.Length, out username)) { - return username; + return username ?? string.Empty; } } } @@ -393,7 +394,7 @@ namespace System } } - private static unsafe bool TryGetUserNameFromPasswd(byte* buf, int bufLen, out string path) + private static unsafe bool TryGetUserNameFromPasswd(byte* buf, int bufLen, out string? username) { // Call getpwuid_r to get the passwd struct Interop.Sys.Passwd passwd; @@ -403,15 +404,15 @@ namespace System if (error == 0) { Debug.Assert(passwd.Name != null); - path = Marshal.PtrToStringAnsi((IntPtr)passwd.Name); + username = Marshal.PtrToStringAnsi((IntPtr)passwd.Name); return true; } // If the current user's entry could not be found, give back null, - // but still return true as false indicates the buffer was too small. + // but still return true (false indicates the buffer was too small). if (error == -1) { - path = null; + username = null; return true; } @@ -421,7 +422,7 @@ namespace System // indicate the caller should try again with a larger buffer. if (errorInfo.Error == Interop.Error.ERANGE) { - path = null; + username = null; return false; } diff --git a/src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs b/src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs index 92be84b..c134102 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs @@ -2,18 +2,17 @@ // 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.Buffers; using System.Collections; -using System.Collections.Generic; using System.Diagnostics; -using System.Reflection; using System.Runtime.InteropServices; namespace System { public static partial class Environment { - private static string GetEnvironmentVariableCore(string variable) + private static string? GetEnvironmentVariableCore(string variable) { Span buffer = stackalloc char[128]; // a somewhat reasonable default size int requiredSize = Interop.Kernel32.GetEnvironmentVariable(variable, buffer); @@ -47,7 +46,7 @@ namespace System } } - private static void SetEnvironmentVariableCore(string variable, string value) + private static void SetEnvironmentVariableCore(string variable, string? value) { if (!Interop.Kernel32.SetEnvironmentVariable(variable, value)) { diff --git a/src/System.Private.CoreLib/shared/System/Environment.Win32.cs b/src/System.Private.CoreLib/shared/System/Environment.Win32.cs index f7b87ff..f58cdcf 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Win32.cs @@ -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.Collections; using System.Diagnostics; using System.IO; @@ -14,7 +15,7 @@ namespace System { public static partial class Environment { - private static string GetEnvironmentVariableFromRegistry(string variable, bool fromMachine) + private static string? GetEnvironmentVariableFromRegistry(string variable, bool fromMachine) { Debug.Assert(variable != null); @@ -23,13 +24,13 @@ namespace System return null; // Systems without the Windows registry pretend that it's always empty. #endif - using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false)) + using (RegistryKey? environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false)) { return environmentKey?.GetValue(variable) as string; } } - private static void SetEnvironmentVariableFromRegistry(string variable, string value, bool fromMachine) + private static void SetEnvironmentVariableFromRegistry(string variable, string? value, bool fromMachine) { Debug.Assert(variable != null); @@ -44,7 +45,7 @@ namespace System throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(variable)); } - using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: true)) + using (RegistryKey? environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: true)) { if (environmentKey != null) { @@ -72,13 +73,13 @@ namespace System return results; #endif - using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false)) + using (RegistryKey? environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false)) { if (environmentKey != null) { foreach (string name in environmentKey.GetValueNames()) { - string value = environmentKey.GetValue(name, "").ToString(); + string? value = environmentKey.GetValue(name, "")!.ToString(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 try { results.Add(name, value); @@ -94,7 +95,7 @@ namespace System return results; } - private static RegistryKey OpenEnvironmentKeyIfExists(bool fromMachine, bool writable) + private static RegistryKey? OpenEnvironmentKeyIfExists(bool fromMachine, bool writable) { RegistryKey baseKey; string keyName; @@ -409,9 +410,9 @@ namespace System if (s_winRTFolderPathsGetFolderPath == null) { Type winRtFolderPathsType = Type.GetType("System.WinRTFolderPaths, System.Runtime.WindowsRuntime, Version=4.0.14.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", throwOnError: false); - MethodInfo getFolderPathsMethod = winRtFolderPathsType?.GetMethod("GetFolderPath", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(SpecialFolder), typeof(SpecialFolderOption) }, null); - var d = (Func)getFolderPathsMethod?.CreateDelegate(typeof(Func)); - s_winRTFolderPathsGetFolderPath = d ?? delegate { return null; }; + MethodInfo? getFolderPathsMethod = winRtFolderPathsType?.GetMethod("GetFolderPath", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(SpecialFolder), typeof(SpecialFolderOption) }, null); + var d = (Func?)getFolderPathsMethod?.CreateDelegate(typeof(Func)); + s_winRTFolderPathsGetFolderPath = d ?? delegate { return string.Empty; }; } return s_winRTFolderPathsGetFolderPath(folder, option); diff --git a/src/System.Private.CoreLib/shared/System/Environment.WinRT.cs b/src/System.Private.CoreLib/shared/System/Environment.WinRT.cs index a8e3dbc..814b7c4 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.WinRT.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.WinRT.cs @@ -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.IO; using Internal.Runtime.Augments; @@ -18,7 +19,7 @@ namespace System WinRTInteropCallbacks callbacks = WinRTInterop.UnsafeCallbacks; return callbacks != null && callbacks.IsAppxModel() ? callbacks.GetFolderPath(folder, option) : - null; + string.Empty; } } } diff --git a/src/System.Private.CoreLib/shared/System/Environment.Windows.cs b/src/System.Private.CoreLib/shared/System/Environment.Windows.cs index 0887630..f60323b 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Windows.cs @@ -2,11 +2,10 @@ // 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.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using Microsoft.Win32; namespace System { diff --git a/src/System.Private.CoreLib/shared/System/Environment.cs b/src/System.Private.CoreLib/shared/System/Environment.cs index ade5091..3691c0d 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.cs @@ -2,8 +2,8 @@ // 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.Collections; -using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Threading; @@ -12,7 +12,7 @@ namespace System { public static partial class Environment { - public static string GetEnvironmentVariable(string variable) + public static string? GetEnvironmentVariable(string variable) { if (variable == null) throw new ArgumentNullException(nameof(variable)); @@ -20,7 +20,7 @@ namespace System return GetEnvironmentVariableCore(variable); } - public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target) + public static string? GetEnvironmentVariable(string variable, EnvironmentVariableTarget target) { if (target == EnvironmentVariableTarget.Process) return GetEnvironmentVariable(variable); @@ -41,13 +41,13 @@ namespace System return GetEnvironmentVariablesFromRegistry(fromMachine); } - public static void SetEnvironmentVariable(string variable, string value) + public static void SetEnvironmentVariable(string variable, string? value) { ValidateVariableAndValue(variable, ref value); SetEnvironmentVariableCore(variable, value); } - public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) + public static void SetEnvironmentVariable(string variable, string? value, EnvironmentVariableTarget target) { if (target == EnvironmentVariableTarget.Process) { @@ -89,7 +89,7 @@ namespace System return ExpandEnvironmentVariablesCore(name); } - private static string[] s_commandLineArgs; + private static string[]? s_commandLineArgs; internal static void SetCommandLineArgs(string[] cmdLineArgs) // invoked from VM { @@ -113,7 +113,7 @@ namespace System public static bool Is64BitOperatingSystem => Is64BitProcess || Is64BitOperatingSystemWhen32BitProcess; - private static OperatingSystem s_osVersion; + private static OperatingSystem? s_osVersion; public static OperatingSystem OSVersion { @@ -123,7 +123,7 @@ namespace System { Interlocked.CompareExchange(ref s_osVersion, GetOSVersion(), null); } - return s_osVersion; + return s_osVersion!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } } @@ -134,7 +134,7 @@ namespace System get { // FX_PRODUCT_VERSION is expected to be set by the host - string versionString = (string)AppContext.GetData("FX_PRODUCT_VERSION"); + string? versionString = (string?)AppContext.GetData("FX_PRODUCT_VERSION"); if (versionString == null) { @@ -150,7 +150,7 @@ namespace System versionSpan = versionSpan.Slice(0, separatorIndex); // Return zeros rather then failing if the version string fails to parse - return Version.TryParse(versionSpan, out Version version) ? version : new Version(); + return Version.TryParse(versionSpan, out Version? version) ? version! : new Version(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } } @@ -163,12 +163,12 @@ namespace System // present in Process. If it proves important, we could look at separating that functionality out of Process into // Common files which could also be included here. Type processType = Type.GetType("System.Diagnostics.Process, System.Diagnostics.Process, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false); - IDisposable currentProcess = processType?.GetMethod("GetCurrentProcess")?.Invoke(null, BindingFlags.DoNotWrapExceptions, null, null, null) as IDisposable; + IDisposable? currentProcess = processType?.GetMethod("GetCurrentProcess")?.Invoke(null, BindingFlags.DoNotWrapExceptions, null, null, null) as IDisposable; if (currentProcess != null) { using (currentProcess) { - object result = processType.GetMethod("get_WorkingSet64")?.Invoke(currentProcess, BindingFlags.DoNotWrapExceptions, null, null, null); + object? result = processType!.GetMethod("get_WorkingSet64")?.Invoke(currentProcess, BindingFlags.DoNotWrapExceptions, null, null, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 if (result is long) return (long)result; } } @@ -191,7 +191,7 @@ namespace System throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(SR.Arg_EnumIllegalVal, target)); } - private static void ValidateVariableAndValue(string variable, ref string value) + private static void ValidateVariableAndValue(string variable, ref string? value) { if (variable == null) throw new ArgumentNullException(nameof(variable)); diff --git a/src/System.Private.CoreLib/shared/System/EnvironmentVariableTarget.cs b/src/System.Private.CoreLib/shared/System/EnvironmentVariableTarget.cs index 806eb75..1f8213c 100644 --- a/src/System.Private.CoreLib/shared/System/EnvironmentVariableTarget.cs +++ b/src/System.Private.CoreLib/shared/System/EnvironmentVariableTarget.cs @@ -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 namespace System { #if PROJECTN @@ -13,4 +14,4 @@ namespace System User = 1, Machine = 2, } -} \ No newline at end of file +} diff --git a/src/System.Private.CoreLib/shared/System/EventArgs.cs b/src/System.Private.CoreLib/shared/System/EventArgs.cs index f3561a8..0d806c6 100644 --- a/src/System.Private.CoreLib/shared/System/EventArgs.cs +++ b/src/System.Private.CoreLib/shared/System/EventArgs.cs @@ -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; namespace System diff --git a/src/System.Private.CoreLib/shared/System/EventHandler.cs b/src/System.Private.CoreLib/shared/System/EventHandler.cs index c38e17c..7e0f183 100644 --- a/src/System.Private.CoreLib/shared/System/EventHandler.cs +++ b/src/System.Private.CoreLib/shared/System/EventHandler.cs @@ -2,11 +2,12 @@ // 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; namespace System { - public delegate void EventHandler(object sender, EventArgs e); + public delegate void EventHandler(object? sender, EventArgs e); - public delegate void EventHandler(object sender, TEventArgs e); // Removed TEventArgs constraint post-.NET 4 + public delegate void EventHandler(object? sender, TEventArgs e); // Removed TEventArgs constraint post-.NET 4 } diff --git a/src/System.Private.CoreLib/shared/System/FlagsAttribute.cs b/src/System.Private.CoreLib/shared/System/FlagsAttribute.cs index 4f3ab36..751f944 100644 --- a/src/System.Private.CoreLib/shared/System/FlagsAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/FlagsAttribute.cs @@ -5,6 +5,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// +#nullable enable namespace System { // Custom attribute to indicate that the enum diff --git a/src/System.Private.CoreLib/shared/System/FormattableString.cs b/src/System.Private.CoreLib/shared/System/FormattableString.cs index 51863d6..965a916 100644 --- a/src/System.Private.CoreLib/shared/System/FormattableString.cs +++ b/src/System.Private.CoreLib/shared/System/FormattableString.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +#nullable enable namespace System { /// @@ -28,7 +29,7 @@ namespace System /// Returns an object array that contains zero or more objects to format. Clients should not /// mutate the contents of the array. /// - public abstract object[] GetArguments(); + public abstract object?[] GetArguments(); /// /// The number of arguments to be formatted. @@ -38,14 +39,14 @@ namespace System /// /// Returns one argument to be formatted from argument position . /// - public abstract object GetArgument(int index); + public abstract object? GetArgument(int index); /// /// Format to a string using the given culture. /// - public abstract string ToString(IFormatProvider formatProvider); + public abstract string ToString(IFormatProvider? formatProvider); - string IFormattable.ToString(string ignored, IFormatProvider formatProvider) + string IFormattable.ToString(string? ignored, IFormatProvider? formatProvider) { return ToString(formatProvider); } diff --git a/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs b/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs index acc415b..66cdcc7 100644 --- a/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs +++ b/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs @@ -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.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; @@ -13,9 +14,13 @@ namespace System /// internal sealed class Gen2GcCallback : CriticalFinalizerObject { - private Gen2GcCallback() - : base() + private readonly Func _callback; + private readonly GCHandle _weakTargetObj; + + private Gen2GcCallback(Func callback, object targetObj) { + _callback = callback; + _weakTargetObj = GCHandle.Alloc(targetObj, GCHandleType.Weak); } /// @@ -28,17 +33,7 @@ namespace System public static void Register(Func callback, object targetObj) { // Create a unreachable object that remembers the callback function and target object. - Gen2GcCallback gcCallback = new Gen2GcCallback(); - gcCallback.Setup(callback, targetObj); - } - - private Func _callback; - private GCHandle _weakTargetObj; - - private void Setup(Func callback, object targetObj) - { - _callback = callback; - _weakTargetObj = GCHandle.Alloc(targetObj, GCHandleType.Weak); + new Gen2GcCallback(callback, targetObj); } ~Gen2GcCallback() diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs index 76ee908..107fac5 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs @@ -131,7 +131,7 @@ namespace System } } - internal static bool TryParseExactMultiple(ReadOnlySpan s, string[] formats, + internal static bool TryParseExactMultiple(ReadOnlySpan s, string?[]? formats, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset) { result = DateTime.MinValue; @@ -149,7 +149,7 @@ namespace System } - internal static bool TryParseExactMultiple(ReadOnlySpan s, string[] formats, + internal static bool TryParseExactMultiple(ReadOnlySpan s, string?[]? formats, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result) { result = DateTime.MinValue; @@ -163,7 +163,7 @@ namespace System return false; } - internal static bool TryParseExactMultiple(ReadOnlySpan s, string[] formats, + internal static bool TryParseExactMultiple(ReadOnlySpan s, string?[]? formats, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result) { if (formats == null) @@ -192,7 +192,7 @@ namespace System // for (int i = 0; i < formats.Length; i++) { - if (formats[i] == null || formats[i].Length == 0) + if (formats[i] == null || formats[i]!.Length == 0) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 { result.SetBadFormatSpecifierFailure(); return false; @@ -5100,15 +5100,15 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, case ParseFailureKind.Format: return new FormatException(SR.GetResourceString(result.failureMessageID)); case ParseFailureKind.FormatWithParameter: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), result.failureMessageFormatArgument)); + return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, result.failureMessageFormatArgument)); case ParseFailureKind.FormatBadDateTimeCalendar: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.originalDateTimeString), result.calendar)); + return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.originalDateTimeString), result.calendar)); case ParseFailureKind.FormatWithOriginalDateTime: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.originalDateTimeString))); + return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.originalDateTimeString))); case ParseFailureKind.FormatWithFormatSpecifier: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.failedFormatSpecifier))); + return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.failedFormatSpecifier))); case ParseFailureKind.FormatWithOriginalDateTimeAndParameter: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.originalDateTimeString), result.failureMessageFormatArgument)); + return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.originalDateTimeString), result.failureMessageFormatArgument)); default: Debug.Fail("Unknown DateTimeParseFailure: " + result.failure.ToString()); return null!; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs b/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs index 7b0136b..4e34474 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs @@ -51,7 +51,7 @@ namespace System.Globalization return true; } - public object Current => GetTextElement(); + public object? Current => GetTextElement(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 public string GetTextElement() { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs b/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs index 39defa0..a03a02c 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs @@ -664,7 +664,7 @@ namespace System.Globalization return parseResult.parsedTimeSpan; } - internal static bool TryParseExactMultiple(ReadOnlySpan input, string?[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + internal static bool TryParseExactMultiple(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); @@ -1670,7 +1670,7 @@ namespace System.Globalization } /// Common private ParseExactMultiple method called by both ParseExactMultiple and TryParseExactMultiple. - private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, string?[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) + private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) { if (formats == null) { diff --git a/src/System.Private.CoreLib/shared/System/Guid.Unix.cs b/src/System.Private.CoreLib/shared/System/Guid.Unix.cs index 1c39e11..113f76d 100644 --- a/src/System.Private.CoreLib/shared/System/Guid.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Guid.Unix.cs @@ -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.Diagnostics; using System.Runtime.InteropServices; diff --git a/src/System.Private.CoreLib/shared/System/Guid.Windows.cs b/src/System.Private.CoreLib/shared/System/Guid.Windows.cs index 6a27508..46bdec2 100644 --- a/src/System.Private.CoreLib/shared/System/Guid.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Guid.Windows.cs @@ -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 namespace System { partial struct Guid diff --git a/src/System.Private.CoreLib/shared/System/Guid.cs b/src/System.Private.CoreLib/shared/System/Guid.cs index ea3ae76..6bcf48c 100644 --- a/src/System.Private.CoreLib/shared/System/Guid.cs +++ b/src/System.Private.CoreLib/shared/System/Guid.cs @@ -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.Diagnostics; using System.Globalization; using System.Runtime.CompilerServices; @@ -269,7 +270,7 @@ namespace System return result._parsedGuid; } - public static bool TryParseExact(string input, string format, out Guid result) + public static bool TryParseExact(string? input, string? format, out Guid result) { if (input == null) { @@ -806,7 +807,7 @@ namespace System // Returns true if and only if the guid represented // by o is the same as this instance. - public override bool Equals(object o) + public override bool Equals(object? o) { Guid g; // Check that o is a Guid first @@ -832,7 +833,7 @@ namespace System private int GetResult(uint me, uint them) => me < them ? -1 : 1; - public int CompareTo(object value) + public int CompareTo(object? value) { if (value == null) { @@ -980,7 +981,7 @@ namespace System Unsafe.Add(ref a._a, 3) != Unsafe.Add(ref b._a, 3); } - public string ToString(string format) + public string ToString(string? format) { return ToString(format, null); } @@ -1023,7 +1024,7 @@ namespace System // IFormattable interface // We currently ignore provider - public string ToString(string format, IFormatProvider provider) + public string ToString(string? format, IFormatProvider? provider) { if (string.IsNullOrEmpty(format)) { @@ -1194,7 +1195,7 @@ namespace System return true; } - bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider provider) + bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) { // Like with the IFormattable implementation, provider is ignored. return TryFormat(destination, out charsWritten, format); diff --git a/src/System.Private.CoreLib/shared/System/HResults.cs b/src/System.Private.CoreLib/shared/System/HResults.cs index a7c1f8c..df12ac3 100644 --- a/src/System.Private.CoreLib/shared/System/HResults.cs +++ b/src/System.Private.CoreLib/shared/System/HResults.cs @@ -18,7 +18,7 @@ // Reflection will use 0x1600 -> 0x161f. IO will use 0x1620 -> 0x163f. // Security will use 0x1640 -> 0x165f - +#nullable enable using System; namespace System diff --git a/src/System.Private.CoreLib/shared/System/HashCode.cs b/src/System.Private.CoreLib/shared/System/HashCode.cs index 39a905b..09fef5d 100644 --- a/src/System.Private.CoreLib/shared/System/HashCode.cs +++ b/src/System.Private.CoreLib/shared/System/HashCode.cs @@ -41,6 +41,7 @@ https://raw.githubusercontent.com/Cyan4973/xxHash/5c174cfa4e45a42f94082dc0d4539b */ +#nullable enable using System.Collections.Generic; using System.ComponentModel; using System.Numerics; @@ -301,7 +302,7 @@ namespace System Add(value?.GetHashCode() ?? 0); } - public void Add(T value, IEqualityComparer comparer) + public void Add(T value, IEqualityComparer? comparer) { Add(comparer != null ? comparer.GetHashCode(value) : (value?.GetHashCode() ?? 0)); } @@ -417,7 +418,7 @@ namespace System [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)] [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object obj) => throw new NotSupportedException(SR.HashCode_EqualityNotSupported); + public override bool Equals(object? obj) => throw new NotSupportedException(SR.HashCode_EqualityNotSupported); #pragma warning restore 0809 } } diff --git a/src/System.Private.CoreLib/shared/System/IAsyncDisposable.cs b/src/System.Private.CoreLib/shared/System/IAsyncDisposable.cs index c29f549..3139b00 100644 --- a/src/System.Private.CoreLib/shared/System/IAsyncDisposable.cs +++ b/src/System.Private.CoreLib/shared/System/IAsyncDisposable.cs @@ -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.Threading.Tasks; namespace System diff --git a/src/System.Private.CoreLib/shared/System/ICloneable.cs b/src/System.Private.CoreLib/shared/System/ICloneable.cs index 9f123e4..325a367 100644 --- a/src/System.Private.CoreLib/shared/System/ICloneable.cs +++ b/src/System.Private.CoreLib/shared/System/ICloneable.cs @@ -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 namespace System { public interface ICloneable diff --git a/src/System.Private.CoreLib/shared/System/IComparable.cs b/src/System.Private.CoreLib/shared/System/IComparable.cs index cf71953..1a23580 100644 --- a/src/System.Private.CoreLib/shared/System/IComparable.cs +++ b/src/System.Private.CoreLib/shared/System/IComparable.cs @@ -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 namespace System { // The IComparable interface is implemented by classes that support an @@ -18,7 +19,7 @@ namespace System // if this is equal to object, or a value greater than zero // if this is greater than object. // - int CompareTo(object obj); + int CompareTo(object? obj); } // Generic version of IComparable. diff --git a/src/System.Private.CoreLib/shared/System/IConvertible.cs b/src/System.Private.CoreLib/shared/System/IConvertible.cs index 7abd0c4..2b0c134 100644 --- a/src/System.Private.CoreLib/shared/System/IConvertible.cs +++ b/src/System.Private.CoreLib/shared/System/IConvertible.cs @@ -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 namespace System { // The IConvertible interface represents an object that contains a value. This @@ -39,25 +40,25 @@ namespace System // implementation must throw an InvalidCastException. If the value of the // underlying object is not within the range of the target type, the // implementation must throw an OverflowException. The - // IFormatProvider will be used to get a NumberFormatInfo or similar + // IFormatProvider? will be used to get a NumberFormatInfo or similar // appropriate service object, and may safely be null. - bool ToBoolean(IFormatProvider provider); - char ToChar(IFormatProvider provider); - sbyte ToSByte(IFormatProvider provider); - byte ToByte(IFormatProvider provider); - short ToInt16(IFormatProvider provider); - ushort ToUInt16(IFormatProvider provider); - int ToInt32(IFormatProvider provider); - uint ToUInt32(IFormatProvider provider); - long ToInt64(IFormatProvider provider); - ulong ToUInt64(IFormatProvider provider); - float ToSingle(IFormatProvider provider); - double ToDouble(IFormatProvider provider); - decimal ToDecimal(IFormatProvider provider); - DateTime ToDateTime(IFormatProvider provider); - string ToString(IFormatProvider provider); - object ToType(Type conversionType, IFormatProvider provider); + bool ToBoolean(IFormatProvider? provider); + char ToChar(IFormatProvider? provider); + sbyte ToSByte(IFormatProvider? provider); + byte ToByte(IFormatProvider? provider); + short ToInt16(IFormatProvider? provider); + ushort ToUInt16(IFormatProvider? provider); + int ToInt32(IFormatProvider? provider); + uint ToUInt32(IFormatProvider? provider); + long ToInt64(IFormatProvider? provider); + ulong ToUInt64(IFormatProvider? provider); + float ToSingle(IFormatProvider? provider); + double ToDouble(IFormatProvider? provider); + decimal ToDecimal(IFormatProvider? provider); + DateTime ToDateTime(IFormatProvider? provider); + string ToString(IFormatProvider? provider); + object ToType(Type conversionType, IFormatProvider? provider); } } diff --git a/src/System.Private.CoreLib/shared/System/ICustomFormatter.cs b/src/System.Private.CoreLib/shared/System/ICustomFormatter.cs index cd798b4..df5d9b8 100644 --- a/src/System.Private.CoreLib/shared/System/ICustomFormatter.cs +++ b/src/System.Private.CoreLib/shared/System/ICustomFormatter.cs @@ -12,13 +12,11 @@ ** ===========================================================*/ -using System; - +#nullable enable namespace System { public interface ICustomFormatter { - // Interface does not need to be marked with the serializable attribute - string Format(string format, object arg, IFormatProvider formatProvider); + string Format(string? format, object? arg, IFormatProvider? formatProvider); } } diff --git a/src/System.Private.CoreLib/shared/System/IDisposable.cs b/src/System.Private.CoreLib/shared/System/IDisposable.cs index 24f0740..fb89476 100644 --- a/src/System.Private.CoreLib/shared/System/IDisposable.cs +++ b/src/System.Private.CoreLib/shared/System/IDisposable.cs @@ -12,6 +12,7 @@ ** ===========================================================*/ +#nullable enable namespace System { // IDisposable is an attempt at helping to solve problems with deterministic diff --git a/src/System.Private.CoreLib/shared/System/IEquatable.cs b/src/System.Private.CoreLib/shared/System/IEquatable.cs index 1264fdd..482f467 100644 --- a/src/System.Private.CoreLib/shared/System/IEquatable.cs +++ b/src/System.Private.CoreLib/shared/System/IEquatable.cs @@ -2,8 +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. -using System; - +#nullable enable namespace System { public interface IEquatable diff --git a/src/System.Private.CoreLib/shared/System/IFormatProvider.cs b/src/System.Private.CoreLib/shared/System/IFormatProvider.cs index 9369b07..706dea8 100644 --- a/src/System.Private.CoreLib/shared/System/IFormatProvider.cs +++ b/src/System.Private.CoreLib/shared/System/IFormatProvider.cs @@ -11,13 +11,12 @@ ** ============================================================*/ -using System; - +#nullable enable namespace System { public interface IFormatProvider { // Interface does not need to be marked with the serializable attribute - object GetFormat(Type formatType); + object? GetFormat(Type? formatType); } } diff --git a/src/System.Private.CoreLib/shared/System/IFormattable.cs b/src/System.Private.CoreLib/shared/System/IFormattable.cs index b5ed9bb..e3fa7c1 100644 --- a/src/System.Private.CoreLib/shared/System/IFormattable.cs +++ b/src/System.Private.CoreLib/shared/System/IFormattable.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; - +#nullable enable namespace System { public interface IFormattable { - string ToString(string format, IFormatProvider formatProvider); + string ToString(string? format, IFormatProvider? formatProvider); } } diff --git a/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs index bb9fa29..7377271 100644 --- a/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs @@ -452,7 +452,7 @@ namespace System.IO // it then fall back to doing the ArrayPool/copy behavior. return new ValueTask( MemoryMarshal.TryGetArray(buffer, out ArraySegment destinationArray) ? - Read(destinationArray.Array, destinationArray.Offset, destinationArray.Count) : + Read(destinationArray.Array!, destinationArray.Offset, destinationArray.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 Read(buffer.Span)); } catch (OperationCanceledException oce) @@ -767,7 +767,7 @@ namespace System.IO // Unlike ReadAsync, we could delegate to WriteAsync(byte[], ...) here, but we don't for consistency. if (MemoryMarshal.TryGetArray(buffer, out ArraySegment sourceArray)) { - Write(sourceArray.Array, sourceArray.Offset, sourceArray.Count); + Write(sourceArray.Array!, sourceArray.Offset, sourceArray.Count); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } else { diff --git a/src/System.Private.CoreLib/shared/System/IO/Stream.cs b/src/System.Private.CoreLib/shared/System/IO/Stream.cs index 1f0943f..55ae900 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Stream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/Stream.cs @@ -381,7 +381,7 @@ namespace System.IO { if (MemoryMarshal.TryGetArray(buffer, out ArraySegment array)) { - return new ValueTask(ReadAsync(array.Array, array.Offset, array.Count, cancellationToken)); + return new ValueTask(ReadAsync(array.Array!, array.Offset, array.Count, cancellationToken)); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } else { @@ -692,7 +692,7 @@ namespace System.IO { if (MemoryMarshal.TryGetArray(buffer, out ArraySegment array)) { - return new ValueTask(WriteAsync(array.Array, array.Offset, array.Count, cancellationToken)); + return new ValueTask(WriteAsync(array.Array!, array.Offset, array.Count, cancellationToken)); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } else { diff --git a/src/System.Private.CoreLib/shared/System/IO/TextReader.cs b/src/System.Private.CoreLib/shared/System/IO/TextReader.cs index 7a43f6e..e2f0af9 100644 --- a/src/System.Private.CoreLib/shared/System/IO/TextReader.cs +++ b/src/System.Private.CoreLib/shared/System/IO/TextReader.cs @@ -254,7 +254,7 @@ namespace System.IO public virtual ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) => new ValueTask(MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? - ReadAsync(array.Array, array.Offset, array.Count) : + ReadAsync(array.Array!, array.Offset, array.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 Task.Factory.StartNew(state => { var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 @@ -292,7 +292,7 @@ namespace System.IO public virtual ValueTask ReadBlockAsync(Memory buffer, CancellationToken cancellationToken = default) => new ValueTask(MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? - ReadBlockAsync(array.Array, array.Offset, array.Count) : + ReadBlockAsync(array.Array!, array.Offset, array.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 Task.Factory.StartNew(state => { var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 diff --git a/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs b/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs index d66ee43..4d555e5 100644 --- a/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs +++ b/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs @@ -607,8 +607,8 @@ namespace System.IO public virtual Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : - MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? - WriteAsync(array.Array, array.Offset, array.Count) : + MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + WriteAsync(array.Array!, array.Offset, array.Count) : Task.Factory.StartNew(state => { var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 @@ -682,8 +682,8 @@ namespace System.IO public virtual Task WriteLineAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : - MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? - WriteLineAsync(array.Array, array.Offset, array.Count) : + MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + WriteLineAsync(array.Array!, array.Offset, array.Count) : Task.Factory.StartNew(state => { var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 diff --git a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs index 8489d66..a42cdf9 100644 --- a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs @@ -512,7 +512,7 @@ namespace System.IO // it then fall back to doing the ArrayPool/copy behavior. return new ValueTask( MemoryMarshal.TryGetArray(buffer, out ArraySegment destinationArray) ? - Read(destinationArray.Array, destinationArray.Offset, destinationArray.Count) : + Read(destinationArray.Array!, destinationArray.Offset, destinationArray.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 Read(buffer.Span)); } catch (Exception ex) @@ -797,7 +797,7 @@ namespace System.IO // Unlike ReadAsync, we could delegate to WriteAsync(byte[], ...) here, but we don't for consistency. if (MemoryMarshal.TryGetArray(buffer, out ArraySegment sourceArray)) { - Write(sourceArray.Array, sourceArray.Offset, sourceArray.Count); + Write(sourceArray.Array!, sourceArray.Offset, sourceArray.Count); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } else { diff --git a/src/System.Private.CoreLib/shared/System/IObservable.cs b/src/System.Private.CoreLib/shared/System/IObservable.cs index aabb0b8..c451a7b 100644 --- a/src/System.Private.CoreLib/shared/System/IObservable.cs +++ b/src/System.Private.CoreLib/shared/System/IObservable.cs @@ -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 namespace System { public interface IObservable diff --git a/src/System.Private.CoreLib/shared/System/IObserver.cs b/src/System.Private.CoreLib/shared/System/IObserver.cs index 39e123d..3590668 100644 --- a/src/System.Private.CoreLib/shared/System/IObserver.cs +++ b/src/System.Private.CoreLib/shared/System/IObserver.cs @@ -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 namespace System { public interface IObserver diff --git a/src/System.Private.CoreLib/shared/System/IProgress.cs b/src/System.Private.CoreLib/shared/System/IProgress.cs index 724c7bd..e344c73 100644 --- a/src/System.Private.CoreLib/shared/System/IProgress.cs +++ b/src/System.Private.CoreLib/shared/System/IProgress.cs @@ -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 namespace System { /// Defines a provider for progress updates. diff --git a/src/System.Private.CoreLib/shared/System/Index.cs b/src/System.Private.CoreLib/shared/System/Index.cs index 62d7f34..9ed7ed1 100644 --- a/src/System.Private.CoreLib/shared/System/Index.cs +++ b/src/System.Private.CoreLib/shared/System/Index.cs @@ -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.Diagnostics; using System.Runtime.CompilerServices; @@ -117,7 +118,7 @@ namespace System /// Indicates whether the current Index object is equal to another object of the same type. /// An object to compare with this object - public override bool Equals(object value) => value is Index && _value == ((Index)value)._value; + public override bool Equals(object? value) => value is Index && _value == ((Index)value)._value; /// Indicates whether the current Index object is equal to another Index object. /// An object to compare with this object diff --git a/src/System.Private.CoreLib/shared/System/IntPtr.cs b/src/System.Private.CoreLib/shared/System/IntPtr.cs index d23742f..1aedd04 100644 --- a/src/System.Private.CoreLib/shared/System/IntPtr.cs +++ b/src/System.Private.CoreLib/shared/System/IntPtr.cs @@ -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.Runtime.CompilerServices; using System.Runtime.Serialization; @@ -72,7 +73,7 @@ namespace System info.AddValue("value", ToInt64()); } - public unsafe override bool Equals(object obj) + public unsafe override bool Equals(object? obj) { if (obj is IntPtr) { diff --git a/src/System.Private.CoreLib/shared/System/Lazy.cs b/src/System.Private.CoreLib/shared/System/Lazy.cs index 6b8c0a4..d8e9a15 100644 --- a/src/System.Private.CoreLib/shared/System/Lazy.cs +++ b/src/System.Private.CoreLib/shared/System/Lazy.cs @@ -150,11 +150,11 @@ namespace System } } - internal static object CreateViaDefaultConstructor(Type type) + internal static T CreateViaDefaultConstructor() { try { - return Activator.CreateInstance(type); + return Activator.CreateInstance(); } catch (MissingMethodException) { @@ -183,10 +183,7 @@ namespace System [DebuggerDisplay("ThreadSafetyMode={Mode}, IsValueCreated={IsValueCreated}, IsValueFaulted={IsValueFaulted}, Value={ValueForDebugDisplay}")] public class Lazy { - private static T CreateViaDefaultConstructor() - { - return (T)LazyHelper.CreateViaDefaultConstructor(typeof(T)); - } + private static T CreateViaDefaultConstructor() => LazyHelper.CreateViaDefaultConstructor(); // _state, a volatile reference, is set to null after _value has been set private volatile LazyHelper? _state; diff --git a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs index 6c0e750..a7c2436 100644 --- a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs +++ b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs @@ -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. -using System; +#nullable enable using System.Runtime.CompilerServices; namespace System diff --git a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.cs b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.cs index b0999da..b63a980 100644 --- a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.cs +++ b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.cs @@ -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. -using System; +#nullable enable using System.Runtime.CompilerServices; namespace System diff --git a/src/System.Private.CoreLib/shared/System/LocalDataStoreSlot.cs b/src/System.Private.CoreLib/shared/System/LocalDataStoreSlot.cs index ae9a741..616967c 100644 --- a/src/System.Private.CoreLib/shared/System/LocalDataStoreSlot.cs +++ b/src/System.Private.CoreLib/shared/System/LocalDataStoreSlot.cs @@ -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.Threading; namespace System @@ -11,13 +12,13 @@ namespace System #endif public sealed class LocalDataStoreSlot { - internal LocalDataStoreSlot(ThreadLocal data) + internal LocalDataStoreSlot(ThreadLocal data) { Data = data; GC.SuppressFinalize(this); } - internal ThreadLocal Data { get; private set; } + internal ThreadLocal Data { get; private set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA1821", Justification = "Finalizer preserved for compat, it is suppressed by the constructor.")] ~LocalDataStoreSlot() diff --git a/src/System.Private.CoreLib/shared/System/MarshalByRefObject.cs b/src/System.Private.CoreLib/shared/System/MarshalByRefObject.cs index a083c97..9ef86b4 100644 --- a/src/System.Private.CoreLib/shared/System/MarshalByRefObject.cs +++ b/src/System.Private.CoreLib/shared/System/MarshalByRefObject.cs @@ -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.Runtime.InteropServices; namespace System diff --git a/src/System.Private.CoreLib/shared/System/Marvin.OrdinalIgnoreCase.cs b/src/System.Private.CoreLib/shared/System/Marvin.OrdinalIgnoreCase.cs index beab0cf..9a8f0ae 100644 --- a/src/System.Private.CoreLib/shared/System/Marvin.OrdinalIgnoreCase.cs +++ b/src/System.Private.CoreLib/shared/System/Marvin.OrdinalIgnoreCase.cs @@ -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.Buffers; using System.Diagnostics; using System.Runtime.InteropServices; @@ -74,7 +75,7 @@ namespace System { Debug.Assert(count > 0); - char[] borrowedArr = null; + char[]? borrowedArr = null; Span scratch = (uint)count <= 64 ? stackalloc char[64] : (borrowedArr = ArrayPool.Shared.Rent(count)); int charsWritten = new ReadOnlySpan(ref data, count).ToUpperInvariant(scratch); diff --git a/src/System.Private.CoreLib/shared/System/Marvin.cs b/src/System.Private.CoreLib/shared/System/Marvin.cs index 832c84b..c03ede4 100644 --- a/src/System.Private.CoreLib/shared/System/Marvin.cs +++ b/src/System.Private.CoreLib/shared/System/Marvin.cs @@ -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.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/shared/System/Math.cs b/src/System.Private.CoreLib/shared/System/Math.cs index 1c36c9d..ca448d0 100644 --- a/src/System.Private.CoreLib/shared/System/Math.cs +++ b/src/System.Private.CoreLib/shared/System/Math.cs @@ -13,6 +13,7 @@ //This class contains only static members and doesn't require serialization. +#nullable enable using System.Diagnostics; using System.Runtime; using System.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/shared/System/MathF.cs b/src/System.Private.CoreLib/shared/System/MathF.cs index 1defa4e..0994ed0 100644 --- a/src/System.Private.CoreLib/shared/System/MathF.cs +++ b/src/System.Private.CoreLib/shared/System/MathF.cs @@ -10,7 +10,7 @@ //This class contains only static members and doesn't require serialization. -using System.Runtime; +#nullable enable using System.Runtime.CompilerServices; namespace System diff --git a/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs b/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs index 6ab6e50..563d010 100644 --- a/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs +++ b/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs @@ -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.Diagnostics; namespace System diff --git a/src/System.Private.CoreLib/shared/System/MidpointRounding.cs b/src/System.Private.CoreLib/shared/System/MidpointRounding.cs index 835dafe..146fed9 100644 --- a/src/System.Private.CoreLib/shared/System/MidpointRounding.cs +++ b/src/System.Private.CoreLib/shared/System/MidpointRounding.cs @@ -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 namespace System { public enum MidpointRounding diff --git a/src/System.Private.CoreLib/shared/System/NonSerializedAttribute.cs b/src/System.Private.CoreLib/shared/System/NonSerializedAttribute.cs index cabd5a2..2caa285 100644 --- a/src/System.Private.CoreLib/shared/System/NonSerializedAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/NonSerializedAttribute.cs @@ -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 namespace System { [AttributeUsage(AttributeTargets.Field, Inherited = false)] diff --git a/src/System.Private.CoreLib/shared/System/Nullable.cs b/src/System.Private.CoreLib/shared/System/Nullable.cs index 6f8d667..10df282 100644 --- a/src/System.Private.CoreLib/shared/System/Nullable.cs +++ b/src/System.Private.CoreLib/shared/System/Nullable.cs @@ -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.Collections.Generic; using System.Runtime.Versioning; @@ -59,7 +60,7 @@ namespace System return hasValue ? value : defaultValue; } - public override bool Equals(object other) + public override bool Equals(object? other) { if (!hasValue) return other == null; if (other == null) return false; @@ -71,7 +72,7 @@ namespace System return hasValue ? value.GetHashCode() : 0; } - public override string ToString() + public override string? ToString() { return hasValue ? value.ToString() : ""; } @@ -85,7 +86,7 @@ namespace System [NonVersionable] public static explicit operator T(Nullable value) { - return value.Value; + return value!.Value; } } @@ -115,7 +116,7 @@ namespace System // If the type provided is not a Nullable Type, return null. // Otherwise, returns the underlying type of the Nullable type - public static Type GetUnderlyingType(Type nullableType) + public static Type? GetUnderlyingType(Type nullableType) { if ((object)nullableType == null) { diff --git a/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs b/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs index 7486817..dbad93f 100644 --- a/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs @@ -11,8 +11,7 @@ ** ===========================================================*/ -using System; - +#nullable enable namespace System { // This attribute is attached to members that are not to be used any longer. @@ -26,7 +25,7 @@ namespace System , Inherited = false)] public sealed class ObsoleteAttribute : Attribute { - private string _message; + private string? _message; private bool _error; public ObsoleteAttribute() @@ -35,19 +34,19 @@ namespace System _error = false; } - public ObsoleteAttribute(string message) + public ObsoleteAttribute(string? message) { _message = message; _error = false; } - public ObsoleteAttribute(string message, bool error) + public ObsoleteAttribute(string? message, bool error) { _message = message; _error = error; } - public string Message + public string? Message { get { return _message; } } diff --git a/src/System.Private.CoreLib/shared/System/OperatingSystem.cs b/src/System.Private.CoreLib/shared/System/OperatingSystem.cs index be30271..2e806de 100644 --- a/src/System.Private.CoreLib/shared/System/OperatingSystem.cs +++ b/src/System.Private.CoreLib/shared/System/OperatingSystem.cs @@ -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.Diagnostics; using System.Runtime.Serialization; @@ -14,14 +15,14 @@ namespace System { private readonly Version _version; private readonly PlatformID _platform; - private readonly string _servicePack; - private string _versionString; + private readonly string? _servicePack; + private string? _versionString; public OperatingSystem(PlatformID platform, Version version) : this(platform, version, null) { } - internal OperatingSystem(PlatformID platform, Version version, string servicePack) + internal OperatingSystem(PlatformID platform, Version version, string? servicePack) { if (platform < PlatformID.Win32S || platform > PlatformID.MacOSX) { diff --git a/src/System.Private.CoreLib/shared/System/ParamArrayAttribute.cs b/src/System.Private.CoreLib/shared/System/ParamArrayAttribute.cs index d3c3d46..8faffc4 100644 --- a/src/System.Private.CoreLib/shared/System/ParamArrayAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/ParamArrayAttribute.cs @@ -11,6 +11,7 @@ ** =============================================================================*/ +#nullable enable namespace System { [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] diff --git a/src/System.Private.CoreLib/shared/System/ParseNumbers.cs b/src/System.Private.CoreLib/shared/System/ParseNumbers.cs index 0978186..ab04cf6 100644 --- a/src/System.Private.CoreLib/shared/System/ParseNumbers.cs +++ b/src/System.Private.CoreLib/shared/System/ParseNumbers.cs @@ -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.Diagnostics; using System.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs b/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs index 1a4d928..fdad698 100644 --- a/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs @@ -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.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; diff --git a/src/System.Private.CoreLib/shared/System/PasteArguments.Windows.cs b/src/System.Private.CoreLib/shared/System/PasteArguments.Windows.cs index 7cdcbc4..42a817b 100644 --- a/src/System.Private.CoreLib/shared/System/PasteArguments.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/PasteArguments.Windows.cs @@ -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.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; diff --git a/src/System.Private.CoreLib/shared/System/PasteArguments.cs b/src/System.Private.CoreLib/shared/System/PasteArguments.cs index c088fd4..afa2e44 100644 --- a/src/System.Private.CoreLib/shared/System/PasteArguments.cs +++ b/src/System.Private.CoreLib/shared/System/PasteArguments.cs @@ -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.Text; namespace System diff --git a/src/System.Private.CoreLib/shared/System/PlatformID.cs b/src/System.Private.CoreLib/shared/System/PlatformID.cs index 2eda3c0..0ec46f3 100644 --- a/src/System.Private.CoreLib/shared/System/PlatformID.cs +++ b/src/System.Private.CoreLib/shared/System/PlatformID.cs @@ -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.ComponentModel; namespace System diff --git a/src/System.Private.CoreLib/shared/System/Progress.cs b/src/System.Private.CoreLib/shared/System/Progress.cs index 6ddfc18..4dae2b1 100644 --- a/src/System.Private.CoreLib/shared/System/Progress.cs +++ b/src/System.Private.CoreLib/shared/System/Progress.cs @@ -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. -using System; +#nullable enable using System.Threading; using System.Diagnostics; @@ -24,7 +24,7 @@ namespace System /// The synchronization context captured upon construction. This will never be null. private readonly SynchronizationContext _synchronizationContext; /// The handler specified to the constructor. This may be null. - private readonly Action _handler; + private readonly Action? _handler; /// A cached delegate used to post invocation to the synchronization context. private readonly SendOrPostCallback _invokeHandlers; @@ -49,8 +49,7 @@ namespace System /// The is null (Nothing in Visual Basic). public Progress(Action handler) : this() { - if (handler == null) throw new ArgumentNullException(nameof(handler)); - _handler = handler; + _handler = handler ?? throw new ArgumentNullException(nameof(handler)); } /// Raised for each reported progress value. @@ -67,7 +66,7 @@ namespace System // If there's no handler, don't bother going through the sync context. // Inside the callback, we'll need to check again, in case // an event handler is removed between now and then. - Action handler = _handler; + Action? handler = _handler; EventHandler changedEvent = ProgressChanged; if (handler != null || changedEvent != null) { @@ -87,7 +86,7 @@ namespace System { T value = (T)state; - Action handler = _handler; + Action? handler = _handler; EventHandler changedEvent = ProgressChanged; if (handler != null) handler(value); diff --git a/src/System.Private.CoreLib/shared/System/Random.cs b/src/System.Private.CoreLib/shared/System/Random.cs index ed79732..92daa51 100644 --- a/src/System.Private.CoreLib/shared/System/Random.cs +++ b/src/System.Private.CoreLib/shared/System/Random.cs @@ -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 namespace System { public class Random diff --git a/src/System.Private.CoreLib/shared/System/Range.cs b/src/System.Private.CoreLib/shared/System/Range.cs index 0098dea..bad059c 100644 --- a/src/System.Private.CoreLib/shared/System/Range.cs +++ b/src/System.Private.CoreLib/shared/System/Range.cs @@ -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.Diagnostics; using System.Runtime.CompilerServices; @@ -35,7 +36,7 @@ namespace System /// Indicates whether the current Range object is equal to another object of the same type. /// An object to compare with this object - public override bool Equals(object value) + public override bool Equals(object? value) { if (value is Range) { @@ -48,7 +49,7 @@ namespace System /// Indicates whether the current Range object is equal to another Range object. /// An object to compare with this object - public bool Equals (Range other) => other.Start.Equals(Start) && other.End.Equals(End); + public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End); /// Returns the hash code for this instance. public override int GetHashCode() diff --git a/src/System.Private.CoreLib/shared/System/ResolveEventArgs.cs b/src/System.Private.CoreLib/shared/System/ResolveEventArgs.cs index 6196947..447d434 100644 --- a/src/System.Private.CoreLib/shared/System/ResolveEventArgs.cs +++ b/src/System.Private.CoreLib/shared/System/ResolveEventArgs.cs @@ -2,24 +2,25 @@ // 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.Reflection; namespace System { public class ResolveEventArgs : EventArgs { - public ResolveEventArgs(string name) + public ResolveEventArgs(string? name) { Name = name; } - public ResolveEventArgs(string name, Assembly requestingAssembly) + public ResolveEventArgs(string? name, Assembly? requestingAssembly) { Name = name; RequestingAssembly = requestingAssembly; } - public string Name { get; } - public Assembly RequestingAssembly { get; } + public string? Name { get; } + public Assembly? RequestingAssembly { get; } } } diff --git a/src/System.Private.CoreLib/shared/System/ResolveEventHandler.cs b/src/System.Private.CoreLib/shared/System/ResolveEventHandler.cs index cb9af5d..829b146 100644 --- a/src/System.Private.CoreLib/shared/System/ResolveEventHandler.cs +++ b/src/System.Private.CoreLib/shared/System/ResolveEventHandler.cs @@ -2,9 +2,10 @@ // 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.Reflection; namespace System { - public delegate Assembly ResolveEventHandler(object sender, ResolveEventArgs args); + public delegate Assembly ResolveEventHandler(object? sender, ResolveEventArgs args); } diff --git a/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs b/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs index 8021494..be44da2 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs @@ -111,7 +111,7 @@ namespace System.Resources args[0] = file; try { - return (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args); + return (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args)!; } catch (MissingMethodException e) { diff --git a/src/System.Private.CoreLib/shared/System/Resources/ManifestBasedResourceGroveler.cs b/src/System.Private.CoreLib/shared/System/Resources/ManifestBasedResourceGroveler.cs index bea782a..569fcf9 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ManifestBasedResourceGroveler.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ManifestBasedResourceGroveler.cs @@ -255,7 +255,7 @@ namespace System.Resources Type readerType = Type.GetType(readerTypeName, throwOnError: true); object[] args = new object[1]; args[0] = store; - reader = (IResourceReader)Activator.CreateInstance(readerType, args); + reader = (IResourceReader)Activator.CreateInstance(readerType, args)!; } object[] resourceSetArgs = new object[1]; @@ -268,13 +268,16 @@ namespace System.Resources resSetType = Type.GetType(resSetTypeName, true, false); } else + { resSetType = _mediator.UserResourceSet; + } + ResourceSet rs = (ResourceSet)Activator.CreateInstance(resSetType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, resourceSetArgs, null, - null); + null)!; return rs; } } @@ -299,14 +302,14 @@ namespace System.Resources // Add in a check for a constructor taking in an assembly first. try { - rs = (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args); + rs = (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args)!; return rs; } catch (MissingMethodException) { } args = new object[1]; args[0] = store; - rs = (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args); + rs = (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args)!; return rs; } diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs index a389dc8..7437ac9 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs @@ -76,7 +76,7 @@ namespace System.Resources Assembly hiddenScopeAssembly = Assembly.Load(Internal.Runtime.Augments.RuntimeAugments.HiddenScopeAssemblyName); Type WinRTResourceManagerType = hiddenScopeAssembly.GetType("System.Resources.WindowsRuntimeResourceManager", true); #endif - return (WindowsRuntimeResourceManagerBase)Activator.CreateInstance(WinRTResourceManagerType, true); + return (WindowsRuntimeResourceManagerBase)Activator.CreateInstance(WinRTResourceManagerType, nonPublic: true)!; } // CoreCLR: When running under AppX, the following rules apply for resource lookup: @@ -100,7 +100,7 @@ namespace System.Resources #if FEATURE_APPX // Check to see if the assembly is under PLATFORM_RESOURCE_ROOTS. If it is, then we should use satellite assembly lookup for it. - string platformResourceRoots = (string)(AppContext.GetData("PLATFORM_RESOURCE_ROOTS")); + string? platformResourceRoots = (string?)AppContext.GetData("PLATFORM_RESOURCE_ROOTS"); if ((platformResourceRoots != null) && (platformResourceRoots != string.Empty)) { string resourceAssemblyPath = resourcesAssembly.Location; diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs index 09d4092..db5f81d 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs @@ -547,7 +547,7 @@ namespace System.Resources return null; } - if (!Version.TryParse(v, out Version version)) + if (!Version.TryParse(v, out Version? version)) { throw new ArgumentException(SR.Format(SR.Arg_InvalidSatelliteContract_Asm_Ver, a, v)); } diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs index c8b34f8..d854550 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs @@ -1177,7 +1177,7 @@ namespace System.Resources } } - public object Current + public object? Current // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 { get { diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs index bf22d74..af1188b 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -363,7 +363,7 @@ namespace System.Runtime.CompilerServices } } - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 public void Reset() { } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FormattableStringFactory.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FormattableStringFactory.cs index 23d0386..3e17cd0 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FormattableStringFactory.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FormattableStringFactory.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +#nullable enable namespace System.Runtime.CompilerServices { /// @@ -22,7 +23,7 @@ namespace System.Runtime.CompilerServices /// Create a from a composite format string and object /// array containing zero or more objects to format. /// - public static FormattableString Create(string format, params object[] arguments) + public static FormattableString Create(string format, params object?[] arguments) { if (format == null) { @@ -40,19 +41,19 @@ namespace System.Runtime.CompilerServices private sealed class ConcreteFormattableString : FormattableString { private readonly string _format; - private readonly object[] _arguments; + private readonly object?[] _arguments; - internal ConcreteFormattableString(string format, object[] arguments) + internal ConcreteFormattableString(string format, object?[] arguments) { _format = format; _arguments = arguments; } public override string Format { get { return _format; } } - public override object[] GetArguments() { return _arguments; } + public override object?[] GetArguments() { return _arguments; } public override int ArgumentCount { get { return _arguments.Length; } } - public override object GetArgument(int index) { return _arguments[index]; } - public override string ToString(IFormatProvider formatProvider) { return string.Format(formatProvider, _format, _arguments); } + public override object? GetArgument(int index) { return _arguments[index]; } + public override string ToString(IFormatProvider? formatProvider) { return string.Format(formatProvider, _format, _arguments); } } } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs index 1e64b86..0ddbdb2 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs @@ -56,7 +56,7 @@ namespace System.Runtime.InteropServices Debug.Assert(obj is MemoryManager); if (Unsafe.As>(obj).TryGetArray(out ArraySegment tempArraySegment)) { - segment = new ArraySegment(tempArraySegment.Array, tempArraySegment.Offset + index, length); + segment = new ArraySegment(tempArraySegment.Array!, tempArraySegment.Offset + index, length); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 return true; } } diff --git a/src/System.Private.CoreLib/shared/System/SByte.cs b/src/System.Private.CoreLib/shared/System/SByte.cs index 0ebe882..62db881 100644 --- a/src/System.Private.CoreLib/shared/System/SByte.cs +++ b/src/System.Private.CoreLib/shared/System/SByte.cs @@ -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.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -29,7 +30,7 @@ namespace System // null is considered to be less than any instance. // If object is not of type SByte, this method throws an ArgumentException. // - public int CompareTo(object obj) + public int CompareTo(object? obj) { if (obj == null) { @@ -48,7 +49,7 @@ namespace System } // Determines whether two Byte objects are equal. - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (!(obj is sbyte)) { @@ -76,17 +77,17 @@ namespace System return Number.FormatInt32(m_value, null, null); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { return Number.FormatInt32(m_value, null, provider); } - public string ToString(string format) + public string ToString(string? format) { return ToString(format, null); } - public string ToString(string format, IFormatProvider provider) + public string ToString(string? format, IFormatProvider? provider) { if (m_value < 0 && format != null && format.Length > 0 && (format[0] == 'X' || format[0] == 'x')) { @@ -96,7 +97,7 @@ namespace System return Number.FormatInt32(m_value, format, provider); } - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider provider = null) + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) { if (m_value < 0 && format.Length > 0 && (format[0] == 'X' || format[0] == 'x')) { @@ -122,7 +123,7 @@ namespace System } [CLSCompliant(false)] - public static sbyte Parse(string s, IFormatProvider provider) + public static sbyte Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); @@ -133,7 +134,7 @@ namespace System // NumberFormatInfo is assumed. // [CLSCompliant(false)] - public static sbyte Parse(string s, NumberStyles style, IFormatProvider provider) + public static sbyte Parse(string s, NumberStyles style, IFormatProvider? provider) { NumberFormatInfo.ValidateParseStyleInteger(style); if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); @@ -141,7 +142,7 @@ namespace System } [CLSCompliant(false)] - public static sbyte Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) + public static sbyte Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); return Parse(s, style, NumberFormatInfo.GetInstance(provider)); @@ -171,7 +172,7 @@ namespace System } [CLSCompliant(false)] - public static bool TryParse(string s, out sbyte result) + public static bool TryParse(string? s, out sbyte result) { if (s == null) { @@ -189,7 +190,7 @@ namespace System } [CLSCompliant(false)] - public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out sbyte result) + public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out sbyte result) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -203,7 +204,7 @@ namespace System } [CLSCompliant(false)] - public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out sbyte result) + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out sbyte result) { NumberFormatInfo.ValidateParseStyleInteger(style); return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result); @@ -233,77 +234,77 @@ namespace System } - bool IConvertible.ToBoolean(IFormatProvider provider) + bool IConvertible.ToBoolean(IFormatProvider? provider) { return Convert.ToBoolean(m_value); } - char IConvertible.ToChar(IFormatProvider provider) + char IConvertible.ToChar(IFormatProvider? provider) { return Convert.ToChar(m_value); } - sbyte IConvertible.ToSByte(IFormatProvider provider) + sbyte IConvertible.ToSByte(IFormatProvider? provider) { return m_value; } - byte IConvertible.ToByte(IFormatProvider provider) + byte IConvertible.ToByte(IFormatProvider? provider) { return Convert.ToByte(m_value); } - short IConvertible.ToInt16(IFormatProvider provider) + short IConvertible.ToInt16(IFormatProvider? provider) { return Convert.ToInt16(m_value); } - ushort IConvertible.ToUInt16(IFormatProvider provider) + ushort IConvertible.ToUInt16(IFormatProvider? provider) { return Convert.ToUInt16(m_value); } - int IConvertible.ToInt32(IFormatProvider provider) + int IConvertible.ToInt32(IFormatProvider? provider) { return m_value; } - uint IConvertible.ToUInt32(IFormatProvider provider) + uint IConvertible.ToUInt32(IFormatProvider? provider) { return Convert.ToUInt32(m_value); } - long IConvertible.ToInt64(IFormatProvider provider) + long IConvertible.ToInt64(IFormatProvider? provider) { return Convert.ToInt64(m_value); } - ulong IConvertible.ToUInt64(IFormatProvider provider) + ulong IConvertible.ToUInt64(IFormatProvider? provider) { return Convert.ToUInt64(m_value); } - float IConvertible.ToSingle(IFormatProvider provider) + float IConvertible.ToSingle(IFormatProvider? provider) { return Convert.ToSingle(m_value); } - double IConvertible.ToDouble(IFormatProvider provider) + double IConvertible.ToDouble(IFormatProvider? provider) { return Convert.ToDouble(m_value); } - decimal IConvertible.ToDecimal(IFormatProvider provider) + decimal IConvertible.ToDecimal(IFormatProvider? provider) { return Convert.ToDecimal(m_value); } - DateTime IConvertible.ToDateTime(IFormatProvider provider) + DateTime IConvertible.ToDateTime(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "SByte", "DateTime")); } - object IConvertible.ToType(Type type, IFormatProvider provider) + object IConvertible.ToType(Type type, IFormatProvider? provider) { return Convert.DefaultToType((IConvertible)this, type, provider); } diff --git a/src/System.Private.CoreLib/shared/System/Security/SecurityElement.cs b/src/System.Private.CoreLib/shared/System/Security/SecurityElement.cs index 974d9a1..05c13c8 100644 --- a/src/System.Private.CoreLib/shared/System/Security/SecurityElement.cs +++ b/src/System.Private.CoreLib/shared/System/Security/SecurityElement.cs @@ -328,12 +328,12 @@ namespace System.Security IEnumerator lhs = _children.GetEnumerator(); IEnumerator rhs = other._children.GetEnumerator(); - SecurityElement e1, e2; + SecurityElement? e1, e2; while (lhs.MoveNext()) { rhs.MoveNext(); - e1 = (SecurityElement)lhs.Current; - e2 = (SecurityElement)rhs.Current; + e1 = (SecurityElement?)lhs.Current; + e2 = (SecurityElement?)rhs.Current; if (e1 == null || !e1.Equal(e2)) return false; } @@ -617,7 +617,7 @@ namespace System.Security // an invalid tag simply won't be found. if (_children == null) return null; - foreach (SecurityElement current in _children) + foreach (SecurityElement? current in _children) { if (current != null && string.Equals(current.Tag, tag)) return current; @@ -639,9 +639,9 @@ namespace System.Security if (_children == null) return null; - foreach (SecurityElement child in Children!) + foreach (SecurityElement? child in Children!) { - string? text = child.SearchForTextOfTag(tag); + string? text = child?.SearchForTextOfTag(tag); if (text != null) return text; } diff --git a/src/System.Private.CoreLib/shared/System/SerializableAttribute.cs b/src/System.Private.CoreLib/shared/System/SerializableAttribute.cs index c256931..9d21d39 100644 --- a/src/System.Private.CoreLib/shared/System/SerializableAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/SerializableAttribute.cs @@ -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 namespace System { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)] diff --git a/src/System.Private.CoreLib/shared/System/StringComparer.cs b/src/System.Private.CoreLib/shared/System/StringComparer.cs index 8fab833..e982a38 100644 --- a/src/System.Private.CoreLib/shared/System/StringComparer.cs +++ b/src/System.Private.CoreLib/shared/System/StringComparer.cs @@ -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.Collections; using System.Collections.Generic; using System.Globalization; @@ -11,7 +12,7 @@ namespace System { [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public abstract class StringComparer : IComparer, IEqualityComparer, IComparer, IEqualityComparer + public abstract class StringComparer : IComparer, IEqualityComparer, IComparer, IEqualityComparer { private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.None); private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.IgnoreCase); @@ -108,7 +109,7 @@ namespace System return new CultureAwareComparer(culture, options); } - public int Compare(object x, object y) + public int Compare(object? x, object? y) { if (x == y) return 0; if (x == null) return -1; @@ -130,7 +131,7 @@ namespace System throw new ArgumentException(SR.Argument_ImplementIComparable); } - public new bool Equals(object x, object y) + public new bool Equals(object? x, object? y) { if (x == y) return true; if (x == null || y == null) return false; @@ -159,9 +160,9 @@ namespace System return obj.GetHashCode(); } - public abstract int Compare(string x, string y); - public abstract bool Equals(string x, string y); - public abstract int GetHashCode(string obj); + public abstract int Compare(string? x, string? y); + public abstract bool Equals(string? x, string? y); + public abstract int GetHashCode(string? obj); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 } [Serializable] @@ -199,7 +200,7 @@ namespace System _options |= ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; } - public override int Compare(string x, string y) + public override int Compare(string? x, string? y) { if (object.ReferenceEquals(x, y)) return 0; if (x == null) return -1; @@ -207,14 +208,14 @@ namespace System return _compareInfo.Compare(x, y, _options); } - public override bool Equals(string x, string y) + public override bool Equals(string? x, string? y) { if (object.ReferenceEquals(x, y)) return true; if (x == null || y == null) return false; return _compareInfo.Compare(x, y, _options) == 0; } - public override int GetHashCode(string obj) + public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 { if (obj == null) { @@ -224,7 +225,7 @@ namespace System } // Equals method for the comparer itself. - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is CultureAwareComparer comparer && @@ -256,7 +257,7 @@ namespace System _ignoreCase = ignoreCase; } - public override int Compare(string x, string y) + public override int Compare(string? x, string? y) { if (ReferenceEquals(x, y)) return 0; @@ -273,7 +274,7 @@ namespace System return string.CompareOrdinal(x, y); } - public override bool Equals(string x, string y) + public override bool Equals(string? x, string? y) { if (ReferenceEquals(x, y)) return true; @@ -291,7 +292,7 @@ namespace System return x.Equals(y); } - public override int GetHashCode(string obj) + public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 { if (obj == null) { @@ -300,14 +301,14 @@ namespace System if (_ignoreCase) { - return obj.GetHashCodeOrdinalIgnoreCase(); + return obj!.GetHashCodeOrdinalIgnoreCase(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } - return obj.GetHashCode(); + return obj!.GetHashCode(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // Equals method for the comparer itself. - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (!(obj is OrdinalComparer comparer)) { @@ -330,17 +331,17 @@ namespace System { } - public override int Compare(string x, string y) => string.CompareOrdinal(x, y); + public override int Compare(string? x, string? y) => string.CompareOrdinal(x, y); - public override bool Equals(string x, string y) => string.Equals(x, y); + public override bool Equals(string? x, string? y) => string.Equals(x, y); - public override int GetHashCode(string obj) + public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 { if (obj == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj); } - return obj.GetHashCode(); + return obj!.GetHashCode(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } public void GetObjectData(SerializationInfo info, StreamingContext context) @@ -357,9 +358,9 @@ namespace System { } - public override int Compare(string x, string y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase); + public override int Compare(string? x, string? y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase); - public override bool Equals(string x, string y) + public override bool Equals(string? x, string? y) { if (ReferenceEquals(x, y)) { @@ -379,13 +380,13 @@ namespace System return CompareInfo.EqualsOrdinalIgnoreCase(ref x.GetRawStringData(), ref y.GetRawStringData(), x.Length); } - public override int GetHashCode(string obj) + public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 { if (obj == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj); } - return obj.GetHashCodeOrdinalIgnoreCase(); + return obj!.GetHashCodeOrdinalIgnoreCase(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } public void GetObjectData(SerializationInfo info, StreamingContext context) diff --git a/src/System.Private.CoreLib/shared/System/StringComparison.cs b/src/System.Private.CoreLib/shared/System/StringComparison.cs index d5c18c8..3f31f33 100644 --- a/src/System.Private.CoreLib/shared/System/StringComparison.cs +++ b/src/System.Private.CoreLib/shared/System/StringComparison.cs @@ -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 namespace System { public enum StringComparison diff --git a/src/System.Private.CoreLib/shared/System/StringSplitOptions.cs b/src/System.Private.CoreLib/shared/System/StringSplitOptions.cs index d702055..3132836 100644 --- a/src/System.Private.CoreLib/shared/System/StringSplitOptions.cs +++ b/src/System.Private.CoreLib/shared/System/StringSplitOptions.cs @@ -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 namespace System { [Flags] diff --git a/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs b/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs index 0133be5..14c9bbe 100644 --- a/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs +++ b/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs @@ -185,7 +185,7 @@ namespace System.Text private static string GetDisplayName(int codePage, int englishNameIndex) { - string displayName = SR.GetResourceString("Globalization_cp_" + codePage.ToString()); + string? displayName = SR.GetResourceString("Globalization_cp_" + codePage.ToString()); if (string.IsNullOrEmpty(displayName)) displayName = s_englishNames.Substring(s_englishNameIndices[englishNameIndex], s_englishNameIndices[englishNameIndex + 1] - s_englishNameIndices[englishNameIndex]); diff --git a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs index 774f92e..a8f1d31 100644 --- a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs @@ -1533,7 +1533,7 @@ namespace System.Text ICustomFormatter? cf = null; if (provider != null) { - cf = (ICustomFormatter)provider.GetFormat(typeof(ICustomFormatter)); + cf = (ICustomFormatter?)provider.GetFormat(typeof(ICustomFormatter)); } while (true) diff --git a/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs b/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs index 8abb989..3528884 100644 --- a/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs @@ -51,7 +51,7 @@ namespace System.Text return true; } - object IEnumerator.Current => _current; + object? IEnumerator.Current => _current; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 void IDisposable.Dispose() { diff --git a/src/System.Private.CoreLib/shared/System/ThreadAttributes.cs b/src/System.Private.CoreLib/shared/System/ThreadAttributes.cs index 6248736..33dd50a 100644 --- a/src/System.Private.CoreLib/shared/System/ThreadAttributes.cs +++ b/src/System.Private.CoreLib/shared/System/ThreadAttributes.cs @@ -8,6 +8,7 @@ ** =============================================================================*/ +#nullable enable namespace System { [AttributeUsage(AttributeTargets.Method)] diff --git a/src/System.Private.CoreLib/shared/System/ThreadStaticAttribute.cs b/src/System.Private.CoreLib/shared/System/ThreadStaticAttribute.cs index c12ac1c..f237ad1 100644 --- a/src/System.Private.CoreLib/shared/System/ThreadStaticAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/ThreadStaticAttribute.cs @@ -13,6 +13,7 @@ ** ===========================================================*/ +#nullable enable using System; namespace System diff --git a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs index 816227b..358b24c 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @@ -445,7 +445,7 @@ namespace System.Threading // Notifications can't exist without values Debug.Assert(nextExecutionCtx!.m_localValues != null); // TODO-NULLABLE: Compiler can't see that we're only here when this is non-null // No previous values, so just check current against null - foreach (IAsyncLocal local in nextChangeNotifications!) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34665 + foreach (IAsyncLocal local in nextChangeNotifications!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 { nextExecutionCtx.m_localValues.TryGetValue(local, out object? currentValue); if (currentValue != null) diff --git a/src/System.Private.CoreLib/shared/System/Threading/Thread.cs b/src/System.Private.CoreLib/shared/System/Threading/Thread.cs index 3a64d01..183f5b2 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Thread.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Thread.cs @@ -323,7 +323,7 @@ namespace System.Threading public static LocalDataStoreSlot AllocateSlot() { - return new LocalDataStoreSlot(new ThreadLocal()); + return new LocalDataStoreSlot(new ThreadLocal()); } private static Dictionary EnsureNameToSlotMap() diff --git a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs index 4185382..5391910 100644 --- a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs +++ b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs @@ -35,6 +35,7 @@ // multiple times for different instantiation. // +#nullable enable using System.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -120,16 +121,16 @@ namespace System internal static void ThrowWrongKeyTypeArgumentException(T key, Type targetType) { // Generic key to move the boxing to the right hand side of throw - throw GetWrongKeyTypeArgumentException((object)key, targetType); + throw GetWrongKeyTypeArgumentException((object?)key, targetType); } internal static void ThrowWrongValueTypeArgumentException(T value, Type targetType) { // Generic key to move the boxing to the right hand side of throw - throw GetWrongValueTypeArgumentException((object)value, targetType); + throw GetWrongValueTypeArgumentException((object?)value, targetType); } - private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object key) + private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object? key) { return new ArgumentException(SR.Format(SR.Argument_AddingDuplicateWithKey, key)); } @@ -137,13 +138,13 @@ namespace System internal static void ThrowAddingDuplicateWithKeyArgumentException(T key) { // Generic key to move the boxing to the right hand side of throw - throw GetAddingDuplicateWithKeyArgumentException((object)key); + throw GetAddingDuplicateWithKeyArgumentException((object?)key); } internal static void ThrowKeyNotFoundException(T key) { // Generic key to move the boxing to the right hand side of throw - throw GetKeyNotFoundException((object)key); + throw GetKeyNotFoundException((object?)key); } internal static void ThrowArgumentException(ExceptionResource resource) @@ -311,7 +312,7 @@ namespace System throw new InvalidOperationException(SR.InvalidOperation_HandleIsNotPinned); } - internal static void ThrowArraySegmentCtorValidationFailedExceptions(Array array, int offset, int count) + internal static void ThrowArraySegmentCtorValidationFailedExceptions(Array? array, int offset, int count) { throw GetArraySegmentCtorValidationFailedException(array, offset, count); } @@ -331,7 +332,7 @@ namespace System throw new ArgumentOutOfRangeException("symbol", SR.Argument_BadFormatSpecifier); } - private static Exception GetArraySegmentCtorValidationFailedException(Array array, int offset, int count) + private static Exception GetArraySegmentCtorValidationFailedException(Array? array, int offset, int count) { if (array == null) return new ArgumentNullException(nameof(array)); @@ -354,17 +355,17 @@ namespace System return new InvalidOperationException(GetResourceString(resource)); } - private static ArgumentException GetWrongKeyTypeArgumentException(object key, Type targetType) + private static ArgumentException GetWrongKeyTypeArgumentException(object? key, Type targetType) { return new ArgumentException(SR.Format(SR.Arg_WrongType, key, targetType), nameof(key)); } - private static ArgumentException GetWrongValueTypeArgumentException(object value, Type targetType) + private static ArgumentException GetWrongValueTypeArgumentException(object? value, Type targetType) { return new ArgumentException(SR.Format(SR.Arg_WrongType, value, targetType), nameof(value)); } - private static KeyNotFoundException GetKeyNotFoundException(object key) + private static KeyNotFoundException GetKeyNotFoundException(object? key) { return new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key)); } @@ -399,7 +400,7 @@ namespace System internal static void IfNullAndNullsAreIllegalThenThrow(object value, ExceptionArgument argName) { // Note that default(T) is not equal to null for value types except when T is Nullable. - if (!(default(T) == null) && value == null) + if (!(default(T)! == null) && value == null) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 ThrowHelper.ThrowArgumentNullException(argName); } diff --git a/src/System.Private.CoreLib/shared/System/TimeSpan.cs b/src/System.Private.CoreLib/shared/System/TimeSpan.cs index dd532a2..2f5c4ed 100644 --- a/src/System.Private.CoreLib/shared/System/TimeSpan.cs +++ b/src/System.Private.CoreLib/shared/System/TimeSpan.cs @@ -2,10 +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. -using System.Text; -using System; -using System.Runtime; -using System.Runtime.CompilerServices; +#nullable enable using System.Globalization; namespace System @@ -178,7 +175,7 @@ namespace System } // Returns a value less than zero if this object - public int CompareTo(object value) + public int CompareTo(object? value) { if (value == null) return 1; if (!(value is TimeSpan)) @@ -209,7 +206,7 @@ namespace System return new TimeSpan(_ticks >= 0 ? _ticks : -_ticks); } - public override bool Equals(object value) + public override bool Equals(object? value) { if (value is TimeSpan) { @@ -316,27 +313,27 @@ namespace System /* Constructs a TimeSpan from a string. Leading and trailing white space characters are allowed. */ return TimeSpanParse.Parse(s, null); } - public static TimeSpan Parse(string input, IFormatProvider formatProvider) + public static TimeSpan Parse(string input, IFormatProvider? formatProvider) { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); return TimeSpanParse.Parse(input, formatProvider); } - public static TimeSpan Parse(ReadOnlySpan input, IFormatProvider formatProvider = null) + public static TimeSpan Parse(ReadOnlySpan input, IFormatProvider? formatProvider = null) { return TimeSpanParse.Parse(input, formatProvider); } - public static TimeSpan ParseExact(string input, string format, IFormatProvider formatProvider) + public static TimeSpan ParseExact(string input, string format, IFormatProvider? formatProvider) { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format); return TimeSpanParse.ParseExact(input, format, formatProvider, TimeSpanStyles.None); } - public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider formatProvider) + public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider? formatProvider) { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None); } - public static TimeSpan ParseExact(string input, string format, IFormatProvider formatProvider, TimeSpanStyles styles) + public static TimeSpan ParseExact(string input, string format, IFormatProvider? formatProvider, TimeSpanStyles styles) { ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); @@ -344,23 +341,23 @@ namespace System return TimeSpanParse.ParseExact(input, format, formatProvider, styles); } - public static TimeSpan ParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider formatProvider, TimeSpanStyles styles = TimeSpanStyles.None) + public static TimeSpan ParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider? formatProvider, TimeSpanStyles styles = TimeSpanStyles.None) { ValidateStyles(styles, nameof(styles)); return TimeSpanParse.ParseExact(input, format, formatProvider, styles); } - public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles) + public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles) { ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles); } - public static TimeSpan ParseExact(ReadOnlySpan input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles = TimeSpanStyles.None) + public static TimeSpan ParseExact(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles = TimeSpanStyles.None) { ValidateStyles(styles, nameof(styles)); return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles); } - public static bool TryParse(string s, out TimeSpan result) + public static bool TryParse(string? s, out TimeSpan result) { if (s == null) { @@ -374,7 +371,7 @@ namespace System return TimeSpanParse.TryParse(s, null, out result); } - public static bool TryParse(string input, IFormatProvider formatProvider, out TimeSpan result) + public static bool TryParse(string? input, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null) { @@ -383,11 +380,11 @@ namespace System } return TimeSpanParse.TryParse(input, formatProvider, out result); } - public static bool TryParse(ReadOnlySpan input, IFormatProvider formatProvider, out TimeSpan result) + public static bool TryParse(ReadOnlySpan input, IFormatProvider? formatProvider, out TimeSpan result) { return TimeSpanParse.TryParse(input, formatProvider, out result); } - public static bool TryParseExact(string input, string format, IFormatProvider formatProvider, out TimeSpan result) + public static bool TryParseExact(string? input, string? format, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null || format == null) { @@ -397,11 +394,11 @@ namespace System return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider formatProvider, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider? formatProvider, out TimeSpan result) { return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(string input, string[] formats, IFormatProvider formatProvider, out TimeSpan result) + public static bool TryParseExact(string? input, string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null) { @@ -410,12 +407,12 @@ namespace System } return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(ReadOnlySpan input, string[] formats, IFormatProvider formatProvider, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) { return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(string input, string format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact(string? input, string? format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); if (input == null || format == null) @@ -427,12 +424,12 @@ namespace System return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result); } - public static bool TryParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result); } - public static bool TryParseExact(string input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact(string? input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); if (input == null) @@ -443,7 +440,7 @@ namespace System return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); } - public static bool TryParseExact(ReadOnlySpan input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); @@ -452,16 +449,16 @@ namespace System { return TimeSpanFormat.FormatC(this); } - public string ToString(string format) + public string ToString(string? format) { return TimeSpanFormat.Format(this, format, null); } - public string ToString(string format, IFormatProvider formatProvider) + public string ToString(string? format, IFormatProvider? formatProvider) { return TimeSpanFormat.Format(this, format, formatProvider); } - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider formatProvider = null) + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? formatProvider = null) { return TimeSpanFormat.TryFormat(this, destination, out charsWritten, format, formatProvider); } diff --git a/src/System.Private.CoreLib/shared/System/TimeZone.cs b/src/System.Private.CoreLib/shared/System/TimeZone.cs index 010db80..20d2b61 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZone.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZone.cs @@ -18,6 +18,7 @@ ** ============================================================*/ +#nullable enable using System; using System.Text; using System.Threading; @@ -29,10 +30,10 @@ namespace System [Obsolete("System.TimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo instead.")] public abstract class TimeZone { - private static volatile TimeZone currentTimeZone = null; + private static volatile TimeZone? currentTimeZone = null; // Private object for locking instead of locking on a public type for SQL reliability work. - private static object s_InternalSyncObject; + private static object? s_InternalSyncObject; private static object InternalSyncObject { get @@ -40,9 +41,9 @@ namespace System if (s_InternalSyncObject == null) { object o = new object(); - Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); + Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); } - return s_InternalSyncObject; + return s_InternalSyncObject!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } } @@ -57,7 +58,7 @@ namespace System { //Grabbing the cached value is required at the top of this function so that //we don't incur a race condition with the ResetTimeZone method below. - TimeZone tz = currentTimeZone; + TimeZone? tz = currentTimeZone; if (tz == null) { lock (InternalSyncObject) diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs index aceb7b9..c3c2c50 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs @@ -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.Runtime.Serialization; namespace System @@ -9,7 +10,7 @@ namespace System public sealed partial class TimeZoneInfo { [Serializable] - public sealed class AdjustmentRule : IEquatable, ISerializable, IDeserializationCallback + public sealed class AdjustmentRule : IEquatable, ISerializable, IDeserializationCallback { private static readonly TimeSpan DaylightDeltaAdjustment = TimeSpan.FromHours(24.0); private static readonly TimeSpan MaxDaylightDelta = TimeSpan.FromHours(12.0); @@ -44,7 +45,7 @@ namespace System (DaylightTransitionStart != default && DaylightTransitionStart.TimeOfDay != DateTime.MinValue) || (DaylightTransitionEnd != default && DaylightTransitionEnd.TimeOfDay != DateTime.MinValue.AddMilliseconds(1)); - public bool Equals(AdjustmentRule other) => + public bool Equals(AdjustmentRule? other) => other != null && _dateStart == other._dateStart && _dateEnd == other._dateEnd && diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs index a0b92ea..7ccdc7c 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs @@ -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.Collections.Generic; using System.Globalization; using System.Runtime.Serialization; @@ -104,7 +105,7 @@ namespace System string displayName = s.GetNextStringValue(); string standardName = s.GetNextStringValue(); string daylightName = s.GetNextStringValue(); - AdjustmentRule[] rules = s.GetNextAdjustmentRuleArrayValue(); + AdjustmentRule[]? rules = s.GetNextAdjustmentRuleArrayValue(); try { @@ -373,13 +374,13 @@ namespace System /// /// Helper function to read an AdjustmentRule[] token. /// - private AdjustmentRule[] GetNextAdjustmentRuleArrayValue() + private AdjustmentRule[]? GetNextAdjustmentRuleArrayValue() { List rules = new List(1); int count = 0; // individual AdjustmentRule array elements do not require semicolons - AdjustmentRule rule = GetNextAdjustmentRuleValue(); + AdjustmentRule? rule = GetNextAdjustmentRuleValue(); while (rule != null) { rules.Add(rule); @@ -404,7 +405,7 @@ namespace System /// /// Helper function to read an AdjustmentRule token. /// - private AdjustmentRule GetNextAdjustmentRuleValue() + private AdjustmentRule? GetNextAdjustmentRuleValue() { // first verify the internal state of the object if (_state == State.EndOfLine) diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.TransitionTime.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.TransitionTime.cs index b937942..87c943d 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.TransitionTime.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.TransitionTime.cs @@ -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.Runtime.Serialization; namespace System @@ -30,7 +31,7 @@ namespace System public bool IsFixedDateRule => _isFixedDateRule; - public override bool Equals(object obj) => + public override bool Equals(object? obj) => obj is TransitionTime && Equals((TransitionTime)obj); public static bool operator ==(TransitionTime t1, TransitionTime t2) => t1.Equals(t2); diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs index 9ca9e9c..78c6894 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs @@ -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.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -32,7 +33,7 @@ namespace System string zoneAbbreviations; bool[] StandardTime; bool[] GmtTime; - string futureTransitionsPosixFormat; + string? futureTransitionsPosixFormat; // parse the raw TZif bytes; this method can throw ArgumentException when the data is malformed. TZif_ParseRaw(data, out t, out dts, out typeOfLocalTime, out transitionType, out zoneAbbreviations, out StandardTime, out GmtTime, out futureTransitionsPosixFormat); @@ -106,7 +107,7 @@ namespace System ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); } - private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, ref string displayName) + private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, ref string? displayName) { if (GlobalizationMode.Invariant) { @@ -182,9 +183,7 @@ namespace System string timeZoneDirectory = GetTimeZoneDirectory(); foreach (string timeZoneId in GetTimeZoneIds(timeZoneDirectory)) { - TimeZoneInfo value; - Exception ex; - TryGetTimeZone(timeZoneId, false, out value, out ex, cachedData, alwaysFallbackToLocalMachine: true); // populate the cache + TryGetTimeZone(timeZoneId, false, out _, out _, cachedData, alwaysFallbackToLocalMachine: true); // populate the cache } } @@ -202,7 +201,7 @@ namespace System return GetLocalTimeZoneFromTzFile(); } - private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo value, out Exception e) + private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo? value, out Exception? e) { value = null; e = null; @@ -309,11 +308,11 @@ namespace System /// 3. Look for the data in GetTimeZoneDirectory()/localtime. /// 4. Use UTC if all else fails. /// - private static bool TryGetLocalTzFile(out byte[] rawData, out string id) + private static bool TryGetLocalTzFile(out byte[]? rawData, out string? id) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { rawData = null; id = null; - string tzVariable = GetTzEnvironmentVariable(); + string? tzVariable = GetTzEnvironmentVariable(); // If the env var is null, use the localtime file if (tzVariable == null) @@ -344,9 +343,9 @@ namespace System return TryLoadTzFile(tzFilePath, ref rawData, ref id); } - private static string GetTzEnvironmentVariable() + private static string? GetTzEnvironmentVariable() { - string result = Environment.GetEnvironmentVariable(TimeZoneEnvironmentVariable); + string? result = Environment.GetEnvironmentVariable(TimeZoneEnvironmentVariable); if (!string.IsNullOrEmpty(result)) { if (result[0] == ':') @@ -359,7 +358,7 @@ namespace System return result; } - private static bool TryLoadTzFile(string tzFilePath, ref byte[] rawData, ref string id) + private static bool TryLoadTzFile(string tzFilePath, ref byte[]? rawData, ref string? id) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { if (File.Exists(tzFilePath)) { @@ -388,15 +387,15 @@ namespace System /// Finds the time zone id by using 'readlink' on the path to see if tzFilePath is /// a symlink to a file. /// - private static string FindTimeZoneIdUsingReadLink(string tzFilePath) + private static string? FindTimeZoneIdUsingReadLink(string tzFilePath) { - string id = null; + string? id = null; - string symlinkPath = Interop.Sys.ReadLink(tzFilePath); + string? symlinkPath = Interop.Sys.ReadLink(tzFilePath); if (symlinkPath != null) { // symlinkPath can be relative path, use Path to get the full absolute path. - symlinkPath = Path.GetFullPath(symlinkPath, Path.GetDirectoryName(tzFilePath)); + symlinkPath = Path.GetFullPath(symlinkPath, Path.GetDirectoryName(tzFilePath)!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 string timeZoneDirectory = GetTimeZoneDirectory(); if (symlinkPath.StartsWith(timeZoneDirectory, StringComparison.Ordinal)) @@ -408,7 +407,7 @@ namespace System return id; } - private static string GetDirectoryEntryFullPath(ref Interop.Sys.DirectoryEntry dirent, string currentPath) + private static string? GetDirectoryEntryFullPath(ref Interop.Sys.DirectoryEntry dirent, string currentPath) { Span nameBuffer = stackalloc char[Interop.Sys.DirectoryEntry.NameBufferSize]; ReadOnlySpan direntName = dirent.GetName(nameBuffer); @@ -425,10 +424,10 @@ namespace System /// private static unsafe void EnumerateFilesRecursively(string path, Predicate condition) { - List toExplore = null; // List used as a stack + List? toExplore = null; // List used as a stack int bufferSize = Interop.Sys.GetReadDirRBufferSize(); - byte[] dirBuffer = null; + byte[]? dirBuffer = null; try { dirBuffer = ArrayPool.Shared.Rent(bufferSize); @@ -450,7 +449,7 @@ namespace System Interop.Sys.DirectoryEntry dirent; while (Interop.Sys.ReadDirR(dirHandle, dirBufferPtr, bufferSize, out dirent) == 0) { - string fullPath = GetDirectoryEntryFullPath(ref dirent, currentPath); + string? fullPath = GetDirectoryEntryFullPath(ref dirent, currentPath); if (fullPath == null) continue; @@ -614,11 +613,11 @@ namespace System /// private static TimeZoneInfo GetLocalTimeZoneFromTzFile() { - byte[] rawData; - string id; - if (TryGetLocalTzFile(out rawData, out id)) + byte[]? rawData; + string? id; + if (TryGetLocalTzFile(out rawData, out id)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - TimeZoneInfo result = GetTimeZoneFromTzData(rawData, id); + TimeZoneInfo? result = GetTimeZoneFromTzData(rawData!, id!); if (result != null) { return result; @@ -629,7 +628,7 @@ namespace System return Utc; } - private static TimeZoneInfo GetTimeZoneFromTzData(byte[] rawData, string id) + private static TimeZoneInfo? GetTimeZoneFromTzData(byte[] rawData, string id) { if (rawData != null) { @@ -652,7 +651,7 @@ namespace System private static string GetTimeZoneDirectory() { - string tzDirectory = Environment.GetEnvironmentVariable(TimeZoneDirectoryEnvironmentVariable); + string? tzDirectory = Environment.GetEnvironmentVariable(TimeZoneDirectoryEnvironmentVariable); if (tzDirectory == null) { @@ -693,8 +692,8 @@ namespace System throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id)); } - TimeZoneInfo value; - Exception e; + TimeZoneInfo? value; + Exception? e; TimeZoneInfoResult result; @@ -707,7 +706,7 @@ namespace System if (result == TimeZoneInfoResult.Success) { - return value; + return value!; } else if (result == TimeZoneInfoResult.InvalidTimeZoneException) { @@ -862,8 +861,8 @@ namespace System // BSD July 18, 2003 BSD // // - private static void TZif_GenerateAdjustmentRules(out AdjustmentRule[] rules, TimeSpan baseUtcOffset, DateTime[] dts, byte[] typeOfLocalTime, - TZifType[] transitionType, bool[] StandardTime, bool[] GmtTime, string futureTransitionsPosixFormat) + private static void TZif_GenerateAdjustmentRules(out AdjustmentRule[]? rules, TimeSpan baseUtcOffset, DateTime[] dts, byte[] typeOfLocalTime, + TZifType[] transitionType, bool[] StandardTime, bool[] GmtTime, string? futureTransitionsPosixFormat) { rules = null; @@ -886,7 +885,7 @@ namespace System } private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZoneBaseUtcOffset, List rulesList, DateTime[] dts, - byte[] typeOfLocalTime, TZifType[] transitionTypes, bool[] StandardTime, bool[] GmtTime, string futureTransitionsPosixFormat) + byte[] typeOfLocalTime, TZifType[] transitionTypes, bool[] StandardTime, bool[] GmtTime, string? futureTransitionsPosixFormat) { // To generate AdjustmentRules, use the following approach: // The first AdjustmentRule will go from DateTime.MinValue to the first transition time greater than DateTime.MinValue. @@ -987,13 +986,13 @@ namespace System if (!string.IsNullOrEmpty(futureTransitionsPosixFormat)) { - AdjustmentRule r = TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset); + AdjustmentRule? r = TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset); if (r != null) { if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r)) { - NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r); + NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } rulesList.Add(r); @@ -1078,7 +1077,7 @@ namespace System /// /// See http://man7.org/linux/man-pages/man3/tzset.3.html for the format and semantics of this POSX string. /// - private static AdjustmentRule TZif_CreateAdjustmentRuleForPosixFormat(string posixFormat, DateTime startTransitionDate, TimeSpan timeZoneBaseUtcOffset) + private static AdjustmentRule? TZif_CreateAdjustmentRuleForPosixFormat(string posixFormat, DateTime startTransitionDate, TimeSpan timeZoneBaseUtcOffset) { if (TZif_ParsePosixFormat(posixFormat, out ReadOnlySpan standardName, @@ -1506,15 +1505,15 @@ namespace System DateTimeOffset.FromUnixTimeSeconds(unixTime).UtcDateTime; private static void TZif_ParseRaw(byte[] data, out TZifHead t, out DateTime[] dts, out byte[] typeOfLocalTime, out TZifType[] transitionType, - out string zoneAbbreviations, out bool[] StandardTime, out bool[] GmtTime, out string futureTransitionsPosixFormat) + out string zoneAbbreviations, out bool[] StandardTime, out bool[] GmtTime, out string? futureTransitionsPosixFormat) { // initialize the out parameters in case the TZifHead ctor throws - dts = null; - typeOfLocalTime = null; - transitionType = null; + dts = null!; + typeOfLocalTime = null!; + transitionType = null!; zoneAbbreviations = string.Empty; - StandardTime = null; - GmtTime = null; + StandardTime = null!; + GmtTime = null!; futureTransitionsPosixFormat = null; // read in the 44-byte TZ header containing the count/length fields diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs index 4de4ea5..d72ef1d 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs @@ -1,992 +1,986 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Security; -using System.Text; -using System.Threading; - -using Microsoft.Win32.SafeHandles; - -using Internal.Win32; -using Internal.Runtime.CompilerServices; - -using REG_TZI_FORMAT = Interop.Kernel32.REG_TZI_FORMAT; -using TIME_ZONE_INFORMATION = Interop.Kernel32.TIME_ZONE_INFORMATION; -using TIME_DYNAMIC_ZONE_INFORMATION = Interop.Kernel32.TIME_DYNAMIC_ZONE_INFORMATION; - -namespace System -{ - public sealed partial class TimeZoneInfo - { - // registry constants for the 'Time Zones' hive - // - private const string TimeZonesRegistryHive = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"; - private const string DisplayValue = "Display"; - private const string DaylightValue = "Dlt"; - private const string StandardValue = "Std"; - private const string MuiDisplayValue = "MUI_Display"; - private const string MuiDaylightValue = "MUI_Dlt"; - private const string MuiStandardValue = "MUI_Std"; - private const string TimeZoneInfoValue = "TZI"; - private const string FirstEntryValue = "FirstEntry"; - private const string LastEntryValue = "LastEntry"; - - private const int MaxKeyLength = 255; - - private sealed partial class CachedData - { - private static TimeZoneInfo GetCurrentOneYearLocal() - { - // load the data from the OS - TIME_ZONE_INFORMATION timeZoneInformation; - uint result = Interop.Kernel32.GetTimeZoneInformation(out timeZoneInformation); - return result == Interop.Kernel32.TIME_ZONE_ID_INVALID ? - CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId) : - GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled: false); - } - - private volatile OffsetAndRule _oneYearLocalFromUtc; - - public OffsetAndRule GetOneYearLocalFromUtc(int year) - { - OffsetAndRule oneYearLocFromUtc = _oneYearLocalFromUtc; - if (oneYearLocFromUtc == null || oneYearLocFromUtc.Year != year) - { - TimeZoneInfo currentYear = GetCurrentOneYearLocal(); - AdjustmentRule rule = currentYear._adjustmentRules == null ? null : currentYear._adjustmentRules[0]; - oneYearLocFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule); - _oneYearLocalFromUtc = oneYearLocFromUtc; - } - return oneYearLocFromUtc; - } - } - - private sealed class OffsetAndRule - { - public readonly int Year; - public readonly TimeSpan Offset; - public readonly AdjustmentRule Rule; - - public OffsetAndRule(int year, TimeSpan offset, AdjustmentRule rule) - { - Year = year; - Offset = offset; - Rule = rule; - } - } - - /// - /// Returns a cloned array of AdjustmentRule objects - /// - public AdjustmentRule[] GetAdjustmentRules() - { - if (_adjustmentRules == null) - { - return Array.Empty(); - } - - return (AdjustmentRule[])_adjustmentRules.Clone(); - } - - private static void PopulateAllSystemTimeZones(CachedData cachedData) - { - Debug.Assert(Monitor.IsEntered(cachedData)); - - using (RegistryKey reg = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false)) - { - if (reg != null) - { - foreach (string keyName in reg.GetSubKeyNames()) - { - TimeZoneInfo value; - Exception ex; - TryGetTimeZone(keyName, false, out value, out ex, cachedData); // populate the cache - } - } - } - } - - private TimeZoneInfo(in TIME_ZONE_INFORMATION zone, bool dstDisabled) - { - string standardName = zone.GetStandardName(); - if (standardName.Length == 0) - { - _id = LocalId; // the ID must contain at least 1 character - initialize _id to "Local" - } - else - { - _id = standardName; - } - _baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0); - - if (!dstDisabled) - { - // only create the adjustment rule if DST is enabled - REG_TZI_FORMAT regZone = new REG_TZI_FORMAT(zone); - AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Bias); - if (rule != null) - { - _adjustmentRules = new[] { rule }; - } - } - - ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); - _displayName = standardName; - _standardDisplayName = standardName; - _daylightDisplayName = zone.GetDaylightName(); - } - - /// - /// Helper function to check if the current TimeZoneInformation struct does not support DST. - /// This check returns true when the DaylightDate == StandardDate. - /// This check is only meant to be used for "Local". - /// - private static bool CheckDaylightSavingTimeNotSupported(in TIME_ZONE_INFORMATION timeZone) => - timeZone.DaylightDate.Equals(timeZone.StandardDate); - - /// - /// Converts a REG_TZI_FORMAT struct to an AdjustmentRule. - /// - private static AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset) - { - bool supportsDst = timeZoneInformation.StandardDate.Month != 0; - - if (!supportsDst) - { - if (timeZoneInformation.Bias == defaultBaseUtcOffset) - { - // this rule will not contain any information to be used to adjust dates. just ignore it - return null; - } - - return AdjustmentRule.CreateAdjustmentRule( - startDate, - endDate, - TimeSpan.Zero, // no daylight saving transition - TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1), - TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1), - new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), // Bias delta is all what we need from this rule - noDaylightTransitions: false); - } - - // - // Create an AdjustmentRule with TransitionTime objects - // - TransitionTime daylightTransitionStart; - if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, readStartDate: true)) - { - return null; - } - - TransitionTime daylightTransitionEnd; - if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, readStartDate: false)) - { - return null; - } - - if (daylightTransitionStart.Equals(daylightTransitionEnd)) - { - // this happens when the time zone does support DST but the OS has DST disabled - return null; - } - - return AdjustmentRule.CreateAdjustmentRule( - startDate, - endDate, - new TimeSpan(0, -timeZoneInformation.DaylightBias, 0), - daylightTransitionStart, - daylightTransitionEnd, - new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), - noDaylightTransitions: false); - } - - /// - /// Helper function that searches the registry for a time zone entry - /// that matches the TimeZoneInformation struct. - /// - private static string FindIdFromTimeZoneInformation(in TIME_ZONE_INFORMATION timeZone, out bool dstDisabled) - { - dstDisabled = false; - - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false)) - { - if (key == null) - { - return null; - } - - foreach (string keyName in key.GetSubKeyNames()) - { - if (TryCompareTimeZoneInformationToRegistry(timeZone, keyName, out dstDisabled)) - { - return keyName; - } - } - } - - return null; - } - - /// - /// Helper function for retrieving the local system time zone. - /// May throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException. - /// Assumes cachedData lock is taken. - /// - /// A new TimeZoneInfo instance. - private static TimeZoneInfo GetLocalTimeZone(CachedData cachedData) - { - Debug.Assert(Monitor.IsEntered(cachedData)); - - // - // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id" - // - var dynamicTimeZoneInformation = new TIME_DYNAMIC_ZONE_INFORMATION(); - - // call kernel32!GetDynamicTimeZoneInformation... - uint result = Interop.Kernel32.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation); - if (result == Interop.Kernel32.TIME_ZONE_ID_INVALID) - { - // return a dummy entry - return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); - } - - // check to see if we can use the key name returned from the API call - string dynamicTimeZoneKeyName = dynamicTimeZoneInformation.GetTimeZoneKeyName(); - if (dynamicTimeZoneKeyName.Length != 0) - { - TimeZoneInfo zone; - Exception ex; - - if (TryGetTimeZone(dynamicTimeZoneKeyName, dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0, out zone, out ex, cachedData) == TimeZoneInfoResult.Success) - { - // successfully loaded the time zone from the registry - return zone; - } - } - - var timeZoneInformation = new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation); - - // the key name was not returned or it pointed to a bogus entry - search for the entry ourselves - string id = FindIdFromTimeZoneInformation(timeZoneInformation, out bool dstDisabled); - - if (id != null) - { - TimeZoneInfo zone; - Exception ex; - if (TryGetTimeZone(id, dstDisabled, out zone, out ex, cachedData) == TimeZoneInfoResult.Success) - { - // successfully loaded the time zone from the registry - return zone; - } - } - - // We could not find the data in the registry. Fall back to using - // the data from the Win32 API - return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled); - } - - /// - /// Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of - /// try/catch logic for handling the TimeZoneInfo private constructor that takes - /// a TIME_ZONE_INFORMATION structure. - /// - private static TimeZoneInfo GetLocalTimeZoneFromWin32Data(in TIME_ZONE_INFORMATION timeZoneInformation, bool dstDisabled) - { - // first try to create the TimeZoneInfo with the original 'dstDisabled' flag - try - { - return new TimeZoneInfo(timeZoneInformation, dstDisabled); - } - catch (ArgumentException) { } - catch (InvalidTimeZoneException) { } - - // if 'dstDisabled' was false then try passing in 'true' as a last ditch effort - if (!dstDisabled) - { - try - { - return new TimeZoneInfo(timeZoneInformation, dstDisabled: true); - } - catch (ArgumentException) { } - catch (InvalidTimeZoneException) { } - } - - // the data returned from Windows is completely bogus; return a dummy entry - return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); - } - - /// - /// Helper function for retrieving a TimeZoneInfo object by time_zone_name. - /// This function wraps the logic necessary to keep the private - /// SystemTimeZones cache in working order - /// - /// This function will either return a valid TimeZoneInfo instance or - /// it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'. - /// - public static TimeZoneInfo FindSystemTimeZoneById(string id) - { - // Special case for Utc as it will not exist in the dictionary with the rest - // of the system time zones. There is no need to do this check for Local.Id - // since Local is a real time zone that exists in the dictionary cache - if (string.Equals(id, UtcId, StringComparison.OrdinalIgnoreCase)) - { - return Utc; - } - - if (id == null) - { - throw new ArgumentNullException(nameof(id)); - } - if (id.Length == 0 || id.Length > MaxKeyLength || id.Contains('\0')) - { - throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id)); - } - - TimeZoneInfo value; - Exception e; - - TimeZoneInfoResult result; - - CachedData cachedData = s_cachedData; - - lock (cachedData) - { - result = TryGetTimeZone(id, false, out value, out e, cachedData); - } - - if (result == TimeZoneInfoResult.Success) - { - return value; - } - else if (result == TimeZoneInfoResult.InvalidTimeZoneException) - { - throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidRegistryData, id), e); - } - else if (result == TimeZoneInfoResult.SecurityException) - { - throw new SecurityException(SR.Format(SR.Security_CannotReadRegistryData, id), e); - } - else - { - throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id), e); - } - } - - // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone - internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst) - { - bool isDaylightSavings = false; - isAmbiguousLocalDst = false; - TimeSpan baseOffset; - int timeYear = time.Year; - - OffsetAndRule match = s_cachedData.GetOneYearLocalFromUtc(timeYear); - baseOffset = match.Offset; - - if (match.Rule != null) - { - baseOffset = baseOffset + match.Rule.BaseUtcOffsetDelta; - if (match.Rule.HasDaylightSaving) - { - isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, null, out isAmbiguousLocalDst, Local); - baseOffset += (isDaylightSavings ? match.Rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); - } - } - return baseOffset; - } - - /// - /// Converts a REG_TZI_FORMAT struct to a TransitionTime - /// - When the argument 'readStart' is true the corresponding daylightTransitionTimeStart field is read - /// - When the argument 'readStart' is false the corresponding dayightTransitionTimeEnd field is read - /// - private static bool TransitionTimeFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, out TransitionTime transitionTime, bool readStartDate) - { - // - // SYSTEMTIME - - // - // If the time zone does not support daylight saving time or if the caller needs - // to disable daylight saving time, the wMonth member in the SYSTEMTIME structure - // must be zero. If this date is specified, the DaylightDate value in the - // TIME_ZONE_INFORMATION structure must also be specified. Otherwise, the system - // assumes the time zone data is invalid and no changes will be applied. - // - bool supportsDst = (timeZoneInformation.StandardDate.Month != 0); - - if (!supportsDst) - { - transitionTime = default; - return false; - } - - // - // SYSTEMTIME - - // - // * FixedDateRule - - // If the Year member is not zero, the transition date is absolute; it will only occur one time - // - // * FloatingDateRule - - // To select the correct day in the month, set the Year member to zero, the Hour and Minute - // members to the transition time, the DayOfWeek member to the appropriate weekday, and the - // Day member to indicate the occurence of the day of the week within the month (first through fifth). - // - // Using this notation, specify the 2:00a.m. on the first Sunday in April as follows: - // Hour = 2, - // Month = 4, - // DayOfWeek = 0, - // Day = 1. - // - // Specify 2:00a.m. on the last Thursday in October as follows: - // Hour = 2, - // Month = 10, - // DayOfWeek = 4, - // Day = 5. - // - if (readStartDate) - { - // - // read the "daylightTransitionStart" - // - if (timeZoneInformation.DaylightDate.Year == 0) - { - transitionTime = TransitionTime.CreateFloatingDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.DaylightDate.Hour, - timeZoneInformation.DaylightDate.Minute, - timeZoneInformation.DaylightDate.Second, - timeZoneInformation.DaylightDate.Milliseconds), - timeZoneInformation.DaylightDate.Month, - timeZoneInformation.DaylightDate.Day, /* Week 1-5 */ - (DayOfWeek)timeZoneInformation.DaylightDate.DayOfWeek); - } - else - { - transitionTime = TransitionTime.CreateFixedDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.DaylightDate.Hour, - timeZoneInformation.DaylightDate.Minute, - timeZoneInformation.DaylightDate.Second, - timeZoneInformation.DaylightDate.Milliseconds), - timeZoneInformation.DaylightDate.Month, - timeZoneInformation.DaylightDate.Day); - } - } - else - { - // - // read the "daylightTransitionEnd" - // - if (timeZoneInformation.StandardDate.Year == 0) - { - transitionTime = TransitionTime.CreateFloatingDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.StandardDate.Hour, - timeZoneInformation.StandardDate.Minute, - timeZoneInformation.StandardDate.Second, - timeZoneInformation.StandardDate.Milliseconds), - timeZoneInformation.StandardDate.Month, - timeZoneInformation.StandardDate.Day, /* Week 1-5 */ - (DayOfWeek)timeZoneInformation.StandardDate.DayOfWeek); - } - else - { - transitionTime = TransitionTime.CreateFixedDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.StandardDate.Hour, - timeZoneInformation.StandardDate.Minute, - timeZoneInformation.StandardDate.Second, - timeZoneInformation.StandardDate.Milliseconds), - timeZoneInformation.StandardDate.Month, - timeZoneInformation.StandardDate.Day); - } - } - - return true; - } - - /// - /// Helper function that takes: - /// 1. A string representing a time_zone_name registry key name. - /// 2. A REG_TZI_FORMAT struct containing the default rule. - /// 3. An AdjustmentRule[] out-parameter. - /// - private static bool TryCreateAdjustmentRules(string id, in REG_TZI_FORMAT defaultTimeZoneInformation, out AdjustmentRule[] rules, out Exception e, int defaultBaseUtcOffset) - { - rules = null; - e = null; - - try - { - // Optional, Dynamic Time Zone Registry Data - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // - // HKLM - // Software - // Microsoft - // Windows NT - // CurrentVersion - // Time Zones - // - // Dynamic DST - // * "FirstEntry" REG_DWORD "1980" - // First year in the table. If the current year is less than this value, - // this entry will be used for DST boundaries - // * "LastEntry" REG_DWORD "2038" - // Last year in the table. If the current year is greater than this value, - // this entry will be used for DST boundaries" - // * "" REG_BINARY REG_TZI_FORMAT - // * "" REG_BINARY REG_TZI_FORMAT - // * "" REG_BINARY REG_TZI_FORMAT - // - using (RegistryKey dynamicKey = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id + "\\Dynamic DST", writable: false)) - { - if (dynamicKey == null) - { - AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation( - defaultTimeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); - if (rule != null) - { - rules = new[] { rule }; - } - return true; - } - - // - // loop over all of the "\Dynamic DST" hive entries - // - // read FirstEntry {MinValue - (year1, 12, 31)} - // read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)} - // read LastEntry {(yearN, 1, 1) - MaxValue } - - // read the FirstEntry and LastEntry key values (ex: "1980", "2038") - int first = (int)dynamicKey.GetValue(FirstEntryValue, -1); - int last = (int)dynamicKey.GetValue(LastEntryValue, -1); - - if (first == -1 || last == -1 || first > last) - { - return false; - } - - // read the first year entry - REG_TZI_FORMAT dtzi; - - if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, first.ToString(CultureInfo.InvariantCulture), out dtzi)) - { - return false; - } - - if (first == last) - { - // there is just 1 dynamic rule for this time zone. - AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(dtzi, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); - if (rule != null) - { - rules = new[] { rule }; - } - return true; - } - - List rulesList = new List(1); - - // there are more than 1 dynamic rules for this time zone. - AdjustmentRule firstRule = CreateAdjustmentRuleFromTimeZoneInformation( - dtzi, - DateTime.MinValue.Date, // MinValue - new DateTime(first, 12, 31), // December 31, - defaultBaseUtcOffset); - - if (firstRule != null) - { - rulesList.Add(firstRule); - } - - // read the middle year entries - for (int i = first + 1; i < last; i++) - { - if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, i.ToString(CultureInfo.InvariantCulture), out dtzi)) - { - return false; - } - AdjustmentRule middleRule = CreateAdjustmentRuleFromTimeZoneInformation( - dtzi, - new DateTime(i, 1, 1), // January 01, - new DateTime(i, 12, 31), // December 31, - defaultBaseUtcOffset); - - if (middleRule != null) - { - rulesList.Add(middleRule); - } - } - - // read the last year entry - if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, last.ToString(CultureInfo.InvariantCulture), out dtzi)) - { - return false; - } - AdjustmentRule lastRule = CreateAdjustmentRuleFromTimeZoneInformation( - dtzi, - new DateTime(last, 1, 1), // January 01, - DateTime.MaxValue.Date, // MaxValue - defaultBaseUtcOffset); - - if (lastRule != null) - { - rulesList.Add(lastRule); - } - - // convert the List to an AdjustmentRule array - if (rulesList.Count != 0) - { - rules = rulesList.ToArray(); - } - } // end of: using (RegistryKey dynamicKey... - } - catch (InvalidCastException ex) - { - // one of the RegistryKey.GetValue calls could not be cast to an expected value type - e = ex; - return false; - } - catch (ArgumentOutOfRangeException ex) - { - e = ex; - return false; - } - catch (ArgumentException ex) - { - e = ex; - return false; - } - return true; - } - - private static unsafe bool TryGetTimeZoneEntryFromRegistry(RegistryKey key, string name, out REG_TZI_FORMAT dtzi) - { - if (!(key.GetValue(name, null) is byte[] regValue) || regValue.Length != sizeof(REG_TZI_FORMAT)) - { - dtzi = default; - return false; - } - fixed (byte * pBytes = ®Value[0]) - dtzi = *(REG_TZI_FORMAT *)pBytes; - return true; - } - - /// - /// Helper function that compares the StandardBias and StandardDate portion a - /// TimeZoneInformation struct to a time zone registry entry. - /// - private static bool TryCompareStandardDate(in TIME_ZONE_INFORMATION timeZone, in REG_TZI_FORMAT registryTimeZoneInfo) => - timeZone.Bias == registryTimeZoneInfo.Bias && - timeZone.StandardBias == registryTimeZoneInfo.StandardBias && - timeZone.StandardDate.Equals(registryTimeZoneInfo.StandardDate); - - /// - /// Helper function that compares a TimeZoneInformation struct to a time zone registry entry. - /// - private static bool TryCompareTimeZoneInformationToRegistry(in TIME_ZONE_INFORMATION timeZone, string id, out bool dstDisabled) - { - dstDisabled = false; - - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false)) - { - if (key == null) - { - return false; - } - - REG_TZI_FORMAT registryTimeZoneInfo; - if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out registryTimeZoneInfo)) - { - return false; - } - - // - // first compare the bias and standard date information between the data from the Win32 API - // and the data from the registry... - // - bool result = TryCompareStandardDate(timeZone, registryTimeZoneInfo); - - if (!result) - { - return false; - } - - result = dstDisabled || CheckDaylightSavingTimeNotSupported(timeZone) || - // - // since Daylight Saving Time is not "disabled", do a straight comparision between - // the Win32 API data and the registry data ... - // - (timeZone.DaylightBias == registryTimeZoneInfo.DaylightBias && - timeZone.DaylightDate.Equals(registryTimeZoneInfo.DaylightDate)); - - // Finally compare the "StandardName" string value... - // - // we do not compare "DaylightName" as this TimeZoneInformation field may contain - // either "StandardName" or "DaylightName" depending on the time of year and current machine settings - // - if (result) - { - string registryStandardName = key.GetValue(StandardValue, string.Empty) as string; - result = string.Equals(registryStandardName, timeZone.GetStandardName(), StringComparison.Ordinal); - } - return result; - } - } - - /// - /// Helper function for retrieving a localized string resource via MUI. - /// The function expects a string in the form: "@resource.dll, -123" - /// - /// "resource.dll" is a language-neutral portable executable (LNPE) file in - /// the %windir%\system32 directory. The OS is queried to find the best-fit - /// localized resource file for this LNPE (ex: %windir%\system32\en-us\resource.dll.mui). - /// If a localized resource file exists, we LoadString resource ID "123" and - /// return it to our caller. - /// - private static string TryGetLocalizedNameByMuiNativeResource(string resource) - { - if (string.IsNullOrEmpty(resource)) - { - return string.Empty; - } - - // parse "@tzres.dll, -100" - // - // filePath = "C:\Windows\System32\tzres.dll" - // resourceId = -100 - // - string[] resources = resource.Split(','); - if (resources.Length != 2) - { - return string.Empty; - } - - string filePath; - int resourceId; - - // get the path to Windows\System32 - string system32 = Environment.SystemDirectory; - - // trim the string "@tzres.dll" => "tzres.dll" - string tzresDll = resources[0].TrimStart('@'); - - try - { - filePath = Path.Combine(system32, tzresDll); - } - catch (ArgumentException) - { - // there were probably illegal characters in the path - return string.Empty; - } - - if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out resourceId)) - { - return string.Empty; - } - resourceId = -resourceId; - - try - { - unsafe - { - char* fileMuiPath = stackalloc char[Interop.Kernel32.MAX_PATH]; - int fileMuiPathLength = Interop.Kernel32.MAX_PATH; - int languageLength = 0; - long enumerator = 0; - - bool succeeded = Interop.Kernel32.GetFileMUIPath( - Interop.Kernel32.MUI_PREFERRED_UI_LANGUAGES, - filePath, null /* language */, ref languageLength, - fileMuiPath, ref fileMuiPathLength, ref enumerator); - return succeeded ? - TryGetLocalizedNameByNativeResource(new string(fileMuiPath, 0, fileMuiPathLength), resourceId) : - string.Empty; - } - } - catch (EntryPointNotFoundException) - { - return string.Empty; - } - } - - /// - /// Helper function for retrieving a localized string resource via a native resource DLL. - /// The function expects a string in the form: "C:\Windows\System32\en-us\resource.dll" - /// - /// "resource.dll" is a language-specific resource DLL. - /// If the localized resource DLL exists, LoadString(resource) is returned. - /// - private static unsafe string TryGetLocalizedNameByNativeResource(string filePath, int resource) - { - using (SafeLibraryHandle handle = Interop.Kernel32.LoadLibraryEx(filePath, IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_AS_DATAFILE)) - { - if (!handle.IsInvalid) - { - const int LoadStringMaxLength = 500; - char* localizedResource = stackalloc char[LoadStringMaxLength]; - - int charsWritten = Interop.User32.LoadString(handle, (uint)resource, localizedResource, LoadStringMaxLength); - if (charsWritten != 0) - { - return new string(localizedResource, 0, charsWritten); - } - } - } - - return string.Empty; - } - - /// - /// Helper function for retrieving the DisplayName, StandardName, and DaylightName from the registry - /// - /// The function first checks the MUI_ key-values, and if they exist, it loads the strings from the MUI - /// resource dll(s). When the keys do not exist, the function falls back to reading from the standard - /// key-values - /// - private static void GetLocalizedNamesByRegistryKey(RegistryKey key, out string displayName, out string standardName, out string daylightName) - { - displayName = string.Empty; - standardName = string.Empty; - daylightName = string.Empty; - - // read the MUI_ registry keys - string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty) as string; - string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty) as string; - string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty) as string; - - // try to load the strings from the native resource DLL(s) - if (!string.IsNullOrEmpty(displayNameMuiResource)) - { - displayName = TryGetLocalizedNameByMuiNativeResource(displayNameMuiResource); - } - - if (!string.IsNullOrEmpty(standardNameMuiResource)) - { - standardName = TryGetLocalizedNameByMuiNativeResource(standardNameMuiResource); - } - - if (!string.IsNullOrEmpty(daylightNameMuiResource)) - { - daylightName = TryGetLocalizedNameByMuiNativeResource(daylightNameMuiResource); - } - - // fallback to using the standard registry keys - if (string.IsNullOrEmpty(displayName)) - { - displayName = key.GetValue(DisplayValue, string.Empty) as string; - } - if (string.IsNullOrEmpty(standardName)) - { - standardName = key.GetValue(StandardValue, string.Empty) as string; - } - if (string.IsNullOrEmpty(daylightName)) - { - daylightName = key.GetValue(DaylightValue, string.Empty) as string; - } - } - - /// - /// Helper function that takes a string representing a time_zone_name registry key name - /// and returns a TimeZoneInfo instance. - /// - private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo value, out Exception e) - { - e = null; - - // Standard Time Zone Registry Data - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - // HKLM - // Software - // Microsoft - // Windows NT - // CurrentVersion - // Time Zones - // - // * STD, REG_SZ "Standard Time Name" - // (For OS installed zones, this will always be English) - // * MUI_STD, REG_SZ "@tzres.dll,-1234" - // Indirect string to localized resource for Standard Time, - // add "%windir%\system32\" after "@" - // * DLT, REG_SZ "Daylight Time Name" - // (For OS installed zones, this will always be English) - // * MUI_DLT, REG_SZ "@tzres.dll,-1234" - // Indirect string to localized resource for Daylight Time, - // add "%windir%\system32\" after "@" - // * Display, REG_SZ "Display Name like (GMT-8:00) Pacific Time..." - // * MUI_Display, REG_SZ "@tzres.dll,-1234" - // Indirect string to localized resource for the Display, - // add "%windir%\system32\" after "@" - // * TZI, REG_BINARY REG_TZI_FORMAT - // - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false)) - { - if (key == null) - { - value = null; - return TimeZoneInfoResult.TimeZoneNotFoundException; - } - - REG_TZI_FORMAT defaultTimeZoneInformation; - if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out defaultTimeZoneInformation)) - { - // the registry value could not be cast to a byte array - value = null; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - - AdjustmentRule[] adjustmentRules; - if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e, defaultTimeZoneInformation.Bias)) - { - value = null; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - - GetLocalizedNamesByRegistryKey(key, out string displayName, out string standardName, out string daylightName); - - try - { - value = new TimeZoneInfo( - id, - new TimeSpan(0, -(defaultTimeZoneInformation.Bias), 0), - displayName, - standardName, - daylightName, - adjustmentRules, - disableDaylightSavingTime: false); - - return TimeZoneInfoResult.Success; - } - catch (ArgumentException ex) - { - // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException - value = null; - e = ex; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - catch (InvalidTimeZoneException ex) - { - // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException - value = null; - e = ex; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - } - } - } -} +// Licensed to the .NET Foundation under one or more agreements. +// 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.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; + +using Microsoft.Win32.SafeHandles; + +using Internal.Win32; +using Internal.Runtime.CompilerServices; + +using REG_TZI_FORMAT = Interop.Kernel32.REG_TZI_FORMAT; +using TIME_ZONE_INFORMATION = Interop.Kernel32.TIME_ZONE_INFORMATION; +using TIME_DYNAMIC_ZONE_INFORMATION = Interop.Kernel32.TIME_DYNAMIC_ZONE_INFORMATION; + +namespace System +{ + public sealed partial class TimeZoneInfo + { + // registry constants for the 'Time Zones' hive + // + private const string TimeZonesRegistryHive = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"; + private const string DisplayValue = "Display"; + private const string DaylightValue = "Dlt"; + private const string StandardValue = "Std"; + private const string MuiDisplayValue = "MUI_Display"; + private const string MuiDaylightValue = "MUI_Dlt"; + private const string MuiStandardValue = "MUI_Std"; + private const string TimeZoneInfoValue = "TZI"; + private const string FirstEntryValue = "FirstEntry"; + private const string LastEntryValue = "LastEntry"; + + private const int MaxKeyLength = 255; + + private sealed partial class CachedData + { + private static TimeZoneInfo GetCurrentOneYearLocal() + { + // load the data from the OS + TIME_ZONE_INFORMATION timeZoneInformation; + uint result = Interop.Kernel32.GetTimeZoneInformation(out timeZoneInformation); + return result == Interop.Kernel32.TIME_ZONE_ID_INVALID ? + CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId) : + GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled: false); + } + + private volatile OffsetAndRule? _oneYearLocalFromUtc; + + public OffsetAndRule GetOneYearLocalFromUtc(int year) + { + OffsetAndRule? oneYearLocFromUtc = _oneYearLocalFromUtc; + if (oneYearLocFromUtc == null || oneYearLocFromUtc.Year != year) + { + TimeZoneInfo currentYear = GetCurrentOneYearLocal(); + AdjustmentRule? rule = currentYear._adjustmentRules == null ? null : currentYear._adjustmentRules[0]; + oneYearLocFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule); + _oneYearLocalFromUtc = oneYearLocFromUtc; + } + return oneYearLocFromUtc; + } + } + + private sealed class OffsetAndRule + { + public readonly int Year; + public readonly TimeSpan Offset; + public readonly AdjustmentRule? Rule; + + public OffsetAndRule(int year, TimeSpan offset, AdjustmentRule? rule) + { + Year = year; + Offset = offset; + Rule = rule; + } + } + + /// + /// Returns a cloned array of AdjustmentRule objects + /// + public AdjustmentRule[] GetAdjustmentRules() + { + if (_adjustmentRules == null) + { + return Array.Empty(); + } + + return (AdjustmentRule[])_adjustmentRules.Clone(); + } + + private static void PopulateAllSystemTimeZones(CachedData cachedData) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + using (RegistryKey? reg = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false)) + { + if (reg != null) + { + foreach (string keyName in reg.GetSubKeyNames()) + { + TryGetTimeZone(keyName, false, out _, out _, cachedData); // populate the cache + } + } + } + } + + private TimeZoneInfo(in TIME_ZONE_INFORMATION zone, bool dstDisabled) + { + string standardName = zone.GetStandardName(); + if (standardName.Length == 0) + { + _id = LocalId; // the ID must contain at least 1 character - initialize _id to "Local" + } + else + { + _id = standardName; + } + _baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0); + + if (!dstDisabled) + { + // only create the adjustment rule if DST is enabled + REG_TZI_FORMAT regZone = new REG_TZI_FORMAT(zone); + AdjustmentRule? rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Bias); + if (rule != null) + { + _adjustmentRules = new[] { rule }; + } + } + + ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); + _displayName = standardName; + _standardDisplayName = standardName; + _daylightDisplayName = zone.GetDaylightName(); + } + + /// + /// Helper function to check if the current TimeZoneInformation struct does not support DST. + /// This check returns true when the DaylightDate == StandardDate. + /// This check is only meant to be used for "Local". + /// + private static bool CheckDaylightSavingTimeNotSupported(in TIME_ZONE_INFORMATION timeZone) => + timeZone.DaylightDate.Equals(timeZone.StandardDate); + + /// + /// Converts a REG_TZI_FORMAT struct to an AdjustmentRule. + /// + private static AdjustmentRule? CreateAdjustmentRuleFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset) + { + bool supportsDst = timeZoneInformation.StandardDate.Month != 0; + + if (!supportsDst) + { + if (timeZoneInformation.Bias == defaultBaseUtcOffset) + { + // this rule will not contain any information to be used to adjust dates. just ignore it + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + TimeSpan.Zero, // no daylight saving transition + TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1), + TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1), + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), // Bias delta is all what we need from this rule + noDaylightTransitions: false); + } + + // + // Create an AdjustmentRule with TransitionTime objects + // + TransitionTime daylightTransitionStart; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, readStartDate: true)) + { + return null; + } + + TransitionTime daylightTransitionEnd; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, readStartDate: false)) + { + return null; + } + + if (daylightTransitionStart.Equals(daylightTransitionEnd)) + { + // this happens when the time zone does support DST but the OS has DST disabled + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + new TimeSpan(0, -timeZoneInformation.DaylightBias, 0), + daylightTransitionStart, + daylightTransitionEnd, + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), + noDaylightTransitions: false); + } + + /// + /// Helper function that searches the registry for a time zone entry + /// that matches the TimeZoneInformation struct. + /// + private static string? FindIdFromTimeZoneInformation(in TIME_ZONE_INFORMATION timeZone, out bool dstDisabled) + { + dstDisabled = false; + + using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false)) + { + if (key == null) + { + return null; + } + + foreach (string keyName in key.GetSubKeyNames()) + { + if (TryCompareTimeZoneInformationToRegistry(timeZone, keyName, out dstDisabled)) + { + return keyName; + } + } + } + + return null; + } + + /// + /// Helper function for retrieving the local system time zone. + /// May throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException. + /// Assumes cachedData lock is taken. + /// + /// A new TimeZoneInfo instance. + private static TimeZoneInfo GetLocalTimeZone(CachedData cachedData) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + // + // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id" + // + var dynamicTimeZoneInformation = new TIME_DYNAMIC_ZONE_INFORMATION(); + + // call kernel32!GetDynamicTimeZoneInformation... + uint result = Interop.Kernel32.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation); + if (result == Interop.Kernel32.TIME_ZONE_ID_INVALID) + { + // return a dummy entry + return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); + } + + // check to see if we can use the key name returned from the API call + string dynamicTimeZoneKeyName = dynamicTimeZoneInformation.GetTimeZoneKeyName(); + if (dynamicTimeZoneKeyName.Length != 0) + { + if (TryGetTimeZone(dynamicTimeZoneKeyName, dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0, out TimeZoneInfo? zone, out _, cachedData) == TimeZoneInfoResult.Success) + { + // successfully loaded the time zone from the registry + return zone!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + } + } + + var timeZoneInformation = new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation); + + // the key name was not returned or it pointed to a bogus entry - search for the entry ourselves + string? id = FindIdFromTimeZoneInformation(timeZoneInformation, out bool dstDisabled); + + if (id != null) + { + if (TryGetTimeZone(id, dstDisabled, out TimeZoneInfo? zone, out _, cachedData) == TimeZoneInfoResult.Success) + { + // successfully loaded the time zone from the registry + return zone!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + } + } + + // We could not find the data in the registry. Fall back to using + // the data from the Win32 API + return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled); + } + + /// + /// Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of + /// try/catch logic for handling the TimeZoneInfo private constructor that takes + /// a TIME_ZONE_INFORMATION structure. + /// + private static TimeZoneInfo GetLocalTimeZoneFromWin32Data(in TIME_ZONE_INFORMATION timeZoneInformation, bool dstDisabled) + { + // first try to create the TimeZoneInfo with the original 'dstDisabled' flag + try + { + return new TimeZoneInfo(timeZoneInformation, dstDisabled); + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + + // if 'dstDisabled' was false then try passing in 'true' as a last ditch effort + if (!dstDisabled) + { + try + { + return new TimeZoneInfo(timeZoneInformation, dstDisabled: true); + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + } + + // the data returned from Windows is completely bogus; return a dummy entry + return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); + } + + /// + /// Helper function for retrieving a TimeZoneInfo object by time_zone_name. + /// This function wraps the logic necessary to keep the private + /// SystemTimeZones cache in working order + /// + /// This function will either return a valid TimeZoneInfo instance or + /// it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'. + /// + public static TimeZoneInfo FindSystemTimeZoneById(string id) + { + // Special case for Utc as it will not exist in the dictionary with the rest + // of the system time zones. There is no need to do this check for Local.Id + // since Local is a real time zone that exists in the dictionary cache + if (string.Equals(id, UtcId, StringComparison.OrdinalIgnoreCase)) + { + return Utc; + } + + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (id.Length == 0 || id.Length > MaxKeyLength || id.Contains('\0')) + { + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id)); + } + + TimeZoneInfo? value; + Exception? e; + + TimeZoneInfoResult result; + + CachedData cachedData = s_cachedData; + + lock (cachedData) + { + result = TryGetTimeZone(id, false, out value, out e, cachedData); + } + + if (result == TimeZoneInfoResult.Success) + { + return value!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + } + else if (result == TimeZoneInfoResult.InvalidTimeZoneException) + { + throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidRegistryData, id), e); + } + else if (result == TimeZoneInfoResult.SecurityException) + { + throw new SecurityException(SR.Format(SR.Security_CannotReadRegistryData, id), e); + } + else + { + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id), e); + } + } + + // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone + internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst) + { + bool isDaylightSavings = false; + isAmbiguousLocalDst = false; + TimeSpan baseOffset; + int timeYear = time.Year; + + OffsetAndRule match = s_cachedData.GetOneYearLocalFromUtc(timeYear); + baseOffset = match.Offset; + + if (match.Rule != null) + { + baseOffset = baseOffset + match.Rule.BaseUtcOffsetDelta; + if (match.Rule.HasDaylightSaving) + { + isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, null, out isAmbiguousLocalDst, Local); + baseOffset += (isDaylightSavings ? match.Rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); + } + } + return baseOffset; + } + + /// + /// Converts a REG_TZI_FORMAT struct to a TransitionTime + /// - When the argument 'readStart' is true the corresponding daylightTransitionTimeStart field is read + /// - When the argument 'readStart' is false the corresponding dayightTransitionTimeEnd field is read + /// + private static bool TransitionTimeFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, out TransitionTime transitionTime, bool readStartDate) + { + // + // SYSTEMTIME - + // + // If the time zone does not support daylight saving time or if the caller needs + // to disable daylight saving time, the wMonth member in the SYSTEMTIME structure + // must be zero. If this date is specified, the DaylightDate value in the + // TIME_ZONE_INFORMATION structure must also be specified. Otherwise, the system + // assumes the time zone data is invalid and no changes will be applied. + // + bool supportsDst = (timeZoneInformation.StandardDate.Month != 0); + + if (!supportsDst) + { + transitionTime = default; + return false; + } + + // + // SYSTEMTIME - + // + // * FixedDateRule - + // If the Year member is not zero, the transition date is absolute; it will only occur one time + // + // * FloatingDateRule - + // To select the correct day in the month, set the Year member to zero, the Hour and Minute + // members to the transition time, the DayOfWeek member to the appropriate weekday, and the + // Day member to indicate the occurence of the day of the week within the month (first through fifth). + // + // Using this notation, specify the 2:00a.m. on the first Sunday in April as follows: + // Hour = 2, + // Month = 4, + // DayOfWeek = 0, + // Day = 1. + // + // Specify 2:00a.m. on the last Thursday in October as follows: + // Hour = 2, + // Month = 10, + // DayOfWeek = 4, + // Day = 5. + // + if (readStartDate) + { + // + // read the "daylightTransitionStart" + // + if (timeZoneInformation.DaylightDate.Year == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.DaylightDate.Hour, + timeZoneInformation.DaylightDate.Minute, + timeZoneInformation.DaylightDate.Second, + timeZoneInformation.DaylightDate.Milliseconds), + timeZoneInformation.DaylightDate.Month, + timeZoneInformation.DaylightDate.Day, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.DaylightDate.DayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.DaylightDate.Hour, + timeZoneInformation.DaylightDate.Minute, + timeZoneInformation.DaylightDate.Second, + timeZoneInformation.DaylightDate.Milliseconds), + timeZoneInformation.DaylightDate.Month, + timeZoneInformation.DaylightDate.Day); + } + } + else + { + // + // read the "daylightTransitionEnd" + // + if (timeZoneInformation.StandardDate.Year == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.StandardDate.Hour, + timeZoneInformation.StandardDate.Minute, + timeZoneInformation.StandardDate.Second, + timeZoneInformation.StandardDate.Milliseconds), + timeZoneInformation.StandardDate.Month, + timeZoneInformation.StandardDate.Day, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.StandardDate.DayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.StandardDate.Hour, + timeZoneInformation.StandardDate.Minute, + timeZoneInformation.StandardDate.Second, + timeZoneInformation.StandardDate.Milliseconds), + timeZoneInformation.StandardDate.Month, + timeZoneInformation.StandardDate.Day); + } + } + + return true; + } + + /// + /// Helper function that takes: + /// 1. A string representing a time_zone_name registry key name. + /// 2. A REG_TZI_FORMAT struct containing the default rule. + /// 3. An AdjustmentRule[] out-parameter. + /// + private static bool TryCreateAdjustmentRules(string id, in REG_TZI_FORMAT defaultTimeZoneInformation, out AdjustmentRule[]? rules, out Exception? e, int defaultBaseUtcOffset) + { + rules = null; + e = null; + + try + { + // Optional, Dynamic Time Zone Registry Data + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + // + // HKLM + // Software + // Microsoft + // Windows NT + // CurrentVersion + // Time Zones + // + // Dynamic DST + // * "FirstEntry" REG_DWORD "1980" + // First year in the table. If the current year is less than this value, + // this entry will be used for DST boundaries + // * "LastEntry" REG_DWORD "2038" + // Last year in the table. If the current year is greater than this value, + // this entry will be used for DST boundaries" + // * "" REG_BINARY REG_TZI_FORMAT + // * "" REG_BINARY REG_TZI_FORMAT + // * "" REG_BINARY REG_TZI_FORMAT + // + using (RegistryKey? dynamicKey = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id + "\\Dynamic DST", writable: false)) + { + if (dynamicKey == null) + { + AdjustmentRule? rule = CreateAdjustmentRuleFromTimeZoneInformation( + defaultTimeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); + if (rule != null) + { + rules = new[] { rule }; + } + return true; + } + + // + // loop over all of the "\Dynamic DST" hive entries + // + // read FirstEntry {MinValue - (year1, 12, 31)} + // read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)} + // read LastEntry {(yearN, 1, 1) - MaxValue } + + // read the FirstEntry and LastEntry key values (ex: "1980", "2038") + int first = (int)dynamicKey.GetValue(FirstEntryValue, -1); + int last = (int)dynamicKey.GetValue(LastEntryValue, -1); + + if (first == -1 || last == -1 || first > last) + { + return false; + } + + // read the first year entry + REG_TZI_FORMAT dtzi; + + if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, first.ToString(CultureInfo.InvariantCulture), out dtzi)) + { + return false; + } + + if (first == last) + { + // there is just 1 dynamic rule for this time zone. + AdjustmentRule? rule = CreateAdjustmentRuleFromTimeZoneInformation(dtzi, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); + if (rule != null) + { + rules = new[] { rule }; + } + return true; + } + + List rulesList = new List(1); + + // there are more than 1 dynamic rules for this time zone. + AdjustmentRule? firstRule = CreateAdjustmentRuleFromTimeZoneInformation( + dtzi, + DateTime.MinValue.Date, // MinValue + new DateTime(first, 12, 31), // December 31, + defaultBaseUtcOffset); + + if (firstRule != null) + { + rulesList.Add(firstRule); + } + + // read the middle year entries + for (int i = first + 1; i < last; i++) + { + if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, i.ToString(CultureInfo.InvariantCulture), out dtzi)) + { + return false; + } + AdjustmentRule? middleRule = CreateAdjustmentRuleFromTimeZoneInformation( + dtzi, + new DateTime(i, 1, 1), // January 01, + new DateTime(i, 12, 31), // December 31, + defaultBaseUtcOffset); + + if (middleRule != null) + { + rulesList.Add(middleRule); + } + } + + // read the last year entry + if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, last.ToString(CultureInfo.InvariantCulture), out dtzi)) + { + return false; + } + AdjustmentRule? lastRule = CreateAdjustmentRuleFromTimeZoneInformation( + dtzi, + new DateTime(last, 1, 1), // January 01, + DateTime.MaxValue.Date, // MaxValue + defaultBaseUtcOffset); + + if (lastRule != null) + { + rulesList.Add(lastRule); + } + + // convert the List to an AdjustmentRule array + if (rulesList.Count != 0) + { + rules = rulesList.ToArray(); + } + } // end of: using (RegistryKey dynamicKey... + } + catch (InvalidCastException ex) + { + // one of the RegistryKey.GetValue calls could not be cast to an expected value type + e = ex; + return false; + } + catch (ArgumentOutOfRangeException ex) + { + e = ex; + return false; + } + catch (ArgumentException ex) + { + e = ex; + return false; + } + return true; + } + + private static unsafe bool TryGetTimeZoneEntryFromRegistry(RegistryKey key, string name, out REG_TZI_FORMAT dtzi) + { + if (!(key.GetValue(name, null) is byte[] regValue) || regValue.Length != sizeof(REG_TZI_FORMAT)) + { + dtzi = default; + return false; + } + fixed (byte * pBytes = ®Value[0]) + dtzi = *(REG_TZI_FORMAT *)pBytes; + return true; + } + + /// + /// Helper function that compares the StandardBias and StandardDate portion a + /// TimeZoneInformation struct to a time zone registry entry. + /// + private static bool TryCompareStandardDate(in TIME_ZONE_INFORMATION timeZone, in REG_TZI_FORMAT registryTimeZoneInfo) => + timeZone.Bias == registryTimeZoneInfo.Bias && + timeZone.StandardBias == registryTimeZoneInfo.StandardBias && + timeZone.StandardDate.Equals(registryTimeZoneInfo.StandardDate); + + /// + /// Helper function that compares a TimeZoneInformation struct to a time zone registry entry. + /// + private static bool TryCompareTimeZoneInformationToRegistry(in TIME_ZONE_INFORMATION timeZone, string id, out bool dstDisabled) + { + dstDisabled = false; + + using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false)) + { + if (key == null) + { + return false; + } + + REG_TZI_FORMAT registryTimeZoneInfo; + if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out registryTimeZoneInfo)) + { + return false; + } + + // + // first compare the bias and standard date information between the data from the Win32 API + // and the data from the registry... + // + bool result = TryCompareStandardDate(timeZone, registryTimeZoneInfo); + + if (!result) + { + return false; + } + + result = dstDisabled || CheckDaylightSavingTimeNotSupported(timeZone) || + // + // since Daylight Saving Time is not "disabled", do a straight comparision between + // the Win32 API data and the registry data ... + // + (timeZone.DaylightBias == registryTimeZoneInfo.DaylightBias && + timeZone.DaylightDate.Equals(registryTimeZoneInfo.DaylightDate)); + + // Finally compare the "StandardName" string value... + // + // we do not compare "DaylightName" as this TimeZoneInformation field may contain + // either "StandardName" or "DaylightName" depending on the time of year and current machine settings + // + if (result) + { + string? registryStandardName = key.GetValue(StandardValue, string.Empty) as string; + result = string.Equals(registryStandardName, timeZone.GetStandardName(), StringComparison.Ordinal); + } + return result; + } + } + + /// + /// Helper function for retrieving a localized string resource via MUI. + /// The function expects a string in the form: "@resource.dll, -123" + /// + /// "resource.dll" is a language-neutral portable executable (LNPE) file in + /// the %windir%\system32 directory. The OS is queried to find the best-fit + /// localized resource file for this LNPE (ex: %windir%\system32\en-us\resource.dll.mui). + /// If a localized resource file exists, we LoadString resource ID "123" and + /// return it to our caller. + /// + private static string TryGetLocalizedNameByMuiNativeResource(string resource) + { + if (string.IsNullOrEmpty(resource)) + { + return string.Empty; + } + + // parse "@tzres.dll, -100" + // + // filePath = "C:\Windows\System32\tzres.dll" + // resourceId = -100 + // + string[] resources = resource.Split(','); + if (resources.Length != 2) + { + return string.Empty; + } + + string filePath; + int resourceId; + + // get the path to Windows\System32 + string system32 = Environment.SystemDirectory; + + // trim the string "@tzres.dll" => "tzres.dll" + string tzresDll = resources[0].TrimStart('@'); + + try + { + filePath = Path.Combine(system32, tzresDll); + } + catch (ArgumentException) + { + // there were probably illegal characters in the path + return string.Empty; + } + + if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out resourceId)) + { + return string.Empty; + } + resourceId = -resourceId; + + try + { + unsafe + { + char* fileMuiPath = stackalloc char[Interop.Kernel32.MAX_PATH]; + int fileMuiPathLength = Interop.Kernel32.MAX_PATH; + int languageLength = 0; + long enumerator = 0; + + bool succeeded = Interop.Kernel32.GetFileMUIPath( + Interop.Kernel32.MUI_PREFERRED_UI_LANGUAGES, + filePath, null /* language */, ref languageLength, + fileMuiPath, ref fileMuiPathLength, ref enumerator); + return succeeded ? + TryGetLocalizedNameByNativeResource(new string(fileMuiPath, 0, fileMuiPathLength), resourceId) : + string.Empty; + } + } + catch (EntryPointNotFoundException) + { + return string.Empty; + } + } + + /// + /// Helper function for retrieving a localized string resource via a native resource DLL. + /// The function expects a string in the form: "C:\Windows\System32\en-us\resource.dll" + /// + /// "resource.dll" is a language-specific resource DLL. + /// If the localized resource DLL exists, LoadString(resource) is returned. + /// + private static unsafe string TryGetLocalizedNameByNativeResource(string filePath, int resource) + { + using (SafeLibraryHandle handle = Interop.Kernel32.LoadLibraryEx(filePath, IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_AS_DATAFILE)) + { + if (!handle.IsInvalid) + { + const int LoadStringMaxLength = 500; + char* localizedResource = stackalloc char[LoadStringMaxLength]; + + int charsWritten = Interop.User32.LoadString(handle, (uint)resource, localizedResource, LoadStringMaxLength); + if (charsWritten != 0) + { + return new string(localizedResource, 0, charsWritten); + } + } + } + + return string.Empty; + } + + /// + /// Helper function for retrieving the DisplayName, StandardName, and DaylightName from the registry + /// + /// The function first checks the MUI_ key-values, and if they exist, it loads the strings from the MUI + /// resource dll(s). When the keys do not exist, the function falls back to reading from the standard + /// key-values + /// + private static void GetLocalizedNamesByRegistryKey(RegistryKey key, out string? displayName, out string? standardName, out string? daylightName) + { + displayName = string.Empty; + standardName = string.Empty; + daylightName = string.Empty; + + // read the MUI_ registry keys + string? displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty) as string; + string? standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty) as string; + string? daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty) as string; + + // try to load the strings from the native resource DLL(s) + if (!string.IsNullOrEmpty(displayNameMuiResource)) + { + displayName = TryGetLocalizedNameByMuiNativeResource(displayNameMuiResource); + } + + if (!string.IsNullOrEmpty(standardNameMuiResource)) + { + standardName = TryGetLocalizedNameByMuiNativeResource(standardNameMuiResource); + } + + if (!string.IsNullOrEmpty(daylightNameMuiResource)) + { + daylightName = TryGetLocalizedNameByMuiNativeResource(daylightNameMuiResource); + } + + // fallback to using the standard registry keys + if (string.IsNullOrEmpty(displayName)) + { + displayName = key.GetValue(DisplayValue, string.Empty) as string; + } + if (string.IsNullOrEmpty(standardName)) + { + standardName = key.GetValue(StandardValue, string.Empty) as string; + } + if (string.IsNullOrEmpty(daylightName)) + { + daylightName = key.GetValue(DaylightValue, string.Empty) as string; + } + } + + /// + /// Helper function that takes a string representing a time_zone_name registry key name + /// and returns a TimeZoneInfo instance. + /// + private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo? value, out Exception? e) + { + e = null; + + // Standard Time Zone Registry Data + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // HKLM + // Software + // Microsoft + // Windows NT + // CurrentVersion + // Time Zones + // + // * STD, REG_SZ "Standard Time Name" + // (For OS installed zones, this will always be English) + // * MUI_STD, REG_SZ "@tzres.dll,-1234" + // Indirect string to localized resource for Standard Time, + // add "%windir%\system32\" after "@" + // * DLT, REG_SZ "Daylight Time Name" + // (For OS installed zones, this will always be English) + // * MUI_DLT, REG_SZ "@tzres.dll,-1234" + // Indirect string to localized resource for Daylight Time, + // add "%windir%\system32\" after "@" + // * Display, REG_SZ "Display Name like (GMT-8:00) Pacific Time..." + // * MUI_Display, REG_SZ "@tzres.dll,-1234" + // Indirect string to localized resource for the Display, + // add "%windir%\system32\" after "@" + // * TZI, REG_BINARY REG_TZI_FORMAT + // + using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false)) + { + if (key == null) + { + value = null; + return TimeZoneInfoResult.TimeZoneNotFoundException; + } + + REG_TZI_FORMAT defaultTimeZoneInformation; + if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out defaultTimeZoneInformation)) + { + // the registry value could not be cast to a byte array + value = null; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + + AdjustmentRule[]? adjustmentRules; + if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e, defaultTimeZoneInformation.Bias)) + { + value = null; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + + GetLocalizedNamesByRegistryKey(key, out string? displayName, out string? standardName, out string? daylightName); + + try + { + value = new TimeZoneInfo( + id, + new TimeSpan(0, -(defaultTimeZoneInformation.Bias), 0), + displayName, + standardName, + daylightName, + adjustmentRules, + disableDaylightSavingTime: false); + + return TimeZoneInfoResult.Success; + } + catch (ArgumentException ex) + { + // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException + value = null; + e = ex; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + catch (InvalidTimeZoneException ex) + { + // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException + value = null; + e = ex; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + } + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs index c7090d5..9b12adb 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs @@ -1,2058 +1,2060 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.Serialization; -using System.Threading; - -namespace System -{ - // - // DateTime uses TimeZoneInfo under the hood for IsDaylightSavingTime, IsAmbiguousTime, and GetUtcOffset. - // These TimeZoneInfo APIs can throw ArgumentException when an Invalid-Time is passed in. To avoid this - // unwanted behavior in DateTime public APIs, DateTime internally passes the - // TimeZoneInfoOptions.NoThrowOnInvalidTime flag to internal TimeZoneInfo APIs. - // - // In the future we can consider exposing similar options on the public TimeZoneInfo APIs if there is enough - // demand for this alternate behavior. - // - [Flags] - internal enum TimeZoneInfoOptions - { - None = 1, - NoThrowOnInvalidTime = 2 - }; - - [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed partial class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback - { - private enum TimeZoneInfoResult - { - Success = 0, - TimeZoneNotFoundException = 1, - InvalidTimeZoneException = 2, - SecurityException = 3 - }; - - private readonly string _id; - private readonly string _displayName; - private readonly string _standardDisplayName; - private readonly string _daylightDisplayName; - private readonly TimeSpan _baseUtcOffset; - private readonly bool _supportsDaylightSavingTime; - private readonly AdjustmentRule[] _adjustmentRules; - - // constants for TimeZoneInfo.Local and TimeZoneInfo.Utc - private const string UtcId = "UTC"; - private const string LocalId = "Local"; - - private static readonly TimeZoneInfo s_utcTimeZone = CreateCustomTimeZone(UtcId, TimeSpan.Zero, UtcId, UtcId); - - private static CachedData s_cachedData = new CachedData(); - - // - // All cached data are encapsulated in a helper class to allow consistent view even when the data are refreshed using ClearCachedData() - // - // For example, TimeZoneInfo.Local can be cleared by another thread calling TimeZoneInfo.ClearCachedData. Without the consistent snapshot, - // there is a chance that the internal ConvertTime calls will throw since 'source' won't be reference equal to the new TimeZoneInfo.Local. - // - private sealed partial class CachedData - { - private volatile TimeZoneInfo _localTimeZone; - - private TimeZoneInfo CreateLocal() - { - lock (this) - { - TimeZoneInfo timeZone = _localTimeZone; - if (timeZone == null) - { - timeZone = GetLocalTimeZone(this); - - // this step is to break the reference equality - // between TimeZoneInfo.Local and a second time zone - // such as "Pacific Standard Time" - timeZone = new TimeZoneInfo( - timeZone._id, - timeZone._baseUtcOffset, - timeZone._displayName, - timeZone._standardDisplayName, - timeZone._daylightDisplayName, - timeZone._adjustmentRules, - disableDaylightSavingTime: false); - - _localTimeZone = timeZone; - } - return timeZone; - } - } - - public TimeZoneInfo Local - { - get - { - TimeZoneInfo timeZone = _localTimeZone; - if (timeZone == null) - { - timeZone = CreateLocal(); - } - return timeZone; - } - } - - /// - /// Helper function that returns the corresponding DateTimeKind for this TimeZoneInfo. - /// - public DateTimeKind GetCorrespondingKind(TimeZoneInfo timeZone) - { - // We check reference equality to see if 'this' is the same as - // TimeZoneInfo.Local or TimeZoneInfo.Utc. This check is needed to - // support setting the DateTime Kind property to 'Local' or - // 'Utc' on the ConverTime(...) return value. - // - // Using reference equality instead of value equality was a - // performance based design compromise. The reference equality - // has much greater performance, but it reduces the number of - // returned DateTime's that can be properly set as 'Local' or 'Utc'. - // - // For example, the user could be converting to the TimeZoneInfo returned - // by FindSystemTimeZoneById("Pacific Standard Time") and their local - // machine may be in Pacific time. If we used value equality to determine - // the corresponding Kind then this conversion would be tagged as 'Local'; - // where as we are currently tagging the returned DateTime as 'Unspecified' - // in this example. Only when the user passes in TimeZoneInfo.Local or - // TimeZoneInfo.Utc to the ConvertTime(...) methods will this check succeed. - // - return - ReferenceEquals(timeZone, s_utcTimeZone) ? DateTimeKind.Utc : - ReferenceEquals(timeZone, _localTimeZone) ? DateTimeKind.Local : - DateTimeKind.Unspecified; - } - - public Dictionary _systemTimeZones; - public ReadOnlyCollection _readOnlySystemTimeZones; - public bool _allSystemTimeZonesRead; - }; - - // used by GetUtcOffsetFromUtc (DateTime.Now, DateTime.ToLocalTime) for max/min whole-day range checks - private static readonly DateTime s_maxDateOnly = new DateTime(9999, 12, 31); - private static readonly DateTime s_minDateOnly = new DateTime(1, 1, 2); - - public string Id => _id; - - public string DisplayName => _displayName ?? string.Empty; - - public string StandardName => _standardDisplayName ?? string.Empty; - - public string DaylightName => _daylightDisplayName ?? string.Empty; - - public TimeSpan BaseUtcOffset => _baseUtcOffset; - - public bool SupportsDaylightSavingTime => _supportsDaylightSavingTime; - - /// - /// Returns an array of TimeSpan objects representing all of - /// possible UTC offset values for this ambiguous time. - /// - public TimeSpan[] GetAmbiguousTimeOffsets(DateTimeOffset dateTimeOffset) - { - if (!SupportsDaylightSavingTime) - { - throw new ArgumentException(SR.Argument_DateTimeOffsetIsNotAmbiguous, nameof(dateTimeOffset)); - } - - DateTime adjustedTime = ConvertTime(dateTimeOffset, this).DateTime; - - bool isAmbiguous = false; - int? ruleIndex; - AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); - if (rule != null && rule.HasDaylightSaving) - { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); - isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); - } - - if (!isAmbiguous) - { - throw new ArgumentException(SR.Argument_DateTimeOffsetIsNotAmbiguous, nameof(dateTimeOffset)); - } - - // the passed in dateTime is ambiguous in this TimeZoneInfo instance - TimeSpan[] timeSpans = new TimeSpan[2]; - - TimeSpan actualUtcOffset = _baseUtcOffset + rule.BaseUtcOffsetDelta; - - // the TimeSpan array must be sorted from least to greatest - if (rule.DaylightDelta > TimeSpan.Zero) - { - timeSpans[0] = actualUtcOffset; // FUTURE: + rule.StandardDelta; - timeSpans[1] = actualUtcOffset + rule.DaylightDelta; - } - else - { - timeSpans[0] = actualUtcOffset + rule.DaylightDelta; - timeSpans[1] = actualUtcOffset; // FUTURE: + rule.StandardDelta; - } - return timeSpans; - } - - /// - /// Returns an array of TimeSpan objects representing all of - /// possible UTC offset values for this ambiguous time. - /// - public TimeSpan[] GetAmbiguousTimeOffsets(DateTime dateTime) - { - if (!SupportsDaylightSavingTime) - { - throw new ArgumentException(SR.Argument_DateTimeIsNotAmbiguous, nameof(dateTime)); - } - - DateTime adjustedTime; - if (dateTime.Kind == DateTimeKind.Local) - { - CachedData cachedData = s_cachedData; - adjustedTime = ConvertTime(dateTime, cachedData.Local, this, TimeZoneInfoOptions.None, cachedData); - } - else if (dateTime.Kind == DateTimeKind.Utc) - { - CachedData cachedData = s_cachedData; - adjustedTime = ConvertTime(dateTime, s_utcTimeZone, this, TimeZoneInfoOptions.None, cachedData); - } - else - { - adjustedTime = dateTime; - } - - bool isAmbiguous = false; - int? ruleIndex; - AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); - if (rule != null && rule.HasDaylightSaving) - { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); - isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); - } - - if (!isAmbiguous) - { - throw new ArgumentException(SR.Argument_DateTimeIsNotAmbiguous, nameof(dateTime)); - } - - // the passed in dateTime is ambiguous in this TimeZoneInfo instance - TimeSpan[] timeSpans = new TimeSpan[2]; - TimeSpan actualUtcOffset = _baseUtcOffset + rule.BaseUtcOffsetDelta; - - // the TimeSpan array must be sorted from least to greatest - if (rule.DaylightDelta > TimeSpan.Zero) - { - timeSpans[0] = actualUtcOffset; // FUTURE: + rule.StandardDelta; - timeSpans[1] = actualUtcOffset + rule.DaylightDelta; - } - else - { - timeSpans[0] = actualUtcOffset + rule.DaylightDelta; - timeSpans[1] = actualUtcOffset; // FUTURE: + rule.StandardDelta; - } - return timeSpans; - } - - // note the time is already adjusted - private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTime, out int? ruleIndex) - { - AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); - if (rule != null && rule.NoDaylightTransitions && !rule.HasDaylightSaving) - { - // When using NoDaylightTransitions rules, each rule is only for one offset. - // When looking for the Daylight savings rules, and we found the non-DST rule, - // then we get the rule right before this rule. - return GetPreviousAdjustmentRule(rule, ruleIndex); - } - - return rule; - } - - /// - /// Gets the AdjustmentRule that is immediately preceding the specified rule. - /// If the specified rule is the first AdjustmentRule, or it isn't in _adjustmentRules, - /// then the specified rule is returned. - /// - private AdjustmentRule GetPreviousAdjustmentRule(AdjustmentRule rule, int? ruleIndex) - { - Debug.Assert(rule.NoDaylightTransitions, "GetPreviousAdjustmentRule should only be used with NoDaylightTransitions rules."); - - if (ruleIndex.HasValue && 0 < ruleIndex.GetValueOrDefault() && ruleIndex.GetValueOrDefault() < _adjustmentRules.Length) - { - return _adjustmentRules[ruleIndex.GetValueOrDefault() - 1]; - } - - AdjustmentRule result = rule; - for (int i = 1; i < _adjustmentRules.Length; i++) - { - // use ReferenceEquals here instead of AdjustmentRule.Equals because - // ReferenceEquals is much faster. This is safe because all the callers - // of GetPreviousAdjustmentRule pass in a rule that was retrieved from - // _adjustmentRules. A different approach will be needed if this ever changes. - if (ReferenceEquals(rule, _adjustmentRules[i])) - { - result = _adjustmentRules[i - 1]; - break; - } - } - return result; - } - - /// - /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. - /// - public TimeSpan GetUtcOffset(DateTimeOffset dateTimeOffset) => - GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this); - - /// - /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. - /// - public TimeSpan GetUtcOffset(DateTime dateTime) => - GetUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime, s_cachedData); - - // Shortcut for TimeZoneInfo.Local.GetUtcOffset - internal static TimeSpan GetLocalUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags) - { - CachedData cachedData = s_cachedData; - return cachedData.Local.GetUtcOffset(dateTime, flags, cachedData); - } - - /// - /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. - /// - internal TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags) => - GetUtcOffset(dateTime, flags, s_cachedData); - - private TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags, CachedData cachedData) - { - if (dateTime.Kind == DateTimeKind.Local) - { - if (cachedData.GetCorrespondingKind(this) != DateTimeKind.Local) - { - // - // normal case of converting from Local to Utc and then getting the offset from the UTC DateTime - // - DateTime adjustedTime = ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, flags); - return GetUtcOffsetFromUtc(adjustedTime, this); - } - - // - // Fall through for TimeZoneInfo.Local.GetUtcOffset(date) - // to handle an edge case with Invalid-Times for DateTime formatting: - // - // Consider the invalid PST time "2007-03-11T02:00:00.0000000-08:00" - // - // By directly calling GetUtcOffset instead of converting to UTC and then calling GetUtcOffsetFromUtc - // the correct invalid offset of "-08:00" is returned. In the normal case of converting to UTC as an - // interim-step, the invalid time is adjusted into a *valid* UTC time which causes a change in output: - // - // 1) invalid PST time "2007-03-11T02:00:00.0000000-08:00" - // 2) converted to UTC "2007-03-11T10:00:00.0000000Z" - // 3) offset returned "2007-03-11T03:00:00.0000000-07:00" - // - } - else if (dateTime.Kind == DateTimeKind.Utc) - { - if (cachedData.GetCorrespondingKind(this) == DateTimeKind.Utc) - { - return _baseUtcOffset; - } - else - { - // - // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a - // special Loss-Less case. - // - return GetUtcOffsetFromUtc(dateTime, this); - } - } - - return GetUtcOffset(dateTime, this, flags); - } - - /// - /// Returns true if the time is during the ambiguous time period - /// for the current TimeZoneInfo instance. - /// - public bool IsAmbiguousTime(DateTimeOffset dateTimeOffset) - { - if (!_supportsDaylightSavingTime) - { - return false; - } - - DateTimeOffset adjustedTime = ConvertTime(dateTimeOffset, this); - return IsAmbiguousTime(adjustedTime.DateTime); - } - - /// - /// Returns true if the time is during the ambiguous time period - /// for the current TimeZoneInfo instance. - /// - public bool IsAmbiguousTime(DateTime dateTime) => - IsAmbiguousTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime); - - /// - /// Returns true if the time is during the ambiguous time period - /// for the current TimeZoneInfo instance. - /// - internal bool IsAmbiguousTime(DateTime dateTime, TimeZoneInfoOptions flags) - { - if (!_supportsDaylightSavingTime) - { - return false; - } - - CachedData cachedData = s_cachedData; - DateTime adjustedTime = - dateTime.Kind == DateTimeKind.Local ? ConvertTime(dateTime, cachedData.Local, this, flags, cachedData) : - dateTime.Kind == DateTimeKind.Utc ? ConvertTime(dateTime, s_utcTimeZone, this, flags, cachedData) : - dateTime; - - int? ruleIndex; - AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); - if (rule != null && rule.HasDaylightSaving) - { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); - return GetIsAmbiguousTime(adjustedTime, rule, daylightTime); - } - return false; - } - - /// - /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. - /// - public bool IsDaylightSavingTime(DateTimeOffset dateTimeOffset) - { - bool isDaylightSavingTime; - GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this, out isDaylightSavingTime); - return isDaylightSavingTime; - } - - /// - /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. - /// - public bool IsDaylightSavingTime(DateTime dateTime) => - IsDaylightSavingTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime, s_cachedData); - - /// - /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. - /// - internal bool IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags) => - IsDaylightSavingTime(dateTime, flags, s_cachedData); - - private bool IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags, CachedData cachedData) - { - // - // dateTime.Kind is UTC, then time will be converted from UTC - // into current instance's timezone - // dateTime.Kind is Local, then time will be converted from Local - // into current instance's timezone - // dateTime.Kind is UnSpecified, then time is already in - // current instance's timezone - // - // Our DateTime handles ambiguous times, (one is in the daylight and - // one is in standard.) If a new DateTime is constructed during ambiguous - // time, it is defaulted to "Standard" (i.e. this will return false). - // For Invalid times, we will return false - - if (!_supportsDaylightSavingTime || _adjustmentRules == null) - { - return false; - } - - DateTime adjustedTime; - // - // handle any Local/Utc special cases... - // - if (dateTime.Kind == DateTimeKind.Local) - { - adjustedTime = ConvertTime(dateTime, cachedData.Local, this, flags, cachedData); - } - else if (dateTime.Kind == DateTimeKind.Utc) - { - if (cachedData.GetCorrespondingKind(this) == DateTimeKind.Utc) - { - // simple always false case: TimeZoneInfo.Utc.IsDaylightSavingTime(dateTime, flags); - return false; - } - else - { - // - // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a - // special Loss-Less case. - // - bool isDaylightSavings; - GetUtcOffsetFromUtc(dateTime, this, out isDaylightSavings); - return isDaylightSavings; - } - } - else - { - adjustedTime = dateTime; - } - - // - // handle the normal cases... - // - int? ruleIndex; - AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); - if (rule != null && rule.HasDaylightSaving) - { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); - return GetIsDaylightSavings(adjustedTime, rule, daylightTime, flags); - } - else - { - return false; - } - } - - /// - /// Returns true when dateTime falls into a "hole in time". - /// - public bool IsInvalidTime(DateTime dateTime) - { - bool isInvalid = false; - - if ((dateTime.Kind == DateTimeKind.Unspecified) || - (dateTime.Kind == DateTimeKind.Local && s_cachedData.GetCorrespondingKind(this) == DateTimeKind.Local)) - { - // only check Unspecified and (Local when this TimeZoneInfo instance is Local) - int? ruleIndex; - AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime, out ruleIndex); - - if (rule != null && rule.HasDaylightSaving) - { - DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule, ruleIndex); - isInvalid = GetIsInvalidTime(dateTime, rule, daylightTime); - } - else - { - isInvalid = false; - } - } - - return isInvalid; - } - - /// - /// Clears data from static members. - /// - public static void ClearCachedData() - { - // Clear a fresh instance of cached data - s_cachedData = new CachedData(); - } - - /// - /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. - /// - public static DateTimeOffset ConvertTimeBySystemTimeZoneId(DateTimeOffset dateTimeOffset, string destinationTimeZoneId) => - ConvertTime(dateTimeOffset, FindSystemTimeZoneById(destinationTimeZoneId)); - - /// - /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. - /// - public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, string destinationTimeZoneId) => - ConvertTime(dateTime, FindSystemTimeZoneById(destinationTimeZoneId)); - - /// - /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. - /// - public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, string sourceTimeZoneId, string destinationTimeZoneId) - { - if (dateTime.Kind == DateTimeKind.Local && string.Equals(sourceTimeZoneId, Local.Id, StringComparison.OrdinalIgnoreCase)) - { - // TimeZoneInfo.Local can be cleared by another thread calling TimeZoneInfo.ClearCachedData. - // Take snapshot of cached data to guarantee this method will not be impacted by the ClearCachedData call. - // Without the snapshot, there is a chance that ConvertTime will throw since 'source' won't - // be reference equal to the new TimeZoneInfo.Local - // - CachedData cachedData = s_cachedData; - return ConvertTime(dateTime, cachedData.Local, FindSystemTimeZoneById(destinationTimeZoneId), TimeZoneInfoOptions.None, cachedData); - } - else if (dateTime.Kind == DateTimeKind.Utc && string.Equals(sourceTimeZoneId, Utc.Id, StringComparison.OrdinalIgnoreCase)) - { - return ConvertTime(dateTime, s_utcTimeZone, FindSystemTimeZoneById(destinationTimeZoneId), TimeZoneInfoOptions.None, s_cachedData); - } - else - { - return ConvertTime(dateTime, FindSystemTimeZoneById(sourceTimeZoneId), FindSystemTimeZoneById(destinationTimeZoneId)); - } - } - - /// - /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone - /// - public static DateTimeOffset ConvertTime(DateTimeOffset dateTimeOffset, TimeZoneInfo destinationTimeZone) - { - if (destinationTimeZone == null) - { - throw new ArgumentNullException(nameof(destinationTimeZone)); - } - - // calculate the destination time zone offset - DateTime utcDateTime = dateTimeOffset.UtcDateTime; - TimeSpan destinationOffset = GetUtcOffsetFromUtc(utcDateTime, destinationTimeZone); - - // check for overflow - long ticks = utcDateTime.Ticks + destinationOffset.Ticks; - - return - ticks > DateTimeOffset.MaxValue.Ticks ? DateTimeOffset.MaxValue : - ticks < DateTimeOffset.MinValue.Ticks ? DateTimeOffset.MinValue : - new DateTimeOffset(ticks, destinationOffset); - } - - /// - /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone - /// - public static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo destinationTimeZone) - { - if (destinationTimeZone == null) - { - throw new ArgumentNullException(nameof(destinationTimeZone)); - } - - // Special case to give a way clearing the cache without exposing ClearCachedData() - if (dateTime.Ticks == 0) - { - ClearCachedData(); - } - CachedData cachedData = s_cachedData; - TimeZoneInfo sourceTimeZone = dateTime.Kind == DateTimeKind.Utc ? s_utcTimeZone : cachedData.Local; - return ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, cachedData); - } - - /// - /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone - /// - public static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone) => - ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, s_cachedData); - - /// - /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone - /// - internal static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags) => - ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, flags, s_cachedData); - - private static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags, CachedData cachedData) - { - if (sourceTimeZone == null) - { - throw new ArgumentNullException(nameof(sourceTimeZone)); - } - - if (destinationTimeZone == null) - { - throw new ArgumentNullException(nameof(destinationTimeZone)); - } - - DateTimeKind sourceKind = cachedData.GetCorrespondingKind(sourceTimeZone); - if (((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && (dateTime.Kind != DateTimeKind.Unspecified) && (dateTime.Kind != sourceKind)) - { - throw new ArgumentException(SR.Argument_ConvertMismatch, nameof(sourceTimeZone)); - } - - // - // check to see if the DateTime is in an invalid time range. This check - // requires the current AdjustmentRule and DaylightTime - which are also - // needed to calculate 'sourceOffset' in the normal conversion case. - // By calculating the 'sourceOffset' here we improve the - // performance for the normal case at the expense of the 'ArgumentException' - // case and Loss-less Local special cases. - // - int? sourceRuleIndex; - AdjustmentRule sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime, out sourceRuleIndex); - TimeSpan sourceOffset = sourceTimeZone.BaseUtcOffset; - - if (sourceRule != null) - { - sourceOffset = sourceOffset + sourceRule.BaseUtcOffsetDelta; - if (sourceRule.HasDaylightSaving) - { - bool sourceIsDaylightSavings = false; - DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule, sourceRuleIndex); - - // 'dateTime' might be in an invalid time range since it is in an AdjustmentRule - // period that supports DST - if (((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && GetIsInvalidTime(dateTime, sourceRule, sourceDaylightTime)) - { - throw new ArgumentException(SR.Argument_DateTimeIsInvalid, nameof(dateTime)); - } - sourceIsDaylightSavings = GetIsDaylightSavings(dateTime, sourceRule, sourceDaylightTime, flags); - - // adjust the sourceOffset according to the Adjustment Rule / Daylight Saving Rule - sourceOffset += (sourceIsDaylightSavings ? sourceRule.DaylightDelta : TimeSpan.Zero /*FUTURE: sourceRule.StandardDelta*/); - } - } - - DateTimeKind targetKind = cachedData.GetCorrespondingKind(destinationTimeZone); - - // handle the special case of Loss-less Local->Local and UTC->UTC) - if (dateTime.Kind != DateTimeKind.Unspecified && sourceKind != DateTimeKind.Unspecified && sourceKind == targetKind) - { - return dateTime; - } - - long utcTicks = dateTime.Ticks - sourceOffset.Ticks; - - // handle the normal case by converting from 'source' to UTC and then to 'target' - bool isAmbiguousLocalDst; - DateTime targetConverted = ConvertUtcToTimeZone(utcTicks, destinationTimeZone, out isAmbiguousLocalDst); - - if (targetKind == DateTimeKind.Local) - { - // Because the ticks conversion between UTC and local is lossy, we need to capture whether the - // time is in a repeated hour so that it can be passed to the DateTime constructor. - return new DateTime(targetConverted.Ticks, DateTimeKind.Local, isAmbiguousLocalDst); - } - else - { - return new DateTime(targetConverted.Ticks, targetKind); - } - } - - /// - /// Converts the value of a DateTime object from Coordinated Universal Time (UTC) to the destinationTimeZone. - /// - public static DateTime ConvertTimeFromUtc(DateTime dateTime, TimeZoneInfo destinationTimeZone) => - ConvertTime(dateTime, s_utcTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, s_cachedData); - - /// - /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). - /// - public static DateTime ConvertTimeToUtc(DateTime dateTime) - { - if (dateTime.Kind == DateTimeKind.Utc) - { - return dateTime; - } - CachedData cachedData = s_cachedData; - return ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, TimeZoneInfoOptions.None, cachedData); - } - - /// - /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). - /// - internal static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfoOptions flags) - { - if (dateTime.Kind == DateTimeKind.Utc) - { - return dateTime; - } - CachedData cachedData = s_cachedData; - return ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, flags, cachedData); - } - - /// - /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). - /// - public static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfo sourceTimeZone) => - ConvertTime(dateTime, sourceTimeZone, s_utcTimeZone, TimeZoneInfoOptions.None, s_cachedData); - - /// - /// Returns value equality. Equals does not compare any localizable - /// String objects (DisplayName, StandardName, DaylightName). - /// - public bool Equals(TimeZoneInfo other) => - other != null && - string.Equals(_id, other._id, StringComparison.OrdinalIgnoreCase) && - HasSameRules(other); - - public override bool Equals(object obj) => Equals(obj as TimeZoneInfo); - - public static TimeZoneInfo FromSerializedString(string source) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if (source.Length == 0) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidSerializedString, source), nameof(source)); - } - - return StringSerializer.GetDeserializedTimeZoneInfo(source); - } - - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(_id); - - /// - /// Returns a containing all valid TimeZone's - /// from the local machine. The entries in the collection are sorted by - /// . - /// This method does *not* throw TimeZoneNotFoundException or InvalidTimeZoneException. - /// - public static ReadOnlyCollection GetSystemTimeZones() - { - CachedData cachedData = s_cachedData; - - lock (cachedData) - { - if (cachedData._readOnlySystemTimeZones == null) - { - PopulateAllSystemTimeZones(cachedData); - cachedData._allSystemTimeZonesRead = true; - - List list; - if (cachedData._systemTimeZones != null) - { - // return a collection of the cached system time zones - list = new List(cachedData._systemTimeZones.Values); - } - else - { - // return an empty collection - list = new List(); - } - - // sort and copy the TimeZoneInfo's into a ReadOnlyCollection for the user - list.Sort((x, y) => - { - // sort by BaseUtcOffset first and by DisplayName second - this is similar to the Windows Date/Time control panel - int comparison = x.BaseUtcOffset.CompareTo(y.BaseUtcOffset); - return comparison == 0 ? string.CompareOrdinal(x.DisplayName, y.DisplayName) : comparison; - }); - - cachedData._readOnlySystemTimeZones = new ReadOnlyCollection(list); - } - } - return cachedData._readOnlySystemTimeZones; - } - - /// - /// Value equality on the "adjustmentRules" array - /// - public bool HasSameRules(TimeZoneInfo other) - { - if (other == null) - { - throw new ArgumentNullException(nameof(other)); - } - - // check the utcOffset and supportsDaylightSavingTime members - if (_baseUtcOffset != other._baseUtcOffset || - _supportsDaylightSavingTime != other._supportsDaylightSavingTime) - { - return false; - } - - bool sameRules; - AdjustmentRule[] currentRules = _adjustmentRules; - AdjustmentRule[] otherRules = other._adjustmentRules; - - sameRules = - (currentRules == null && otherRules == null) || - (currentRules != null && otherRules != null); - - if (!sameRules) - { - // AdjustmentRule array mismatch - return false; - } - - if (currentRules != null) - { - if (currentRules.Length != otherRules.Length) - { - // AdjustmentRule array length mismatch - return false; - } - - for (int i = 0; i < currentRules.Length; i++) - { - if (!(currentRules[i]).Equals(otherRules[i])) - { - // AdjustmentRule value-equality mismatch - return false; - } - } - } - return sameRules; - } - - /// - /// Returns a TimeZoneInfo instance that represents the local time on the machine. - /// Accessing this property may throw InvalidTimeZoneException or COMException - /// if the machine is in an unstable or corrupt state. - /// - public static TimeZoneInfo Local => s_cachedData.Local; - - // - // ToSerializedString - - // - // "TimeZoneInfo" := TimeZoneInfo Data;[AdjustmentRule Data 1];...;[AdjustmentRule Data N] - // - // "TimeZoneInfo Data" := <_id>;<_baseUtcOffset>;<_displayName>; - // <_standardDisplayName>;<_daylightDispayName>; - // - // "AdjustmentRule Data" := ;;; - // [TransitionTime Data DST Start] - // [TransitionTime Data DST End] - // - // "TransitionTime Data" += ;;;; - // - public string ToSerializedString() => StringSerializer.GetSerializedString(this); - - /// - /// Returns the : "(GMT-08:00) Pacific Time (US & Canada); Tijuana" - /// - public override string ToString() => DisplayName; - - /// - /// Returns a TimeZoneInfo instance that represents Universal Coordinated Time (UTC) - /// - public static TimeZoneInfo Utc => s_utcTimeZone; - - private TimeZoneInfo( - string id, - TimeSpan baseUtcOffset, - string displayName, - string standardDisplayName, - string daylightDisplayName, - AdjustmentRule[] adjustmentRules, - bool disableDaylightSavingTime) - { - bool adjustmentRulesSupportDst; - ValidateTimeZoneInfo(id, baseUtcOffset, adjustmentRules, out adjustmentRulesSupportDst); - - _id = id; - _baseUtcOffset = baseUtcOffset; - _displayName = displayName; - _standardDisplayName = standardDisplayName; - _daylightDisplayName = disableDaylightSavingTime ? null : daylightDisplayName; - _supportsDaylightSavingTime = adjustmentRulesSupportDst && !disableDaylightSavingTime; - _adjustmentRules = adjustmentRules; - } - - /// - /// Returns a simple TimeZoneInfo instance that does not support Daylight Saving Time. - /// - public static TimeZoneInfo CreateCustomTimeZone( - string id, - TimeSpan baseUtcOffset, - string displayName, - string standardDisplayName) - { - return new TimeZoneInfo( - id, - baseUtcOffset, - displayName, - standardDisplayName, - standardDisplayName, - adjustmentRules: null, - disableDaylightSavingTime: false); - } - - /// - /// Returns a TimeZoneInfo instance that may support Daylight Saving Time. - /// - public static TimeZoneInfo CreateCustomTimeZone( - string id, - TimeSpan baseUtcOffset, - string displayName, - string standardDisplayName, - string daylightDisplayName, - AdjustmentRule[] adjustmentRules) - { - return CreateCustomTimeZone( - id, - baseUtcOffset, - displayName, - standardDisplayName, - daylightDisplayName, - adjustmentRules, - disableDaylightSavingTime: false); - } - - /// - /// Returns a TimeZoneInfo instance that may support Daylight Saving Time. - /// - public static TimeZoneInfo CreateCustomTimeZone( - string id, - TimeSpan baseUtcOffset, - string displayName, - string standardDisplayName, - string daylightDisplayName, - AdjustmentRule[] adjustmentRules, - bool disableDaylightSavingTime) - { - if (!disableDaylightSavingTime && adjustmentRules?.Length > 0) - { - adjustmentRules = (AdjustmentRule[])adjustmentRules.Clone(); - } - - return new TimeZoneInfo( - id, - baseUtcOffset, - displayName, - standardDisplayName, - daylightDisplayName, - adjustmentRules, - disableDaylightSavingTime); - } - - void IDeserializationCallback.OnDeserialization(object sender) - { - try - { - bool adjustmentRulesSupportDst; - ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out adjustmentRulesSupportDst); - - if (adjustmentRulesSupportDst != _supportsDaylightSavingTime) - { - throw new SerializationException(SR.Format(SR.Serialization_CorruptField, "SupportsDaylightSavingTime")); - } - } - catch (ArgumentException e) - { - throw new SerializationException(SR.Serialization_InvalidData, e); - } - catch (InvalidTimeZoneException e) - { - throw new SerializationException(SR.Serialization_InvalidData, e); - } - } - - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) - { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } - - info.AddValue("Id", _id); // Do not rename (binary serialization) - info.AddValue("DisplayName", _displayName); // Do not rename (binary serialization) - info.AddValue("StandardName", _standardDisplayName); // Do not rename (binary serialization) - info.AddValue("DaylightName", _daylightDisplayName); // Do not rename (binary serialization) - info.AddValue("BaseUtcOffset", _baseUtcOffset); // Do not rename (binary serialization) - info.AddValue("AdjustmentRules", _adjustmentRules); // Do not rename (binary serialization) - info.AddValue("SupportsDaylightSavingTime", _supportsDaylightSavingTime); // Do not rename (binary serialization) - } - - private TimeZoneInfo(SerializationInfo info, StreamingContext context) - { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } - - _id = (string)info.GetValue("Id", typeof(string)); // Do not rename (binary serialization) - _displayName = (string)info.GetValue("DisplayName", typeof(string)); // Do not rename (binary serialization) - _standardDisplayName = (string)info.GetValue("StandardName", typeof(string)); // Do not rename (binary serialization) - _daylightDisplayName = (string)info.GetValue("DaylightName", typeof(string)); // Do not rename (binary serialization) - _baseUtcOffset = (TimeSpan)info.GetValue("BaseUtcOffset", typeof(TimeSpan)); // Do not rename (binary serialization) - _adjustmentRules = (AdjustmentRule[])info.GetValue("AdjustmentRules", typeof(AdjustmentRule[])); // Do not rename (binary serialization) - _supportsDaylightSavingTime = (bool)info.GetValue("SupportsDaylightSavingTime", typeof(bool)); // Do not rename (binary serialization) - } - - private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, out int? ruleIndex) - { - AdjustmentRule result = GetAdjustmentRuleForTime(dateTime, dateTimeisUtc: false, ruleIndex: out ruleIndex); - Debug.Assert(result == null || ruleIndex.HasValue, "If an AdjustmentRule was found, ruleIndex should also be set."); - - return result; - } - - private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTimeisUtc, out int? ruleIndex) - { - if (_adjustmentRules == null || _adjustmentRules.Length == 0) - { - ruleIndex = null; - return null; - } - - // Only check the whole-date portion of the dateTime for DateTimeKind.Unspecified rules - - // This is because the AdjustmentRule DateStart & DateEnd are stored as - // Date-only values {4/2/2006 - 10/28/2006} but actually represent the - // time span {4/2/2006@00:00:00.00000 - 10/28/2006@23:59:59.99999} - DateTime date = dateTimeisUtc ? - (dateTime + BaseUtcOffset).Date : - dateTime.Date; - - int low = 0; - int high = _adjustmentRules.Length - 1; - - while (low <= high) - { - int median = low + ((high - low) >> 1); - - AdjustmentRule rule = _adjustmentRules[median]; - AdjustmentRule previousRule = median > 0 ? _adjustmentRules[median - 1] : rule; - - int compareResult = CompareAdjustmentRuleToDateTime(rule, previousRule, dateTime, date, dateTimeisUtc); - if (compareResult == 0) - { - ruleIndex = median; - return rule; - } - else if (compareResult < 0) - { - low = median + 1; - } - else - { - high = median - 1; - } - } - - ruleIndex = null; - return null; - } - - /// - /// Determines if 'rule' is the correct AdjustmentRule for the given dateTime. - /// - /// - /// A value less than zero if rule is for times before dateTime. - /// Zero if rule is correct for dateTime. - /// A value greater than zero if rule is for times after dateTime. - /// - private int CompareAdjustmentRuleToDateTime(AdjustmentRule rule, AdjustmentRule previousRule, - DateTime dateTime, DateTime dateOnly, bool dateTimeisUtc) - { - bool isAfterStart; - if (rule.DateStart.Kind == DateTimeKind.Utc) - { - DateTime dateTimeToCompare = dateTimeisUtc ? - dateTime : - // use the previous rule to compute the dateTimeToCompare, since the time daylight savings "switches" - // is based on the previous rule's offset - ConvertToUtc(dateTime, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta); - - isAfterStart = dateTimeToCompare >= rule.DateStart; - } - else - { - // if the rule's DateStart is Unspecified, then use the whole-date portion - isAfterStart = dateOnly >= rule.DateStart; - } - - if (!isAfterStart) - { - return 1; - } - - bool isBeforeEnd; - if (rule.DateEnd.Kind == DateTimeKind.Utc) - { - DateTime dateTimeToCompare = dateTimeisUtc ? - dateTime : - ConvertToUtc(dateTime, rule.DaylightDelta, rule.BaseUtcOffsetDelta); - - isBeforeEnd = dateTimeToCompare <= rule.DateEnd; - } - else - { - // if the rule's DateEnd is Unspecified, then use the whole-date portion - isBeforeEnd = dateOnly <= rule.DateEnd; - } - - return isBeforeEnd ? 0 : -1; - } - - /// - /// Converts the dateTime to UTC using the specified deltas. - /// - private DateTime ConvertToUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta) => - ConvertToFromUtc(dateTime, daylightDelta, baseUtcOffsetDelta, convertToUtc: true); - - /// - /// Converts the dateTime from UTC using the specified deltas. - /// - private DateTime ConvertFromUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta) => - ConvertToFromUtc(dateTime, daylightDelta, baseUtcOffsetDelta, convertToUtc: false); - - /// - /// Converts the dateTime to or from UTC using the specified deltas. - /// - private DateTime ConvertToFromUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta, bool convertToUtc) - { - TimeSpan offset = BaseUtcOffset + daylightDelta + baseUtcOffsetDelta; - if (convertToUtc) - { - offset = offset.Negate(); - } - - long ticks = dateTime.Ticks + offset.Ticks; - - return - ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : - ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : - new DateTime(ticks); - } - - /// - /// Helper function that converts a dateTime from UTC into the destinationTimeZone - /// - Returns DateTime.MaxValue when the converted value is too large. - /// - Returns DateTime.MinValue when the converted value is too small. - /// - private static DateTime ConvertUtcToTimeZone(long ticks, TimeZoneInfo destinationTimeZone, out bool isAmbiguousLocalDst) - { - // used to calculate the UTC offset in the destinationTimeZone - DateTime utcConverted = - ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : - ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : - new DateTime(ticks); - - // verify the time is between MinValue and MaxValue in the new time zone - TimeSpan offset = GetUtcOffsetFromUtc(utcConverted, destinationTimeZone, out isAmbiguousLocalDst); - ticks += offset.Ticks; - - return - ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : - ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : - new DateTime(ticks); - } - - /// - /// Helper function that returns a DaylightTime from a year and AdjustmentRule. - /// - private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule, int? ruleIndex) - { - TimeSpan delta = rule.DaylightDelta; - DateTime startTime; - DateTime endTime; - if (rule.NoDaylightTransitions) - { - // NoDaylightTransitions rules don't use DaylightTransition Start and End, instead - // the DateStart and DateEnd are UTC times that represent when daylight savings time changes. - // Convert the UTC times into adjusted time zone times. - - // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule - AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); - startTime = ConvertFromUtc(rule.DateStart, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta); - - endTime = ConvertFromUtc(rule.DateEnd, rule.DaylightDelta, rule.BaseUtcOffsetDelta); - } - else - { - startTime = TransitionTimeToDateTime(year, rule.DaylightTransitionStart); - endTime = TransitionTimeToDateTime(year, rule.DaylightTransitionEnd); - } - return new DaylightTimeStruct(startTime, endTime, delta); - } - - /// - /// Helper function that checks if a given dateTime is in Daylight Saving Time (DST). - /// This function assumes the dateTime and AdjustmentRule are both in the same time zone. - /// - private static bool GetIsDaylightSavings(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime, TimeZoneInfoOptions flags) - { - if (rule == null) - { - return false; - } - - DateTime startTime; - DateTime endTime; - - if (time.Kind == DateTimeKind.Local) - { - // startTime and endTime represent the period from either the start of - // DST to the end and ***includes*** the potentially overlapped times - startTime = rule.IsStartDateMarkerForBeginningOfYear() ? - new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) : - daylightTime.Start + daylightTime.Delta; - - endTime = rule.IsEndDateMarkerForEndOfYear() ? - new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) : - daylightTime.End; - } - else - { - // startTime and endTime represent the period from either the start of DST to the end and - // ***does not include*** the potentially overlapped times - // - // -=-=-=-=-=- Pacific Standard Time -=-=-=-=-=-=- - // April 2, 2006 October 29, 2006 - // 2AM 3AM 1AM 2AM - // | +1 hr | | -1 hr | - // | | | | - // [========== DST ========>) - // - // -=-=-=-=-=- Some Weird Time Zone -=-=-=-=-=-=- - // April 2, 2006 October 29, 2006 - // 1AM 2AM 2AM 3AM - // | -1 hr | | +1 hr | - // | | | | - // [======== DST ========>) - // - bool invalidAtStart = rule.DaylightDelta > TimeSpan.Zero; - - startTime = rule.IsStartDateMarkerForBeginningOfYear() ? - new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) : - daylightTime.Start + (invalidAtStart ? rule.DaylightDelta : TimeSpan.Zero); /* FUTURE: - rule.StandardDelta; */ - - endTime = rule.IsEndDateMarkerForEndOfYear() ? - new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) : - daylightTime.End + (invalidAtStart ? -rule.DaylightDelta : TimeSpan.Zero); - } - - bool isDst = CheckIsDst(startTime, time, endTime, false, rule); - - // If this date was previously converted from a UTC date and we were able to detect that the local - // DateTime would be ambiguous, this data is stored in the DateTime to resolve this ambiguity. - if (isDst && time.Kind == DateTimeKind.Local) - { - // For normal time zones, the ambiguous hour is the last hour of daylight saving when you wind the - // clock back. It is theoretically possible to have a positive delta, (which would really be daylight - // reduction time), where you would have to wind the clock back in the begnning. - if (GetIsAmbiguousTime(time, rule, daylightTime)) - { - isDst = time.IsAmbiguousDaylightSavingTime(); - } - } - - return isDst; - } - - /// - /// Gets the offset that should be used to calculate DST start times from a UTC time. - /// - private TimeSpan GetDaylightSavingsStartOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule, int? ruleIndex) - { - if (rule.NoDaylightTransitions) - { - // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule - AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); - return baseUtcOffset + previousRule.BaseUtcOffsetDelta + previousRule.DaylightDelta; - } - else - { - return baseUtcOffset + rule.BaseUtcOffsetDelta; /* FUTURE: + rule.StandardDelta; */ - } - } - - /// - /// Gets the offset that should be used to calculate DST end times from a UTC time. - /// - private TimeSpan GetDaylightSavingsEndOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule) - { - // NOTE: even NoDaylightTransitions rules use this logic since DST ends w.r.t. the current rule - return baseUtcOffset + rule.BaseUtcOffsetDelta + rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ - } - - /// - /// Helper function that checks if a given dateTime is in Daylight Saving Time (DST). - /// This function assumes the dateTime is in UTC and AdjustmentRule is in a different time zone. - /// - private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpan utc, AdjustmentRule rule, int? ruleIndex, out bool isAmbiguousLocalDst, TimeZoneInfo zone) - { - isAmbiguousLocalDst = false; - - if (rule == null) - { - return false; - } - - // Get the daylight changes for the year of the specified time. - DaylightTimeStruct daylightTime = zone.GetDaylightTime(year, rule, ruleIndex); - - // The start and end times represent the range of universal times that are in DST for that year. - // Within that there is an ambiguous hour, usually right at the end, but at the beginning in - // the unusual case of a negative daylight savings delta. - // We need to handle the case if the current rule has daylight saving end by the end of year. If so, we need to check if next year starts with daylight saving on - // and get the actual daylight saving end time. Here is example for such case: - // Converting the UTC datetime "12/31/2011 8:00:00 PM" to "(UTC+03:00) Moscow, St. Petersburg, Volgograd (RTZ 2)" zone. - // In 2011 the daylight saving will go through the end of the year. If we use the end of 2011 as the daylight saving end, - // that will fail the conversion because the UTC time +4 hours (3 hours for the zone UTC offset and 1 hour for daylight saving) will move us to the next year "1/1/2012 12:00 AM", - // checking against the end of 2011 will tell we are not in daylight saving which is wrong and the conversion will be off by one hour. - // Note we handle the similar case when rule year start with daylight saving and previous year end with daylight saving. - - bool ignoreYearAdjustment = false; - TimeSpan dstStartOffset = zone.GetDaylightSavingsStartOffsetFromUtc(utc, rule, ruleIndex); - DateTime startTime; - if (rule.IsStartDateMarkerForBeginningOfYear() && daylightTime.Start.Year > DateTime.MinValue.Year) - { - int? previousYearRuleIndex; - AdjustmentRule previousYearRule = zone.GetAdjustmentRuleForTime( - new DateTime(daylightTime.Start.Year - 1, 12, 31), - out previousYearRuleIndex); - if (previousYearRule != null && previousYearRule.IsEndDateMarkerForEndOfYear()) - { - DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime( - daylightTime.Start.Year - 1, - previousYearRule, - previousYearRuleIndex); - startTime = previousDaylightTime.Start - utc - previousYearRule.BaseUtcOffsetDelta; - ignoreYearAdjustment = true; - } - else - { - startTime = new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) - dstStartOffset; - } - } - else - { - startTime = daylightTime.Start - dstStartOffset; - } - - TimeSpan dstEndOffset = zone.GetDaylightSavingsEndOffsetFromUtc(utc, rule); - DateTime endTime; - if (rule.IsEndDateMarkerForEndOfYear() && daylightTime.End.Year < DateTime.MaxValue.Year) - { - int? nextYearRuleIndex; - AdjustmentRule nextYearRule = zone.GetAdjustmentRuleForTime( - new DateTime(daylightTime.End.Year + 1, 1, 1), - out nextYearRuleIndex); - if (nextYearRule != null && nextYearRule.IsStartDateMarkerForBeginningOfYear()) - { - if (nextYearRule.IsEndDateMarkerForEndOfYear()) - { - // next year end with daylight saving on too - endTime = new DateTime(daylightTime.End.Year + 1, 12, 31) - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; - } - else - { - DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime( - daylightTime.End.Year + 1, - nextYearRule, - nextYearRuleIndex); - endTime = nextdaylightTime.End - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; - } - ignoreYearAdjustment = true; - } - else - { - endTime = new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) - dstEndOffset; - } - } - else - { - endTime = daylightTime.End - dstEndOffset; - } - - DateTime ambiguousStart; - DateTime ambiguousEnd; - if (daylightTime.Delta.Ticks > 0) - { - ambiguousStart = endTime - daylightTime.Delta; - ambiguousEnd = endTime; - } - else - { - ambiguousStart = startTime; - ambiguousEnd = startTime - daylightTime.Delta; - } - - bool isDst = CheckIsDst(startTime, time, endTime, ignoreYearAdjustment, rule); - - // See if the resulting local time becomes ambiguous. This must be captured here or the - // DateTime will not be able to round-trip back to UTC accurately. - if (isDst) - { - isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); - - if (!isAmbiguousLocalDst && ambiguousStart.Year != ambiguousEnd.Year) - { - // there exists an extreme corner case where the start or end period is on a year boundary and - // because of this the comparison above might have been performed for a year-early or a year-later - // than it should have been. - DateTime ambiguousStartModified; - DateTime ambiguousEndModified; - try - { - ambiguousStartModified = ambiguousStart.AddYears(1); - ambiguousEndModified = ambiguousEnd.AddYears(1); - isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); - } - catch (ArgumentOutOfRangeException) { } - - if (!isAmbiguousLocalDst) - { - try - { - ambiguousStartModified = ambiguousStart.AddYears(-1); - ambiguousEndModified = ambiguousEnd.AddYears(-1); - isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); - } - catch (ArgumentOutOfRangeException) { } - } - } - } - - return isDst; - } - - private static bool CheckIsDst(DateTime startTime, DateTime time, DateTime endTime, bool ignoreYearAdjustment, AdjustmentRule rule) - { - // NoDaylightTransitions AdjustmentRules should never get their year adjusted since they adjust the offset for the - // entire time period - which may be for multiple years - if (!ignoreYearAdjustment && !rule.NoDaylightTransitions) - { - int startTimeYear = startTime.Year; - int endTimeYear = endTime.Year; - - if (startTimeYear != endTimeYear) - { - endTime = endTime.AddYears(startTimeYear - endTimeYear); - } - - int timeYear = time.Year; - - if (startTimeYear != timeYear) - { - time = time.AddYears(startTimeYear - timeYear); - } - } - - if (startTime > endTime) - { - // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year. - // Note, the summer in the southern hemisphere begins late in the year. - return (time < endTime || time >= startTime); - } - else if (rule.NoDaylightTransitions) - { - // In NoDaylightTransitions AdjustmentRules, the startTime is always before the endTime, - // and both the start and end times are inclusive - return time >= startTime && time <= endTime; - } - else - { - // In northern hemisphere, the daylight saving time starts in the middle of the year. - return time >= startTime && time < endTime; - } - } - - /// - /// Returns true when the dateTime falls into an ambiguous time range. - /// - /// For example, in Pacific Standard Time on Sunday, October 29, 2006 time jumps from - /// 2AM to 1AM. This means the timeline on Sunday proceeds as follows: - /// 12AM ... [1AM ... 1:59:59AM -> 1AM ... 1:59:59AM] 2AM ... 3AM ... - /// - /// In this example, any DateTime values that fall into the [1AM - 1:59:59AM] range - /// are ambiguous; as it is unclear if these times are in Daylight Saving Time. - /// - private static bool GetIsAmbiguousTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) - { - bool isAmbiguous = false; - if (rule == null || rule.DaylightDelta == TimeSpan.Zero) - { - return isAmbiguous; - } - - DateTime startAmbiguousTime; - DateTime endAmbiguousTime; - - // if at DST start we transition forward in time then there is an ambiguous time range at the DST end - if (rule.DaylightDelta > TimeSpan.Zero) - { - if (rule.IsEndDateMarkerForEndOfYear()) - { // year end with daylight on so there is no ambiguous time - return false; - } - startAmbiguousTime = daylightTime.End; - endAmbiguousTime = daylightTime.End - rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ - } - else - { - if (rule.IsStartDateMarkerForBeginningOfYear()) - { // year start with daylight on so there is no ambiguous time - return false; - } - startAmbiguousTime = daylightTime.Start; - endAmbiguousTime = daylightTime.Start + rule.DaylightDelta; /* FUTURE: - rule.StandardDelta; */ - } - - isAmbiguous = (time >= endAmbiguousTime && time < startAmbiguousTime); - - if (!isAmbiguous && startAmbiguousTime.Year != endAmbiguousTime.Year) - { - // there exists an extreme corner case where the start or end period is on a year boundary and - // because of this the comparison above might have been performed for a year-early or a year-later - // than it should have been. - DateTime startModifiedAmbiguousTime; - DateTime endModifiedAmbiguousTime; - try - { - startModifiedAmbiguousTime = startAmbiguousTime.AddYears(1); - endModifiedAmbiguousTime = endAmbiguousTime.AddYears(1); - isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime); - } - catch (ArgumentOutOfRangeException) { } - - if (!isAmbiguous) - { - try - { - startModifiedAmbiguousTime = startAmbiguousTime.AddYears(-1); - endModifiedAmbiguousTime = endAmbiguousTime.AddYears(-1); - isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime); - } - catch (ArgumentOutOfRangeException) { } - } - } - return isAmbiguous; - } - - /// - /// Helper function that checks if a given DateTime is in an invalid time ("time hole") - /// A "time hole" occurs at a DST transition point when time jumps forward; - /// For example, in Pacific Standard Time on Sunday, April 2, 2006 time jumps from - /// 1:59:59.9999999 to 3AM. The time range 2AM to 2:59:59.9999999AM is the "time hole". - /// A "time hole" is not limited to only occurring at the start of DST, and may occur at - /// the end of DST as well. - /// - private static bool GetIsInvalidTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) - { - bool isInvalid = false; - if (rule == null || rule.DaylightDelta == TimeSpan.Zero) - { - return isInvalid; - } - - DateTime startInvalidTime; - DateTime endInvalidTime; - - // if at DST start we transition forward in time then there is an ambiguous time range at the DST end - if (rule.DaylightDelta < TimeSpan.Zero) - { - // if the year ends with daylight saving on then there cannot be any time-hole's in that year. - if (rule.IsEndDateMarkerForEndOfYear()) - return false; - - startInvalidTime = daylightTime.End; - endInvalidTime = daylightTime.End - rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ - } - else - { - // if the year starts with daylight saving on then there cannot be any time-hole's in that year. - if (rule.IsStartDateMarkerForBeginningOfYear()) - return false; - - startInvalidTime = daylightTime.Start; - endInvalidTime = daylightTime.Start + rule.DaylightDelta; /* FUTURE: - rule.StandardDelta; */ - } - - isInvalid = (time >= startInvalidTime && time < endInvalidTime); - - if (!isInvalid && startInvalidTime.Year != endInvalidTime.Year) - { - // there exists an extreme corner case where the start or end period is on a year boundary and - // because of this the comparison above might have been performed for a year-early or a year-later - // than it should have been. - DateTime startModifiedInvalidTime; - DateTime endModifiedInvalidTime; - try - { - startModifiedInvalidTime = startInvalidTime.AddYears(1); - endModifiedInvalidTime = endInvalidTime.AddYears(1); - isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime); - } - catch (ArgumentOutOfRangeException) { } - - if (!isInvalid) - { - try - { - startModifiedInvalidTime = startInvalidTime.AddYears(-1); - endModifiedInvalidTime = endInvalidTime.AddYears(-1); - isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime); - } - catch (ArgumentOutOfRangeException) { } - } - } - return isInvalid; - } - - /// - /// Helper function that calculates the UTC offset for a dateTime in a timeZone. - /// This function assumes that the dateTime is already converted into the timeZone. - /// - private static TimeSpan GetUtcOffset(DateTime time, TimeZoneInfo zone, TimeZoneInfoOptions flags) - { - TimeSpan baseOffset = zone.BaseUtcOffset; - int? ruleIndex; - AdjustmentRule rule = zone.GetAdjustmentRuleForTime(time, out ruleIndex); - - if (rule != null) - { - baseOffset = baseOffset + rule.BaseUtcOffsetDelta; - if (rule.HasDaylightSaving) - { - DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule, ruleIndex); - bool isDaylightSavings = GetIsDaylightSavings(time, rule, daylightTime, flags); - baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); - } - } - - return baseOffset; - } - - /// - /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. - /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. - /// - private static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone) - { - bool isDaylightSavings; - return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings); - } - - /// - /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. - /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. - /// - private static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out bool isDaylightSavings) - { - bool isAmbiguousLocalDst; - return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings, out isAmbiguousLocalDst); - } - - /// - /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. - /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. - /// - internal static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out bool isDaylightSavings, out bool isAmbiguousLocalDst) - { - isDaylightSavings = false; - isAmbiguousLocalDst = false; - TimeSpan baseOffset = zone.BaseUtcOffset; - int year; - int? ruleIndex; - AdjustmentRule rule; - - if (time > s_maxDateOnly) - { - rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue, out ruleIndex); - year = 9999; - } - else if (time < s_minDateOnly) - { - rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue, out ruleIndex); - year = 1; - } - else - { - rule = zone.GetAdjustmentRuleForTime(time, dateTimeisUtc: true, ruleIndex: out ruleIndex); - Debug.Assert(rule == null || ruleIndex.HasValue, - "If GetAdjustmentRuleForTime returned an AdjustmentRule, ruleIndex should also be set."); - - // As we get the associated rule using the adjusted targetTime, we should use the adjusted year (targetTime.Year) too as after adding the baseOffset, - // sometimes the year value can change if the input datetime was very close to the beginning or the end of the year. Examples of such cases: - // Libya Standard Time when used with the date 2011-12-31T23:59:59.9999999Z - // "W. Australia Standard Time" used with date 2005-12-31T23:59:00.0000000Z - DateTime targetTime = time + baseOffset; - year = targetTime.Year; - } - - if (rule != null) - { - baseOffset = baseOffset + rule.BaseUtcOffsetDelta; - if (rule.HasDaylightSaving) - { - isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone._baseUtcOffset, rule, ruleIndex, out isAmbiguousLocalDst, zone); - baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); - } - } - - return baseOffset; - } - - /// - /// Helper function that converts a year and TransitionTime into a DateTime. - /// - internal static DateTime TransitionTimeToDateTime(int year, TransitionTime transitionTime) - { - DateTime value; - DateTime timeOfDay = transitionTime.TimeOfDay; - - if (transitionTime.IsFixedDateRule) - { - // create a DateTime from the passed in year and the properties on the transitionTime - - // if the day is out of range for the month then use the last day of the month - int day = DateTime.DaysInMonth(year, transitionTime.Month); - - value = new DateTime(year, transitionTime.Month, (day < transitionTime.Day) ? day : transitionTime.Day, - timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); - } - else - { - if (transitionTime.Week <= 4) - { - // - // Get the (transitionTime.Week)th Sunday. - // - value = new DateTime(year, transitionTime.Month, 1, - timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); - - int dayOfWeek = (int)value.DayOfWeek; - int delta = (int)transitionTime.DayOfWeek - dayOfWeek; - if (delta < 0) - { - delta += 7; - } - delta += 7 * (transitionTime.Week - 1); - - if (delta > 0) - { - value = value.AddDays(delta); - } - } - else - { - // - // If TransitionWeek is greater than 4, we will get the last week. - // - int daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month); - value = new DateTime(year, transitionTime.Month, daysInMonth, - timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); - - // This is the day of week for the last day of the month. - int dayOfWeek = (int)value.DayOfWeek; - int delta = dayOfWeek - (int)transitionTime.DayOfWeek; - if (delta < 0) - { - delta += 7; - } - - if (delta > 0) - { - value = value.AddDays(-delta); - } - } - } - return value; - } - - /// - /// Helper function for retrieving a TimeZoneInfo object by time_zone_name. - /// - /// This function may return null. - /// - /// assumes cachedData lock is taken - /// - private static TimeZoneInfoResult TryGetTimeZone(string id, bool dstDisabled, out TimeZoneInfo value, out Exception e, CachedData cachedData, bool alwaysFallbackToLocalMachine = false) - { - Debug.Assert(Monitor.IsEntered(cachedData)); - - TimeZoneInfoResult result = TimeZoneInfoResult.Success; - e = null; - TimeZoneInfo match = null; - - // check the cache - if (cachedData._systemTimeZones != null) - { - if (cachedData._systemTimeZones.TryGetValue(id, out match)) - { - if (dstDisabled && match._supportsDaylightSavingTime) - { - // we found a cache hit but we want a time zone without DST and this one has DST data - value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); - } - else - { - value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, - match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); - } - return result; - } - } - - // Fall back to reading from the local machine when the cache is not fully populated. - // On UNIX, there may be some tzfiles that aren't in the zones.tab file, and thus aren't returned from GetSystemTimeZones(). - // If a caller asks for one of these zones before calling GetSystemTimeZones(), the time zone is returned successfully. But if - // GetSystemTimeZones() is called first, FindSystemTimeZoneById will throw TimeZoneNotFoundException, which is inconsistent. - // To fix this, when 'alwaysFallbackToLocalMachine' is true, even if _allSystemTimeZonesRead is true, try reading the tzfile - // from disk, but don't add the time zone to the list returned from GetSystemTimeZones(). These time zones will only be - // available if asked for directly. - if (!cachedData._allSystemTimeZonesRead || alwaysFallbackToLocalMachine) - { - result = TryGetTimeZoneFromLocalMachine(id, dstDisabled, out value, out e, cachedData); - } - else - { - result = TimeZoneInfoResult.TimeZoneNotFoundException; - value = null; - } - - return result; - } - - private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool dstDisabled, out TimeZoneInfo value, out Exception e, CachedData cachedData) - { - TimeZoneInfoResult result; - TimeZoneInfo match; - - result = TryGetTimeZoneFromLocalMachine(id, out match, out e); - - if (result == TimeZoneInfoResult.Success) - { - if (cachedData._systemTimeZones == null) - cachedData._systemTimeZones = new Dictionary(StringComparer.OrdinalIgnoreCase); - - cachedData._systemTimeZones.Add(id, match); - - if (dstDisabled && match._supportsDaylightSavingTime) - { - // we found a cache hit but we want a time zone without DST and this one has DST data - value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); - } - else - { - value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, - match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); - } - } - else - { - value = null; - } - - return result; - } - - /// - /// Helper function that performs all of the validation checks for the - /// factory methods and deserialization callback. - /// - private static void ValidateTimeZoneInfo(string id, TimeSpan baseUtcOffset, AdjustmentRule[] adjustmentRules, out bool adjustmentRulesSupportDst) - { - if (id == null) - { - throw new ArgumentNullException(nameof(id)); - } - - if (id.Length == 0) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidId, id), nameof(id)); - } - - if (UtcOffsetOutOfRange(baseUtcOffset)) - { - throw new ArgumentOutOfRangeException(nameof(baseUtcOffset), SR.ArgumentOutOfRange_UtcOffset); - } - - if (baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) - { - throw new ArgumentException(SR.Argument_TimeSpanHasSeconds, nameof(baseUtcOffset)); - } - - adjustmentRulesSupportDst = false; - - // - // "adjustmentRules" can either be null or a valid array of AdjustmentRule objects. - // A valid array is one that does not contain any null elements and all elements - // are sorted in chronological order - // - - if (adjustmentRules != null && adjustmentRules.Length != 0) - { - adjustmentRulesSupportDst = true; - AdjustmentRule prev = null; - AdjustmentRule current = null; - for (int i = 0; i < adjustmentRules.Length; i++) - { - prev = current; - current = adjustmentRules[i]; - - if (current == null) - { - throw new InvalidTimeZoneException(SR.Argument_AdjustmentRulesNoNulls); - } - - if (!IsValidAdjustmentRuleOffest(baseUtcOffset, current)) - { - throw new InvalidTimeZoneException(SR.ArgumentOutOfRange_UtcOffsetAndDaylightDelta); - } - - if (prev != null && current.DateStart <= prev.DateEnd) - { - // verify the rules are in chronological order and the DateStart/DateEnd do not overlap - throw new InvalidTimeZoneException(SR.Argument_AdjustmentRulesOutOfOrder); - } - } - } - } - - private static readonly TimeSpan MaxOffset = TimeSpan.FromHours(14.0); - private static readonly TimeSpan MinOffset = -MaxOffset; - - /// - /// Helper function that validates the TimeSpan is within +/- 14.0 hours - /// - internal static bool UtcOffsetOutOfRange(TimeSpan offset) => - offset < MinOffset || offset > MaxOffset; - - private static TimeSpan GetUtcOffset(TimeSpan baseUtcOffset, AdjustmentRule adjustmentRule) - { - return baseUtcOffset - + adjustmentRule.BaseUtcOffsetDelta - + (adjustmentRule.HasDaylightSaving ? adjustmentRule.DaylightDelta : TimeSpan.Zero); - } - - /// - /// Helper function that performs adjustment rule validation - /// - private static bool IsValidAdjustmentRuleOffest(TimeSpan baseUtcOffset, AdjustmentRule adjustmentRule) - { - TimeSpan utcOffset = GetUtcOffset(baseUtcOffset, adjustmentRule); - return !UtcOffsetOutOfRange(utcOffset); - } - - /// - /// Normalize adjustment rule offset so that it is within valid range - /// This method should not be called at all but is here in case something changes in the future - /// or if really old time zones are present on the OS (no combination is known at the moment) - /// - private static void NormalizeAdjustmentRuleOffset(TimeSpan baseUtcOffset, ref AdjustmentRule adjustmentRule) - { - // Certain time zones such as: - // Time Zone start date end date offset - // ----------------------------------------------------- - // America/Yakutat 0001-01-01 1867-10-18 14:41:00 - // America/Yakutat 1867-10-18 1900-08-20 14:41:00 - // America/Sitka 0001-01-01 1867-10-18 14:58:00 - // America/Sitka 1867-10-18 1900-08-20 14:58:00 - // Asia/Manila 0001-01-01 1844-12-31 -15:56:00 - // Pacific/Guam 0001-01-01 1845-01-01 -14:21:00 - // Pacific/Saipan 0001-01-01 1845-01-01 -14:21:00 - // - // have larger offset than currently supported by framework. - // If for whatever reason we find that time zone exceeding max - // offset of 14h this function will truncate it to the max valid offset. - // Updating max offset may cause problems with interacting with SQL server - // which uses SQL DATETIMEOFFSET field type which was originally designed to be - // bit-for-bit compatible with DateTimeOffset. - - TimeSpan utcOffset = GetUtcOffset(baseUtcOffset, adjustmentRule); - - // utc base offset delta increment - TimeSpan adjustment = TimeSpan.Zero; - - if (utcOffset > MaxOffset) - { - adjustment = MaxOffset - utcOffset; - } - else if (utcOffset < MinOffset) - { - adjustment = MinOffset - utcOffset; - } - - if (adjustment != TimeSpan.Zero) - { - adjustmentRule = AdjustmentRule.CreateAdjustmentRule( - adjustmentRule.DateStart, - adjustmentRule.DateEnd, - adjustmentRule.DaylightDelta, - adjustmentRule.DaylightTransitionStart, - adjustmentRule.DaylightTransitionEnd, - adjustmentRule.BaseUtcOffsetDelta + adjustment, - adjustmentRule.NoDaylightTransitions); - } - } - } -} +// Licensed to the .NET Foundation under one or more agreements. +// 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.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.Serialization; +using System.Threading; + +namespace System +{ + // + // DateTime uses TimeZoneInfo under the hood for IsDaylightSavingTime, IsAmbiguousTime, and GetUtcOffset. + // These TimeZoneInfo APIs can throw ArgumentException when an Invalid-Time is passed in. To avoid this + // unwanted behavior in DateTime public APIs, DateTime internally passes the + // TimeZoneInfoOptions.NoThrowOnInvalidTime flag to internal TimeZoneInfo APIs. + // + // In the future we can consider exposing similar options on the public TimeZoneInfo APIs if there is enough + // demand for this alternate behavior. + // + [Flags] + internal enum TimeZoneInfoOptions + { + None = 1, + NoThrowOnInvalidTime = 2 + }; + + [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public sealed partial class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback + { + private enum TimeZoneInfoResult + { + Success = 0, + TimeZoneNotFoundException = 1, + InvalidTimeZoneException = 2, + SecurityException = 3 + }; + + private readonly string _id; + private readonly string? _displayName; + private readonly string? _standardDisplayName; + private readonly string? _daylightDisplayName; + private readonly TimeSpan _baseUtcOffset; + private readonly bool _supportsDaylightSavingTime; + private readonly AdjustmentRule[]? _adjustmentRules; + + // constants for TimeZoneInfo.Local and TimeZoneInfo.Utc + private const string UtcId = "UTC"; + private const string LocalId = "Local"; + + private static readonly TimeZoneInfo s_utcTimeZone = CreateCustomTimeZone(UtcId, TimeSpan.Zero, UtcId, UtcId); + + private static CachedData s_cachedData = new CachedData(); + + // + // All cached data are encapsulated in a helper class to allow consistent view even when the data are refreshed using ClearCachedData() + // + // For example, TimeZoneInfo.Local can be cleared by another thread calling TimeZoneInfo.ClearCachedData. Without the consistent snapshot, + // there is a chance that the internal ConvertTime calls will throw since 'source' won't be reference equal to the new TimeZoneInfo.Local. + // + private sealed partial class CachedData + { + private volatile TimeZoneInfo? _localTimeZone; + + private TimeZoneInfo CreateLocal() + { + lock (this) + { + TimeZoneInfo? timeZone = _localTimeZone; + if (timeZone == null) + { + timeZone = GetLocalTimeZone(this); + + // this step is to break the reference equality + // between TimeZoneInfo.Local and a second time zone + // such as "Pacific Standard Time" + timeZone = new TimeZoneInfo( + timeZone._id, + timeZone._baseUtcOffset, + timeZone._displayName, + timeZone._standardDisplayName, + timeZone._daylightDisplayName, + timeZone._adjustmentRules, + disableDaylightSavingTime: false); + + _localTimeZone = timeZone; + } + return timeZone; + } + } + + public TimeZoneInfo Local + { + get + { + TimeZoneInfo? timeZone = _localTimeZone; + if (timeZone == null) + { + timeZone = CreateLocal(); + } + return timeZone; + } + } + + /// + /// Helper function that returns the corresponding DateTimeKind for this TimeZoneInfo. + /// + public DateTimeKind GetCorrespondingKind(TimeZoneInfo? timeZone) + { + // We check reference equality to see if 'this' is the same as + // TimeZoneInfo.Local or TimeZoneInfo.Utc. This check is needed to + // support setting the DateTime Kind property to 'Local' or + // 'Utc' on the ConverTime(...) return value. + // + // Using reference equality instead of value equality was a + // performance based design compromise. The reference equality + // has much greater performance, but it reduces the number of + // returned DateTime's that can be properly set as 'Local' or 'Utc'. + // + // For example, the user could be converting to the TimeZoneInfo returned + // by FindSystemTimeZoneById("Pacific Standard Time") and their local + // machine may be in Pacific time. If we used value equality to determine + // the corresponding Kind then this conversion would be tagged as 'Local'; + // where as we are currently tagging the returned DateTime as 'Unspecified' + // in this example. Only when the user passes in TimeZoneInfo.Local or + // TimeZoneInfo.Utc to the ConvertTime(...) methods will this check succeed. + // + return + ReferenceEquals(timeZone, s_utcTimeZone) ? DateTimeKind.Utc : + ReferenceEquals(timeZone, _localTimeZone) ? DateTimeKind.Local : + DateTimeKind.Unspecified; + } + + public Dictionary? _systemTimeZones; + public ReadOnlyCollection? _readOnlySystemTimeZones; + public bool _allSystemTimeZonesRead; + }; + + // used by GetUtcOffsetFromUtc (DateTime.Now, DateTime.ToLocalTime) for max/min whole-day range checks + private static readonly DateTime s_maxDateOnly = new DateTime(9999, 12, 31); + private static readonly DateTime s_minDateOnly = new DateTime(1, 1, 2); + + public string Id => _id; + + public string DisplayName => _displayName ?? string.Empty; + + public string StandardName => _standardDisplayName ?? string.Empty; + + public string DaylightName => _daylightDisplayName ?? string.Empty; + + public TimeSpan BaseUtcOffset => _baseUtcOffset; + + public bool SupportsDaylightSavingTime => _supportsDaylightSavingTime; + + /// + /// Returns an array of TimeSpan objects representing all of + /// possible UTC offset values for this ambiguous time. + /// + public TimeSpan[] GetAmbiguousTimeOffsets(DateTimeOffset dateTimeOffset) + { + if (!SupportsDaylightSavingTime) + { + throw new ArgumentException(SR.Argument_DateTimeOffsetIsNotAmbiguous, nameof(dateTimeOffset)); + } + + DateTime adjustedTime = ConvertTime(dateTimeOffset, this).DateTime; + + bool isAmbiguous = false; + int? ruleIndex; + AdjustmentRule? rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); + } + + if (!isAmbiguous) + { + throw new ArgumentException(SR.Argument_DateTimeOffsetIsNotAmbiguous, nameof(dateTimeOffset)); + } + + // the passed in dateTime is ambiguous in this TimeZoneInfo instance + TimeSpan[] timeSpans = new TimeSpan[2]; + + TimeSpan actualUtcOffset = _baseUtcOffset + rule!.BaseUtcOffsetDelta; + + // the TimeSpan array must be sorted from least to greatest + if (rule.DaylightDelta > TimeSpan.Zero) + { + timeSpans[0] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + timeSpans[1] = actualUtcOffset + rule.DaylightDelta; + } + else + { + timeSpans[0] = actualUtcOffset + rule.DaylightDelta; + timeSpans[1] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + } + return timeSpans; + } + + /// + /// Returns an array of TimeSpan objects representing all of + /// possible UTC offset values for this ambiguous time. + /// + public TimeSpan[] GetAmbiguousTimeOffsets(DateTime dateTime) + { + if (!SupportsDaylightSavingTime) + { + throw new ArgumentException(SR.Argument_DateTimeIsNotAmbiguous, nameof(dateTime)); + } + + DateTime adjustedTime; + if (dateTime.Kind == DateTimeKind.Local) + { + CachedData cachedData = s_cachedData; + adjustedTime = ConvertTime(dateTime, cachedData.Local, this, TimeZoneInfoOptions.None, cachedData); + } + else if (dateTime.Kind == DateTimeKind.Utc) + { + CachedData cachedData = s_cachedData; + adjustedTime = ConvertTime(dateTime, s_utcTimeZone, this, TimeZoneInfoOptions.None, cachedData); + } + else + { + adjustedTime = dateTime; + } + + bool isAmbiguous = false; + int? ruleIndex; + AdjustmentRule? rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); + } + + if (!isAmbiguous) + { + throw new ArgumentException(SR.Argument_DateTimeIsNotAmbiguous, nameof(dateTime)); + } + + // the passed in dateTime is ambiguous in this TimeZoneInfo instance + TimeSpan[] timeSpans = new TimeSpan[2]; + TimeSpan actualUtcOffset = _baseUtcOffset + rule!.BaseUtcOffsetDelta; + + // the TimeSpan array must be sorted from least to greatest + if (rule.DaylightDelta > TimeSpan.Zero) + { + timeSpans[0] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + timeSpans[1] = actualUtcOffset + rule.DaylightDelta; + } + else + { + timeSpans[0] = actualUtcOffset + rule.DaylightDelta; + timeSpans[1] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + } + return timeSpans; + } + + // note the time is already adjusted + private AdjustmentRule? GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTime, out int? ruleIndex) + { + AdjustmentRule? rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + if (rule != null && rule.NoDaylightTransitions && !rule.HasDaylightSaving) + { + // When using NoDaylightTransitions rules, each rule is only for one offset. + // When looking for the Daylight savings rules, and we found the non-DST rule, + // then we get the rule right before this rule. + return GetPreviousAdjustmentRule(rule, ruleIndex); + } + + return rule; + } + + /// + /// Gets the AdjustmentRule that is immediately preceding the specified rule. + /// If the specified rule is the first AdjustmentRule, or it isn't in _adjustmentRules, + /// then the specified rule is returned. + /// + private AdjustmentRule GetPreviousAdjustmentRule(AdjustmentRule rule, int? ruleIndex) + { + Debug.Assert(rule.NoDaylightTransitions, "GetPreviousAdjustmentRule should only be used with NoDaylightTransitions rules."); + Debug.Assert(_adjustmentRules != null); + + if (ruleIndex.HasValue && 0 < ruleIndex.GetValueOrDefault() && ruleIndex.GetValueOrDefault() < _adjustmentRules.Length) + { + return _adjustmentRules[ruleIndex.GetValueOrDefault() - 1]; + } + + AdjustmentRule result = rule; + for (int i = 1; i < _adjustmentRules.Length; i++) + { + // use ReferenceEquals here instead of AdjustmentRule.Equals because + // ReferenceEquals is much faster. This is safe because all the callers + // of GetPreviousAdjustmentRule pass in a rule that was retrieved from + // _adjustmentRules. A different approach will be needed if this ever changes. + if (ReferenceEquals(rule, _adjustmentRules[i])) + { + result = _adjustmentRules[i - 1]; + break; + } + } + return result; + } + + /// + /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. + /// + public TimeSpan GetUtcOffset(DateTimeOffset dateTimeOffset) => + GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this); + + /// + /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. + /// + public TimeSpan GetUtcOffset(DateTime dateTime) => + GetUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime, s_cachedData); + + // Shortcut for TimeZoneInfo.Local.GetUtcOffset + internal static TimeSpan GetLocalUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags) + { + CachedData cachedData = s_cachedData; + return cachedData.Local.GetUtcOffset(dateTime, flags, cachedData); + } + + /// + /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. + /// + internal TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags) => + GetUtcOffset(dateTime, flags, s_cachedData); + + private TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags, CachedData cachedData) + { + if (dateTime.Kind == DateTimeKind.Local) + { + if (cachedData.GetCorrespondingKind(this) != DateTimeKind.Local) + { + // + // normal case of converting from Local to Utc and then getting the offset from the UTC DateTime + // + DateTime adjustedTime = ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, flags); + return GetUtcOffsetFromUtc(adjustedTime, this); + } + + // + // Fall through for TimeZoneInfo.Local.GetUtcOffset(date) + // to handle an edge case with Invalid-Times for DateTime formatting: + // + // Consider the invalid PST time "2007-03-11T02:00:00.0000000-08:00" + // + // By directly calling GetUtcOffset instead of converting to UTC and then calling GetUtcOffsetFromUtc + // the correct invalid offset of "-08:00" is returned. In the normal case of converting to UTC as an + // interim-step, the invalid time is adjusted into a *valid* UTC time which causes a change in output: + // + // 1) invalid PST time "2007-03-11T02:00:00.0000000-08:00" + // 2) converted to UTC "2007-03-11T10:00:00.0000000Z" + // 3) offset returned "2007-03-11T03:00:00.0000000-07:00" + // + } + else if (dateTime.Kind == DateTimeKind.Utc) + { + if (cachedData.GetCorrespondingKind(this) == DateTimeKind.Utc) + { + return _baseUtcOffset; + } + else + { + // + // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a + // special Loss-Less case. + // + return GetUtcOffsetFromUtc(dateTime, this); + } + } + + return GetUtcOffset(dateTime, this, flags); + } + + /// + /// Returns true if the time is during the ambiguous time period + /// for the current TimeZoneInfo instance. + /// + public bool IsAmbiguousTime(DateTimeOffset dateTimeOffset) + { + if (!_supportsDaylightSavingTime) + { + return false; + } + + DateTimeOffset adjustedTime = ConvertTime(dateTimeOffset, this); + return IsAmbiguousTime(adjustedTime.DateTime); + } + + /// + /// Returns true if the time is during the ambiguous time period + /// for the current TimeZoneInfo instance. + /// + public bool IsAmbiguousTime(DateTime dateTime) => + IsAmbiguousTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime); + + /// + /// Returns true if the time is during the ambiguous time period + /// for the current TimeZoneInfo instance. + /// + internal bool IsAmbiguousTime(DateTime dateTime, TimeZoneInfoOptions flags) + { + if (!_supportsDaylightSavingTime) + { + return false; + } + + CachedData cachedData = s_cachedData; + DateTime adjustedTime = + dateTime.Kind == DateTimeKind.Local ? ConvertTime(dateTime, cachedData.Local, this, flags, cachedData) : + dateTime.Kind == DateTimeKind.Utc ? ConvertTime(dateTime, s_utcTimeZone, this, flags, cachedData) : + dateTime; + + int? ruleIndex; + AdjustmentRule? rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + return GetIsAmbiguousTime(adjustedTime, rule, daylightTime); + } + return false; + } + + /// + /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. + /// + public bool IsDaylightSavingTime(DateTimeOffset dateTimeOffset) + { + bool isDaylightSavingTime; + GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this, out isDaylightSavingTime); + return isDaylightSavingTime; + } + + /// + /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. + /// + public bool IsDaylightSavingTime(DateTime dateTime) => + IsDaylightSavingTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime, s_cachedData); + + /// + /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. + /// + internal bool IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags) => + IsDaylightSavingTime(dateTime, flags, s_cachedData); + + private bool IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags, CachedData cachedData) + { + // + // dateTime.Kind is UTC, then time will be converted from UTC + // into current instance's timezone + // dateTime.Kind is Local, then time will be converted from Local + // into current instance's timezone + // dateTime.Kind is UnSpecified, then time is already in + // current instance's timezone + // + // Our DateTime handles ambiguous times, (one is in the daylight and + // one is in standard.) If a new DateTime is constructed during ambiguous + // time, it is defaulted to "Standard" (i.e. this will return false). + // For Invalid times, we will return false + + if (!_supportsDaylightSavingTime || _adjustmentRules == null) + { + return false; + } + + DateTime adjustedTime; + // + // handle any Local/Utc special cases... + // + if (dateTime.Kind == DateTimeKind.Local) + { + adjustedTime = ConvertTime(dateTime, cachedData.Local, this, flags, cachedData); + } + else if (dateTime.Kind == DateTimeKind.Utc) + { + if (cachedData.GetCorrespondingKind(this) == DateTimeKind.Utc) + { + // simple always false case: TimeZoneInfo.Utc.IsDaylightSavingTime(dateTime, flags); + return false; + } + else + { + // + // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a + // special Loss-Less case. + // + bool isDaylightSavings; + GetUtcOffsetFromUtc(dateTime, this, out isDaylightSavings); + return isDaylightSavings; + } + } + else + { + adjustedTime = dateTime; + } + + // + // handle the normal cases... + // + int? ruleIndex; + AdjustmentRule? rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + return GetIsDaylightSavings(adjustedTime, rule, daylightTime, flags); + } + else + { + return false; + } + } + + /// + /// Returns true when dateTime falls into a "hole in time". + /// + public bool IsInvalidTime(DateTime dateTime) + { + bool isInvalid = false; + + if ((dateTime.Kind == DateTimeKind.Unspecified) || + (dateTime.Kind == DateTimeKind.Local && s_cachedData.GetCorrespondingKind(this) == DateTimeKind.Local)) + { + // only check Unspecified and (Local when this TimeZoneInfo instance is Local) + int? ruleIndex; + AdjustmentRule? rule = GetAdjustmentRuleForTime(dateTime, out ruleIndex); + + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule, ruleIndex); + isInvalid = GetIsInvalidTime(dateTime, rule, daylightTime); + } + else + { + isInvalid = false; + } + } + + return isInvalid; + } + + /// + /// Clears data from static members. + /// + public static void ClearCachedData() + { + // Clear a fresh instance of cached data + s_cachedData = new CachedData(); + } + + /// + /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. + /// + public static DateTimeOffset ConvertTimeBySystemTimeZoneId(DateTimeOffset dateTimeOffset, string destinationTimeZoneId) => + ConvertTime(dateTimeOffset, FindSystemTimeZoneById(destinationTimeZoneId)); + + /// + /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. + /// + public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, string destinationTimeZoneId) => + ConvertTime(dateTime, FindSystemTimeZoneById(destinationTimeZoneId)); + + /// + /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. + /// + public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, string sourceTimeZoneId, string destinationTimeZoneId) + { + if (dateTime.Kind == DateTimeKind.Local && string.Equals(sourceTimeZoneId, Local.Id, StringComparison.OrdinalIgnoreCase)) + { + // TimeZoneInfo.Local can be cleared by another thread calling TimeZoneInfo.ClearCachedData. + // Take snapshot of cached data to guarantee this method will not be impacted by the ClearCachedData call. + // Without the snapshot, there is a chance that ConvertTime will throw since 'source' won't + // be reference equal to the new TimeZoneInfo.Local + // + CachedData cachedData = s_cachedData; + return ConvertTime(dateTime, cachedData.Local, FindSystemTimeZoneById(destinationTimeZoneId), TimeZoneInfoOptions.None, cachedData); + } + else if (dateTime.Kind == DateTimeKind.Utc && string.Equals(sourceTimeZoneId, Utc.Id, StringComparison.OrdinalIgnoreCase)) + { + return ConvertTime(dateTime, s_utcTimeZone, FindSystemTimeZoneById(destinationTimeZoneId), TimeZoneInfoOptions.None, s_cachedData); + } + else + { + return ConvertTime(dateTime, FindSystemTimeZoneById(sourceTimeZoneId), FindSystemTimeZoneById(destinationTimeZoneId)); + } + } + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + public static DateTimeOffset ConvertTime(DateTimeOffset dateTimeOffset, TimeZoneInfo destinationTimeZone) + { + if (destinationTimeZone == null) + { + throw new ArgumentNullException(nameof(destinationTimeZone)); + } + + // calculate the destination time zone offset + DateTime utcDateTime = dateTimeOffset.UtcDateTime; + TimeSpan destinationOffset = GetUtcOffsetFromUtc(utcDateTime, destinationTimeZone); + + // check for overflow + long ticks = utcDateTime.Ticks + destinationOffset.Ticks; + + return + ticks > DateTimeOffset.MaxValue.Ticks ? DateTimeOffset.MaxValue : + ticks < DateTimeOffset.MinValue.Ticks ? DateTimeOffset.MinValue : + new DateTimeOffset(ticks, destinationOffset); + } + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + public static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo destinationTimeZone) + { + if (destinationTimeZone == null) + { + throw new ArgumentNullException(nameof(destinationTimeZone)); + } + + // Special case to give a way clearing the cache without exposing ClearCachedData() + if (dateTime.Ticks == 0) + { + ClearCachedData(); + } + CachedData cachedData = s_cachedData; + TimeZoneInfo sourceTimeZone = dateTime.Kind == DateTimeKind.Utc ? s_utcTimeZone : cachedData.Local; + return ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, cachedData); + } + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + public static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone) => + ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, s_cachedData); + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + internal static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags) => + ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, flags, s_cachedData); + + private static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags, CachedData cachedData) + { + if (sourceTimeZone == null) + { + throw new ArgumentNullException(nameof(sourceTimeZone)); + } + + if (destinationTimeZone == null) + { + throw new ArgumentNullException(nameof(destinationTimeZone)); + } + + DateTimeKind sourceKind = cachedData.GetCorrespondingKind(sourceTimeZone); + if (((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && (dateTime.Kind != DateTimeKind.Unspecified) && (dateTime.Kind != sourceKind)) + { + throw new ArgumentException(SR.Argument_ConvertMismatch, nameof(sourceTimeZone)); + } + + // + // check to see if the DateTime is in an invalid time range. This check + // requires the current AdjustmentRule and DaylightTime - which are also + // needed to calculate 'sourceOffset' in the normal conversion case. + // By calculating the 'sourceOffset' here we improve the + // performance for the normal case at the expense of the 'ArgumentException' + // case and Loss-less Local special cases. + // + int? sourceRuleIndex; + AdjustmentRule? sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime, out sourceRuleIndex); + TimeSpan sourceOffset = sourceTimeZone.BaseUtcOffset; + + if (sourceRule != null) + { + sourceOffset = sourceOffset + sourceRule.BaseUtcOffsetDelta; + if (sourceRule.HasDaylightSaving) + { + bool sourceIsDaylightSavings = false; + DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule, sourceRuleIndex); + + // 'dateTime' might be in an invalid time range since it is in an AdjustmentRule + // period that supports DST + if (((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && GetIsInvalidTime(dateTime, sourceRule, sourceDaylightTime)) + { + throw new ArgumentException(SR.Argument_DateTimeIsInvalid, nameof(dateTime)); + } + sourceIsDaylightSavings = GetIsDaylightSavings(dateTime, sourceRule, sourceDaylightTime, flags); + + // adjust the sourceOffset according to the Adjustment Rule / Daylight Saving Rule + sourceOffset += (sourceIsDaylightSavings ? sourceRule.DaylightDelta : TimeSpan.Zero /*FUTURE: sourceRule.StandardDelta*/); + } + } + + DateTimeKind targetKind = cachedData.GetCorrespondingKind(destinationTimeZone); + + // handle the special case of Loss-less Local->Local and UTC->UTC) + if (dateTime.Kind != DateTimeKind.Unspecified && sourceKind != DateTimeKind.Unspecified && sourceKind == targetKind) + { + return dateTime; + } + + long utcTicks = dateTime.Ticks - sourceOffset.Ticks; + + // handle the normal case by converting from 'source' to UTC and then to 'target' + bool isAmbiguousLocalDst; + DateTime targetConverted = ConvertUtcToTimeZone(utcTicks, destinationTimeZone, out isAmbiguousLocalDst); + + if (targetKind == DateTimeKind.Local) + { + // Because the ticks conversion between UTC and local is lossy, we need to capture whether the + // time is in a repeated hour so that it can be passed to the DateTime constructor. + return new DateTime(targetConverted.Ticks, DateTimeKind.Local, isAmbiguousLocalDst); + } + else + { + return new DateTime(targetConverted.Ticks, targetKind); + } + } + + /// + /// Converts the value of a DateTime object from Coordinated Universal Time (UTC) to the destinationTimeZone. + /// + public static DateTime ConvertTimeFromUtc(DateTime dateTime, TimeZoneInfo destinationTimeZone) => + ConvertTime(dateTime, s_utcTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, s_cachedData); + + /// + /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). + /// + public static DateTime ConvertTimeToUtc(DateTime dateTime) + { + if (dateTime.Kind == DateTimeKind.Utc) + { + return dateTime; + } + CachedData cachedData = s_cachedData; + return ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, TimeZoneInfoOptions.None, cachedData); + } + + /// + /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). + /// + internal static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfoOptions flags) + { + if (dateTime.Kind == DateTimeKind.Utc) + { + return dateTime; + } + CachedData cachedData = s_cachedData; + return ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, flags, cachedData); + } + + /// + /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). + /// + public static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfo sourceTimeZone) => + ConvertTime(dateTime, sourceTimeZone, s_utcTimeZone, TimeZoneInfoOptions.None, s_cachedData); + + /// + /// Returns value equality. Equals does not compare any localizable + /// String objects (DisplayName, StandardName, DaylightName). + /// + public bool Equals(TimeZoneInfo? other) => + other != null && + string.Equals(_id, other._id, StringComparison.OrdinalIgnoreCase) && + HasSameRules(other); + + public override bool Equals(object? obj) => Equals(obj as TimeZoneInfo); + + public static TimeZoneInfo FromSerializedString(string source) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + if (source.Length == 0) + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidSerializedString, source), nameof(source)); + } + + return StringSerializer.GetDeserializedTimeZoneInfo(source); + } + + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(_id); + + /// + /// Returns a containing all valid TimeZone's + /// from the local machine. The entries in the collection are sorted by + /// . + /// This method does *not* throw TimeZoneNotFoundException or InvalidTimeZoneException. + /// + public static ReadOnlyCollection GetSystemTimeZones() + { + CachedData cachedData = s_cachedData; + + lock (cachedData) + { + if (cachedData._readOnlySystemTimeZones == null) + { + PopulateAllSystemTimeZones(cachedData); + cachedData._allSystemTimeZonesRead = true; + + List list; + if (cachedData._systemTimeZones != null) + { + // return a collection of the cached system time zones + list = new List(cachedData._systemTimeZones.Values); + } + else + { + // return an empty collection + list = new List(); + } + + // sort and copy the TimeZoneInfo's into a ReadOnlyCollection for the user + list.Sort((x, y) => + { + // sort by BaseUtcOffset first and by DisplayName second - this is similar to the Windows Date/Time control panel + int comparison = x.BaseUtcOffset.CompareTo(y.BaseUtcOffset); + return comparison == 0 ? string.CompareOrdinal(x.DisplayName, y.DisplayName) : comparison; + }); + + cachedData._readOnlySystemTimeZones = new ReadOnlyCollection(list); + } + } + return cachedData._readOnlySystemTimeZones; + } + + /// + /// Value equality on the "adjustmentRules" array + /// + public bool HasSameRules(TimeZoneInfo other) + { + if (other == null) + { + throw new ArgumentNullException(nameof(other)); + } + + // check the utcOffset and supportsDaylightSavingTime members + if (_baseUtcOffset != other._baseUtcOffset || + _supportsDaylightSavingTime != other._supportsDaylightSavingTime) + { + return false; + } + + bool sameRules; + AdjustmentRule[]? currentRules = _adjustmentRules; + AdjustmentRule[]? otherRules = other._adjustmentRules; + + sameRules = + (currentRules == null && otherRules == null) || + (currentRules != null && otherRules != null); + + if (!sameRules) + { + // AdjustmentRule array mismatch + return false; + } + + if (currentRules != null) + { + if (currentRules.Length != otherRules!.Length) + { + // AdjustmentRule array length mismatch + return false; + } + + for (int i = 0; i < currentRules.Length; i++) + { + if (!(currentRules[i]).Equals(otherRules[i])) + { + // AdjustmentRule value-equality mismatch + return false; + } + } + } + return sameRules; + } + + /// + /// Returns a TimeZoneInfo instance that represents the local time on the machine. + /// Accessing this property may throw InvalidTimeZoneException or COMException + /// if the machine is in an unstable or corrupt state. + /// + public static TimeZoneInfo Local => s_cachedData.Local; + + // + // ToSerializedString - + // + // "TimeZoneInfo" := TimeZoneInfo Data;[AdjustmentRule Data 1];...;[AdjustmentRule Data N] + // + // "TimeZoneInfo Data" := <_id>;<_baseUtcOffset>;<_displayName>; + // <_standardDisplayName>;<_daylightDispayName>; + // + // "AdjustmentRule Data" := ;;; + // [TransitionTime Data DST Start] + // [TransitionTime Data DST End] + // + // "TransitionTime Data" += ;;;; + // + public string ToSerializedString() => StringSerializer.GetSerializedString(this); + + /// + /// Returns the : "(GMT-08:00) Pacific Time (US & Canada); Tijuana" + /// + public override string ToString() => DisplayName; + + /// + /// Returns a TimeZoneInfo instance that represents Universal Coordinated Time (UTC) + /// + public static TimeZoneInfo Utc => s_utcTimeZone; + + private TimeZoneInfo( + string id, + TimeSpan baseUtcOffset, + string? displayName, + string? standardDisplayName, + string? daylightDisplayName, + AdjustmentRule[]? adjustmentRules, + bool disableDaylightSavingTime) + { + bool adjustmentRulesSupportDst; + ValidateTimeZoneInfo(id, baseUtcOffset, adjustmentRules, out adjustmentRulesSupportDst); + + _id = id; + _baseUtcOffset = baseUtcOffset; + _displayName = displayName; + _standardDisplayName = standardDisplayName; + _daylightDisplayName = disableDaylightSavingTime ? null : daylightDisplayName; + _supportsDaylightSavingTime = adjustmentRulesSupportDst && !disableDaylightSavingTime; + _adjustmentRules = adjustmentRules; + } + + /// + /// Returns a simple TimeZoneInfo instance that does not support Daylight Saving Time. + /// + public static TimeZoneInfo CreateCustomTimeZone( + string id, + TimeSpan baseUtcOffset, + string? displayName, + string? standardDisplayName) + { + return new TimeZoneInfo( + id, + baseUtcOffset, + displayName, + standardDisplayName, + standardDisplayName, + adjustmentRules: null, + disableDaylightSavingTime: false); + } + + /// + /// Returns a TimeZoneInfo instance that may support Daylight Saving Time. + /// + public static TimeZoneInfo CreateCustomTimeZone( + string id, + TimeSpan baseUtcOffset, + string displayName, + string standardDisplayName, + string daylightDisplayName, + AdjustmentRule[] adjustmentRules) + { + return CreateCustomTimeZone( + id, + baseUtcOffset, + displayName, + standardDisplayName, + daylightDisplayName, + adjustmentRules, + disableDaylightSavingTime: false); + } + + /// + /// Returns a TimeZoneInfo instance that may support Daylight Saving Time. + /// + public static TimeZoneInfo CreateCustomTimeZone( + string id, + TimeSpan baseUtcOffset, + string? displayName, + string? standardDisplayName, + string? daylightDisplayName, + AdjustmentRule[]? adjustmentRules, + bool disableDaylightSavingTime) + { + if (!disableDaylightSavingTime && adjustmentRules?.Length > 0) + { + adjustmentRules = (AdjustmentRule[])adjustmentRules.Clone(); + } + + return new TimeZoneInfo( + id, + baseUtcOffset, + displayName, + standardDisplayName, + daylightDisplayName, + adjustmentRules, + disableDaylightSavingTime); + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + try + { + bool adjustmentRulesSupportDst; + ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out adjustmentRulesSupportDst); + + if (adjustmentRulesSupportDst != _supportsDaylightSavingTime) + { + throw new SerializationException(SR.Format(SR.Serialization_CorruptField, "SupportsDaylightSavingTime")); + } + } + catch (ArgumentException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + catch (InvalidTimeZoneException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + info.AddValue("Id", _id); // Do not rename (binary serialization) + info.AddValue("DisplayName", _displayName); // Do not rename (binary serialization) + info.AddValue("StandardName", _standardDisplayName); // Do not rename (binary serialization) + info.AddValue("DaylightName", _daylightDisplayName); // Do not rename (binary serialization) + info.AddValue("BaseUtcOffset", _baseUtcOffset); // Do not rename (binary serialization) + info.AddValue("AdjustmentRules", _adjustmentRules); // Do not rename (binary serialization) + info.AddValue("SupportsDaylightSavingTime", _supportsDaylightSavingTime); // Do not rename (binary serialization) + } + + private TimeZoneInfo(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + _id = (string)info.GetValue("Id", typeof(string)); // Do not rename (binary serialization) + _displayName = (string)info.GetValue("DisplayName", typeof(string)); // Do not rename (binary serialization) + _standardDisplayName = (string)info.GetValue("StandardName", typeof(string)); // Do not rename (binary serialization) + _daylightDisplayName = (string)info.GetValue("DaylightName", typeof(string)); // Do not rename (binary serialization) + _baseUtcOffset = (TimeSpan)info.GetValue("BaseUtcOffset", typeof(TimeSpan)); // Do not rename (binary serialization) + _adjustmentRules = (AdjustmentRule[])info.GetValue("AdjustmentRules", typeof(AdjustmentRule[])); // Do not rename (binary serialization) + _supportsDaylightSavingTime = (bool)info.GetValue("SupportsDaylightSavingTime", typeof(bool)); // Do not rename (binary serialization) + } + + private AdjustmentRule? GetAdjustmentRuleForTime(DateTime dateTime, out int? ruleIndex) + { + AdjustmentRule? result = GetAdjustmentRuleForTime(dateTime, dateTimeisUtc: false, ruleIndex: out ruleIndex); + Debug.Assert(result == null || ruleIndex.HasValue, "If an AdjustmentRule was found, ruleIndex should also be set."); + + return result; + } + + private AdjustmentRule? GetAdjustmentRuleForTime(DateTime dateTime, bool dateTimeisUtc, out int? ruleIndex) + { + if (_adjustmentRules == null || _adjustmentRules.Length == 0) + { + ruleIndex = null; + return null; + } + + // Only check the whole-date portion of the dateTime for DateTimeKind.Unspecified rules - + // This is because the AdjustmentRule DateStart & DateEnd are stored as + // Date-only values {4/2/2006 - 10/28/2006} but actually represent the + // time span {4/2/2006@00:00:00.00000 - 10/28/2006@23:59:59.99999} + DateTime date = dateTimeisUtc ? + (dateTime + BaseUtcOffset).Date : + dateTime.Date; + + int low = 0; + int high = _adjustmentRules.Length - 1; + + while (low <= high) + { + int median = low + ((high - low) >> 1); + + AdjustmentRule rule = _adjustmentRules[median]; + AdjustmentRule previousRule = median > 0 ? _adjustmentRules[median - 1] : rule; + + int compareResult = CompareAdjustmentRuleToDateTime(rule, previousRule, dateTime, date, dateTimeisUtc); + if (compareResult == 0) + { + ruleIndex = median; + return rule; + } + else if (compareResult < 0) + { + low = median + 1; + } + else + { + high = median - 1; + } + } + + ruleIndex = null; + return null; + } + + /// + /// Determines if 'rule' is the correct AdjustmentRule for the given dateTime. + /// + /// + /// A value less than zero if rule is for times before dateTime. + /// Zero if rule is correct for dateTime. + /// A value greater than zero if rule is for times after dateTime. + /// + private int CompareAdjustmentRuleToDateTime(AdjustmentRule rule, AdjustmentRule previousRule, + DateTime dateTime, DateTime dateOnly, bool dateTimeisUtc) + { + bool isAfterStart; + if (rule.DateStart.Kind == DateTimeKind.Utc) + { + DateTime dateTimeToCompare = dateTimeisUtc ? + dateTime : + // use the previous rule to compute the dateTimeToCompare, since the time daylight savings "switches" + // is based on the previous rule's offset + ConvertToUtc(dateTime, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta); + + isAfterStart = dateTimeToCompare >= rule.DateStart; + } + else + { + // if the rule's DateStart is Unspecified, then use the whole-date portion + isAfterStart = dateOnly >= rule.DateStart; + } + + if (!isAfterStart) + { + return 1; + } + + bool isBeforeEnd; + if (rule.DateEnd.Kind == DateTimeKind.Utc) + { + DateTime dateTimeToCompare = dateTimeisUtc ? + dateTime : + ConvertToUtc(dateTime, rule.DaylightDelta, rule.BaseUtcOffsetDelta); + + isBeforeEnd = dateTimeToCompare <= rule.DateEnd; + } + else + { + // if the rule's DateEnd is Unspecified, then use the whole-date portion + isBeforeEnd = dateOnly <= rule.DateEnd; + } + + return isBeforeEnd ? 0 : -1; + } + + /// + /// Converts the dateTime to UTC using the specified deltas. + /// + private DateTime ConvertToUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta) => + ConvertToFromUtc(dateTime, daylightDelta, baseUtcOffsetDelta, convertToUtc: true); + + /// + /// Converts the dateTime from UTC using the specified deltas. + /// + private DateTime ConvertFromUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta) => + ConvertToFromUtc(dateTime, daylightDelta, baseUtcOffsetDelta, convertToUtc: false); + + /// + /// Converts the dateTime to or from UTC using the specified deltas. + /// + private DateTime ConvertToFromUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta, bool convertToUtc) + { + TimeSpan offset = BaseUtcOffset + daylightDelta + baseUtcOffsetDelta; + if (convertToUtc) + { + offset = offset.Negate(); + } + + long ticks = dateTime.Ticks + offset.Ticks; + + return + ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : + ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : + new DateTime(ticks); + } + + /// + /// Helper function that converts a dateTime from UTC into the destinationTimeZone + /// - Returns DateTime.MaxValue when the converted value is too large. + /// - Returns DateTime.MinValue when the converted value is too small. + /// + private static DateTime ConvertUtcToTimeZone(long ticks, TimeZoneInfo destinationTimeZone, out bool isAmbiguousLocalDst) + { + // used to calculate the UTC offset in the destinationTimeZone + DateTime utcConverted = + ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : + ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : + new DateTime(ticks); + + // verify the time is between MinValue and MaxValue in the new time zone + TimeSpan offset = GetUtcOffsetFromUtc(utcConverted, destinationTimeZone, out isAmbiguousLocalDst); + ticks += offset.Ticks; + + return + ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : + ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : + new DateTime(ticks); + } + + /// + /// Helper function that returns a DaylightTime from a year and AdjustmentRule. + /// + private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule, int? ruleIndex) + { + TimeSpan delta = rule.DaylightDelta; + DateTime startTime; + DateTime endTime; + if (rule.NoDaylightTransitions) + { + // NoDaylightTransitions rules don't use DaylightTransition Start and End, instead + // the DateStart and DateEnd are UTC times that represent when daylight savings time changes. + // Convert the UTC times into adjusted time zone times. + + // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule + AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); + startTime = ConvertFromUtc(rule.DateStart, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta); + + endTime = ConvertFromUtc(rule.DateEnd, rule.DaylightDelta, rule.BaseUtcOffsetDelta); + } + else + { + startTime = TransitionTimeToDateTime(year, rule.DaylightTransitionStart); + endTime = TransitionTimeToDateTime(year, rule.DaylightTransitionEnd); + } + return new DaylightTimeStruct(startTime, endTime, delta); + } + + /// + /// Helper function that checks if a given dateTime is in Daylight Saving Time (DST). + /// This function assumes the dateTime and AdjustmentRule are both in the same time zone. + /// + private static bool GetIsDaylightSavings(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime, TimeZoneInfoOptions flags) + { + if (rule == null) + { + return false; + } + + DateTime startTime; + DateTime endTime; + + if (time.Kind == DateTimeKind.Local) + { + // startTime and endTime represent the period from either the start of + // DST to the end and ***includes*** the potentially overlapped times + startTime = rule.IsStartDateMarkerForBeginningOfYear() ? + new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) : + daylightTime.Start + daylightTime.Delta; + + endTime = rule.IsEndDateMarkerForEndOfYear() ? + new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) : + daylightTime.End; + } + else + { + // startTime and endTime represent the period from either the start of DST to the end and + // ***does not include*** the potentially overlapped times + // + // -=-=-=-=-=- Pacific Standard Time -=-=-=-=-=-=- + // April 2, 2006 October 29, 2006 + // 2AM 3AM 1AM 2AM + // | +1 hr | | -1 hr | + // | | | | + // [========== DST ========>) + // + // -=-=-=-=-=- Some Weird Time Zone -=-=-=-=-=-=- + // April 2, 2006 October 29, 2006 + // 1AM 2AM 2AM 3AM + // | -1 hr | | +1 hr | + // | | | | + // [======== DST ========>) + // + bool invalidAtStart = rule.DaylightDelta > TimeSpan.Zero; + + startTime = rule.IsStartDateMarkerForBeginningOfYear() ? + new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) : + daylightTime.Start + (invalidAtStart ? rule.DaylightDelta : TimeSpan.Zero); /* FUTURE: - rule.StandardDelta; */ + + endTime = rule.IsEndDateMarkerForEndOfYear() ? + new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) : + daylightTime.End + (invalidAtStart ? -rule.DaylightDelta : TimeSpan.Zero); + } + + bool isDst = CheckIsDst(startTime, time, endTime, false, rule); + + // If this date was previously converted from a UTC date and we were able to detect that the local + // DateTime would be ambiguous, this data is stored in the DateTime to resolve this ambiguity. + if (isDst && time.Kind == DateTimeKind.Local) + { + // For normal time zones, the ambiguous hour is the last hour of daylight saving when you wind the + // clock back. It is theoretically possible to have a positive delta, (which would really be daylight + // reduction time), where you would have to wind the clock back in the begnning. + if (GetIsAmbiguousTime(time, rule, daylightTime)) + { + isDst = time.IsAmbiguousDaylightSavingTime(); + } + } + + return isDst; + } + + /// + /// Gets the offset that should be used to calculate DST start times from a UTC time. + /// + private TimeSpan GetDaylightSavingsStartOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule, int? ruleIndex) + { + if (rule.NoDaylightTransitions) + { + // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule + AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); + return baseUtcOffset + previousRule.BaseUtcOffsetDelta + previousRule.DaylightDelta; + } + else + { + return baseUtcOffset + rule.BaseUtcOffsetDelta; /* FUTURE: + rule.StandardDelta; */ + } + } + + /// + /// Gets the offset that should be used to calculate DST end times from a UTC time. + /// + private TimeSpan GetDaylightSavingsEndOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule) + { + // NOTE: even NoDaylightTransitions rules use this logic since DST ends w.r.t. the current rule + return baseUtcOffset + rule.BaseUtcOffsetDelta + rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ + } + + /// + /// Helper function that checks if a given dateTime is in Daylight Saving Time (DST). + /// This function assumes the dateTime is in UTC and AdjustmentRule is in a different time zone. + /// + private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpan utc, AdjustmentRule rule, int? ruleIndex, out bool isAmbiguousLocalDst, TimeZoneInfo zone) + { + isAmbiguousLocalDst = false; + + if (rule == null) + { + return false; + } + + // Get the daylight changes for the year of the specified time. + DaylightTimeStruct daylightTime = zone.GetDaylightTime(year, rule, ruleIndex); + + // The start and end times represent the range of universal times that are in DST for that year. + // Within that there is an ambiguous hour, usually right at the end, but at the beginning in + // the unusual case of a negative daylight savings delta. + // We need to handle the case if the current rule has daylight saving end by the end of year. If so, we need to check if next year starts with daylight saving on + // and get the actual daylight saving end time. Here is example for such case: + // Converting the UTC datetime "12/31/2011 8:00:00 PM" to "(UTC+03:00) Moscow, St. Petersburg, Volgograd (RTZ 2)" zone. + // In 2011 the daylight saving will go through the end of the year. If we use the end of 2011 as the daylight saving end, + // that will fail the conversion because the UTC time +4 hours (3 hours for the zone UTC offset and 1 hour for daylight saving) will move us to the next year "1/1/2012 12:00 AM", + // checking against the end of 2011 will tell we are not in daylight saving which is wrong and the conversion will be off by one hour. + // Note we handle the similar case when rule year start with daylight saving and previous year end with daylight saving. + + bool ignoreYearAdjustment = false; + TimeSpan dstStartOffset = zone.GetDaylightSavingsStartOffsetFromUtc(utc, rule, ruleIndex); + DateTime startTime; + if (rule.IsStartDateMarkerForBeginningOfYear() && daylightTime.Start.Year > DateTime.MinValue.Year) + { + int? previousYearRuleIndex; + AdjustmentRule? previousYearRule = zone.GetAdjustmentRuleForTime( + new DateTime(daylightTime.Start.Year - 1, 12, 31), + out previousYearRuleIndex); + if (previousYearRule != null && previousYearRule.IsEndDateMarkerForEndOfYear()) + { + DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime( + daylightTime.Start.Year - 1, + previousYearRule, + previousYearRuleIndex); + startTime = previousDaylightTime.Start - utc - previousYearRule.BaseUtcOffsetDelta; + ignoreYearAdjustment = true; + } + else + { + startTime = new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) - dstStartOffset; + } + } + else + { + startTime = daylightTime.Start - dstStartOffset; + } + + TimeSpan dstEndOffset = zone.GetDaylightSavingsEndOffsetFromUtc(utc, rule); + DateTime endTime; + if (rule.IsEndDateMarkerForEndOfYear() && daylightTime.End.Year < DateTime.MaxValue.Year) + { + int? nextYearRuleIndex; + AdjustmentRule? nextYearRule = zone.GetAdjustmentRuleForTime( + new DateTime(daylightTime.End.Year + 1, 1, 1), + out nextYearRuleIndex); + if (nextYearRule != null && nextYearRule.IsStartDateMarkerForBeginningOfYear()) + { + if (nextYearRule.IsEndDateMarkerForEndOfYear()) + { + // next year end with daylight saving on too + endTime = new DateTime(daylightTime.End.Year + 1, 12, 31) - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; + } + else + { + DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime( + daylightTime.End.Year + 1, + nextYearRule, + nextYearRuleIndex); + endTime = nextdaylightTime.End - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; + } + ignoreYearAdjustment = true; + } + else + { + endTime = new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) - dstEndOffset; + } + } + else + { + endTime = daylightTime.End - dstEndOffset; + } + + DateTime ambiguousStart; + DateTime ambiguousEnd; + if (daylightTime.Delta.Ticks > 0) + { + ambiguousStart = endTime - daylightTime.Delta; + ambiguousEnd = endTime; + } + else + { + ambiguousStart = startTime; + ambiguousEnd = startTime - daylightTime.Delta; + } + + bool isDst = CheckIsDst(startTime, time, endTime, ignoreYearAdjustment, rule); + + // See if the resulting local time becomes ambiguous. This must be captured here or the + // DateTime will not be able to round-trip back to UTC accurately. + if (isDst) + { + isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); + + if (!isAmbiguousLocalDst && ambiguousStart.Year != ambiguousEnd.Year) + { + // there exists an extreme corner case where the start or end period is on a year boundary and + // because of this the comparison above might have been performed for a year-early or a year-later + // than it should have been. + DateTime ambiguousStartModified; + DateTime ambiguousEndModified; + try + { + ambiguousStartModified = ambiguousStart.AddYears(1); + ambiguousEndModified = ambiguousEnd.AddYears(1); + isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); + } + catch (ArgumentOutOfRangeException) { } + + if (!isAmbiguousLocalDst) + { + try + { + ambiguousStartModified = ambiguousStart.AddYears(-1); + ambiguousEndModified = ambiguousEnd.AddYears(-1); + isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); + } + catch (ArgumentOutOfRangeException) { } + } + } + } + + return isDst; + } + + private static bool CheckIsDst(DateTime startTime, DateTime time, DateTime endTime, bool ignoreYearAdjustment, AdjustmentRule rule) + { + // NoDaylightTransitions AdjustmentRules should never get their year adjusted since they adjust the offset for the + // entire time period - which may be for multiple years + if (!ignoreYearAdjustment && !rule.NoDaylightTransitions) + { + int startTimeYear = startTime.Year; + int endTimeYear = endTime.Year; + + if (startTimeYear != endTimeYear) + { + endTime = endTime.AddYears(startTimeYear - endTimeYear); + } + + int timeYear = time.Year; + + if (startTimeYear != timeYear) + { + time = time.AddYears(startTimeYear - timeYear); + } + } + + if (startTime > endTime) + { + // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year. + // Note, the summer in the southern hemisphere begins late in the year. + return (time < endTime || time >= startTime); + } + else if (rule.NoDaylightTransitions) + { + // In NoDaylightTransitions AdjustmentRules, the startTime is always before the endTime, + // and both the start and end times are inclusive + return time >= startTime && time <= endTime; + } + else + { + // In northern hemisphere, the daylight saving time starts in the middle of the year. + return time >= startTime && time < endTime; + } + } + + /// + /// Returns true when the dateTime falls into an ambiguous time range. + /// + /// For example, in Pacific Standard Time on Sunday, October 29, 2006 time jumps from + /// 2AM to 1AM. This means the timeline on Sunday proceeds as follows: + /// 12AM ... [1AM ... 1:59:59AM -> 1AM ... 1:59:59AM] 2AM ... 3AM ... + /// + /// In this example, any DateTime values that fall into the [1AM - 1:59:59AM] range + /// are ambiguous; as it is unclear if these times are in Daylight Saving Time. + /// + private static bool GetIsAmbiguousTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) + { + bool isAmbiguous = false; + if (rule == null || rule.DaylightDelta == TimeSpan.Zero) + { + return isAmbiguous; + } + + DateTime startAmbiguousTime; + DateTime endAmbiguousTime; + + // if at DST start we transition forward in time then there is an ambiguous time range at the DST end + if (rule.DaylightDelta > TimeSpan.Zero) + { + if (rule.IsEndDateMarkerForEndOfYear()) + { // year end with daylight on so there is no ambiguous time + return false; + } + startAmbiguousTime = daylightTime.End; + endAmbiguousTime = daylightTime.End - rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ + } + else + { + if (rule.IsStartDateMarkerForBeginningOfYear()) + { // year start with daylight on so there is no ambiguous time + return false; + } + startAmbiguousTime = daylightTime.Start; + endAmbiguousTime = daylightTime.Start + rule.DaylightDelta; /* FUTURE: - rule.StandardDelta; */ + } + + isAmbiguous = (time >= endAmbiguousTime && time < startAmbiguousTime); + + if (!isAmbiguous && startAmbiguousTime.Year != endAmbiguousTime.Year) + { + // there exists an extreme corner case where the start or end period is on a year boundary and + // because of this the comparison above might have been performed for a year-early or a year-later + // than it should have been. + DateTime startModifiedAmbiguousTime; + DateTime endModifiedAmbiguousTime; + try + { + startModifiedAmbiguousTime = startAmbiguousTime.AddYears(1); + endModifiedAmbiguousTime = endAmbiguousTime.AddYears(1); + isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime); + } + catch (ArgumentOutOfRangeException) { } + + if (!isAmbiguous) + { + try + { + startModifiedAmbiguousTime = startAmbiguousTime.AddYears(-1); + endModifiedAmbiguousTime = endAmbiguousTime.AddYears(-1); + isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime); + } + catch (ArgumentOutOfRangeException) { } + } + } + return isAmbiguous; + } + + /// + /// Helper function that checks if a given DateTime is in an invalid time ("time hole") + /// A "time hole" occurs at a DST transition point when time jumps forward; + /// For example, in Pacific Standard Time on Sunday, April 2, 2006 time jumps from + /// 1:59:59.9999999 to 3AM. The time range 2AM to 2:59:59.9999999AM is the "time hole". + /// A "time hole" is not limited to only occurring at the start of DST, and may occur at + /// the end of DST as well. + /// + private static bool GetIsInvalidTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) + { + bool isInvalid = false; + if (rule == null || rule.DaylightDelta == TimeSpan.Zero) + { + return isInvalid; + } + + DateTime startInvalidTime; + DateTime endInvalidTime; + + // if at DST start we transition forward in time then there is an ambiguous time range at the DST end + if (rule.DaylightDelta < TimeSpan.Zero) + { + // if the year ends with daylight saving on then there cannot be any time-hole's in that year. + if (rule.IsEndDateMarkerForEndOfYear()) + return false; + + startInvalidTime = daylightTime.End; + endInvalidTime = daylightTime.End - rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ + } + else + { + // if the year starts with daylight saving on then there cannot be any time-hole's in that year. + if (rule.IsStartDateMarkerForBeginningOfYear()) + return false; + + startInvalidTime = daylightTime.Start; + endInvalidTime = daylightTime.Start + rule.DaylightDelta; /* FUTURE: - rule.StandardDelta; */ + } + + isInvalid = (time >= startInvalidTime && time < endInvalidTime); + + if (!isInvalid && startInvalidTime.Year != endInvalidTime.Year) + { + // there exists an extreme corner case where the start or end period is on a year boundary and + // because of this the comparison above might have been performed for a year-early or a year-later + // than it should have been. + DateTime startModifiedInvalidTime; + DateTime endModifiedInvalidTime; + try + { + startModifiedInvalidTime = startInvalidTime.AddYears(1); + endModifiedInvalidTime = endInvalidTime.AddYears(1); + isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime); + } + catch (ArgumentOutOfRangeException) { } + + if (!isInvalid) + { + try + { + startModifiedInvalidTime = startInvalidTime.AddYears(-1); + endModifiedInvalidTime = endInvalidTime.AddYears(-1); + isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime); + } + catch (ArgumentOutOfRangeException) { } + } + } + return isInvalid; + } + + /// + /// Helper function that calculates the UTC offset for a dateTime in a timeZone. + /// This function assumes that the dateTime is already converted into the timeZone. + /// + private static TimeSpan GetUtcOffset(DateTime time, TimeZoneInfo zone, TimeZoneInfoOptions flags) + { + TimeSpan baseOffset = zone.BaseUtcOffset; + int? ruleIndex; + AdjustmentRule? rule = zone.GetAdjustmentRuleForTime(time, out ruleIndex); + + if (rule != null) + { + baseOffset = baseOffset + rule.BaseUtcOffsetDelta; + if (rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule, ruleIndex); + bool isDaylightSavings = GetIsDaylightSavings(time, rule, daylightTime, flags); + baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); + } + } + + return baseOffset; + } + + /// + /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. + /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. + /// + private static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone) + { + bool isDaylightSavings; + return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings); + } + + /// + /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. + /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. + /// + private static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out bool isDaylightSavings) + { + bool isAmbiguousLocalDst; + return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings, out isAmbiguousLocalDst); + } + + /// + /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. + /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. + /// + internal static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out bool isDaylightSavings, out bool isAmbiguousLocalDst) + { + isDaylightSavings = false; + isAmbiguousLocalDst = false; + TimeSpan baseOffset = zone.BaseUtcOffset; + int year; + int? ruleIndex; + AdjustmentRule? rule; + + if (time > s_maxDateOnly) + { + rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue, out ruleIndex); + year = 9999; + } + else if (time < s_minDateOnly) + { + rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue, out ruleIndex); + year = 1; + } + else + { + rule = zone.GetAdjustmentRuleForTime(time, dateTimeisUtc: true, ruleIndex: out ruleIndex); + Debug.Assert(rule == null || ruleIndex.HasValue, + "If GetAdjustmentRuleForTime returned an AdjustmentRule, ruleIndex should also be set."); + + // As we get the associated rule using the adjusted targetTime, we should use the adjusted year (targetTime.Year) too as after adding the baseOffset, + // sometimes the year value can change if the input datetime was very close to the beginning or the end of the year. Examples of such cases: + // Libya Standard Time when used with the date 2011-12-31T23:59:59.9999999Z + // "W. Australia Standard Time" used with date 2005-12-31T23:59:00.0000000Z + DateTime targetTime = time + baseOffset; + year = targetTime.Year; + } + + if (rule != null) + { + baseOffset = baseOffset + rule.BaseUtcOffsetDelta; + if (rule.HasDaylightSaving) + { + isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone._baseUtcOffset, rule, ruleIndex, out isAmbiguousLocalDst, zone); + baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); + } + } + + return baseOffset; + } + + /// + /// Helper function that converts a year and TransitionTime into a DateTime. + /// + internal static DateTime TransitionTimeToDateTime(int year, TransitionTime transitionTime) + { + DateTime value; + DateTime timeOfDay = transitionTime.TimeOfDay; + + if (transitionTime.IsFixedDateRule) + { + // create a DateTime from the passed in year and the properties on the transitionTime + + // if the day is out of range for the month then use the last day of the month + int day = DateTime.DaysInMonth(year, transitionTime.Month); + + value = new DateTime(year, transitionTime.Month, (day < transitionTime.Day) ? day : transitionTime.Day, + timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + } + else + { + if (transitionTime.Week <= 4) + { + // + // Get the (transitionTime.Week)th Sunday. + // + value = new DateTime(year, transitionTime.Month, 1, + timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + + int dayOfWeek = (int)value.DayOfWeek; + int delta = (int)transitionTime.DayOfWeek - dayOfWeek; + if (delta < 0) + { + delta += 7; + } + delta += 7 * (transitionTime.Week - 1); + + if (delta > 0) + { + value = value.AddDays(delta); + } + } + else + { + // + // If TransitionWeek is greater than 4, we will get the last week. + // + int daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month); + value = new DateTime(year, transitionTime.Month, daysInMonth, + timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + + // This is the day of week for the last day of the month. + int dayOfWeek = (int)value.DayOfWeek; + int delta = dayOfWeek - (int)transitionTime.DayOfWeek; + if (delta < 0) + { + delta += 7; + } + + if (delta > 0) + { + value = value.AddDays(-delta); + } + } + } + return value; + } + + /// + /// Helper function for retrieving a TimeZoneInfo object by time_zone_name. + /// + /// This function may return null. + /// + /// assumes cachedData lock is taken + /// + private static TimeZoneInfoResult TryGetTimeZone(string id, bool dstDisabled, out TimeZoneInfo? value, out Exception? e, CachedData cachedData, bool alwaysFallbackToLocalMachine = false) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + TimeZoneInfoResult result = TimeZoneInfoResult.Success; + e = null; + TimeZoneInfo? match = null; + + // check the cache + if (cachedData._systemTimeZones != null) + { + if (cachedData._systemTimeZones.TryGetValue(id, out match)) + { + if (dstDisabled && match._supportsDaylightSavingTime) + { + // we found a cache hit but we want a time zone without DST and this one has DST data + value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); + } + else + { + value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, + match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); + } + return result; + } + } + + // Fall back to reading from the local machine when the cache is not fully populated. + // On UNIX, there may be some tzfiles that aren't in the zones.tab file, and thus aren't returned from GetSystemTimeZones(). + // If a caller asks for one of these zones before calling GetSystemTimeZones(), the time zone is returned successfully. But if + // GetSystemTimeZones() is called first, FindSystemTimeZoneById will throw TimeZoneNotFoundException, which is inconsistent. + // To fix this, when 'alwaysFallbackToLocalMachine' is true, even if _allSystemTimeZonesRead is true, try reading the tzfile + // from disk, but don't add the time zone to the list returned from GetSystemTimeZones(). These time zones will only be + // available if asked for directly. + if (!cachedData._allSystemTimeZonesRead || alwaysFallbackToLocalMachine) + { + result = TryGetTimeZoneFromLocalMachine(id, dstDisabled, out value, out e, cachedData); + } + else + { + result = TimeZoneInfoResult.TimeZoneNotFoundException; + value = null; + } + + return result; + } + + private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool dstDisabled, out TimeZoneInfo? value, out Exception? e, CachedData cachedData) + { + TimeZoneInfoResult result; + TimeZoneInfo? match; + + result = TryGetTimeZoneFromLocalMachine(id, out match, out e); + + if (result == TimeZoneInfoResult.Success) + { + if (cachedData._systemTimeZones == null) + cachedData._systemTimeZones = new Dictionary(StringComparer.OrdinalIgnoreCase); + + cachedData._systemTimeZones.Add(id, match!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + + if (dstDisabled && match!._supportsDaylightSavingTime) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + { + // we found a cache hit but we want a time zone without DST and this one has DST data + value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); + } + else + { + value = new TimeZoneInfo(match!._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); + } + } + else + { + value = null; + } + + return result; + } + + /// + /// Helper function that performs all of the validation checks for the + /// factory methods and deserialization callback. + /// + private static void ValidateTimeZoneInfo(string id, TimeSpan baseUtcOffset, AdjustmentRule[]? adjustmentRules, out bool adjustmentRulesSupportDst) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + if (id.Length == 0) + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidId, id), nameof(id)); + } + + if (UtcOffsetOutOfRange(baseUtcOffset)) + { + throw new ArgumentOutOfRangeException(nameof(baseUtcOffset), SR.ArgumentOutOfRange_UtcOffset); + } + + if (baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) + { + throw new ArgumentException(SR.Argument_TimeSpanHasSeconds, nameof(baseUtcOffset)); + } + + adjustmentRulesSupportDst = false; + + // + // "adjustmentRules" can either be null or a valid array of AdjustmentRule objects. + // A valid array is one that does not contain any null elements and all elements + // are sorted in chronological order + // + + if (adjustmentRules != null && adjustmentRules.Length != 0) + { + adjustmentRulesSupportDst = true; + AdjustmentRule? prev = null; + AdjustmentRule? current = null; + for (int i = 0; i < adjustmentRules.Length; i++) + { + prev = current; + current = adjustmentRules[i]; + + if (current == null) + { + throw new InvalidTimeZoneException(SR.Argument_AdjustmentRulesNoNulls); + } + + if (!IsValidAdjustmentRuleOffest(baseUtcOffset, current)) + { + throw new InvalidTimeZoneException(SR.ArgumentOutOfRange_UtcOffsetAndDaylightDelta); + } + + if (prev != null && current.DateStart <= prev.DateEnd) + { + // verify the rules are in chronological order and the DateStart/DateEnd do not overlap + throw new InvalidTimeZoneException(SR.Argument_AdjustmentRulesOutOfOrder); + } + } + } + } + + private static readonly TimeSpan MaxOffset = TimeSpan.FromHours(14.0); + private static readonly TimeSpan MinOffset = -MaxOffset; + + /// + /// Helper function that validates the TimeSpan is within +/- 14.0 hours + /// + internal static bool UtcOffsetOutOfRange(TimeSpan offset) => + offset < MinOffset || offset > MaxOffset; + + private static TimeSpan GetUtcOffset(TimeSpan baseUtcOffset, AdjustmentRule adjustmentRule) + { + return baseUtcOffset + + adjustmentRule.BaseUtcOffsetDelta + + (adjustmentRule.HasDaylightSaving ? adjustmentRule.DaylightDelta : TimeSpan.Zero); + } + + /// + /// Helper function that performs adjustment rule validation + /// + private static bool IsValidAdjustmentRuleOffest(TimeSpan baseUtcOffset, AdjustmentRule adjustmentRule) + { + TimeSpan utcOffset = GetUtcOffset(baseUtcOffset, adjustmentRule); + return !UtcOffsetOutOfRange(utcOffset); + } + + /// + /// Normalize adjustment rule offset so that it is within valid range + /// This method should not be called at all but is here in case something changes in the future + /// or if really old time zones are present on the OS (no combination is known at the moment) + /// + private static void NormalizeAdjustmentRuleOffset(TimeSpan baseUtcOffset, ref AdjustmentRule adjustmentRule) + { + // Certain time zones such as: + // Time Zone start date end date offset + // ----------------------------------------------------- + // America/Yakutat 0001-01-01 1867-10-18 14:41:00 + // America/Yakutat 1867-10-18 1900-08-20 14:41:00 + // America/Sitka 0001-01-01 1867-10-18 14:58:00 + // America/Sitka 1867-10-18 1900-08-20 14:58:00 + // Asia/Manila 0001-01-01 1844-12-31 -15:56:00 + // Pacific/Guam 0001-01-01 1845-01-01 -14:21:00 + // Pacific/Saipan 0001-01-01 1845-01-01 -14:21:00 + // + // have larger offset than currently supported by framework. + // If for whatever reason we find that time zone exceeding max + // offset of 14h this function will truncate it to the max valid offset. + // Updating max offset may cause problems with interacting with SQL server + // which uses SQL DATETIMEOFFSET field type which was originally designed to be + // bit-for-bit compatible with DateTimeOffset. + + TimeSpan utcOffset = GetUtcOffset(baseUtcOffset, adjustmentRule); + + // utc base offset delta increment + TimeSpan adjustment = TimeSpan.Zero; + + if (utcOffset > MaxOffset) + { + adjustment = MaxOffset - utcOffset; + } + else if (utcOffset < MinOffset) + { + adjustment = MinOffset - utcOffset; + } + + if (adjustment != TimeSpan.Zero) + { + adjustmentRule = AdjustmentRule.CreateAdjustmentRule( + adjustmentRule.DateStart, + adjustmentRule.DateEnd, + adjustmentRule.DaylightDelta, + adjustmentRule.DaylightTransitionStart, + adjustmentRule.DaylightTransitionEnd, + adjustmentRule.BaseUtcOffsetDelta + adjustment, + adjustmentRule.NoDaylightTransitions); + } + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Tuple.cs b/src/System.Private.CoreLib/shared/System/Tuple.cs index f9111b9..cf99600 100644 --- a/src/System.Private.CoreLib/shared/System/Tuple.cs +++ b/src/System.Private.CoreLib/shared/System/Tuple.cs @@ -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.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -115,12 +116,12 @@ namespace System m_Item1 = item1; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -132,7 +133,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -185,7 +186,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -214,12 +215,12 @@ namespace System m_Item2 = item2; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -231,7 +232,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -292,7 +293,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -328,12 +329,12 @@ namespace System m_Item3 = item3; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -345,7 +346,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -412,7 +413,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -453,12 +454,12 @@ namespace System m_Item4 = item4; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -470,7 +471,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -543,7 +544,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -589,12 +590,12 @@ namespace System m_Item5 = item5; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -606,7 +607,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -685,7 +686,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -736,12 +737,12 @@ namespace System m_Item6 = item6; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -753,7 +754,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5) && comparer.Equals(m_Item6, objTuple.m_Item6); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -838,7 +839,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -894,12 +895,12 @@ namespace System m_Item7 = item7; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -911,7 +912,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5) && comparer.Equals(m_Item6, objTuple.m_Item6) && comparer.Equals(m_Item7, objTuple.m_Item7); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -1002,7 +1003,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -1068,12 +1069,12 @@ namespace System m_Rest = rest; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null) return false; @@ -1085,7 +1086,7 @@ namespace System return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5) && comparer.Equals(m_Item6, objTuple.m_Item6) && comparer.Equals(m_Item7, objTuple.m_Item7) && comparer.Equals(m_Rest, objTuple.m_Rest); } - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); } @@ -1140,7 +1141,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple - ITupleInternal t = (ITupleInternal)m_Rest; + ITupleInternal t = (ITupleInternal)m_Rest!; // TODO-NULLABLE-GENERIC if (t.Length >= 8) { return t.GetHashCode(comparer); } // In this case, the rest memeber has less than 8 elements so we need to combine some our elements with the elements in rest @@ -1193,7 +1194,7 @@ namespace System sb.Append(", "); sb.Append(m_Item7); sb.Append(", "); - return ((ITupleInternal)m_Rest).ToString(sb); + return ((ITupleInternal)m_Rest!).ToString(sb); // TODO-NULLABLE-GENERIC } /// @@ -1203,14 +1204,14 @@ namespace System { get { - return 7 + ((ITupleInternal)Rest).Length; + return 7 + ((ITupleInternal)Rest!).Length; // TODO-NULLABLE-GENERIC } } /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -1232,7 +1233,7 @@ namespace System return Item7; } - return ((ITupleInternal)Rest)[index - 7]; + return ((ITupleInternal)Rest!)[index - 7]; // TODO-NULLABLE-GENERIC } } } diff --git a/src/System.Private.CoreLib/shared/System/TupleExtensions.cs b/src/System.Private.CoreLib/shared/System/TupleExtensions.cs index 106a88a..bf1aa07 100644 --- a/src/System.Private.CoreLib/shared/System/TupleExtensions.cs +++ b/src/System.Private.CoreLib/shared/System/TupleExtensions.cs @@ -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.ComponentModel; using System.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/shared/System/TypeCode.cs b/src/System.Private.CoreLib/shared/System/TypeCode.cs index 2961986..08216dc 100644 --- a/src/System.Private.CoreLib/shared/System/TypeCode.cs +++ b/src/System.Private.CoreLib/shared/System/TypeCode.cs @@ -21,6 +21,7 @@ // of an object is TypeCode.Object, a further instance-of check can be used to // determine if the object is one of these values. +#nullable enable namespace System { public enum TypeCode diff --git a/src/System.Private.CoreLib/shared/System/UIntPtr.cs b/src/System.Private.CoreLib/shared/System/UIntPtr.cs index 9197792..c6372f0 100644 --- a/src/System.Private.CoreLib/shared/System/UIntPtr.cs +++ b/src/System.Private.CoreLib/shared/System/UIntPtr.cs @@ -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.Runtime.CompilerServices; using System.Runtime.Serialization; @@ -68,7 +69,7 @@ namespace System info.AddValue("value", ToUInt64()); } - public unsafe override bool Equals(object obj) + public unsafe override bool Equals(object? obj) { if (obj is UIntPtr) { diff --git a/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventArgs.cs b/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventArgs.cs index c214afd..5f4e010 100644 --- a/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventArgs.cs +++ b/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventArgs.cs @@ -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 namespace System { public class UnhandledExceptionEventArgs : EventArgs diff --git a/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventHandler.cs b/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventHandler.cs index 58f1eb5..36ce061 100644 --- a/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventHandler.cs +++ b/src/System.Private.CoreLib/shared/System/UnhandledExceptionEventHandler.cs @@ -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 namespace System { public delegate void UnhandledExceptionEventHandler(object sender, UnhandledExceptionEventArgs e); diff --git a/src/System.Private.CoreLib/shared/System/UnitySerializationHolder.cs b/src/System.Private.CoreLib/shared/System/UnitySerializationHolder.cs index 53323c3..c5d61f2 100644 --- a/src/System.Private.CoreLib/shared/System/UnitySerializationHolder.cs +++ b/src/System.Private.CoreLib/shared/System/UnitySerializationHolder.cs @@ -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.Runtime.Serialization; namespace System diff --git a/src/System.Private.CoreLib/shared/System/ValueTuple.cs b/src/System.Private.CoreLib/shared/System/ValueTuple.cs index fdcead2..0fd476e 100644 --- a/src/System.Private.CoreLib/shared/System/ValueTuple.cs +++ b/src/System.Private.CoreLib/shared/System/ValueTuple.cs @@ -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.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -38,7 +39,7 @@ namespace System /// /// The object to compare with this instance. /// if is a . - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple; } @@ -51,12 +52,12 @@ namespace System return true; } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { return other is ValueTuple; } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -135,7 +136,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -330,7 +331,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -350,7 +351,7 @@ namespace System return EqualityComparer.Default.Equals(Item1, other.Item1); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -359,7 +360,7 @@ namespace System return comparer.Equals(Item1, objTuple.Item1); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -446,7 +447,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -505,7 +506,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -543,7 +544,7 @@ namespace System /// implementation. If this method call returns , the method is /// called again and passed the values of the two instances. /// - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -553,7 +554,7 @@ namespace System && comparer.Equals(Item2, objTuple.Item2); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -652,7 +653,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -720,7 +721,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -742,7 +743,7 @@ namespace System && EqualityComparer.Default.Equals(Item3, other.Item3); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -753,7 +754,7 @@ namespace System && comparer.Equals(Item3, objTuple.Item3); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -858,7 +859,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -935,7 +936,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -958,7 +959,7 @@ namespace System && EqualityComparer.Default.Equals(Item4, other.Item4); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -970,7 +971,7 @@ namespace System && comparer.Equals(Item4, objTuple.Item4); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -1083,7 +1084,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -1169,7 +1170,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -1193,7 +1194,7 @@ namespace System && EqualityComparer.Default.Equals(Item5, other.Item5); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -1206,7 +1207,7 @@ namespace System && comparer.Equals(Item5, objTuple.Item5); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -1327,7 +1328,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -1422,7 +1423,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -1447,7 +1448,7 @@ namespace System && EqualityComparer.Default.Equals(Item6, other.Item6); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -1461,7 +1462,7 @@ namespace System && comparer.Equals(Item6, objTuple.Item6); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -1590,7 +1591,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -1694,7 +1695,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -1720,7 +1721,7 @@ namespace System && EqualityComparer.Default.Equals(Item7, other.Item7); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -1735,7 +1736,7 @@ namespace System && comparer.Equals(Item7, objTuple.Item7); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -1872,7 +1873,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -1991,7 +1992,7 @@ namespace System /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. /// /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ValueTuple && Equals((ValueTuple)obj); } @@ -2018,7 +2019,7 @@ namespace System && EqualityComparer.Default.Equals(Rest, other.Rest); } - bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) { if (other == null || !(other is ValueTuple)) return false; @@ -2034,7 +2035,7 @@ namespace System && comparer.Equals(Rest, objTuple.Rest); } - int IComparable.CompareTo(object other) + int IComparable.CompareTo(object? other) { if (other == null) return 1; @@ -2122,7 +2123,7 @@ namespace System public override int GetHashCode() { // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple - IValueTupleInternal rest = Rest as IValueTupleInternal; + IValueTupleInternal? rest = Rest as IValueTupleInternal; if (rest == null) { return ValueTuple.CombineHashCodes(Item1?.GetHashCode() ?? 0, @@ -2198,7 +2199,7 @@ namespace System private int GetHashCodeCore(IEqualityComparer comparer) { // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple - IValueTupleInternal rest = Rest as IValueTupleInternal; + IValueTupleInternal? rest = Rest as IValueTupleInternal; if (rest == null) { return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), comparer.GetHashCode(Item2), comparer.GetHashCode(Item3), @@ -2256,7 +2257,7 @@ namespace System /// public override string ToString() { - IValueTupleInternal rest = Rest as IValueTupleInternal; + IValueTupleInternal? rest = Rest as IValueTupleInternal; if (rest == null) { return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")"; @@ -2269,7 +2270,7 @@ namespace System string IValueTupleInternal.ToStringEnd() { - IValueTupleInternal rest = Rest as IValueTupleInternal; + IValueTupleInternal? rest = Rest as IValueTupleInternal; if (rest == null) { return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")"; @@ -2287,7 +2288,7 @@ namespace System { get { - IValueTupleInternal rest = Rest as IValueTupleInternal; + IValueTupleInternal? rest = Rest as IValueTupleInternal; return rest == null ? 8 : 7 + rest.Length; } } @@ -2295,7 +2296,7 @@ namespace System /// /// Get the element at position . /// - object ITuple.this[int index] + object? ITuple.this[int index] { get { @@ -2317,7 +2318,7 @@ namespace System return Item7; } - IValueTupleInternal rest = Rest as IValueTupleInternal; + IValueTupleInternal? rest = Rest as IValueTupleInternal; if (rest == null) { if (index == 7) diff --git a/src/System.Private.CoreLib/shared/System/Version.cs b/src/System.Private.CoreLib/shared/System/Version.cs index 359837f..c6399ba 100644 --- a/src/System.Private.CoreLib/shared/System/Version.cs +++ b/src/System.Private.CoreLib/shared/System/Version.cs @@ -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.Diagnostics; using System.Text; @@ -17,7 +18,7 @@ namespace System [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed class Version : ICloneable, IComparable, IComparable, IEquatable, ISpanFormattable + public sealed class Version : ICloneable, IComparable, IComparable, IEquatable, ISpanFormattable { // AssemblyName depends on the order staying the same private readonly int _Major; // Do not rename (binary serialization) @@ -135,23 +136,22 @@ namespace System get { return (short)(_Revision & 0xFFFF); } } - public int CompareTo(object version) + public int CompareTo(object? version) { if (version == null) { return 1; } - Version v = version as Version; - if (v == null) + if (version is Version v) { - throw new ArgumentException(SR.Arg_MustBeVersion); + return CompareTo(v); } - return CompareTo(v); + throw new ArgumentException(SR.Arg_MustBeVersion); } - public int CompareTo(Version value) + public int CompareTo(Version? value) { return object.ReferenceEquals(value, this) ? 0 : @@ -163,12 +163,12 @@ namespace System 0; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return Equals(obj as Version); } - public bool Equals(Version obj) + public bool Equals(Version? obj) { return object.ReferenceEquals(obj, this) || (!(obj is null) && @@ -230,7 +230,7 @@ namespace System return false; } - bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider provider) + bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) { // format and provider are ignored. return TryFormat(destination, out charsWritten); @@ -301,13 +301,13 @@ namespace System throw new ArgumentNullException(nameof(input)); } - return ParseVersion(input.AsSpan(), throwOnFailure: true); + return ParseVersion(input.AsSpan(), throwOnFailure: true)!; } public static Version Parse(ReadOnlySpan input) => - ParseVersion(input, throwOnFailure: true); + ParseVersion(input, throwOnFailure: true)!; - public static bool TryParse(string input, out Version result) + public static bool TryParse(string? input, out Version? result) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { if (input == null) { @@ -318,10 +318,10 @@ namespace System return (result = ParseVersion(input.AsSpan(), throwOnFailure: false)) != null; } - public static bool TryParse(ReadOnlySpan input, out Version result) => + public static bool TryParse(ReadOnlySpan input, out Version? result) => (result = ParseVersion(input, throwOnFailure: false)) != null; - private static Version ParseVersion(ReadOnlySpan input, bool throwOnFailure) + private static Version? ParseVersion(ReadOnlySpan input, bool throwOnFailure) { // Find the separator between major and minor. It must exist. int majorEnd = input.IndexOf('.'); @@ -408,7 +408,7 @@ namespace System // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Version v1, Version v2) + public static bool operator ==(Version? v1, Version? v2) { // Test "right" first to allow branch elimination when inlined for null checks (== null) // so it can become a simple test @@ -422,33 +422,37 @@ namespace System return ReferenceEquals(v2, v1) ? true : v2.Equals(v1); } - public static bool operator !=(Version v1, Version v2) + public static bool operator !=(Version? v1, Version? v2) { return !(v1 == v2); } - public static bool operator <(Version v1, Version v2) + public static bool operator <(Version v1, Version? v2) { - if ((object)v1 == null) + if (v1 is null) throw new ArgumentNullException(nameof(v1)); return (v1.CompareTo(v2) < 0); } - public static bool operator <=(Version v1, Version v2) + public static bool operator <=(Version v1, Version? v2) { - if ((object)v1 == null) + if (v1 is null) throw new ArgumentNullException(nameof(v1)); return (v1.CompareTo(v2) <= 0); } - public static bool operator >(Version v1, Version v2) + public static bool operator >(Version v1, Version? v2) { - return (v2 < v1); + if (v1 is null) + throw new ArgumentNullException(nameof(v1)); + return (v1.CompareTo(v2) > 0); } - public static bool operator >=(Version v1, Version v2) + public static bool operator >=(Version v1, Version? v2) { - return (v2 <= v1); + if (v1 is null) + throw new ArgumentNullException(nameof(v1)); + return (v1.CompareTo(v2) >= 0); } } } diff --git a/src/System.Private.CoreLib/shared/System/Void.cs b/src/System.Private.CoreLib/shared/System/Void.cs index 5162e6a..f0a7ddd 100644 --- a/src/System.Private.CoreLib/shared/System/Void.cs +++ b/src/System.Private.CoreLib/shared/System/Void.cs @@ -7,6 +7,7 @@ // This class represents the void return type //////////////////////////////////////////////////////////////////////////////// +#nullable enable namespace System { // This class represents the void return type diff --git a/src/System.Private.CoreLib/src/System/AppContext.CoreCLR.cs b/src/System.Private.CoreLib/src/System/AppContext.CoreCLR.cs index 4d11c16..4ef4a34 100644 --- a/src/System.Private.CoreLib/src/System/AppContext.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/AppContext.CoreCLR.cs @@ -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.IO; using System.Reflection; @@ -17,10 +18,10 @@ namespace System } } - private static string GetBaseDirectoryCore() + private static string? GetBaseDirectoryCore() { // Fallback path for hosts that do not set APP_CONTEXT_BASE_DIRECTORY explicitly - string directory = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); + string? directory = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); if (directory != null && !PathInternal.EndsInDirectorySeparator(directory)) directory += Path.DirectorySeparatorChar; return directory; diff --git a/src/System.Private.CoreLib/src/System/ApplicationModel.Windows.cs b/src/System.Private.CoreLib/src/System/ApplicationModel.Windows.cs index ea1e017..1b49dec 100644 --- a/src/System.Private.CoreLib/src/System/ApplicationModel.Windows.cs +++ b/src/System.Private.CoreLib/src/System/ApplicationModel.Windows.cs @@ -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.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/System.Private.CoreLib/src/System/ArgIterator.cs b/src/System.Private.CoreLib/src/System/ArgIterator.cs index 72ea254..2c1f54a 100644 --- a/src/System.Private.CoreLib/src/System/ArgIterator.cs +++ b/src/System.Private.CoreLib/src/System/ArgIterator.cs @@ -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 namespace System { using System; @@ -128,7 +129,7 @@ namespace System } // Inherited from object - public override bool Equals(object o) + public override bool Equals(object? o) { throw new NotSupportedException(SR.NotSupported_NYI); } @@ -149,7 +150,7 @@ namespace System throw new PlatformNotSupportedException(SR.PlatformNotSupported_ArgIterator); // https://github.com/dotnet/coreclr/issues/9204 } - public override bool Equals(Object o) + public override bool Equals(Object? o) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ArgIterator); // https://github.com/dotnet/coreclr/issues/9204 } diff --git a/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs index 56f36de..6835f5e 100644 --- a/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs @@ -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.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/System.Private.CoreLib/src/System/CLRConfig.cs b/src/System.Private.CoreLib/src/System/CLRConfig.cs index 5b14f28..76e38ac 100644 --- a/src/System.Private.CoreLib/src/System/CLRConfig.cs +++ b/src/System.Private.CoreLib/src/System/CLRConfig.cs @@ -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.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.Win32; diff --git a/src/System.Private.CoreLib/src/System/Char8.cs b/src/System.Private.CoreLib/src/System/Char8.cs index 7a71e2f..46789fa 100644 --- a/src/System.Private.CoreLib/src/System/Char8.cs +++ b/src/System.Private.CoreLib/src/System/Char8.cs @@ -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 namespace System { /// @@ -59,7 +60,7 @@ namespace System public int CompareTo(Char8 other) => this._value.CompareTo(other._value); - public override bool Equals(object obj) => (obj is Char8 other) && (this == other); + public override bool Equals(object? obj) => (obj is Char8 other) && (this == other); public bool Equals(Char8 other) => this == other; public override int GetHashCode() => _value; diff --git a/src/System.Private.CoreLib/src/System/Currency.cs b/src/System.Private.CoreLib/src/System/Currency.cs index c9e8dc0..e306989 100644 --- a/src/System.Private.CoreLib/src/System/Currency.cs +++ b/src/System.Private.CoreLib/src/System/Currency.cs @@ -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 namespace System { internal struct Currency diff --git a/src/System.Private.CoreLib/src/System/DateTime.Unix.CoreCLR.cs b/src/System.Private.CoreLib/src/System/DateTime.Unix.CoreCLR.cs index 1fd1e9c..c988343 100644 --- a/src/System.Private.CoreLib/src/System/DateTime.Unix.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/DateTime.Unix.CoreCLR.cs @@ -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.Runtime.CompilerServices; namespace System @@ -19,4 +20,4 @@ namespace System [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern long GetSystemTimeAsFileTime(); } -} \ No newline at end of file +} diff --git a/src/System.Private.CoreLib/src/System/DateTime.Windows.cs b/src/System.Private.CoreLib/src/System/DateTime.Windows.cs index 9d0d0cd..69cddb7 100644 --- a/src/System.Private.CoreLib/src/System/DateTime.Windows.cs +++ b/src/System.Private.CoreLib/src/System/DateTime.Windows.cs @@ -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.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs index d5fea8a..9021db7 100644 --- a/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs @@ -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.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -33,7 +34,7 @@ namespace System // to assign blame for crashes. Don't mess with this, such as by making it call // another managed helper method, unless you consult with some CLR Watson experts. [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void FailFast(string message); + public static extern void FailFast(string? message); // This overload of FailFast will allow you to specify the exception object // whose bucket details *could* be used when undergoing the failfast process. @@ -49,10 +50,10 @@ namespace System // IP for bucketing. If the exception object is not preallocated, it will use the bucket // details contained in the object (if any). [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void FailFast(string message, Exception exception); + public static extern void FailFast(string? message, Exception? exception); [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void FailFast(string message, Exception exception, string errorMessage); + public static extern void FailFast(string? message, Exception? exception, string? errorMessage); [MethodImpl(MethodImplOptions.InternalCall)] private static extern string[] GetCommandLineArgsNative(); @@ -91,7 +92,7 @@ namespace System // If you change this method's signature then you must change the code that calls it // in excep.cpp and probably you will have to visit mscorlib.h to add the new signature // as well as metasig.h to create the new signature type - internal static string GetResourceStringLocal(string key) => SR.GetResourceString(key); + internal static string? GetResourceStringLocal(string key) => SR.GetResourceString(key); public static string StackTrace { diff --git a/src/System.Private.CoreLib/src/System/Exception.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Exception.CoreCLR.cs index c19aa64..119f09d 100644 --- a/src/System.Private.CoreLib/src/System/Exception.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Exception.CoreCLR.cs @@ -465,7 +465,7 @@ namespace System { string? retMesg = null; GetMessageFromNativeResources(kind, JitHelpers.GetStringHandleOnStack(ref retMesg)); - return retMesg; + return retMesg!; } [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/System.Private.CoreLib/src/System/GC.cs b/src/System.Private.CoreLib/src/System/GC.cs index 4485afe..123156e 100644 --- a/src/System.Private.CoreLib/src/System/GC.cs +++ b/src/System.Private.CoreLib/src/System/GC.cs @@ -13,8 +13,8 @@ ** ===========================================================*/ +#nullable enable using System.Runtime.CompilerServices; -using System.Globalization; using System.Runtime.InteropServices; using System.Diagnostics; @@ -236,7 +236,7 @@ namespace System // If we insert a call to GC.KeepAlive(this) at the end of Problem(), then // Foo doesn't get finalized and the stream stays open. [MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations - public static void KeepAlive(object obj) + public static void KeepAlive(object? obj) { } diff --git a/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs b/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs index 9da8e35..ebeab9a 100644 --- a/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs @@ -22,16 +22,16 @@ namespace System.IO internal static string FormatFileLoadExceptionMessage(string? fileName, int hResult) { - string? format = null; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 GetStringHandleOnStack needs to be attributed + string? format = null; GetFileLoadExceptionMessage(hResult, JitHelpers.GetStringHandleOnStack(ref format)); - string? message = null; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 GetStringHandleOnStack needs to be attributed + string? message = null; if (hResult == System.HResults.COR_E_BADEXEFORMAT) message = SR.Arg_BadImageFormatException; else GetMessageForHR(hResult, JitHelpers.GetStringHandleOnStack(ref message)); - return string.Format(format, fileName, message); + return string.Format(format!, fileName, message!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 GetStringHandleOnStack needs to be attributed } [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/System.Private.CoreLib/src/System/Internal.cs b/src/System.Private.CoreLib/src/System/Internal.cs index cc0b828..88a3498 100644 --- a/src/System.Private.CoreLib/src/System/Internal.cs +++ b/src/System.Private.CoreLib/src/System/Internal.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +#nullable disable // Code in this file isn't actually executed using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Collections.Generic; diff --git a/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs index 149dd06..b33ae1e 100644 --- a/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs @@ -13,6 +13,7 @@ //This class contains only static members and doesn't require serialization. +#nullable enable using System.Runtime.CompilerServices; namespace System diff --git a/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs b/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs index 5ba0a92..ba575d9 100644 --- a/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs @@ -10,6 +10,7 @@ //This class contains only static members and doesn't require serialization. +#nullable enable using System.Runtime.CompilerServices; namespace System diff --git a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs index 4683b88..9335713 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.IO; -using System.Configuration.Assemblies; +#nullable enable using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; -using System.Runtime.Loader; using StackCrawlMark = System.Threading.StackCrawlMark; namespace System.Reflection @@ -40,7 +37,7 @@ namespace System.Reflection // weak. The assembly is loaded into the domain of the caller. internal static Assembly Load(AssemblyName assemblyRef, ref StackCrawlMark stackMark, IntPtr ptrLoadContextBinder) { - AssemblyName modifiedAssemblyRef = null; + AssemblyName? modifiedAssemblyRef = null; if (assemblyRef.CodeBase != null) { modifiedAssemblyRef = (AssemblyName)assemblyRef.Clone(); @@ -59,9 +56,9 @@ namespace System.Reflection internal static RuntimeAssembly GetExecutingAssembly(ref StackCrawlMark stackMark) { - RuntimeAssembly retAssembly = null; + RuntimeAssembly? retAssembly = null; GetExecutingAssemblyNative(JitHelpers.GetStackCrawlMarkHandle(ref stackMark), JitHelpers.GetObjectHandleOnStack(ref retAssembly)); - return retAssembly; + return retAssembly!; // TODO-NULLABLE: Confirm this can never be null } // Get the assembly that the current code is running from. @@ -88,12 +85,12 @@ namespace System.Reflection // internal test hook private static bool s_forceNullEntryPoint = false; - public static Assembly GetEntryAssembly() + public static Assembly? GetEntryAssembly() { if (s_forceNullEntryPoint) return null; - RuntimeAssembly entryAssembly = null; + RuntimeAssembly? entryAssembly = null; GetEntryAssemblyNative(JitHelpers.GetObjectHandleOnStack(ref entryAssembly)); return entryAssembly; } diff --git a/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs b/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs index e804799..7ea9b59 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs @@ -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.Configuration.Assemblies; using System.IO; using System.Runtime.CompilerServices; @@ -15,16 +16,16 @@ namespace System.Reflection { // If you modify any of these fields, you must also update the // AssemblyBaseObject structure in object.h - private string _name; - private byte[] _publicKey; - private byte[] _publicKeyToken; - private CultureInfo _cultureInfo; - private string _codeBase; - private Version _version; + private string? _name; + private byte[]? _publicKey; + private byte[]? _publicKeyToken; + private CultureInfo? _cultureInfo; + private string? _codeBase; + private Version? _version; - private StrongNameKeyPair _strongNameKeyPair; + private StrongNameKeyPair? _strongNameKeyPair; - private byte[] _hashForControl; + private byte[]? _hashForControl; private AssemblyHashAlgorithm _hashAlgorithm; private AssemblyHashAlgorithm _hashAlgorithmForControl; @@ -53,26 +54,26 @@ namespace System.Reflection // Set and get the name of the assembly. If this is a weak Name // then it optionally contains a site. For strong assembly names, // the name partitions up the strong name's namespace - public string Name + public string? Name { get { return _name; } set { _name = value; } } - public Version Version + public Version? Version { get { return _version; } set { _version = value; } } // Locales, internally the LCID is used for the match. - public CultureInfo CultureInfo + public CultureInfo? CultureInfo { get { return _cultureInfo; } set { _cultureInfo = value; } } - public string CultureName + public string? CultureName { get { @@ -84,13 +85,13 @@ namespace System.Reflection } } - public string CodeBase + public string? CodeBase { get { return _codeBase; } set { _codeBase = value; } } - public string EscapedCodeBase + public string? EscapedCodeBase { get { @@ -180,12 +181,12 @@ namespace System.Reflection // inclusion into the namespace. If the public key associated // with the namespace cannot verify the assembly the assembly // will fail to load. - public byte[] GetPublicKey() + public byte[]? GetPublicKey() { return _publicKey; } - public void SetPublicKey(byte[] publicKey) + public void SetPublicKey(byte[]? publicKey) { _publicKey = publicKey; @@ -204,7 +205,7 @@ namespace System.Reflection return _publicKeyToken; } - public void SetPublicKeyToken(byte[] publicKeyToken) + public void SetPublicKeyToken(byte[]? publicKeyToken) { _publicKeyToken = publicKeyToken; } @@ -238,7 +239,7 @@ namespace System.Reflection set { _versionCompatibility = value; } } - public StrongNameKeyPair KeyPair + public StrongNameKeyPair? KeyPair { get { return _strongNameKeyPair; } set { _strongNameKeyPair = value; } @@ -260,7 +261,7 @@ namespace System.Reflection { string s = FullName; if (s == null) - return base.ToString(); + return base.ToString()!; else return s; } @@ -280,7 +281,7 @@ namespace System.Reflection /// match the intent of this api, this api has been broken this way since its debut and we cannot /// change its behavior now. /// - public static bool ReferenceMatchesDefinition(AssemblyName reference, AssemblyName definition) + public static bool ReferenceMatchesDefinition(AssemblyName? reference, AssemblyName? definition) { if (object.ReferenceEquals(reference, definition)) return true; @@ -297,11 +298,11 @@ namespace System.Reflection } [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern void nInit(out RuntimeAssembly assembly, bool raiseResolveEvent); + internal extern void nInit(out RuntimeAssembly? assembly, bool raiseResolveEvent); internal void nInit() { - RuntimeAssembly dummy = null; + RuntimeAssembly? dummy = null; nInit(out dummy, false); } @@ -349,16 +350,16 @@ namespace System.Reflection return ProcessorArchitecture.None; } - internal void Init(string name, - byte[] publicKey, - byte[] publicKeyToken, - Version version, - CultureInfo cultureInfo, + internal void Init(string? name, + byte[]? publicKey, + byte[]? publicKeyToken, + Version? version, + CultureInfo? cultureInfo, AssemblyHashAlgorithm hashAlgorithm, AssemblyVersionCompatibility versionCompatibility, - string codeBase, + string? codeBase, AssemblyNameFlags flags, - StrongNameKeyPair keyPair) // Null if ref, matching Assembly if def + StrongNameKeyPair? keyPair) // Null if ref, matching Assembly if def { _name = name; @@ -393,13 +394,13 @@ namespace System.Reflection [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern byte[] nGetPublicKeyToken(); - internal static string EscapeCodeBase(string codebase) + internal static string EscapeCodeBase(string? codebase) { if (codebase == null) return string.Empty; int position = 0; - char[] dest = EscapeString(codebase, 0, codebase.Length, null, ref position, true, c_DummyChar, c_DummyChar, c_DummyChar); + char[]? dest = EscapeString(codebase, 0, codebase.Length, null, ref position, true, c_DummyChar, c_DummyChar, c_DummyChar); if (dest == null) return codebase; @@ -418,7 +419,7 @@ namespace System.Reflection // // Returns null if nothing has to be escaped AND passed dest was null, otherwise the resulting array with the updated destPos // - internal static unsafe char[] EscapeString(string input, int start, int end, char[] dest, ref int destPos, + internal static unsafe char[]? EscapeString(string input, int start, int end, char[]? dest, ref int destPos, bool isUriString, char force1, char force2, char rsvd) { int i = start; @@ -519,15 +520,15 @@ namespace System.Reflection // // ensure destination array has enough space and contains all the needed input stuff // - private static unsafe char[] EnsureDestinationSize(char* pStr, char[] dest, int currentInputPos, + private static unsafe char[] EnsureDestinationSize(char* pStr, char[]? dest, int currentInputPos, short charsToAdd, short minReallocateChars, ref int destPos, int prevInputPos) { - if ((object)dest == null || dest.Length < destPos + (currentInputPos - prevInputPos) + charsToAdd) + if (dest is null || dest.Length < destPos + (currentInputPos - prevInputPos) + charsToAdd) { // allocating or reallocating array by ensuring enough space based on maxCharsToAdd. char[] newresult = new char[destPos + (currentInputPos - prevInputPos) + minReallocateChars]; - if ((object)dest != null && destPos != 0) + if (!(dest is null) && destPos != 0) Buffer.BlockCopy(dest, 0, newresult, 0, destPos << 1); dest = newresult; } diff --git a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index 394a8f3..0720ae9 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -2,12 +2,11 @@ // 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.Collections.Generic; using System.Diagnostics; using CultureInfo = System.Globalization.CultureInfo; -using System.Security; using System.IO; -using StringBuilder = System.Text.StringBuilder; using System.Configuration.Assemblies; using StackCrawlMark = System.Threading.StackCrawlMark; using System.Runtime.InteropServices; @@ -23,8 +22,8 @@ namespace System.Reflection #region private data members private event ModuleResolveEventHandler _ModuleResolve; - private string m_fullname; - private object m_syncRoot; // Used to keep collectible types alive and as the syncroot for reflection.emit + private string? m_fullname; + private object? m_syncRoot; // Used to keep collectible types alive and as the syncroot for reflection.emit private IntPtr m_assembly; // slack for ptr datum on unmanaged side #endregion @@ -45,9 +44,9 @@ namespace System.Reflection { if (m_syncRoot == null) { - Interlocked.CompareExchange(ref m_syncRoot, new object(), null); + Interlocked.CompareExchange(ref m_syncRoot, new object(), null); } - return m_syncRoot; + return m_syncRoot!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } } @@ -70,14 +69,14 @@ namespace System.Reflection bool copiedName, StringHandleOnStack retString); - internal string GetCodeBase(bool copiedName) + internal string? GetCodeBase(bool copiedName) { - string codeBase = null; + string? codeBase = null; GetCodeBase(GetNativeHandle(), copiedName, JitHelpers.GetStringHandleOnStack(ref codeBase)); return codeBase; } - public override string CodeBase => GetCodeBase(false); + public override string? CodeBase => GetCodeBase(false); internal RuntimeAssembly GetNativeHandle() => this; @@ -88,7 +87,7 @@ namespace System.Reflection { AssemblyName an = new AssemblyName(); - string codeBase = GetCodeBase(copiedName); + string? codeBase = GetCodeBase(copiedName); an.Init(GetSimpleName(), GetPublicKey(), @@ -101,12 +100,12 @@ namespace System.Reflection GetFlags() | AssemblyNameFlags.PublicKey, null); // strong name key pair - Module manifestModule = ManifestModule; + Module? manifestModule = ManifestModule; if (manifestModule != null) { if (manifestModule.MDStreamVersion > 0x10000) { - ManifestModule.GetPEKind(out PortableExecutableKinds pek, out ImageFileMachine ifm); + manifestModule.GetPEKind(out PortableExecutableKinds pek, out ImageFileMachine ifm); an.SetProcArchIndex(pek, ifm); } } @@ -116,16 +115,16 @@ namespace System.Reflection [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void GetFullName(RuntimeAssembly assembly, StringHandleOnStack retString); - public override string FullName + public override string? FullName { get { // If called by Object.ToString(), return val may be NULL. if (m_fullname == null) { - string s = null; + string? s = null; GetFullName(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref s)); - Interlocked.CompareExchange(ref m_fullname, s, null); + Interlocked.CompareExchange(ref m_fullname, s, null); } return m_fullname; @@ -135,11 +134,11 @@ namespace System.Reflection [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void GetEntryPoint(RuntimeAssembly assembly, ObjectHandleOnStack retMethod); - public override MethodInfo EntryPoint + public override MethodInfo? EntryPoint { get { - IRuntimeMethodInfo methodHandle = null; + IRuntimeMethodInfo? methodHandle = null; GetEntryPoint(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref methodHandle)); if (methodHandle == null) @@ -157,14 +156,14 @@ namespace System.Reflection ObjectHandleOnStack type, ObjectHandleOnStack keepAlive); - public override Type GetType(string name, bool throwOnError, bool ignoreCase) + public override Type? GetType(string name, bool throwOnError, bool ignoreCase) { // throw on null strings regardless of the value of "throwOnError" if (name == null) throw new ArgumentNullException(nameof(name)); - RuntimeType type = null; - object keepAlive = null; + RuntimeType? type = null; + object? keepAlive = null; GetType(GetNativeHandle(), name, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref type), JitHelpers.GetObjectHandleOnStack(ref keepAlive)); GC.KeepAlive(keepAlive); @@ -176,9 +175,9 @@ namespace System.Reflection public override Type[] GetExportedTypes() { - Type[] types = null; + Type[]? types = null; GetExportedTypes(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref types)); - return types; + return types!; } public override IEnumerable DefinedTypes @@ -215,12 +214,12 @@ namespace System.Reflection out uint length); // Load a resource based on the NameSpace of the type. - public override Stream GetManifestResourceStream(Type type, string name) + public override Stream? GetManifestResourceStream(Type type, string name) { if (type == null && name == null) throw new ArgumentNullException(nameof(type)); - string nameSpace = type?.Namespace; + string? nameSpace = type?.Namespace; char c = Type.Delimiter; string resourceName = nameSpace != null && name != null ? @@ -230,7 +229,7 @@ namespace System.Reflection return GetManifestResourceStream(resourceName); } - public unsafe override Stream GetManifestResourceStream(string name) + public unsafe override Stream? GetManifestResourceStream(string name) { uint length = 0; byte* pbInMemoryResource = GetResource(GetNativeHandle(), name, out length); @@ -249,7 +248,7 @@ namespace System.Reflection throw new PlatformNotSupportedException(); } - public override Module ManifestModule + public override Module? ManifestModule { get { @@ -269,7 +268,7 @@ namespace System.Reflection if (attributeType == null) throw new ArgumentNullException(nameof(attributeType)); - RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType; + RuntimeType? attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType; if (attributeRuntimeType == null) throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType)); @@ -282,7 +281,7 @@ namespace System.Reflection if (attributeType == null) throw new ArgumentNullException(nameof(attributeType)); - RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType; + RuntimeType? attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType; if (attributeRuntimeType == null) throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType)); @@ -297,7 +296,7 @@ namespace System.Reflection internal static RuntimeAssembly InternalLoad(string assemblyString, ref StackCrawlMark stackMark) { - RuntimeAssembly assembly; + RuntimeAssembly? assembly; AssemblyName an = CreateAssemblyName(assemblyString, out assembly); if (assembly != null) @@ -312,7 +311,7 @@ namespace System.Reflection // Creates AssemblyName. Fills assembly if AssemblyResolve event has been raised. internal static AssemblyName CreateAssemblyName( string assemblyString, - out RuntimeAssembly assemblyFromResolveEvent) + out RuntimeAssembly? assemblyFromResolveEvent) { if (assemblyString == null) throw new ArgumentNullException(nameof(assemblyString)); @@ -348,15 +347,15 @@ namespace System.Reflection assemblyRef.ProcessorArchitecture = ProcessorArchitecture.None; } - string codeBase = VerifyCodeBase(assemblyRef.CodeBase); + string? codeBase = VerifyCodeBase(assemblyRef.CodeBase); return nLoad(assemblyRef, codeBase, null, ref stackMark, true, ptrLoadContextBinder); } [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern RuntimeAssembly nLoad(AssemblyName fileName, - string codeBase, - RuntimeAssembly assemblyContext, + string? codeBase, + RuntimeAssembly? assemblyContext, ref StackCrawlMark stackMark, bool throwOnFileNotFound, IntPtr ptrLoadContextBinder); @@ -374,18 +373,18 @@ namespace System.Reflection [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void GetModule(RuntimeAssembly assembly, string name, ObjectHandleOnStack retModule); - public override Module GetModule(string name) + public override Module? GetModule(string name) { - Module retModule = null; + Module? retModule = null; GetModule(GetNativeHandle(), name, JitHelpers.GetObjectHandleOnStack(ref retModule)); return retModule; } // Returns the file in the File table of the manifest that matches the // given name. (Name should not include path.) - public override FileStream GetFile(string name) + public override FileStream? GetFile(string name) { - RuntimeModule m = (RuntimeModule)GetModule(name); + RuntimeModule? m = (RuntimeModule?)GetModule(name); if (m == null) return null; @@ -434,10 +433,10 @@ namespace System.Reflection ObjectHandleOnStack assemblyRef, StringHandleOnStack retFileName); - public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) + public override ManifestResourceInfo? GetManifestResourceInfo(string resourceName) { - RuntimeAssembly retAssembly = null; - string fileName = null; + RuntimeAssembly? retAssembly = null; + string? fileName = null; int location = GetManifestResourceInfo(GetNativeHandle(), resourceName, JitHelpers.GetObjectHandleOnStack(ref retAssembly), JitHelpers.GetStringHandleOnStack(ref fileName)); @@ -456,11 +455,11 @@ namespace System.Reflection { get { - string location = null; + string? location = null; GetLocation(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref location)); - return location; + return location!; } } @@ -471,9 +470,9 @@ namespace System.Reflection { get { - string s = null; + string? s = null; GetImageRuntimeVersion(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref s)); - return s; + return s!; } } @@ -493,7 +492,7 @@ namespace System.Reflection } } - private static string VerifyCodeBase(string codebase) + private static string? VerifyCodeBase(string? codebase) { if (codebase == null) return null; @@ -540,7 +539,7 @@ namespace System.Reflection internal CultureInfo GetLocale() { - string locale = null; + string? locale = null; GetLocale(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref locale)); @@ -564,9 +563,9 @@ namespace System.Reflection [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void GetSimpleName(RuntimeAssembly assembly, StringHandleOnStack retSimpleName); - internal string GetSimpleName() + internal string? GetSimpleName() { - string name = null; + string? name = null; GetSimpleName(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref name)); return name; } @@ -590,15 +589,15 @@ namespace System.Reflection [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void GetPublicKey(RuntimeAssembly assembly, ObjectHandleOnStack retPublicKey); - internal byte[] GetPublicKey() + internal byte[]? GetPublicKey() { - byte[] publicKey = null; + byte[]? publicKey = null; GetPublicKey(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref publicKey)); return publicKey; } // This method is called by the VM. - private RuntimeModule OnModuleResolveEvent(string moduleName) + private RuntimeModule? OnModuleResolveEvent(string moduleName) { ModuleResolveEventHandler moduleResolve = _ModuleResolve; if (moduleResolve == null) @@ -620,17 +619,17 @@ namespace System.Reflection } // Useful for binding to a very specific version of a satellite assembly - public override Assembly GetSatelliteAssembly(CultureInfo culture, Version version) + public override Assembly GetSatelliteAssembly(CultureInfo culture, Version? version) { if (culture == null) throw new ArgumentNullException(nameof(culture)); - return InternalGetSatelliteAssembly(culture, version, true); + return InternalGetSatelliteAssembly(culture, version, throwOnFileNotFound: true)!; } [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod - internal Assembly InternalGetSatelliteAssembly(CultureInfo culture, - Version version, + internal Assembly? InternalGetSatelliteAssembly(CultureInfo culture, + Version? version, bool throwOnFileNotFound) { AssemblyName an = new AssemblyName(); @@ -649,7 +648,7 @@ namespace System.Reflection // This stack crawl mark is never used because the requesting assembly is explicitly specified, // so the value could be anything. StackCrawlMark unused = default; - RuntimeAssembly retAssembly = nLoad(an, null, this, ref unused, throwOnFileNotFound, IntPtr.Zero); + RuntimeAssembly? retAssembly = nLoad(an, null, this, ref unused, throwOnFileNotFound, IntPtr.Zero); if (retAssembly == this) { @@ -673,9 +672,9 @@ namespace System.Reflection private RuntimeModule[] GetModulesInternal(bool loadIfNotFound, bool getResourceModules) { - RuntimeModule[] modules = null; + RuntimeModule[]? modules = null; GetModules(GetNativeHandle(), loadIfNotFound, getResourceModules, JitHelpers.GetObjectHandleOnStack(ref modules)); - return modules; + return modules!; } public override Module[] GetModules(bool getResourceModules) @@ -704,8 +703,8 @@ namespace System.Reflection for (int i = 0; i < enumResult.Length; i++) { MetadataToken mdtExternalType = enumResult[i]; - Type type = null; - Exception exception = null; + Type? type = null; + Exception? exception = null; ObjectHandleOnStack pType = JitHelpers.GetObjectHandleOnStack(ref type); try { @@ -719,7 +718,7 @@ namespace System.Reflection exception = e; } - Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null. + Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null. // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 if (type != null) { @@ -728,7 +727,7 @@ namespace System.Reflection } else { - exceptions.Add(exception); + exceptions.Add(exception!); } } diff --git a/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs index 9955336..43f9efd 100644 --- a/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs @@ -11,7 +11,7 @@ namespace System.Resources internal partial class ManifestBasedResourceGroveler { // Internal version of GetSatelliteAssembly that avoids throwing FileNotFoundException - private static Assembly InternalGetSatelliteAssembly(Assembly mainAssembly, + private static Assembly? InternalGetSatelliteAssembly(Assembly mainAssembly, CultureInfo culture, Version? version) { diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs index 1080821..1eae91c 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs @@ -7,6 +7,7 @@ // Low-level Jit Helpers //////////////////////////////////////////////////////////////////////////////// +#nullable enable using System.Threading; using System.Diagnostics; using Internal.Runtime.CompilerServices; @@ -66,14 +67,14 @@ namespace System.Runtime.CompilerServices // Wraps object variable into a handle. Used to return managed strings from QCalls. // s has to be a local variable on the stack. - internal static StringHandleOnStack GetStringHandleOnStack(ref string s) + internal static StringHandleOnStack GetStringHandleOnStack(ref string? s) { return new StringHandleOnStack((IntPtr)Unsafe.AsPointer(ref s)); } // Wraps object variable into a handle. Used to pass managed object references in and out of QCalls. // o has to be a local variable on the stack. - internal static ObjectHandleOnStack GetObjectHandleOnStack(ref T o) where T : class + internal static ObjectHandleOnStack GetObjectHandleOnStack(ref T o) where T : class? { return new ObjectHandleOnStack((IntPtr)Unsafe.AsPointer(ref o)); } diff --git a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs index 1cbadc8..065ff40 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs @@ -123,7 +123,7 @@ namespace System.Runtime.Loader return null; } - private Assembly ValidateAssemblyNameWithSimpleName(Assembly assembly, string requestedSimpleName) + private Assembly ValidateAssemblyNameWithSimpleName(Assembly assembly, string? requestedSimpleName) { // Get the name of the loaded assembly string? loadedSimpleName = null; @@ -138,15 +138,21 @@ namespace System.Runtime.Loader } // The simple names should match at the very least - if (string.IsNullOrEmpty(loadedSimpleName) || (!requestedSimpleName.Equals(loadedSimpleName, StringComparison.InvariantCultureIgnoreCase))) + if (string.IsNullOrEmpty(requestedSimpleName)) + { + throw new ArgumentException(SR.ArgumentNull_AssemblyNameName); + } + if (string.IsNullOrEmpty(loadedSimpleName) || requestedSimpleName.Equals(loadedSimpleName, StringComparison.InvariantCultureIgnoreCase)) + { throw new InvalidOperationException(SR.Argument_CustomAssemblyLoadContextRequestedNameMismatch); + } return assembly; } private Assembly? ResolveUsingLoad(AssemblyName assemblyName) { - string simpleName = assemblyName.Name; + string? simpleName = assemblyName.Name; Assembly? assembly = Load(assemblyName); if (assembly != null) @@ -159,7 +165,7 @@ namespace System.Runtime.Loader private Assembly ResolveUsingEvent(AssemblyName assemblyName) { - string simpleName = assemblyName.Name; + string? simpleName = assemblyName.Name; // Invoke the AssemblyResolve event callbacks if wired up Assembly? assembly = GetFirstResolvedAssembly(assemblyName); diff --git a/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs b/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs index 2066ed7..5cc7238 100644 --- a/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs +++ b/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs @@ -2,9 +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. - -using System; - +#nullable enable namespace System { // This value type is used for constructing System.ArgIterator. diff --git a/src/System.Private.CoreLib/src/System/StartupHookProvider.cs b/src/System.Private.CoreLib/src/System/StartupHookProvider.cs index 051b379..6856817 100644 --- a/src/System.Private.CoreLib/src/System/StartupHookProvider.cs +++ b/src/System.Private.CoreLib/src/System/StartupHookProvider.cs @@ -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.Diagnostics; using System.IO; using System.Reflection; @@ -28,7 +29,7 @@ namespace System // Initialize tracing before any user code can be called. System.Diagnostics.Tracing.EventPipeController.Initialize(); - string startupHooksVariable = (string)AppContext.GetData("STARTUP_HOOKS"); + string? startupHooksVariable = (string?)AppContext.GetData("STARTUP_HOOKS"); if (startupHooksVariable == null) { return; @@ -121,7 +122,7 @@ namespace System catch (Exception assemblyLoadException) { throw new ArgumentException( - SR.Format(SR.Argument_StartupHookAssemblyLoadFailed, startupHook.Path ?? startupHook.AssemblyName.ToString()), + SR.Format(SR.Argument_StartupHookAssemblyLoadFailed, startupHook.Path ?? startupHook.AssemblyName!.ToString()), assemblyLoadException); } diff --git a/src/System.Private.CoreLib/src/System/StubHelpers.cs b/src/System.Private.CoreLib/src/System/StubHelpers.cs index 7fc7db1..e28e536 100644 --- a/src/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/System.Private.CoreLib/src/System/StubHelpers.cs @@ -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 namespace System.StubHelpers { using System.Text; @@ -103,7 +103,7 @@ namespace System.StubHelpers return (IntPtr)pbNativeBuffer; } - internal static unsafe string ConvertToManaged(IntPtr cstr) + internal static unsafe string? ConvertToManaged(IntPtr cstr) { if (IntPtr.Zero == cstr) return null; @@ -155,7 +155,7 @@ namespace System.StubHelpers return (IntPtr)pbNativeBuffer; } - internal static unsafe string ConvertToManaged(IntPtr cstr) + internal static unsafe string? ConvertToManaged(IntPtr cstr) { if (IntPtr.Zero == cstr) return null; @@ -277,7 +277,7 @@ namespace System.StubHelpers } } - internal static unsafe string ConvertToManaged(IntPtr bstr) + internal static unsafe string? ConvertToManaged(IntPtr bstr) { if (IntPtr.Zero == bstr) { @@ -371,7 +371,7 @@ namespace System.StubHelpers return new IntPtr(pNative); } - internal static unsafe string ConvertToManaged(IntPtr pNative, int cch) + internal static unsafe string? ConvertToManaged(IntPtr pNative, int cch) { if (IntPtr.Zero == pNative) { @@ -399,7 +399,7 @@ namespace System.StubHelpers return IntPtr.Zero; } - byte[] bytes = null; + byte[]? bytes = null; int nb = 0; if (strManaged.Length > 0) @@ -410,7 +410,7 @@ namespace System.StubHelpers return Interop.OleAut32.SysAllocStringByteLen(bytes, (uint)nb); } - internal static unsafe string ConvertToManaged(IntPtr bstr) + internal static unsafe string? ConvertToManaged(IntPtr bstr) { if (IntPtr.Zero == bstr) { @@ -442,7 +442,7 @@ namespace System.StubHelpers return IntPtr.Zero; } - internal static string ConvertToManaged(IntPtr bstr) + internal static string? ConvertToManaged(IntPtr bstr) { Debug.Fail("NYI"); return null; @@ -695,7 +695,7 @@ namespace System.StubHelpers [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void ConvertContentsToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome); - internal static unsafe void ConvertContentsToNative_DateTime(ref DateTimeOffset[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToNative_DateTime(ref DateTimeOffset[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -707,7 +707,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToNative_Type(ref System.Type[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToNative_Type(ref System.Type[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -719,7 +719,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToNative_Exception(ref Exception[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToNative_Exception(ref Exception[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -731,7 +731,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToNative_Nullable(ref Nullable[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToNative_Nullable(ref Nullable[]? managedArray, IntPtr pNativeHome) where T : struct { if (managedArray != null) @@ -744,7 +744,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToNative_KeyValuePair(ref KeyValuePair[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToNative_KeyValuePair(ref KeyValuePair[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -762,7 +762,7 @@ namespace System.StubHelpers [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void ConvertContentsToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome); - internal static unsafe void ConvertContentsToManaged_DateTime(ref DateTimeOffset[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToManaged_DateTime(ref DateTimeOffset[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -774,7 +774,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToManaged_Type(ref System.Type[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToManaged_Type(ref System.Type?[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -786,7 +786,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToManaged_Exception(ref Exception[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToManaged_Exception(ref Exception?[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -798,7 +798,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToManaged_Nullable(ref Nullable[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToManaged_Nullable(ref Nullable[]? managedArray, IntPtr pNativeHome) where T : struct { if (managedArray != null) @@ -811,7 +811,7 @@ namespace System.StubHelpers } } - internal static unsafe void ConvertContentsToManaged_KeyValuePair(ref KeyValuePair[] managedArray, IntPtr pNativeHome) + internal static unsafe void ConvertContentsToManaged_KeyValuePair(ref KeyValuePair[]? managedArray, IntPtr pNativeHome) { if (managedArray != null) { @@ -883,10 +883,10 @@ namespace System.StubHelpers private BackPropAction backPropAction; // The managed layout type for BackPropAction.Layout. - private Type layoutType; + private Type? layoutType; // Cleanup list to be destroyed when clearing the native view (for layouts with SafeHandles). - private CleanupWorkListElement cleanupWorkList; + private CleanupWorkListElement? cleanupWorkList; [Flags] internal enum AsAnyFlags @@ -1129,8 +1129,8 @@ namespace System.StubHelpers } else { - string strValue; - StringBuilder sbValue; + string? strValue; + StringBuilder? sbValue; if ((strValue = pManagedHome as string) != null) { @@ -1333,7 +1333,7 @@ namespace System.StubHelpers Marshal.ThrowExceptionForHR(hrCreate, new IntPtr(-1)); } - internal static unsafe void ConvertToManaged(TypeNameNative* pNativeType, ref System.Type managedType) + internal static unsafe void ConvertToManaged(TypeNameNative* pNativeType, ref System.Type? managedType) { if (!Environment.IsWinRTSupported) { @@ -1389,14 +1389,14 @@ namespace System.StubHelpers return ex.HResult; } - internal static Exception ConvertToManaged(int hr) + internal static Exception? ConvertToManaged(int hr) { if (!Environment.IsWinRTSupported) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT); } - Exception e = null; + Exception? e = null; if (hr < 0) { e = StubHelpers.InternalGetCOMHRExceptionObject(hr, IntPtr.Zero, null, /* fForWinRT */ true); @@ -1458,13 +1458,13 @@ namespace System.StubHelpers internal abstract class CleanupWorkListElement { - private CleanupWorkListElement m_Next; + private CleanupWorkListElement? m_Next; protected abstract void DestroyCore(); public void Destroy() { DestroyCore(); - CleanupWorkListElement next = m_Next; + CleanupWorkListElement? next = m_Next; while (next != null) { next.DestroyCore(); @@ -1569,7 +1569,7 @@ namespace System.StubHelpers CleanupWorkListElement.AddToCleanupList(ref pCleanupWorkList, element); } - internal static void DestroyCleanupList(ref CleanupWorkListElement pCleanupWorkList) + internal static void DestroyCleanupList(ref CleanupWorkListElement? pCleanupWorkList) { if (pCleanupWorkList != null) { @@ -1604,7 +1604,7 @@ namespace System.StubHelpers } [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern Exception InternalGetCOMHRExceptionObject(int hr, IntPtr pCPCMD, object pThis, bool fForWinRT); + internal static extern Exception InternalGetCOMHRExceptionObject(int hr, IntPtr pCPCMD, object? pThis, bool fForWinRT); #endif // FEATURE_COMINTEROP @@ -1623,7 +1623,7 @@ namespace System.StubHelpers ThrowHelper.ThrowArgumentNullException(ExceptionArgument.pHandle, ExceptionResource.ArgumentNull_SafeHandle); } - pHandle.DangerousAddRef(ref success); + pHandle!.DangerousAddRef(ref success); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return pHandle.DangerousGetHandle(); } @@ -1637,7 +1637,7 @@ namespace System.StubHelpers try { - pHandle.DangerousRelease(); + pHandle!.DangerousRelease(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } catch { @@ -1725,7 +1725,7 @@ namespace System.StubHelpers } [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe void FmtClassUpdateNativeInternal(object obj, byte* pNative, ref CleanupWorkListElement pCleanupWorkList); + internal static extern unsafe void FmtClassUpdateNativeInternal(object obj, byte* pNative, ref CleanupWorkListElement? pCleanupWorkList); [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern unsafe void FmtClassUpdateCLRInternal(object obj, byte* pNative); [MethodImplAttribute(MethodImplOptions.InternalCall)] diff --git a/src/System.Private.CoreLib/src/System/TypeLoadException.CoreCLR.cs b/src/System.Private.CoreLib/src/System/TypeLoadException.CoreCLR.cs index 90f969a..6120669 100644 --- a/src/System.Private.CoreLib/src/System/TypeLoadException.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/TypeLoadException.CoreCLR.cs @@ -43,7 +43,7 @@ namespace System string? format = null; GetTypeLoadExceptionMessage(_resourceId, JitHelpers.GetStringHandleOnStack(ref format)); - _message = string.Format(format, _className, _assemblyName, _messageArg); + _message = string.Format(format!, _className, _assemblyName, _messageArg); } } } diff --git a/src/System.Private.CoreLib/src/System/TypedReference.cs b/src/System.Private.CoreLib/src/System/TypedReference.cs index 152ba70..0713624 100644 --- a/src/System.Private.CoreLib/src/System/TypedReference.cs +++ b/src/System.Private.CoreLib/src/System/TypedReference.cs @@ -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 namespace System { // TypedReference is basically only ever seen on the call stack, and in param arrays. @@ -37,7 +38,7 @@ namespace System RuntimeType targetType = (RuntimeType)target.GetType(); for (int i = 0; i < flds.Length; i++) { - RuntimeFieldInfo field = flds[i] as RuntimeFieldInfo; + RuntimeFieldInfo? field = flds[i] as RuntimeFieldInfo; if (field == null) throw new ArgumentException(SR.Argument_MustBeRuntimeFieldInfo); @@ -80,7 +81,7 @@ namespace System return __reftype(this).GetHashCode(); } - public override bool Equals(object o) + public override bool Equals(object? o) { throw new NotSupportedException(SR.NotSupported_NYI); } @@ -113,12 +114,12 @@ namespace System // This may cause the type to be changed. [CLSCompliant(false)] - public static unsafe void SetTypedReference(TypedReference target, object value) + public static unsafe void SetTypedReference(TypedReference target, object? value) { InternalSetTypedReference(&target, value); } [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe void InternalSetTypedReference(void* target, object value); + internal static extern unsafe void InternalSetTypedReference(void* target, object? value); } } diff --git a/src/System.Private.CoreLib/src/System/Utf8Extensions.cs b/src/System.Private.CoreLib/src/System/Utf8Extensions.cs index 9fa2a54..1382d58 100644 --- a/src/System.Private.CoreLib/src/System/Utf8Extensions.cs +++ b/src/System.Private.CoreLib/src/System/Utf8Extensions.cs @@ -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.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; @@ -24,7 +25,7 @@ namespace System /// The target . /// Returns default when is null. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsBytes(this Utf8String text) + public static ReadOnlySpan AsBytes(this Utf8String? text) { if (text == null) return default; @@ -42,7 +43,7 @@ namespace System /// Thrown when the specified index is not in range (<0 or >text.Length). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsBytes(this Utf8String text, int start) + public static ReadOnlySpan AsBytes(this Utf8String? text, int start) { if (text == null) { @@ -68,7 +69,7 @@ namespace System /// Thrown when the specified index or is not in range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsBytes(this Utf8String text, int start, int length) + public static ReadOnlySpan AsBytes(this Utf8String? text, int start, int length) { if (text == null) { @@ -95,7 +96,7 @@ namespace System /// The target . /// Returns default when is null. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsSpan(this Utf8String text) + public static ReadOnlySpan AsSpan(this Utf8String? text) { if (text == null) return default; @@ -113,7 +114,7 @@ namespace System /// Thrown when the specified index is not in range (<0 or >text.Length). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsSpan(this Utf8String text, int start) + public static ReadOnlySpan AsSpan(this Utf8String? text, int start) { if (text == null) { @@ -139,7 +140,7 @@ namespace System /// Thrown when the specified index or is not in range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsSpan(this Utf8String text, int start, int length) + public static ReadOnlySpan AsSpan(this Utf8String? text, int start, int length) { if (text == null) { @@ -163,7 +164,7 @@ namespace System /// Creates a new over the portion of the target . /// The target . /// Returns default when is null. - public static ReadOnlyMemory AsMemory(this Utf8String text) + public static ReadOnlyMemory AsMemory(this Utf8String? text) { if (text == null) return default; @@ -178,7 +179,7 @@ namespace System /// /// Thrown when the specified index is not in range (<0 or >text.Length). /// - public static ReadOnlyMemory AsMemory(this Utf8String text, int start) + public static ReadOnlyMemory AsMemory(this Utf8String? text, int start) { if (text == null) { @@ -196,7 +197,7 @@ namespace System /// Creates a new over the portion of the target . /// The target . /// The index at which to begin this slice. - public static ReadOnlyMemory AsMemory(this Utf8String text, Index startIndex) + public static ReadOnlyMemory AsMemory(this Utf8String? text, Index startIndex) { if (text == null) { @@ -221,7 +222,7 @@ namespace System /// /// Thrown when the specified index or is not in range. /// - public static ReadOnlyMemory AsMemory(this Utf8String text, int start, int length) + public static ReadOnlyMemory AsMemory(this Utf8String? text, int start, int length) { if (text == null) { @@ -245,7 +246,7 @@ namespace System /// Creates a new over the portion of the target . /// The target . /// The range used to indicate the start and length of the sliced string. - public static ReadOnlyMemory AsMemory(this Utf8String text, Range range) + public static ReadOnlyMemory AsMemory(this Utf8String? text, Range range) { if (text == null) { @@ -265,7 +266,7 @@ namespace System /// Creates a new over the portion of the target . /// The target . /// Returns default when is null. - public static ReadOnlyMemory AsMemoryBytes(this Utf8String text) + public static ReadOnlyMemory AsMemoryBytes(this Utf8String? text) { if (text == null) return default; @@ -280,7 +281,7 @@ namespace System /// /// Thrown when the specified index is not in range (<0 or >text.Length). /// - public static ReadOnlyMemory AsMemoryBytes(this Utf8String text, int start) + public static ReadOnlyMemory AsMemoryBytes(this Utf8String? text, int start) { if (text == null) { @@ -298,7 +299,7 @@ namespace System /// Creates a new over the portion of the target . /// The target . /// The index at which to begin this slice. - public static ReadOnlyMemory AsMemoryBytes(this Utf8String text, Index startIndex) + public static ReadOnlyMemory AsMemoryBytes(this Utf8String? text, Index startIndex) { if (text == null) { @@ -323,7 +324,7 @@ namespace System /// /// Thrown when the specified index or is not in range. /// - public static ReadOnlyMemory AsMemoryBytes(this Utf8String text, int start, int length) + public static ReadOnlyMemory AsMemoryBytes(this Utf8String? text, int start, int length) { if (text == null) { @@ -347,7 +348,7 @@ namespace System /// Creates a new over the portion of the target . /// The target . /// The range used to indicate the start and length of the sliced string. - public static ReadOnlyMemory AsMemoryBytes(this Utf8String text, Range range) + public static ReadOnlyMemory AsMemoryBytes(this Utf8String? text, Range range) { if (text == null) { diff --git a/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs b/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs index 9ecd44f..4cf302e 100644 --- a/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs +++ b/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs @@ -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.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -49,7 +50,7 @@ namespace System Utf8String newString = FastAllocate(value.Length); Buffer.Memmove(ref newString.DangerousGetMutableReference(), ref MemoryMarshal.GetReference(value), (uint)value.Length); - return Utf8Utility.ValidateAndFixupUtf8String(newString); + return Utf8Utility.ValidateAndFixupUtf8String(newString)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } /// @@ -60,7 +61,7 @@ namespace System /// Invalid code unit sequences are replaced with U+FFFD in the resulting . /// [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(byte[] value, int startIndex, int length); + public extern Utf8String(byte[]? value, int startIndex, int length); #if PROJECTN [DependencyReductionRoot] @@ -68,7 +69,7 @@ namespace System #if !CORECLR static #endif - private Utf8String Ctor(byte[] value, int startIndex, int length) => Ctor(new ReadOnlySpan(value, startIndex, length)); + private Utf8String Ctor(byte[]? value, int startIndex, int length) => Ctor(new ReadOnlySpan(value, startIndex, length)); /// /// Creates a instance from existing null-terminated UTF-8 data. @@ -135,7 +136,7 @@ namespace System /// Invalid code unit sequences are replaced with U+FFFD in the resulting . /// [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(char[] value, int startIndex, int length); + public extern Utf8String(char[]? value, int startIndex, int length); #if PROJECTN [DependencyReductionRoot] @@ -143,7 +144,7 @@ namespace System #if !CORECLR static #endif - private Utf8String Ctor(char[] value, int startIndex, int length) => Ctor(new ReadOnlySpan(value, startIndex, length)); + private Utf8String Ctor(char[]? value, int startIndex, int length) => Ctor(new ReadOnlySpan(value, startIndex, length)); /// /// Creates a instance from existing null-terminated UTF-16 data. @@ -180,7 +181,7 @@ namespace System /// Invalid code unit sequences are replaced with U+FFFD in the resulting . /// [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(string value); + public extern Utf8String(string? value); #if PROJECTN [DependencyReductionRoot] @@ -188,7 +189,7 @@ namespace System #if !CORECLR static #endif - private Utf8String Ctor(string value) => Ctor(value.AsSpan()); + private Utf8String Ctor(string? value) => Ctor(value.AsSpan()); /* * HELPER METHODS diff --git a/src/System.Private.CoreLib/src/System/Utf8String.Manipulation.cs b/src/System.Private.CoreLib/src/System/Utf8String.Manipulation.cs index 9ca72f1..52e494d 100644 --- a/src/System.Private.CoreLib/src/System/Utf8String.Manipulation.cs +++ b/src/System.Private.CoreLib/src/System/Utf8String.Manipulation.cs @@ -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.Diagnostics; using System.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/src/System/Utf8String.Searching.cs b/src/System.Private.CoreLib/src/System/Utf8String.Searching.cs index 0373cdd..e607d02 100644 --- a/src/System.Private.CoreLib/src/System/Utf8String.Searching.cs +++ b/src/System.Private.CoreLib/src/System/Utf8String.Searching.cs @@ -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.Runtime.InteropServices; using System.Text; using System.Text.Unicode; diff --git a/src/System.Private.CoreLib/src/System/Utf8String.cs b/src/System.Private.CoreLib/src/System/Utf8String.cs index 8551830..684c928 100644 --- a/src/System.Private.CoreLib/src/System/Utf8String.cs +++ b/src/System.Private.CoreLib/src/System/Utf8String.cs @@ -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.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -13,7 +14,7 @@ namespace System /// /// Represents an immutable string of UTF-8 code units. /// - public sealed partial class Utf8String : IEquatable + public sealed partial class Utf8String : IEquatable { /* * STATIC FIELDS @@ -36,22 +37,22 @@ namespace System /// /// Compares two instances for equality using a comparer. /// - public static bool operator ==(Utf8String left, Utf8String right) => Equals(left, right); + public static bool operator ==(Utf8String? left, Utf8String? right) => Equals(left, right); /// /// Compares two instances for inequality using a comparer. /// - public static bool operator !=(Utf8String left, Utf8String right) => !Equals(left, right); + public static bool operator !=(Utf8String? left, Utf8String? right) => !Equals(left, right); /// /// Projects a instance as a . /// - public static explicit operator ReadOnlySpan(Utf8String value) => value.AsBytes(); + public static explicit operator ReadOnlySpan(Utf8String? value) => value.AsBytes(); /// /// Projects a instance as a . /// - public static implicit operator ReadOnlySpan(Utf8String value) => value.AsSpan(); + public static implicit operator ReadOnlySpan(Utf8String? value) => value.AsSpan(); /* * INSTANCE PROPERTIES @@ -129,7 +130,7 @@ namespace System /// /// Performs an equality comparison using a comparer. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Utf8String other && this.Equals(other); } @@ -137,7 +138,7 @@ namespace System /// /// Performs an equality comparison using a comparer. /// - public bool Equals(Utf8String value) + public bool Equals(Utf8String? value) { // First, a very quick check for referential equality. @@ -156,7 +157,7 @@ namespace System /// /// Compares two instances using a comparer. /// - public static bool Equals(Utf8String left, Utf8String right) + public static bool Equals(Utf8String? left, Utf8String? right) { // First, a very quick check for referential equality. @@ -198,7 +199,7 @@ namespace System /// Returns if is or zero length; /// otherwise. /// - public static bool IsNullOrEmpty(Utf8String value) + public static bool IsNullOrEmpty(Utf8String? value) { // Copied from String.IsNullOrEmpty. See that method for detailed comments on why this pattern is used. return (value is null || 0u >= (uint)value.Length) ? true : false; diff --git a/src/System.Private.CoreLib/src/System/Variant.cs b/src/System.Private.CoreLib/src/System/Variant.cs index 385a44f..f8da7e3 100644 --- a/src/System.Private.CoreLib/src/System/Variant.cs +++ b/src/System.Private.CoreLib/src/System/Variant.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +#nullable enable using System; using System.Reflection; using System.Threading; @@ -27,7 +28,7 @@ namespace System { //Do Not change the order of these fields. //They are mapped to the native VariantData * data structure. - private object m_objref; + private object? m_objref; private int m_data1; private int m_data2; private int m_flags; @@ -265,7 +266,7 @@ namespace System m_data2 = 0; } - public Variant(object obj) + public Variant(object? obj) { m_data1 = 0; m_data2 = 0; @@ -365,7 +366,7 @@ namespace System } } - public object ToObject() + public object? ToObject() { switch (CVType) { @@ -422,7 +423,7 @@ namespace System // managed variants as an intermediate type. internal static void MarshalHelperConvertObjectToVariant(object o, ref Variant v) { - IConvertible ic = o as IConvertible; + IConvertible? ic = o as IConvertible; if (o == null) { @@ -520,7 +521,7 @@ namespace System // Helper code for marshaling VARIANTS to managed objects (we use // managed variants as an intermediate type. - internal static object MarshalHelperConvertVariantToObject(ref Variant v) + internal static object? MarshalHelperConvertVariantToObject(ref Variant v) { return v.ToObject(); } diff --git a/src/System.Private.CoreLib/src/System/WeakReference.cs b/src/System.Private.CoreLib/src/System/WeakReference.cs index da0b1a2..64a38a9 100644 --- a/src/System.Private.CoreLib/src/System/WeakReference.cs +++ b/src/System.Private.CoreLib/src/System/WeakReference.cs @@ -9,6 +9,7 @@ ** ===========================================================*/ +#nullable enable using System; using System.Runtime.Serialization; using System.Security; @@ -37,14 +38,14 @@ namespace System // Creates a new WeakReference that keeps track of target. // Assumes a Short Weak Reference (ie TrackResurrection is false.) // - public WeakReference(object target) + public WeakReference(object? target) : this(target, false) { } //Creates a new WeakReference that keeps track of target. // - public WeakReference(object target, bool trackResurrection) + public WeakReference(object? target, bool trackResurrection) { Create(target, trackResurrection); } @@ -83,7 +84,7 @@ namespace System //Gets the Object stored in the handle if it's accessible. // Or sets it. // - public extern virtual object Target + public extern virtual object? Target { [MethodImplAttribute(MethodImplOptions.InternalCall)] get; @@ -111,7 +112,7 @@ namespace System } [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern void Create(object target, bool trackResurrection); + private extern void Create(object? target, bool trackResurrection); [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern bool IsTrackResurrection(); diff --git a/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs b/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs index 15f6daf..fb26126 100644 --- a/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs +++ b/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs @@ -9,6 +9,7 @@ ** ===========================================================*/ +#nullable enable using System; using System.Runtime.Serialization; using System.Security; @@ -22,7 +23,7 @@ namespace System [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] // This class is sealed to mitigate security issues caused by Object::MemberwiseClone. public sealed class WeakReference : ISerializable - where T : class + where T : class? { // If you fix bugs here, please fix them in WeakReference at the same time. diff --git a/src/System.Private.CoreLib/src/System/__Canon.cs b/src/System.Private.CoreLib/src/System/__Canon.cs index 7fbfa75..5bc4d56 100644 --- a/src/System.Private.CoreLib/src/System/__Canon.cs +++ b/src/System.Private.CoreLib/src/System/__Canon.cs @@ -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.Runtime.InteropServices; namespace System diff --git a/src/System.Private.CoreLib/src/System/__ComObject.cs b/src/System.Private.CoreLib/src/System/__ComObject.cs index 0aeb391..0d1d3d1 100644 --- a/src/System.Private.CoreLib/src/System/__ComObject.cs +++ b/src/System.Private.CoreLib/src/System/__ComObject.cs @@ -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.Collections; using System.Runtime.InteropServices; using System.Runtime.InteropServices.WindowsRuntime; @@ -15,7 +16,7 @@ namespace System /// internal class __ComObject : MarshalByRefObject { - private Hashtable m_ObjectToDataMap; // Do not rename (runtime relies on this name). + private Hashtable? m_ObjectToDataMap; // Do not rename (runtime relies on this name). /// /// Default constructor - can't instantiate this directly. @@ -42,15 +43,15 @@ namespace System } } - return base.ToString(); + return base.ToString()!; } /// /// Retrieves the data associated with the specified if such data exists. /// - internal object GetData(object key) + internal object? GetData(object key) { - object data = null; + object? data = null; // Synchronize access to the map. lock (this) @@ -69,7 +70,7 @@ namespace System /// /// Sets the data for the specified key on the current __ComObject. /// - internal bool SetData(object key, object data) + internal bool SetData(object key, object? data) { bool bAdded = false; @@ -104,7 +105,7 @@ namespace System // If the map hasn't been allocated, then there is nothing to do. if (m_ObjectToDataMap != null) { - foreach (object o in m_ObjectToDataMap.Values) + foreach (object? o in m_ObjectToDataMap.Values) { // Note: the value could be an object[] // We are fine for now as object[] doesn't implement IDisposable nor derive from __ComObject @@ -130,7 +131,7 @@ namespace System internal object GetEventProvider(RuntimeType t) { // Check to see if we already have a cached event provider for this type. - object provider = GetData(t); + object? provider = GetData(t); if (provider != null) { return provider; @@ -147,7 +148,7 @@ namespace System private object CreateEventProvider(RuntimeType t) { // Create the event provider for the specified type. - object EvProvider = Activator.CreateInstance(t, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[] { this }, null); + object EvProvider = Activator.CreateInstance(t, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[] { this }, null)!; // Attempt to cache the wrapper on the object. if (!SetData(t, EvProvider)) @@ -159,7 +160,7 @@ namespace System } // Another thead already cached the wrapper so use that one instead. - EvProvider = GetData(t); + EvProvider = GetData(t)!; } return EvProvider; -- 2.7.4