如何记录与 Q_PROPERTY 同名的访问器函数?

How do I document an accessor function with the same name as a Q_PROPERTY?

TL;DR: 如何为与 Q_PROPERTY 声明的 属性 同名的访问器生成 doxygen 文档?


Qt 的 property system 使得在给定属性上使用 Qt 的元对象系统成为可能:

// example class and documentation
class Widget : public QObject {
  Q_OBJECT
  Q_PROPERTY(int size READ size WRITE setSize NOTIFY sizeChanged)

public:
  Widget(QObject * parent = nullptr) : QObject(parent){}
  int size() const;

public slots:
  void setSize(int new_size);

signals:
  void sizeChanged(int); //!< signals a size change

private:
  int m_size = 0; //!< the Widget's size, see #size.
};

如果现在在实现中使用 doxygen

//! @property size is the size of our widget

//! @brief Set the widget's size to @a new_size.
void Widget::setSize(int new_size) { 
  if(new_size != m_size) {
    m_size = new_size; 
    emit sizeChanged(m_size);
  }
}

//! @brief Returns the widget's size.
int Widget::size() const {
  return m_size;
}

只有 setSize 的文档生成正确。 size() 的文档被误认为是 属性 的 文档。上面的代码相当于 if

//! @property size
//! @brief Returns the widget's size.
int Widget::size() const {
  return m_size;
}

被使用了。 @fn Widget::size()const 和任何其他 doxygen 特殊命令似乎都无济于事:size() 生成的文档保持为空并最终出现在 size (属性) 文档中。

这是一个错误,还是我遗漏了什么?

这是一个 known bug 或者更确切地说是未实现的功能。从今天开始,如果 属性 和 getter 具有相同的名称,则无法记录它们。 getter 的文档将始终出现在 属性 的文档中。

原因是 doxygenfindmember 实施。如果您使用 doxygen -d findmembers,您可以看到 size(属性)和 size()(函数)"match":

findMemberDocumentation(): root->type=`int' root->inside=`' root->name=`Widget::size' root->args=`() const ' section=6000000 root->spec=0 root->mGrpId=-1
findMember(root=0x197efe0,funcDecl=`int Widget::size() const ',related=`',overload=0,isFunc=1 mGrpId=-1 tArgList=(nil) (#=0) spec=0 lang=200
findMember() Parse results:
  namespaceName=`'
  className=`Widget`
  funcType=`int'
  funcSpec=`'
  funcName=`size'
  funcArgs=`() const'
  funcTempList=`'
  funcDecl=`int Widget::size'
  related=`'
  exceptions=`'
  isRelated=0
  isMemberOf=0
  isFriend=0
  isFunc=1

1. funcName=`size'
2. member name exists (2 members with this name)
3. member definition found, scope needed=`Widget' scope=`Widget' args=`' fileName=/tmp/test/example.cpp
4. class definition Widget found
5. matching `'`() const' className=Widget namespaceName=
6. match results of matchArguments2 = 1

您甚至可以使用另一个非const 变体int size() 重现它。您最终会得到三个同名的成员。 Doxygen 目前无法处理具有相同名称的属性和函数,并且在这种情况下不会记录 getters。

如果您不需要 属性 文档,您可以在 Doxyfile 中禁用 Q_PROPERTY 宏(如 documented):

ENABLE_PREPROCESSING  = YES
MACRO_EXPANSION       = YES
PREDEFINED            = Q_PROPERTY(x)= 

这样词法分析器就不会扫描 Q_PROPERTY

如约而至: 与原代码不同的是文档没有放在实现文件中,而是放在包含文件中。

包含文件:

// example class and documentation
class Widget : public QObject {
  Q_OBJECT
  //! size is the size of our widget
  Q_PROPERTY(int size READ size WRITE setSize NOTIFY sizeChanged)

public:
  //! Set the widget's size to @a new_size.
  Widget(QObject * parent = nullptr) : QObject(parent){}
  //! Returns the widget's size.
  int size() const;

public slots:
  void setSize(int new_size);

signals:
  void sizeChanged(int); //!< signals a size change

private:
  int m_size = 0; //!< the Widget's size, see #size.
};

实现文件:

void Widget::setSize(int new_size) {
  if(new_size != m_size) {
    m_size = new_size;
    emit sizeChanged(m_size);
  }
}

int Widget::size() const {
  return m_size;
}

doxygen 配置文件的差异(Doxyfile,可能有几个设置为 YES):

EXTRACT_ALL            = YES
EXTRACT_PRIVATE        = YES
EXTRACT_PACKAGE        = YES
EXTRACT_STATIC         = YES
EXTRACT_LOCAL_METHODS  = YES
EXTRACT_ANON_NSPACES   = YES