Skip to content

Commit 1170a68

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Delete traitCast and identifier traits (#42748)
Summary: Pull Request resolved: #42748 React Native has globally enabled RTTI within `rn_xplat_cxx_library`, ahead of RTTI being forced on (regardless of flag) in Android apps (it was previously enabled everywhere but Android, which has caused us no small share of headaches, with public JSI APIs designed around clients using RTTI). This diff: 1. Mechanically replaces usages of `traitCast` with equivalent calls to `dynamic_cast` or `dynamic_pointer_cast` 1. These have similar semantics as current iteration of `traitCast`, where we return `nullptr` for pointer form, or throw on invalid cast for reference form. 2. Removes `IdentifierTrait` as a requirement to cast to a ShadowNode 3. Removes the ShadowNode traits used solely as cast identities This enables consistent usage of `dynamic_cast` (including for user defined ShadowNodes), and also exposes some places where `traitCast` allowed implicit const conversion. The OSS builds should already have RTTI on, and will be able to use `dynamic_cast` on RN provided types (`traitCast` is not extendable). Changelog: [General][Breaking] - Delete traitCast and identifier traits Reviewed By: sammy-SC Differential Revision: D53215009 fbshipit-source-id: d20cbf66b725f5565fa5d03332010d87f2b08b61
1 parent 810c205 commit 1170a68

File tree

26 files changed

+75
-371
lines changed

26 files changed

+75
-371
lines changed

packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ add_executable(reactnative_unittest
154154
${REACT_COMMON_DIR}/react/renderer/core/tests/PrimitivesTest.cpp
155155
${REACT_COMMON_DIR}/react/renderer/core/tests/RawPropsTest.cpp
156156
${REACT_COMMON_DIR}/react/renderer/core/tests/ShadowNodeFamilyTest.cpp
157-
${REACT_COMMON_DIR}/react/renderer/core/tests/traitCastTest.cpp
158157
${REACT_COMMON_DIR}/react/renderer/debug/tests/DebugStringConvertibleTest.cpp
159158
${REACT_COMMON_DIR}/react/renderer/element/tests/ElementTest.cpp
160159
${REACT_COMMON_DIR}/react/renderer/graphics/tests/GraphicsTest.cpp

packages/react-native/ReactCommon/react/renderer/components/text/BaseTextShadowNode.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <react/renderer/components/text/RawTextShadowNode.h>
1212
#include <react/renderer/components/text/TextProps.h>
1313
#include <react/renderer/components/text/TextShadowNode.h>
14-
#include <react/renderer/core/TraitCast.h>
1514
#include <react/renderer/mounting/ShadowView.h>
1615

1716
namespace facebook::react {
@@ -33,7 +32,7 @@ void BaseTextShadowNode::buildAttributedString(
3332
for (const auto& childNode : parentNode.getChildren()) {
3433
// RawShadowNode
3534
auto rawTextShadowNode =
36-
traitCast<const RawTextShadowNode*>(childNode.get());
35+
dynamic_cast<const RawTextShadowNode*>(childNode.get());
3736
if (rawTextShadowNode != nullptr) {
3837
auto fragment = AttributedString::Fragment{};
3938
fragment.string = rawTextShadowNode->getConcreteProps().text;
@@ -49,7 +48,7 @@ void BaseTextShadowNode::buildAttributedString(
4948
}
5049

5150
// TextShadowNode
52-
auto textShadowNode = traitCast<const TextShadowNode*>(childNode.get());
51+
auto textShadowNode = dynamic_cast<const TextShadowNode*>(childNode.get());
5352
if (textShadowNode != nullptr) {
5453
auto localTextAttributes = baseTextAttributes;
5554
localTextAttributes.apply(

packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <react/renderer/attributedstring/AttributedStringBox.h>
1414
#include <react/renderer/components/view/ViewShadowNode.h>
1515
#include <react/renderer/components/view/conversions.h>
16-
#include <react/renderer/core/TraitCast.h>
1716
#include <react/renderer/graphics/rounding.h>
1817
#include <react/renderer/telemetry/TransactionTelemetry.h>
1918
#include <react/renderer/textlayoutmanager/TextLayoutContext.h>
@@ -31,7 +30,7 @@ ParagraphShadowNode::ParagraphShadowNode(
3130
const ShadowNodeFragment& fragment)
3231
: ConcreteViewShadowNode(sourceShadowNode, fragment) {
3332
auto& sourceParagraphShadowNode =
34-
traitCast<ParagraphShadowNode const&>(sourceShadowNode);
33+
dynamic_cast<const ParagraphShadowNode&>(sourceShadowNode);
3534
if (!fragment.children && !fragment.props &&
3635
sourceParagraphShadowNode.getIsLayoutClean()) {
3736
// This ParagraphShadowNode was cloned but did not change
@@ -84,7 +83,7 @@ Content ParagraphShadowNode::getContentWithMeasuredAttachments(
8483

8584
for (const auto& attachment : content.attachments) {
8685
auto laytableShadowNode =
87-
traitCast<const LayoutableShadowNode*>(attachment.shadowNode);
86+
dynamic_cast<const LayoutableShadowNode*>(attachment.shadowNode);
8887

8988
if (laytableShadowNode == nullptr) {
9089
continue;
@@ -213,7 +212,7 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
213212
for (size_t i = 0; i < content.attachments.size(); i++) {
214213
auto& attachment = content.attachments.at(i);
215214

216-
if (traitCast<const LayoutableShadowNode*>(attachment.shadowNode) ==
215+
if (dynamic_cast<const LayoutableShadowNode*>(attachment.shadowNode) ==
217216
nullptr) {
218217
// Not a layoutable `ShadowNode`, no need to lay it out.
219218
continue;
@@ -231,7 +230,7 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
231230
static_cast<ParagraphShadowNode*>(paragraphOwningShadowNode.get());
232231

233232
auto& layoutableShadowNode =
234-
traitCast<LayoutableShadowNode&>(*clonedShadowNode);
233+
dynamic_cast<LayoutableShadowNode&>(*clonedShadowNode);
235234

236235
auto attachmentFrame = measurement.attachments[i].frame;
237236
auto attachmentSize = roundToPixel<&ceil>(

packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class ParagraphShadowNode final : public ConcreteViewShadowNode<
4141
static ShadowNodeTraits BaseTraits() {
4242
auto traits = ConcreteViewShadowNode::BaseTraits();
4343
traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
44-
traits.set(ShadowNodeTraits::Trait::TextKind);
4544
traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
4645

4746
#ifdef ANDROID

packages/react-native/ReactCommon/react/renderer/components/text/RawTextShadowNode.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,6 @@ class RawTextShadowNode : public ConcreteShadowNode<
2626
RawTextProps> {
2727
public:
2828
using ConcreteShadowNode::ConcreteShadowNode;
29-
static ShadowNodeTraits BaseTraits() {
30-
auto traits = ConcreteShadowNode::BaseTraits();
31-
traits.set(IdentifierTrait());
32-
return traits;
33-
}
34-
static ShadowNodeTraits::Trait IdentifierTrait() {
35-
return ShadowNodeTraits::Trait::RawText;
36-
}
3729
};
3830

3931
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/components/text/TextShadowNode.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,12 @@ class TextShadowNode : public ConcreteShadowNode<
2929
public:
3030
static ShadowNodeTraits BaseTraits() {
3131
auto traits = ConcreteShadowNode::BaseTraits();
32-
3332
#ifdef ANDROID
3433
traits.set(ShadowNodeTraits::Trait::FormsView);
3534
#endif
36-
traits.set(IdentifierTrait());
37-
3835
return traits;
3936
}
4037

41-
static ShadowNodeTraits::Trait IdentifierTrait() {
42-
return ShadowNodeTraits::Trait::Text;
43-
}
44-
4538
using ConcreteShadowNode::ConcreteShadowNode;
4639

4740
#ifdef ANDROID

packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ class AndroidTextInputShadowNode final : public ConcreteViewShadowNode<
3131
public:
3232
static ShadowNodeTraits BaseTraits() {
3333
auto traits = ConcreteViewShadowNode::BaseTraits();
34-
traits.set(ShadowNodeTraits::Trait::TextKind);
3534
traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
3635
return traits;
3736
}

packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ class TextInputShadowNode final : public ConcreteViewShadowNode<
3434

3535
static ShadowNodeTraits BaseTraits() {
3636
auto traits = ConcreteViewShadowNode::BaseTraits();
37-
traits.set(ShadowNodeTraits::Trait::TextKind);
3837
traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
3938
traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
4039
return traits;

packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ class ViewShadowNode final : public ConcreteViewShadowNode<
3434
ViewShadowNodeProps,
3535
ViewEventEmitter> {
3636
public:
37-
static ShadowNodeTraits BaseTraits() {
38-
auto traits = ConcreteViewShadowNode::BaseTraits();
39-
traits.set(ShadowNodeTraits::Trait::View);
40-
return traits;
41-
}
42-
4337
ViewShadowNode(
4438
const ShadowNodeFragment& fragment,
4539
const ShadowNodeFamily::Shared& family,

packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <react/renderer/components/view/conversions.h>
1515
#include <react/renderer/core/LayoutConstraints.h>
1616
#include <react/renderer/core/LayoutContext.h>
17-
#include <react/renderer/core/TraitCast.h>
1817
#include <react/renderer/debug/DebugStringConvertibleItem.h>
1918
#include <react/renderer/debug/SystraceSection.h>
2019
#include <react/utils/CoreFeatures.h>
@@ -25,6 +24,8 @@
2524

2625
namespace facebook::react {
2726

27+
static_assert(RawPropsFilterable<YogaLayoutableShadowNode>);
28+
2829
static int FabricDefaultYogaLog(
2930
const YGConfigConstRef /*unused*/,
3031
const YGNodeConstRef /*unused*/,
@@ -62,16 +63,6 @@ static int FabricDefaultYogaLog(
6263

6364
thread_local LayoutContext threadLocalLayoutContext;
6465

65-
ShadowNodeTraits YogaLayoutableShadowNode::BaseTraits() {
66-
auto traits = LayoutableShadowNode::BaseTraits();
67-
traits.set(IdentifierTrait());
68-
return traits;
69-
}
70-
71-
ShadowNodeTraits::Trait YogaLayoutableShadowNode::IdentifierTrait() {
72-
return ShadowNodeTraits::Trait::YogaLayoutableKind;
73-
}
74-
7566
YogaLayoutableShadowNode::YogaLayoutableShadowNode(
7667
const ShadowNodeFragment& fragment,
7768
const ShadowNodeFamily::Shared& family,
@@ -123,8 +114,10 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode(
123114

124115
if (!getTraits().check(ShadowNodeTraits::Trait::LeafYogaNode)) {
125116
for (auto& child : getChildren()) {
126-
if (auto layoutableChild = traitCast<YogaLayoutableShadowNode>(child)) {
127-
yogaLayoutableChildren_.push_back(layoutableChild);
117+
if (auto layoutableChild =
118+
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(
119+
child)) {
120+
yogaLayoutableChildren_.push_back(std::move(layoutableChild));
128121
}
129122
}
130123
}
@@ -210,7 +203,7 @@ void YogaLayoutableShadowNode::adoptYogaChild(size_t index) {
210203
!getTraits().check(ShadowNodeTraits::Trait::LeafYogaNode));
211204

212205
auto& childNode =
213-
traitCast<const YogaLayoutableShadowNode&>(*getChildren().at(index));
206+
dynamic_cast<const YogaLayoutableShadowNode&>(*getChildren().at(index));
214207

215208
if (childNode.yogaNode_.getOwner() == nullptr) {
216209
// The child node is not owned.
@@ -243,7 +236,8 @@ void YogaLayoutableShadowNode::appendChild(
243236
}
244237

245238
if (auto yogaLayoutableChild =
246-
traitCast<YogaLayoutableShadowNode>(childNode)) {
239+
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(
240+
childNode)) {
247241
// Here we don't have information about the previous structure of the node
248242
// (if it that existed before), so we don't have anything to compare the
249243
// Yoga node with (like a previous version of this node). Therefore we must
@@ -273,8 +267,9 @@ void YogaLayoutableShadowNode::replaceChild(
273267
ensureYogaChildrenLookFine();
274268

275269
auto layoutableOldChild =
276-
traitCast<const YogaLayoutableShadowNode*>(&oldChild);
277-
auto layoutableNewChild = traitCast<YogaLayoutableShadowNode>(newChild);
270+
dynamic_cast<const YogaLayoutableShadowNode*>(&oldChild);
271+
auto layoutableNewChild =
272+
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(newChild);
278273

279274
if (layoutableOldChild == nullptr && layoutableNewChild == nullptr) {
280275
// No need to mutate yogaLayoutableChildren_
@@ -349,7 +344,8 @@ void YogaLayoutableShadowNode::updateYogaChildren() {
349344

350345
for (size_t i = 0; i < getChildren().size(); i++) {
351346
if (auto yogaLayoutableChild =
352-
traitCast<YogaLayoutableShadowNode>(getChildren()[i])) {
347+
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(
348+
getChildren()[i])) {
353349
appendYogaChild(yogaLayoutableChild);
354350
adoptYogaChild(i);
355351

@@ -496,7 +492,7 @@ void YogaLayoutableShadowNode::configureYogaTree(
496492
}
497493

498494
YGErrata YogaLayoutableShadowNode::resolveErrata(YGErrata defaultErrata) const {
499-
if (auto viewShadowNode = traitCast<const ViewShadowNode*>(this)) {
495+
if (auto viewShadowNode = dynamic_cast<const ViewShadowNode*>(this)) {
500496
const auto& props = viewShadowNode->getConcreteProps();
501497
switch (props.experimental_layoutConformance) {
502498
case LayoutConformance::Classic:
@@ -745,7 +741,7 @@ Rect YogaLayoutableShadowNode::getContentBounds() const {
745741

746742
auto layoutMetricsWithOverflowInset = childNode.getLayoutMetrics();
747743
if (layoutMetricsWithOverflowInset.displayType != DisplayType::None) {
748-
auto viewChildNode = traitCast<const ViewShadowNode*>(&childNode);
744+
auto viewChildNode = dynamic_cast<const ViewShadowNode*>(&childNode);
749745
auto hitSlop = viewChildNode != nullptr
750746
? viewChildNode->getConcreteProps().hitSlop
751747
: EdgeInsets{};
@@ -776,6 +772,13 @@ Rect YogaLayoutableShadowNode::getContentBounds() const {
776772
return contentBounds;
777773
}
778774

775+
/*static*/ void YogaLayoutableShadowNode::filterRawProps(RawProps& rawProps) {
776+
if (CoreFeatures::excludeYogaFromRawProps) {
777+
// TODO: this shouldn't live in RawProps
778+
rawProps.filterYogaStylePropsInDynamicConversion();
779+
}
780+
}
781+
779782
#pragma mark - Yoga Connectors
780783

781784
YGNodeRef YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(
@@ -837,7 +840,7 @@ YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector(
837840

838841
YogaLayoutableShadowNode& YogaLayoutableShadowNode::shadowNodeFromContext(
839842
YGNodeConstRef yogaNode) {
840-
return traitCast<YogaLayoutableShadowNode&>(
843+
return dynamic_cast<YogaLayoutableShadowNode&>(
841844
*static_cast<ShadowNode*>(YGNodeGetContext(yogaNode)));
842845
}
843846

@@ -1014,7 +1017,7 @@ void YogaLayoutableShadowNode::ensureYogaChildrenAlignment() const {
10141017
auto& child = children.at(i);
10151018
react_native_assert(
10161019
yogaChild->getContext() ==
1017-
traitCast<const YogaLayoutableShadowNode*>(child.get()));
1020+
dynamic_cast<const YogaLayoutableShadowNode*>(child.get()));
10181021
}
10191022
#endif
10201023
}

packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
2626
using Shared = std::shared_ptr<const YogaLayoutableShadowNode>;
2727
using ListOfShared = std::vector<Shared>;
2828

29-
static ShadowNodeTraits BaseTraits();
30-
static ShadowNodeTraits::Trait IdentifierTrait();
31-
3229
#pragma mark - Constructors
3330

3431
YogaLayoutableShadowNode(
@@ -88,6 +85,8 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
8885

8986
Rect getContentBounds() const;
9087

88+
static void filterRawProps(RawProps& rawProps);
89+
9190
protected:
9291
/*
9392
* Yoga config associated (only) with this particular node.

packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,8 @@ class ConcreteComponentDescriptor : public ComponentDescriptor {
105105
return ShadowNodeT::defaultSharedProps();
106106
}
107107

108-
if (CoreFeatures::excludeYogaFromRawProps) {
109-
if (ShadowNodeT::IdentifierTrait() ==
110-
ShadowNodeTraits::Trait::YogaLayoutableKind) {
111-
rawProps.filterYogaStylePropsInDynamicConversion();
112-
}
108+
if constexpr (RawPropsFilterable<ShadowNodeT>) {
109+
ShadowNodeT::filterRawProps(rawProps);
113110
}
114111

115112
rawProps.parse(rawPropsParser_);

packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ class ConcreteShadowNode : public BaseShadowNodeT {
7070
return BaseShadowNodeT::BaseTraits();
7171
}
7272

73-
static ShadowNodeTraits::Trait IdentifierTrait() {
74-
return BaseShadowNodeT::IdentifierTrait();
75-
}
76-
7773
static UnsharedConcreteProps Props(
7874
const PropsParserContext& context,
7975
const RawProps& rawProps,

0 commit comments

Comments
 (0)