diff --git a/src/Hl7.Fhir.Base/ElementModel/DomNode.cs b/src/Hl7.Fhir.Base/ElementModel/DomNode.cs index 71fdeff3c5..bd1e4b0977 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,28 +18,28 @@ 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; protected List ChildList { - get => LazyInitializer.EnsureInitialized(ref _childList, () => new()); + get => LazyInitializer.EnsureInitialized(ref _childList, () => [])!; 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 DomNodeList this[string name] => new (ChildrenInternal(name)); 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; diff --git a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs index 105d07577e..6298866f86 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ElementNode.cs @@ -1,5 +1,4 @@ - -/* +/* * Copyright (c) 2018, Firely (info@fire.ly) and contributors * See the file CONTRIBUTORS for details. * @@ -7,17 +6,20 @@ * 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; 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 @@ -43,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 is not null; - object conv() + object? conv() { // NOTE: Keep Any.TryConvertToSystemValue, TypeSpecifier.TryGetNativeType and TypeSpecifier.ForNativeType in sync switch (value) @@ -94,8 +96,8 @@ 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()! }; /// @@ -107,10 +109,10 @@ public static IEnumerable CreateList(params object[] values) => 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, @@ -119,9 +121,9 @@ public static IEnumerable CreateList(params object[] values) => public static readonly IEnumerable EmptyList = []; - 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) + private ElementNode(string name, object? value, string? instanceType, IElementDefinitionSummary? definition) { Name = name ?? throw new ArgumentNullException(nameof(name)); InstanceType = instanceType; @@ -129,16 +131,16 @@ internal ElementNode(string name, object value, string instanceType, IElementDef Definition = definition; } - private IReadOnlyCollection _childDefinitions = null; + private IReadOnlyCollection _childDefinitions = null!; private IReadOnlyCollection getChildDefinitions(IStructureDefinitionSummaryProvider provider) { LazyInitializer.EnsureInitialized(ref _childDefinitions, () => this.ChildDefinitions(provider)); - return _childDefinitions!; + 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)); @@ -147,7 +149,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)); @@ -182,7 +184,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."); @@ -195,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.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) @@ -230,7 +232,7 @@ 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)); @@ -241,13 +243,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) { @@ -288,11 +290,11 @@ public ElementNode ShallowCopy() 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) { 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/ITypedElement.cs b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs index 0335bb020c..bfe5cc4cb6 100644 --- a/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs +++ b/src/Hl7.Fhir.Base/ElementModel/ITypedElement.cs @@ -8,6 +8,9 @@ using Hl7.Fhir.Specification; +#nullable enable + + namespace Hl7.Fhir.ElementModel { /// @@ -28,10 +31,10 @@ 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; } - IElementDefinitionSummary Definition { get; } + IElementDefinitionSummary? Definition { get; } } } \ No newline at end of file diff --git a/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs b/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs index 08da2a4595..5279489210 100644 --- a/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs +++ b/src/Hl7.Fhir.Base/ElementModel/PrimitiveElement.cs @@ -54,9 +54,7 @@ public PrimitiveElement(object value, string? name = null, bool useFullTypeName InstanceType = useFullTypeName ? systemType.FullName : systemType.Name; Name = name ?? "@primitivevalue@"; } - - - + public string Name { get; private set; } diff --git a/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs b/src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs index 7c7390a32e..9cfd3e4924 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; @@ -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 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 16bec51789..9e1787e440 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 { @@ -22,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; @@ -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)); @@ -76,9 +77,9 @@ public static bool TryParse(string value, Type primitiveType, out object? parsed 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)) @@ -90,7 +91,7 @@ public static bool TryParse(string value, Type primitiveType, out object? parsed 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); } @@ -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; @@ -158,7 +159,7 @@ public static bool TryConvert(object value, out Any? primitiveValue) /// /// 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; @@ -186,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 75c55467eb..1c16a7643c 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)); @@ -65,8 +66,8 @@ public static bool TryParse(string representation, out Boolean? value) 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/Code.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs index e422779836..c9c816a27e 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..b1c66d58df 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,12 +31,12 @@ 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; + 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 b6237c71c6..9052a579cc 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; @@ -105,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)); @@ -245,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 bd69f84f6b..2d44d464a4 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 @@ -357,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 3c6c31fc81..8c7611d68d 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; @@ -19,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; } @@ -30,21 +29,22 @@ 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, out Decimal? value) + public static bool TryParse(string representation, [NotNullWhen(true)] out Decimal? value) { if (representation == null) throw new ArgumentNullException(nameof(representation)); 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; } @@ -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 024119b347..d7ec21972c 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; @@ -30,7 +31,7 @@ public static bool TryParse(string representation, 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; } @@ -79,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 6f343eb298..87ed8fa6dc 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; @@ -77,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 a6856ab0d3..6c0f2af763 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; @@ -125,7 +126,7 @@ public static bool TryParse(string representation, out Quantity quantity) /// 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)); @@ -375,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/Ratio.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs index 6bf504fe66..dbe63f3286 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..36257422dd 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; @@ -105,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 6cdcf0dc7e..ce55794194 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); @@ -42,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 @@ -221,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())); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs index 7b29a3764b..43e3f932d5 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 { @@ -42,7 +43,7 @@ internal static bool TryCanonicalize(this Quantity quantity, out Quantity? canon } } - 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/ClassMapping.cs b/src/Hl7.Fhir.Base/Introspection/ClassMapping.cs index d04006849f..ef314bd070 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; @@ -39,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; @@ -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..4d1a00e09f 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 @@ -34,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; @@ -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..55389f5966 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..03e3257761 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; @@ -23,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 @@ -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..97d4f26006 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 @@ -66,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); @@ -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; } @@ -134,7 +135,7 @@ 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 @@ -147,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 b525637dce..3d3bb72a9a 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; @@ -43,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)] @@ -69,32 +72,30 @@ 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"); } + 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"); } + get { return _value; } + set { _value = value; OnPropertyChanged("Value"); } } - private Hl7.Fhir.Model.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; @@ -102,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() @@ -155,7 +156,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..f7136581e9 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..4deb2f2173 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..50070153b1 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() { @@ -106,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."); @@ -116,7 +117,7 @@ protected override void OnObjectValueChanged() /// 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) { - 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/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/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..f60b5774ac 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 8bee33575e..d2905aaadf 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); @@ -135,7 +136,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 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; diff --git a/src/Hl7.Fhir.Base/Utility/AnnotationList.cs b/src/Hl7.Fhir.Base/Utility/AnnotationList.cs index dad5cafc25..45b6cae8c1 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/FhirReleaseParser.cs b/src/Hl7.Fhir.Base/Utility/FhirReleaseParser.cs index 4b71c409ad..708b5cefae 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 { @@ -106,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 { @@ -164,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..c6510676cc 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,25 +24,25 @@ 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; } - 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() == 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)); } diff --git a/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs b/src/Hl7.Fhir.Base/Utility/NullableAttribute.cs new file mode 100644 index 0000000000..e49f933799 --- /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..cb0a96f190 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.Base/Utility/SerializationUtil.cs b/src/Hl7.Fhir.Base/Utility/SerializationUtil.cs index e47a4e017d..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 { @@ -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.Conformance/Specification/Source/Summary/ArtifactSummary.cs b/src/Hl7.Fhir.Conformance/Specification/Source/Summary/ArtifactSummary.cs index 00b7afb215..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, 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.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/ScopedNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs index f3b5128762..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,9 +314,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.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.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.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 fba99285f0..143e3a2486 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,14 +79,12 @@ 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; - - // 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); } @@ -94,7 +95,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. @@ -126,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; } @@ -171,7 +172,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 +181,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.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..0a5837b073 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); @@ -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.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; 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 75f6b42c82..d1b5bc7996 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); diff --git a/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs b/src/Hl7.Fhir.Support.Tests/ElementModel/QuantityTests.cs index 71fdde70fb..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); @@ -126,8 +126,8 @@ 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); @@ -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 } }; @@ -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