From b0d1d4aaa01082b508193220baae2e2f60cf1f16 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 20 Mar 2024 15:23:32 +0100 Subject: [PATCH 01/17] Added some nullability and notnull annotations --- src/Hl7.Fhir.Base/ElementModel/Types/Any.cs | 5 +- .../ElementModel/Types/Boolean.cs | 3 +- src/Hl7.Fhir.Base/ElementModel/Types/Code.cs | 3 +- .../ElementModel/Types/Concept.cs | 3 +- src/Hl7.Fhir.Base/ElementModel/Types/Date.cs | 3 +- .../ElementModel/Types/DateTime.cs | 3 +- .../ElementModel/Types/Decimal.cs | 3 +- .../ElementModel/Types/Integer.cs | 5 +- src/Hl7.Fhir.Base/ElementModel/Types/Long.cs | 3 +- .../ElementModel/Types/Quantity.cs | 3 +- src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs | 3 +- .../ElementModel/Types/String.cs | 3 +- src/Hl7.Fhir.Base/ElementModel/Types/Time.cs | 3 +- .../Introspection/ClassMapping.cs | 3 +- .../Introspection/EnumMapping.cs | 3 +- .../Introspection/EnumMemberMapping.cs | 3 +- .../Introspection/PropertyMapping.cs | 3 +- src/Hl7.Fhir.Base/Model/Date.cs | 5 +- src/Hl7.Fhir.Base/Model/Extension.cs | 13 +- src/Hl7.Fhir.Base/Model/FhirDateTime.cs | 7 +- src/Hl7.Fhir.Base/Model/PrimitiveType.cs | 3 +- src/Hl7.Fhir.Base/Model/Time.cs | 9 +- .../Utility/FhirReleaseParser.cs | 5 +- .../Utility/NullableAttribute.cs | 208 ++++++++++++++++++ src/Hl7.Fhir.Base/Utility/SemVersion.cs | 3 +- .../Source/Summary/ArtifactSummary.cs | 2 +- .../Source/Summary/ArtifactSummary.cs | 13 +- .../Model/TimeTests.cs | 4 +- .../ElementModel/QuantityTests.cs | 6 +- 29 files changed, 284 insertions(+), 49 deletions(-) create mode 100644 src/Hl7.Fhir.Base/Utility/NullableAttribute.cs diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs index 16bec51789..193b902c69 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; namespace Hl7.Fhir.ElementModel.Types { @@ -56,7 +57,7 @@ public static object Parse(string value, Type primitiveType) throw new FormatException($"Input string '{value}' was not in a correct format for type '{primitiveType}'."); } - public static bool TryParse(string value, Type primitiveType, out object? parsed) + public static bool TryParse(string value, Type primitiveType, [NotNullWhen(true)]out object? parsed) { if (value == null) throw new ArgumentNullException(nameof(value)); if (!typeof(Any).IsAssignableFrom(primitiveType)) throw new ArgumentException($"Must be a subclass of {nameof(Any)}.", nameof(primitiveType)); @@ -111,7 +112,7 @@ internal static (bool, T?) DoConvert(Func parser) /// /// Try to convert a .NET instance to a Cql/FhirPath Any-based type. /// - public static bool TryConvert(object value, out Any? primitiveValue) + public static bool TryConvert(object value, [NotNullWhen(true)]out Any? primitiveValue) { primitiveValue = conv(); return primitiveValue != null; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs index 75c55467eb..63319d26c3 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using static Hl7.Fhir.Utility.Result; namespace Hl7.Fhir.ElementModel.Types @@ -29,7 +30,7 @@ public Boolean() : this(default) { } public static Boolean Parse(string value) => TryParse(value, out var result) ? result! : throw new FormatException($"String '{value}' was not recognized as a valid boolean."); - public static bool TryParse(string representation, out Boolean? value) + public static bool TryParse(string representation, [NotNullWhen(true)]out Boolean? value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs index e422779836..56851f7d0c 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using static Hl7.Fhir.Utility.Result; namespace Hl7.Fhir.ElementModel.Types @@ -30,7 +31,7 @@ public Code(string? system, string code, string? display = null, string? version public string? Version { get; } public static Code Parse(string value) => throw new NotImplementedException(); - public static bool TryParse(string representation, out Code? value) => throw new NotImplementedException(); + public static bool TryParse(string representation, [NotNullWhen(true)]out Code? value) => throw new NotImplementedException(); public override int GetHashCode() => (System, Value, Display, Version).GetHashCode(); public override string ToString() => $"{Value}@{System} " + Display ?? ""; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs index 0e65125b71..90edf34208 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs @@ -11,6 +11,7 @@ using Hl7.Fhir.Utility; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using static Hl7.Fhir.Utility.Result; @@ -30,7 +31,7 @@ public Concept(IEnumerable codes, string? display = null) public string? Display { get; } public static Concept Parse(string representation) => throw new NotImplementedException(); - public static bool TryParse(string representation, out Concept? value) => throw new NotImplementedException(); + public static bool TryParse(string representation, [NotNullWhen(true)]out Concept? value) => throw new NotImplementedException(); public override bool Equals(object? obj) => obj is Concept c && Enumerable.SequenceEqual(Codes, c.Codes) && Display == c.Display; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs index b6237c71c6..b3acf52f03 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; using static Hl7.Fhir.Utility.Result; @@ -29,7 +30,7 @@ private Date(DateTimeOffset value, DateTimePrecision precision, bool hasOffset) public static Date Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid date."); - public static bool TryParse(string representation, out Date value) => tryParse(representation, out value); + public static bool TryParse(string representation, [NotNullWhen(true)]out Date? value) => tryParse(representation, out value); public static Date FromDateTimeOffset(DateTimeOffset dto, DateTimePrecision prec = DateTimePrecision.Day, bool includeOffset = false) => new(dto, prec, includeOffset); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs index bd69f84f6b..c79ad78aaa 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.RegularExpressions; using static Hl7.Fhir.Utility.Result; @@ -28,7 +29,7 @@ private DateTime(DateTimeOffset value, DateTimePrecision precision, bool include public static DateTime Parse(string representation) => TryParse(representation, out var result) ? result! : throw new FormatException($"String '{representation}' was not recognized as a valid datetime."); - public static bool TryParse(string representation, out DateTime value) => tryParse(representation, out value); + public static bool TryParse(string representation, [NotNullWhen(true)]out DateTime? value) => tryParse(representation, out value); /// /// Rounds the contents of a to the given precision, unused precision if filled out diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs index 3c6c31fc81..e190b77b9d 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Xml; @@ -32,7 +33,7 @@ public Decimal() : this(default) { } public static Decimal Parse(string value) => TryParse(value, out var result) ? result! : throw new FormatException($"String '{value}' was not recognized as a valid decimal."); - public static bool TryParse(string representation, out Decimal? value) + public static bool TryParse(string representation, [NotNullWhen(true)]out Decimal? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs index 024119b347..2088bde0a2 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Xml; using static Hl7.Fhir.Utility.Result; @@ -26,11 +27,11 @@ public Integer() : this(default) { } public static Integer Parse(string value) => TryParse(value, out var result) ? result : throw new FormatException($"String '{value}' was not recognized as a valid integer."); - public static bool TryParse(string representation, out Integer value) + public static bool TryParse(string representation, [NotNullWhen(true)]out Integer? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); - (var succ, var val) = Any.DoConvert(() => XmlConvert.ToInt32(representation)); + var (succ, val) = DoConvert(() => XmlConvert.ToInt32(representation)); value = new Integer(val); return succ; } diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs index 6f343eb298..a30a32fa84 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Xml; using static Hl7.Fhir.Utility.Result; @@ -26,7 +27,7 @@ public Long() : this(default) { } public static Long Parse(string value) => TryParse(value, out var result) ? result : throw new FormatException($"String '{value}' was not recognized as a valid long integer."); - public static bool TryParse(string representation, out Long value) + public static bool TryParse(string representation, [NotNullWhen(true)]out Long? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs index a6856ab0d3..d3fcfb6cea 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs @@ -11,6 +11,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.RegularExpressions; using static Hl7.Fhir.Utility.Result; @@ -83,7 +84,7 @@ public static Quantity ForCalendarDuration(decimal value, string calendarUnit) public static Quantity Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid quantity."); - public static bool TryParse(string representation, out Quantity quantity) + public static bool TryParse(string representation, [NotNullWhen(true)]out Quantity? quantity) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs index 6bf504fe66..0c7109e02e 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using static Hl7.Fhir.Utility.Result; namespace Hl7.Fhir.ElementModel.Types @@ -27,7 +28,7 @@ public Ratio(Quantity numerator, Quantity denominator) public static Ratio Parse(string representation) => TryParse(representation, out var result) ? result! : throw new FormatException($"String '{representation}' was not recognized as a valid ratio."); - public static bool TryParse(string representation, out Ratio? value) + public static bool TryParse(string representation, [NotNullWhen(true)]out Ratio? value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs index b171aac54f..70621aa939 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using static Hl7.Fhir.Utility.Result; @@ -28,7 +29,7 @@ public static String Parse(string value) => // Actually, it's not that trivial, since CQL strings accept a subset of C#'s escape sequences, // we *could* validate those here. - public static bool TryParse(string representation, out String value) + public static bool TryParse(string representation, [NotNullWhen(true)]out String? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs index 6cdcf0dc7e..79a75387b8 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.RegularExpressions; using static Hl7.Fhir.Utility.Result; @@ -30,7 +31,7 @@ private Time(DateTimeOffset parsedValue, DateTimePrecision precision, bool hasOf public static Time Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid time."); - public static bool TryParse(string representation, out Time value) => tryParse(representation, out value); + public static bool TryParse(string representation, [NotNullWhen(true)]out Time? value) => tryParse(representation, out value); public static Time FromDateTimeOffset(DateTimeOffset dto, DateTimePrecision prec = DateTimePrecision.Fraction, bool includeOffset = false) => new(dto, prec, includeOffset); diff --git a/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs b/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs index d04006849f..0996f5ca5e 100644 --- a/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs @@ -16,6 +16,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Threading; @@ -53,7 +54,7 @@ public static bool TryGetMappingForType(Type t, FhirRelease release, out ClassMa /// /// For classes shared across FHIR versions, there may be metadata present for different versions /// of FHIR, the is used to select which subset of metadata to extract. - public static bool TryCreate(Type type, out ClassMapping? result, FhirRelease release = (FhirRelease)int.MaxValue) + public static bool TryCreate(Type type, [NotNullWhen(true)]out ClassMapping? result, FhirRelease release = (FhirRelease)int.MaxValue) { // Simulate reading the ClassMappings from the primitive types (from http://hl7.org/fhirpath namespace). // These are in fact defined as POCOs in Hl7.Fhir.ElementModel.Types, diff --git a/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs b/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs index 7b591d424e..7d3892d76b 100644 --- a/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace Hl7.Fhir.Introspection @@ -48,7 +49,7 @@ public static bool TryGetMappingForEnum(Type t, FhirRelease release, out EnumMap /// /// For classes shared across FHIR versions, there may be metadata present for different versions /// of FHIR, the is used to select which subset of metadata to extract. - public static bool TryCreate(Type type, out EnumMapping? result, FhirRelease release = (FhirRelease)int.MaxValue) + public static bool TryCreate(Type type, [NotNullWhen(true)]out EnumMapping? result, FhirRelease release = (FhirRelease)int.MaxValue) { result = default; if (!type.IsEnum) return false; diff --git a/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs b/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs index 4d9dcd523c..b6b74739f4 100644 --- a/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs @@ -11,6 +11,7 @@ using Hl7.Fhir.Specification; using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace Hl7.Fhir.Introspection @@ -57,7 +58,7 @@ private EnumMemberMapping(FieldInfo fieldInfo, string code, string? system, obje /// /// Inspects the given enum member, extracting metadata from its attributes and creating a new . /// - public static bool TryCreate(FieldInfo member, out EnumMemberMapping? result, FhirRelease release = (FhirRelease)int.MaxValue, string? defaultSystem = null) + public static bool TryCreate(FieldInfo member, [NotNullWhen(true)]out EnumMemberMapping? result, FhirRelease release = (FhirRelease)int.MaxValue, string? defaultSystem = null) { result = null; if (ClassMapping.GetAttribute(member, release) is not { } ela) return false; diff --git a/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs b/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs index 0c3378debb..b002e32bcc 100644 --- a/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs @@ -11,6 +11,7 @@ using Hl7.Fhir.Validation; using System; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Threading; @@ -172,7 +173,7 @@ private PropertyMapping( /// /// There should generally be no reason to call this method, as you can easily get the required PropertyMapping via /// a ClassMapping - which will cache this information as well. This constructor is public for historical reasons only. - public static bool TryCreate(PropertyInfo prop, out PropertyMapping? result, ClassMapping declaringClass, FhirRelease release) + public static bool TryCreate(PropertyInfo prop, [NotNullWhen(true)]out PropertyMapping? result, ClassMapping declaringClass, FhirRelease release) { if (prop == null) throw Error.ArgumentNull(nameof(prop)); result = default; diff --git a/src/Hl7.Fhir.Base/Model/Date.cs b/src/Hl7.Fhir.Base/Model/Date.cs index a381d4feb7..7cbceba5e8 100644 --- a/src/Hl7.Fhir.Base/Model/Date.cs +++ b/src/Hl7.Fhir.Base/Model/Date.cs @@ -29,6 +29,7 @@ POSSIBILITY OF SUCH DAMAGE. */ using System; +using System.Diagnostics.CodeAnalysis; using P = Hl7.Fhir.ElementModel.Types; #nullable enable @@ -75,7 +76,7 @@ public Date(int year) : this(string.Format(System.Globalization.CultureInfo.Inva /// Converts a Fhir Date to a . /// /// true if the Fhir Date contains a valid date string, false otherwise. - public bool TryToDate(out P.Date? date) + public bool TryToDate([NotNullWhen(true)]out P.Date? date) { if (_parsedValue is null) { @@ -90,7 +91,7 @@ public bool TryToDate(out P.Date? date) } else { - date = _parsedValue; + date = _parsedValue!; return true; } diff --git a/src/Hl7.Fhir.Base/Model/Extension.cs b/src/Hl7.Fhir.Base/Model/Extension.cs index b525637dce..d020f5d339 100644 --- a/src/Hl7.Fhir.Base/Model/Extension.cs +++ b/src/Hl7.Fhir.Base/Model/Extension.cs @@ -28,12 +28,15 @@ POSSIBILITY OF SUCH DAMAGE. */ +#nullable enable + using Hl7.Fhir.Introspection; using Hl7.Fhir.Specification; using Hl7.Fhir.Validation; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization; using SystemPrimitive = Hl7.Fhir.ElementModel.Types; @@ -69,26 +72,26 @@ public Extension(string url, DataType value) [Cardinality(Min = 1, Max = 1)] [UriPattern] [DataMember] - public string Url + public string? Url { get { return _Url; } set { _Url = value; OnPropertyChanged("Url"); } } - private string _Url; + private string? _Url; /// /// Value of extension /// [FhirElement("value", InSummary = true, Order = 40, Choice = ChoiceType.DatatypeChoice)] [DataMember] - public Hl7.Fhir.Model.DataType Value + public DataType? Value { get { return _Value; } set { _Value = value; OnPropertyChanged("Value"); } } - private Hl7.Fhir.Model.DataType _Value; + private DataType? _Value; public override IDeepCopyable CopyTo(IDeepCopyable other) { @@ -155,7 +158,7 @@ public override IEnumerable NamedChildren } } - protected override bool TryGetValue(string key, out object value) + protected override bool TryGetValue(string key, [NotNullWhen(true)]out object? value) { switch (key) { diff --git a/src/Hl7.Fhir.Base/Model/FhirDateTime.cs b/src/Hl7.Fhir.Base/Model/FhirDateTime.cs index 86c18fad5d..8a3d962a59 100644 --- a/src/Hl7.Fhir.Base/Model/FhirDateTime.cs +++ b/src/Hl7.Fhir.Base/Model/FhirDateTime.cs @@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. using Hl7.Fhir.Serialization; using System; +using System.Diagnostics.CodeAnalysis; using P = Hl7.Fhir.ElementModel.Types; namespace Hl7.Fhir.Model @@ -97,7 +98,7 @@ public FhirDateTime(int year) /// Converts a FhirDateTime to a . /// /// true if the FhirDateTime contains a valid date/time string, false otherwise. - public bool TryToDateTime(out P.DateTime? dateTime) + public bool TryToDateTime([NotNullWhen(true)]out P.DateTime? dateTime) { if (_parsedValue is null) { @@ -112,7 +113,7 @@ public bool TryToDateTime(out P.DateTime? dateTime) } else { - dateTime = _parsedValue; + dateTime = _parsedValue!; return true; } @@ -124,7 +125,7 @@ public bool TryToDateTime(out P.DateTime? dateTime) /// /// The DateTime, or null if the is null. /// Thrown when the Value does not contain a valid FHIR DateTime. - public P.DateTime? ToDateTime() => TryToDateTime(out var dt) ? dt : throw new FormatException($"String '{Value}' was not recognized as a valid datetime."); + public P.DateTime ToDateTime() => TryToDateTime(out var dt) ? dt : throw new FormatException($"String '{Value}' was not recognized as a valid datetime."); protected override void OnObjectValueChanged() { diff --git a/src/Hl7.Fhir.Base/Model/PrimitiveType.cs b/src/Hl7.Fhir.Base/Model/PrimitiveType.cs index fdf9f180a6..96196e6047 100644 --- a/src/Hl7.Fhir.Base/Model/PrimitiveType.cs +++ b/src/Hl7.Fhir.Base/Model/PrimitiveType.cs @@ -12,6 +12,7 @@ using Hl7.Fhir.Serialization; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.Serialization; @@ -113,7 +114,7 @@ public override bool IsExactly(IDeepComparable other) public override IEnumerable NamedChildren => base.NamedChildren; /// - protected override bool TryGetValue(string key, out object? value) + protected override bool TryGetValue(string key, [NotNullWhen(true)]out object? value) { if (key == "value") { diff --git a/src/Hl7.Fhir.Base/Model/Time.cs b/src/Hl7.Fhir.Base/Model/Time.cs index c67e35ef8d..72e07941df 100644 --- a/src/Hl7.Fhir.Base/Model/Time.cs +++ b/src/Hl7.Fhir.Base/Model/Time.cs @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. #nullable enable using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using P = Hl7.Fhir.ElementModel.Types; @@ -68,7 +69,7 @@ public Time(int hour, int minute, int second) : this(string.Format(CultureInfo.I /// Converts a Fhir Time to a . /// /// true if the Fhir Time contains a valid time string, false otherwise. - public bool TryToTime(out P.Time? time) + public bool TryToTime([NotNullWhen(true)]out P.Time? time) { if (_parsedValue is null) { @@ -83,7 +84,7 @@ public bool TryToTime(out P.Time? time) } else { - time = _parsedValue; + time = _parsedValue!; return true; } @@ -95,7 +96,7 @@ public bool TryToTime(out P.Time? time) /// /// The Time, or null if the is null. /// Thrown when the Value does not contain a valid FHIR Time. - public P.Time? ToTime() => TryToTime(out var dt) ? dt : throw new FormatException($"String '{Value}' was not recognized as a valid time."); + public P.Time ToTime() => TryToTime(out var dt) ? dt : throw new FormatException($"String '{Value}' was not recognized as a valid time."); protected override void OnObjectValueChanged() { @@ -114,7 +115,7 @@ protected override void OnObjectValueChanged() /// Convert this FhirDateTime to a . /// /// True if the value of the Fhir Time is not null and can be parsed as a Time without an offset, false otherwise. - public bool TryToTimeSpan(out TimeSpan dto) + public bool TryToTimeSpan([NotNullWhen(true)]out TimeSpan? dto) { if (Value is not null && TryToTime(out var dt) && !dt!.HasOffset) { diff --git a/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs b/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs index 4b71c409ad..5f687ab5f5 100644 --- a/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs +++ b/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs @@ -8,11 +8,10 @@ using Hl7.Fhir.Specification; using System; +using System.Diagnostics.CodeAnalysis; namespace Hl7.Fhir.Utility { - - public class FhirReleaseParser { /// @@ -31,7 +30,7 @@ public static FhirRelease Parse(string version) => /// Fhir Release version number /// Official FHIR Release /// true if the conversion succeeded; false otherwise. - public static bool TryParse(string version, out FhirRelease? release) + public static bool TryParse(string version, [NotNullWhen(true)]out FhirRelease? release) { release = version switch { diff --git a/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs b/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs new file mode 100644 index 0000000000..6e55499c3e --- /dev/null +++ b/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs @@ -0,0 +1,208 @@ +// https://github.com/dotnet/runtime/blob/527f9ae88a0ee216b44d556f9bdc84037fe0ebda/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +#pragma warning disable +#define INTERNAL_NULLABLE_ATTRIBUTES + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Diagnostics.CodeAnalysis +{ +#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class AllowNullAttribute : Attribute + { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DisallowNullAttribute : Attribute + { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullAttribute : Attribute + { } + + /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullAttribute : Attribute + { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnAttribute : Attribute + { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +#endif + +#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_0 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } +#endif +} diff --git a/src/Hl7.Fhir.Base/Utility/SemVersion.cs b/src/Hl7.Fhir.Base/Utility/SemVersion.cs index 689939e4d1..3d709ebb2f 100644 --- a/src/Hl7.Fhir.Base/Utility/SemVersion.cs +++ b/src/Hl7.Fhir.Base/Utility/SemVersion.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; #if NET452 using System.Runtime.Serialization; @@ -118,7 +119,7 @@ public static SemVersion Parse(string version, bool strict = false) /// If set to minor and patch version are required, /// otherwise they are optional. /// when a invalid version string is passed, otherwise . - public static bool TryParse(string version, out SemVersion semver, bool strict = false) + public static bool TryParse(string version, [NotNullWhen(true)]out SemVersion semver, bool strict = false) { semver = null; if (version is null) return false; diff --git a/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs b/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs index 00b7afb215..cd2834e621 100644 --- a/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs +++ b/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs @@ -171,7 +171,7 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, IModelInfo modelI /// Gets the property value associated with the specified property key. #pragma warning disable CS8767 - public bool TryGetValue(string key, out object? value) => properties.TryGetValue(key, out value); + public bool TryGetValue(string key, [NotNullWhen(true)]out object? value) => properties.TryGetValue(key, out value); #pragma warning restore CS8767 #endregion diff --git a/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs b/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs index fba99285f0..e0da7b0548 100644 --- a/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs +++ b/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs @@ -6,6 +6,8 @@ * available at https://github.com/FirelyTeam/firely-net-sdk/blob/master/LICENSE */ +#nullable enable + using Hl7.Fhir.Model; using Hl7.Fhir.Serialization; using Hl7.Fhir.Specification.Summary; @@ -14,6 +16,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Collections; +using System.Diagnostics.CodeAnalysis; namespace Hl7.Fhir.Specification.Source { @@ -52,7 +55,7 @@ public class ArtifactSummary : IArtifactSummaryPropertyBag /// Create a new instance from the specified exception. /// An exception that occured while harvesting artifact summary information. /// The original location of the target artifact. - public static ArtifactSummary FromException(Exception error, string origin) + public static ArtifactSummary FromException(Exception error, string? origin) { if (error == null) { throw Errors.ArgumentNull(nameof(error)); } // Create a new (default) ArtifactSummaryPropertyBag to store the artifact origin @@ -76,7 +79,7 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties) : this(properties /// Create a new instance from a set of harvested artifact summary properties /// and a runtime exception that occured during harvesting. /// - public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception error) + public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception? error) { this.properties = properties ?? throw Errors.ArgumentNull(nameof(properties)); this.Error = error; @@ -94,7 +97,7 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception error) #region Properties /// Returns information about errors that occured while generating the artifact summary. - public Exception Error { get; } + public Exception? Error { get; } /// Indicates if any errors occured while generating the artifact summary. /// If true, then the property returns detailed error information. @@ -171,7 +174,7 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception error) public bool ContainsKey(string key) => properties.ContainsKey(key); /// Gets the property value associated with the specified property key. - public bool TryGetValue(string key, out object value) => properties.TryGetValue(key, out value); + public bool TryGetValue(string key, [NotNullWhen(true)]out object? value) => properties.TryGetValue(key, out value); #endregion @@ -180,6 +183,6 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception error) [DebuggerBrowsable(DebuggerBrowsableState.Never)] protected virtual string DebuggerDisplay => $"{GetType().Name} for {ResourceTypeName} | Origin: {Origin}" - + (IsFaulted ? " | Error: " + Error.Message : string.Empty); + + (IsFaulted ? " | Error: " + Error!.Message : string.Empty); } } \ No newline at end of file diff --git a/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs b/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs index 74a907862c..5f7ec59981 100644 --- a/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs +++ b/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs @@ -64,13 +64,13 @@ public void UpdatesCachedValue() dft.Value = "01:02"; dft.TryToTimeSpan(out dto).Should().BeTrue(); - dto.Hours.Should().Be(1); + dto!.Value.Hours.Should().Be(1); dft.TryToTimeSpan(out dto2).Should().BeTrue(); dto.Equals(dto2).Should().BeTrue(); dft.ObjectValue = "18:23:34"; dft.TryToTimeSpan(out dto).Should().BeTrue(); - dto.Minutes.Should().Be(23); + dto!.Value.Minutes.Should().Be(23); dft.TryToTimeSpan(out dto2).Should().BeTrue(); dto.Equals(dto2).Should().BeTrue(); diff --git a/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs b/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs index 71fdde70fb..f84a7b1886 100644 --- a/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs +++ b/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs @@ -126,10 +126,10 @@ public enum Comparison public void QuantityCompareTests(string left, string right, Comparison expectedResult, bool shouldThrowException = false) { - P.Quantity.TryParse(left, out var a); - P.Quantity.TryParse(right, out var b); + Quantity.TryParse(left, out var a); + Quantity.TryParse(right, out var b); - Func func = () => a.CompareTo(b); + Func func = () => a!.CompareTo(b); if (shouldThrowException) { From 47148d28816819df4fe23de30c3dd7f771c60c3c Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 20 Mar 2024 16:19:13 +0100 Subject: [PATCH 02/17] more nullability --- src/Hl7.Fhir.Base/ElementModel/DomNode.cs | 22 +++--- src/Hl7.Fhir.Base/ElementModel/ElementNode.cs | 71 +++++++++++-------- .../ElementModel/IBaseElementNavigator.cs | 6 +- .../ElementModel/PrimitiveElement.cs | 4 +- src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs | 4 +- src/Hl7.Fhir.Base/ElementModel/Types/Any.cs | 6 +- src/Hl7.Fhir.Base/ElementModel/Types/Date.cs | 2 +- .../ElementModel/Types/DateTime.cs | 2 +- .../ElementModel/Types/Quantity.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Time.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs | 3 +- .../FhirPath/ElementNavFhirExtensions.cs | 4 +- .../ScopedNodeTests.cs | 4 +- .../ElementModel/QuantityTests.cs | 2 +- 14 files changed, 73 insertions(+), 61 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/DomNode.cs b/src/Hl7.Fhir.Base/ElementModel/DomNode.cs index 71fdeff3c5..a9c7fcbb21 100644 --- a/src/Hl7.Fhir.Base/ElementModel/DomNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/DomNode.cs @@ -6,6 +6,8 @@ * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE */ +#nullable enable + using Hl7.Fhir.Utility; using System; using System.Collections.Generic; @@ -16,39 +18,39 @@ namespace Hl7.Fhir.ElementModel { public class DomNode : IAnnotatable where T : DomNode { - public string Name { get; set; } + public string Name { get; set; } = null!; - private List _childList = null; + private List? _childList = null; protected List ChildList { - get => LazyInitializer.EnsureInitialized(ref _childList, () => new()); + get => LazyInitializer.EnsureInitialized(ref _childList, () => new()) ?? throw new InvalidOperationException(); set => _childList = value; } - internal IEnumerable ChildrenInternal(string name = null) => + internal IEnumerable ChildrenInternal(string? name = null) => name == null ? ChildList : ChildList.Where(c => c.Name.MatchesPrefix(name)); - public T Parent { get; protected set; } + public T? Parent { get; protected set; } public DomNodeList this[string name] => new DomNodeList(ChildrenInternal(name)); - public T this[int index] => ChildList[index]; + public T? this[int index] => ChildList?[index]; #region << Annotations >> - private AnnotationList _annotations = null; - protected AnnotationList AnnotationsInternal => LazyInitializer.EnsureInitialized(ref _annotations, () => new()); + private AnnotationList? _annotations = null; + protected AnnotationList? AnnotationsInternal => LazyInitializer.EnsureInitialized(ref _annotations, () => new()); protected bool HasAnnotations => _annotations is not null && !_annotations.IsEmpty; public void AddAnnotation(object annotation) { - AnnotationsInternal.AddAnnotation(annotation); + AnnotationsInternal!.AddAnnotation(annotation); } public void RemoveAnnotations(Type type) { - AnnotationsInternal.RemoveAnnotations(type); + AnnotationsInternal!.RemoveAnnotations(type); } #endregion } diff --git a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs index 523ede5594..4341f8473b 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs @@ -6,10 +6,13 @@ * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE */ +#nullable enable + using Hl7.Fhir.Specification; using Hl7.Fhir.Utility; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using P = Hl7.Fhir.ElementModel.Types; @@ -26,7 +29,7 @@ public class ElementNode : DomNode, ITypedElement, IAnnotated, IAnn // HACK: For now, allow a Quantity (which is NOT a primitive) in the .Value property // of ITypedElement. This is a temporary situation to make a quick & dirty upgrade of // FP to Normative (with Quantity support) possible. - public static ITypedElement ForPrimitive(object value) + public static ITypedElement ForPrimitive(object? value) { return value switch { @@ -42,12 +45,12 @@ public static ITypedElement ForPrimitive(object value) /// /// /// - public static bool TryConvertToElementValue(object value, out object primitiveValue) + public static bool TryConvertToElementValue(object? value, [NotNullWhen(true)] out object? primitiveValue) { primitiveValue = conv(); return primitiveValue != null; - object conv() + object? conv() { // NOTE: Keep Any.TryConvertToSystemValue, TypeSpecifier.TryGetNativeType and TypeSpecifier.ForNativeType in sync switch (value) @@ -89,13 +92,14 @@ object conv() /// /// /// - public static IEnumerable CreateList(params object[] values) => + public static IEnumerable CreateList(params object[]? values) => values != null - ? values.Select(value => value == null - ? null - : value is ITypedElement element - ? element - : ForPrimitive(value)) + ? values.Select(value => value switch + { + null => null, + ITypedElement element => element, + _ => ForPrimitive(value) + }) : EmptyList; /// @@ -104,14 +108,19 @@ public static IEnumerable CreateList(params object[] values) => /// /// /// - public static IEnumerable CreateList(IEnumerable values) => values != null - ? values.Select(value => value == null ? null : value is ITypedElement element ? element : ForPrimitive(value)) + public static IEnumerable CreateList(IEnumerable? values) => values != null + ? values.Select(value => value switch + { + null => null, + ITypedElement element => element, + _ => ForPrimitive(value) + }) : EmptyList; public static readonly IEnumerable EmptyList = Enumerable.Empty(); - public IEnumerable Children(string name = null) => ChildrenInternal(name); + public IEnumerable Children(string? name = null) => ChildrenInternal(name); - internal ElementNode(string name, object value, string instanceType, IElementDefinitionSummary definition) + internal ElementNode(string name, object? value, string? instanceType, IElementDefinitionSummary? definition) { Name = name ?? throw new ArgumentNullException(nameof(name)); InstanceType = instanceType; @@ -119,16 +128,16 @@ internal ElementNode(string name, object value, string instanceType, IElementDef Definition = definition; } - private IReadOnlyCollection _childDefinitions = null; + private IReadOnlyCollection _childDefinitions = Array.Empty(); private IReadOnlyCollection getChildDefinitions(IStructureDefinitionSummaryProvider provider) { - LazyInitializer.EnsureInitialized(ref _childDefinitions, () => this.ChildDefinitions(provider)); + LazyInitializer.EnsureInitialized>(ref _childDefinitions, () => this.ChildDefinitions(provider)); return _childDefinitions; } - public ElementNode Add(IStructureDefinitionSummaryProvider provider, ElementNode child, string name = null) + public ElementNode Add(IStructureDefinitionSummaryProvider provider, ElementNode child, string? name = null) { if (provider == null) throw new ArgumentNullException(nameof(provider)); if (child == null) throw new ArgumentNullException(nameof(child)); @@ -137,7 +146,7 @@ public ElementNode Add(IStructureDefinitionSummaryProvider provider, ElementNode return child; } - public ElementNode Add(IStructureDefinitionSummaryProvider provider, string name, object value = null, string instanceType = null) + public ElementNode Add(IStructureDefinitionSummaryProvider provider, string name, object? value = null, string? instanceType = null) { if (provider == null) throw new ArgumentNullException(nameof(provider)); if (name == null) throw new ArgumentNullException(nameof(name)); @@ -172,7 +181,7 @@ public void Replace(IStructureDefinitionSummaryProvider provider, ElementNode ol /// /// Will update the child to reflect it being a child of this element, but will not yet add the child at any position within this element /// - private void importChild(IStructureDefinitionSummaryProvider provider, ElementNode child, string name, int? position = null) + private void importChild(IStructureDefinitionSummaryProvider provider, ElementNode child, string? name, int? position = null) { child.Name = name ?? child.Name; if (child.Name == null) throw Error.Argument($"The ElementNode given should have its Name property set or the '{nameof(name)}' parameter should be given."); @@ -185,7 +194,7 @@ private void importChild(IStructureDefinitionSummaryProvider provider, ElementNo // we think it should be - this way you can safely first create a node representing // an independently created root for a resource of datatype, and then add it to the tree. var childDefs = getChildDefinitions(provider ?? throw Error.ArgumentNull(nameof(provider))); - var childDef = childDefs.Where(cd => cd.ElementName == child.Name).SingleOrDefault(); + var childDef = childDefs?.SingleOrDefault(cd => cd.ElementName == child.Name); child.Definition = childDef ?? child.Definition; // if we don't know about the definition, stick with the old one (if any) @@ -220,13 +229,13 @@ private void importChild(IStructureDefinitionSummaryProvider provider, ElementNo } - public static ElementNode Root(IStructureDefinitionSummaryProvider provider, string type, string name = null, object value = null) + public static ElementNode Root(IStructureDefinitionSummaryProvider provider, string type, string? name = null, object? value = null) { if (provider == null) throw Error.ArgumentNull(nameof(provider)); if (type == null) throw Error.ArgumentNull(nameof(type)); var sd = provider.Provide(type); - IElementDefinitionSummary definition = null; + IElementDefinitionSummary? definition = null; // Should we throw if type is not found? if (sd != null) @@ -235,13 +244,13 @@ public static ElementNode Root(IStructureDefinitionSummaryProvider provider, str return new ElementNode(name ?? type, value, type, definition); } - public static ElementNode FromElement(ITypedElement node, bool recursive = true, IEnumerable annotationsToCopy = null) + public static ElementNode FromElement(ITypedElement node, bool recursive = true, IEnumerable? annotationsToCopy = null) { if (node == null) throw new ArgumentNullException(nameof(node)); return buildNode(node, recursive, annotationsToCopy, null); } - private static ElementNode buildNode(ITypedElement node, bool recursive, IEnumerable annotationsToCopy, ElementNode parent) + private static ElementNode buildNode(ITypedElement node, bool recursive, IEnumerable? annotationsToCopy, ElementNode? parent) { var me = new ElementNode(node.Name, node.Value, node.InstanceType, node.Definition) { @@ -253,7 +262,7 @@ private static ElementNode buildNode(ITypedElement node, bool recursive, IEnumer me.AddAnnotation(ann); if (recursive) - me.ChildList.AddRange(node.Children().Select(c => buildNode(c, recursive: true, annotationsToCopy: annotationsToCopy, me))); + me.ChildList.AddRange(node.Children()!.Select(c => buildNode(c, recursive: true, annotationsToCopy: annotationsToCopy, me))); return me; } @@ -277,23 +286,23 @@ public ElementNode ShallowCopy() }; if (HasAnnotations) - copy.AnnotationsInternal.AddRange(AnnotationsInternal); + copy.AnnotationsInternal!.AddRange(AnnotationsInternal); return copy; } - public IElementDefinitionSummary Definition { get; private set; } + public IElementDefinitionSummary? Definition { get; private set; } - public string InstanceType { get; private set; } + public string? InstanceType { get; private set; } - public object Value { get; set; } + public object? Value { get; set; } public IEnumerable Annotations(Type type) { if (type == null) throw new ArgumentNullException(nameof(type)); return (type == typeof(ElementNode) || type == typeof(ITypedElement) || type == typeof(IShortPathGenerator)) ? (new[] { this }) - : HasAnnotations ? AnnotationsInternal.OfType(type) : Enumerable.Empty(); + : HasAnnotations ? AnnotationsInternal!.OfType(type) : Enumerable.Empty(); } public string Location @@ -310,7 +319,7 @@ public string Location } else - return Name; + return Name!; } } @@ -333,7 +342,7 @@ public string ShortPath } } else - return Name; + return Name!; } } } diff --git a/src/Hl7.Fhir.Base/ElementModel/IBaseElementNavigator.cs b/src/Hl7.Fhir.Base/ElementModel/IBaseElementNavigator.cs index bf8bf0b69b..8c38a31275 100644 --- a/src/Hl7.Fhir.Base/ElementModel/IBaseElementNavigator.cs +++ b/src/Hl7.Fhir.Base/ElementModel/IBaseElementNavigator.cs @@ -26,7 +26,7 @@ public interface IBaseElementNavigator where TDerived : IBaseElementNa /// /// Return only the children with the given name. /// - IEnumerable Children(string? name = null); + IEnumerable Children(string? name = null); /// /// Name of the node, e.g. "active", "value". @@ -36,7 +36,7 @@ public interface IBaseElementNavigator where TDerived : IBaseElementNa /// /// Type of the node. If a FHIR type, this is just a simple string, otherwise a StructureDefinition url for a type defined as a logical model. /// - string InstanceType { get; } + string? InstanceType { get; } /// /// The value of the node (if it represents a primitive FHIR value) @@ -63,7 +63,7 @@ public interface IBaseElementNavigator where TDerived : IBaseElementNa /// base64Binary string (uuencoded) /// xhtml string /// - object Value { get; } + object? Value { get; } } } diff --git a/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs b/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs index 08da2a4595..ddd8356e69 100644 --- a/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs +++ b/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs @@ -39,7 +39,7 @@ private PrimitiveElement(object value, string instanceType, string name) Name = name ?? throw new ArgumentNullException(nameof(name)); } - public PrimitiveElement(object value, string? name = null, bool useFullTypeName = false) + public PrimitiveElement(object? value, string? name = null, bool useFullTypeName = false) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -60,7 +60,7 @@ public PrimitiveElement(object value, string? name = null, bool useFullTypeName public string Name { get; private set; } - public object Value { get; private set; } + public object? Value { get; private set; } public string InstanceType { get; private set; } diff --git a/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs b/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs index 7c7390a32e..523de2c865 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs @@ -81,10 +81,10 @@ private ScopedNode(ScopedNode parentNode, ScopedNode? parentResource, ITypedElem public string Name => Current.Name; /// - public string InstanceType => Current.InstanceType; + public string InstanceType => Current.InstanceType!; /// - public object Value => Current.Value; + public object? Value => Current.Value; /// public string Location => Current.Location; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs index 193b902c69..7fb804ab1b 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs @@ -23,7 +23,7 @@ public abstract class Any /// /// /// - public static bool TryGetSystemTypeByName(string name, out Type? result) + public static bool TryGetSystemTypeByName(string name, [NotNullWhen(true)] out Type? result) { result = get(); return result != null; @@ -112,7 +112,7 @@ internal static (bool, T?) DoConvert(Func parser) /// /// Try to convert a .NET instance to a Cql/FhirPath Any-based type. /// - public static bool TryConvert(object value, [NotNullWhen(true)]out Any? primitiveValue) + public static bool TryConvert(object? value, [NotNullWhen(true)]out Any? primitiveValue) { primitiveValue = conv(); return primitiveValue != null; @@ -159,7 +159,7 @@ public static bool TryConvert(object value, [NotNullWhen(true)]out Any? primitiv /// /// Converts a .NET instance to a Cql/FhirPath Any-based type. /// - public static Any? Convert(object value) + public static Any? Convert(object? value) { if (value == null) return null; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs index b3acf52f03..e762585a9b 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs @@ -106,7 +106,7 @@ public DateTimeOffset ToDateTimeOffset(int hours, int minutes, int seconds, int /// Converts the date to a full DateTimeOffset instance. /// /// - private static bool tryParse(string representation, out Date value) + private static bool tryParse(string representation, [NotNullWhen(true)] out Date? value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs index c79ad78aaa..cfe2a4cf59 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs @@ -105,7 +105,7 @@ public DateTimeOffset ToDateTimeOffset(TimeSpan defaultOffset) => new("^" + DATETIMEFORMAT + "$", RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled | RegexOptions.ExplicitCapture); - private static bool tryParse(string representation, out DateTime value) + private static bool tryParse(string representation, [NotNullWhen(true)] out DateTime? value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs index d3fcfb6cea..90c014e301 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs @@ -126,7 +126,7 @@ public static bool TryParse(string representation, [NotNullWhen(true)]out Quanti /// The parsed unit, either as a UCUM code or a non-UCUM calender unit. /// True is this is a non-UCUM calendar unit. /// True if this is a recognized time unit literal, false otherwise. - public static bool TryParseTimeUnit(string unitLiteral, out string? unit, out bool isCalendarUnit) + public static bool TryParseTimeUnit(string unitLiteral, [NotNullWhen(true)] out string? unit, out bool isCalendarUnit) { if (unitLiteral is null) throw new ArgumentNullException(nameof(unitLiteral)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs index 79a75387b8..32ec8bc110 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs @@ -101,7 +101,7 @@ public DateTimeOffset ToDateTimeOffset(int year, int month, int day, TimeSpan de private static readonly Regex PARTIALTIMEREGEX = new Regex("^" + PARTIALTIMEFORMAT + "$", RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled | RegexOptions.ExplicitCapture); - private static bool tryParse(string representation, out Time value) + private static bool tryParse(string representation, [NotNullWhen(true)] out Time? value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs index 7b29a3764b..da8b29f6d6 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs @@ -12,6 +12,7 @@ using Fhir.Metrics; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using M = Fhir.Metrics; namespace Hl7.Fhir.ElementModel.Types @@ -26,7 +27,7 @@ internal static class Ucum /// A system type Quantity of system Ucum /// The converted system type Quantity when the conversion was a success. /// true when the conversion succeeded. Or false otherwise. - internal static bool TryCanonicalize(this Quantity quantity, out Quantity? canonicalizedQuantity) + internal static bool TryCanonicalize(this Quantity quantity, [NotNullWhen(true)] out Quantity? canonicalizedQuantity) { try { diff --git a/src/Hl7.Fhir.Base/FhirPath/ElementNavFhirExtensions.cs b/src/Hl7.Fhir.Base/FhirPath/ElementNavFhirExtensions.cs index 468bfb6f6b..cf2c0a6711 100644 --- a/src/Hl7.Fhir.Base/FhirPath/ElementNavFhirExtensions.cs +++ b/src/Hl7.Fhir.Base/FhirPath/ElementNavFhirExtensions.cs @@ -109,7 +109,7 @@ public static bool HtmlChecks(this ITypedElement focus) return fhirValue.FhirValue; } - object result = r.Value; + object? result = r.Value; return result switch { @@ -121,7 +121,7 @@ public static bool HtmlChecks(this ITypedElement focus) P.Date d => new Date(d.ToString()), P.Time t => new Time(t.ToString()), P.DateTime dt => new FhirDateTime(dt.ToDateTimeOffset(TimeSpan.Zero).ToUniversalTime()), - _ => (Base)result + _ => result as Base }; }); } diff --git a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs index 133a303b39..1a0ae011f3 100644 --- a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs +++ b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs @@ -313,9 +313,9 @@ private class TypedElementWithoutDefinition : ITypedElement, IResourceTypeSuppli public string Name => _wrapped.Name; - public string InstanceType => _wrapped.InstanceType; + public string? InstanceType => _wrapped.InstanceType; - public object Value => _wrapped.Value; + public object? Value => _wrapped.Value; public string Location => _wrapped.Location; diff --git a/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs b/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs index f84a7b1886..368aa240de 100644 --- a/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs +++ b/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs @@ -189,7 +189,7 @@ public void ArithmeticOperationsTests(string left, string right, object result, _ = Quantity.TryParse(left, out var q1); _ = Quantity.TryParse(right, out var q2); - var opResult = operation(q1, q2); + var opResult = operation(q1!, q2!); if (result is string r && Quantity.TryParse(r, out var q3)) { From ee4094058b4d428a5d3acc57b1b06bbf05194a76 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 20 Mar 2024 17:31:44 +0100 Subject: [PATCH 03/17] another bunch of nullability --- .../ElementModel/ITypedElement.cs | 4 +- src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs | 2 +- .../ElementModel/TypedElementOnSourceNode.cs | 54 ++++++++++--------- src/Hl7.Fhir.Base/ElementModel/Types/Any.cs | 4 +- .../ElementModel/Types/Boolean.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Code.cs | 2 +- .../ElementModel/Types/Concept.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Date.cs | 2 +- .../ElementModel/Types/Decimal.cs | 2 +- .../ElementModel/Types/Integer.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Long.cs | 2 +- .../ElementModel/Types/Quantity.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs | 2 +- .../ElementModel/Types/String.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Time.cs | 2 +- .../Introspection/ClassMapping.cs | 2 +- .../Introspection/EnumMapping.cs | 2 +- src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs | 1 - src/Hl7.Fhir.Base/Rest/CompressedContent.cs | 2 + .../BaseFhirJsonPocoDeserializer.cs | 5 +- .../BaseFhirXmlPocoDeserializer.cs | 5 +- .../Serialization/BundleFilter.cs | 3 +- .../Serialization/ElementMetadataFilter.cs | 1 + .../SystemTextJsonParsingExtensions.cs | 3 +- .../Serialization/XObjectExtensions.cs | 23 ++++---- .../Serialization/XObjectFhirXmlExtensions.cs | 13 +++-- .../engine/ElementModelSerializationEngine.cs | 3 +- .../engine/PocoDeserializationExtensions.cs | 5 +- .../engine/PocoSerializationEngine.cs | 1 + .../Utility/FhirReleaseParser.cs | 4 +- src/Hl7.Fhir.Base/Utility/IAnnotated.cs | 15 +++--- .../Utility/SerializationUtil.cs | 2 +- .../ElementDefinitionNavigatorExtensions.cs | 3 +- .../ElementDefinitionNavigatorExtensions.cs | 3 +- .../Source/Summary/ArtifactSummary.cs | 2 +- .../Model/ModelInfo.cs | 1 + 36 files changed, 106 insertions(+), 79 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs index 0335bb020c..3c3861ede8 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs @@ -8,6 +8,8 @@ using Hl7.Fhir.Specification; +#nullable enable + namespace Hl7.Fhir.ElementModel { /// @@ -32,6 +34,6 @@ public interface ITypedElement : IBaseElementNavigator /// the user in locating issues in the data. string Location { get; } - IElementDefinitionSummary Definition { get; } + IElementDefinitionSummary? Definition { get; } } } \ No newline at end of file diff --git a/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs b/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs index 523de2c865..9cfd3e4924 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs @@ -123,7 +123,7 @@ public ITypedElement ResourceContext } /// - public IElementDefinitionSummary Definition => Current.Definition; + public IElementDefinitionSummary? Definition => Current.Definition; /// /// Get the list of container parents in a list, nearest parent first. diff --git a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs index 905d45d0bb..e220ed950f 100644 --- a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs @@ -10,10 +10,13 @@ using Hl7.Fhir.Utility; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using P = Hl7.Fhir.ElementModel.Types; +#nullable enable + namespace Hl7.Fhir.ElementModel { internal class TypedElementOnSourceNode : ITypedElement, IAnnotated, IExceptionSource, IShortPathGenerator @@ -21,7 +24,7 @@ internal class TypedElementOnSourceNode : ITypedElement, IAnnotated, IExceptionS private const string XHTML_INSTANCETYPE = "xhtml"; private const string XHTML_DIV_TAG_NAME = "div"; - public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefinitionSummaryProvider provider, TypedElementSettings settings = null) + public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefinitionSummaryProvider provider, TypedElementSettings settings = null!) { if (source == null) throw Error.ArgumentNull(nameof(source)); @@ -36,7 +39,7 @@ public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefin (InstanceType, Definition) = buildRootPosition(type); } - private (string instanceType, IElementDefinitionSummary definition) buildRootPosition(string type) + private (string? instanceType, IElementDefinitionSummary? definition) buildRootPosition(string type) { var rootType = type ?? _source.GetResourceTypeIndicator(); if (rootType == null) @@ -66,7 +69,7 @@ public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefin } - private TypedElementOnSourceNode(TypedElementOnSourceNode parent, ISourceNode source, IElementDefinitionSummary definition, string instanceType, string prettyPath) + private TypedElementOnSourceNode(TypedElementOnSourceNode parent, ISourceNode source, IElementDefinitionSummary? definition, string? instanceType, string prettyPath) { _source = source; ShortPath = prettyPath; @@ -77,9 +80,9 @@ private TypedElementOnSourceNode(TypedElementOnSourceNode parent, ISourceNode so _settings = parent._settings; } - public ExceptionNotificationHandler ExceptionHandler { get; set; } + public ExceptionNotificationHandler ExceptionHandler { get; set; } = null!; - private void raiseTypeError(string message, object source, bool warning = false, string location = null) + private void raiseTypeError(string message, object source, bool warning = false, string? location = null) { var exMessage = $"Type checking the data: {message}"; if (!string.IsNullOrEmpty(location)) @@ -93,7 +96,7 @@ private void raiseTypeError(string message, object source, bool warning = false, ExceptionHandler.NotifyOrThrow(source, notification); } - public string InstanceType { get; private set; } + public string? InstanceType { get; private set; } private readonly ISourceNode _source; @@ -101,7 +104,7 @@ private void raiseTypeError(string message, object source, bool warning = false, private readonly TypedElementSettings _settings; - public IElementDefinitionSummary Definition { get; private set; } + public IElementDefinitionSummary? Definition { get; private set; } public string Name => Definition?.ElementName ?? _source.Name; @@ -120,7 +123,7 @@ private void raiseTypeError(string message, object source, bool warning = false, // R3 and R4, these value (and url and id elements by the way) will indicate which type // of system types there are, implicitly specifying the mapping between primitive // FHIR types and system types. - private static Type tryMapFhirPrimitiveTypeToSystemType(string fhirType) + private static Type? tryMapFhirPrimitiveTypeToSystemType(string fhirType) { switch (fhirType) { @@ -158,7 +161,7 @@ private static Type tryMapFhirPrimitiveTypeToSystemType(string fhirType) } } - private object valueFactory() + private object? valueFactory() { string sourceText = _source.Text; @@ -209,7 +212,7 @@ private object valueFactory() if (P.Any.TryParse(sourceText, typeof(P.DateTime), out var dateTimeVal)) { // TruncateToDate converts 1991-02-03T11:22:33Z to 1991-02-03+00:00 which is not a valid date! - var date = (dateTimeVal as P.DateTime).TruncateToDate(); + var date = (dateTimeVal as P.DateTime)!.TruncateToDate(); // so we cut off timezone by converting it to timeoffset and cast back to date. return P.Date.FromDateTimeOffset(date.ToDateTimeOffset(0, 0, 0, TimeSpan.Zero)); } @@ -220,13 +223,13 @@ private object valueFactory() } } - private object _value; + private object? _value; private bool _valueInitialized = false; private static object _initializationLock = new(); - public object Value => LazyInitializer.EnsureInitialized(ref _value, ref _valueInitialized, ref _initializationLock, valueFactory); + public object? Value => LazyInitializer.EnsureInitialized(ref _value, ref _valueInitialized, ref _initializationLock, valueFactory); - private string deriveInstanceType(ISourceNode current, IElementDefinitionSummary info) + private string? deriveInstanceType(ISourceNode current, IElementDefinitionSummary info) { var resourceTypeIndicator = current.GetResourceTypeIndicator(); @@ -338,7 +341,7 @@ private string typeFromLogicalModelCanonical(ITypeSerializationInfo info) return pos > -1 ? type.Substring(pos + 1) : type; } - private bool tryGetBySuffixedName(Dictionary dis, string name, out IElementDefinitionSummary info) + private bool tryGetBySuffixedName(Dictionary dis, string name, [NotNullWhen(true)] out IElementDefinitionSummary? info) { // Simplest case, one on one match between name and element name if (dis.TryGetValue(name, out info)) @@ -361,7 +364,7 @@ private bool tryGetBySuffixedName(Dictionary } } - private IEnumerable enumerateElements(Dictionary dis, ISourceNode parent, string name) + private IEnumerable enumerateElements(Dictionary dis, ISourceNode parent, string? name) { IEnumerable childSet; @@ -372,17 +375,17 @@ private IEnumerable enumerateElements(Dictionary(); } - string lastName = null; + string? lastName = null; int _nameIndex = 0; foreach (var scan in childSet) { var hit = tryGetBySuffixedName(dis, scan.Name, out var info); - string instanceType = info == null ? null : + string? instanceType = info == null ? null : deriveInstanceType(scan, info); // If we have definitions for the children, but we didn't find definitions for this @@ -406,13 +409,13 @@ private IEnumerable enumerateElements(Dictionary c.Annotation()?.XHtmlText); @@ -427,7 +430,7 @@ private IEnumerable enumerateElements(Dictionary Children(string name = null) + public IEnumerable Children(string? name = null) { // If we have an xhtml typed node and there is not a div tag around the content // then we will not enumerate through the children of this node, since there will be no types @@ -463,13 +466,14 @@ private IEnumerable runAdditionalRules(IEnumerable #pragma warning disable 612, 618 var additionalRules = _source.Annotations(typeof(AdditionalStructuralRule)); var stateBag = new Dictionary(); + IEnumerable enumerable = additionalRules.ToList(); foreach (var child in children) { - foreach (var rule in additionalRules.Cast()) + foreach (var rule in enumerable.Cast()) { - stateBag.TryGetValue(rule, out object state); + stateBag.TryGetValue(rule, out object? state); state = rule(child, this, state); - if (state != null) stateBag[rule] = state; + stateBag[rule] = state; } yield return child; @@ -496,6 +500,6 @@ public IEnumerable Annotations(Type type) } [Obsolete("This class is used for internal purposes and is subject to change without notice. Don't use.")] - public delegate object AdditionalStructuralRule(ITypedElement node, IExceptionSource ies, object state); + public delegate object AdditionalStructuralRule(ITypedElement node, IExceptionSource ies, object? state); } diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs index 7fb804ab1b..889e254dd4 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs @@ -57,7 +57,7 @@ public static object Parse(string value, Type primitiveType) throw new FormatException($"Input string '{value}' was not in a correct format for type '{primitiveType}'."); } - public static bool TryParse(string value, Type primitiveType, [NotNullWhen(true)]out object? parsed) + public static bool TryParse(string value, Type primitiveType, [NotNullWhen(true)] out object? parsed) { if (value == null) throw new ArgumentNullException(nameof(value)); if (!typeof(Any).IsAssignableFrom(primitiveType)) throw new ArgumentException($"Must be a subclass of {nameof(Any)}.", nameof(primitiveType)); @@ -112,7 +112,7 @@ internal static (bool, T?) DoConvert(Func parser) /// /// Try to convert a .NET instance to a Cql/FhirPath Any-based type. /// - public static bool TryConvert(object? value, [NotNullWhen(true)]out Any? primitiveValue) + public static bool TryConvert(object? value, [NotNullWhen(true)] out Any? primitiveValue) { primitiveValue = conv(); return primitiveValue != null; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs index 63319d26c3..b00a906a88 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs @@ -30,7 +30,7 @@ public Boolean() : this(default) { } public static Boolean Parse(string value) => TryParse(value, out var result) ? result! : throw new FormatException($"String '{value}' was not recognized as a valid boolean."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Boolean? value) + public static bool TryParse(string representation, [NotNullWhen(true)] out Boolean? value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs index 56851f7d0c..c9c816a27e 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs @@ -31,7 +31,7 @@ public Code(string? system, string code, string? display = null, string? version public string? Version { get; } public static Code Parse(string value) => throw new NotImplementedException(); - public static bool TryParse(string representation, [NotNullWhen(true)]out Code? value) => throw new NotImplementedException(); + public static bool TryParse(string representation, [NotNullWhen(true)] out Code? value) => throw new NotImplementedException(); public override int GetHashCode() => (System, Value, Display, Version).GetHashCode(); public override string ToString() => $"{Value}@{System} " + Display ?? ""; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs index 90edf34208..5aad7693ca 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs @@ -31,7 +31,7 @@ public Concept(IEnumerable codes, string? display = null) public string? Display { get; } public static Concept Parse(string representation) => throw new NotImplementedException(); - public static bool TryParse(string representation, [NotNullWhen(true)]out Concept? value) => throw new NotImplementedException(); + public static bool TryParse(string representation, [NotNullWhen(true)] out Concept? value) => throw new NotImplementedException(); public override bool Equals(object? obj) => obj is Concept c && Enumerable.SequenceEqual(Codes, c.Codes) && Display == c.Display; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs index e762585a9b..55ee038413 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs @@ -30,7 +30,7 @@ private Date(DateTimeOffset value, DateTimePrecision precision, bool hasOffset) public static Date Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid date."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Date? value) => tryParse(representation, out value); + public static bool TryParse(string representation, [NotNullWhen(true)] out Date? value) => tryParse(representation, out value); public static Date FromDateTimeOffset(DateTimeOffset dto, DateTimePrecision prec = DateTimePrecision.Day, bool includeOffset = false) => new(dto, prec, includeOffset); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs index e190b77b9d..a09ec9381a 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs @@ -33,7 +33,7 @@ public Decimal() : this(default) { } public static Decimal Parse(string value) => TryParse(value, out var result) ? result! : throw new FormatException($"String '{value}' was not recognized as a valid decimal."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Decimal? value) + public static bool TryParse(string representation, [NotNullWhen(true)] out Decimal? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs index 2088bde0a2..e5d23fbf2f 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs @@ -27,7 +27,7 @@ public Integer() : this(default) { } public static Integer Parse(string value) => TryParse(value, out var result) ? result : throw new FormatException($"String '{value}' was not recognized as a valid integer."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Integer? value) + public static bool TryParse(string representation, [NotNullWhen(true)] out Integer? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs index a30a32fa84..52a349414c 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs @@ -27,7 +27,7 @@ public Long() : this(default) { } public static Long Parse(string value) => TryParse(value, out var result) ? result : throw new FormatException($"String '{value}' was not recognized as a valid long integer."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Long? value) + public static bool TryParse(string representation, [NotNullWhen(true)] out Long? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs index 90c014e301..7be49773eb 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs @@ -84,7 +84,7 @@ public static Quantity ForCalendarDuration(decimal value, string calendarUnit) public static Quantity Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid quantity."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Quantity? quantity) + public static bool TryParse(string representation, [NotNullWhen(true)] out Quantity? quantity) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs index 0c7109e02e..dbe63f3286 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs @@ -28,7 +28,7 @@ public Ratio(Quantity numerator, Quantity denominator) public static Ratio Parse(string representation) => TryParse(representation, out var result) ? result! : throw new FormatException($"String '{representation}' was not recognized as a valid ratio."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Ratio? value) + public static bool TryParse(string representation, [NotNullWhen(true)] out Ratio? value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs index 70621aa939..740904be15 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs @@ -29,7 +29,7 @@ public static String Parse(string value) => // Actually, it's not that trivial, since CQL strings accept a subset of C#'s escape sequences, // we *could* validate those here. - public static bool TryParse(string representation, [NotNullWhen(true)]out String? value) + public static bool TryParse(string representation, [NotNullWhen(true)] out String? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs index 32ec8bc110..973c999d2b 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs @@ -31,7 +31,7 @@ private Time(DateTimeOffset parsedValue, DateTimePrecision precision, bool hasOf public static Time Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid time."); - public static bool TryParse(string representation, [NotNullWhen(true)]out Time? value) => tryParse(representation, out value); + public static bool TryParse(string representation, [NotNullWhen(true)] out Time? value) => tryParse(representation, out value); public static Time FromDateTimeOffset(DateTimeOffset dto, DateTimePrecision prec = DateTimePrecision.Fraction, bool includeOffset = false) => new(dto, prec, includeOffset); diff --git a/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs b/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs index 0996f5ca5e..ef314bd070 100644 --- a/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs @@ -40,7 +40,7 @@ public class ClassMapping : IStructureDefinitionSummary /// For classes shared across FHIR versions, there may be metadata present for different versions /// of FHIR, the is used to select which subset of metadata to extract. /// - public static bool TryGetMappingForType(Type t, FhirRelease release, out ClassMapping? mapping) + public static bool TryGetMappingForType(Type t, FhirRelease release, [NotNullWhen(true)] out ClassMapping? mapping) { mapping = _mappedClasses.GetOrAdd((t, release), createMapping); return mapping is not null; diff --git a/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs b/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs index 7d3892d76b..18a4caf75a 100644 --- a/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs @@ -35,7 +35,7 @@ public class EnumMapping /// For enums shared across FHIR versions, there may be metadata present for different versions /// of FHIR, the is used to select which subset of metadata to extract. /// - public static bool TryGetMappingForEnum(Type t, FhirRelease release, out EnumMapping? mapping) + public static bool TryGetMappingForEnum(Type t, FhirRelease release, [NotNullWhen(true)] out EnumMapping? mapping) { mapping = _mappedEnums.GetOrAdd((t, release), createMapping); return mapping is not null; diff --git a/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs b/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs index c425d957e0..a73ac6e231 100644 --- a/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs +++ b/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs @@ -70,7 +70,6 @@ public FhirUri(): this((string)null) {} /// [FhirElement("value", IsPrimitiveValue=true, XmlSerialization=XmlRepresentation.XmlAttr, InSummary=true, Order=30)] [DeclaredType(Type = typeof(SystemPrimitive.String))] - [UriPattern] [DataMember] public string Value { diff --git a/src/Hl7.Fhir.Base/Rest/CompressedContent.cs b/src/Hl7.Fhir.Base/Rest/CompressedContent.cs index 5d5d731c96..d51dd936cc 100644 --- a/src/Hl7.Fhir.Base/Rest/CompressedContent.cs +++ b/src/Hl7.Fhir.Base/Rest/CompressedContent.cs @@ -40,6 +40,8 @@ protected override bool TryComputeLength(out long length) length = -1; return false; } + + // @Ewout why is this here? protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) { diff --git a/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoDeserializer.cs b/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoDeserializer.cs index 0bf643a631..5719240418 100644 --- a/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoDeserializer.cs +++ b/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoDeserializer.cs @@ -14,6 +14,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Text.Json; @@ -85,7 +86,7 @@ public BaseFhirJsonPocoDeserializer(ModelInspector inspector, FhirJsonPocoDeseri /// The result of deserialization. May be incomplete when there are issues. /// Issues encountered while deserializing. Will be empty when the function returns true. /// false if there are issues, true otherwise. - public bool TryDeserializeResource(ref Utf8JsonReader reader, out Resource? instance, out IEnumerable issues) + public bool TryDeserializeResource(ref Utf8JsonReader reader, [NotNullWhen(true)] out Resource? instance, out IEnumerable issues) { if (reader.CurrentState.Options.CommentHandling is not JsonCommentHandling.Skip and not JsonCommentHandling.Disallow) throw new InvalidOperationException("The reader must be set to ignore or refuse comments."); @@ -109,7 +110,7 @@ public bool TryDeserializeResource(ref Utf8JsonReader reader, out Resource? inst /// The result of deserialization. May be incomplete when there are issues. /// Issues encountered while deserializing. Will be empty when the function returns true. /// false if there are issues, true otherwise. - public bool TryDeserializeObject(Type targetType, ref Utf8JsonReader reader, out Base? instance, out IEnumerable issues) + public bool TryDeserializeObject(Type targetType, ref Utf8JsonReader reader, [NotNullWhen(true)] out Base? instance, out IEnumerable issues) { if (reader.CurrentState.Options.CommentHandling is not JsonCommentHandling.Skip and not JsonCommentHandling.Disallow) throw new InvalidOperationException("The reader must be set to ignore or refuse comments."); diff --git a/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoDeserializer.cs b/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoDeserializer.cs index 09eccdbe8c..4b638a00c1 100644 --- a/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoDeserializer.cs +++ b/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoDeserializer.cs @@ -6,6 +6,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Xml; @@ -69,7 +70,7 @@ public BaseFhirXmlPocoDeserializer(ModelInspector inspector, FhirXmlPocoDeserial /// The result of deserialization. May be incomplete when there are issues. /// Issues encountered while deserializing. Will be empty when the function returns true. /// false if there are issues, true otherwise. - public bool TryDeserializeResource(XmlReader reader, out Resource? instance, out IEnumerable issues) + public bool TryDeserializeResource(XmlReader reader, [NotNullWhen(true)] out Resource? instance, out IEnumerable issues) { FhirXmlPocoDeserializerState state = new(); @@ -96,7 +97,7 @@ public bool TryDeserializeResource(XmlReader reader, out Resource? instance, out /// The result of deserialization. May be incomplete when there are issues. /// Issues encountered while deserializing. Will be empty when the function returns true. /// false if there are issues, true otherwise. - public bool TryDeserializeElement(Type targetType, XmlReader reader, out Base? instance, out IEnumerable issues) + public bool TryDeserializeElement(Type targetType, XmlReader reader, [NotNullWhen(true)] out Base? instance, out IEnumerable issues) { FhirXmlPocoDeserializerState state = new(); diff --git a/src/Hl7.Fhir.Base/Serialization/BundleFilter.cs b/src/Hl7.Fhir.Base/Serialization/BundleFilter.cs index bb3c11cfc5..80f810e5dc 100644 --- a/src/Hl7.Fhir.Base/Serialization/BundleFilter.cs +++ b/src/Hl7.Fhir.Base/Serialization/BundleFilter.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Introspection; using System; +using System.Diagnostics.CodeAnalysis; namespace Hl7.Fhir.Serialization { @@ -55,7 +56,7 @@ public override void EnterObject(object value, ClassMapping? mapping) } /// - public override bool TryEnterMember(string name, object value, PropertyMapping? mapping) => + public override bool TryEnterMember(string name, object value, [NotNullWhen(true)] PropertyMapping? mapping) => inRootBundle || ChildFilter.TryEnterMember(name, value, mapping); /// diff --git a/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs b/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs index 62684fa38e..6fe9135129 100644 --- a/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs +++ b/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs @@ -11,6 +11,7 @@ using Hl7.Fhir.Introspection; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Hl7.Fhir.Serialization diff --git a/src/Hl7.Fhir.Base/Serialization/SystemTextJsonParsingExtensions.cs b/src/Hl7.Fhir.Base/Serialization/SystemTextJsonParsingExtensions.cs index bb36eb5f28..739629f170 100644 --- a/src/Hl7.Fhir.Base/Serialization/SystemTextJsonParsingExtensions.cs +++ b/src/Hl7.Fhir.Base/Serialization/SystemTextJsonParsingExtensions.cs @@ -9,6 +9,7 @@ #if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; using System.Text.Json; @@ -52,7 +53,7 @@ internal static string GenerateLocationMessage(this ref Utf8JsonReader reader, o } - public static bool TryGetNumber(this ref Utf8JsonReader reader, out object? value) + public static bool TryGetNumber(this ref Utf8JsonReader reader, [NotNullWhen(true)] out object? value) { value = null; diff --git a/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs b/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs index 7e743554ad..dec0392eaa 100644 --- a/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs +++ b/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs @@ -1,12 +1,15 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Xml.Linq; +#nullable enable + namespace Hl7.Fhir.Utility { public static class XObjectExtensions { - public static bool TryGetAttribute(this XElement docNode, XName name, out string value) + public static bool TryGetAttribute(this XElement docNode, XName name, [NotNullWhen(true)] out string? value) { var attr = docNode.Attribute(name); @@ -38,7 +41,7 @@ public static bool TryGetAttribute(this XElement docNode, XName name, out string * * Note: XDocumentType, XProcessingInstruction appear only on XDocument */ - public static XObject FirstChild(this XObject node) + public static XObject? FirstChild(this XObject node) { if (node is XContainer container) { @@ -53,7 +56,7 @@ public static XObject FirstChild(this XObject node) return null; } - public static XObject NextSibling(this XObject node) + public static XObject? NextSibling(this XObject node) { if (node is XNode n) return n.NextNode; @@ -64,11 +67,11 @@ public static XObject NextSibling(this XObject node) if (attr.NextAttribute != null) return attr.NextAttribute; // out of attributes, continue with our parents first "real" node - return attr.Parent.FirstNode; + return attr.Parent!.FirstNode; } } - public static XName Name(this XObject node) + public static XName? Name(this XObject node) { if (node is XElement xe) return xe.Name; if (node is XAttribute xa) return xa.Name; @@ -76,7 +79,7 @@ public static XName Name(this XObject node) return null; } - public static string Value(this XObject node) + public static string? Value(this XObject node) { if (node is XElement xe) return xe.Value; if (node is XAttribute xa) return xa.Value; @@ -85,12 +88,12 @@ public static string Value(this XObject node) return null; } - public static string Text(this XObject node) + public static string? Text(this XObject node) { return (node is XContainer container) ? extractString(container.Nodes().OfType().Select(t => t.Value)) : null; - string extractString(IEnumerable source) + string? extractString(IEnumerable source) { var concatenated = string.Concat(source).Trim(); return string.IsNullOrEmpty(concatenated) ? null : concatenated; @@ -110,10 +113,10 @@ public static IEnumerable PreviousNodes(this XNode node) public static bool AtXhtmlDiv(this XObject node) => (node as XElement)?.Name == XmlNs.XHTMLDIV; - public static XDocument Rename(this XDocument doc, string newRootName) + public static XDocument Rename(this XDocument doc, string? newRootName) { if (newRootName != null) - doc.Root.Name = XName.Get(newRootName, doc.Root.Name.Namespace.NamespaceName); + doc.Root!.Name = XName.Get(newRootName, doc.Root.Name.Namespace.NamespaceName); return doc; } } diff --git a/src/Hl7.Fhir.Base/Serialization/XObjectFhirXmlExtensions.cs b/src/Hl7.Fhir.Base/Serialization/XObjectFhirXmlExtensions.cs index cce48f62c8..6b873b0507 100644 --- a/src/Hl7.Fhir.Base/Serialization/XObjectFhirXmlExtensions.cs +++ b/src/Hl7.Fhir.Base/Serialization/XObjectFhirXmlExtensions.cs @@ -8,10 +8,13 @@ using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Xml; using System.Xml.Linq; +#nullable enable + namespace Hl7.Fhir.Serialization { internal static class XObjectFhirXmlExtensions @@ -19,7 +22,7 @@ internal static class XObjectFhirXmlExtensions public static bool IsResourceName(this XName elementName, bool ignoreNameSpace = false) => Char.IsUpper(elementName.LocalName, 0) && (ignoreNameSpace || elementName.Namespace == XmlNs.XFHIR); - public static bool TryGetContainedResource(this XElement xe, out XElement contained, bool ignoreNameSpace = false) + public static bool TryGetContainedResource(this XElement xe, [NotNullWhen(true)] out XElement? contained, bool ignoreNameSpace = false) { contained = null; @@ -38,20 +41,20 @@ public static bool TryGetContainedResource(this XElement xe, out XElement contai return false; } - public static XObject NextElementOrAttribute(this XObject current) + public static XObject? NextElementOrAttribute(this XObject current) { var scan = current.NextSibling(); return scanToNextRelevantNode(scan); } - public static XObject FirstChildElementOrAttribute(this XObject current) + public static XObject? FirstChildElementOrAttribute(this XObject current) { var scan = current.FirstChild(); return scanToNextRelevantNode(scan); } - private static XObject scanToNextRelevantNode(this XObject scan) + private static XObject? scanToNextRelevantNode(this XObject? scan) { while (scan != null) { @@ -75,7 +78,7 @@ private static bool isRelevantAttribute(XAttribute a) => public static bool HasRelevantAttributes(this XElement scan) => scan.Attributes().Any(a => isRelevantAttribute(a)); - public static string GetValue(this XObject current) + public static string? GetValue(this XObject current) { if (current.AtXhtmlDiv()) return ((XElement)current).ToString(SaveOptions.DisableFormatting); diff --git a/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs index 4e84c1eb36..82ae305b82 100644 --- a/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs +++ b/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs @@ -14,6 +14,7 @@ using Hl7.Fhir.Model; using Hl7.Fhir.Utility; using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http.Headers; @@ -43,7 +44,7 @@ public ElementModelSerializationEngine( _pocoSettings = pocoSettings; } - public static bool TryUnpackElementModelException(DeserializationFailedException dfe, out FormatException? fe) + public static bool TryUnpackElementModelException(DeserializationFailedException dfe, [NotNullWhen(true)] out FormatException? fe) { if (dfe.Exceptions.Count == 1 && dfe.Exceptions.Single() is ElementModelParserException empe) { diff --git a/src/Hl7.Fhir.Base/Serialization/engine/PocoDeserializationExtensions.cs b/src/Hl7.Fhir.Base/Serialization/engine/PocoDeserializationExtensions.cs index 86872606f1..ce9664b461 100644 --- a/src/Hl7.Fhir.Base/Serialization/engine/PocoDeserializationExtensions.cs +++ b/src/Hl7.Fhir.Base/Serialization/engine/PocoDeserializationExtensions.cs @@ -12,6 +12,7 @@ using Hl7.Fhir.Utility; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.Json; using System.Xml; @@ -57,7 +58,7 @@ public static Resource DeserializeResource(this BaseFhirXmlPocoDeserializer dese public static bool TryDeserializeResource( this BaseFhirXmlPocoDeserializer deserializer, string data, - out Resource? instance, + [NotNullWhen(true)] out Resource? instance, out IEnumerable issues) { var xmlReader = SerializationUtil.XmlReaderFromXmlText(data); @@ -118,7 +119,7 @@ public static Resource DeserializeResource(this BaseFhirJsonPocoDeserializer des public static bool TryDeserializeResource( this BaseFhirJsonPocoDeserializer deserializer, string json, - out Resource? instance, + [NotNullWhen(true)] out Resource? instance, out IEnumerable issues) { var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json), new() { CommentHandling = JsonCommentHandling.Skip }); diff --git a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs index 3df475b436..22b3221abc 100644 --- a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs +++ b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs @@ -14,6 +14,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Hl7.Fhir.Serialization diff --git a/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs b/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs index 5f687ab5f5..825995864e 100644 --- a/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs +++ b/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs @@ -105,7 +105,7 @@ public static FhirRelease FhirReleaseFromMimeVersion(string fhirMimeVersion) => /// 'fhirversion' MIME-Type parameter /// Official FHIR Release /// true if the conversion succeeded; false otherwise. - public static bool TryGetFhirReleaseFromMimeVersion(string fhirMimeVersion, out FhirRelease? release) + public static bool TryGetFhirReleaseFromMimeVersion(string fhirMimeVersion, [NotNullWhen(true)] out FhirRelease? release) { release = fhirMimeVersion switch { @@ -163,7 +163,7 @@ public static FhirRelease FhirReleaseFromCorePackageName(string packageName) => /// FHIR Core package name /// Official FHIR Release /// true if the conversion succeeded; false otherwise - public static bool TryGetFhirReleaseFromCorePackageName(string packageName, out FhirRelease? release) + public static bool TryGetFhirReleaseFromCorePackageName(string packageName, [NotNullWhen(true)] out FhirRelease? release) { release = packageName switch { diff --git a/src/Hl7.Fhir.Base/Utility/IAnnotated.cs b/src/Hl7.Fhir.Base/Utility/IAnnotated.cs index b87c52cbfd..9af7aa23ba 100644 --- a/src/Hl7.Fhir.Base/Utility/IAnnotated.cs +++ b/src/Hl7.Fhir.Base/Utility/IAnnotated.cs @@ -8,10 +8,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; +#nullable enable + namespace Hl7.Fhir.Utility { public interface IAnnotated @@ -21,19 +24,19 @@ public interface IAnnotated public static class AnnotatedExtensions { - public static object Annotation(this IAnnotated annotated, Type type) => annotated.Annotations(type)?.FirstOrDefault(); + public static object? Annotation(this IAnnotated annotated, Type type) => annotated.Annotations(type).FirstOrDefault(); - public static bool TryGetAnnotation(this IAnnotated annotated, Type type, out object annotation) + public static bool TryGetAnnotation(this IAnnotated annotated, Type type, [NotNullWhen(true)] out object? annotation) { - annotation = annotated.Annotations(type)?.FirstOrDefault(); + annotation = annotated.Annotations(type).FirstOrDefault(); return annotation != null; } - public static A Annotation(this IAnnotated annotated) => (A)annotated.Annotation(typeof(A)); + public static A? Annotation(this IAnnotated annotated) => (A?)annotated.Annotation(typeof(A)); - public static bool TryGetAnnotation(this IAnnotated annotated, out A annotation) where A:class + public static bool TryGetAnnotation(this IAnnotated annotated, out A? annotation) where A:class { - annotation = annotated.Annotations()?.FirstOrDefault(); + annotation = annotated.Annotations().FirstOrDefault(); return annotation != null; } diff --git a/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs b/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs index e47a4e017d..635175429b 100644 --- a/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs +++ b/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs @@ -486,7 +486,7 @@ public static string[] RunFhirXhtmlSchemaValidation(XDocument doc) { var result = new List(); - if (!doc.Root.AtXhtmlDiv()) + if (!doc.Root!.AtXhtmlDiv()) return new[] { $"Root element of XHTML is not a
from the XHTML namespace ({XmlNs.XHTML})." }; if (!hasContent(doc.Root!)) diff --git a/src/Hl7.Fhir.Conformance/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs b/src/Hl7.Fhir.Conformance/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs index 847deeaa4a..fc357ce8e8 100644 --- a/src/Hl7.Fhir.Conformance/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs +++ b/src/Hl7.Fhir.Conformance/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Model; using System; +using System.Diagnostics.CodeAnalysis; namespace Hl7.Fhir.Specification.Navigation { @@ -37,7 +38,7 @@ internal static string ConstraintDescription(this ElementDefinition.ConstraintCo /// Resolve a the contentReference in a navigator and returns a navigator that is located on the target of the contentReference. /// /// The current navigator must be located at an element that contains a contentReference. - public static bool TryFollowContentReference(this ElementDefinitionNavigator sourceNavigator, Func resolver, out ElementDefinitionNavigator? targetNavigator) + public static bool TryFollowContentReference(this ElementDefinitionNavigator sourceNavigator, Func resolver, [NotNullWhen(true)] out ElementDefinitionNavigator? targetNavigator) { targetNavigator = null; diff --git a/src/Hl7.Fhir.STU3/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs b/src/Hl7.Fhir.STU3/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs index bccfabe64d..f165005b6f 100644 --- a/src/Hl7.Fhir.STU3/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs +++ b/src/Hl7.Fhir.STU3/Specification/Navigation/ElementDefinitionNavigatorExtensions.cs @@ -10,6 +10,7 @@ using Hl7.Fhir.Model; using System; +using System.Diagnostics.CodeAnalysis; namespace Hl7.Fhir.Specification.Navigation { @@ -37,7 +38,7 @@ internal static string ConstraintDescription(this ElementDefinition.ConstraintCo /// Resolve a the contentReference in a navigator and returns a navigator that is located on the target of the contentReference. /// /// The current navigator must be located at an element that contains a contentReference. - public static bool TryFollowContentReference(this ElementDefinitionNavigator sourceNavigator, Func resolver, out ElementDefinitionNavigator? targetNavigator) + public static bool TryFollowContentReference(this ElementDefinitionNavigator sourceNavigator, Func resolver, [NotNullWhen(true)] out ElementDefinitionNavigator? targetNavigator) { targetNavigator = null; diff --git a/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs b/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs index e0da7b0548..f7050d2e79 100644 --- a/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs +++ b/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs @@ -174,7 +174,7 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception? error) public bool ContainsKey(string key) => properties.ContainsKey(key); /// Gets the property value associated with the specified property key. - public bool TryGetValue(string key, [NotNullWhen(true)]out object? value) => properties.TryGetValue(key, out value); + public bool TryGetValue(string key, [NotNullWhen(true)] out object? value) => properties.TryGetValue(key, out value); #endregion diff --git a/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs b/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs index 02a54c3061..2014ac4b98 100644 --- a/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs +++ b/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; From 0e8d856046d1bc715ed436e9037cee40f71c8b16 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Thu, 21 Mar 2024 11:22:15 +0100 Subject: [PATCH 04/17] nullability again --- src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs | 1 + src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs | 4 ++-- src/Hl7.Fhir.Base/Utility/IAnnotated.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs index 3c3861ede8..3263deb618 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs @@ -10,6 +10,7 @@ #nullable enable + namespace Hl7.Fhir.ElementModel { /// diff --git a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs index e220ed950f..3ab145158a 100644 --- a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs @@ -24,7 +24,7 @@ internal class TypedElementOnSourceNode : ITypedElement, IAnnotated, IExceptionS private const string XHTML_INSTANCETYPE = "xhtml"; private const string XHTML_DIV_TAG_NAME = "div"; - public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefinitionSummaryProvider provider, TypedElementSettings settings = null!) + public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefinitionSummaryProvider provider, TypedElementSettings? settings = null) { if (source == null) throw Error.ArgumentNull(nameof(source)); @@ -39,7 +39,7 @@ public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefin (InstanceType, Definition) = buildRootPosition(type); } - private (string? instanceType, IElementDefinitionSummary? definition) buildRootPosition(string type) + private (string? instanceType, IElementDefinitionSummary? definition) buildRootPosition(string? type) { var rootType = type ?? _source.GetResourceTypeIndicator(); if (rootType == null) diff --git a/src/Hl7.Fhir.Base/Utility/IAnnotated.cs b/src/Hl7.Fhir.Base/Utility/IAnnotated.cs index 9af7aa23ba..9a14494790 100644 --- a/src/Hl7.Fhir.Base/Utility/IAnnotated.cs +++ b/src/Hl7.Fhir.Base/Utility/IAnnotated.cs @@ -42,7 +42,7 @@ public static bool TryGetAnnotation(this IAnnotated annotated, out A? annotat public static IEnumerable Annotations(this IAnnotated annotated) => annotated.Annotations(typeof(A))?.Cast() ?? Enumerable.Empty(); - public static bool HasAnnotation(this IAnnotated annotated, Type type) => annotated.Annotations(type)?.Any() == true; + public static bool HasAnnotation(this IAnnotated annotated, Type type) => annotated.Annotations(type).Any(); public static bool HasAnnotation(this IAnnotated annotated) => annotated.HasAnnotation(typeof(A)); } From 8e94626757533589262236628d727d75fb348588 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Thu, 21 Mar 2024 13:18:42 +0100 Subject: [PATCH 05/17] fixed unit test --- src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs | 2 +- src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs b/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs index b002e32bcc..dd17a50a22 100644 --- a/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs @@ -24,7 +24,7 @@ namespace Hl7.Fhir.Introspection /// /// A container for the metadata of an element of a FHIR datatype as present on a property of a (generated) .NET POCO class. /// - [System.Diagnostics.DebuggerDisplay(@"\{Name={Name} ElementType={ElementType.Name}}")] + [System.Diagnostics.DebuggerDisplay(@"\{Name={Name} ElementType={ImplementingType.Name}}")] public class PropertyMapping : IElementDefinitionSummary { // no public constructors diff --git a/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs b/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs index a73ac6e231..c425d957e0 100644 --- a/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs +++ b/src/Hl7.Fhir.Base/Model/Generated/FhirUri.cs @@ -70,6 +70,7 @@ public FhirUri(): this((string)null) {} /// [FhirElement("value", IsPrimitiveValue=true, XmlSerialization=XmlRepresentation.XmlAttr, InSummary=true, Order=30)] [DeclaredType(Type = typeof(SystemPrimitive.String))] + [UriPattern] [DataMember] public string Value { From 3155e5d6518fe1524d76afcb6cf9e1680c6ac916 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Thu, 21 Mar 2024 13:49:25 +0100 Subject: [PATCH 06/17] more unit test fixes --- src/Hl7.Fhir.Base/ElementModel/ElementNode.cs | 2 +- .../ElementModel/TypedElementOnSourceNode.cs | 2 +- .../ElementNodeTests.cs | 2 +- .../SourceNodeTests.cs | 2 +- .../SummarySerializationTests.cs | 36 +++++++++---------- .../TestDataVersionCheck.cs | 2 +- .../Validation/SearchDataExtraction.cs | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs index 4341f8473b..35ccd67888 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs @@ -128,7 +128,7 @@ internal ElementNode(string name, object? value, string? instanceType, IElementD Definition = definition; } - private IReadOnlyCollection _childDefinitions = Array.Empty(); + private IReadOnlyCollection _childDefinitions = null!; private IReadOnlyCollection getChildDefinitions(IStructureDefinitionSummaryProvider provider) { diff --git a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs index 3ab145158a..0dadbde315 100644 --- a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs @@ -473,7 +473,7 @@ private IEnumerable runAdditionalRules(IEnumerable { stateBag.TryGetValue(rule, out object? state); state = rule(child, this, state); - stateBag[rule] = state; + if (state != null) stateBag[rule] = state; } yield return child; diff --git a/src/Hl7.Fhir.ElementModel.Shared.Tests/ElementNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/ElementNodeTests.cs index ebab5cb164..016051f269 100644 --- a/src/Hl7.Fhir.ElementModel.Shared.Tests/ElementNodeTests.cs +++ b/src/Hl7.Fhir.ElementModel.Shared.Tests/ElementNodeTests.cs @@ -266,7 +266,7 @@ public void KeepsAnnotations() [TestMethod] public void CanBuildFromITypedElement() { - var tpXml = File.ReadAllText(@"TestData\fp-test-patient.xml"); + var tpXml = File.ReadAllText(@"TestData/fp-test-patient.xml"); var patientElem = (new FhirXmlParser()).Parse(tpXml).ToTypedElement(); var nodes = ElementNode.FromElement(patientElem); Assert.IsTrue(patientElem.IsEqualTo(nodes).Success); diff --git a/src/Hl7.Fhir.ElementModel.Shared.Tests/SourceNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/SourceNodeTests.cs index da484be55c..c1a25cf5be 100644 --- a/src/Hl7.Fhir.ElementModel.Shared.Tests/SourceNodeTests.cs +++ b/src/Hl7.Fhir.ElementModel.Shared.Tests/SourceNodeTests.cs @@ -116,7 +116,7 @@ public void KeepsAnnotations() [TestMethod] public void ReadsFromNav() { - var tpXml = File.ReadAllText(@"TestData\fp-test-patient.xml"); + var tpXml = File.ReadAllText(@"TestData/fp-test-patient.xml"); var xmlnode = FhirXmlNode.Parse(tpXml); var nodes = SourceNode.FromNode(xmlnode); Assert.IsTrue(xmlnode.IsEqualTo(nodes).Success); diff --git a/src/Hl7.Fhir.Shared.Tests/Serialization/SummarySerializationTests.cs b/src/Hl7.Fhir.Shared.Tests/Serialization/SummarySerializationTests.cs index c356b9e2d5..9528d91c01 100644 --- a/src/Hl7.Fhir.Shared.Tests/Serialization/SummarySerializationTests.cs +++ b/src/Hl7.Fhir.Shared.Tests/Serialization/SummarySerializationTests.cs @@ -256,16 +256,16 @@ public async T.Task TestBundleWithSummaryJson() { Dictionary data = new Dictionary { - { "summary\\bundle-summary-true.json", SummaryType.True }, - { "summary\\bundle-summary-false.json", SummaryType.False }, - { "summary\\bundle-summary-data.json", SummaryType.Data }, - { "summary\\bundle-summary-text.json", SummaryType.Text }, - { "summary\\bundle-summary-count.json", SummaryType.Count }, - { "summary\\bundle-summary-true.xml", SummaryType.True }, - { "summary\\bundle-summary-false.xml", SummaryType.False }, - { "summary\\bundle-summary-data.xml", SummaryType.Data }, - { "summary\\bundle-summary-text.xml", SummaryType.Text }, - { "summary\\bundle-summary-count.xml", SummaryType.Count } + { "summary/bundle-summary-true.json", SummaryType.True }, + { "summary/bundle-summary-false.json", SummaryType.False }, + { "summary/bundle-summary-data.json", SummaryType.Data }, + { "summary/bundle-summary-text.json", SummaryType.Text }, + { "summary/bundle-summary-count.json", SummaryType.Count }, + { "summary/bundle-summary-true.xml", SummaryType.True }, + { "summary/bundle-summary-false.xml", SummaryType.False }, + { "summary/bundle-summary-data.xml", SummaryType.Data }, + { "summary/bundle-summary-text.xml", SummaryType.Text }, + { "summary/bundle-summary-count.xml", SummaryType.Count } }; var patientOne = new Patient @@ -320,14 +320,14 @@ public async T.Task TestResourceWithSummary() { Dictionary data = new Dictionary { - { "summary\\summary-true.json", SummaryType.True }, - { "summary\\summary-false.json", SummaryType.False }, - { "summary\\summary-data.json", SummaryType.Data }, - { "summary\\summary-text.json", SummaryType.Text }, - { "summary\\summary-true.xml", SummaryType.True }, - { "summary\\summary-false.xml", SummaryType.False }, - { "summary\\summary-data.xml", SummaryType.Data }, - { "summary\\summary-text.xml", SummaryType.Text } + { "summary/summary-true.json", SummaryType.True }, + { "summary/summary-false.json", SummaryType.False }, + { "summary/summary-data.json", SummaryType.Data }, + { "summary/summary-text.json", SummaryType.Text }, + { "summary/summary-true.xml", SummaryType.True }, + { "summary/summary-false.xml", SummaryType.False }, + { "summary/summary-data.xml", SummaryType.Data }, + { "summary/summary-text.xml", SummaryType.Text } }; foreach (var pair in data) diff --git a/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs b/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs index 497cc591f3..22685cb65a 100644 --- a/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs +++ b/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs @@ -23,7 +23,7 @@ public class TestDataVersionCheck public async Tasks.Task VerifyAllTestData() { string location = typeof(TestDataHelper).GetTypeInfo().Assembly.Location; - var path = Path.GetDirectoryName(location) + "\\TestData"; + var path = Path.GetDirectoryName(location) + "/TestData"; Console.WriteLine(path); StringBuilder issues = new StringBuilder(); await ValidateFolder(path, path, issues); diff --git a/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs b/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs index 47526b5480..6e4f982a63 100644 --- a/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs +++ b/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs @@ -32,7 +32,7 @@ public partial class ValidateSearchExtractionAllExamplesTest [TestCategory("LongRunner")] public void SearchExtractionAllExamples() { - string examplesZip = @"TestData\examples.zip"; + string examplesZip = @"TestData/examples.zip"; FhirXmlParser parser = new(); int errorCount = 0; From 42597aec4299627eb7aa8c356e83c5e95f59ae37 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Thu, 21 Mar 2024 14:01:13 +0100 Subject: [PATCH 07/17] more unit test fixes --- .../SummarySerializationTests.cs | 36 +++++++++---------- .../TestDataVersionCheck.cs | 6 ++-- .../Model/StructureDefinition.cs | 2 +- .../TestDataVersionCheck.cs | 4 +-- .../SpecificationTestDataVersionCheck.cs | 2 +- .../SnapshotGeneratorManifestTests.cs | 2 +- .../Source/ArtifactSummaryTests.cs | 2 +- .../SpecificationTestDataVersionCheck.cs | 2 +- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Hl7.Fhir.STU3.Tests/Serialization/SummarySerializationTests.cs b/src/Hl7.Fhir.STU3.Tests/Serialization/SummarySerializationTests.cs index c908b9088e..93add63119 100644 --- a/src/Hl7.Fhir.STU3.Tests/Serialization/SummarySerializationTests.cs +++ b/src/Hl7.Fhir.STU3.Tests/Serialization/SummarySerializationTests.cs @@ -256,16 +256,16 @@ public async T.Task TestBundleWithSummaryJson() { Dictionary data = new Dictionary { - { "summary\\bundle-summary-true.json", SummaryType.True }, - { "summary\\bundle-summary-false.json", SummaryType.False }, - { "summary\\bundle-summary-data.json", SummaryType.Data }, - { "summary\\bundle-summary-text.json", SummaryType.Text }, - { "summary\\bundle-summary-count.json", SummaryType.Count }, - { "summary\\bundle-summary-true.xml", SummaryType.True }, - { "summary\\bundle-summary-false.xml", SummaryType.False }, - { "summary\\bundle-summary-data.xml", SummaryType.Data }, - { "summary\\bundle-summary-text.xml", SummaryType.Text }, - { "summary\\bundle-summary-count.xml", SummaryType.Count } + { "summary/bundle-summary-true.json", SummaryType.True }, + { "summary/bundle-summary-false.json", SummaryType.False }, + { "summary/bundle-summary-data.json", SummaryType.Data }, + { "summary/bundle-summary-text.json", SummaryType.Text }, + { "summary/bundle-summary-count.json", SummaryType.Count }, + { "summary/bundle-summary-true.xml", SummaryType.True }, + { "summary/bundle-summary-false.xml", SummaryType.False }, + { "summary/bundle-summary-data.xml", SummaryType.Data }, + { "summary/bundle-summary-text.xml", SummaryType.Text }, + { "summary/bundle-summary-count.xml", SummaryType.Count } }; var patientOne = new Patient @@ -320,14 +320,14 @@ public async T.Task TestResourceWithSummary() { Dictionary data = new Dictionary { - { "summary\\summary-true.json", SummaryType.True }, - { "summary\\summary-false.json", SummaryType.False }, - { "summary\\summary-data.json", SummaryType.Data }, - { "summary\\summary-text.json", SummaryType.Text }, - { "summary\\summary-true.xml", SummaryType.True }, - { "summary\\summary-false.xml", SummaryType.False }, - { "summary\\summary-data.xml", SummaryType.Data }, - { "summary\\summary-text.xml", SummaryType.Text } + { "summary/summary-true.json", SummaryType.True }, + { "summary/summary-false.json", SummaryType.False }, + { "summary/summary-data.json", SummaryType.Data }, + { "summary/summary-text.json", SummaryType.Text }, + { "summary/summary-true.xml", SummaryType.True }, + { "summary/summary-false.xml", SummaryType.False }, + { "summary/summary-data.xml", SummaryType.Data }, + { "summary/summary-text.xml", SummaryType.Text } }; foreach (var pair in data) diff --git a/src/Hl7.Fhir.STU3.Tests/TestDataVersionCheck.cs b/src/Hl7.Fhir.STU3.Tests/TestDataVersionCheck.cs index 497cc591f3..6bfaebc358 100644 --- a/src/Hl7.Fhir.STU3.Tests/TestDataVersionCheck.cs +++ b/src/Hl7.Fhir.STU3.Tests/TestDataVersionCheck.cs @@ -23,7 +23,7 @@ public class TestDataVersionCheck public async Tasks.Task VerifyAllTestData() { string location = typeof(TestDataHelper).GetTypeInfo().Assembly.Location; - var path = Path.GetDirectoryName(location) + "\\TestData"; + var path = Path.GetDirectoryName(location) + "/TestData"; Console.WriteLine(path); StringBuilder issues = new StringBuilder(); await ValidateFolder(path, path, issues); @@ -49,12 +49,12 @@ private async Tasks.Task ValidateFolder(string basePath, string path, StringBuil string content = File.ReadAllText(item); if (new FileInfo(item).Extension == ".xml") { - Console.WriteLine($" {item.Replace(path+"\\", "")}"); + Console.WriteLine($" {item.Replace(path+"//", "")}"); await xmlParser.ParseAsync(content); } else if (new FileInfo(item).Extension == ".json") { - Console.WriteLine($" {item.Replace(path + "\\", "")}"); + Console.WriteLine($" {item.Replace(path + "//", "")}"); await jsonParser.ParseAsync(content); } else diff --git a/src/Hl7.Fhir.STU3/Model/StructureDefinition.cs b/src/Hl7.Fhir.STU3/Model/StructureDefinition.cs index 9231a871f7..ea634c7e78 100644 --- a/src/Hl7.Fhir.STU3/Model/StructureDefinition.cs +++ b/src/Hl7.Fhir.STU3/Model/StructureDefinition.cs @@ -41,7 +41,7 @@ public interface IElementList : IModifierExtendable, INotifyPropertyChanged, IDe } // [WMR 20161005] Added specific debugger display attribute that includes the canonical url - [System.Diagnostics.DebuggerDisplay("\\{\"{TypeName,nq}/{Id,nq}\" Identity={DebuggerDisplay}} Url={Url}")] + [System.Diagnostics.DebuggerDisplay("/{\"{TypeName,nq}/{Id,nq}\" Identity={DebuggerDisplay}} Url={Url}")] public partial class StructureDefinition { [DebuggerBrowsable(DebuggerBrowsableState.Never)] diff --git a/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs b/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs index 22685cb65a..0a5837b073 100644 --- a/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs +++ b/src/Hl7.Fhir.Shared.Tests/TestDataVersionCheck.cs @@ -49,12 +49,12 @@ private async Tasks.Task ValidateFolder(string basePath, string path, StringBuil string content = File.ReadAllText(item); if (new FileInfo(item).Extension == ".xml") { - Console.WriteLine($" {item.Replace(path+"\\", "")}"); + Console.WriteLine($" {item.Replace(path+"/", "")}"); await xmlParser.ParseAsync(content); } else if (new FileInfo(item).Extension == ".json") { - Console.WriteLine($" {item.Replace(path + "\\", "")}"); + Console.WriteLine($" {item.Replace(path + "/", "")}"); await jsonParser.ParseAsync(content); } else diff --git a/src/Hl7.Fhir.Specification.STU3.Tests/SpecificationTestDataVersionCheck.cs b/src/Hl7.Fhir.Specification.STU3.Tests/SpecificationTestDataVersionCheck.cs index 052a5a1971..2a4362455d 100644 --- a/src/Hl7.Fhir.Specification.STU3.Tests/SpecificationTestDataVersionCheck.cs +++ b/src/Hl7.Fhir.Specification.STU3.Tests/SpecificationTestDataVersionCheck.cs @@ -20,7 +20,7 @@ public class SpecificationTestDataVersionCheck public async Tasks.Task VerifyAllTestDataSpecification() { string location = typeof(TestDataHelper).GetTypeInfo().Assembly.Location; - var path = Path.GetDirectoryName(location) + "\\TestData"; + var path = Path.GetDirectoryName(location) + "/TestData"; Console.WriteLine(path); List issues = new List(); await ValidateFolder(path, path, issues); diff --git a/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorManifestTests.cs b/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorManifestTests.cs index f9d2303c13..f9b4c2568b 100644 --- a/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorManifestTests.cs +++ b/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorManifestTests.cs @@ -48,7 +48,7 @@ namespace Hl7.Fhir.Specification.Tests [TestClass, TestCategory("Snapshot")] public class SnapshotGeneratorManifestTests { - const string ManifestPath = @"TestData\snapshot-test\Type Slicing"; + const string ManifestPath = @"TestData/snapshot-test/Type Slicing"; const string ManifestFileName = "manifest.xml"; //const string ExtensionsPath = @"C:\Users\Michel\.fhir\packages\simplifier.core.r4.extensions-4.0.0\package"; diff --git a/src/Hl7.Fhir.Specification.Shared.Tests/Source/ArtifactSummaryTests.cs b/src/Hl7.Fhir.Specification.Shared.Tests/Source/ArtifactSummaryTests.cs index 7474925f10..20e03f3f05 100644 --- a/src/Hl7.Fhir.Specification.Shared.Tests/Source/ArtifactSummaryTests.cs +++ b/src/Hl7.Fhir.Specification.Shared.Tests/Source/ArtifactSummaryTests.cs @@ -458,7 +458,7 @@ public void TestSummarizeAnonymousResources() [TestMethod] public void TestErrorSummaries() { - string path = Path.Combine(Directory.GetCurrentDirectory(), @"TestData\grahame-validation-examples"); + string path = Path.Combine(Directory.GetCurrentDirectory(), @"TestData/grahame-validation-examples"); var dirSource = new DirectorySource(path, new DirectorySourceSettings(includeSubdirectories: false)); var summaries = dirSource.ListSummaries().ToList(); Assert.IsNotNull(summaries); diff --git a/src/Hl7.Fhir.Specification.Shared.Tests/SpecificationTestDataVersionCheck.cs b/src/Hl7.Fhir.Specification.Shared.Tests/SpecificationTestDataVersionCheck.cs index 1a0b094306..1e20396084 100644 --- a/src/Hl7.Fhir.Specification.Shared.Tests/SpecificationTestDataVersionCheck.cs +++ b/src/Hl7.Fhir.Specification.Shared.Tests/SpecificationTestDataVersionCheck.cs @@ -20,7 +20,7 @@ public partial class SpecificationTestDataVersionCheck public async Tasks.Task VerifyAllTestDataSpecification() { string location = typeof(TestDataHelper).GetTypeInfo().Assembly.Location; - var path = Path.GetDirectoryName(location) + "\\TestData"; + var path = Path.GetDirectoryName(location) + "/TestData"; Console.WriteLine(path); List issues = new List(); await ValidateFolder(path, path, issues); From 924a30abb4bf489c388c02fe577d0a098d89885c Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Thu, 21 Mar 2024 14:47:17 +0100 Subject: [PATCH 08/17] Solved merge conflicts --- src/Hl7.Fhir.Base/ElementModel/ElementNode.cs | 2 +- .../Serialization/engine/IFhirSerializationEngine.cs | 4 ++-- .../Serialization/engine/PocoSerializationEngine.cs | 4 ---- .../Serialization/engine/PocoSerializationEngine_Json.cs | 2 -- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs index e6f18e55e9..7f230091df 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs @@ -96,7 +96,7 @@ public static bool TryConvertToElementValue(object? value, [NotNullWhen(true)] o values switch { null => EmptyList, - [var one] => [toTT(one)], + [var one] => [toTT(one)!], _ => values.Select(toTT).ToList()! }; diff --git a/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs index 01fb26d397..b26c11df2a 100644 --- a/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs +++ b/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs @@ -1,7 +1,7 @@ -/* +/* * Copyright (c) 2023, Firely (info@fire.ly) and contributors * See the file CONTRIBUTORS for details. - * + * * This file is licensed under the BSD 3-Clause license * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE */ diff --git a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs index 5eb38bba57..5ae6925590 100644 --- a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs +++ b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs @@ -10,15 +10,11 @@ using Hl7.Fhir.Introspection; using Hl7.Fhir.Model; -using Hl7.Fhir.Specification; using Hl7.Fhir.Utility; using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Text.Json; -using System.Xml; namespace Hl7.Fhir.Serialization { diff --git a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Json.cs b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Json.cs index eea780d6d4..5224a23247 100644 --- a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Json.cs +++ b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Json.cs @@ -1,8 +1,6 @@ #nullable enable -using Hl7.Fhir.Introspection; using Hl7.Fhir.Model; -using Hl7.Fhir.Utility; using System; using System.Linq; using System.Text.Json; From 1eb3fd672e6d22d7ccd72dfbbc8cb14b51284a81 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Thu, 21 Mar 2024 14:53:48 +0100 Subject: [PATCH 09/17] simplified ElementNode --- src/Hl7.Fhir.Base/ElementModel/ElementNode.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs index 7f230091df..1f3fe80465 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs @@ -19,7 +19,7 @@ namespace Hl7.Fhir.ElementModel { - public class ElementNode : DomNode, ITypedElement, IAnnotated, IAnnotatable, IShortPathGenerator + public class ElementNode : DomNode, ITypedElement, IAnnotated, IShortPathGenerator { /// /// Creates an implementation of ITypedElement that represents a primitive value @@ -135,7 +135,7 @@ internal ElementNode(string name, object? value, string? instanceType, IElementD private IReadOnlyCollection getChildDefinitions(IStructureDefinitionSummaryProvider provider) { - LazyInitializer.EnsureInitialized>(ref _childDefinitions, () => this.ChildDefinitions(provider)); + LazyInitializer.EnsureInitialized(ref _childDefinitions, () => this.ChildDefinitions(provider)); return _childDefinitions; } @@ -197,7 +197,7 @@ private void importChild(IStructureDefinitionSummaryProvider provider, ElementNo // we think it should be - this way you can safely first create a node representing // an independently created root for a resource of datatype, and then add it to the tree. var childDefs = getChildDefinitions(provider ?? throw Error.ArgumentNull(nameof(provider))); - var childDef = childDefs?.SingleOrDefault(cd => cd.ElementName == child.Name); + var childDef = childDefs.SingleOrDefault(cd => cd.ElementName == child.Name); child.Definition = childDef ?? child.Definition; // if we don't know about the definition, stick with the old one (if any) @@ -261,7 +261,7 @@ private static ElementNode buildNode(ITypedElement node, bool recursive, IEnumer me.AddAnnotation(ann); if (recursive) - me.ChildList.AddRange(node.Children()!.Select(c => buildNode(c, recursive: true, annotationsToCopy: annotationsToCopy, me))); + me.ChildList.AddRange(node.Children().Select(c => buildNode(c, recursive: true, annotationsToCopy: annotationsToCopy, me))); return me; } @@ -318,7 +318,7 @@ public string Location } else - return Name!; + return Name; } } @@ -341,7 +341,7 @@ public string ShortPath } } else - return Name!; + return Name; } } } From 7e62e6f43bed39d948d894028429d84e7ffcfc42 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Thu, 21 Mar 2024 15:00:44 +0100 Subject: [PATCH 10/17] fixed build warnings --- .../RoundtripAllSerializers.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs b/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs index ce410988f2..6b15a13ac2 100644 --- a/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs +++ b/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs @@ -28,12 +28,12 @@ public string RoundTripXml(string original) => engine.SerializeToXml( engine.DeserializeFromJson( engine.SerializeToJson( - engine.DeserializeFromXml(original)))); + engine.DeserializeFromXml(original)!))!); public string RoundTripJson(string original) => engine.SerializeToJson( engine.DeserializeFromXml( engine.SerializeToXml( - engine.DeserializeFromJson(original)))); + engine.DeserializeFromJson(original)!))!); } internal class TypedElementBasedRoundtripper(IStructureDefinitionSummaryProvider provider) : IRoundTripper @@ -249,7 +249,7 @@ public void TestMatchAndExactly(ZipArchiveEntry entry) ? NEW_POCO_ENGINE.DeserializeFromXml(input) : NEW_POCO_ENGINE.DeserializeFromJson(input); - var r2 = (Resource)resource.DeepCopy(); + var r2 = (Resource)resource!.DeepCopy(); Assert.IsTrue(resource.Matches(r2), "Serialization of " + name + " did not match output - Matches test"); Assert.IsTrue(resource.IsExactly(r2), From 72b1d27c76283bf682fa73a5acbc8cbabfc03cbf Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 27 Mar 2024 11:51:19 +0100 Subject: [PATCH 11/17] extra nullability --- src/Hl7.Fhir.Base/ElementModel/DomNode.cs | 16 ++++++------ src/Hl7.Fhir.Base/ElementModel/ElementNode.cs | 20 +++++++------- .../ElementModel/ITypedElement.cs | 2 +- .../ElementModel/PrimitiveElement.cs | 8 +++--- src/Hl7.Fhir.Base/Utility/AnnotationList.cs | 26 +++++++++++++++---- .../Utility/CollectionBuilderAttribute.cs | 25 ++++++++++++++++++ .../Utility/NullableAttribute.cs | 4 +-- .../ScopedNodeTests.cs | 2 +- 8 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 src/Hl7.Fhir.Base/Utility/CollectionBuilderAttribute.cs diff --git a/src/Hl7.Fhir.Base/ElementModel/DomNode.cs b/src/Hl7.Fhir.Base/ElementModel/DomNode.cs index a9c7fcbb21..bd1e4b0977 100644 --- a/src/Hl7.Fhir.Base/ElementModel/DomNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/DomNode.cs @@ -20,11 +20,11 @@ public class DomNode : IAnnotatable where T : DomNode { public string Name { get; set; } = null!; - private List? _childList = null; + private List? _childList; protected List ChildList { - get => LazyInitializer.EnsureInitialized(ref _childList, () => new()) ?? throw new InvalidOperationException(); + get => LazyInitializer.EnsureInitialized(ref _childList, () => [])!; set => _childList = value; } @@ -33,24 +33,24 @@ internal IEnumerable ChildrenInternal(string? name = null) => public T? Parent { get; protected set; } - public DomNodeList this[string name] => new DomNodeList(ChildrenInternal(name)); + public DomNodeList this[string name] => new (ChildrenInternal(name)); - public T? this[int index] => ChildList?[index]; + public T this[int index] => ChildList[index]; #region << Annotations >> - private AnnotationList? _annotations = null; - protected AnnotationList? AnnotationsInternal => LazyInitializer.EnsureInitialized(ref _annotations, () => new()); + private AnnotationList? _annotations; + protected AnnotationList AnnotationsInternal => LazyInitializer.EnsureInitialized(ref _annotations, () => [])!; protected bool HasAnnotations => _annotations is not null && !_annotations.IsEmpty; public void AddAnnotation(object annotation) { - AnnotationsInternal!.AddAnnotation(annotation); + AnnotationsInternal.AddAnnotation(annotation); } public void RemoveAnnotations(Type type) { - AnnotationsInternal!.RemoveAnnotations(type); + AnnotationsInternal.RemoveAnnotations(type); } #endregion } diff --git a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs index 1f3fe80465..6298866f86 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs @@ -29,7 +29,7 @@ public class ElementNode : DomNode, ITypedElement, IAnnotated, ISho // HACK: For now, allow a Quantity (which is NOT a primitive) in the .Value property // of ITypedElement. This is a temporary situation to make a quick & dirty upgrade of // FP to Normative (with Quantity support) possible. - public static ITypedElement ForPrimitive(object? value) + public static ITypedElement ForPrimitive(object value) { return value switch { @@ -92,12 +92,12 @@ public static bool TryConvertToElementValue(object? value, [NotNullWhen(true)] o /// /// /// - public static IEnumerable CreateList(params object[] values) => + public static IEnumerable CreateList(params object[] values) => values switch { null => EmptyList, - [var one] => [toTT(one)!], - _ => values.Select(toTT).ToList()! + [var one] => [toTe(one)!], + _ => values.Select(toTe).ToList()! }; /// @@ -106,13 +106,13 @@ public static bool TryConvertToElementValue(object? value, [NotNullWhen(true)] o /// /// /// - public static IEnumerable CreateList(IEnumerable values) => values switch + public static IEnumerable CreateList(IEnumerable values) => values switch { null => EmptyList, - _ => values.Select(toTT).ToList()! + _ => values.Select(toTe).ToList()! }; - private static ITypedElement? toTT(object value) => value switch + private static ITypedElement? toTe(object? value) => value switch { null => null, ITypedElement element => element, @@ -123,7 +123,7 @@ public static bool TryConvertToElementValue(object? value, [NotNullWhen(true)] o public static readonly IEnumerable EmptyList = []; public IEnumerable Children(string? name = null) => ChildrenInternal(name); - internal ElementNode(string name, object? value, string? instanceType, IElementDefinitionSummary? definition) + private ElementNode(string name, object? value, string? instanceType, IElementDefinitionSummary? definition) { Name = name ?? throw new ArgumentNullException(nameof(name)); InstanceType = instanceType; @@ -285,7 +285,7 @@ public ElementNode ShallowCopy() }; if (HasAnnotations) - copy.AnnotationsInternal!.AddRange(AnnotationsInternal); + copy.AnnotationsInternal.AddRange(AnnotationsInternal); return copy; } @@ -301,7 +301,7 @@ public IEnumerable Annotations(Type type) if (type == null) throw new ArgumentNullException(nameof(type)); return (type == typeof(ElementNode) || type == typeof(ITypedElement) || type == typeof(IShortPathGenerator)) ? (new[] { this }) - : HasAnnotations ? AnnotationsInternal!.OfType(type) : Enumerable.Empty(); + : HasAnnotations ? AnnotationsInternal.OfType(type) : Enumerable.Empty(); } public string Location diff --git a/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs index 3263deb618..bfe5cc4cb6 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs @@ -31,7 +31,7 @@ public interface ITypedElement : IBaseElementNavigator /// An indication of the location of this node within the data represented by the ITypedElement. /// /// The format of the location is the dotted name of the property, including indices to make - /// sure repeated occurences of an element can be distinguished. It needs to be sufficiently precise to aid + /// sure repeated occurrences of an element can be distinguished. It needs to be sufficiently precise to aid /// the user in locating issues in the data. string Location { get; } diff --git a/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs b/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs index ddd8356e69..5279489210 100644 --- a/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs +++ b/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs @@ -39,7 +39,7 @@ private PrimitiveElement(object value, string instanceType, string name) Name = name ?? throw new ArgumentNullException(nameof(name)); } - public PrimitiveElement(object? value, string? name = null, bool useFullTypeName = false) + public PrimitiveElement(object value, string? name = null, bool useFullTypeName = false) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -54,13 +54,11 @@ public PrimitiveElement(object? value, string? name = null, bool useFullTypeName InstanceType = useFullTypeName ? systemType.FullName : systemType.Name; Name = name ?? "@primitivevalue@"; } - - - + public string Name { get; private set; } - public object? Value { get; private set; } + public object Value { get; private set; } public string InstanceType { get; private set; } diff --git a/src/Hl7.Fhir.Base/Utility/AnnotationList.cs b/src/Hl7.Fhir.Base/Utility/AnnotationList.cs index dad5cafc25..7a022c8d49 100644 --- a/src/Hl7.Fhir.Base/Utility/AnnotationList.cs +++ b/src/Hl7.Fhir.Base/Utility/AnnotationList.cs @@ -6,30 +6,42 @@ * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE */ -using Hl7.Fhir.Utility; using System; +using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace Hl7.Fhir.Utility { /// - /// This class implements the interfaces IAnnotatable and IAnnotated. It can be used by the classes that also implements these + /// This class implements the interfaces and . It can be used by the classes that also implements these /// interfaces to have a common implementation. /// This list is thread safe /// - public class AnnotationList : IAnnotatable, IAnnotated + [CollectionBuilder(typeof(AnnotationList), nameof(AnnotationList.create) )] + public class AnnotationList : IAnnotatable, IAnnotated, IEnumerable { private Lazy>> _annotations = new Lazy>>(() => new ConcurrentDictionary>()); private ConcurrentDictionary> annotations { get { return _annotations.Value; } } + public static AnnotationList create(ReadOnlySpan annotations) + { + var list = new AnnotationList(); + foreach (var annotation in annotations) + { + list.AddAnnotation(annotation); + } + return list; + } + public void AddAnnotation(object annotation) { annotations.AddOrUpdate( annotation.GetType(), - new List() { annotation }, - (t, existingList) => new List(existingList) { annotation }); + [annotation], + (_, existingList) => [..existingList, annotation]); } public void RemoveAnnotations(Type type) => annotations.TryRemove(type, out _); @@ -59,5 +71,9 @@ public void AddRange(AnnotationList source) { _annotations = new Lazy>>(() => new ConcurrentDictionary>(source.annotations)); } + + IEnumerator IEnumerable.GetEnumerator() => annotations.Values.SelectMany(v => v).GetEnumerator(); + + public IEnumerator GetEnumerator() => ((IEnumerable)this).GetEnumerator(); } } diff --git a/src/Hl7.Fhir.Base/Utility/CollectionBuilderAttribute.cs b/src/Hl7.Fhir.Base/Utility/CollectionBuilderAttribute.cs new file mode 100644 index 0000000000..65d68a812b --- /dev/null +++ b/src/Hl7.Fhir.Base/Utility/CollectionBuilderAttribute.cs @@ -0,0 +1,25 @@ +#nullable enable + +#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_0 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] + public sealed class CollectionBuilderAttribute : Attribute + { + /// Initializes a new instance of that refers to the method on the type. + /// The type of the builder to use to construct the collection. + /// The name of the method on the builder to use to construct the collection. + public CollectionBuilderAttribute(Type builderType, string methodName) + { + this.BuilderType = builderType; + this.MethodName = methodName; + } + + /// Gets the type of the builder to use to construct the collection. + public Type BuilderType { get; } + + /// Gets the name of the method on the builder to use to construct the collection. + public string MethodName { get; } + } +} +#endif \ No newline at end of file diff --git a/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs b/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs index 6e55499c3e..e49f933799 100644 --- a/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs +++ b/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs @@ -8,7 +8,7 @@ namespace System.Diagnostics.CodeAnalysis { -#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 +#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// Specifies that null is allowed as an input even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] #if SYSTEM_PRIVATE_CORELIB @@ -137,7 +137,7 @@ sealed class DoesNotReturnIfAttribute : Attribute } #endif -#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_0 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 +#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_0 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// Specifies that the method or property will ensure that the listed field and property members have not-null values. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] #if SYSTEM_PRIVATE_CORELIB diff --git a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs index 6c4c89a6f4..ce40defeb2 100644 --- a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs +++ b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs @@ -313,7 +313,7 @@ private class TypedElementWithoutDefinition : ITypedElement, IResourceTypeSuppli public string Name => _wrapped.Name; - public string? InstanceType => _wrapped.InstanceType; + public string InstanceType => _wrapped.InstanceType; public object? Value => _wrapped.Value; From ce7ab6b379001afbbffdd87e4aac398fdd9aa20c Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 27 Mar 2024 13:28:29 +0100 Subject: [PATCH 12/17] elementmodel and types --- .../ElementModel/TypedElementOnSourceNode.cs | 8 ++-- src/Hl7.Fhir.Base/ElementModel/Types/Any.cs | 6 +-- .../ElementModel/Types/Concept.cs | 4 +- src/Hl7.Fhir.Base/ElementModel/Types/Date.cs | 4 +- .../ElementModel/Types/DateTime.cs | 2 +- .../ElementModel/Types/Decimal.cs | 17 ++++---- .../ElementModel/Types/Integer.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Long.cs | 2 +- .../ElementModel/Types/Quantity.cs | 2 +- .../ElementModel/Types/String.cs | 2 +- src/Hl7.Fhir.Base/ElementModel/Types/Time.cs | 4 +- .../ScopedNodeTests.cs | 41 ++++++++++--------- 12 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs index ede8590a8d..57e66ef588 100644 --- a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs @@ -39,7 +39,7 @@ public TypedElementOnSourceNode(ISourceNode source, string? type, IStructureDefi (InstanceType, Definition) = buildRootPosition(type); } - private (string instanceType, IElementDefinitionSummary? definition) buildRootPosition(string? type) + private (string? instanceType, IElementDefinitionSummary? definition) buildRootPosition(string? type) { var rootType = type ?? _source.GetResourceTypeIndicator(); if (rootType == null) @@ -48,7 +48,7 @@ public TypedElementOnSourceNode(ISourceNode source, string? type, IStructureDefi throw Error.Format(nameof(type), $"Cannot determine the type of the root element at '{_source.Location}', " + $"please supply a type argument."); else - return ("Base", null); + return (null, null); } var elementType = Provider.Provide(rootType); @@ -97,7 +97,7 @@ private void raiseTypeError(string message, object source, bool warning = false, ExceptionHandler.NotifyOrThrow(source, notification); } - public string InstanceType { get; private set; } + public string? InstanceType { get; private set; } private readonly ISourceNode _source; @@ -489,7 +489,7 @@ private IEnumerable runAdditionalRules(IEnumerable public string ShortPath { get; private set; } public override string ToString() => - $"{(($"[{InstanceType}] "))}{_source}"; + $"{(InstanceType != null ? ($"[{InstanceType}] ") : "")}{_source}"; public IEnumerable Annotations(Type type) { diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs index 889e254dd4..072a4e3a32 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs @@ -77,9 +77,9 @@ public static bool TryParse(string value, Type primitiveType, [NotNullWhen(true) else if (primitiveType == typeof(Decimal)) return (Decimal.TryParse(value, out var p), p?.Value); else if (primitiveType == typeof(Integer)) - return (Integer.TryParse(value, out var p), p?.Value); + return (Integer.TryParse(value, out var p), p.Value); else if (primitiveType == typeof(Long)) - return (Long.TryParse(value, out var p), p?.Value); + return (Long.TryParse(value, out var p), p.Value); else if (primitiveType == typeof(Date)) return (Date.TryParse(value, out var p), p); else if (primitiveType == typeof(DateTime)) @@ -91,7 +91,7 @@ public static bool TryParse(string value, Type primitiveType, [NotNullWhen(true) else if (primitiveType == typeof(Quantity)) return (Quantity.TryParse(value, out var p), p); else if (primitiveType == typeof(String)) - return (String.TryParse(value, out var p), p?.Value); + return (String.TryParse(value, out var p), p.Value); else return (false, null); } diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs index 5aad7693ca..b1c66d58df 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs @@ -33,10 +33,10 @@ public Concept(IEnumerable codes, string? display = null) public static Concept Parse(string representation) => throw new NotImplementedException(); public static bool TryParse(string representation, [NotNullWhen(true)] out Concept? value) => throw new NotImplementedException(); - public override bool Equals(object? obj) => obj is Concept c && Enumerable.SequenceEqual(Codes, c.Codes) && Display == c.Display; + public override bool Equals(object? obj) => obj is Concept c && Codes.SequenceEqual(c.Codes) && Display == c.Display; public override int GetHashCode() => (Codes, Display).GetHashCode(); - public override string ToString() => string.Join(", ", Codes) + Display != null ? $" \"{Display}\"" : ""; + public override string ToString() => string.Join(", ", Codes) + (Display != null ? $" \"{Display}\"" : ""); Result ICqlConvertible.TryConvertToConcept() => Ok(this); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs index 55ee038413..d0b633197e 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs @@ -30,7 +30,7 @@ private Date(DateTimeOffset value, DateTimePrecision precision, bool hasOffset) public static Date Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid date."); - public static bool TryParse(string representation, [NotNullWhen(true)] out Date? value) => tryParse(representation, out value); + public static bool TryParse(string representation, out Date value) => tryParse(representation, out value); public static Date FromDateTimeOffset(DateTimeOffset dto, DateTimePrecision prec = DateTimePrecision.Day, bool includeOffset = false) => new(dto, prec, includeOffset); @@ -106,7 +106,7 @@ public DateTimeOffset ToDateTimeOffset(int hours, int minutes, int seconds, int /// Converts the date to a full DateTimeOffset instance. /// /// - private static bool tryParse(string representation, [NotNullWhen(true)] out Date? value) + private static bool tryParse(string representation, [NotNullWhen(true)] out Date value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs index cfe2a4cf59..c79ad78aaa 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs @@ -105,7 +105,7 @@ public DateTimeOffset ToDateTimeOffset(TimeSpan defaultOffset) => new("^" + DATETIMEFORMAT + "$", RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled | RegexOptions.ExplicitCapture); - private static bool tryParse(string representation, [NotNullWhen(true)] out DateTime? value) + private static bool tryParse(string representation, out DateTime value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs index a09ec9381a..989fa12e6a 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs @@ -20,9 +20,7 @@ namespace Hl7.Fhir.ElementModel.Types { public class Decimal : Any, IComparable, ICqlEquatable, ICqlOrderable, ICqlConvertible { - public Decimal() : this(default) { } - - public Decimal(decimal value) => Value = value; + public Decimal(decimal value = default) => Value = value; public decimal Value { get; } @@ -31,7 +29,7 @@ public Decimal() : this(default) { } private static readonly string[] FORBIDDEN_DECIMAL_PREFIXES = new[] { "+", "." }; public static Decimal Parse(string value) => - TryParse(value, out var result) ? result! : throw new FormatException($"String '{value}' was not recognized as a valid decimal."); + TryParse(value, out var result) ? result : throw new FormatException($"String '{value}' was not recognized as a valid decimal."); public static bool TryParse(string representation, [NotNullWhen(true)] out Decimal? value) { @@ -39,13 +37,14 @@ public static bool TryParse(string representation, [NotNullWhen(true)] out Decim value = default; - if (FORBIDDEN_DECIMAL_PREFIXES.Any(prefix => representation.StartsWith(prefix)) || representation.EndsWith(".")) + if (FORBIDDEN_DECIMAL_PREFIXES.Any(representation.StartsWith) || representation.EndsWith(".")) return false; - (var succ, var val) = Any.DoConvert(() => decimal.Parse(representation, NumberStyles.AllowDecimalPoint | - NumberStyles.AllowExponent | - NumberStyles.AllowLeadingSign, - CultureInfo.InvariantCulture)); + var (succ, val) = Any.DoConvert(() => + decimal.Parse(representation, + NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, + CultureInfo.InvariantCulture)); + value = new Decimal(val); return succ; } diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs index e5d23fbf2f..e05d1e8a4b 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs @@ -27,7 +27,7 @@ public Integer() : this(default) { } public static Integer Parse(string value) => TryParse(value, out var result) ? result : throw new FormatException($"String '{value}' was not recognized as a valid integer."); - public static bool TryParse(string representation, [NotNullWhen(true)] out Integer? value) + public static bool TryParse(string representation, out Integer value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs index 52a349414c..a2250d1e52 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs @@ -27,7 +27,7 @@ public Long() : this(default) { } public static Long Parse(string value) => TryParse(value, out var result) ? result : throw new FormatException($"String '{value}' was not recognized as a valid long integer."); - public static bool TryParse(string representation, [NotNullWhen(true)] out Long? value) + public static bool TryParse(string representation, out Long value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs index 7be49773eb..51ecbeb826 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs @@ -84,7 +84,7 @@ public static Quantity ForCalendarDuration(decimal value, string calendarUnit) public static Quantity Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid quantity."); - public static bool TryParse(string representation, [NotNullWhen(true)] out Quantity? quantity) + public static bool TryParse(string representation, out Quantity quantity) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs index 740904be15..dedb3a0944 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs @@ -29,7 +29,7 @@ public static String Parse(string value) => // Actually, it's not that trivial, since CQL strings accept a subset of C#'s escape sequences, // we *could* validate those here. - public static bool TryParse(string representation, [NotNullWhen(true)] out String? value) + public static bool TryParse(string representation, out String value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs index 973c999d2b..8658062a19 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs @@ -31,7 +31,7 @@ private Time(DateTimeOffset parsedValue, DateTimePrecision precision, bool hasOf public static Time Parse(string representation) => TryParse(representation, out var result) ? result : throw new FormatException($"String '{representation}' was not recognized as a valid time."); - public static bool TryParse(string representation, [NotNullWhen(true)] out Time? value) => tryParse(representation, out value); + public static bool TryParse(string representation, [NotNullWhen(true)] out Time value) => tryParse(representation, out value); public static Time FromDateTimeOffset(DateTimeOffset dto, DateTimePrecision prec = DateTimePrecision.Fraction, bool includeOffset = false) => new(dto, prec, includeOffset); @@ -101,7 +101,7 @@ public DateTimeOffset ToDateTimeOffset(int year, int month, int day, TimeSpan de private static readonly Regex PARTIALTIMEREGEX = new Regex("^" + PARTIALTIMEFORMAT + "$", RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled | RegexOptions.ExplicitCapture); - private static bool tryParse(string representation, [NotNullWhen(true)] out Time? value) + private static bool tryParse(string representation, out Time value) { if (representation is null) throw new ArgumentNullException(nameof(representation)); diff --git a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs index ce40defeb2..a0b48d11f0 100644 --- a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs +++ b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs @@ -92,9 +92,9 @@ public void KeepScopesContained() entry = entry.Children("resource").FirstOrDefault() as ScopedNode; Assert.IsNotNull(entry); - entry = entry!.Children("contained").FirstOrDefault() as ScopedNode; + entry = entry.Children("contained").FirstOrDefault() as ScopedNode; Assert.IsNotNull(entry); - Assert.AreNotEqual("Bundle", entry!.InstanceType); + Assert.AreNotEqual("Bundle", entry.InstanceType); Assert.IsTrue(entry.AtResource); Assert.AreEqual("Bundle.entry[6].resource[0].contained[0]", entry.Location); @@ -103,7 +103,7 @@ public void KeepScopesContained() entry = entry.Children("id").FirstOrDefault() as ScopedNode; Assert.IsNotNull(entry); - Assert.AreNotEqual("Bundle", entry!.InstanceType); + Assert.AreNotEqual("Bundle", entry.InstanceType); Assert.IsFalse(entry.AtResource); Assert.AreEqual("Bundle.entry[6].resource[0].contained[0].id[0]", entry.Location); @@ -144,17 +144,17 @@ public void GetFullUrl() Assert.AreEqual("http://example.org/fhir/Patient/b", entries[3].FullUrl); var entry3 = entries[3].Resource; - entry3 = entry3!.Children("managingOrganization").FirstOrDefault() as ScopedNode; + entry3 = entry3?.Children("managingOrganization").FirstOrDefault() as ScopedNode; Assert.IsNotNull(entry3); - entry3 = entry3!.Children("reference").FirstOrDefault() as ScopedNode; + entry3 = entry3.Children("reference").FirstOrDefault() as ScopedNode; Assert.IsNotNull(entry3); - Assert.AreEqual(entries[3].FullUrl, entry3!.FullUrl()); - Assert.AreEqual(entry3!.ParentResource!.FullUrl(), entry3.FullUrl()); + Assert.AreEqual(entries[3].FullUrl, entry3.FullUrl()); + Assert.AreEqual(entry3.ParentResource!.FullUrl(), entry3.FullUrl()); var entry6 = entries[6].Resource; - entry6 = entry6!.Children("contained").Skip(1).FirstOrDefault() as ScopedNode; + entry6 = entry6?.Children("contained").Skip(1).FirstOrDefault() as ScopedNode; Assert.IsNotNull(entry6); - Assert.AreEqual("#orgY", entry6!.Id()); + Assert.AreEqual("#orgY", entry6.Id()); Assert.AreEqual(entries[6].FullUrl, entry6.FullUrl()); Assert.AreEqual(entry6.ParentResource!.FullUrl(), entry6.FullUrl()); } @@ -165,9 +165,9 @@ public void TestMakeAbsolute() var inner0 = _bundleNode!.Children("entry").First().Children("resource").Children("active").SingleOrDefault() as ScopedNode; Assert.IsNotNull(inner0); - Assert.AreEqual("http://example.org/fhir/Patient/3", inner0!.MakeAbsolute("Patient/3")); - Assert.AreEqual("http://nu.nl/myPat/3x", inner0!.MakeAbsolute("http://nu.nl/myPat/3x")); - Assert.AreEqual("http://example.org/fhir/Organization/5", inner0!.MakeAbsolute("http://example.org/fhir/Organization/5")); + Assert.AreEqual("http://example.org/fhir/Patient/3", inner0.MakeAbsolute("Patient/3")); + Assert.AreEqual("http://nu.nl/myPat/3x", inner0.MakeAbsolute("http://nu.nl/myPat/3x")); + Assert.AreEqual("http://example.org/fhir/Organization/5", inner0.MakeAbsolute("http://example.org/fhir/Organization/5")); var inner1 = _bundleNode.Children("entry").Skip(1).First().Children("resource").Children("active").SingleOrDefault() as ScopedNode; @@ -197,7 +197,7 @@ public void TestResolve() ScopedNode inner7 = (_bundleNode!.Children("entry").Skip(6).First().Children("resource").Children("managingOrganization").SingleOrDefault() as ScopedNode)!; Assert.AreEqual("Bundle.entry[6].resource[0]", inner7.Resolve("http://example.org/fhir/Patient/e")!.Location); - Assert.AreEqual("Bundle.entry[6].resource[0].contained[1]", inner7!.Resolve("#orgY")!.Location); + Assert.AreEqual("Bundle.entry[6].resource[0].contained[1]", inner7.Resolve("#orgY")!.Location); Assert.AreEqual("Bundle.entry[6].resource[0]", inner7.Resolve("#e")!.Location); Assert.AreEqual("Bundle.entry[5].resource[0]", inner7.Resolve("http://example.org/fhir/Patient/d")!.Location); Assert.AreEqual("Bundle.entry[5].resource[0]", inner7.Resolve("Patient/d")!.Location); @@ -206,7 +206,7 @@ public void TestResolve() Assert.IsNull(inner7.Resolve("http://nu.nl/3")); Assert.AreEqual("Bundle.entry[6].resource[0].contained[1]", inner7.Resolve()!.Location); - Assert.IsTrue(inner7!.Children("reference").Any()); + Assert.IsTrue(inner7.Children("reference").Any()); Assert.AreEqual("Bundle.entry[6].resource[0].contained[1]", inner7.Children("reference").First().Resolve()!.Location); string lastUrlResolved = ""; @@ -264,11 +264,12 @@ static bool CCDATypeNameMapper(string typeName, out string canonical) var assertXHtml = typedElement.Children("text"); Assert.IsNotNull(assertXHtml); - Assert.AreEqual(1, assertXHtml.Count()); - Assert.AreEqual("text", assertXHtml.First().Name); - Assert.AreEqual("xhtml", assertXHtml.First().InstanceType); - Assert.AreEqual("Section.text[0]", assertXHtml.First().Location); - Assert.IsNotNull(assertXHtml.First().Value); + IEnumerable typedElements = assertXHtml as ITypedElement[] ?? assertXHtml.ToArray(); + Assert.AreEqual(1, typedElements.Count()); + Assert.AreEqual("text", typedElements.First().Name); + Assert.AreEqual("xhtml", typedElements.First().InstanceType); + Assert.AreEqual("Section.text[0]", typedElements.First().Location); + Assert.IsNotNull(typedElements.First().Value); } @@ -313,7 +314,7 @@ private class TypedElementWithoutDefinition : ITypedElement, IResourceTypeSuppli public string Name => _wrapped.Name; - public string InstanceType => _wrapped.InstanceType; + public string? InstanceType => _wrapped.InstanceType; public object? Value => _wrapped.Value; From 30b1aa423498b04f859d913aa118f79b0db6b683 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 27 Mar 2024 14:25:25 +0100 Subject: [PATCH 13/17] revised nullability changes and applied some autofixes to specific warnings --- src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs | 2 +- .../Introspection/EnumMapping.cs | 2 +- .../Introspection/EnumMemberMapping.cs | 2 +- .../Introspection/PropertyMapping.cs | 2 +- src/Hl7.Fhir.Base/Model/Date.cs | 10 +- src/Hl7.Fhir.Base/Model/Extension.cs | 20 ++-- src/Hl7.Fhir.Base/Model/FhirDateTime.cs | 2 +- src/Hl7.Fhir.Base/Model/PrimitiveType.cs | 2 +- src/Hl7.Fhir.Base/Model/Time.cs | 8 +- .../Serialization/ElementMetadataFilter.cs | 1 - .../Serialization/XObjectExtensions.cs | 2 +- .../engine/IFhirSerializationEngine.cs | 4 +- .../Utility/FhirReleaseParser.cs | 2 +- src/Hl7.Fhir.Base/Utility/IAnnotated.cs | 2 +- src/Hl7.Fhir.Base/Utility/SemVersion.cs | 2 +- .../Utility/SerializationUtil.cs | 2 +- .../Source/Summary/ArtifactSummary.cs | 2 +- .../Source/Summary/ArtifactSummary.cs | 8 +- .../Model/ModelInfo.cs | 1 - .../Model/TimeTests.cs | 4 +- .../ElementModel/QuantityTests.cs | 98 +++++++++---------- 21 files changed, 82 insertions(+), 96 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs index da8b29f6d6..43e3f932d5 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs @@ -43,7 +43,7 @@ internal static bool TryCanonicalize(this Quantity quantity, [NotNullWhen(true)] } } - private static M.Quantity toUnitsOfMeasureQuantity(this decimal value, string unit) + private static M.Quantity toUnitsOfMeasureQuantity(this decimal value, string? unit) { Metric metric = (unit != null) ? SYSTEM.Value.Metric(unit) : new Metric(new List()); return new M.Quantity(value, metric); diff --git a/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs b/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs index 18a4caf75a..4d1a00e09f 100644 --- a/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/EnumMapping.cs @@ -49,7 +49,7 @@ public static bool TryGetMappingForEnum(Type t, FhirRelease release, [NotNullWhe /// /// For classes shared across FHIR versions, there may be metadata present for different versions /// of FHIR, the is used to select which subset of metadata to extract. - public static bool TryCreate(Type type, [NotNullWhen(true)]out EnumMapping? result, FhirRelease release = (FhirRelease)int.MaxValue) + public static bool TryCreate(Type type, [NotNullWhen(true)] out EnumMapping? result, FhirRelease release = (FhirRelease)int.MaxValue) { result = default; if (!type.IsEnum) return false; diff --git a/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs b/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs index b6b74739f4..55389f5966 100644 --- a/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/EnumMemberMapping.cs @@ -58,7 +58,7 @@ private EnumMemberMapping(FieldInfo fieldInfo, string code, string? system, obje /// /// Inspects the given enum member, extracting metadata from its attributes and creating a new . /// - public static bool TryCreate(FieldInfo member, [NotNullWhen(true)]out EnumMemberMapping? result, FhirRelease release = (FhirRelease)int.MaxValue, string? defaultSystem = null) + public static bool TryCreate(FieldInfo member, [NotNullWhen(true)] out EnumMemberMapping? result, FhirRelease release = (FhirRelease)int.MaxValue, string? defaultSystem = null) { result = null; if (ClassMapping.GetAttribute(member, release) is not { } ela) return false; diff --git a/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs b/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs index dd17a50a22..03e3257761 100644 --- a/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs +++ b/src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs @@ -173,7 +173,7 @@ private PropertyMapping( /// /// There should generally be no reason to call this method, as you can easily get the required PropertyMapping via /// a ClassMapping - which will cache this information as well. This constructor is public for historical reasons only. - public static bool TryCreate(PropertyInfo prop, [NotNullWhen(true)]out PropertyMapping? result, ClassMapping declaringClass, FhirRelease release) + public static bool TryCreate(PropertyInfo prop, [NotNullWhen(true)] out PropertyMapping? result, ClassMapping declaringClass, FhirRelease release) { if (prop == null) throw Error.ArgumentNull(nameof(prop)); result = default; diff --git a/src/Hl7.Fhir.Base/Model/Date.cs b/src/Hl7.Fhir.Base/Model/Date.cs index 7cbceba5e8..667f3644ad 100644 --- a/src/Hl7.Fhir.Base/Model/Date.cs +++ b/src/Hl7.Fhir.Base/Model/Date.cs @@ -67,7 +67,7 @@ public Date(int year) : this(string.Format(System.Globalization.CultureInfo.Inva [NonSerialized] // To prevent binary serialization from serializing this field private P.Date? _parsedValue = null; - // This is a sentintel value that marks that the current string representation is + // This is a sentinel value that marks that the current string representation is // not parseable, so we don't have to try again. It's value is never used, it's just // checked by reference. private static readonly P.Date INVALID_VALUE = P.Date.FromDateTimeOffset(DateTimeOffset.MinValue); @@ -76,7 +76,7 @@ public Date(int year) : this(string.Format(System.Globalization.CultureInfo.Inva /// Converts a Fhir Date to a . /// /// true if the Fhir Date contains a valid date string, false otherwise. - public bool TryToDate([NotNullWhen(true)]out P.Date? date) + public bool TryToDate(out P.Date? date) { if (_parsedValue is null) { @@ -131,11 +131,11 @@ protected override void OnObjectValueChanged() /// Convert this Fhir Date to a . /// /// True if the value of the Fhir Date is not null and can be parsed as a DateTimeOffset, false otherwise. - public bool TryToDateTimeOffset(out DateTimeOffset dto) + public bool TryToDateTimeOffset(out DateTimeOffset? dto) { if (Value is not null && TryToDate(out var dt)) { - dto = dt!.ToDateTimeOffset(TimeSpan.Zero); + dto = dt?.ToDateTimeOffset(TimeSpan.Zero); return true; } else @@ -148,7 +148,7 @@ public bool TryToDateTimeOffset(out DateTimeOffset dto) /// /// Checks whether the given literal is correctly formatted. /// - public static bool IsValidValue(string value) => P.Date.TryParse(value, out var parsed) && !parsed!.HasOffset; + public static bool IsValidValue(string value) => P.Date.TryParse(value, out var parsed) && !parsed.HasOffset; } } diff --git a/src/Hl7.Fhir.Base/Model/Extension.cs b/src/Hl7.Fhir.Base/Model/Extension.cs index d020f5d339..3d3bb72a9a 100644 --- a/src/Hl7.Fhir.Base/Model/Extension.cs +++ b/src/Hl7.Fhir.Base/Model/Extension.cs @@ -46,7 +46,7 @@ namespace Hl7.Fhir.Model /// Optional Extensions Element /// [Serializable] - [System.Diagnostics.DebuggerDisplay(@"\{Value={Value} Url={_Url}}")] + [System.Diagnostics.DebuggerDisplay(@"\{Value={Value} Url={_url}}")] [FhirType("Extension", "http://hl7.org/fhir/StructureDefinition/Extension")] [DataContract] [Bindable(true)] @@ -74,11 +74,11 @@ public Extension(string url, DataType value) [DataMember] public string? Url { - get { return _Url; } - set { _Url = value; OnPropertyChanged("Url"); } + get { return _url; } + set { _url = value; OnPropertyChanged("Url"); } } - private string? _Url; + private string? _url; /// /// Value of extension @@ -87,17 +87,15 @@ public string? Url [DataMember] public DataType? Value { - get { return _Value; } - set { _Value = value; OnPropertyChanged("Value"); } + get { return _value; } + set { _value = value; OnPropertyChanged("Value"); } } - private DataType? _Value; + private DataType? _value; public override IDeepCopyable CopyTo(IDeepCopyable other) { - var dest = other as Extension; - - if (dest != null) + if (other is Extension dest) { base.CopyTo(dest); if (Url != null) dest.Url = Url; @@ -105,7 +103,7 @@ public override IDeepCopyable CopyTo(IDeepCopyable other) return dest; } else - throw new ArgumentException("Can only copy to an object of the same type", "other"); + throw new ArgumentException("Can only copy to an object of the same type", nameof(other)); } public override IDeepCopyable DeepCopy() diff --git a/src/Hl7.Fhir.Base/Model/FhirDateTime.cs b/src/Hl7.Fhir.Base/Model/FhirDateTime.cs index 8a3d962a59..f7136581e9 100644 --- a/src/Hl7.Fhir.Base/Model/FhirDateTime.cs +++ b/src/Hl7.Fhir.Base/Model/FhirDateTime.cs @@ -98,7 +98,7 @@ public FhirDateTime(int year) /// Converts a FhirDateTime to a . /// /// true if the FhirDateTime contains a valid date/time string, false otherwise. - public bool TryToDateTime([NotNullWhen(true)]out P.DateTime? dateTime) + public bool TryToDateTime([NotNullWhen(true)] out P.DateTime? dateTime) { if (_parsedValue is null) { diff --git a/src/Hl7.Fhir.Base/Model/PrimitiveType.cs b/src/Hl7.Fhir.Base/Model/PrimitiveType.cs index 96196e6047..4deb2f2173 100644 --- a/src/Hl7.Fhir.Base/Model/PrimitiveType.cs +++ b/src/Hl7.Fhir.Base/Model/PrimitiveType.cs @@ -114,7 +114,7 @@ public override bool IsExactly(IDeepComparable other) public override IEnumerable NamedChildren => base.NamedChildren; /// - protected override bool TryGetValue(string key, [NotNullWhen(true)]out object? value) + protected override bool TryGetValue(string key, [NotNullWhen(true)] out object? value) { if (key == "value") { diff --git a/src/Hl7.Fhir.Base/Model/Time.cs b/src/Hl7.Fhir.Base/Model/Time.cs index 72e07941df..50070153b1 100644 --- a/src/Hl7.Fhir.Base/Model/Time.cs +++ b/src/Hl7.Fhir.Base/Model/Time.cs @@ -69,7 +69,7 @@ public Time(int hour, int minute, int second) : this(string.Format(CultureInfo.I /// Converts a Fhir Time to a . /// /// true if the Fhir Time contains a valid time string, false otherwise. - public bool TryToTime([NotNullWhen(true)]out P.Time? time) + public bool TryToTime([NotNullWhen(true)] out P.Time? time) { if (_parsedValue is null) { @@ -107,7 +107,7 @@ protected override void OnObjectValueChanged() /// /// Converts this Fhir Time to a . /// - public TimeSpan? ToTimeSpan() => + public TimeSpan ToTimeSpan() => TryToTimeSpan(out var dt) ? dt : throw new FormatException($"Time '{Value}' was null or not recognized as a valid time."); @@ -115,9 +115,9 @@ protected override void OnObjectValueChanged() /// Convert this FhirDateTime to a . /// /// True if the value of the Fhir Time is not null and can be parsed as a Time without an offset, false otherwise. - public bool TryToTimeSpan([NotNullWhen(true)]out TimeSpan? dto) + public bool TryToTimeSpan(out TimeSpan dto) { - if (Value is not null && TryToTime(out var dt) && !dt!.HasOffset) + if (Value is not null && TryToTime(out var dt) && !dt.HasOffset) { dto = dt.ToTimeSpan(); return true; diff --git a/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs b/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs index 6fe9135129..62684fa38e 100644 --- a/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs +++ b/src/Hl7.Fhir.Base/Serialization/ElementMetadataFilter.cs @@ -11,7 +11,6 @@ using Hl7.Fhir.Introspection; using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Hl7.Fhir.Serialization diff --git a/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs b/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs index dec0392eaa..f60b5774ac 100644 --- a/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs +++ b/src/Hl7.Fhir.Base/Serialization/XObjectExtensions.cs @@ -67,7 +67,7 @@ public static bool TryGetAttribute(this XElement docNode, XName name, [NotNullWh if (attr.NextAttribute != null) return attr.NextAttribute; // out of attributes, continue with our parents first "real" node - return attr.Parent!.FirstNode; + return attr.Parent?.FirstNode; } } diff --git a/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs index b26c11df2a..01fb26d397 100644 --- a/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs +++ b/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs @@ -1,7 +1,7 @@ -/* +/* * Copyright (c) 2023, Firely (info@fire.ly) and contributors * See the file CONTRIBUTORS for details. - * + * * This file is licensed under the BSD 3-Clause license * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE */ diff --git a/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs b/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs index 825995864e..708b5cefae 100644 --- a/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs +++ b/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs @@ -30,7 +30,7 @@ public static FhirRelease Parse(string version) => /// Fhir Release version number /// Official FHIR Release /// true if the conversion succeeded; false otherwise. - public static bool TryParse(string version, [NotNullWhen(true)]out FhirRelease? release) + public static bool TryParse(string version, [NotNullWhen(true)] out FhirRelease? release) { release = version switch { diff --git a/src/Hl7.Fhir.Base/Utility/IAnnotated.cs b/src/Hl7.Fhir.Base/Utility/IAnnotated.cs index 9a14494790..c6510676cc 100644 --- a/src/Hl7.Fhir.Base/Utility/IAnnotated.cs +++ b/src/Hl7.Fhir.Base/Utility/IAnnotated.cs @@ -40,7 +40,7 @@ public static bool TryGetAnnotation(this IAnnotated annotated, out A? annotat return annotation != null; } - public static IEnumerable Annotations(this IAnnotated annotated) => annotated.Annotations(typeof(A))?.Cast() ?? Enumerable.Empty(); + public static IEnumerable Annotations(this IAnnotated annotated) => annotated.Annotations(typeof(A)).Cast(); public static bool HasAnnotation(this IAnnotated annotated, Type type) => annotated.Annotations(type).Any(); diff --git a/src/Hl7.Fhir.Base/Utility/SemVersion.cs b/src/Hl7.Fhir.Base/Utility/SemVersion.cs index 3d709ebb2f..cb0a96f190 100644 --- a/src/Hl7.Fhir.Base/Utility/SemVersion.cs +++ b/src/Hl7.Fhir.Base/Utility/SemVersion.cs @@ -119,7 +119,7 @@ public static SemVersion Parse(string version, bool strict = false) /// If set to minor and patch version are required, /// otherwise they are optional. /// when a invalid version string is passed, otherwise . - public static bool TryParse(string version, [NotNullWhen(true)]out SemVersion semver, bool strict = false) + public static bool TryParse(string version, [NotNullWhen(true)] out SemVersion semver, bool strict = false) { semver = null; if (version is null) return false; diff --git a/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs b/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs index 635175429b..1c54f33bff 100644 --- a/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs +++ b/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs @@ -51,7 +51,7 @@ public static bool ProbeIsFhirJson(string data) => ProbeIsJson(data) && data.Contains($"\"resourceType\""); - private static XDocument XDocumentFromReaderInternal(XmlReader reader, bool ignoreComments = false) + private static XDocument XDocumentFromReaderInternal(XmlReader reader) { try { diff --git a/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs b/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs index cd2834e621..c33f838ef1 100644 --- a/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs +++ b/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs @@ -171,7 +171,7 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, IModelInfo modelI /// Gets the property value associated with the specified property key. #pragma warning disable CS8767 - public bool TryGetValue(string key, [NotNullWhen(true)]out object? value) => properties.TryGetValue(key, out value); + public bool TryGetValue(string key, [NotNullWhen(true)] out object? value) => properties.TryGetValue(key, out value); #pragma warning restore CS8767 #endregion diff --git a/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs b/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs index f7050d2e79..143e3a2486 100644 --- a/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs +++ b/src/Hl7.Fhir.STU3/Specification/Source/Summary/ArtifactSummary.cs @@ -83,10 +83,8 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception? error) { this.properties = properties ?? throw Errors.ArgumentNull(nameof(properties)); this.Error = error; - - // Try to parse the specified type name to a known enum value - var typeName = ResourceTypeName; - if (typeName != null) + + if (ResourceTypeName != null) { ResourceType = ModelInfo.FhirTypeNameToResourceType(ResourceTypeName); } @@ -129,7 +127,7 @@ public ArtifactSummary(IArtifactSummaryPropertyBag properties, Exception? error) public string Position => properties.GetPosition(); /// Gets the type name of the resource. - public string ResourceTypeName => properties.GetTypeName(); + public string? ResourceTypeName => properties.GetTypeName(); /// Gets the type of the resource, parsed from the original value, or null. public ResourceType? ResourceType { get; } diff --git a/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs b/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs index 2014ac4b98..02a54c3061 100644 --- a/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs +++ b/src/Hl7.Fhir.Shims.STU3AndUp/Model/ModelInfo.cs @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. using System; using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; diff --git a/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs b/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs index 5f7ec59981..74a907862c 100644 --- a/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs +++ b/src/Hl7.Fhir.Support.Poco.Tests/Model/TimeTests.cs @@ -64,13 +64,13 @@ public void UpdatesCachedValue() dft.Value = "01:02"; dft.TryToTimeSpan(out dto).Should().BeTrue(); - dto!.Value.Hours.Should().Be(1); + dto.Hours.Should().Be(1); dft.TryToTimeSpan(out dto2).Should().BeTrue(); dto.Equals(dto2).Should().BeTrue(); dft.ObjectValue = "18:23:34"; dft.TryToTimeSpan(out dto).Should().BeTrue(); - dto!.Value.Minutes.Should().Be(23); + dto.Minutes.Should().Be(23); dft.TryToTimeSpan(out dto2).Should().BeTrue(); dto.Equals(dto2).Should().BeTrue(); diff --git a/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs b/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs index 368aa240de..3682222415 100644 --- a/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs +++ b/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs @@ -6,15 +6,14 @@ * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE */ +#nullable enable + using FluentAssertions; using Hl7.Fhir.ElementModel.Types; using Hl7.Fhir.Utility; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; -using P = Hl7.Fhir.ElementModel.Types; - -#nullable enable namespace Hl7.Fhir.ElementModel.Tests { @@ -24,16 +23,16 @@ public class QuantityTests [TestMethod] public void QuantityParsing() { - Assert.AreEqual(new P.Quantity(75.5m, "kg"), P.Quantity.Parse("75.5 'kg'")); - Assert.AreEqual(new P.Quantity(75.5m, "kg"), P.Quantity.Parse("75.5'kg'")); - Assert.AreEqual(new P.Quantity(75m, "kg"), P.Quantity.Parse("75 'kg'")); - Assert.AreEqual(new P.Quantity(40m, "wk"), P.Quantity.Parse("40 'wk'")); - Assert.AreEqual(new P.Quantity(40m, "wk"), P.Quantity.Parse("40 weeks")); - Assert.AreEqual(P.Quantity.ForCalendarDuration(2m, "year"), P.Quantity.Parse("2 year")); - Assert.AreEqual(P.Quantity.ForCalendarDuration(6m, "month"), P.Quantity.Parse("6 months")); - Assert.AreEqual(new P.Quantity(40.0m, P.Quantity.UCUM_UNIT), P.Quantity.Parse("40.0")); - Assert.AreEqual(new P.Quantity(1m), P.Quantity.Parse("1 '1'")); - Assert.AreEqual(new P.Quantity(1m, "m/s"), P.Quantity.Parse("1 'm/s'")); + Assert.AreEqual(new Quantity(75.5m, "kg"), Quantity.Parse("75.5 'kg'")); + Assert.AreEqual(new Quantity(75.5m, "kg"), Quantity.Parse("75.5'kg'")); + Assert.AreEqual(new Quantity(75m, "kg"), Quantity.Parse("75 'kg'")); + Assert.AreEqual(new Quantity(40m, "wk"), Quantity.Parse("40 'wk'")); + Assert.AreEqual(new Quantity(40m, "wk"), Quantity.Parse("40 weeks")); + Assert.AreEqual(Quantity.ForCalendarDuration(2m, "year"), Quantity.Parse("2 year")); + Assert.AreEqual(Quantity.ForCalendarDuration(6m, "month"), Quantity.Parse("6 months")); + Assert.AreEqual(new Quantity(40.0m), Quantity.Parse("40.0")); + Assert.AreEqual(new Quantity(1m), Quantity.Parse("1 '1'")); + Assert.AreEqual(new Quantity(1m, "m/s"), Quantity.Parse("1 'm/s'")); reject("40,5 weeks"); reject("40 weks"); @@ -46,19 +45,19 @@ public void QuantityParsing() void reject(string testValue) { - Assert.IsFalse(P.Quantity.TryParse(testValue, out _)); + Assert.IsFalse(Quantity.TryParse(testValue, out _)); } [TestMethod] public void QuantityFormatting() { - Assert.AreEqual("75.6 'kg'", new P.Quantity(75.6m, "kg").ToString()); + Assert.AreEqual("75.6 'kg'", new Quantity(75.6m, "kg").ToString()); } [TestMethod] public void QuantityConstructor() { - var newq = new P.Quantity(3.14m, "kg"); + var newq = new Quantity(3.14m, "kg"); Assert.AreEqual("kg", newq.Unit); Assert.AreEqual(3.14m, newq.Value); } @@ -66,20 +65,21 @@ public void QuantityConstructor() [TestMethod] public void QuantityEquals() { - var newq = new P.Quantity(3.14m, "kg"); + var newq = new Quantity(3.14m, "kg"); - Assert.AreEqual(newq, new P.Quantity(3.14m, "kg")); - Assert.AreNotEqual(newq, new P.Quantity(3.15m, "kg")); + Assert.AreEqual(newq, new Quantity(3.14m, "kg")); + Assert.AreNotEqual(newq, new Quantity(3.15m, "kg")); } [TestMethod] public void QuantityComparison() { - var smaller = new P.Quantity(3.14m, "kg"); - var bigger = new P.Quantity(4.0m, "kg"); + var smaller = new Quantity(3.14m, "kg"); + var bigger = new Quantity(4.0m, "kg"); Assert.IsTrue(smaller < bigger); #pragma warning disable CS1718 // Comparison made to same variable + // ReSharper disable once EqualExpressionComparison Assert.IsTrue(smaller <= smaller); #pragma warning restore CS1718 // Comparison made to same variable Assert.IsTrue(bigger >= smaller); @@ -93,8 +93,8 @@ public void QuantityComparison() [TestMethod] public void DifferentUnitsNotSupported() { - var a = new P.Quantity(3.14m, "kg"); - var b = new P.Quantity(30.5m, "g"); + var a = new Quantity(3.14m, "kg"); + var b = new Quantity(30.5m, "g"); /* Func func = () => a < b; ExceptionAssert.Throws); @@ -129,7 +129,7 @@ public void QuantityCompareTests(string left, string right, Comparison expectedR Quantity.TryParse(left, out var a); Quantity.TryParse(right, out var b); - Func func = () => a!.CompareTo(b); + Func func = () => a.CompareTo(b); if (shouldThrowException) { @@ -154,31 +154,25 @@ public void QuantityCompareTests(string left, string right, Comparison expectedR public static IEnumerable ArithmeticTestdata => new[] { - new object[] { "25 'kg'", "5 'kg'", "30 'kg'" , (object)Quantity.Add }, - new object[] { "25 'kg'", "1000 'g'", "26000 'g'", (object)Quantity.Add }, - new object[] { "3 '[in_i]'", "2 '[in_i]'", "5 '[in_i]'", (object)Quantity.Add }, - new object[] { "4.0 'kg.m/s2'", "2000 'g.m.s-2'", "6000 'g.m.s-2'", (object)Quantity.Add } , - new object[] { "3 'm'", "3 'cm'", "303 'cm'", (object)Quantity.Add }, - new object[] { "3 'm'", "0 'cm'","300 'cm'", (object)Quantity.Add }, - new object[] { "3 'm'", "-80 'cm'", "220 'cm'", (object)Quantity.Add }, - - new object?[] { "3 'm'", "0 'kg'", null, (object)Quantity.Add }, - - new object[] { "25 'kg'", "500 'g'", "24500 'g'", (object)Quantity.Substract }, - new object[] { "25 'kg'", "25001 'g'", "-1 'g'", (object)Quantity.Substract}, - new object[] { "1 '[in_i]'", "2 'cm'", "0.005400 'm'", (object)Quantity.Substract }, - - new object?[] { "1 '[in_i]'", "2 'kg'", null, (object)Quantity.Substract }, - - new object[] { "25 'km'", "20 'cm'", "5000 'm2'", (object)Quantity.Multiply }, - new object[] { "2.0 'cm'", "2.0 'm'", "0.040 'm2'", (object)Quantity.Multiply }, - new object[] { "2.0 'cm'", "9 'kg'", "180 'g.m'", (object)Quantity.Multiply }, - - - new object[] { "14.4 'km'", "2.0 'h'", "2 'm.s-1'", (object)Quantity.Divide }, - new object[] { "9 'm2'", "3 'm'", "3 'm'", (object)Quantity.Divide }, - new object[] { "6 'm'", "3 'm'", "2 '1'", (object)Quantity.Divide }, - new object?[] { "3 'm'", "0 'cm'", null, (object)Quantity.Divide }, + ["25 'kg'", "5 'kg'", "30 'kg'" , (object)Quantity.Add], + ["25 'kg'", "1000 'g'", "26000 'g'", (object)Quantity.Add], + ["3 '[in_i]'", "2 '[in_i]'", "5 '[in_i]'", (object)Quantity.Add], + ["4.0 'kg.m/s2'", "2000 'g.m.s-2'", "6000 'g.m.s-2'", (object)Quantity.Add], + ["3 'm'", "3 'cm'", "303 'cm'", (object)Quantity.Add], + ["3 'm'", "0 'cm'","300 'cm'", (object)Quantity.Add], + ["3 'm'", "-80 'cm'", "220 'cm'", (object)Quantity.Add], + ["3 'm'", "0 'kg'", null, (object)Quantity.Add], + ["25 'kg'", "500 'g'", "24500 'g'", (object)Quantity.Substract], + ["25 'kg'", "25001 'g'", "-1 'g'", (object)Quantity.Substract], + ["1 '[in_i]'", "2 'cm'", "0.005400 'm'", (object)Quantity.Substract], + ["1 '[in_i]'", "2 'kg'", null, (object)Quantity.Substract], + ["25 'km'", "20 'cm'", "5000 'm2'", (object)Quantity.Multiply], + ["2.0 'cm'", "2.0 'm'", "0.040 'm2'", (object)Quantity.Multiply], + ["2.0 'cm'", "9 'kg'", "180 'g.m'", (object)Quantity.Multiply], + ["14.4 'km'", "2.0 'h'", "2 'm.s-1'", (object)Quantity.Divide], + ["9 'm2'", "3 'm'", "3 'm'", (object)Quantity.Divide], + ["6 'm'", "3 'm'", "2 '1'", (object)Quantity.Divide], + new[] { "3 'm'", "0 'cm'", null, (object)Quantity.Divide } }; @@ -189,7 +183,7 @@ public void ArithmeticOperationsTests(string left, string right, object result, _ = Quantity.TryParse(left, out var q1); _ = Quantity.TryParse(right, out var q2); - var opResult = operation(q1!, q2!); + var opResult = operation(q1, q2); if (result is string r && Quantity.TryParse(r, out var q3)) { @@ -201,6 +195,4 @@ public void ArithmeticOperationsTests(string left, string right, object result, } } } -} - -#nullable restore \ No newline at end of file +} \ No newline at end of file From 613836b49507f2212e73d144dce938cc858163fb Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 27 Mar 2024 14:40:10 +0100 Subject: [PATCH 14/17] date changes to not change public interface --- src/Hl7.Fhir.Base/Model/Date.cs | 6 +++--- src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Hl7.Fhir.Base/Model/Date.cs b/src/Hl7.Fhir.Base/Model/Date.cs index 667f3644ad..97d4f26006 100644 --- a/src/Hl7.Fhir.Base/Model/Date.cs +++ b/src/Hl7.Fhir.Base/Model/Date.cs @@ -76,7 +76,7 @@ public Date(int year) : this(string.Format(System.Globalization.CultureInfo.Inva /// Converts a Fhir Date to a . /// /// true if the Fhir Date contains a valid date string, false otherwise. - public bool TryToDate(out P.Date? date) + public bool TryToDate([NotNullWhen(true)] out P.Date? date) { if (_parsedValue is null) { @@ -131,11 +131,11 @@ protected override void OnObjectValueChanged() /// Convert this Fhir Date to a . /// /// True if the value of the Fhir Date is not null and can be parsed as a DateTimeOffset, false otherwise. - public bool TryToDateTimeOffset(out DateTimeOffset? dto) + public bool TryToDateTimeOffset(out DateTimeOffset dto) { if (Value is not null && TryToDate(out var dt)) { - dto = dt?.ToDateTimeOffset(TimeSpan.Zero); + dto = dt.ToDateTimeOffset(TimeSpan.Zero); return true; } else diff --git a/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs b/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs index 5ed71246af..91afe8b70e 100644 --- a/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs +++ b/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs @@ -76,7 +76,7 @@ public void UpdatesCachedValue() dft.ObjectValue = "2023-07-11"; dft.TryToDateTimeOffset(out dto).Should().BeTrue(); - dto.Month.Should().Be(7); + dto.Day.Should().Be(7); dft.TryToDateTimeOffset(out dto2).Should().BeTrue(); dto.Equals(dto2).Should().BeTrue(); From a9715fe151488a9cae96ba9c8b1f38177af6a652 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 27 Mar 2024 14:43:15 +0100 Subject: [PATCH 15/17] reverted unit test to old form --- src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs b/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs index 91afe8b70e..5ed71246af 100644 --- a/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs +++ b/src/Hl7.Fhir.Support.Poco.Tests/Model/DateTests.cs @@ -76,7 +76,7 @@ public void UpdatesCachedValue() dft.ObjectValue = "2023-07-11"; dft.TryToDateTimeOffset(out dto).Should().BeTrue(); - dto.Day.Should().Be(7); + dto.Month.Should().Be(7); dft.TryToDateTimeOffset(out dto2).Should().BeTrue(); dto.Equals(dto2).Should().BeTrue(); From 6a9fedc67ce0ab6fe9eed32099eeaeb3b64fd4a4 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 27 Mar 2024 17:45:11 +0100 Subject: [PATCH 16/17] added nullability to ICqlEquatable and ICqlOrderable arguments --- src/Hl7.Fhir.Base/ElementModel/Types/Any.cs | 6 +++--- src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs | 4 ++-- src/Hl7.Fhir.Base/ElementModel/Types/Date.cs | 6 +++--- src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs | 6 +++--- src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs | 6 +++--- src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs | 6 +++--- src/Hl7.Fhir.Base/ElementModel/Types/Long.cs | 6 +++--- src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs | 8 ++++---- src/Hl7.Fhir.Base/ElementModel/Types/String.cs | 6 +++--- src/Hl7.Fhir.Base/ElementModel/Types/Time.cs | 14 +++++++------- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs index 072a4e3a32..9e1787e440 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs @@ -187,13 +187,13 @@ protected static Result propagateNull(object obj, Func a) => obj is nul public interface ICqlEquatable { - bool? IsEqualTo(Any other); - bool IsEquivalentTo(Any other); + bool? IsEqualTo(Any? other); + bool IsEquivalentTo(Any? other); } public interface ICqlOrderable { - int? CompareTo(Any other); + int? CompareTo(Any? other); } public interface ICqlConvertible diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs index b00a906a88..1c16a7643c 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs @@ -66,8 +66,8 @@ public static bool TryParse(string representation, [NotNullWhen(true)] out Boole public static explicit operator Quantity(Boolean b) => ((ICqlConvertible)b).TryConvertToQuantity().ValueOrThrow(); public static explicit operator String(Boolean b) => ((ICqlConvertible)b).TryConvertToString().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } ? (bool?)Equals(other) : null; - bool ICqlEquatable.IsEquivalentTo(Any other) => Equals(other); + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } ? (bool?)Equals(other) : null; + bool ICqlEquatable.IsEquivalentTo(Any? other) => Equals(other); Result ICqlConvertible.TryConvertToBoolean() => Ok(this); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs index d0b633197e..9052a579cc 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs @@ -246,12 +246,12 @@ public Result TryCompareTo(Any other) public static explicit operator Date(DateTimeOffset dto) => FromDateTimeOffset(dto); public static explicit operator String(Date d) => ((ICqlConvertible)d).TryConvertToString().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } && TryEquals(other) is Ok ok ? ok.Value : (bool?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } && TryEquals(other) is Ok ok ? ok.Value : null; // Note that, in contrast to equals, this will return false if operators cannot be compared (as described by the spec) - bool ICqlEquatable.IsEquivalentTo(Any other) => other is { } pd && TryEquals(pd).ValueOrDefault(false); + bool ICqlEquatable.IsEquivalentTo(Any? other) => other is { } pd && TryEquals(pd).ValueOrDefault(false); - int? ICqlOrderable.CompareTo(Any other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : (int?)null; + int? ICqlOrderable.CompareTo(Any? other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : null; Result ICqlConvertible.TryConvertToDateTime() => Ok(ToDateTime()); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs index c79ad78aaa..2d44d464a4 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs @@ -358,12 +358,12 @@ internal static string ToStringWithPrecision(DateTimeOffset dto, DateTimePrecisi public static explicit operator Date(DateTime dt) => ((ICqlConvertible)dt).TryConvertToDate().ValueOrThrow(); public static explicit operator String(DateTime dt) => ((ICqlConvertible)dt).TryConvertToString().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } && TryEquals(other) is Ok ok ? ok.Value : (bool?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } && TryEquals(other) is Ok ok ? ok.Value : null; // Note that, in contrast to equals, this will return false if operators cannot be compared (as described by the spec) - bool ICqlEquatable.IsEquivalentTo(Any other) => other is { } pd && TryEquals(pd).ValueOrDefault(false); + bool ICqlEquatable.IsEquivalentTo(Any? other) => other is { } pd && TryEquals(pd).ValueOrDefault(false); - int? ICqlOrderable.CompareTo(Any other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : (int?)null; + int? ICqlOrderable.CompareTo(Any? other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : null; Result ICqlConvertible.TryConvertToDateTime() => Ok(this); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs index 989fa12e6a..8c7611d68d 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs @@ -157,9 +157,9 @@ public int CompareTo(object? obj) public static explicit operator Boolean(Decimal d) => ((ICqlConvertible)d).TryConvertToBoolean().ValueOrThrow(); public static explicit operator String(Decimal d) => ((ICqlConvertible)d).TryConvertToString().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } ? Equals(other, CQL_EQUALS_COMPARISON) : (bool?)null; - bool ICqlEquatable.IsEquivalentTo(Any other) => Equals(other, CQL_EQUIVALENCE_COMPARISON); - int? ICqlOrderable.CompareTo(Any other) => other is { } ? CompareTo(other) : (int?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } ? Equals(other, CQL_EQUALS_COMPARISON) : null; + bool ICqlEquatable.IsEquivalentTo(Any? other) => other is { } && Equals(other, CQL_EQUIVALENCE_COMPARISON); + int? ICqlOrderable.CompareTo(Any? other) => other is { } ? CompareTo(other) : null; Result ICqlConvertible.TryConvertToBoolean() => Value switch diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs index e05d1e8a4b..d7ec21972c 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Integer.cs @@ -80,9 +80,9 @@ public int CompareTo(object? obj) public static explicit operator Boolean(Integer i) => ((ICqlConvertible)i).TryConvertToBoolean().ValueOrThrow(); public static explicit operator String(Integer i) => ((ICqlConvertible)i).TryConvertToString().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } ? Equals(other) : (bool?)null; - bool ICqlEquatable.IsEquivalentTo(Any other) => Equals(other); - int? ICqlOrderable.CompareTo(Any other) => other is { } ? CompareTo(other) : (int?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } ? Equals(other) : null; + bool ICqlEquatable.IsEquivalentTo(Any? other) => Equals(other); + int? ICqlOrderable.CompareTo(Any? other) => other is { } ? CompareTo(other) : null; Result ICqlConvertible.TryConvertToBoolean() => Value switch diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs index a2250d1e52..87ed8fa6dc 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs @@ -78,9 +78,9 @@ public int CompareTo(object? obj) public static explicit operator String(Long l) => ((ICqlConvertible)l).TryConvertToString().ValueOrThrow(); public static explicit operator Integer(Long l) => ((ICqlConvertible)l).TryConvertToInteger().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } ? Equals(other) : (bool?)null; - bool ICqlEquatable.IsEquivalentTo(Any other) => Equals(other); - int? ICqlOrderable.CompareTo(Any other) => other is { } ? CompareTo(other) : (int?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } ? Equals(other) : null; + bool ICqlEquatable.IsEquivalentTo(Any? other) => Equals(other); + int? ICqlOrderable.CompareTo(Any? other) => other is { } ? CompareTo(other) : null; Result ICqlConvertible.TryConvertToBoolean() => Value switch diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs index 51ecbeb826..6c0f2af763 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs @@ -376,13 +376,13 @@ internal static Result Divide(Quantity a, Quantity b) public override string ToString() => $"{Value.ToString(CultureInfo.InvariantCulture)} '{Unit}'"; - bool? ICqlEquatable.IsEqualTo(Any other) => - other is { } && TryEquals(other, CQL_EQUALS_COMPARISON) is Ok ok ? ok.Value : (bool?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => + other is { } && TryEquals(other, CQL_EQUALS_COMPARISON) is Ok ok ? ok.Value : null; // Note that, in contrast to equals, this will return false if operators cannot be compared (as described by the spec) - bool ICqlEquatable.IsEquivalentTo(Any other) => other is { } && TryEquals(other, CQL_EQUIVALENCE_COMPARISON).ValueOrDefault(false); + bool ICqlEquatable.IsEquivalentTo(Any? other) => other is { } && TryEquals(other, CQL_EQUIVALENCE_COMPARISON).ValueOrDefault(false); - int? ICqlOrderable.CompareTo(Any other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : (int?)null; + int? ICqlOrderable.CompareTo(Any? other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : null; public static explicit operator String(Quantity q) => ((ICqlConvertible)q).TryConvertToString().ValueOrThrow(); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs index dedb3a0944..36257422dd 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs @@ -106,9 +106,9 @@ public int CompareTo(object? obj) public static explicit operator Long(String s) => ((ICqlConvertible)s).TryConvertToLong().ValueOrThrow(); public static explicit operator Quantity(String s) => ((ICqlConvertible)s).TryConvertToQuantity().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } ? Equals(other, CQL_EQUALS_COMPARISON) : (bool?)null; - bool ICqlEquatable.IsEquivalentTo(Any other) => Equals(other, CQL_EQUIVALENCE_COMPARISON); - int? ICqlOrderable.CompareTo(Any other) => other is { } ? CompareTo(other) : (int?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } ? Equals(other, CQL_EQUALS_COMPARISON) : null; + bool ICqlEquatable.IsEquivalentTo(Any? other) => other is { } && Equals(other, CQL_EQUIVALENCE_COMPARISON); + int? ICqlOrderable.CompareTo(Any? other) => other is { } ? CompareTo(other) : null; Result ICqlConvertible.TryConvertToBoolean() { diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs index 8658062a19..ce55794194 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs @@ -43,10 +43,10 @@ public static Time FromDateTimeOffset(DateTimeOffset dto, DateTimePrecision prec /// public DateTimePrecision Precision { get; private set; } - public int? Hours => Precision >= DateTimePrecision.Hour ? _value.Hour : (int?)null; - public int? Minutes => Precision >= DateTimePrecision.Minute ? _value.Minute : (int?)null; - public int? Seconds => Precision >= DateTimePrecision.Second ? _value.Second : (int?)null; - public int? Millis => Precision >= DateTimePrecision.Fraction ? _value.Millisecond : (int?)null; + public int? Hours => Precision >= DateTimePrecision.Hour ? _value.Hour : null; + public int? Minutes => Precision >= DateTimePrecision.Minute ? _value.Minute : null; + public int? Seconds => Precision >= DateTimePrecision.Second ? _value.Second : null; + public int? Millis => Precision >= DateTimePrecision.Fraction ? _value.Millisecond : null; /// /// The span of time ahead/behind UTC @@ -222,12 +222,12 @@ public override string ToString() public static explicit operator Time(DateTimeOffset dto) => FromDateTimeOffset(dto); public static explicit operator String(Time dt) => ((ICqlConvertible)dt).TryConvertToString().ValueOrThrow(); - bool? ICqlEquatable.IsEqualTo(Any other) => other is { } && TryEquals(other) is Ok ok ? ok.Value : (bool?)null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is { } && TryEquals(other) is Ok ok ? ok.Value : null; // Note that, in contrast to equals, this will return false if operators cannot be compared (as described by the spec) - bool ICqlEquatable.IsEquivalentTo(Any other) => other is { } pd && TryEquals(pd).ValueOrDefault(false); + bool ICqlEquatable.IsEquivalentTo(Any? other) => other is { } pd && TryEquals(pd).ValueOrDefault(false); - int? ICqlOrderable.CompareTo(Any other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : (int?)null; + int? ICqlOrderable.CompareTo(Any? other) => other is { } && TryCompareTo(other) is Ok ok ? ok.Value : null; Result ICqlConvertible.TryConvertToString() => Ok(new String(ToString())); From 761f6562051b6856cb3a159506be90b86dcfe3c8 Mon Sep 17 00:00:00 2001 From: Kasdejong Date: Wed, 3 Apr 2024 10:05:57 +0200 Subject: [PATCH 17/17] pr requested changes --- src/Hl7.Fhir.Base/Rest/CompressedContent.cs | 2 -- src/Hl7.Fhir.Base/Utility/AnnotationList.cs | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Hl7.Fhir.Base/Rest/CompressedContent.cs b/src/Hl7.Fhir.Base/Rest/CompressedContent.cs index d51dd936cc..5d5d731c96 100644 --- a/src/Hl7.Fhir.Base/Rest/CompressedContent.cs +++ b/src/Hl7.Fhir.Base/Rest/CompressedContent.cs @@ -40,8 +40,6 @@ protected override bool TryComputeLength(out long length) length = -1; return false; } - - // @Ewout why is this here? protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) { diff --git a/src/Hl7.Fhir.Base/Utility/AnnotationList.cs b/src/Hl7.Fhir.Base/Utility/AnnotationList.cs index 7a022c8d49..45b6cae8c1 100644 --- a/src/Hl7.Fhir.Base/Utility/AnnotationList.cs +++ b/src/Hl7.Fhir.Base/Utility/AnnotationList.cs @@ -20,13 +20,13 @@ namespace Hl7.Fhir.Utility /// interfaces to have a common implementation. /// This list is thread safe /// - [CollectionBuilder(typeof(AnnotationList), nameof(AnnotationList.create) )] + [CollectionBuilder(typeof(AnnotationList), nameof(AnnotationList.Create) )] public class AnnotationList : IAnnotatable, IAnnotated, IEnumerable { private Lazy>> _annotations = new Lazy>>(() => new ConcurrentDictionary>()); private ConcurrentDictionary> annotations { get { return _annotations.Value; } } - public static AnnotationList create(ReadOnlySpan annotations) + public static AnnotationList Create(ReadOnlySpan annotations) { var list = new AnnotationList(); foreach (var annotation in annotations)