From 51002ce4b9394aa5c66077742ad8744039c23669 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Fri, 26 Jun 2026 08:48:34 -0700 Subject: [PATCH] Fix ctor/setProp prop-name gaps surfaced by iterator-setter audit (#57330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Auditing every Props .cpp file in the renderer surfaced six cases where a prop key parsed by the 3-arg constructor's `convertRawProp(...)` call had no matching `case` in the same class's `setProp` method. With the iterator-setter path now routing every prop through `setProp` (instead of re-running the parsing constructor), each gap silently drops the prop on the floor when the iterator-setter path is active. Fix each gap: - `BaseScrollViewProps::setProp` — add `RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustKeyboardInsets)`. Parsed in ctor, missing case. - `BaseTextProps::setProp` — add `REBUILD_FIELD_SWITCH_CASE(... dynamicTypeRamp, "dynamicTypeRamp")`. Parsed in ctor, missing case. - `BaseTextProps::setProp` — rename the `baseWritingDirection` switch case key to `writingDirection`. JS sends `writingDirection` (the C++ field is named `baseWritingDirection` internally, but JS / Flow / TS / codegen all use `writingDirection` — verified across `StyleSheetTypes.js`, `StyleSheetTypes.d.ts`, `ReactNativeStyleAttributes.js`, `RCTTextInputViewConfig.js`, and the `Text-itest.js` integration test mounts ``). The setProp case was keyed off the C++ field name and never fired for any real JS prop. `appendTextAttributesProps` still emits `baseWritingDirection` for the C++→JS diff path — that's a separate, out-of-scope inconsistency. - `AccessibilityProps::setProp` — rename the `accessibilityOrder` switch case key to `experimental_accessibilityOrder`. JS sends the prefixed name (verified in `ViewPropTypes.js`, `BaseViewConfig.android.js`, `BaseViewConfig.ios.js`, `ViewProps.kt`'s `ACCESSIBILITY_ORDER = "experimental_accessibilityOrder"` constant, and `HostPlatformViewProps::getDebugProps` which serializes back out as `experimental_accessibilityOrder`). The unprefixed case never fired. - `BaseViewProps::setProp` — add `RAW_SET_PROP_SWITCH_CASE_BASIC(transformOrigin)`. Parsed in ctor, missing case. - `BaseViewProps::setProp` — add `SET_CASCADED_RECTANGLE_CORNERS(borderCurves, "border", "Curve", value)`. The ctor parses the full 13-key cascaded set (`borderCurve`, `borderTopLeftCurve`, … `borderStartStartCurve`) via `CascadedRectangleCornersNames`, but `setProp` had `SET_CASCADED_RECTANGLE_CORNERS` for `borderRadii` and `SET_CASCADED_RECTANGLE_EDGES` for `borderColors`/`borderStyles` — the corresponding `borderCurves` invocation was missing. Same gaps in the `third-party/react-native-macos/.../BaseViewProps.cpp` mirror — applied the same fixes there. Out-of-scope but flagged by the audit (left for follow-ups): - `propsConversions.h`'s `ViewEvents` converter doesn't handle `onGotPointerCapture` / `onLostPointerCapture` (explicit `// TODO` at line 541). `BaseViewProps::setProp` does. Asymmetry runs the other direction — iterator-setter handles these, classic ctor doesn't. - android `HostPlatformViewProps.cpp` defines `VIEW_EVENT_CASE` macro but never invokes it in its switch — dead code (events live on `BaseViewProps::events`). Cleanup candidate. Changelog: [General][Fixed] - Several view, text, scrollview, and accessibility props that the iterator-setter path silently dropped now propagate correctly through `setProp`: `automaticallyAdjustKeyboardInsets`, `dynamicTypeRamp`, `writingDirection`, `experimental_accessibilityOrder`, `transformOrigin`, and the full `borderCurves` cascaded set. Differential Revision: D109584760 --- .../components/scrollview/BaseScrollViewProps.cpp | 1 + .../renderer/components/text/BaseTextProps.cpp | 4 +++- .../renderer/components/view/AccessibilityProps.cpp | 3 ++- .../renderer/components/view/BaseViewProps.cpp | 2 ++ .../components/view/HostPlatformViewProps.cpp | 12 ------------ .../renderer/components/view/propsConversions.h | 13 ++++++++++++- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp index a683cb87f825..93f7cc0a29e1 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp @@ -395,6 +395,7 @@ void BaseScrollViewProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(centerContent); RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustContentInsets); RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustsScrollIndicatorInsets); + RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustKeyboardInsets); RAW_SET_PROP_SWITCH_CASE_BASIC(decelerationRate); RAW_SET_PROP_SWITCH_CASE_BASIC(directionalLockEnabled); RAW_SET_PROP_SWITCH_CASE_BASIC(indicatorStyle); diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp index e2ab6780f96d..bf0019e02815 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp @@ -273,6 +273,8 @@ void BaseTextProps::setProp( textAttributes, maxFontSizeMultiplier, "maxFontSizeMultiplier"); + REBUILD_FIELD_SWITCH_CASE( + defaults, value, textAttributes, dynamicTypeRamp, "dynamicTypeRamp"); REBUILD_FIELD_SWITCH_CASE( defaults, value, textAttributes, letterSpacing, "letterSpacing"); REBUILD_FIELD_SWITCH_CASE( @@ -286,7 +288,7 @@ void BaseTextProps::setProp( value, textAttributes, baseWritingDirection, - "baseWritingDirection"); + "writingDirection"); REBUILD_FIELD_SWITCH_CASE( defaults, value, diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp index f94ac81e59f3..c9356759d7a9 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp @@ -267,7 +267,8 @@ void AccessibilityProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(accessible); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityState); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabel); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityOrder); + RAW_SET_PROP_SWITCH_CASE( + accessibilityOrder, "experimental_accessibilityOrder"); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabelledBy); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLiveRegion); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityHint); diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp index d3bae3163c09..50e57aeb70d9 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp @@ -465,6 +465,7 @@ void BaseViewProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOpacity); RAW_SET_PROP_SWITCH_CASE_BASIC(shadowRadius); RAW_SET_PROP_SWITCH_CASE_BASIC(transform); + RAW_SET_PROP_SWITCH_CASE_BASIC(transformOrigin); RAW_SET_PROP_SWITCH_CASE_BASIC(backfaceVisibility); RAW_SET_PROP_SWITCH_CASE_BASIC(shouldRasterize); RAW_SET_PROP_SWITCH_CASE_BASIC(zIndex); @@ -522,6 +523,7 @@ void BaseViewProps::setProp( // BorderRadii SET_CASCADED_RECTANGLE_CORNERS(borderRadii, "border", "Radius", value); SET_CASCADED_RECTANGLE_EDGES(borderColors, "border", "Color", value); + SET_CASCADED_RECTANGLE_CORNERS(borderCurves, "border", "Curve", value); SET_CASCADED_RECTANGLE_EDGES(borderStyles, "border", "Style", value); } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp index 304cfa8c27da..4a9bf3c78b39 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp @@ -143,18 +143,6 @@ HostPlatformViewProps::HostPlatformViewProps( sourceProps.nextFocusUp, {})) {} -#define VIEW_EVENT_CASE(eventType) \ - case CONSTEXPR_RAW_PROPS_KEY_HASH("on" #eventType): { \ - const auto offset = ViewEvents::Offset::eventType; \ - ViewEvents defaultViewEvents{}; \ - bool res = defaultViewEvents[offset]; \ - if (value.hasValue()) { \ - fromRawValue(context, value, res); \ - } \ - events[offset] = res; \ - return; \ - } - void HostPlatformViewProps::setProp( const PropsParserContext& context, RawPropsPropNameHash hash, diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h index 54602ebaf2f1..5b19dfc2c077 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h @@ -538,7 +538,18 @@ static inline ViewEvents convertRawProp( "onPointerUpCapture", sourceValue[Offset::PointerUpCapture], defaultValue[Offset::PointerUpCapture]); - // TODO: gotPointerCapture & lostPointerCapture + result[Offset::GotPointerCapture] = convertRawProp( + context, + rawProps, + "onGotPointerCapture", + sourceValue[Offset::GotPointerCapture], + defaultValue[Offset::GotPointerCapture]); + result[Offset::LostPointerCapture] = convertRawProp( + context, + rawProps, + "onLostPointerCapture", + sourceValue[Offset::LostPointerCapture], + defaultValue[Offset::LostPointerCapture]); // PanResponder callbacks result[Offset::MoveShouldSetResponder] = convertRawProp(