Skip to content

refactor: replace private access hacks with accessor pattern#625

Open
zccrs wants to merge 2 commits into
linuxdeepin:masterfrom
zccrs:master
Open

refactor: replace private access hacks with accessor pattern#625
zccrs wants to merge 2 commits into
linuxdeepin:masterfrom
zccrs:master

Conversation

@zccrs
Copy link
Copy Markdown
Member

@zccrs zccrs commented May 25, 2026

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.

Add src/private/dprivateaccessor_p.h with Accessor/AccessorImpl templates and D_DECLARE_PRIVATE_MEMBER, D_DECLARE_PRIVATE_METHOD, D_DECLARE_PRIVATE_CONST_METHOD, D_PRIVATE_MEMBER, D_PRIVATE_CALL macros. All helpers are in global namespace so ADL correctly finds the friend-injected get() function.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @zccrs, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@zccrs zccrs requested a review from Copilot May 25, 2026 05:13
@deepin-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: zccrs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes preprocessor-based private/protected access hacks and replaces them with a template-based private accessor pattern for reaching Qt private members, while also adding new CI workflows to build the project on Deepin (crimson) and Arch Linux.

Changes:

  • Added a new header implementing an explicit-template-instantiation-based private member accessor and convenience macros.
  • Refactored DQMLGlobalObject to access QSGNode private fields via the new accessor macros instead of #define private public.
  • Updated scenegraph rendering logic in dbackdropnode.cpp and introduced new GitHub Actions build workflows for Deepin and Arch Linux.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/util/dprivateaccessor_p.h Adds the template-based private accessor pattern + macros.
src/private/dqmlglobalobject.cpp Replaces #define private public usage with accessor tags/macros for QSGNode internals.
src/private/dbackdropnode.cpp Removes access-hack macros and updates renderer invocation flow.
.github/workflows/dtkdeclarative-deepin-build.yml Adds Deepin (crimson) container build workflow that builds dependencies from source and produces .deb artifacts.
.github/workflows/dtkdeclarative-archlinux-build.yml Adds Arch Linux container build workflow producing install artifacts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/util/dprivateaccessor_p.h
Comment thread src/util/dprivateaccessor_p.h
Comment thread src/util/dprivateaccessor_p.h
Comment thread .github/workflows/dtkdeclarative-deepin-build.yml
Comment thread .github/workflows/dtkdeclarative-deepin-build.yml
Comment thread .github/workflows/dtkdeclarative-archlinux-build.yml
@zccrs zccrs force-pushed the master branch 6 times, most recently from 827b521 to 5579d87 Compare May 26, 2026 06:18
zccrs added 2 commits May 26, 2026 18:35
Add CI workflows to verify the project builds correctly on both Arch Linux
(latest) and Deepin crimson. This helps catch any platform-specific
compilation issues introduced by the accessor pattern refactor.
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.
@deepin-ci-robot
Copy link
Copy Markdown
Contributor

deepin pr auto review

这份代码变更主要做了两件事:

  1. 新增了两个 GitHub Actions CI 工作流:分别用于在 Arch Linux 和 Deepin crimson 环境下构建 dtkdeclarative
  2. 重构了访问 Qt 私有/受保护成员的方式:使用 C++ 显式模板实例化技术替代了极具争议的 #define private public 宏,并适配了 Qt 6 中 QSGRenderer 的新接口。

整体来看,代码质量有了显著提升,特别是摒弃了破坏 ODR 和导致未定义行为的宏。以下是针对语法逻辑、代码质量、代码性能和代码安全方面的详细审查与改进建议:


一、 CI/CD 工作流审查

1. Arch Linux 工作流 (dtkdeclarative-archlinux-build.yml)

代码质量与逻辑:

  • Checkout 时机不合理actions/checkout@v4 被放在了安装大量系统依赖之后。这不仅意味着如果代码拉取失败,仍会浪费大量时间安装依赖;更严重的是,如果 debian/control 或项目中的构建脚本在后续步骤被需要,当前步骤无法提前使用。建议将 actions/checkout 移至 Steps 的最前面。
  • 工作流触发条件过于宽泛on: push:on: pull_request: 会监听所有分支的所有推送和 PR。建议限制监听的分支(如 mainmasterdevelop),以节省 CI 资源。

代码性能:

  • 依赖缓存缺失:Arch Linux 的 pacman 没有开启缓存。每次 CI 运行都要重新下载几百兆甚至上 GB 的依赖包。建议使用 actions/cache/var/cache/pacman/pkg 进行缓存。

代码安全:

  • 缺少完整性校验:虽然 pacman-key --init 初始化了密钥环,但在容器环境中,如果镜像源被篡改,仍存在供应链攻击风险。建议在系统更新时加入 pacman -Syu --noconfirm --noprogressbar --needed 并确保密钥环包先更新:pacman -Sy --noconfirm archlinux-keyring && pacman -Su --noconfirm

2. Deepin 工作流 (dtkdeclarative-deepin-build.yml)

代码质量与逻辑:

  • Checkout 时机同上:建议移到最前。
  • Git 依赖缺乏版本锁定git clone --depth=1 https://github.com/linuxdeepin/dtkcommon.git 等步骤总是拉取最新的 master 分支。这会导致 CI 具有不可重现性,如果上游仓库引入破坏性更新,CI 会莫名失败。建议使用特定的 commit hash 或 tag 进行拉取。

代码性能:

  • 未复用构建缓存:每次都在 /tmp 下重新克隆和编译 dtkcommon、dtklog 等依赖,非常耗时。可以考虑使用 GitHub Actions 的缓存机制,将编译好的 .deb 文件按依赖仓库的 commit hash 进行缓存。

代码安全:

  • apt 源强制信任deb [trusted=yes] ... 跳过了 GPG 签名验证,存在中间人攻击风险。如果是在内部 CI,风险可控,但最好加上注释说明原因。

二、 C++ 核心代码审查

1. 私有访问器工具 (dprivateaccessor_p.h)

语法逻辑与代码质量(极高评价):
利用 C++ 标准 [temp.explicit]/12 的漏洞(显式实例化不受访问控制限制)来获取私有成员指针,是非常优雅且符合标准的做法,彻底消除了 #define private public 带来的 ODR 违背和 UB 风险。注释也非常清晰。

代码安全与健壮性(改进建议):

  • 宏展开的命名冲突D_DECLARE_PRIVATE_MEMBER 等宏会在全局作用域生成 struct TagName。如果不同 .cpp 文件使用了相同的 TagName(例如都叫 Tag_d),在链接时可能会引发 ODR 冲突或符号重定义。建议在注释中强调 TagName 必须具备全局唯一性(目前的代码中 QSGNode_m_subtreeRenderableCount_tag 命名规范很好,但需保持)。
  • QT_WARNING_PUSH 的通用性:使用了 QT_WARNING_PUSH 等 Qt 宏,这要求该头文件必须包含 <QtCore/qglobal.h> 或类似前置依赖。原代码包含的是 <QtCore/qcompilerdetection.h>,虽然部分 Qt 版本中它也定义了 QT_WARNING_PUSH,但为了安全起见,建议包含 <QtCore/qglobal.h>
  • D_PRIVATE_CALL 的参数传递((obj).*dtk_private_detail::access(tag))(__VA_ARGS__) 中,如果 __VA_ARGS__ 为空,某些编译器可能会将 () 误解析或产生警告。不过在 C++11 及以上的可变参数宏中,这通常是合法的,保持现状即可。

2. 业务逻辑修改 (dbackdropnode.cpp & dqmlglobalobject.cpp)

语法逻辑:

  • 私有成员的访问替换非常准确,D_PRIVATE_MEMBER(*rhi(), QRhi_d_tag{}) 语法正确,解引用和成员指针访问结合完美。
  • dqmlglobalobject.cpp 中的 D_PRIVATE_MEMBER(*node, QSGNode_m_subtreeRenderableCount_tag{}) 返回引用,与原 return node->m_subtreeRenderableCount; 语义完全一致。

代码质量与安全(重要改进点):

  • QRhi_d_tag 的条件编译缺陷

    #ifndef QT_NO_OPENGL
    D_DECLARE_PRIVATE_MEMBER(QRhi_d_tag, QRhi, d, QRhiImplementation*);
    #endif

    这里的 #ifndef QT_NO_OPENGL 逻辑可能不正确QRhi::d 指针是 QRhi 的核心实现(Pimpl 指针),无论底层是 OpenGL、Vulkan 还是 Metal,它都存在。将其限制在 QT_NO_OPENGL 未定义时编译,意味着如果 Qt 编译时禁用了 OpenGL 但启用了 Vulkan,此代码将编译失败。建议移除 #ifndef QT_NO_OPENGL 限制,或者改为更通用的 Qt Rhi 检查宏。

  • Qt 6 API 适配的健壮性

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

    这里从直接修改私有变量+调用私有方法,改为了调用 Qt 6 新增的 prepareSceneInline()renderSceneInline()。逻辑上更安全,但极度依赖 Qt 版本。请确保 CI 和构建系统(CMake)中严格检查了 Qt 版本(Qt6Widgets 且至少是某个特定补丁版本),否则在较旧的 Qt 6 版本上编译会报错(因为这些 inline 函数可能是在较新的 Qt 6 小版本中引入的)。


三、 改进后的代码片段建议

1. CI 工作流优化 (以 Arch 为例,Deepin 类似)

on:
  push:
    branches: [ main, master, develop ] # 限制分支,提升性能
  pull_request:
    branches: [ main, master ]

jobs:
  container:
    runs-on: ubuntu-latest
    container: archlinux:latest
    steps:
      - uses: actions/checkout@v4 # 移到最前面
        with:
          fetch-depth: 0

      - name: Cache pacman packages # 增加缓存,提升性能
        uses: actions/cache@v4
        with:
          path: /var/cache/pacman/pkg
          key: ${{ runner.os }}-arch-pacman-${{ hashFiles('**/some-lock-file-or-date') }}
          restore-keys: |
            ${{ runner.os }}-arch-pacman-

      - name: Initialize pacman and system update
        run: |
          pacman-key --init
          # 安全性提升:优先更新密钥环
          pacman -Sy --noconfirm archlinux-keyring
          pacman -Su --noconfirm --noprogressbar
# ... 以下省略 ...

2. C++ 头文件与条件编译修正

dprivateaccessor_p.h:

// 建议将 <QtCore/qcompilerdetection.h> 替换为更稳妥的 qglobal.h
#include <QtCore/qglobal.h> 
// ... 其余代码不变 ...

dbackdropnode.cpp:

// 移除不准确的 QT_NO_OPENGL 限制,QRhi::d 在所有 Rhi 后端都存在
+D_DECLARE_PRIVATE_MEMBER(QRhi_d_tag, QRhi, d, QRhiImplementation*);

 DQUICK_BEGIN_NAMESPACE
// ...

总结

此次提交重构了关键的底层访问机制,从“黑魔法”(宏替换)走向了“白魔法”(模板实例化漏洞),是极其值得肯定的高质量改动。CI 的加入也为项目的持续集成打下了基础。主要需要关注的是 CI 流程的性能优化与健壮性,以及 C++ 层面针对 Qt Rhi 条件编译的准确性修正。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants