diff --git a/eng/targets/CSharp.Common.targets b/eng/targets/CSharp.Common.targets index e327a7b886..2caa7bf00e 100644 --- a/eng/targets/CSharp.Common.targets +++ b/eng/targets/CSharp.Common.targets @@ -28,6 +28,17 @@ + + + + $(DefineConstants),INTERNAL_NULLABLE_ATTRIBUTES + + + + + + + diff --git a/eng/targets/ReferenceAssembly.targets b/eng/targets/ReferenceAssembly.targets index bdf7e2c384..ec7dc3f721 100644 --- a/eng/targets/ReferenceAssembly.targets +++ b/eng/targets/ReferenceAssembly.targets @@ -26,11 +26,12 @@ <_TargetFrameworkOverride /> <_TargetFrameworkOverride Condition=" @(_ResultTargetFramework->Count()) > 1 ">%0A <TargetFrameworks Condition="'%24(DotNetBuildFromSource)' == 'true'">%24(DefaultNetCoreTargetFramework)</TargetFrameworks> + <_NullableProperty Condition="'$(Nullable)' != ''">%0A <Nullable>annotations</Nullable> - @(_ResultTargetFramework)$(_TargetFrameworkOverride) + @(_ResultTargetFramework)$(_TargetFrameworkOverride)$(_NullableProperty) @(ProjectListContentItem->'%(Identity)', '%0A') diff --git a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj index a6ffa6ada6..dc3a3b1ec2 100644 --- a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj +++ b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj @@ -3,6 +3,7 @@ netstandard2.0;$(DefaultNetCoreTargetFramework) $(DefaultNetCoreTargetFramework) + annotations diff --git a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs index 3b6186e98f..5943610fe8 100644 --- a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs +++ b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs @@ -21,10 +21,10 @@ namespace Microsoft.Extensions.Localization { public LocalizedString(string name, string value) { } public LocalizedString(string name, string value, bool resourceNotFound) { } - public LocalizedString(string name, string value, bool resourceNotFound, string searchedLocation) { } + public LocalizedString(string name, string value, bool resourceNotFound, string? searchedLocation) { } public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public bool ResourceNotFound { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string SearchedLocation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public string? SearchedLocation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public string Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public static implicit operator string (Microsoft.Extensions.Localization.LocalizedString localizedString) { throw null; } public override string ToString() { throw null; } diff --git a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netstandard2.0.cs b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netstandard2.0.cs index 3b6186e98f..5943610fe8 100644 --- a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netstandard2.0.cs +++ b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netstandard2.0.cs @@ -21,10 +21,10 @@ namespace Microsoft.Extensions.Localization { public LocalizedString(string name, string value) { } public LocalizedString(string name, string value, bool resourceNotFound) { } - public LocalizedString(string name, string value, bool resourceNotFound, string searchedLocation) { } + public LocalizedString(string name, string value, bool resourceNotFound, string? searchedLocation) { } public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public bool ResourceNotFound { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string SearchedLocation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public string? SearchedLocation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public string Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public static implicit operator string (Microsoft.Extensions.Localization.LocalizedString localizedString) { throw null; } public override string ToString() { throw null; } diff --git a/src/Localization/Abstractions/src/LocalizedString.cs b/src/Localization/Abstractions/src/LocalizedString.cs index 7cac58d16a..9cf8cb819e 100644 --- a/src/Localization/Abstractions/src/LocalizedString.cs +++ b/src/Localization/Abstractions/src/LocalizedString.cs @@ -38,7 +38,7 @@ namespace Microsoft.Extensions.Localization /// The actual string. /// Whether the string was not found in a resource. Set this to true to indicate an alternate string value was used. /// The location which was searched for a localization value. - public LocalizedString(string name, string value, bool resourceNotFound, string searchedLocation) + public LocalizedString(string name, string value, bool resourceNotFound, string? searchedLocation) { if (name == null) { @@ -60,7 +60,7 @@ namespace Microsoft.Extensions.Localization /// Implicitly converts the to a . /// /// The string to be implicitly converted. - public static implicit operator string(LocalizedString localizedString) + public static implicit operator string?(LocalizedString localizedString) { return localizedString?.Value; } @@ -83,7 +83,7 @@ namespace Microsoft.Extensions.Localization /// /// The location which was searched for a localization value. /// - public string SearchedLocation { get; } + public string? SearchedLocation { get; } /// /// Returns the actual string. diff --git a/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj b/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj index 4bf8ba5329..59c2ee7360 100644 --- a/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj +++ b/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj @@ -13,6 +13,7 @@ Microsoft.Extensions.Localization.IStringLocalizer<T> localization true true + enable diff --git a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj index b20502c893..a3b3faa042 100644 --- a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj +++ b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj @@ -3,6 +3,7 @@ netstandard2.0;$(DefaultNetCoreTargetFramework) $(DefaultNetCoreTargetFramework) + annotations diff --git a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp.cs b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp.cs index dea13ee364..c606bf0a9c 100644 --- a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp.cs +++ b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp.cs @@ -13,7 +13,7 @@ namespace Microsoft.Extensions.Localization { public partial interface IResourceNamesCache { - System.Collections.Generic.IList GetOrAdd(string name, System.Func> valueFactory); + System.Collections.Generic.IList? GetOrAdd(string name, System.Func?> valueFactory); } public partial class LocalizationOptions { @@ -35,7 +35,7 @@ namespace Microsoft.Extensions.Localization public virtual Microsoft.Extensions.Localization.LocalizedString this[string name, params object[] arguments] { get { throw null; } } public virtual System.Collections.Generic.IEnumerable GetAllStrings(bool includeParentCultures) { throw null; } protected System.Collections.Generic.IEnumerable GetAllStrings(bool includeParentCultures, System.Globalization.CultureInfo culture) { throw null; } - protected string GetStringSafely(string name, System.Globalization.CultureInfo culture) { throw null; } + protected string? GetStringSafely(string name, System.Globalization.CultureInfo? culture) { throw null; } } public partial class ResourceManagerStringLocalizerFactory : Microsoft.Extensions.Localization.IStringLocalizerFactory { @@ -43,17 +43,17 @@ namespace Microsoft.Extensions.Localization public Microsoft.Extensions.Localization.IStringLocalizer Create(string baseName, string location) { throw null; } public Microsoft.Extensions.Localization.IStringLocalizer Create(System.Type resourceSource) { throw null; } protected virtual Microsoft.Extensions.Localization.ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(System.Reflection.Assembly assembly, string baseName) { throw null; } - protected virtual Microsoft.Extensions.Localization.ResourceLocationAttribute GetResourceLocationAttribute(System.Reflection.Assembly assembly) { throw null; } + protected virtual Microsoft.Extensions.Localization.ResourceLocationAttribute? GetResourceLocationAttribute(System.Reflection.Assembly assembly) { throw null; } protected virtual string GetResourcePrefix(System.Reflection.TypeInfo typeInfo) { throw null; } - protected virtual string GetResourcePrefix(System.Reflection.TypeInfo typeInfo, string baseNamespace, string resourcesRelativePath) { throw null; } + protected virtual string GetResourcePrefix(System.Reflection.TypeInfo typeInfo, string? baseNamespace, string? resourcesRelativePath) { throw null; } protected virtual string GetResourcePrefix(string baseResourceName, string baseNamespace) { throw null; } protected virtual string GetResourcePrefix(string location, string baseName, string resourceLocation) { throw null; } - protected virtual Microsoft.Extensions.Localization.RootNamespaceAttribute GetRootNamespaceAttribute(System.Reflection.Assembly assembly) { throw null; } + protected virtual Microsoft.Extensions.Localization.RootNamespaceAttribute? GetRootNamespaceAttribute(System.Reflection.Assembly assembly) { throw null; } } public partial class ResourceNamesCache : Microsoft.Extensions.Localization.IResourceNamesCache { public ResourceNamesCache() { } - public System.Collections.Generic.IList GetOrAdd(string name, System.Func> valueFactory) { throw null; } + public System.Collections.Generic.IList? GetOrAdd(string name, System.Func?> valueFactory) { throw null; } } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple=false, Inherited=false)] public partial class RootNamespaceAttribute : System.Attribute @@ -69,15 +69,15 @@ namespace Microsoft.Extensions.Localization.Internal public AssemblyWrapper(System.Reflection.Assembly assembly) { } public System.Reflection.Assembly Assembly { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public virtual string FullName { get { throw null; } } - public virtual System.IO.Stream GetManifestResourceStream(string name) { throw null; } + public virtual System.IO.Stream? GetManifestResourceStream(string name) { throw null; } } public partial interface IResourceStringProvider { - System.Collections.Generic.IList GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing); + System.Collections.Generic.IList? GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing); } public partial class ResourceManagerStringProvider : Microsoft.Extensions.Localization.Internal.IResourceStringProvider { public ResourceManagerStringProvider(Microsoft.Extensions.Localization.IResourceNamesCache resourceCache, System.Resources.ResourceManager resourceManager, System.Reflection.Assembly assembly, string baseName) { } - public System.Collections.Generic.IList GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing) { throw null; } + public System.Collections.Generic.IList? GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing) { throw null; } } } diff --git a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netstandard2.0.cs b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netstandard2.0.cs index dea13ee364..c606bf0a9c 100644 --- a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netstandard2.0.cs +++ b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netstandard2.0.cs @@ -13,7 +13,7 @@ namespace Microsoft.Extensions.Localization { public partial interface IResourceNamesCache { - System.Collections.Generic.IList GetOrAdd(string name, System.Func> valueFactory); + System.Collections.Generic.IList? GetOrAdd(string name, System.Func?> valueFactory); } public partial class LocalizationOptions { @@ -35,7 +35,7 @@ namespace Microsoft.Extensions.Localization public virtual Microsoft.Extensions.Localization.LocalizedString this[string name, params object[] arguments] { get { throw null; } } public virtual System.Collections.Generic.IEnumerable GetAllStrings(bool includeParentCultures) { throw null; } protected System.Collections.Generic.IEnumerable GetAllStrings(bool includeParentCultures, System.Globalization.CultureInfo culture) { throw null; } - protected string GetStringSafely(string name, System.Globalization.CultureInfo culture) { throw null; } + protected string? GetStringSafely(string name, System.Globalization.CultureInfo? culture) { throw null; } } public partial class ResourceManagerStringLocalizerFactory : Microsoft.Extensions.Localization.IStringLocalizerFactory { @@ -43,17 +43,17 @@ namespace Microsoft.Extensions.Localization public Microsoft.Extensions.Localization.IStringLocalizer Create(string baseName, string location) { throw null; } public Microsoft.Extensions.Localization.IStringLocalizer Create(System.Type resourceSource) { throw null; } protected virtual Microsoft.Extensions.Localization.ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(System.Reflection.Assembly assembly, string baseName) { throw null; } - protected virtual Microsoft.Extensions.Localization.ResourceLocationAttribute GetResourceLocationAttribute(System.Reflection.Assembly assembly) { throw null; } + protected virtual Microsoft.Extensions.Localization.ResourceLocationAttribute? GetResourceLocationAttribute(System.Reflection.Assembly assembly) { throw null; } protected virtual string GetResourcePrefix(System.Reflection.TypeInfo typeInfo) { throw null; } - protected virtual string GetResourcePrefix(System.Reflection.TypeInfo typeInfo, string baseNamespace, string resourcesRelativePath) { throw null; } + protected virtual string GetResourcePrefix(System.Reflection.TypeInfo typeInfo, string? baseNamespace, string? resourcesRelativePath) { throw null; } protected virtual string GetResourcePrefix(string baseResourceName, string baseNamespace) { throw null; } protected virtual string GetResourcePrefix(string location, string baseName, string resourceLocation) { throw null; } - protected virtual Microsoft.Extensions.Localization.RootNamespaceAttribute GetRootNamespaceAttribute(System.Reflection.Assembly assembly) { throw null; } + protected virtual Microsoft.Extensions.Localization.RootNamespaceAttribute? GetRootNamespaceAttribute(System.Reflection.Assembly assembly) { throw null; } } public partial class ResourceNamesCache : Microsoft.Extensions.Localization.IResourceNamesCache { public ResourceNamesCache() { } - public System.Collections.Generic.IList GetOrAdd(string name, System.Func> valueFactory) { throw null; } + public System.Collections.Generic.IList? GetOrAdd(string name, System.Func?> valueFactory) { throw null; } } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple=false, Inherited=false)] public partial class RootNamespaceAttribute : System.Attribute @@ -69,15 +69,15 @@ namespace Microsoft.Extensions.Localization.Internal public AssemblyWrapper(System.Reflection.Assembly assembly) { } public System.Reflection.Assembly Assembly { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public virtual string FullName { get { throw null; } } - public virtual System.IO.Stream GetManifestResourceStream(string name) { throw null; } + public virtual System.IO.Stream? GetManifestResourceStream(string name) { throw null; } } public partial interface IResourceStringProvider { - System.Collections.Generic.IList GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing); + System.Collections.Generic.IList? GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing); } public partial class ResourceManagerStringProvider : Microsoft.Extensions.Localization.Internal.IResourceStringProvider { public ResourceManagerStringProvider(Microsoft.Extensions.Localization.IResourceNamesCache resourceCache, System.Resources.ResourceManager resourceManager, System.Reflection.Assembly assembly, string baseName) { } - public System.Collections.Generic.IList GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing) { throw null; } + public System.Collections.Generic.IList? GetAllResourceStrings(System.Globalization.CultureInfo culture, bool throwOnMissing) { throw null; } } } diff --git a/src/Localization/Localization/src/IResourceNamesCache.cs b/src/Localization/Localization/src/IResourceNamesCache.cs index 90d104aa68..4f0995c9f1 100644 --- a/src/Localization/Localization/src/IResourceNamesCache.cs +++ b/src/Localization/Localization/src/IResourceNamesCache.cs @@ -17,6 +17,6 @@ namespace Microsoft.Extensions.Localization /// The resource name to add string names for. /// The function used to generate the string names for the resource. /// The string names for the resource. - IList GetOrAdd(string name, Func> valueFactory); + IList? GetOrAdd(string name, Func?> valueFactory); } } diff --git a/src/Localization/Localization/src/Internal/AssemblyWrapper.cs b/src/Localization/Localization/src/Internal/AssemblyWrapper.cs index 11e118e326..813d8717b1 100644 --- a/src/Localization/Localization/src/Internal/AssemblyWrapper.cs +++ b/src/Localization/Localization/src/Internal/AssemblyWrapper.cs @@ -25,8 +25,8 @@ namespace Microsoft.Extensions.Localization.Internal public Assembly Assembly { get; } - public virtual string FullName => Assembly.FullName; + public virtual string FullName => Assembly.FullName!; - public virtual Stream GetManifestResourceStream(string name) => Assembly.GetManifestResourceStream(name); + public virtual Stream? GetManifestResourceStream(string name) => Assembly.GetManifestResourceStream(name); } } diff --git a/src/Localization/Localization/src/Internal/IResourceStringProvider.cs b/src/Localization/Localization/src/Internal/IResourceStringProvider.cs index 157e8e976e..16df0065ac 100644 --- a/src/Localization/Localization/src/Internal/IResourceStringProvider.cs +++ b/src/Localization/Localization/src/Internal/IResourceStringProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; @@ -12,6 +12,6 @@ namespace Microsoft.Extensions.Localization.Internal /// public interface IResourceStringProvider { - IList GetAllResourceStrings(CultureInfo culture, bool throwOnMissing); + IList? GetAllResourceStrings(CultureInfo culture, bool throwOnMissing); } } diff --git a/src/Localization/Localization/src/Internal/ResourceManagerStringLocalizerLoggerExtensions.cs b/src/Localization/Localization/src/Internal/ResourceManagerStringLocalizerLoggerExtensions.cs index 63f40536ca..67d244f265 100644 --- a/src/Localization/Localization/src/Internal/ResourceManagerStringLocalizerLoggerExtensions.cs +++ b/src/Localization/Localization/src/Internal/ResourceManagerStringLocalizerLoggerExtensions.cs @@ -1,5 +1,5 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Globalization; @@ -9,7 +9,7 @@ namespace Microsoft.Extensions.Localization.Internal { internal static class ResourceManagerStringLocalizerLoggerExtensions { - private static readonly Action _searchedLocation; + private static readonly Action _searchedLocation; static ResourceManagerStringLocalizerLoggerExtensions() { diff --git a/src/Localization/Localization/src/Internal/ResourceManagerStringProvider.cs b/src/Localization/Localization/src/Internal/ResourceManagerStringProvider.cs index 62250938c8..00850b1655 100644 --- a/src/Localization/Localization/src/Internal/ResourceManagerStringProvider.cs +++ b/src/Localization/Localization/src/Internal/ResourceManagerStringProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections; @@ -51,7 +51,7 @@ namespace Microsoft.Extensions.Localization.Internal return resourceStreamName; } - public IList GetAllResourceStrings(CultureInfo culture, bool throwOnMissing) + public IList? GetAllResourceStrings(CultureInfo culture, bool throwOnMissing) { var cacheKey = GetResourceCacheKey(culture); @@ -72,9 +72,12 @@ namespace Microsoft.Extensions.Localization.Internal } var names = new List(); - foreach (DictionaryEntry entry in resourceSet) + foreach (DictionaryEntry? entry in resourceSet) { - names.Add((string)entry.Key); + if (entry?.Key is string key) + { + names.Add(key); + } } return names; diff --git a/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj b/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj index c3ffbeb772..be1ebd7044 100644 --- a/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj +++ b/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj @@ -10,6 +10,7 @@ localization true true + enable diff --git a/src/Localization/Localization/src/ResourceManagerStringLocalizer.cs b/src/Localization/Localization/src/ResourceManagerStringLocalizer.cs index 0f033a5227..b1e9845a0c 100644 --- a/src/Localization/Localization/src/ResourceManagerStringLocalizer.cs +++ b/src/Localization/Localization/src/ResourceManagerStringLocalizer.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Reflection; using System.Resources; using Microsoft.Extensions.Localization.Internal; @@ -19,7 +20,7 @@ namespace Microsoft.Extensions.Localization /// This type is thread-safe. public class ResourceManagerStringLocalizer : IStringLocalizer { - private readonly ConcurrentDictionary _missingManifestCache = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _missingManifestCache = new ConcurrentDictionary(); private readonly IResourceNamesCache _resourceNamesCache; private readonly ResourceManager _resourceManager; private readonly IResourceStringProvider _resourceStringProvider; @@ -171,7 +172,7 @@ namespace Microsoft.Extensions.Localization ? GetResourceNamesFromCultureHierarchy(culture) : _resourceStringProvider.GetAllResourceStrings(culture, true); - foreach (var name in resourceNames) + foreach (var name in resourceNames ?? Enumerable.Empty()) { var value = GetStringSafely(name, culture); yield return new LocalizedString(name, value ?? name, resourceNotFound: value == null, searchedLocation: _resourceBaseName); @@ -185,7 +186,7 @@ namespace Microsoft.Extensions.Localization /// The name of the string resource. /// The to get the string for. /// The resource string, or null if none was found. - protected string GetStringSafely(string name, CultureInfo culture) + protected string? GetStringSafely(string name, CultureInfo? culture) { if (name == null) { diff --git a/src/Localization/Localization/src/ResourceManagerStringLocalizerFactory.cs b/src/Localization/Localization/src/ResourceManagerStringLocalizerFactory.cs index a525f72368..34d5f34659 100644 --- a/src/Localization/Localization/src/ResourceManagerStringLocalizerFactory.cs +++ b/src/Localization/Localization/src/ResourceManagerStringLocalizerFactory.cs @@ -82,7 +82,7 @@ namespace Microsoft.Extensions.Localization /// For the type "Sample.Controllers.Home" if there's a resourceRelativePath return /// "Sample.Resourcepath.Controllers.Home" if there isn't one then it would return "Sample.Controllers.Home". /// - protected virtual string GetResourcePrefix(TypeInfo typeInfo, string baseNamespace, string resourcesRelativePath) + protected virtual string GetResourcePrefix(TypeInfo typeInfo, string? baseNamespace, string? resourcesRelativePath) { if (typeInfo == null) { @@ -94,6 +94,11 @@ namespace Microsoft.Extensions.Localization throw new ArgumentNullException(nameof(baseNamespace)); } + if (string.IsNullOrEmpty(typeInfo.FullName)) + { + throw new ArgumentException(Resources.FormatLocalization_TypeMustHaveTypeName(typeInfo)); + } + if (string.IsNullOrEmpty(resourcesRelativePath)) { return typeInfo.FullName; @@ -219,7 +224,7 @@ namespace Microsoft.Extensions.Localization /// The assembly to get a from. /// The associated with the given . /// This method is protected and virtual for testing purposes only. - protected virtual ResourceLocationAttribute GetResourceLocationAttribute(Assembly assembly) + protected virtual ResourceLocationAttribute? GetResourceLocationAttribute(Assembly assembly) { return assembly.GetCustomAttribute(); } @@ -228,17 +233,21 @@ namespace Microsoft.Extensions.Localization /// The assembly to get a from. /// The associated with the given . /// This method is protected and virtual for testing purposes only. - protected virtual RootNamespaceAttribute GetRootNamespaceAttribute(Assembly assembly) + protected virtual RootNamespaceAttribute? GetRootNamespaceAttribute(Assembly assembly) { return assembly.GetCustomAttribute(); } - private string GetRootNamespace(Assembly assembly) + private string? GetRootNamespace(Assembly assembly) { var rootNamespaceAttribute = GetRootNamespaceAttribute(assembly); - return rootNamespaceAttribute?.RootNamespace ?? - new AssemblyName(assembly.FullName).Name; + if (rootNamespaceAttribute != null) + { + return rootNamespaceAttribute.RootNamespace; + } + + return assembly.GetName().Name; } private string GetResourcePath(Assembly assembly) @@ -256,7 +265,7 @@ namespace Microsoft.Extensions.Localization return resourceLocation; } - private static string TrimPrefix(string name, string prefix) + private static string? TrimPrefix(string name, string prefix) { if (name.StartsWith(prefix, StringComparison.Ordinal)) { diff --git a/src/Localization/Localization/src/ResourceNamesCache.cs b/src/Localization/Localization/src/ResourceNamesCache.cs index 72b7986d9f..de3f0f5bc6 100644 --- a/src/Localization/Localization/src/ResourceNamesCache.cs +++ b/src/Localization/Localization/src/ResourceNamesCache.cs @@ -12,7 +12,7 @@ namespace Microsoft.Extensions.Localization /// public class ResourceNamesCache : IResourceNamesCache { - private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>(); + private readonly ConcurrentDictionary?> _cache = new ConcurrentDictionary?>(); /// /// Creates a new @@ -22,7 +22,7 @@ namespace Microsoft.Extensions.Localization } /// - public IList GetOrAdd(string name, Func> valueFactory) + public IList? GetOrAdd(string name, Func?> valueFactory) { return _cache.GetOrAdd(name, valueFactory); } diff --git a/src/Localization/Localization/src/Resources.resx b/src/Localization/Localization/src/Resources.resx index b679f04664..dad5018260 100644 --- a/src/Localization/Localization/src/Resources.resx +++ b/src/Localization/Localization/src/Resources.resx @@ -123,4 +123,7 @@ No manifests exist for the current culture. + + Type '{0}' must have a non-null type name. + \ No newline at end of file diff --git a/src/Localization/Localization/test/Microsoft.Extensions.Localization.RootNamespace.Tests/Microsoft.Extensions.Localization.RootNamespace.Tests.csproj b/src/Localization/Localization/test/Microsoft.Extensions.Localization.RootNamespace.Tests/Microsoft.Extensions.Localization.RootNamespace.Tests.csproj index c81af4416d..29d2e8f504 100644 --- a/src/Localization/Localization/test/Microsoft.Extensions.Localization.RootNamespace.Tests/Microsoft.Extensions.Localization.RootNamespace.Tests.csproj +++ b/src/Localization/Localization/test/Microsoft.Extensions.Localization.RootNamespace.Tests/Microsoft.Extensions.Localization.RootNamespace.Tests.csproj @@ -2,6 +2,7 @@ $(DefaultNetCoreTargetFramework);net472 LocalizationTest.Abc + enable diff --git a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/Microsoft.Extensions.Localization.Tests.csproj b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/Microsoft.Extensions.Localization.Tests.csproj index 4599766c21..508310f142 100644 --- a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/Microsoft.Extensions.Localization.Tests.csproj +++ b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/Microsoft.Extensions.Localization.Tests.csproj @@ -2,6 +2,7 @@ $(DefaultNetCoreTargetFramework);net472 + enable diff --git a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerFactoryTest.cs b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerFactoryTest.cs index 86f6e15ccd..12af15805f 100644 --- a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerFactoryTest.cs +++ b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerFactoryTest.cs @@ -1,6 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#nullable disable using System; using System.IO; using System.Reflection; @@ -84,7 +85,7 @@ namespace Microsoft.Extensions.Localization.Tests // Assert Assert.Equal(typeFactory.BaseName, stringFactory.BaseName); - Assert.Equal(typeFactory.Assembly.FullName, stringFactory.Assembly.FullName); + Assert.Equal(typeFactory.Assembly!.FullName, stringFactory.Assembly!.FullName); } [Fact] @@ -293,7 +294,7 @@ namespace Microsoft.Extensions.Localization.Tests var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object, loggerFactory: loggerFactory); // Act & Assert - Assert.Throws(() => factory.Create("baseName", location: null)); + Assert.Throws(() => factory.Create("baseName", location: null!)); } } } diff --git a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs index a82ce9d1d3..a2bd1ed7c1 100644 --- a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs +++ b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs @@ -249,9 +249,9 @@ namespace Microsoft.Extensions.Localization _assemblyWrapper = assemblyWrapper; } - public override string GetString(string name, CultureInfo culture) => null; + public override string? GetString(string name, CultureInfo? culture) => null; - public override ResourceSet GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents) + public override ResourceSet? GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents) { var resourceStream = _assemblyWrapper.GetManifestResourceStream(BaseName); @@ -287,7 +287,7 @@ namespace Microsoft.Extensions.Localization public int ManifestResourceStreamCallCount { get; private set; } - public override Stream GetManifestResourceStream(string name) + public override Stream? GetManifestResourceStream(string name) { ManifestResourceStreamCallCount++; diff --git a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/StringLocalizerOfTTest.cs b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/StringLocalizerOfTTest.cs index 53d290064e..50da5d0aca 100644 --- a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/StringLocalizerOfTTest.cs +++ b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests/StringLocalizerOfTTest.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Globalization; using Moq; using Xunit; @@ -15,7 +14,7 @@ namespace Microsoft.Extensions.Localization { // Arrange, act and assert var exception = Assert.Throws( - () => new StringLocalizer(factory: null)); + () => new StringLocalizer(factory: null!)); Assert.Equal("factory", exception.ParamName); } @@ -45,7 +44,7 @@ namespace Microsoft.Extensions.Localization var localizer = new StringLocalizer(factory.Object); // Act and assert - var exception = Assert.Throws(() => localizer[name: null]); + var exception = Assert.Throws(() => localizer[name: null!]); Assert.Equal("name", exception.ParamName); } @@ -80,7 +79,7 @@ namespace Microsoft.Extensions.Localization var localizer = new StringLocalizer(factory.Object); // Act and assert - var exception = Assert.Throws(() => localizer[name: null]); + var exception = Assert.Throws(() => localizer[name: null!]); Assert.Equal("name", exception.ParamName); } diff --git a/src/Shared/Nullable/NullableAttributes.cs b/src/Shared/Nullable/NullableAttributes.cs new file mode 100644 index 0000000000..936ee5832c --- /dev/null +++ b/src/Shared/Nullable/NullableAttributes.cs @@ -0,0 +1,196 @@ +// 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. +// From https://github.com/dotnet/runtime/blob/ef72b95937703e485fdbbb75f3251fedfd1a0ef9/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class AllowNullAttribute : Attribute { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DisallowNullAttribute : Attribute { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullAttribute : Attribute { } + + /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnAttribute : Attribute { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } +} \ No newline at end of file