Fix behavior of MTRDevice readAttributePaths if it happens mid-priming. (#35656)

* Fix behavior of MTRDevice readAttributePaths if it happens mid-priming.

We might not know the values of AttributeList/ServerList/PartsList yet at that
point.  Just go ahead and figure out which attribute values we have by walking
our own data structures, not the metadata list attribute values.

* Apply suggestion from code review.

Co-authored-by: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com>

---------

Co-authored-by: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com>
diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
index d741d01..bc26905 100644
--- a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
+++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
@@ -2983,11 +2983,31 @@
     // Determine the set of what the spec calls "existent paths" that correspond
     // to the request paths.  Building the whole set in-memory is OK, because
     // we're going to need all those paths for our return value anyway.
+    //
+    // Note that we don't use the structural attributes (PartsList, ServerList,
+    // AttributeList) to determine this set, because we might be in the middle
+    // of priming right now and have not gotten those yet.  Just use the set of
+    // attribute paths we actually have.
     NSMutableSet<MTRAttributePath *> * existentPaths = [[NSMutableSet alloc] init];
     {
         std::lock_guard lock(_lock);
-        for (MTRAttributeRequestPath * path in attributePaths) {
-            [self _addExistentPathsFor:path to:existentPaths];
+        for (MTRAttributeRequestPath * requestPath in attributePaths) {
+            for (MTRClusterPath * clusterPath in [self _knownClusters]) {
+                if (requestPath.endpoint != nil && ![requestPath.endpoint isEqual:clusterPath.endpoint]) {
+                    continue;
+                }
+                if (requestPath.cluster != nil && ![requestPath.cluster isEqual:clusterPath.cluster]) {
+                    continue;
+                }
+                MTRDeviceClusterData * clusterData = [self _clusterDataForPath:clusterPath];
+                if (requestPath.attribute == nil) {
+                    for (NSNumber * attributeID in clusterData.attributes) {
+                        [existentPaths addObject:[MTRAttributePath attributePathWithEndpointID:clusterPath.endpoint clusterID:clusterPath.cluster attributeID:attributeID]];
+                    }
+                } else if ([clusterData.attributes objectForKey:requestPath.attribute] != nil) {
+                    [existentPaths addObject:[MTRAttributePath attributePathWithEndpointID:clusterPath.endpoint clusterID:clusterPath.cluster attributeID:requestPath.attribute]];
+                }
+            }
         }
     }
 
@@ -3006,51 +3026,6 @@
     return result;
 }
 
-- (void)_addExistentPathsFor:(MTRAttributeRequestPath *)path to:(NSMutableSet<MTRAttributePath *> *)set
-{
-    os_unfair_lock_assert_owner(&_lock);
-
-    if (path.endpoint != nil) {
-        [self _addExistentPathsForEndpoint:path.endpoint path:path to:set];
-        return;
-    }
-
-    NSArray<NSNumber *> * endpointList = [self _endpointList];
-    for (NSNumber * endpoint in endpointList) {
-        [self _addExistentPathsForEndpoint:endpoint path:path to:set];
-    }
-}
-
-- (void)_addExistentPathsForEndpoint:(NSNumber *)endpoint path:(MTRAttributeRequestPath *)path to:(NSMutableSet<MTRAttributePath *> *)set
-{
-    os_unfair_lock_assert_owner(&_lock);
-
-    if (path.cluster != nil) {
-        [self _addExistentPathsForEndpoint:endpoint cluster:path.cluster attribute:path.attribute to:set];
-        return;
-    }
-
-    auto * clusterList = [self _serverListForEndpointID:endpoint];
-    for (NSNumber * cluster in clusterList) {
-        [self _addExistentPathsForEndpoint:endpoint cluster:cluster attribute:path.attribute to:set];
-    }
-}
-
-- (void)_addExistentPathsForEndpoint:(NSNumber *)endpoint cluster:(NSNumber *)cluster attribute:(NSNumber * _Nullable)attribute to:(NSMutableSet<MTRAttributePath *> *)set
-{
-    os_unfair_lock_assert_owner(&_lock);
-
-    if (attribute != nil) {
-        [set addObject:[MTRAttributePath attributePathWithEndpointID:endpoint clusterID:cluster attributeID:attribute]];
-        return;
-    }
-
-    auto * attributeList = [self _attributeListForEndpointID:endpoint clusterID:cluster];
-    for (NSNumber * existentAttribute in attributeList) {
-        [set addObject:[MTRAttributePath attributePathWithEndpointID:endpoint clusterID:cluster attributeID:existentAttribute]];
-    }
-}
-
 - (void)_invokeCommandWithEndpointID:(NSNumber *)endpointID
                            clusterID:(NSNumber *)clusterID
                            commandID:(NSNumber *)commandID
@@ -3652,6 +3627,9 @@
     return attributesToReport;
 }
 
+// TODO: Figure out whether we can get rid of this in favor of readAttributePaths.  This differs from
+// readAttributePaths in one respect: that function will do read-through for
+// C-quality attributes, but this one does not.
 - (NSArray<NSDictionary<NSString *, id> *> *)getAllAttributesReport
 {
     std::lock_guard lock(_lock);