Skip to content

Conversation

@brendankowitz
Copy link
Member

@brendankowitz brendankowitz commented Oct 17, 2025

Description

This pull request introduces significant changes to how FHIR resources are represented and processed within the codebase, moving from the use of ITypedElement to PocoNode for resource elements. This update impacts a wide range of files, refactoring interfaces, implementations, and test code to align with the new model. Additionally, there are several dependency version updates and some package version downgrades.

The most important changes are:

Core Model Refactoring

  • Refactored ResourceElement and related APIs to use PocoNode instead of ITypedElement, affecting constructors, properties, and internal logic in ResourceElement, ResourceTypeExtensions, and all related usages. This change improves consistency and interoperability with the FHIR .NET library. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
  • Updated the IReferenceToElementResolver interface and its implementation to return PocoNode instead of ITypedElement. [1] [2] [3]
  • Changed the IModelInfoProvider.GetEvaluationContext signature to accept a resolver function returning PocoNode. [1] [2]

Dependency and Package Version Updates

  • Downgraded or updated several package versions in Directory.Packages.props, including HealthcareSharedPackageVersion, DotNetSdkPackageVersion, Azure.Identity, Microsoft.Data.SqlClient, and Newtonsoft.Json. Also, updated Hl7FhirVersion and OpenIddict packages to newer versions. [1] [2] [3] [4]
  • Added new package references, such as IdentityServer4 and updated Microsoft.EntityFrameworkCore.InMemory to a newer version. [1] [2]

Test Adjustments

  • Updated unit tests to use the new PocoNode-based APIs and adjusted mock setups and test logic accordingly. [1] [2] [3] [4] [5] [6]

Minor Logic Changes

  • Improved FHIRPath evaluation and search parameter extraction to operate on PocoNode instances, ensuring correct FHIRPath context and evaluation. [1] [2] [3]
  • Fixed logic in CreateBulkUpdateHandler to correctly extract the operation value from FHIR parameters, handling FhirString specifically.

These changes collectively modernize the resource handling pipeline and align the codebase with the latest FHIR .NET best practices.

Related issues

Addresses [issue #].

Testing

Describe how this change was tested.

FHIR Team Checklist

  • Update the title of the PR to be succinct and less than 65 characters
  • Add a milestone to the PR for the sprint that it is merged (i.e. add S47)
  • Tag the PR with the type of update: Bug, Build, Dependencies, Enhancement, New-Feature or Documentation
  • Tag the PR with Open source, Azure API for FHIR (CosmosDB or common code) or Azure Healthcare APIs (SQL or common code) to specify where this change is intended to be released.
  • Tag the PR with Schema Version backward compatible or Schema Version backward incompatible or Schema Version unchanged if this adds or updates Sql script which is/is not backward compatible with the code.
  • When changing or adding behavior, if your code modifies the system design or changes design assumptions, please create and include an ADR.
  • CI is green before merge Build Status
  • Review squash-merge requirements

Semver Change (docs)

Patch|Skip|Feature|Breaking (reason)

<PackageVersion Include="Hl7.Fhir.Specification.R4" Version="$(Hl7FhirVersion)" />
<PackageVersion Include="Hl7.Fhir.Specification.R4B" Version="$(Hl7FhirVersion)" />
<PackageVersion Include="Hl7.Fhir.Specification.R5" Version="$(Hl7FhirVersion)" />
<PackageVersion Include="IdentityServer4" Version="4.1.2" />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bad things happened to this merge 😞

@brendankowitz brendankowitz force-pushed the feature/firely-6-update branch from a499f9a to 41108f4 Compare October 27, 2025 23:03
ResourceWrapperOperation resourceWrapper = await BundleTestsCommonFunctions.GetResourceWrapperOperationAsync(
resource,
new BundleResourceContext(Bundle.BundleType.Batch, BundleProcessingLogic.Parallel, GetHttpVerb(i), persistedId: null, operation.Id));
ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb((int)i), string.Empty, operation.Id));

Check warning

Code scanning / CodeQL

Cast to same type Warning

This cast is redundant because the expression already has type Int32.

Copilot Autofix

AI 2 months ago

To fix the issue, simply remove the redundant cast (int)i and use i directly as the argument to GetHttpVerb. This means editing the one line within the method GivenABatchOperation_WhenAppendedMultipleResourcesInParallelWaitForAllToBeAppended_ThenCompleteWithSuccess so that GetHttpVerb((int)i) becomes GetHttpVerb(i). No imports, methods, or additional definitions are required.

Suggested changeset 1
src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs
--- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs
@@ -92,7 +92,7 @@
             Parallel.For(0, numberOfResources, (i, task) =>
             {
                 DomainResource resource = BundleTestsCommonFunctions.GetSamplePatient(Guid.NewGuid());
-                ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb((int)i), string.Empty, operation.Id));
+                ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb(i), string.Empty, operation.Id));
 
                 Task<UpsertOutcome> appendedResourceTask = operation.AppendResourceAsync(resourceWrapper, dataStore, cts.Token);
                 tasksWaitingForMergeAsync.Add(appendedResourceTask);
EOF
@@ -92,7 +92,7 @@
Parallel.For(0, numberOfResources, (i, task) =>
{
DomainResource resource = BundleTestsCommonFunctions.GetSamplePatient(Guid.NewGuid());
ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb((int)i), string.Empty, operation.Id));
ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb(i), string.Empty, operation.Id));

Task<UpsertOutcome> appendedResourceTask = operation.AppendResourceAsync(resourceWrapper, dataStore, cts.Token);
tasksWaitingForMergeAsync.Add(appendedResourceTask);
Copilot is powered by AI and may make mistakes. Always verify output.
ResourceWrapperOperation resourceWrapper = await BundleTestsCommonFunctions.GetResourceWrapperOperationAsync(
resource,
new BundleResourceContext(Bundle.BundleType.Batch, BundleProcessingLogic.Parallel, GetHttpVerb(i), persistedId: null, operation.Id));
ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb((int)i), string.Empty, operation.Id));

Check warning

Code scanning / CodeQL

Cast to same type Warning

This cast is redundant because the expression already has type Int32.

Copilot Autofix

AI 2 months ago

The best way to fix the problem is to remove the redundant cast (int)i on line 220. Instead, pass i directly to the GetHttpVerb function. No changes are needed to any imports, method signatures, or additional code outside of removing the unnecessary cast. Only a single edit to line 220 in the file is required.

Suggested changeset 1
src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs
--- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Persistence/Orchestration/BundleOrchestratorOperationTests.cs
@@ -217,7 +217,7 @@
                 else
                 {
                     DomainResource resource = BundleTestsCommonFunctions.GetSamplePatient(Guid.NewGuid());
-                    ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb((int)i), string.Empty, operation.Id));
+                    ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb(i), string.Empty, operation.Id));
 
                     appendTask = operation.AppendResourceAsync(resourceWrapper, dataStore, cts.Token);
                 }
EOF
@@ -217,7 +217,7 @@
else
{
DomainResource resource = BundleTestsCommonFunctions.GetSamplePatient(Guid.NewGuid());
ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb((int)i), string.Empty, operation.Id));
ResourceWrapperOperation resourceWrapper = BundleTestsCommonFunctions.GetResourceWrapperOperation(resource, new BundleResourceContext(null, BundleProcessingLogic.Parallel, GetHttpVerb(i), string.Empty, operation.Id));

appendTask = operation.AppendResourceAsync(resourceWrapper, dataStore, cts.Token);
}
Copilot is powered by AI and may make mistakes. Always verify output.
RegexOptions.Compiled);

private FhirJsonParser _parser;
private FhirJsonDeserializer _parser;

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note

Field '_parser' can be 'readonly'.

Copilot Autofix

AI 2 months ago

To fix this issue, add the readonly modifier to the field _parser. This ensures that _parser can only be set during the field's declaration or within the class's constructor, preventing unintended assignment elsewhere. Specifically, locate the declaration private FhirJsonDeserializer _parser; (line 23) in the file ImportResourceParser.cs and change it to private readonly FhirJsonDeserializer _parser;. No other code or imports need to be changed, as assignment occurs appropriately in the constructor.


Suggested changeset 1
src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/Import/ImportResourceParser.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/Import/ImportResourceParser.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/Import/ImportResourceParser.cs
--- a/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/Import/ImportResourceParser.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/Import/ImportResourceParser.cs
@@ -20,7 +20,7 @@
 {
     public class ImportResourceParser : IImportResourceParser
     {
-        private FhirJsonDeserializer _parser;
+        private readonly FhirJsonDeserializer _parser;
         private IResourceWrapperFactory _resourceFactory;
 
         public ImportResourceParser(FhirJsonDeserializer parser, IResourceWrapperFactory resourceFactory)
EOF
@@ -20,7 +20,7 @@
{
public class ImportResourceParser : IImportResourceParser
{
private FhirJsonDeserializer _parser;
private readonly FhirJsonDeserializer _parser;
private IResourceWrapperFactory _resourceFactory;

public ImportResourceParser(FhirJsonDeserializer parser, IResourceWrapperFactory resourceFactory)
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +30 to +37
if (resource is ResourceReference reference)
{
var childValue = child.Value;
if (childValue.TypeName == "Reference")
if (reference.Reference != null && reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
{
var reference = (ResourceReference)childValue;
if (reference.Reference != null && reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
{
reference.Reference = null;
reference.Display = "Referenced resource deleted";
}
reference.Reference = null;
reference.Display = "Referenced resource deleted";
}
else if (childValue.Children.Any())
}

Check notice

Code scanning / CodeQL

Nested 'if' statements can be combined Note

These 'if' statements can be combined.

Copilot Autofix

AI 2 months ago

To fix the issue, combine the two if statements at lines 30 and 32 into a single conditional by combining their conditions with &&. Use proper parentheses to ensure correct operator precedence and take care that the inline variable (reference) declared by the pattern-matching is expression is only used if the type match succeeds. In recent C# versions, this is permitted directly in the conditional. Replace:

if (resource is ResourceReference reference)
{
    if (reference.Reference != null && reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
    {
        // ...
    }
}

with:

if (resource is ResourceReference reference 
    && reference.Reference != null 
    && reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
{
    // ...
}

Only lines within the method RemoveReferenceRecursive in file src/Microsoft.Health.Fhir.Shared.Core/Features/Resources/Delete/ReferenceRemover.cs need updating.

No additional imports, methods, or definitions are required.

Suggested changeset 1
src/Microsoft.Health.Fhir.Shared.Core/Features/Resources/Delete/ReferenceRemover.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Resources/Delete/ReferenceRemover.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Resources/Delete/ReferenceRemover.cs
--- a/src/Microsoft.Health.Fhir.Shared.Core/Features/Resources/Delete/ReferenceRemover.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Resources/Delete/ReferenceRemover.cs
@@ -27,13 +27,12 @@
             }
 
             // Check if this is a ResourceReference
-            if (resource is ResourceReference reference)
+            if (resource is ResourceReference reference
+                && reference.Reference != null
+                && reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
             {
-                if (reference.Reference != null && reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
-                {
-                    reference.Reference = null;
-                    reference.Display = "Referenced resource deleted";
-                }
+                reference.Reference = null;
+                reference.Display = "Referenced resource deleted";
             }
 
             // Recursively process all properties
EOF
@@ -27,13 +27,12 @@
}

// Check if this is a ResourceReference
if (resource is ResourceReference reference)
if (resource is ResourceReference reference
&& reference.Reference != null
&& reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
{
if (reference.Reference != null && reference.Reference.Equals(target, StringComparison.OrdinalIgnoreCase))
{
reference.Reference = null;
reference.Display = "Referenced resource deleted";
}
reference.Reference = null;
reference.Display = "Referenced resource deleted";
}

// Recursively process all properties
Copilot is powered by AI and may make mistakes. Always verify output.
}

var fhirJsonSerializer = new FhirJsonSerializer(new SerializerSettings() { AppendNewLine = false, Pretty = false });
var fhirJsonSerializer = new FhirJsonSerializer();

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning test

This assignment to
fhirJsonSerializer
is useless, since its value is never read.

Copilot Autofix

AI 2 months ago

To fix this problem, simply remove the unused assignment var fhirJsonSerializer = new FhirJsonSerializer(); from line 329 in the method. This does not affect the program logic, since the instantiated object is never used, nor does its construction have any necessary, visible side-effect in this context. No other changes are needed elsewhere, and no imports or definitions need to be modified or added.

Suggested changeset 1
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/Search/SearchTestsBase.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/Search/SearchTestsBase.cs b/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/Search/SearchTestsBase.cs
--- a/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/Search/SearchTestsBase.cs
+++ b/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/Search/SearchTestsBase.cs
@@ -326,7 +326,6 @@
                 }
             }
 
-            var fhirJsonSerializer = new FhirJsonSerializer();
             using var sw = new StringWriter(sb);
             sb.AppendLine("Actual collection as below -");
             foreach (var element in actualResources)
EOF
@@ -326,7 +326,6 @@
}
}

var fhirJsonSerializer = new FhirJsonSerializer();
using var sw = new StringWriter(sb);
sb.AppendLine("Actual collection as below -");
foreach (var element in actualResources)
Copilot is powered by AI and may make mistakes. Always verify output.
parameters.Parameter.Add(new Parameters.ParameterComponent() { Name = "profile", Value = new FhirString(profile) });

var parser = new FhirJsonParser();
var parser = new FhirJsonDeserializer();

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning test

This assignment to
parser
is useless, since its value is never read.

Copilot Autofix

AI 1 day ago

In general, to fix a "useless assignment to local variable" you either (a) remove the unused variable and its assignment if they are truly unnecessary, or (b) start using the variable where it was intended to be used, if the code is incomplete. Here, the parser variable is created but never used, and the test already performs JSON conversion via parameters.ToJson(), so the parser is clearly redundant.

The best fix without changing functionality is to delete the declaration/assignment line var parser = new FhirJsonDeserializer(); in GivenInvalidProfile_WhenValidateCalled_ThenBadRequestReturned in test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/ValidateTests.cs. No other code in the method needs to be updated, and no new imports or helper methods are required. This change simply removes dead code and does not affect the test’s behavior.

Suggested changeset 1
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/ValidateTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/ValidateTests.cs b/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/ValidateTests.cs
--- a/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/ValidateTests.cs
+++ b/test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/ValidateTests.cs
@@ -210,7 +210,6 @@
             Parameters parameters = new Parameters();
             parameters.Parameter.Add(new Parameters.ParameterComponent() { Name = "profile", Value = new FhirString(profile) });
 
-            var parser = new FhirJsonDeserializer();
             parameters.Parameter.Add(new Parameters.ParameterComponent() { Name = "resource", Resource = Samples.GetDefaultPatient().ToPoco<Patient>() });
 
             exception = await Assert.ThrowsAsync<FhirClientException>(async () => await _client.ValidateAsync("Patient/$validate", parameters.ToJson()));
EOF
@@ -210,7 +210,6 @@
Parameters parameters = new Parameters();
parameters.Parameter.Add(new Parameters.ParameterComponent() { Name = "profile", Value = new FhirString(profile) });

var parser = new FhirJsonDeserializer();
parameters.Parameter.Add(new Parameters.ParameterComponent() { Name = "resource", Resource = Samples.GetDefaultPatient().ToPoco<Patient>() });

exception = await Assert.ThrowsAsync<FhirClientException>(async () => await _client.ValidateAsync("Patient/$validate", parameters.ToJson()));
Copilot is powered by AI and may make mistakes. Always verify output.
{
private ResourceWrapperFactory _resourceWrapperFactory;
private FhirJsonParser _fhirJsonParser;
private FhirJsonDeserializer _fhirJsonDeserializer;

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note

Field '_fhirJsonDeserializer' can be 'readonly'.

Copilot Autofix

AI 1 day ago

To fix the problem, the _fhirJsonDeserializer field should be marked readonly so it cannot be reassigned after the object is constructed. For consistency and the same reasoning, the other similar dependency fields (_resourceWrapperFactory, _fhirJsonSerializer, _modelInfoProvider) should also be made readonly, provided they are initialized in the constructor and not reassigned elsewhere. This change does not alter runtime behavior as long as there are no later assignments; it only enforces the existing usage pattern at compile time.

Concretely, in tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs, update the field declarations near the top of the ResourceWrapperParser class (lines 27–30) by adding the readonly modifier to each of these four private fields:

  • private ResourceWrapperFactory _resourceWrapperFactory;
  • private FhirJsonDeserializer _fhirJsonDeserializer;
  • private FhirJsonSerializer _fhirJsonSerializer;
  • private IModelInfoProvider _modelInfoProvider;

No additional methods, imports, or definitions are required; this is a modifier-only change.

Suggested changeset 1
tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs b/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs
--- a/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs
+++ b/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs
@@ -24,10 +24,10 @@
 {
     public class ResourceWrapperParser
     {
-        private ResourceWrapperFactory _resourceWrapperFactory;
-        private FhirJsonDeserializer _fhirJsonDeserializer;
-        private FhirJsonSerializer _fhirJsonSerializer;
-        private IModelInfoProvider _modelInfoProvider;
+        private readonly ResourceWrapperFactory _resourceWrapperFactory;
+        private readonly FhirJsonDeserializer _fhirJsonDeserializer;
+        private readonly FhirJsonSerializer _fhirJsonSerializer;
+        private readonly IModelInfoProvider _modelInfoProvider;
 
         public ResourceWrapperParser()
         {
EOF
@@ -24,10 +24,10 @@
{
public class ResourceWrapperParser
{
private ResourceWrapperFactory _resourceWrapperFactory;
private FhirJsonDeserializer _fhirJsonDeserializer;
private FhirJsonSerializer _fhirJsonSerializer;
private IModelInfoProvider _modelInfoProvider;
private readonly ResourceWrapperFactory _resourceWrapperFactory;
private readonly FhirJsonDeserializer _fhirJsonDeserializer;
private readonly FhirJsonSerializer _fhirJsonSerializer;
private readonly IModelInfoProvider _modelInfoProvider;

public ResourceWrapperParser()
{
Copilot is powered by AI and may make mistakes. Always verify output.
@brendankowitz brendankowitz force-pushed the feature/firely-6-update branch from 41108f4 to 2809f6c Compare January 9, 2026 02:53
Base element2 = null;

// Act
var result = element1.EqualValues(element2);

Check failure

Code scanning / CodeQL

Dereferenced variable is always null Error

Variable
element1
is always null at this dereference.

Copilot Autofix

AI 1 day ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

Comment on lines +85 to +91
if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild)
{
if (!sourceChild.EqualValues(sourceElement.Key, otherChild, otherElement.Key))
{
return false;
}
}

Check notice

Code scanning / CodeQL

Nested 'if' statements can be combined Note

These 'if' statements can be combined.

Copilot Autofix

AI 1 day ago

In general, to fix this kind of issue you merge nested if statements that both guard the same block of logic and have no else parts into a single if whose condition is the logical && of the original conditions. This keeps behavior identical but avoids unnecessary nesting and makes intent clearer.

In this specific case in src/Microsoft.Health.Fhir.Core/Extensions/BaseExtensions.cs, within the for (int j = 0; j < sourceList.Count; j++) loop, there is an outer if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild) and then an inner if (!sourceChild.EqualValues(...)). CodeQL, however, is flagging the pattern at line 85 as nested ifs that can be combined. The actual nested-if pattern exists one level deeper: currently the code is:

for (int j = 0; j < sourceList.Count; j++)
{
    if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild)
    {
        if (!sourceChild.EqualValues(sourceElement.Key, otherChild, otherElement.Key))
        {
            return false;
        }
    }
}

We can combine the two if statements into one by moving the EqualValues check into the combined condition. The resulting code:

for (int j = 0; j < sourceList.Count; j++)
{
    if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild &&
        !sourceChild.EqualValues(sourceElement.Key, otherChild, otherElement.Key))
    {
        return false;
    }
}

preserves the logic: EqualValues is only evaluated when both list entries are Base instances, and return false is executed when they are both Base and not equal. No new imports or helper methods are required; this is a local change inside EqualValues(Base source, string sourceName, Base other, string otherName).

Suggested changeset 1
src/Microsoft.Health.Fhir.Core/Extensions/BaseExtensions.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Microsoft.Health.Fhir.Core/Extensions/BaseExtensions.cs b/src/Microsoft.Health.Fhir.Core/Extensions/BaseExtensions.cs
--- a/src/Microsoft.Health.Fhir.Core/Extensions/BaseExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Core/Extensions/BaseExtensions.cs
@@ -82,12 +82,10 @@
 
                         for (int j = 0; j < sourceList.Count; j++)
                         {
-                            if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild)
+                            if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild &&
+                                !sourceChild.EqualValues(sourceElement.Key, otherChild, otherElement.Key))
                             {
-                                if (!sourceChild.EqualValues(sourceElement.Key, otherChild, otherElement.Key))
-                                {
-                                    return false;
-                                }
+                                return false;
                             }
                         }
                     }
EOF
@@ -82,12 +82,10 @@

for (int j = 0; j < sourceList.Count; j++)
{
if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild)
if (sourceList[j] is Base sourceChild && otherList[j] is Base otherChild &&
!sourceChild.EqualValues(sourceElement.Key, otherChild, otherElement.Key))
{
if (!sourceChild.EqualValues(sourceElement.Key, otherChild, otherElement.Key))
{
return false;
}
return false;
}
}
}
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants