From 75e674cc2040c2347ec05b6bf6d353b97a9e0965 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Wed, 25 Feb 2026 11:59:53 -0800 Subject: [PATCH] Use std::ranges::reverse_view and enable clang-tidy reverse ranges Summary: Previously, the RN build in fbcode was using an old platform version with poor support for std::ranges, so we had disabled clang-tidy's `modernize-loop-convert.UseCxx20ReverseRanges` check. This is no longer the case, so we can remove the suppression and replace instances of reverse iteration using rbegin/rend iterators with `std::ranges::reverse_view`. Changelog: [Internal] Differential Revision: D75834622 --- .../ComponentViews/View/RCTViewComponentView.mm | 4 ++-- .../RuntimeSamplingProfileTraceEventSerializer.cpp | 4 ++-- .../react/renderer/core/LayoutableShadowNode.cpp | 10 ++++++---- .../ReactCommon/react/renderer/core/ShadowNode.cpp | 6 +++--- .../react/renderer/core/ShadowNodeFamily.cpp | 4 ++-- .../renderer/uimanager/PointerEventsProcessor.cpp | 12 ++++++------ .../react/renderer/uimanager/PointerHoverTracker.cpp | 5 +++-- .../renderer/uimanager/UIManagerUpdateShadowTree.cpp | 9 +++++---- 8 files changed, 29 insertions(+), 25 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index d338f1649373..23d1a212238c 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -1216,9 +1216,9 @@ - (void)invalidateLayer if (!_boxShadowLayers) { _boxShadowLayers = [NSMutableArray new]; } - for (auto it = _props->boxShadow.rbegin(); it != _props->boxShadow.rend(); ++it) { + for (const auto &shadow : std::ranges::reverse_view(_props->boxShadow)) { CALayer *shadowLayer = RCTGetBoxShadowLayer( - *it, + shadow, RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), RCTUIEdgeInsetsFromEdgeInsets(borderMetrics.borderWidths), self.layer.bounds.size); diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tracing/RuntimeSamplingProfileTraceEventSerializer.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tracing/RuntimeSamplingProfileTraceEventSerializer.cpp index f95fb225b820..dd5b303a3cda 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tracing/RuntimeSamplingProfileTraceEventSerializer.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/tracing/RuntimeSamplingProfileTraceEventSerializer.cpp @@ -10,6 +10,7 @@ #include "ProfileTreeNode.h" #include "TraceEventSerializer.h" +#include #include #include @@ -192,8 +193,7 @@ void processCallStack( } ProfileTreeNode* previousNode = &rootNode; - for (auto it = callStack.rbegin(); it != callStack.rend(); ++it) { - const RuntimeSamplingProfile::SampleCallStackFrame& callFrame = *it; + for (const auto& callFrame : std::ranges::reverse_view(callStack)) { bool isGarbageCollectorFrame = callFrame.kind == RuntimeSamplingProfile::SampleCallStackFrame::Kind::GarbageCollector; diff --git a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp index 515ee47a39f2..b2ccd71436ab 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp @@ -7,6 +7,8 @@ #include "LayoutableShadowNode.h" +#include + #include #include #include @@ -106,8 +108,8 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( // root because we measure it from an outside tree perspective. shadowNodeList.push_back(descendantNode); - for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) { - auto& shadowNode = it->first.get(); + for (auto& ancestor : std::ranges::reverse_view(ancestors)) { + auto& shadowNode = ancestor.first.get(); shadowNodeList.push_back(&shadowNode); @@ -334,8 +336,8 @@ std::shared_ptr LayoutableShadowNode::findNodeAtPoint( return lhs->getOrderIndex() < rhs->getOrderIndex(); }); - for (auto it = sortedChildren.rbegin(); it != sortedChildren.rend(); it++) { - const auto& childShadowNode = *it; + for (const auto& childShadowNode : + std::ranges::reverse_view(sortedChildren)) { auto hitView = findNodeAtPoint(childShadowNode, newPoint); if (hitView) { return hitView; diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp index 168dd4079d4d..df0f4e9cb8a0 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -391,9 +392,8 @@ std::shared_ptr ShadowNode::cloneTree( auto childNode = newShadowNode; - for (auto it = ancestors.rbegin(); it != ancestors.rend(); ++it) { - auto& parentNode = it->first.get(); - auto childIndex = it->second; + for (auto& [ancestorRef, childIndex] : std::ranges::reverse_view(ancestors)) { + auto& parentNode = ancestorRef.get(); auto children = parentNode.getChildren(); react_native_assert( diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp index 68a322bc1791..dc5bdb8c5d30 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -116,8 +117,7 @@ AncestorList ShadowNodeFamily::getAncestors( auto ancestors = AncestorList{}; auto parentNode = &ancestorShadowNode; - for (auto it = families.rbegin(); it != families.rend(); it++) { - auto childFamily = *it; + for (auto childFamily : std::ranges::reverse_view(families)) { auto found = false; auto childIndex = 0; for (const auto& childNode : *parentNode->children_) { diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp index ea46a1a3a5e9..0d87b7b8fcd2 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace facebook::react { @@ -79,8 +80,9 @@ static bool isAnyViewInPathToRootListeningToEvents( auto ancestors = nodeFamily.getAncestors(*owningRootShadowNode); // Check for listeners from the target's parent to the root - for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) { - auto& currentNode = it->first.get(); + for (auto& [ancestorNode, childIndex] : + std::ranges::reverse_view(ancestors)) { + auto& currentNode = ancestorNode.get(); if (isViewListeningToEvents(currentNode, eventTypes)) { return true; } @@ -488,11 +490,9 @@ void PointerEventsProcessor::handleIncomingPointerEventOnNode( } // Actually emit the leave events (in order from target to root) - for (auto it = targetsToEmitLeaveTo.rbegin(); - it != targetsToEmitLeaveTo.rend(); - it++) { + for (auto& target : std::ranges::reverse_view(targetsToEmitLeaveTo)) { eventDispatcher( - *it, "topPointerLeave", ReactEventPriority::Discrete, event); + target, "topPointerLeave", ReactEventPriority::Discrete, event); } // Over diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/PointerHoverTracker.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/PointerHoverTracker.cpp index e37e9dc3dd19..4e13c75ead55 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/PointerHoverTracker.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/PointerHoverTracker.cpp @@ -7,6 +7,7 @@ #include "PointerHoverTracker.h" +#include #include namespace facebook::react { @@ -139,8 +140,8 @@ EventPath PointerHoverTracker::getEventPathTargets() const { auto ancestors = target_->getFamily().getAncestors(*root_); result.emplace_back(*target_); - for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) { - result.push_back(it->first); + for (auto& [ancestor, index] : std::ranges::reverse_view(ancestors)) { + result.push_back(ancestor); } return result; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerUpdateShadowTree.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerUpdateShadowTree.cpp index c691d5a897ca..c3b8dc955e32 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerUpdateShadowTree.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerUpdateShadowTree.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace facebook::react { @@ -52,8 +53,8 @@ void addAncestorsToUpdateList( int ancestorDepth = static_cast(ancestors.size() - 1); // iterate from current ShadowNode's parent to root ShadowNode - for (auto iter = ancestors.rbegin(); iter != ancestors.rend(); ++iter) { - auto& ancestorShadowNode = iter->first.get(); + for (auto& [ancestorRef, childIdx] : std::ranges::reverse_view(ancestors)) { + auto& ancestorShadowNode = ancestorRef.get(); auto ancestorTag = ancestorShadowNode.getTag(); auto ancestorAddedToUpdateList = std::find_if( shadowNodesToUpdate.begin(), @@ -67,10 +68,10 @@ void addAncestorsToUpdateList( .tag = ancestorShadowNode.getTag(), .depth = ancestorDepth, .node = ancestorShadowNodesShared[ancestorDepth], - .updatedChildrenIndices = {iter->second}, + .updatedChildrenIndices = {childIdx}, }); } else { - ancestorAddedToUpdateList->updatedChildrenIndices.push_back(iter->second); + ancestorAddedToUpdateList->updatedChildrenIndices.push_back(childIdx); } ancestorDepth--; }