diff --git a/src/Http/Headers/src/BaseHeaderParser.cs b/src/Http/Headers/src/BaseHeaderParser.cs index f3caaafb706c..851f27e1e756 100644 --- a/src/Http/Headers/src/BaseHeaderParser.cs +++ b/src/Http/Headers/src/BaseHeaderParser.cs @@ -1,6 +1,7 @@ // 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.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Headers @@ -14,9 +15,9 @@ protected BaseHeaderParser(bool supportsMultipleValues) protected abstract int GetParsedValueLength(StringSegment value, int startIndex, out T parsedValue); - public sealed override bool TryParseValue(StringSegment value, ref int index, out T parsedValue) + public sealed override bool TryParseValue(StringSegment value, ref int index, [MaybeNullWhen(false)]out T parsedValue) { - parsedValue = default(T); + parsedValue = default(T)!; // If multiple values are supported (i.e. list of values), then accept an empty string: The header may // be added multiple times to the request/response message. E.g. diff --git a/src/Http/Headers/src/CacheControlHeaderValue.cs b/src/Http/Headers/src/CacheControlHeaderValue.cs index cee7f8b8c1ce..81ff69a68e13 100644 --- a/src/Http/Headers/src/CacheControlHeaderValue.cs +++ b/src/Http/Headers/src/CacheControlHeaderValue.cs @@ -31,12 +31,12 @@ public class CacheControlHeaderValue // Cache-Control headers, only one instance of CacheControlHeaderValue is created (if all headers contain valid // values, otherwise we may have multiple strings containing the invalid values). private static readonly HttpHeaderParser Parser - = new GenericHeaderParser(true, GetCacheControlLength); + = new GenericHeaderParser(true, GetCacheControlLength!); private static readonly Action CheckIsValidTokenAction = CheckIsValidToken; private bool _noCache; - private ICollection _noCacheHeaders; + private ICollection? _noCacheHeaders; private bool _noStore; private TimeSpan? _maxAge; private TimeSpan? _sharedMaxAge; @@ -47,10 +47,10 @@ private static readonly HttpHeaderParser Parser private bool _onlyIfCached; private bool _public; private bool _private; - private ICollection _privateHeaders; + private ICollection? _privateHeaders; private bool _mustRevalidate; private bool _proxyRevalidate; - private IList _extensions; + private IList? _extensions; public CacheControlHeaderValue() { @@ -240,7 +240,7 @@ public override string ToString() return sb.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as CacheControlHeaderValue; @@ -335,7 +335,7 @@ public static CacheControlHeaderValue Parse(StringSegment input) return result; } - public static bool TryParse(StringSegment input, out CacheControlHeaderValue parsedValue) + public static bool TryParse(StringSegment input, out CacheControlHeaderValue? parsedValue) { int index = 0; // Cache-Control is unusual because there are no required values so the parser will succeed for an empty string, but still return null. @@ -347,7 +347,7 @@ public static bool TryParse(StringSegment input, out CacheControlHeaderValue par return false; } - private static int GetCacheControlLength(StringSegment input, int startIndex, out CacheControlHeaderValue parsedValue) + private static int GetCacheControlLength(StringSegment input, int startIndex, out CacheControlHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); @@ -361,11 +361,10 @@ private static int GetCacheControlLength(StringSegment input, int startIndex, ou // Cache-Control header consists of a list of name/value pairs, where the value is optional. So use an // instance of NameValueHeaderParser to parse the string. var current = startIndex; - NameValueHeaderValue nameValue = null; var nameValueList = new List(); while (current < input.Length) { - if (!NameValueHeaderValue.MultipleValueParser.TryParseValue(input, ref current, out nameValue)) + if (!NameValueHeaderValue.MultipleValueParser.TryParseValue(input, ref current, out var nameValue)) { return 0; } @@ -539,11 +538,11 @@ private static bool TrySetTokenOnlyValue(NameValueHeaderValue nameValue, ref boo private static bool TrySetOptionalTokenList( NameValueHeaderValue nameValue, ref bool boolField, - ref ICollection destination) + ref ICollection? destination) { Contract.Requires(nameValue != null); - if (nameValue.Value == null) + if (nameValue!.Value == null) { boolField = true; return true; @@ -605,7 +604,7 @@ private static bool TrySetTimeSpan(NameValueHeaderValue nameValue, ref TimeSpan? { Contract.Requires(nameValue != null); - if (nameValue.Value == null) + if (nameValue!.Value == null) { return false; } diff --git a/src/Http/Headers/src/ContentDispositionHeaderValue.cs b/src/Http/Headers/src/ContentDispositionHeaderValue.cs index cb868ce8973d..0935db40f539 100644 --- a/src/Http/Headers/src/ContentDispositionHeaderValue.cs +++ b/src/Http/Headers/src/ContentDispositionHeaderValue.cs @@ -4,6 +4,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; @@ -26,10 +27,10 @@ public class ContentDispositionHeaderValue private static readonly char[] SingleQuote = new char[] { '\'' }; private static readonly HttpHeaderParser Parser - = new GenericHeaderParser(false, GetDispositionTypeLength); + = new GenericHeaderParser(false, GetDispositionTypeLength!); // Use list instead of dictionary since we may have multiple parameters with the same name. - private ObjectCollection _parameters; + private ObjectCollection? _parameters; private StringSegment _dispositionType; private ContentDispositionHeaderValue() @@ -128,7 +129,7 @@ public long? Size // Remove parameter if (sizeParameter != null) { - _parameters.Remove(sizeParameter); + _parameters!.Remove(sizeParameter); } } else if (value < 0) @@ -142,7 +143,7 @@ public long? Size else { string sizeString = value.GetValueOrDefault().ToString(CultureInfo.InvariantCulture); - _parameters.Add(new NameValueHeaderValue(SizeString, sizeString)); + _parameters!.Add(new NameValueHeaderValue(SizeString, sizeString)); } } } @@ -180,7 +181,7 @@ public override string ToString() return _dispositionType + NameValueHeaderValue.ToString(_parameters, ';', true); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as ContentDispositionHeaderValue; @@ -205,13 +206,13 @@ public static ContentDispositionHeaderValue Parse(StringSegment input) return Parser.ParseValue(input, ref index); } - public static bool TryParse(StringSegment input, out ContentDispositionHeaderValue parsedValue) + public static bool TryParse(StringSegment input, [NotNullWhen(true)]out ContentDispositionHeaderValue? parsedValue) { var index = 0; return Parser.TryParseValue(input, ref index, out parsedValue); } - private static int GetDispositionTypeLength(StringSegment input, int startIndex, out ContentDispositionHeaderValue parsedValue) + private static int GetDispositionTypeLength(StringSegment input, int startIndex, out ContentDispositionHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); @@ -318,7 +319,7 @@ private void SetDate(string parameter, DateTimeOffset? date) // Remove parameter if (dateParameter != null) { - _parameters.Remove(dateParameter); + _parameters!.Remove(dateParameter); } } else @@ -343,7 +344,7 @@ private StringSegment GetName(string parameter) var nameParameter = NameValueHeaderValue.Find(_parameters, parameter); if (nameParameter != null) { - string result; + string? result; // filename*=utf-8'lang'%7FMyString if (parameter.EndsWith("*", StringComparison.Ordinal)) { @@ -375,7 +376,7 @@ private void SetName(StringSegment parameter, StringSegment value) // Remove parameter if (nameParameter != null) { - _parameters.Remove(nameParameter); + _parameters!.Remove(nameParameter); } } else @@ -497,7 +498,7 @@ private unsafe string EncodeMime(StringSegment input) } // Attempt to decode MIME encoded strings - private bool TryDecodeMime(StringSegment input, out string output) + private bool TryDecodeMime(StringSegment input, [NotNullWhen(true)]out string? output) { Contract.Assert(input != null); @@ -582,7 +583,7 @@ private static void HexEscape(StringBuilder builder, char c) // Attempt to decode using RFC 5987 encoding. // encoding'language'my%20string - private bool TryDecode5987(StringSegment input, out string output) + private bool TryDecode5987(StringSegment input, [NotNullWhen(true)]out string? output) { output = null; @@ -593,7 +594,7 @@ private bool TryDecode5987(StringSegment input, out string output) } var decoded = new StringBuilder(); - byte[] unescapedBytes = null; + byte[]? unescapedBytes = null; try { var encoding = Encoding.GetEncoding(parts[0].ToString()); diff --git a/src/Http/Headers/src/ContentRangeHeaderValue.cs b/src/Http/Headers/src/ContentRangeHeaderValue.cs index 99723864f390..bec47fc60b82 100644 --- a/src/Http/Headers/src/ContentRangeHeaderValue.cs +++ b/src/Http/Headers/src/ContentRangeHeaderValue.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.Text; @@ -12,7 +13,7 @@ namespace Microsoft.Net.Http.Headers public class ContentRangeHeaderValue { private static readonly HttpHeaderParser Parser - = new GenericHeaderParser(false, GetContentRangeLength); + = new GenericHeaderParser(false, GetContentRangeLength!); private StringSegment _unit; private long? _from; @@ -113,7 +114,7 @@ public long? Length get { return _from != null; } } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as ContentRangeHeaderValue; @@ -185,7 +186,7 @@ public static bool TryParse(StringSegment input, out ContentRangeHeaderValue par return Parser.TryParseValue(input, ref index, out parsedValue); } - private static int GetContentRangeLength(StringSegment input, int startIndex, out ContentRangeHeaderValue parsedValue) + private static int GetContentRangeLength(StringSegment input, int startIndex, out ContentRangeHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); @@ -351,7 +352,7 @@ private static bool TryCreateContentRange( int toLength, int lengthStartIndex, int lengthLength, - out ContentRangeHeaderValue parsedValue) + [NotNullWhen(true)]out ContentRangeHeaderValue? parsedValue) { parsedValue = null; diff --git a/src/Http/Headers/src/CookieHeaderParser.cs b/src/Http/Headers/src/CookieHeaderParser.cs index 7201ae21a18d..e47198ef0d58 100644 --- a/src/Http/Headers/src/CookieHeaderParser.cs +++ b/src/Http/Headers/src/CookieHeaderParser.cs @@ -1,6 +1,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using Microsoft.Extensions.Primitives; @@ -13,7 +14,9 @@ internal CookieHeaderParser(bool supportsMultipleValues) { } - public override bool TryParseValue(StringSegment value, ref int index, out CookieHeaderValue parsedValue) +#pragma warning disable CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. + public override bool TryParseValue(StringSegment value, ref int index, [NotNullWhen(true)]out CookieHeaderValue? parsedValue) +#pragma warning restore CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. { parsedValue = null; @@ -43,7 +46,7 @@ public override bool TryParseValue(StringSegment value, ref int index, out Cooki return SupportsMultipleValues; } - CookieHeaderValue result = null; + CookieHeaderValue? result = null; if (!CookieHeaderValue.TryGetCookieLength(value, ref current, out result)) { return false; diff --git a/src/Http/Headers/src/CookieHeaderValue.cs b/src/Http/Headers/src/CookieHeaderValue.cs index 54753d2830b4..878b01742f96 100644 --- a/src/Http/Headers/src/CookieHeaderValue.cs +++ b/src/Http/Headers/src/CookieHeaderValue.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Text; using Microsoft.Extensions.Primitives; @@ -86,7 +87,7 @@ public static CookieHeaderValue Parse(StringSegment input) return SingleValueParser.ParseValue(input, ref index); } - public static bool TryParse(StringSegment input, out CookieHeaderValue parsedValue) + public static bool TryParse(StringSegment input, [NotNullWhen(true)]out CookieHeaderValue? parsedValue) { var index = 0; return SingleValueParser.TryParseValue(input, ref index, out parsedValue); @@ -102,18 +103,18 @@ public static IList ParseStrictList(IList inputs) return MultipleValueParser.ParseStrictValues(inputs); } - public static bool TryParseList(IList inputs, out IList parsedValues) + public static bool TryParseList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseValues(inputs, out parsedValues); } - public static bool TryParseStrictList(IList inputs, out IList parsedValues) + public static bool TryParseStrictList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues); } // name=value; name="value" - internal static bool TryGetCookieLength(StringSegment input, ref int offset, out CookieHeaderValue parsedValue) + internal static bool TryGetCookieLength(StringSegment input, ref int offset, [NotNullWhen(true)]out CookieHeaderValue? parsedValue) { Contract.Requires(offset >= 0); @@ -256,7 +257,7 @@ internal static void CheckValueFormat(StringSegment value, string parameterName) } } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as CookieHeaderValue; diff --git a/src/Http/Headers/src/EntityTagHeaderValue.cs b/src/Http/Headers/src/EntityTagHeaderValue.cs index 9b3a37136b49..fe903a065214 100644 --- a/src/Http/Headers/src/EntityTagHeaderValue.cs +++ b/src/Http/Headers/src/EntityTagHeaderValue.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using Microsoft.Extensions.Primitives; @@ -13,15 +14,15 @@ public class EntityTagHeaderValue // Note that the ETag header does not allow a * but we're not that strict: We allow both '*' and ETag values in a single value. // We can't guarantee that a single parsed value will be used directly in an ETag header. private static readonly HttpHeaderParser SingleValueParser - = new GenericHeaderParser(false, GetEntityTagLength); + = new GenericHeaderParser(false, GetEntityTagLength!); // Note that if multiple ETag values are allowed (e.g. 'If-Match', 'If-None-Match'), according to the RFC // the value must either be '*' or a list of ETag values. It's not allowed to have both '*' and a list of // ETag values. We're not that strict: We allow both '*' and ETag values in a list. If the server sends such // an invalid list, we want to be able to represent it using the corresponding header property. private static readonly HttpHeaderParser MultipleValueParser - = new GenericHeaderParser(true, GetEntityTagLength); + = new GenericHeaderParser(true, GetEntityTagLength!); - private static EntityTagHeaderValue AnyType; + private static EntityTagHeaderValue? AnyType; private StringSegment _tag; private bool _isWeak; @@ -103,7 +104,7 @@ public override string ToString() /// true if the strength and tag of the two values match, /// false if the other value is null, is not an , or if there is a mismatch of strength or tag between the two values. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as EntityTagHeaderValue; @@ -170,17 +171,17 @@ public static IList ParseStrictList(IList inputs) return MultipleValueParser.ParseStrictValues(inputs); } - public static bool TryParseList(IList inputs, out IList parsedValues) + public static bool TryParseList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseValues(inputs, out parsedValues); } - public static bool TryParseStrictList(IList inputs, out IList parsedValues) + public static bool TryParseStrictList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues); } - internal static int GetEntityTagLength(StringSegment input, int startIndex, out EntityTagHeaderValue parsedValue) + internal static int GetEntityTagLength(StringSegment input, int startIndex, out EntityTagHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); diff --git a/src/Http/Headers/src/GenericHeaderParser.cs b/src/Http/Headers/src/GenericHeaderParser.cs index a2fbf720f9f7..57c493e5063b 100644 --- a/src/Http/Headers/src/GenericHeaderParser.cs +++ b/src/Http/Headers/src/GenericHeaderParser.cs @@ -2,13 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Headers { internal sealed class GenericHeaderParser : BaseHeaderParser { - internal delegate int GetParsedValueLengthDelegate(StringSegment value, int startIndex, out T parsedValue); + internal delegate int GetParsedValueLengthDelegate(StringSegment value, int startIndex, [MaybeNull]out T parsedValue); private GetParsedValueLengthDelegate _getParsedValueLength; diff --git a/src/Http/Headers/src/HeaderUtilities.cs b/src/Http/Headers/src/HeaderUtilities.cs index ff5bb5400c6f..1f01afa61620 100644 --- a/src/Http/Headers/src/HeaderUtilities.cs +++ b/src/Http/Headers/src/HeaderUtilities.cs @@ -41,7 +41,7 @@ internal static void SetQuality(IList parameters, double? } else { - parameters.Add(new NameValueHeaderValue(QualityName, qualityString)); + parameters!.Add(new NameValueHeaderValue(QualityName, qualityString)); } } else @@ -49,7 +49,7 @@ internal static void SetQuality(IList parameters, double? // Remove quality parameter if (qualityParameter != null) { - parameters.Remove(qualityParameter); + parameters!.Remove(qualityParameter); } } } @@ -85,12 +85,12 @@ internal static void CheckValidToken(StringSegment value, string parameterName) } } - internal static bool AreEqualCollections(ICollection x, ICollection y) + internal static bool AreEqualCollections(ICollection? x, ICollection? y) { return AreEqualCollections(x, y, null); } - internal static bool AreEqualCollections(ICollection x, ICollection y, IEqualityComparer comparer) + internal static bool AreEqualCollections(ICollection? x, ICollection? y, IEqualityComparer? comparer) { if (x == null) { diff --git a/src/Http/Headers/src/HttpHeaderParser.cs b/src/Http/Headers/src/HttpHeaderParser.cs index 027a9de43840..a6df791ee82c 100644 --- a/src/Http/Headers/src/HttpHeaderParser.cs +++ b/src/Http/Headers/src/HttpHeaderParser.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using Microsoft.Extensions.Primitives; @@ -27,7 +28,7 @@ public bool SupportsMultipleValues // pointing to the next non-whitespace character after a delimiter. E.g. if called with a start index of 0 // for string "value , second_value", then after the call completes, 'index' must point to 's', i.e. the first // non-whitespace after the separator ','. - public abstract bool TryParseValue(StringSegment value, ref int index, out T parsedValue); + public abstract bool TryParseValue(StringSegment value, ref int index, [NotNullWhen(true)]out T parsedValue); public T ParseValue(StringSegment value, ref int index) { @@ -46,23 +47,23 @@ public T ParseValue(StringSegment value, ref int index) return result; } - public virtual bool TryParseValues(IList values, out IList parsedValues) + public virtual bool TryParseValues(IList values, [NotNullWhen(true)]out IList? parsedValues) { return TryParseValues(values, strict: false, parsedValues: out parsedValues); } - public virtual bool TryParseStrictValues(IList values, out IList parsedValues) + public virtual bool TryParseStrictValues(IList values, [NotNullWhen(true)]out IList? parsedValues) { return TryParseValues(values, strict: true, parsedValues: out parsedValues); } - protected virtual bool TryParseValues(IList values, bool strict, out IList parsedValues) + protected virtual bool TryParseValues(IList values, bool strict, [NotNullWhen(true)]out IList? parsedValues) { Contract.Assert(_supportsMultipleValues); // If a parser returns an empty list, it means there was no value, but that's valid (e.g. "Accept: "). The caller // can ignore the value. parsedValues = null; - List results = null; + List? results = null; if (values == null) { return false; @@ -166,7 +167,7 @@ public virtual string ToString(object value) { Contract.Requires(value != null); - return value.ToString(); + return value!.ToString()!; } } } diff --git a/src/Http/Headers/src/MediaTypeHeaderValue.cs b/src/Http/Headers/src/MediaTypeHeaderValue.cs index a7a39c904e5b..5674b12d3f5b 100644 --- a/src/Http/Headers/src/MediaTypeHeaderValue.cs +++ b/src/Http/Headers/src/MediaTypeHeaderValue.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; @@ -29,12 +30,12 @@ public class MediaTypeHeaderValue private static readonly char[] PeriodCharacterArray = new char[] { PeriodCharacter }; private static readonly HttpHeaderParser SingleValueParser - = new GenericHeaderParser(false, GetMediaTypeLength); + = new GenericHeaderParser(false, GetMediaTypeLength!); private static readonly HttpHeaderParser MultipleValueParser - = new GenericHeaderParser(true, GetMediaTypeLength); + = new GenericHeaderParser(true, GetMediaTypeLength!); // Use a collection instead of a dictionary since we may have multiple parameters with the same name. - private ObjectCollection _parameters; + private ObjectCollection? _parameters; private StringSegment _mediaType; private bool _isReadOnly; @@ -108,7 +109,7 @@ public StringSegment Charset /// Gets or sets the value of the Encoding parameter. Setting the Encoding will set /// the to . /// - public Encoding Encoding + public Encoding? Encoding { get { @@ -205,7 +206,7 @@ public IList Parameters /// public double? Quality { - get { return HeaderUtilities.GetQuality(_parameters); } + get { return HeaderUtilities.GetQuality(Parameters); } set { HeaderUtilities.ThrowIfReadOnly(IsReadOnly); @@ -444,7 +445,7 @@ public override string ToString() return builder.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as MediaTypeHeaderValue; @@ -513,7 +514,7 @@ public static IList ParseStrictList(IList inputs) /// A list of media types /// The parsed . /// True if the value was successfully parsed. - public static bool TryParseList(IList inputs, out IList parsedValues) + public static bool TryParseList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseValues(inputs, out parsedValues); } @@ -524,12 +525,12 @@ public static bool TryParseList(IList inputs, out IListA list of media types /// The parsed . /// True if the value was successfully parsed. - public static bool TryParseStrictList(IList inputs, out IList parsedValues) + public static bool TryParseStrictList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues); } - private static int GetMediaTypeLength(StringSegment input, int startIndex, out MediaTypeHeaderValue parsedValue) + private static int GetMediaTypeLength(StringSegment input, int startIndex, out MediaTypeHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); @@ -550,7 +551,7 @@ private static int GetMediaTypeLength(StringSegment input, int startIndex, out M var current = startIndex + mediaTypeLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); - MediaTypeHeaderValue mediaTypeHeader = null; + MediaTypeHeaderValue? mediaTypeHeader = null; // If we're not done and we have a parameter delimiter, then we have a list of parameters. if ((current < input.Length) && (input[current] == ';')) diff --git a/src/Http/Headers/src/Microsoft.Net.Http.Headers.csproj b/src/Http/Headers/src/Microsoft.Net.Http.Headers.csproj index 96cadd39d535..346969928fe8 100644 --- a/src/Http/Headers/src/Microsoft.Net.Http.Headers.csproj +++ b/src/Http/Headers/src/Microsoft.Net.Http.Headers.csproj @@ -9,6 +9,7 @@ true http false + enable diff --git a/src/Http/Headers/src/NameValueHeaderValue.cs b/src/Http/Headers/src/NameValueHeaderValue.cs index 58d337d55af6..83f1de1e73cc 100644 --- a/src/Http/Headers/src/NameValueHeaderValue.cs +++ b/src/Http/Headers/src/NameValueHeaderValue.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.Text; @@ -16,9 +17,9 @@ namespace Microsoft.Net.Http.Headers public class NameValueHeaderValue { private static readonly HttpHeaderParser SingleValueParser - = new GenericHeaderParser(false, GetNameValueLength); + = new GenericHeaderParser(false, GetNameValueLength!); internal static readonly HttpHeaderParser MultipleValueParser - = new GenericHeaderParser(true, GetNameValueLength); + = new GenericHeaderParser(true, GetNameValueLength!); private StringSegment _name; private StringSegment _value; @@ -109,7 +110,7 @@ public override int GetHashCode() return nameHashCode; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as NameValueHeaderValue; @@ -171,7 +172,7 @@ public static NameValueHeaderValue Parse(StringSegment input) return SingleValueParser.ParseValue(input, ref index); } - public static bool TryParse(StringSegment input, out NameValueHeaderValue parsedValue) + public static bool TryParse(StringSegment input, [NotNullWhen(true)]out NameValueHeaderValue? parsedValue) { var index = 0; return SingleValueParser.TryParseValue(input, ref index, out parsedValue); @@ -187,12 +188,12 @@ public static IList ParseStrictList(IList input) return MultipleValueParser.ParseStrictValues(input); } - public static bool TryParseList(IList input, out IList parsedValues) + public static bool TryParseList(IList input, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseValues(input, out parsedValues); } - public static bool TryParseStrictList(IList input, out IList parsedValues) + public static bool TryParseStrictList(IList input, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseStrictValues(input, out parsedValues); } @@ -207,7 +208,7 @@ public override string ToString() } internal static void ToString( - IList values, + IList? values, char separator, bool leadingSeparator, StringBuilder destination) @@ -235,7 +236,7 @@ internal static void ToString( } } - internal static string ToString(IList values, char separator, bool leadingSeparator) + internal static string? ToString(IList? values, char separator, bool leadingSeparator) { if ((values == null) || (values.Count == 0)) { @@ -249,7 +250,7 @@ internal static string ToString(IList values, char separat return sb.ToString(); } - internal static int GetHashCode(IList values) + internal static int GetHashCode(IList? values) { if ((values == null) || (values.Count == 0)) { @@ -264,7 +265,7 @@ internal static int GetHashCode(IList values) return result; } - private static int GetNameValueLength(StringSegment input, int startIndex, out NameValueHeaderValue parsedValue) + private static int GetNameValueLength(StringSegment input, int startIndex, out NameValueHeaderValue? parsedValue) { Contract.Requires(input != null); Contract.Requires(startIndex >= 0); @@ -334,8 +335,7 @@ internal static int GetNameValueListLength( var current = startIndex + HttpRuleParser.GetWhitespaceLength(input, startIndex); while (true) { - NameValueHeaderValue parameter = null; - var nameValueLength = GetNameValueLength(input, current, out parameter); + var nameValueLength = GetNameValueLength(input, current, out var parameter); if (nameValueLength == 0) { @@ -343,7 +343,7 @@ internal static int GetNameValueListLength( return current - startIndex; } - nameValueCollection.Add(parameter); + nameValueCollection!.Add(parameter!); current = current + nameValueLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); @@ -359,7 +359,7 @@ internal static int GetNameValueListLength( } } - public static NameValueHeaderValue Find(IList values, StringSegment name) + public static NameValueHeaderValue? Find(IList? values, StringSegment name) { Contract.Requires((name != null) && (name.Length > 0)); diff --git a/src/Http/Headers/src/ObjectCollection.cs b/src/Http/Headers/src/ObjectCollection.cs index f46b2dd743b0..c322802440cf 100644 --- a/src/Http/Headers/src/ObjectCollection.cs +++ b/src/Http/Headers/src/ObjectCollection.cs @@ -21,7 +21,7 @@ internal static readonly ObjectCollection EmptyReadOnlyCollection // We need to create a 'read-only' inner list for Collection to do the right // thing. - private static IList CreateInnerList(bool isReadOnly, IEnumerable other = null) + private static IList CreateInnerList(bool isReadOnly, IEnumerable? other = null) { var list = other == null ? new List() : new List(other); if (isReadOnly) @@ -78,4 +78,4 @@ private static void CheckNotNull(T item) } } } -} \ No newline at end of file +} diff --git a/src/Http/Headers/src/RangeConditionHeaderValue.cs b/src/Http/Headers/src/RangeConditionHeaderValue.cs index b1d6513e2ee8..d7b48e084da8 100644 --- a/src/Http/Headers/src/RangeConditionHeaderValue.cs +++ b/src/Http/Headers/src/RangeConditionHeaderValue.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using Microsoft.Extensions.Primitives; @@ -10,10 +11,10 @@ namespace Microsoft.Net.Http.Headers public class RangeConditionHeaderValue { private static readonly HttpHeaderParser Parser - = new GenericHeaderParser(false, GetRangeConditionLength); + = new GenericHeaderParser(false, GetRangeConditionLength!); private DateTimeOffset? _lastModified; - private EntityTagHeaderValue _entityTag; + private EntityTagHeaderValue? _entityTag; private RangeConditionHeaderValue() { @@ -45,7 +46,7 @@ public DateTimeOffset? LastModified get { return _lastModified; } } - public EntityTagHeaderValue EntityTag + public EntityTagHeaderValue? EntityTag { get { return _entityTag; } } @@ -59,7 +60,7 @@ public override string ToString() return _entityTag.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as RangeConditionHeaderValue; @@ -92,13 +93,13 @@ public static RangeConditionHeaderValue Parse(StringSegment input) return Parser.ParseValue(input, ref index); } - public static bool TryParse(StringSegment input, out RangeConditionHeaderValue parsedValue) + public static bool TryParse(StringSegment input, [NotNullWhen(true)]out RangeConditionHeaderValue? parsedValue) { var index = 0; return Parser.TryParseValue(input, ref index, out parsedValue); } - private static int GetRangeConditionLength(StringSegment input, int startIndex, out RangeConditionHeaderValue parsedValue) + private static int GetRangeConditionLength(StringSegment input, int startIndex, out RangeConditionHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); @@ -114,7 +115,7 @@ private static int GetRangeConditionLength(StringSegment input, int startIndex, // Caller must remove leading whitespaces. DateTimeOffset date = DateTimeOffset.MinValue; - EntityTagHeaderValue entityTag = null; + EntityTagHeaderValue? entityTag = null; // Entity tags are quoted strings optionally preceded by "W/". By looking at the first two character we // can determine whether the string is en entity tag or a date. @@ -164,4 +165,4 @@ private static int GetRangeConditionLength(StringSegment input, int startIndex, return current - startIndex; } } -} \ No newline at end of file +} diff --git a/src/Http/Headers/src/RangeHeaderValue.cs b/src/Http/Headers/src/RangeHeaderValue.cs index 67d671267b60..58e46fea9060 100644 --- a/src/Http/Headers/src/RangeHeaderValue.cs +++ b/src/Http/Headers/src/RangeHeaderValue.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Text; using Microsoft.Extensions.Primitives; @@ -12,10 +13,10 @@ namespace Microsoft.Net.Http.Headers public class RangeHeaderValue { private static readonly HttpHeaderParser Parser - = new GenericHeaderParser(false, GetRangeLength); + = new GenericHeaderParser(false, GetRangeLength!); private StringSegment _unit; - private ICollection _ranges; + private ICollection? _ranges; public RangeHeaderValue() { @@ -77,7 +78,7 @@ public override string ToString() return sb.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as RangeHeaderValue; @@ -108,13 +109,13 @@ public static RangeHeaderValue Parse(StringSegment input) return Parser.ParseValue(input, ref index); } - public static bool TryParse(StringSegment input, out RangeHeaderValue parsedValue) + public static bool TryParse(StringSegment input, [NotNullWhen(true)]out RangeHeaderValue parsedValue) { var index = 0; return Parser.TryParseValue(input, ref index, out parsedValue); } - private static int GetRangeLength(StringSegment input, int startIndex, out RangeHeaderValue parsedValue) + private static int GetRangeLength(StringSegment input, int startIndex, out RangeHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); diff --git a/src/Http/Headers/src/RangeItemHeaderValue.cs b/src/Http/Headers/src/RangeItemHeaderValue.cs index 010f2da1e0ae..beedd710fd8b 100644 --- a/src/Http/Headers/src/RangeItemHeaderValue.cs +++ b/src/Http/Headers/src/RangeItemHeaderValue.cs @@ -61,7 +61,7 @@ public override string ToString() _to.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is RangeItemHeaderValue other) { @@ -93,7 +93,7 @@ internal static int GetRangeItemListLength( { Contract.Requires(rangeCollection != null); Contract.Requires(startIndex >= 0); - Contract.Ensures((Contract.Result() == 0) || (rangeCollection.Count > 0), + Contract.Ensures((Contract.Result() == 0) || (rangeCollection!.Count > 0), "If we can parse the string, then we expect to have at least one range item."); if ((StringSegment.IsNullOrEmpty(input)) || (startIndex >= input.Length)) @@ -111,7 +111,7 @@ internal static int GetRangeItemListLength( return 0; } - RangeItemHeaderValue range = null; + RangeItemHeaderValue? range = null; while (true) { var rangeLength = GetRangeItemLength(input, current, out range); @@ -121,7 +121,7 @@ internal static int GetRangeItemListLength( return 0; } - rangeCollection.Add(range); + rangeCollection!.Add(range!); current = current + rangeLength; current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, current, true, out separatorFound); @@ -140,7 +140,7 @@ internal static int GetRangeItemListLength( } } - internal static int GetRangeItemLength(StringSegment input, int startIndex, out RangeItemHeaderValue parsedValue) + internal static int GetRangeItemLength(StringSegment input, int startIndex, out RangeItemHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index cdf12381aa44..7553763b78ad 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Text; using Microsoft.Extensions.Primitives; @@ -31,9 +32,9 @@ public class SetCookieHeaderValue private const string ExpiresDateFormat = "r"; private static readonly HttpHeaderParser SingleValueParser - = new GenericHeaderParser(false, GetSetCookieLength); + = new GenericHeaderParser(false, GetSetCookieLength!); private static readonly HttpHeaderParser MultipleValueParser - = new GenericHeaderParser(true, GetSetCookieLength); + = new GenericHeaderParser(true, GetSetCookieLength!); private StringSegment _name; private StringSegment _value; @@ -103,8 +104,8 @@ public override string ToString() { var length = _name.Length + EqualsToken.Length + _value.Length; - string maxAge = null; - string sameSite = null; + string? maxAge = null; + string? sameSite = null; if (Expires.HasValue) { @@ -299,7 +300,7 @@ public static SetCookieHeaderValue Parse(StringSegment input) return SingleValueParser.ParseValue(input, ref index); } - public static bool TryParse(StringSegment input, out SetCookieHeaderValue parsedValue) + public static bool TryParse(StringSegment input, [NotNullWhen(true)]out SetCookieHeaderValue? parsedValue) { var index = 0; return SingleValueParser.TryParseValue(input, ref index, out parsedValue); @@ -315,18 +316,18 @@ public static IList ParseStrictList(IList inputs) return MultipleValueParser.ParseStrictValues(inputs); } - public static bool TryParseList(IList inputs, out IList parsedValues) + public static bool TryParseList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseValues(inputs, out parsedValues); } - public static bool TryParseStrictList(IList inputs, out IList parsedValues) + public static bool TryParseStrictList(IList inputs, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues); } // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax|None}; httponly - private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue parsedValue) + private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); var offset = startIndex; @@ -537,7 +538,7 @@ private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int o return result; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as SetCookieHeaderValue; diff --git a/src/Http/Headers/src/StringWithQualityHeaderValue.cs b/src/Http/Headers/src/StringWithQualityHeaderValue.cs index 153643b36156..c9cee9af7e44 100644 --- a/src/Http/Headers/src/StringWithQualityHeaderValue.cs +++ b/src/Http/Headers/src/StringWithQualityHeaderValue.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using Microsoft.Extensions.Primitives; @@ -12,9 +13,9 @@ namespace Microsoft.Net.Http.Headers public class StringWithQualityHeaderValue { private static readonly HttpHeaderParser SingleValueParser - = new GenericHeaderParser(false, GetStringWithQualityLength); + = new GenericHeaderParser(false, GetStringWithQualityLength!); private static readonly HttpHeaderParser MultipleValueParser - = new GenericHeaderParser(true, GetStringWithQualityLength); + = new GenericHeaderParser(true, GetStringWithQualityLength!); private StringSegment _value; private double? _quality; @@ -64,7 +65,7 @@ public override string ToString() return _value.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as StringWithQualityHeaderValue; @@ -125,17 +126,17 @@ public static IList ParseStrictList(IList return MultipleValueParser.ParseStrictValues(input); } - public static bool TryParseList(IList input, out IList parsedValues) + public static bool TryParseList(IList input, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseValues(input, out parsedValues); } - public static bool TryParseStrictList(IList input, out IList parsedValues) + public static bool TryParseStrictList(IList input, [NotNullWhen(true)]out IList? parsedValues) { return MultipleValueParser.TryParseStrictValues(input, out parsedValues); } - private static int GetStringWithQualityLength(StringSegment input, int startIndex, out StringWithQualityHeaderValue parsedValue) + private static int GetStringWithQualityLength(StringSegment input, int startIndex, out StringWithQualityHeaderValue? parsedValue) { Contract.Requires(startIndex >= 0); diff --git a/src/Http/Http.Abstractions/src/CookieBuilder.cs b/src/Http/Http.Abstractions/src/CookieBuilder.cs index 429de53cf32a..456bc05e99d1 100644 --- a/src/Http/Http.Abstractions/src/CookieBuilder.cs +++ b/src/Http/Http.Abstractions/src/CookieBuilder.cs @@ -11,12 +11,12 @@ namespace Microsoft.AspNetCore.Http /// public class CookieBuilder { - private string _name; + private string? _name; /// /// The name of the cookie. /// - public virtual string Name + public virtual string? Name { get => _name; set => _name = !string.IsNullOrEmpty(value) @@ -30,7 +30,7 @@ public virtual string Name /// /// Determines the value that will set on . /// - public virtual string Path { get; set; } + public virtual string? Path { get; set; } /// /// The domain to associate the cookie with. @@ -38,7 +38,7 @@ public virtual string Name /// /// Determines the value that will set on . /// - public virtual string Domain { get; set; } + public virtual string? Domain { get; set; } /// /// Indicates whether a cookie is accessible by client-side script. diff --git a/src/Http/Http.Abstractions/src/Extensions/EndpointBuilder.cs b/src/Http/Http.Abstractions/src/Extensions/EndpointBuilder.cs index 2db104bb45e2..470bb5031f84 100644 --- a/src/Http/Http.Abstractions/src/Extensions/EndpointBuilder.cs +++ b/src/Http/Http.Abstractions/src/Extensions/EndpointBuilder.cs @@ -14,12 +14,12 @@ public abstract class EndpointBuilder /// /// Gets or sets the delegate used to process requests for the endpoint. /// - public RequestDelegate RequestDelegate { get; set; } + public RequestDelegate? RequestDelegate { get; set; } /// /// Gets or sets the informational display name of this endpoint. /// - public string DisplayName { get; set; } + public string? DisplayName { get; set; } /// /// Gets the collection of metadata associated with this endpoint. diff --git a/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs b/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs index fc33e8fe8aa1..a74a883b20be 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs @@ -46,7 +46,7 @@ public static IApplicationBuilder Map(this IApplicationBuilder app, PathString p throw new ArgumentNullException(nameof(configuration)); } - if (pathMatch.HasValue && pathMatch.Value.EndsWith("/", StringComparison.Ordinal)) + if (pathMatch.HasValue && pathMatch.Value!.EndsWith("/", StringComparison.Ordinal)) { throw new ArgumentException("The path must not end with a '/'", nameof(pathMatch)); } diff --git a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs index 0ba76507c8ad..cf9e617bd8cb 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs @@ -32,6 +32,11 @@ public MapMiddleware(RequestDelegate next, MapOptions options) throw new ArgumentNullException(nameof(options)); } + if (options.Branch == null) + { + throw new ArgumentException("Branch not set on options.", nameof(options)); + } + _next = next; _options = options; } @@ -62,7 +67,7 @@ public async Task Invoke(HttpContext context) try { - await _options.Branch(context); + await _options.Branch!(context); } finally { diff --git a/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs b/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs index d914aa4210ff..61c1e8d9a4fd 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs @@ -18,7 +18,7 @@ public class MapOptions /// /// The branch taken for a positive match. /// - public RequestDelegate Branch { get; set; } + public RequestDelegate? Branch { get; set; } /// /// If false, matched path would be removed from Request.Path and added to Request.PathBase diff --git a/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs index 1441da4d9920..4c384104e61e 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs @@ -32,6 +32,16 @@ public MapWhenMiddleware(RequestDelegate next, MapWhenOptions options) throw new ArgumentNullException(nameof(options)); } + if (options.Predicate == null) + { + throw new ArgumentException("Predicate not set on options.", nameof(options)); + } + + if (options.Branch == null) + { + throw new ArgumentException("Branch not set on options.", nameof(options)); + } + _next = next; _options = options; } @@ -48,9 +58,9 @@ public async Task Invoke(HttpContext context) throw new ArgumentNullException(nameof(context)); } - if (_options.Predicate(context)) + if (_options.Predicate!(context)) { - await _options.Branch(context); + await _options.Branch!(context); } else { @@ -58,4 +68,4 @@ public async Task Invoke(HttpContext context) } } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Abstractions/src/Extensions/MapWhenOptions.cs b/src/Http/Http.Abstractions/src/Extensions/MapWhenOptions.cs index d18eb7f257a1..3696306962de 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapWhenOptions.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapWhenOptions.cs @@ -11,12 +11,12 @@ namespace Microsoft.AspNetCore.Builder.Extensions /// public class MapWhenOptions { - private Func _predicate; + private Func? _predicate; /// /// The user callback that determines if the branch should be taken. /// - public Func Predicate + public Func? Predicate { get { @@ -36,6 +36,6 @@ public Func Predicate /// /// The branch taken for a positive match. /// - public RequestDelegate Branch { get; set; } + public RequestDelegate? Branch { get; set; } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs b/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs index 3342b4e08d72..a28df53105c8 100644 --- a/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs +++ b/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs @@ -20,7 +20,7 @@ public static class UseMiddlewareExtensions internal const string InvokeMethodName = "Invoke"; internal const string InvokeAsyncMethodName = "InvokeAsync"; - private static readonly MethodInfo GetServiceInfo = typeof(UseMiddlewareExtensions).GetMethod(nameof(GetService), BindingFlags.NonPublic | BindingFlags.Static); + private static readonly MethodInfo GetServiceInfo = typeof(UseMiddlewareExtensions).GetMethod(nameof(GetService), BindingFlags.NonPublic | BindingFlags.Static)!; /// /// Adds a middleware type to the application's request pipeline. @@ -116,7 +116,7 @@ private static IApplicationBuilder UseMiddlewareInterface(IApplicationBuilder ap { return async context => { - var middlewareFactory = (IMiddlewareFactory)context.RequestServices.GetService(typeof(IMiddlewareFactory)); + var middlewareFactory = (IMiddlewareFactory?)context.RequestServices.GetService(typeof(IMiddlewareFactory)); if (middlewareFactory == null) { // No middleware factory diff --git a/src/Http/Http.Abstractions/src/FragmentString.cs b/src/Http/Http.Abstractions/src/FragmentString.cs index fbe936ce899d..6233d7f2a10a 100644 --- a/src/Http/Http.Abstractions/src/FragmentString.cs +++ b/src/Http/Http.Abstractions/src/FragmentString.cs @@ -114,7 +114,7 @@ public bool Equals(FragmentString other) return string.Equals(_value, other._value, StringComparison.Ordinal); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) { diff --git a/src/Http/Http.Abstractions/src/HostString.cs b/src/Http/Http.Abstractions/src/HostString.cs index 0f7cbd73f6f0..d6c30e3c7361 100644 --- a/src/Http/Http.Abstractions/src/HostString.cs +++ b/src/Http/Http.Abstractions/src/HostString.cs @@ -297,7 +297,7 @@ public bool Equals(HostString other) /// /// The to compare against. /// if they have the same value. - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) { diff --git a/src/Http/Http.Abstractions/src/HttpRequest.cs b/src/Http/Http.Abstractions/src/HttpRequest.cs index 373b82588ab2..33f8a9ed8f9d 100644 --- a/src/Http/Http.Abstractions/src/HttpRequest.cs +++ b/src/Http/Http.Abstractions/src/HttpRequest.cs @@ -131,6 +131,6 @@ public abstract class HttpRequest /// Gets the collection of route values for this request. /// /// The collection of route values for this request. - public virtual RouteValueDictionary RouteValues { get; set; } + public virtual RouteValueDictionary RouteValues { get; set; } = null!; } } diff --git a/src/Http/Http.Abstractions/src/Internal/HeaderSegment.cs b/src/Http/Http.Abstractions/src/Internal/HeaderSegment.cs index f86ea7db073f..00bf3e8cf295 100644 --- a/src/Http/Http.Abstractions/src/Internal/HeaderSegment.cs +++ b/src/Http/Http.Abstractions/src/Internal/HeaderSegment.cs @@ -35,7 +35,7 @@ public bool Equals(HeaderSegment other) return _formatting.Equals(other._formatting) && _data.Equals(other._data); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) { diff --git a/src/Http/Http.Abstractions/src/Internal/HeaderSegmentCollection.cs b/src/Http/Http.Abstractions/src/Internal/HeaderSegmentCollection.cs index 70d6b4510907..b83bf4eeeaea 100644 --- a/src/Http/Http.Abstractions/src/Internal/HeaderSegmentCollection.cs +++ b/src/Http/Http.Abstractions/src/Internal/HeaderSegmentCollection.cs @@ -22,7 +22,7 @@ public bool Equals(HeaderSegmentCollection other) return StringValues.Equals(_headers, other._headers); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) { diff --git a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj index c5ab085eef0a..33ce43772ee8 100644 --- a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj +++ b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj @@ -14,6 +14,7 @@ Microsoft.AspNetCore.Http.HttpResponse aspnetcore $(NoWarn);CS1591 false + enable diff --git a/src/Http/Http.Abstractions/src/PathString.cs b/src/Http/Http.Abstractions/src/PathString.cs index 40fe610a82dc..79f82ddd1a4e 100644 --- a/src/Http/Http.Abstractions/src/PathString.cs +++ b/src/Http/Http.Abstractions/src/PathString.cs @@ -20,14 +20,14 @@ namespace Microsoft.AspNetCore.Http /// public static readonly PathString Empty = new PathString(string.Empty); - private readonly string _value; + private readonly string? _value; /// /// Initialize the path string with a given value. This value must be in unescaped format. Use /// PathString.FromUriComponent(value) if you have a path value which is in an escaped format. /// /// The unescaped path to be assigned to the Value property. - public PathString(string value) + public PathString(string? value) { if (!string.IsNullOrEmpty(value) && value[0] != '/') { @@ -39,7 +39,7 @@ public PathString(string value) /// /// The unescaped path value /// - public string Value + public string? Value { get { return _value; } } @@ -72,7 +72,7 @@ public string ToUriComponent() return string.Empty; } - var value = _value; + var value = _value!; var i = 0; for (; i < value.Length; i++) { @@ -92,7 +92,7 @@ public string ToUriComponent() private static string ToEscapedUriComponent(string value, int i) { - StringBuilder buffer = null; + StringBuilder? buffer = null; var start = 0; var count = i; @@ -174,7 +174,7 @@ private static string ToEscapedUriComponent(string value, int i) } } - return buffer.ToString(); + return buffer?.ToString() ?? string.Empty; } } @@ -318,11 +318,11 @@ public PathString Add(PathString other) { if (HasValue && other.HasValue && - Value[Value.Length - 1] == '/') + Value![Value.Length - 1] == '/') { // If the path string has a trailing slash and the other string has a leading slash, we need // to trim one of them. - return new PathString(Value + other.Value.Substring(1)); + return new PathString(Value + other.Value!.Substring(1)); } return new PathString(Value + other.Value); @@ -367,7 +367,7 @@ public bool Equals(PathString other, StringComparison comparisonType) /// /// The second PathString for comparison. /// True if both PathString values are equal - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) { @@ -382,7 +382,7 @@ public override bool Equals(object obj) /// The hash code public override int GetHashCode() { - return (HasValue ? StringComparer.OrdinalIgnoreCase.GetHashCode(_value) : 0); + return (HasValue ? StringComparer.OrdinalIgnoreCase.GetHashCode(_value!) : 0); } /// @@ -457,7 +457,7 @@ public override int GetHashCode() /// Implicitly creates a new PathString from the given string. /// /// - public static implicit operator PathString(string s) + public static implicit operator PathString(string? s) => ConvertFromString(s); /// @@ -467,7 +467,7 @@ public static implicit operator PathString(string s) public static implicit operator string(PathString path) => path.ToString(); - internal static PathString ConvertFromString(string s) + internal static PathString ConvertFromString(string? s) => string.IsNullOrEmpty(s) ? new PathString(s) : FromUriComponent(s); } @@ -486,7 +486,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) => destinationType == typeof(string) - ? value.ToString() + ? value.ToString() ?? string.Empty : base.ConvertTo(context, culture, value, destinationType); } } diff --git a/src/Http/Http.Abstractions/src/QueryString.cs b/src/Http/Http.Abstractions/src/QueryString.cs index 64296e6beeb2..a60f78504267 100644 --- a/src/Http/Http.Abstractions/src/QueryString.cs +++ b/src/Http/Http.Abstractions/src/QueryString.cs @@ -218,7 +218,7 @@ public bool Equals(QueryString other) return string.Equals(_value, other._value, StringComparison.Ordinal); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) { @@ -247,7 +247,7 @@ public override int GetHashCode() return left.Add(right); } - private static void AppendKeyValuePair(StringBuilder builder, string key, string value, bool first) + private static void AppendKeyValuePair(StringBuilder builder, string key, string? value, bool first) { builder.Append(first ? "?" : "&"); builder.Append(UrlEncoder.Default.Encode(key)); diff --git a/src/Http/Http.Abstractions/src/Routing/Endpoint.cs b/src/Http/Http.Abstractions/src/Routing/Endpoint.cs index dbca2944e03c..4733177674ba 100644 --- a/src/Http/Http.Abstractions/src/Routing/Endpoint.cs +++ b/src/Http/Http.Abstractions/src/Routing/Endpoint.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. namespace Microsoft.AspNetCore.Http @@ -44,6 +44,6 @@ public Endpoint( /// public RequestDelegate RequestDelegate { get; } - public override string ToString() => DisplayName ?? base.ToString(); + public override string? ToString() => DisplayName ?? base.ToString(); } } diff --git a/src/Http/Http.Abstractions/src/Routing/EndpointHttpContextExtensions.cs b/src/Http/Http.Abstractions/src/Routing/EndpointHttpContextExtensions.cs index d766e8336a8a..3eea0541f4b9 100644 --- a/src/Http/Http.Abstractions/src/Routing/EndpointHttpContextExtensions.cs +++ b/src/Http/Http.Abstractions/src/Routing/EndpointHttpContextExtensions.cs @@ -16,7 +16,7 @@ public static class EndpointHttpContextExtensions /// /// The context. /// The . - public static Endpoint GetEndpoint(this HttpContext context) + public static Endpoint? GetEndpoint(this HttpContext context) { if (context == null) { @@ -31,7 +31,7 @@ public static Endpoint GetEndpoint(this HttpContext context) /// /// The context. /// The . - public static void SetEndpoint(this HttpContext context, Endpoint endpoint) + public static void SetEndpoint(this HttpContext context, Endpoint? endpoint) { if (context == null) { @@ -64,7 +64,7 @@ public static void SetEndpoint(this HttpContext context, Endpoint endpoint) private class EndpointFeature : IEndpointFeature { - public Endpoint Endpoint { get; set; } + public Endpoint? Endpoint { get; set; } } } } diff --git a/src/Http/Http.Abstractions/src/Routing/EndpointMetadataCollection.cs b/src/Http/Http.Abstractions/src/Routing/EndpointMetadataCollection.cs index 47f9d6e1e57e..6051068e527c 100644 --- a/src/Http/Http.Abstractions/src/Routing/EndpointMetadataCollection.cs +++ b/src/Http/Http.Abstractions/src/Routing/EndpointMetadataCollection.cs @@ -72,7 +72,7 @@ public EndpointMetadataCollection(params object[] items) /// The most significant metadata of type or null. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T GetMetadata() where T : class + public T? GetMetadata() where T : class { if (_cache.TryGetValue(typeof(T), out var obj)) { @@ -84,7 +84,7 @@ public T GetMetadata() where T : class return GetMetadataSlow(); } - private T GetMetadataSlow() where T : class + private T? GetMetadataSlow() where T : class { var result = GetOrderedMetadataSlow(); var length = result.Length; @@ -111,7 +111,7 @@ public IReadOnlyList GetOrderedMetadata() where T : class private T[] GetOrderedMetadataSlow() where T : class { // Perf: avoid allocations totally for the common case where there are no matching metadata. - List matches = null; + List? matches = null; var items = _items; for (var i = 0; i < items.Length; i++) @@ -149,7 +149,7 @@ private T[] GetOrderedMetadataSlow() where T : class /// /// Enumerates the elements of an . /// - public struct Enumerator : IEnumerator + public struct Enumerator : IEnumerator { // Intentionally not readonly to prevent defensive struct copies private object[] _items; @@ -165,7 +165,7 @@ internal Enumerator(EndpointMetadataCollection collection) /// /// Gets the element at the current position of the enumerator /// - public object Current { get; private set; } + public object? Current { get; private set; } /// /// Releases all resources used by the . diff --git a/src/Http/Http.Abstractions/src/Routing/IEndpointFeature.cs b/src/Http/Http.Abstractions/src/Routing/IEndpointFeature.cs index ff0762bb2050..d8c1f1e7dba2 100644 --- a/src/Http/Http.Abstractions/src/Routing/IEndpointFeature.cs +++ b/src/Http/Http.Abstractions/src/Routing/IEndpointFeature.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. namespace Microsoft.AspNetCore.Http.Features @@ -13,6 +13,6 @@ public interface IEndpointFeature /// Gets or sets the selected for the current /// request. /// - Endpoint Endpoint { get; set; } + Endpoint? Endpoint { get; set; } } } diff --git a/src/Http/Http.Abstractions/src/Routing/RouteValueDictionary.cs b/src/Http/Http.Abstractions/src/Routing/RouteValueDictionary.cs index 13c433b38747..6c585c7f4cab 100644 --- a/src/Http/Http.Abstractions/src/Routing/RouteValueDictionary.cs +++ b/src/Http/Http.Abstractions/src/Routing/RouteValueDictionary.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Http.Abstractions; using Microsoft.Extensions.Internal; @@ -15,13 +16,13 @@ namespace Microsoft.AspNetCore.Routing /// /// An type for route values. /// - public class RouteValueDictionary : IDictionary, IReadOnlyDictionary + public class RouteValueDictionary : IDictionary, IReadOnlyDictionary { // 4 is a good default capacity here because that leaves enough space for area/controller/action/id private const int DefaultCapacity = 4; - internal KeyValuePair[] _arrayStorage; - internal PropertyStorage _propertyStorage; + internal KeyValuePair[] _arrayStorage; + internal PropertyStorage? _propertyStorage; private int _count; /// @@ -30,7 +31,7 @@ public class RouteValueDictionary : IDictionary, IReadOnlyDictio /// /// The items array. /// A new . - public static RouteValueDictionary FromArray(KeyValuePair[] items) + public static RouteValueDictionary FromArray(KeyValuePair[] items) { if (items == null) { @@ -80,7 +81,7 @@ public static RouteValueDictionary FromArray(KeyValuePair[] item /// public RouteValueDictionary() { - _arrayStorage = Array.Empty>(); + _arrayStorage = Array.Empty>(); } /// @@ -105,6 +106,7 @@ public RouteValueDictionary(object values) // PropertyStorage is immutable so we can just copy it. _propertyStorage = dictionary._propertyStorage; _count = dictionary._count; + _arrayStorage = Array.Empty>(); return; } @@ -112,14 +114,14 @@ public RouteValueDictionary(object values) if (count > 0) { var other = dictionary._arrayStorage; - var storage = new KeyValuePair[count]; + var storage = new KeyValuePair[count]; Array.Copy(other, 0, storage, 0, count); _arrayStorage = storage; _count = count; } else { - _arrayStorage = Array.Empty>(); + _arrayStorage = Array.Empty>(); } return; @@ -127,7 +129,7 @@ public RouteValueDictionary(object values) if (values is IEnumerable> keyValueEnumerable) { - _arrayStorage = Array.Empty>(); + _arrayStorage = Array.Empty>(); foreach (var kvp in keyValueEnumerable) { @@ -139,7 +141,7 @@ public RouteValueDictionary(object values) if (values is IEnumerable> stringValueEnumerable) { - _arrayStorage = Array.Empty>(); + _arrayStorage = Array.Empty>(); foreach (var kvp in stringValueEnumerable) { @@ -154,15 +156,16 @@ public RouteValueDictionary(object values) var storage = new PropertyStorage(values); _propertyStorage = storage; _count = storage.Properties.Length; + _arrayStorage = Array.Empty>(); } else { - _arrayStorage = Array.Empty>(); + _arrayStorage = Array.Empty>(); } } /// - public object this[string key] + public object? this[string key] { get { @@ -171,8 +174,7 @@ public object this[string key] ThrowArgumentNullExceptionForKey(); } - object value; - TryGetValue(key, out value); + TryGetValue(key, out var value); return value; } @@ -192,11 +194,11 @@ public object this[string key] if (index < 0) { EnsureCapacity(_count + 1); - _arrayStorage[_count++] = new KeyValuePair(key, value); + _arrayStorage[_count++] = new KeyValuePair(key, value); } else { - _arrayStorage[index] = new KeyValuePair(key, value); + _arrayStorage[index] = new KeyValuePair(key, value); } } } @@ -213,7 +215,7 @@ public object this[string key] public int Count => _count; /// - bool ICollection>.IsReadOnly => false; + bool ICollection>.IsReadOnly => false; /// public ICollection Keys @@ -233,17 +235,17 @@ public ICollection Keys } } - IEnumerable IReadOnlyDictionary.Keys => Keys; + IEnumerable IReadOnlyDictionary.Keys => Keys; /// - public ICollection Values + public ICollection Values { get { EnsureCapacity(_count); var array = _arrayStorage; - var values = new object[_count]; + var values = new object?[_count]; for (var i = 0; i < values.Length; i++) { values[i] = array[i].Value; @@ -253,16 +255,16 @@ public ICollection Values } } - IEnumerable IReadOnlyDictionary.Values => Values; + IEnumerable IReadOnlyDictionary.Values => Values; /// - void ICollection>.Add(KeyValuePair item) + void ICollection>.Add(KeyValuePair item) { Add(item.Key, item.Value); } /// - public void Add(string key, object value) + public void Add(string key, object? value) { if (key == null) { @@ -277,7 +279,7 @@ public void Add(string key, object value) throw new ArgumentException(message, nameof(key)); } - _arrayStorage[_count] = new KeyValuePair(key, value); + _arrayStorage[_count] = new KeyValuePair(key, value); _count++; } @@ -291,7 +293,7 @@ public void Clear() if (_propertyStorage != null) { - _arrayStorage = Array.Empty>(); + _arrayStorage = Array.Empty>(); _propertyStorage = null; _count = 0; return; @@ -302,7 +304,7 @@ public void Clear() } /// - bool ICollection>.Contains(KeyValuePair item) + bool ICollection>.Contains(KeyValuePair item) { return TryGetValue(item.Key, out var value) && EqualityComparer.Default.Equals(value, item.Value); } @@ -330,8 +332,8 @@ private bool ContainsKeyCore(string key) } /// - void ICollection>.CopyTo( - KeyValuePair[] array, + void ICollection>.CopyTo( + KeyValuePair[] array, int arrayIndex) { if (array == null) @@ -362,7 +364,7 @@ public Enumerator GetEnumerator() } /// - IEnumerator> IEnumerable>.GetEnumerator() + IEnumerator> IEnumerable>.GetEnumerator() { return GetEnumerator(); } @@ -374,13 +376,15 @@ IEnumerator IEnumerable.GetEnumerator() } /// - bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) { if (Count == 0) { return false; } + Debug.Assert(_arrayStorage != null); + EnsureCapacity(Count); var index = FindIndex(item.Key); @@ -435,7 +439,7 @@ public bool Remove(string key) /// /// true if the object was removed successfully; otherwise, false. /// - public bool Remove(string key, out object value) + public bool Remove(string key, out object? value) { if (key == null) { @@ -487,13 +491,13 @@ public bool TryAdd(string key, object value) } EnsureCapacity(Count + 1); - _arrayStorage[Count] = new KeyValuePair(key, value); + _arrayStorage[Count] = new KeyValuePair(key, value); _count++; return true; } /// - public bool TryGetValue(string key, out object value) + public bool TryGetValue(string key, [NotNullWhen(true)]out object? value) { if (key == null) { @@ -508,7 +512,7 @@ public bool TryGetValue(string key, out object value) return TryGetValueSlow(key, out value); } - private bool TryGetValueSlow(string key, out object value) + private bool TryGetValueSlow(string key, [NotNullWhen(true)]out object? value) { if (_propertyStorage != null) { @@ -527,6 +531,7 @@ private bool TryGetValueSlow(string key, out object value) return false; } + [DoesNotReturn] private static void ThrowArgumentNullExceptionForKey() { throw new ArgumentNullException("key"); @@ -550,12 +555,12 @@ private void EnsureCapacitySlow(int capacity) // If we're converting from properties, it's likely due to an 'add' to make sure we have at least // the default amount of space. capacity = Math.Max(DefaultCapacity, Math.Max(storage.Properties.Length, capacity)); - var array = new KeyValuePair[capacity]; + var array = new KeyValuePair[capacity]; for (var i = 0; i < storage.Properties.Length; i++) { var property = storage.Properties[i]; - array[i] = new KeyValuePair(property.Name, property.GetValue(storage.Value)); + array[i] = new KeyValuePair(property.Name, property.GetValue(storage.Value)); } _arrayStorage = array; @@ -566,7 +571,7 @@ private void EnsureCapacitySlow(int capacity) if (_arrayStorage.Length < capacity) { capacity = _arrayStorage.Length == 0 ? DefaultCapacity : _arrayStorage.Length * 2; - var array = new KeyValuePair[capacity]; + var array = new KeyValuePair[capacity]; if (_count > 0) { Array.Copy(_arrayStorage, 0, array, 0, _count); @@ -596,7 +601,7 @@ private int FindIndex(string key) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool TryFindItem(string key, out object value) + private bool TryFindItem(string key, [NotNullWhen(true)]out object? value) { var array = _arrayStorage; var count = _count; @@ -642,6 +647,8 @@ private bool ContainsKeyArray(string key) [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool ContainsKeyProperties(string key) { + Debug.Assert(_propertyStorage != null); + var properties = _propertyStorage.Properties; for (var i = 0; i < properties.Length; i++) { @@ -654,7 +661,7 @@ private bool ContainsKeyProperties(string key) return false; } - public struct Enumerator : IEnumerator> + public struct Enumerator : IEnumerator> { private readonly RouteValueDictionary _dictionary; private int _index; @@ -672,7 +679,7 @@ public Enumerator(RouteValueDictionary dictionary) _index = 0; } - public KeyValuePair Current { get; private set; } + public KeyValuePair Current { get; private set; } object IEnumerator.Current => Current; @@ -704,7 +711,7 @@ private bool MoveNextRare() { var storage = dictionary._propertyStorage; var property = storage.Properties[_index]; - Current = new KeyValuePair(property.Name, property.GetValue(storage.Value)); + Current = new KeyValuePair(property.Name, property.GetValue(storage.Value)); _index++; return true; } @@ -735,7 +742,7 @@ public PropertyStorage(object value) // Cache the properties so we can know if we've already validated them for duplicates. var type = Value.GetType(); - if (!_propertyCache.TryGetValue(type, out Properties)) + if (!_propertyCache.TryGetValue(type, out Properties!)) { Properties = PropertyHelper.GetVisibleProperties(type); ValidatePropertyNames(type, Properties); @@ -765,4 +772,4 @@ private static void ValidatePropertyNames(Type type, PropertyHelper[] properties } } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Abstractions/src/WebSocketManager.cs b/src/Http/Http.Abstractions/src/WebSocketManager.cs index 79afefa5c0d4..1fe47d59587d 100644 --- a/src/Http/Http.Abstractions/src/WebSocketManager.cs +++ b/src/Http/Http.Abstractions/src/WebSocketManager.cs @@ -36,6 +36,6 @@ public virtual Task AcceptWebSocketAsync() /// /// The sub-protocol to use. /// A task representing the completion of the transition. - public abstract Task AcceptWebSocketAsync(string subProtocol); + public abstract Task AcceptWebSocketAsync(string? subProtocol); } } diff --git a/src/Http/Http.Abstractions/test/RouteValueDictionaryTests.cs b/src/Http/Http.Abstractions/test/RouteValueDictionaryTests.cs index ab5925e219e2..244d8c99aae8 100644 --- a/src/Http/Http.Abstractions/test/RouteValueDictionaryTests.cs +++ b/src/Http/Http.Abstractions/test/RouteValueDictionaryTests.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; @@ -70,7 +70,7 @@ public void CreateFromRouteValueDictionary_WithPropertyStorage_CopiesStorage() // Assert Assert.Equal(other, dict); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); var storage = dict._propertyStorage; var otherStorage = other._propertyStorage; @@ -262,7 +262,7 @@ public void CreateFromObject_CopiesPropertiesFromRegularType_IgnoresStatic() // Assert Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Empty(dict); } @@ -277,7 +277,7 @@ public void CreateFromObject_CopiesPropertiesFromRegularType_IgnoresSetOnly() // Assert Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Empty(dict); } @@ -292,7 +292,7 @@ public void CreateFromObject_CopiesPropertiesFromRegularType_IncludesInherited() // Assert Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Collection( dict.OrderBy(kvp => kvp.Key), kvp => @@ -320,7 +320,7 @@ public void CreateFromObject_CopiesPropertiesFromRegularType_WithHiddenProperty( // Assert Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Collection( dict.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("DerivedProperty", kvp.Key); Assert.Equal(5, kvp.Value); }); @@ -337,7 +337,7 @@ public void CreateFromObject_CopiesPropertiesFromRegularType_WithIndexerProperty // Assert Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Empty(dict); } @@ -926,7 +926,7 @@ public void Clear_PropertyStorage_AlreadyEmpty() // Assert Assert.Empty(dict); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); } [Fact] @@ -1053,7 +1053,7 @@ public void Contains_PropertyStorage_KeyValuePair_True() // Assert Assert.True(result); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Collection( dict, kvp => Assert.Equal(new KeyValuePair("key", "value"), kvp)); @@ -1073,7 +1073,7 @@ public void Contains_PropertyStory_KeyValuePair_True_CaseInsensitive() // Assert Assert.True(result); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Collection( dict, kvp => Assert.Equal(new KeyValuePair("key", "value"), kvp)); @@ -1093,7 +1093,7 @@ public void Contains_PropertyStorage_KeyValuePair_False() // Assert Assert.False(result); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Collection( dict, kvp => Assert.Equal(new KeyValuePair("key", "value"), kvp)); @@ -1114,7 +1114,7 @@ public void Contains_PropertyStorage_KeyValuePair_False_ValueComparisonIsDefault // Assert Assert.False(result); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.Collection( dict, kvp => Assert.Equal(new KeyValuePair("key", "value"), kvp)); @@ -1158,7 +1158,7 @@ public void ContainsKey_PropertyStorage_False() // Assert Assert.False(result); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); } [Fact] @@ -1173,7 +1173,7 @@ public void ContainsKey_PropertyStorage_True() // Assert Assert.True(result); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); } [Fact] @@ -1188,7 +1188,7 @@ public void ContainsKey_PropertyStorage_True_CaseInsensitive() // Assert Assert.True(result); Assert.NotNull(dict._propertyStorage); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); } [Fact] @@ -1761,7 +1761,7 @@ public void TryAdd_PropertyStory_KeyExist_DoesNotConvertPropertyStorageToArraySt // Assert Assert.False(result); - Assert.Null(dict._arrayStorage); + AssertEmptyArrayStorage(dict); Assert.NotNull(dict._propertyStorage); Assert.Collection( dict, @@ -2113,6 +2113,11 @@ public void FromArray_RemovesGapsInArray() array); } + private void AssertEmptyArrayStorage(RouteValueDictionary value) + { + Assert.Same(Array.Empty>(), value._arrayStorage); + } + private class RegularType { public bool IsAwesome { get; set; } @@ -2172,4 +2177,4 @@ private class Address public string State { get; set; } } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Features/src/CookieOptions.cs b/src/Http/Http.Features/src/CookieOptions.cs index 833eeedea2e6..74512d23609a 100644 --- a/src/Http/Http.Features/src/CookieOptions.cs +++ b/src/Http/Http.Features/src/CookieOptions.cs @@ -22,13 +22,13 @@ public CookieOptions() /// Gets or sets the domain to associate the cookie with. /// /// The domain to associate the cookie with. - public string Domain { get; set; } + public string? Domain { get; set; } /// /// Gets or sets the cookie path. /// /// The cookie path. - public string Path { get; set; } + public string? Path { get; set; } /// /// Gets or sets the expiration date and time for the cookie. diff --git a/src/Http/Http.Features/src/FeatureCollection.cs b/src/Http/Http.Features/src/FeatureCollection.cs index e79ecfee224a..f9d1736b5760 100644 --- a/src/Http/Http.Features/src/FeatureCollection.cs +++ b/src/Http/Http.Features/src/FeatureCollection.cs @@ -11,8 +11,8 @@ namespace Microsoft.AspNetCore.Http.Features public class FeatureCollection : IFeatureCollection { private static KeyComparer FeatureKeyComparer = new KeyComparer(); - private readonly IFeatureCollection _defaults; - private IDictionary _features; + private readonly IFeatureCollection? _defaults; + private IDictionary? _features; private volatile int _containerRevision; public FeatureCollection() @@ -31,7 +31,7 @@ public virtual int Revision public bool IsReadOnly { get { return false; } } - public object this[Type key] + public object? this[Type key] { get { @@ -40,7 +40,7 @@ public object this[Type key] throw new ArgumentNullException(nameof(key)); } - object result; + object? result; return _features != null && _features.TryGetValue(key, out result) ? result : _defaults?[key]; } set @@ -95,7 +95,9 @@ public IEnumerator> GetEnumerator() public TFeature Get() { +#pragma warning disable CS8601 // Possible null reference assignment. return (TFeature)this[typeof(TFeature)]; +#pragma warning restore CS8601 // Possible null reference assignment. } public void Set(TFeature instance) @@ -116,4 +118,4 @@ public int GetHashCode(KeyValuePair obj) } } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Features/src/FeatureReference.cs b/src/Http/Http.Features/src/FeatureReference.cs index 501660212310..516fb70e909e 100644 --- a/src/Http/Http.Features/src/FeatureReference.cs +++ b/src/Http/Http.Features/src/FeatureReference.cs @@ -1,6 +1,8 @@ // 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.Diagnostics.CodeAnalysis; + namespace Microsoft.AspNetCore.Http.Features { public struct FeatureReference @@ -14,15 +16,16 @@ private FeatureReference(T feature, int revision) _revision = revision; } - public static readonly FeatureReference Default = new FeatureReference(default(T), -1); + public static readonly FeatureReference Default = new FeatureReference(default(T)!, -1); + [return: MaybeNull] public T Fetch(IFeatureCollection features) { if (_revision == features.Revision) { return _feature; } - _feature = (T)features[typeof(T)]; + _feature = (T)features[typeof(T)]!; _revision = features.Revision; return _feature; } @@ -35,4 +38,4 @@ public T Update(IFeatureCollection features, T feature) return feature; } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Features/src/FeatureReferences.cs b/src/Http/Http.Features/src/FeatureReferences.cs index f19938bfe98a..fa32c413471e 100644 --- a/src/Http/Http.Features/src/FeatureReferences.cs +++ b/src/Http/Http.Features/src/FeatureReferences.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Microsoft.AspNetCore.Http.Features @@ -36,6 +37,7 @@ public void Initalize(IFeatureCollection collection, int revision) // be able to pass ref values that "dot through" the TCache struct memory, // if it was a Property then that getter would return a copy of the memory // preventing the use of "ref" + [AllowNull, MaybeNull] public TCache Cache; // Careful with modifications to the Fetch method; it is carefully constructed for inlining @@ -60,7 +62,7 @@ public void Initalize(IFeatureCollection collection, int revision) // Generally Fetch is called at a ratio > x4 of UpdateCached so this is a large gain [MethodImpl(MethodImplOptions.AggressiveInlining)] public TFeature Fetch( - ref TFeature cached, + [AllowNull, MaybeNull]ref TFeature cached, TState state, Func factory) where TFeature : class { @@ -69,12 +71,12 @@ public TFeature Fetch( if (Revision != revision) { // Clear cached value to force call to UpdateCached - cached = null; + cached = null!; // Collection changed, clear whole feature cache flush = true; } - return cached ?? UpdateCached(ref cached, state, factory, revision, flush); + return cached ?? UpdateCached(ref cached!, state, factory, revision, flush); } // Update and cache clearing logic, when the fast-path in Fetch isn't applicable @@ -106,8 +108,8 @@ private TFeature UpdateCached(ref TFeature cached, TState stat return cached; } - public TFeature Fetch(ref TFeature cached, Func factory) - where TFeature : class => Fetch(ref cached, Collection, factory); + public TFeature Fetch([AllowNull, MaybeNull]ref TFeature cached, Func factory) + where TFeature : class => Fetch(ref cached!, Collection, factory); private static int ContextDisposed() { diff --git a/src/Http/Http.Features/src/IFeatureCollection.cs b/src/Http/Http.Features/src/IFeatureCollection.cs index f7b23ed16f25..6d087df337d7 100644 --- a/src/Http/Http.Features/src/IFeatureCollection.cs +++ b/src/Http/Http.Features/src/IFeatureCollection.cs @@ -26,7 +26,7 @@ public interface IFeatureCollection : IEnumerable> /// /// /// The requested feature, or null if it is not present. - object this[Type key] { get; set; } + object? this[Type key] { get; set; } /// /// Retrieves the requested feature from the collection. diff --git a/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj b/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj index 74dc703d749b..001d35a48ae7 100644 --- a/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj +++ b/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj @@ -1,4 +1,4 @@ - + ASP.NET Core HTTP feature interface definitions. @@ -9,8 +9,13 @@ true aspnetcore true + enable + + + + diff --git a/src/Http/Http.Features/src/WebSocketAcceptContext.cs b/src/Http/Http.Features/src/WebSocketAcceptContext.cs index 5e3659d64784..beb7e0a59d67 100644 --- a/src/Http/Http.Features/src/WebSocketAcceptContext.cs +++ b/src/Http/Http.Features/src/WebSocketAcceptContext.cs @@ -5,6 +5,6 @@ namespace Microsoft.AspNetCore.Http { public class WebSocketAcceptContext { - public virtual string SubProtocol { get; set; } + public virtual string? SubProtocol { get; set; } } -} \ No newline at end of file +} diff --git a/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj b/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj index 4240032c6ffa..43573fb90ce1 100644 --- a/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj +++ b/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj @@ -1,4 +1,4 @@ - + ASP.NET Core abstractions for routing requests to application logic and for generating links. @@ -11,6 +11,7 @@ Microsoft.AspNetCore.Routing.RouteData true aspnetcore;routing false + annotations diff --git a/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj b/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj index 7c399fe55754..c99863572f7a 100644 --- a/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj +++ b/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj @@ -1,4 +1,4 @@ - + ASP.NET Core middleware for routing requests to application logic and for generating links. @@ -12,6 +12,7 @@ Microsoft.AspNetCore.Routing.RouteCollection aspnetcore;routing true false + annotations diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs index f99de518cffb..235c0ea0cf69 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs @@ -1177,7 +1177,7 @@ private Task ResultNext(ref State next, ref Scope scope, var resultExecutingContext = _resultExecutingContext; var resultExecutedContext = _resultExecutedContext; - if (resultExecutedContext == null || resultExecutingContext.Cancel) + if (_resultExecutedContext == null || resultExecutingContext.Cancel) { // Short-circuited by not calling next || Short-circuited by setting Cancel == true _logger.ResultFilterShortCircuited(filter); diff --git a/src/Mvc/Mvc.Core/src/Microsoft.AspNetCore.Mvc.Core.csproj b/src/Mvc/Mvc.Core/src/Microsoft.AspNetCore.Mvc.Core.csproj index 1d1eaa6448ee..7700a27787ad 100644 --- a/src/Mvc/Mvc.Core/src/Microsoft.AspNetCore.Mvc.Core.csproj +++ b/src/Mvc/Mvc.Core/src/Microsoft.AspNetCore.Mvc.Core.csproj @@ -16,6 +16,7 @@ Microsoft.AspNetCore.Mvc.RouteAttribute true aspnetcore;aspnetcoremvc false + annotations diff --git a/src/Servers/Connections.Abstractions/src/ConnectionContext.cs b/src/Servers/Connections.Abstractions/src/ConnectionContext.cs index 947066ca796f..6480926520ac 100644 --- a/src/Servers/Connections.Abstractions/src/ConnectionContext.cs +++ b/src/Servers/Connections.Abstractions/src/ConnectionContext.cs @@ -30,12 +30,12 @@ public abstract class ConnectionContext : IAsyncDisposable /// /// Gets or sets a key/value collection that can be used to share data within the scope of this connection. /// - public abstract IDictionary Items { get; set; } + public abstract IDictionary Items { get; set; } /// /// Gets or sets the that can be used to read or write data on this connection. /// - public abstract IDuplexPipe Transport { get; set; } + public abstract IDuplexPipe? Transport { get; set; } /// /// Triggered when the client connection is closed. @@ -45,12 +45,12 @@ public abstract class ConnectionContext : IAsyncDisposable /// /// Gets or sets the local endpoint for this connection. /// - public virtual EndPoint LocalEndPoint { get; set; } + public virtual EndPoint? LocalEndPoint { get; set; } /// /// Gets or sets the remote endpoint for this connection. /// - public virtual EndPoint RemoteEndPoint { get; set; } + public virtual EndPoint? RemoteEndPoint { get; set; } /// /// Aborts the underlying connection. diff --git a/src/Servers/Connections.Abstractions/src/ConnectionItems.cs b/src/Servers/Connections.Abstractions/src/ConnectionItems.cs index f5c7dd0352d4..5d9ef2cdb89f 100644 --- a/src/Servers/Connections.Abstractions/src/ConnectionItems.cs +++ b/src/Servers/Connections.Abstractions/src/ConnectionItems.cs @@ -6,22 +6,22 @@ namespace Microsoft.AspNetCore.Connections { - public class ConnectionItems : IDictionary + public class ConnectionItems : IDictionary { public ConnectionItems() - : this(new Dictionary()) + : this(new Dictionary()) { } - public ConnectionItems(IDictionary items) + public ConnectionItems(IDictionary items) { Items = items; } - public IDictionary Items { get; } + public IDictionary Items { get; } // Replace the indexer with one that returns null for missing values - object IDictionary.this[object key] + object? IDictionary.this[object key] { get { @@ -34,67 +34,67 @@ object IDictionary.this[object key] set { Items[key] = value; } } - void IDictionary.Add(object key, object value) + void IDictionary.Add(object key, object? value) { Items.Add(key, value); } - bool IDictionary.ContainsKey(object key) + bool IDictionary.ContainsKey(object key) { return Items.ContainsKey(key); } - ICollection IDictionary.Keys + ICollection IDictionary.Keys { get { return Items.Keys; } } - bool IDictionary.Remove(object key) + bool IDictionary.Remove(object key) { return Items.Remove(key); } - bool IDictionary.TryGetValue(object key, out object value) + bool IDictionary.TryGetValue(object key, out object? value) { return Items.TryGetValue(key, out value); } - ICollection IDictionary.Values + ICollection IDictionary.Values { get { return Items.Values; } } - void ICollection>.Add(KeyValuePair item) + void ICollection>.Add(KeyValuePair item) { Items.Add(item); } - void ICollection>.Clear() + void ICollection>.Clear() { Items.Clear(); } - bool ICollection>.Contains(KeyValuePair item) + bool ICollection>.Contains(KeyValuePair item) { return Items.Contains(item); } - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { Items.CopyTo(array, arrayIndex); } - int ICollection>.Count + int ICollection>.Count { get { return Items.Count; } } - bool ICollection>.IsReadOnly + bool ICollection>.IsReadOnly { get { return Items.IsReadOnly; } } - bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) { if (Items.TryGetValue(item.Key, out var value) && Equals(item.Value, value)) { @@ -103,7 +103,7 @@ bool ICollection>.Remove(KeyValuePair> IEnumerable>.GetEnumerator() + IEnumerator> IEnumerable>.GetEnumerator() { return Items.GetEnumerator(); } diff --git a/src/Servers/Connections.Abstractions/src/DefaultConnectionContext.cs b/src/Servers/Connections.Abstractions/src/DefaultConnectionContext.cs index 870fc4548f6e..94bfb9213e65 100644 --- a/src/Servers/Connections.Abstractions/src/DefaultConnectionContext.cs +++ b/src/Servers/Connections.Abstractions/src/DefaultConnectionContext.cs @@ -58,21 +58,21 @@ public DefaultConnectionContext(string id, IDuplexPipe transport, IDuplexPipe ap public override IFeatureCollection Features { get; } - public ClaimsPrincipal User { get; set; } + public ClaimsPrincipal? User { get; set; } - public override IDictionary Items { get; set; } = new ConnectionItems(); + public override IDictionary Items { get; set; } = new ConnectionItems(); - public IDuplexPipe Application { get; set; } + public IDuplexPipe? Application { get; set; } - public override IDuplexPipe Transport { get; set; } + public override IDuplexPipe? Transport { get; set; } public override CancellationToken ConnectionClosed { get; set; } - public override EndPoint LocalEndPoint { get; set; } - public override EndPoint RemoteEndPoint { get; set; } + public override EndPoint? LocalEndPoint { get; set; } + public override EndPoint? RemoteEndPoint { get; set; } public override void Abort(ConnectionAbortedException abortReason) { - ThreadPool.UnsafeQueueUserWorkItem(cts => ((CancellationTokenSource)cts).Cancel(), _connectionClosedTokenSource); + ThreadPool.UnsafeQueueUserWorkItem(cts => ((CancellationTokenSource)cts!).Cancel(), _connectionClosedTokenSource); } public override ValueTask DisposeAsync() diff --git a/src/Servers/Connections.Abstractions/src/Features/IConnectionEndpointFeature.cs b/src/Servers/Connections.Abstractions/src/Features/IConnectionEndpointFeature.cs index 7c44146ede79..6b51aa3a390d 100644 --- a/src/Servers/Connections.Abstractions/src/Features/IConnectionEndpointFeature.cs +++ b/src/Servers/Connections.Abstractions/src/Features/IConnectionEndpointFeature.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Connections.Features { public interface IConnectionEndPointFeature { - EndPoint LocalEndPoint { get; set; } - EndPoint RemoteEndPoint { get; set; } + EndPoint? LocalEndPoint { get; set; } + EndPoint? RemoteEndPoint { get; set; } } } diff --git a/src/Servers/Connections.Abstractions/src/Features/IConnectionItemsFeature.cs b/src/Servers/Connections.Abstractions/src/Features/IConnectionItemsFeature.cs index 3d40d5498f53..038383e65ef5 100644 --- a/src/Servers/Connections.Abstractions/src/Features/IConnectionItemsFeature.cs +++ b/src/Servers/Connections.Abstractions/src/Features/IConnectionItemsFeature.cs @@ -7,6 +7,6 @@ namespace Microsoft.AspNetCore.Connections.Features { public interface IConnectionItemsFeature { - IDictionary Items { get; set; } + IDictionary Items { get; set; } } -} \ No newline at end of file +} diff --git a/src/Servers/Connections.Abstractions/src/Features/IConnectionTransportFeature.cs b/src/Servers/Connections.Abstractions/src/Features/IConnectionTransportFeature.cs index 0b218972d70c..7f4fd4f9d623 100644 --- a/src/Servers/Connections.Abstractions/src/Features/IConnectionTransportFeature.cs +++ b/src/Servers/Connections.Abstractions/src/Features/IConnectionTransportFeature.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.IO.Pipelines; @@ -7,6 +7,6 @@ namespace Microsoft.AspNetCore.Connections.Features { public interface IConnectionTransportFeature { - IDuplexPipe Transport { get; set; } + IDuplexPipe? Transport { get; set; } } } diff --git a/src/Servers/Connections.Abstractions/src/Features/IConnectionUserFeature.cs b/src/Servers/Connections.Abstractions/src/Features/IConnectionUserFeature.cs index 7698693a54e0..8e082af24a8a 100644 --- a/src/Servers/Connections.Abstractions/src/Features/IConnectionUserFeature.cs +++ b/src/Servers/Connections.Abstractions/src/Features/IConnectionUserFeature.cs @@ -7,6 +7,6 @@ namespace Microsoft.AspNetCore.Connections.Features { public interface IConnectionUserFeature { - ClaimsPrincipal User { get; set; } + ClaimsPrincipal? User { get; set; } } } diff --git a/src/Servers/Connections.Abstractions/src/Microsoft.AspNetCore.Connections.Abstractions.csproj b/src/Servers/Connections.Abstractions/src/Microsoft.AspNetCore.Connections.Abstractions.csproj index 43f6d4b5748e..8b2e6e253918 100644 --- a/src/Servers/Connections.Abstractions/src/Microsoft.AspNetCore.Connections.Abstractions.csproj +++ b/src/Servers/Connections.Abstractions/src/Microsoft.AspNetCore.Connections.Abstractions.csproj @@ -1,4 +1,4 @@ - + Core components of ASP.NET Core networking protocol stack. @@ -9,8 +9,13 @@ aspnetcore CS1591;$(NoWarn) true + enable + + + + diff --git a/src/Shared/CodeAnalysis/NullableAttributes.cs b/src/Shared/CodeAnalysis/NullableAttributes.cs new file mode 100644 index 000000000000..73f7a4d58d04 --- /dev/null +++ b/src/Shared/CodeAnalysis/NullableAttributes.cs @@ -0,0 +1,85 @@ +// 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. + +namespace System.Diagnostics.CodeAnalysis +{ +#if NETSTANDARD2_0 + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal 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)] + internal 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)] + internal sealed class MaybeNullAttribute : Attribute { } + + /// Specifies that an output will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal 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)] + internal 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)] + internal 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)] + internal 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)] + internal 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)] + internal 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; } + } +#endif +} diff --git a/src/Shared/PropertyHelper/PropertyHelper.cs b/src/Shared/PropertyHelper/PropertyHelper.cs index 334983326438..c36ff159f8c0 100644 --- a/src/Shared/PropertyHelper/PropertyHelper.cs +++ b/src/Shared/PropertyHelper/PropertyHelper.cs @@ -16,19 +16,19 @@ internal class PropertyHelper private delegate TValue ByRefFunc(ref TDeclaringType arg); private static readonly MethodInfo CallPropertyGetterOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter)); + typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter))!; private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetterByReference)); + typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetterByReference))!; private static readonly MethodInfo CallNullSafePropertyGetterOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetter)); + typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetter))!; private static readonly MethodInfo CallNullSafePropertyGetterByReferenceOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetterByReference)); + typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetterByReference))!; private static readonly MethodInfo CallPropertySetterOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter)); + typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter))!; // Using an array rather than IEnumerable, as target will be called on the hot path numerous times. private static readonly ConcurrentDictionary PropertiesCache = @@ -41,10 +41,10 @@ internal class PropertyHelper // for platforms where the attribute is not defined, like net46. So we can fetch the attribute // by late binding. If the attribute isn't defined, then we assume we won't encounter any // 'ref struct' types. - private static readonly Type IsByRefLikeAttribute = Type.GetType("System.Runtime.CompilerServices.IsByRefLikeAttribute", throwOnError: false); + private static readonly Type? IsByRefLikeAttribute = Type.GetType("System.Runtime.CompilerServices.IsByRefLikeAttribute", throwOnError: false); - private Action _valueSetter; - private Func _valueGetter; + private Action? _valueSetter; + private Func? _valueGetter; /// /// Initializes a fast . @@ -243,7 +243,7 @@ private static Func MakeFastPropertyGetter( // Instance methods in the CLR can be turned into static methods where the first parameter // is open over "target". This parameter is always passed by reference, so we have a code // path for value types and a code path for reference types. - if (getMethod.DeclaringType.GetTypeInfo().IsValueType) + if (getMethod.DeclaringType!.GetTypeInfo().IsValueType) { // Create a delegate (ref TDeclaringType) -> TValue return MakeFastPropertyGetter( @@ -266,7 +266,7 @@ private static Func MakeFastPropertyGetter( MethodInfo propertyGetMethod, MethodInfo openGenericWrapperMethod) { - var typeInput = propertyGetMethod.DeclaringType; + var typeInput = propertyGetMethod.DeclaringType!; var typeOutput = propertyGetMethod.ReturnType; var delegateType = openGenericDelegateType.MakeGenericType(typeInput, typeOutput); @@ -292,7 +292,7 @@ private static Func MakeFastPropertyGetter( public static Action MakeFastPropertySetter(PropertyInfo propertyInfo) { Debug.Assert(propertyInfo != null); - Debug.Assert(!propertyInfo.DeclaringType.GetTypeInfo().IsValueType); + Debug.Assert(!propertyInfo.DeclaringType!.GetTypeInfo().IsValueType); var setMethod = propertyInfo.SetMethod; Debug.Assert(setMethod != null); @@ -304,7 +304,7 @@ public static Action MakeFastPropertySetter(PropertyInfo propert // Instance methods in the CLR can be turned into static methods where the first parameter // is open over "target". This parameter is always passed by reference, so we have a code // path for value types and a code path for reference types. - var typeInput = setMethod.DeclaringType; + var typeInput = setMethod.DeclaringType!; var parameterType = parameters[0].ParameterType; // Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; } @@ -357,7 +357,7 @@ private static PropertyHelper CreateInstance(PropertyInfo property) } // Called via reflection - private static object CallPropertyGetter( + private static object? CallPropertyGetter( Func getter, object target) { @@ -365,7 +365,7 @@ private static object CallPropertyGetter( } // Called via reflection - private static object CallPropertyGetterByReference( + private static object? CallPropertyGetterByReference( ByRefFunc getter, object target) { @@ -374,7 +374,7 @@ private static object CallPropertyGetterByReference( } // Called via reflection - private static object CallNullSafePropertyGetter( + private static object? CallNullSafePropertyGetter( Func getter, object target) { @@ -387,7 +387,7 @@ private static object CallNullSafePropertyGetter( } // Called via reflection - private static object CallNullSafePropertyGetterByReference( + private static object? CallNullSafePropertyGetterByReference( ByRefFunc getter, object target) { @@ -455,8 +455,8 @@ protected static PropertyHelper[] GetVisibleProperties( // Walk up the hierarchy until we find the type that actually declares this // PropertyInfo. - var currentTypeInfo = type.GetTypeInfo(); - var declaringTypeInfo = declaringType.GetTypeInfo(); + TypeInfo? currentTypeInfo = type.GetTypeInfo(); + var declaringTypeInfo = declaringType?.GetTypeInfo(); while (currentTypeInfo != null && currentTypeInfo != declaringTypeInfo) { // We've found a 'more proximal' public definition diff --git a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj index 1e41510bfbe0..64fb1bae266b 100644 --- a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj +++ b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj @@ -4,6 +4,7 @@ $(DefaultNetCoreTargetFramework) portable true + annotations