Skip to content

Commit a262b4e

Browse files
committed
refactor: replace private access hacks with accessor pattern
Remove all '#define private/protected public' hacks and replace them with a proper C++ template-based private accessor pattern using explicit template instantiation (friend injection trick), mirroring the approach used in linuxdeepin/treeland#875. Adds src/util/dprivateaccessor_p.h with Accessor/AccessorImpl templates and D_DECLARE_PRIVATE_MEMBER, D_PRIVATE_MEMBER macros. All helpers live at global scope so ADL correctly resolves the friend-injected get() function.
1 parent 2806ffa commit a262b4e

3 files changed

Lines changed: 92 additions & 18 deletions

File tree

src/private/dbackdropnode.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

55
#include <QDebug>
6-
#define protected public
7-
#define private public
86
#include <rhi/qrhi.h>
97
#include <private/qsgrenderer_p.h>
10-
#undef protected
11-
#undef private
128

139
#include "dbackdropnode_p.h"
1410
#include "dqmlglobalobject_p.h"
11+
#include "util/dprivateaccessor_p.h"
1512

1613
#include <QQuickItem>
1714
#include <QRunnable>
@@ -34,6 +31,10 @@
3431

3532
#include <algorithm>
3633

34+
#ifndef QT_NO_OPENGL
35+
D_DECLARE_PRIVATE_MEMBER(QRhi_d_tag, QRhi, d, QRhiImplementation*);
36+
#endif
37+
3738
DQUICK_BEGIN_NAMESPACE
3839

3940
class Q_DECL_HIDDEN DataManagerBase : public QObject
@@ -360,7 +361,7 @@ class Q_DECL_HIDDEN RhiManager : public DataManager<RhiManager, void>
360361
QRhiGles2 *gles2Rhi = nullptr;
361362
if (forceSurface) {
362363
Q_ASSERT(rhi()->backend() == QRhi::OpenGLES2);
363-
gles2Rhi = static_cast<QRhiGles2*>(rhi()->d);
364+
gles2Rhi = static_cast<QRhiGles2*>(D_PRIVATE_MEMBER(*rhi(), QRhi_d_tag{}));
364365
fallbackSurface = gles2Rhi->fallbackSurface;
365366
gles2Rhi->fallbackSurface = forceSurface;
366367
}
@@ -383,17 +384,14 @@ class Q_DECL_HIDDEN RhiManager : public DataManager<RhiManager, void>
383384
oldCB = dc->currentFrameCommandBuffer();
384385
context->prepareSync(renderer->devicePixelRatio(), cb, graphicsConfiguration());
385386

386-
renderer->m_is_rendering = true;
387-
renderer->preprocess();
387+
renderer->prepareSceneInline();
388388

389389
return true;
390390
}
391391

392392
bool render(qreal oldDPR, QRhiCommandBuffer* &oldCB) {
393-
Q_ASSERT(renderer->m_is_rendering);
394-
renderer->render();
395-
renderer->m_is_rendering = false;
396-
renderer->m_changed_emitted = false;
393+
renderer->renderSceneInline();
394+
renderer->clearChangedFlag();
397395

398396
context->prepareSync(oldDPR, oldCB, graphicsConfiguration());
399397

src/private/dqmlglobalobject.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

5-
#define private public
65
#include <QSGNode>
7-
#undef private
86

97
#include "dqmlglobalobject_p.h"
108
#include "dqmlglobalobject_p_p.h"
9+
#include "util/dprivateaccessor_p.h"
1110
#include "dquickcontrolpalette_p.h"
1211
#include "dquickdciicon_p.h"
1312
#include "dquickimageprovider_p.h"
@@ -36,6 +35,11 @@
3635

3736
DGUI_USE_NAMESPACE
3837

38+
D_DECLARE_PRIVATE_MEMBER(QSGNode_m_subtreeRenderableCount_tag, QSGNode, m_subtreeRenderableCount, int);
39+
D_DECLARE_PRIVATE_MEMBER(QSGNode_m_firstChild_tag, QSGNode, m_firstChild, QSGNode *);
40+
D_DECLARE_PRIVATE_MEMBER(QSGNode_m_lastChild_tag, QSGNode, m_lastChild, QSGNode *);
41+
D_DECLARE_PRIVATE_MEMBER(QSGNode_m_parent_tag, QSGNode, m_parent, QSGNode *);
42+
3943
DQUICK_BEGIN_NAMESPACE
4044

4145
// ###(zccrs): The offset must greater than QColor::Spec
@@ -550,22 +554,22 @@ QSGRootNode *DQMLGlobalObject::getRootNode(QQuickItem *item)
550554

551555
int &DQMLGlobalObject::QSGNode_subtreeRenderableCount(QSGNode *node)
552556
{
553-
return node->m_subtreeRenderableCount;
557+
return D_PRIVATE_MEMBER(*node, QSGNode_m_subtreeRenderableCount_tag{});
554558
}
555559

556560
QSGNode *&DQMLGlobalObject::QSGNode_firstChild(QSGNode *node)
557561
{
558-
return node->m_firstChild;
562+
return D_PRIVATE_MEMBER(*node, QSGNode_m_firstChild_tag{});
559563
}
560564

561565
QSGNode *&DQMLGlobalObject::QSGNode_lastChild(QSGNode *node)
562566
{
563-
return node->m_lastChild;
567+
return D_PRIVATE_MEMBER(*node, QSGNode_m_lastChild_tag{});
564568
}
565569

566570
QSGNode *&DQMLGlobalObject::QSGNode_parent(QSGNode *node)
567571
{
568-
return node->m_parent;
572+
return D_PRIVATE_MEMBER(*node, QSGNode_m_parent_tag{});
569573
}
570574
#endif
571575

src/util/dprivateaccessor_p.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
2+
//
3+
// SPDX-License-Identifier: LGPL-3.0-or-later
4+
5+
#pragma once
6+
7+
#include <QtCore/qcompilerdetection.h>
8+
9+
// Private member accessor using the explicit template instantiation technique.
10+
//
11+
// C++ Standard [temp.explicit]/12 states:
12+
// "The usual access checking rules do not apply to names used to
13+
// specify explicit instantiation definitions."
14+
//
15+
// This allows passing pointers to private/protected data members and
16+
// member functions as template arguments in explicit instantiations,
17+
// bypassing normal access control — without modifying the class definition
18+
// and without the UB caused by "#define private public".
19+
//
20+
// NOTE: These helper structs must be in the SAME namespace as the Tag structs
21+
// (global namespace, since the macros expand at file scope). If they were in a
22+
// sub-namespace, the friend definition would create a different function than
23+
// the friend declaration in the Tag struct, causing undefined-reference errors.
24+
25+
QT_WARNING_PUSH
26+
QT_WARNING_DISABLE_GCC("-Wnon-template-friend")
27+
28+
template<typename Tag>
29+
struct DtkDeclarativePrivateAccessor
30+
{
31+
using MemberPtr = typename Tag::MemberPtr;
32+
friend MemberPtr get(Tag) noexcept;
33+
};
34+
35+
template<typename Tag, typename Tag::MemberPtr Ptr>
36+
struct DtkDeclarativePrivateAccessorImpl : DtkDeclarativePrivateAccessor<Tag>
37+
{
38+
friend typename Tag::MemberPtr get(Tag) noexcept { return Ptr; }
39+
};
40+
41+
QT_WARNING_POP
42+
43+
#define D_DECLARE_PRIVATE_MEMBER(TagName, ClassName, Member, MemberType) \
44+
struct TagName { \
45+
using MemberPtr = MemberType ClassName::*; \
46+
friend MemberPtr get(TagName) noexcept; \
47+
}; \
48+
template struct DtkDeclarativePrivateAccessorImpl<TagName, &ClassName::Member>
49+
50+
#define D_DECLARE_PRIVATE_METHOD(TagName, ClassName, MethodName, RetType, ...) \
51+
struct TagName { \
52+
using MemberPtr = RetType (ClassName::*)(__VA_ARGS__); \
53+
friend MemberPtr get(TagName) noexcept; \
54+
}; \
55+
template struct DtkDeclarativePrivateAccessorImpl<TagName, &ClassName::MethodName>
56+
57+
#define D_DECLARE_PRIVATE_CONST_METHOD(TagName, ClassName, MethodName, RetType, ...) \
58+
struct TagName { \
59+
using MemberPtr = RetType (ClassName::*)(__VA_ARGS__) const; \
60+
friend MemberPtr get(TagName) noexcept; \
61+
}; \
62+
template struct DtkDeclarativePrivateAccessorImpl<TagName, &ClassName::MethodName>
63+
64+
// Trampoline: ensures get(tag) is called from a context with no class-scope
65+
// get() member that might suppress ADL (C++ [basic.lookup.argdep] para 3).
66+
namespace dtk_private_detail {
67+
template<typename Tag>
68+
inline typename Tag::MemberPtr access(Tag t) noexcept { return get(t); }
69+
}
70+
71+
#define D_PRIVATE_MEMBER(obj, tag) ((obj).*dtk_private_detail::access(tag))
72+
#define D_PRIVATE_CALL(obj, tag, ...) ((obj).*dtk_private_detail::access(tag))(__VA_ARGS__)

0 commit comments

Comments
 (0)