diff options
author | Vladimír Vondruš <mosra@centrum.cz> | 2019-01-01 17:01:22 (GMT) |
---|---|---|
committer | Vladimír Vondruš <mosra@centrum.cz> | 2019-01-03 10:32:17 (GMT) |
commit | d18b3eaf3486e224fa9de7e77b536883952b40b9 (patch) | |
tree | 045620bc9c59d68e2fb32bf035f0147e164a360b | |
parent | 3b2198babbaf8edafe03e5298e7c194763a1f9fa (diff) | |
download | Doxygen-d18b3eaf3486e224fa9de7e77b536883952b40b9.zip Doxygen-d18b3eaf3486e224fa9de7e77b536883952b40b9.tar.gz Doxygen-d18b3eaf3486e224fa9de7e77b536883952b40b9.tar.bz2 |
Implement a new EXTRACT_PRIVATE_VIRTUAL option.
The classic article about virtuality from Herb Sutter [1] suggests that
virtual functions are always private and public class interface is never
virtual. Until now, it was not really possible to document these
functions in Doxygen:
* Enabling EXTRACT_PRIVATE would show all internals, not just virtual
functions, which is not wanted.
* Enabling HIDE_UNDOC_MEMBERS and HIDE_UNDOC_CLASSES would effectively
disable warnings about *all* undocumented members, which is not wanted.
The usual workaround was to put the members into protected scope just
for Doxygen:
#ifdef DOXYGEN_GENERATING_OUTPUT
protected:
#else
private:
#endif
/** @brief Documented private virtual function */
virtual doStuff();
The new EXTRACT_PRIVATE_VIRTUAL option makes these visible (and able to
be linked to), but shows them *only* if they are documented.
[1] http://www.gotw.ca/publications/mill18.htm
-rw-r--r-- | src/classdef.cpp | 4 | ||||
-rw-r--r-- | src/config.xml | 8 | ||||
-rw-r--r-- | src/memberdef.cpp | 17 | ||||
-rw-r--r-- | testing/081/class_interface.xml | 110 | ||||
-rw-r--r-- | testing/081_extract_private_virtual.cpp | 35 |
5 files changed, 169 insertions, 5 deletions
diff --git a/src/classdef.cpp b/src/classdef.cpp index e9d39d5..f275d1d 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -620,6 +620,10 @@ void ClassDef::internalInsertMember(MemberDef *md, { addMemberToList(MemberListType_relatedMembers,md,FALSE); } + else if (md->isFunction() && md->protection()==Private && md->virtualness()!=Normal && Config_getBool(EXTRACT_PRIVATE_VIRTUAL)) + { + addMemberToList(MemberListType_functionMembers,md,FALSE); + } else { switch (md->memberType()) diff --git a/src/config.xml b/src/config.xml index fdc562d..8bf45bb 100644 --- a/src/config.xml +++ b/src/config.xml @@ -838,6 +838,14 @@ Go to the <a href="commands.html">next</a> section or return to the ]]> </docs> </option> + <option type='bool' id='EXTRACT_PRIVATE_VIRTUAL' defval='0'> + <docs> +<![CDATA[ + If the \c EXTRACT_PRIVATE_VIRTUAL tag is set to \c YES, documented private + virtual methods of a class will be included in the documentation. +]]> + </docs> + </option> <option type='bool' id='EXTRACT_PACKAGE' defval='0'> <docs> <![CDATA[ diff --git a/src/memberdef.cpp b/src/memberdef.cpp index a2fcf69..58a2b12 100644 --- a/src/memberdef.cpp +++ b/src/memberdef.cpp @@ -1080,6 +1080,7 @@ QCString MemberDef::anchor() const void MemberDef::_computeLinkableInProject() { static bool extractStatic = Config_getBool(EXTRACT_STATIC); + static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIVATE_VIRTUAL); m_isLinkableCached = 2; // linkable //printf("MemberDef::isLinkableInProject(name=%s)\n",name().data()); if (isHidden()) @@ -1133,7 +1134,7 @@ void MemberDef::_computeLinkableInProject() m_isLinkableCached = 1; // in file (and not in namespace) but file not linkable return; } - if (!protectionLevelVisible(m_impl->prot) && m_impl->mtype!=MemberType_Friend) + if ((!protectionLevelVisible(m_impl->prot) && m_impl->mtype!=MemberType_Friend) && !(m_impl->prot==Private && m_impl->virt!=Normal && extractPrivateVirtual)) { //printf("private and invisible!\n"); m_isLinkableCached = 1; // hidden due to protection @@ -1315,6 +1316,7 @@ ClassDef *MemberDef::getClassDefOfAnonymousType() bool MemberDef::isBriefSectionVisible() const { static bool extractStatic = Config_getBool(EXTRACT_STATIC); + static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIVATE_VIRTUAL); static bool hideUndocMembers = Config_getBool(HIDE_UNDOC_MEMBERS); static bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC); static bool repeatBrief = Config_getBool(REPEAT_BRIEF); @@ -1365,9 +1367,12 @@ bool MemberDef::isBriefSectionVisible() const ); // only include members that are non-private unless EXTRACT_PRIVATE is - // set to YES or the member is part of a group + // set to YES or the member is part of a group. And as a special case, + // private *documented* virtual members are shown if EXTRACT_PRIVATE_VIRTUAL + // is set to YES bool visibleIfPrivate = (protectionLevelVisible(protection()) || - m_impl->mtype==MemberType_Friend + m_impl->mtype==MemberType_Friend || + (m_impl->prot==Private && m_impl->virt!=Normal && extractPrivateVirtual && hasDocs) ); // hide member if it overrides a member in a superclass and has no @@ -1639,11 +1644,12 @@ void MemberDef::writeDeclaration(OutputList &ol, if (!name().isEmpty() && name().at(0)!='@') // hide anonymous stuff { static bool extractPrivate = Config_getBool(EXTRACT_PRIVATE); + static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIVATE_VIRTUAL); static bool extractStatic = Config_getBool(EXTRACT_STATIC); //printf("Member name=`%s gd=%p md->groupDef=%p inGroup=%d isLinkable()=%d hasDocumentation=%d\n",name().data(),gd,getGroupDef(),inGroup,isLinkable(),hasDocumentation()); if (!(name().isEmpty() || name().at(0)=='@') && // name valid (hasDocumentation() || isReference()) && // has docs - !(m_impl->prot==Private && !extractPrivate && m_impl->mtype!=MemberType_Friend) && // hidden due to protection + !(m_impl->prot==Private && !extractPrivate && (m_impl->virt==Normal || !extractPrivateVirtual) && m_impl->mtype!=MemberType_Friend) && // hidden due to protection !(isStatic() && m_impl->classDef==0 && !extractStatic) // hidden due to static-ness ) { @@ -1896,6 +1902,7 @@ bool MemberDef::isDetailedSectionLinkable() const static bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC); static bool hideUndocMembers = Config_getBool(HIDE_UNDOC_MEMBERS); static bool extractStatic = Config_getBool(EXTRACT_STATIC); + static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIVATE_VIRTUAL); // the member has details documentation for any of the following reasons bool docFilter = @@ -1933,7 +1940,7 @@ bool MemberDef::isDetailedSectionLinkable() const // only include members that are non-private unless EXTRACT_PRIVATE is // set to YES or the member is part of a group - bool privateFilter = protectionLevelVisible(protection()) || m_impl->mtype==MemberType_Friend; + bool privateFilter = protectionLevelVisible(protection()) || m_impl->mtype==MemberType_Friend || (m_impl->prot==Private && m_impl->virt!=Normal && extractPrivateVirtual); // member is part of an anonymous scope that is the type of // another member in the list. diff --git a/testing/081/class_interface.xml b/testing/081/class_interface.xml new file mode 100644 index 0000000..2385b86 --- /dev/null +++ b/testing/081/class_interface.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version=""> + <compounddef id="class_interface" kind="class" language="C++" prot="public" abstract="yes"> + <compoundname>Interface</compoundname> + <sectiondef kind="public-func"> + <memberdef kind="function" id="class_interface_1ab58d3008a7001cbb47f2fa5a5a1aeefa" prot="public" static="no" const="no" explicit="no" inline="no" virt="non-virtual"> + <type>void</type> + <definition>void Interface::load</definition> + <argsstring>()</argsstring> + <name>load</name> + <briefdescription> + <para>Load things. </para> + </briefdescription> + <detaileddescription> + <para>Calls <ref refid="class_interface_1a328e0a16ccee5d796ca93801a055d27d" kindref="member">doLoad()</ref>. </para> + </detaileddescription> + <inbodydescription> + </inbodydescription> + <location file="081_extract_private_virtual.cpp" line="13" column="1"/> + </memberdef> + </sectiondef> + <sectiondef kind="private-func"> + <memberdef kind="function" id="class_interface_1a328e0a16ccee5d796ca93801a055d27d" prot="private" static="no" const="no" explicit="no" inline="no" virt="pure-virtual"> + <type>void</type> + <definition>virtual void Interface::doLoad</definition> + <argsstring>()=0</argsstring> + <name>doLoad</name> + <briefdescription> + <para>Pure virtual implementation for <ref refid="class_interface_1ab58d3008a7001cbb47f2fa5a5a1aeefa" kindref="member">load()</ref> </para> + </briefdescription> + <detaileddescription> + <para>Details. </para> + </detaileddescription> + <inbodydescription> + </inbodydescription> + <location file="081_extract_private_virtual.cpp" line="21" column="1"/> + </memberdef> + <memberdef kind="function" id="class_interface_1ad13fffb1181ab0da1f8fbb586eff9afe" prot="private" static="no" const="no" explicit="no" inline="no" virt="virtual"> + <type>void</type> + <definition>virtual void Interface::doOtherStuff</definition> + <argsstring>()</argsstring> + <name>doOtherStuff</name> + <briefdescription> + <para>Non-pure virtual function. </para> + </briefdescription> + <detaileddescription> + <para>Details. </para> + </detaileddescription> + <inbodydescription> + </inbodydescription> + <location file="081_extract_private_virtual.cpp" line="28" column="1"/> + </memberdef> + <memberdef kind="function" id="class_interface_1a46062977049a7c2c2c141e4487e954b8" prot="private" static="no" const="no" explicit="no" inline="no" virt="virtual"> + <type>void</type> + <definition>virtual void Interface::doSomethingUndocumented</definition> + <argsstring>()</argsstring> + <name>doSomethingUndocumented</name> + <briefdescription> + </briefdescription> + <detaileddescription> + </detaileddescription> + <inbodydescription> + </inbodydescription> + <location file="081_extract_private_virtual.cpp" line="31" column="1"/> + </memberdef> + <memberdef kind="function" id="class_interface_1a108dce1debd0596b57e7985bbb0f63a1" prot="private" static="no" const="no" explicit="no" inline="no" virt="non-virtual"> + <type>void</type> + <definition>void Interface::someUtility</definition> + <argsstring>()</argsstring> + <name>someUtility</name> + <briefdescription> + <para>A non-virtual private function, not extracted. </para> + </briefdescription> + <detaileddescription> + </detaileddescription> + <inbodydescription> + </inbodydescription> + <location file="081_extract_private_virtual.cpp" line="34" column="1"/> + </memberdef> + </sectiondef> + <briefdescription> + <para>An interface. </para> + </briefdescription> + <detaileddescription> + </detaileddescription> + <location file="081_extract_private_virtual.cpp" line="6" column="1" bodyfile="081_extract_private_virtual.cpp" bodystart="6" bodyend="35"/> + <listofallmembers> + <member refid="class_interface_1a328e0a16ccee5d796ca93801a055d27d" prot="private" virt="pure-virtual"> + <scope>Interface</scope> + <name>doLoad</name> + </member> + <member refid="class_interface_1ad13fffb1181ab0da1f8fbb586eff9afe" prot="private" virt="virtual"> + <scope>Interface</scope> + <name>doOtherStuff</name> + </member> + <member refid="class_interface_1a46062977049a7c2c2c141e4487e954b8" prot="private" virt="virtual"> + <scope>Interface</scope> + <name>doSomethingUndocumented</name> + </member> + <member refid="class_interface_1ab58d3008a7001cbb47f2fa5a5a1aeefa" prot="public" virt="non-virtual"> + <scope>Interface</scope> + <name>load</name> + </member> + <member refid="class_interface_1a108dce1debd0596b57e7985bbb0f63a1" prot="private" virt="non-virtual"> + <scope>Interface</scope> + <name>someUtility</name> + </member> + </listofallmembers> + </compounddef> +</doxygen> diff --git a/testing/081_extract_private_virtual.cpp b/testing/081_extract_private_virtual.cpp new file mode 100644 index 0000000..ce4ed30 --- /dev/null +++ b/testing/081_extract_private_virtual.cpp @@ -0,0 +1,35 @@ +// objective: allow linking to private virtual functions +// check: class_interface.xml +// config: EXTRACT_PRIVATE_VIRTUAL = YES + +/** @brief An interface */ +class Interface { + public: + /** + * @brief Load things. + * + * Calls @ref doLoad(). + */ + void load(); + + private: + /** + * @brief Pure virtual implementation for @ref load() + * + * Details. + */ + virtual void doLoad() = 0; + + /** + * @brief Non-pure virtual function + * + * Details. + */ + virtual void doOtherStuff(); + + /* Undocumented, should not appear in the docs */ + virtual void doSomethingUndocumented(); + + /** @brief A non-virtual private function, not extracted */ + void someUtility(); +}; |