External documented functions not found (functions generated by macros).
Describe the bug This is... weird, and I can't figure it out. In Doxygen 1.9.6 everything is parsed correctly. Starting from 1.9.7 (I checked), some functions documented in an external file are not found. Not all of them - just some.
We (ns-3) have some extremely weird code in some points - so bear with us.
In some points we have to generate accessor functions, and we do it using macros, so stuff like ATTRIBUTE_ACCESSOR_DEFINE(Boolean); is expanded in several functions like MakeBooleanAccessor.
These functions can not be documented in the code, because they're generated by the C++ preprocessor, so we have to generate an introspected documentation file, i.e., the Doxygen documentation itself is generated by a script in a different file named introspected-doxygen.h.
So far so good. Until 1.9.6 (included) the documentation was generated flawlessly.
Starting from 1.9.7, Doxygen issues warning about missing documentation for some functions, in particular all the MakeXxxChecker and makeXxxAccessor, even though they're documented.
Expected behavior The same behaviour as 1.9.6 - find them all.
Screenshots No screenshot, as they generate warnings.
To Reproduce
Sorry for the messy sources, I tried to change as little as possible of the original files. Just check the warnings relative to boolean.{cc,h} and string.{cc,h}, the others are there because I didn't touch the introspected file generated by ns-3.
Version MacOS M2, Doxygen 1.10.0, but it happens also with ArchLinux.
Stack trace No crash
Additional context If I can help tracking (or fixing) the problem, I'll be more than happy to help.
I assume you refer to the warnings like:
.../boolean.cc:110: warning: Member MakeBooleanChecker() (function) of namespace ns3 is not documented.
.../boolean.cc:110: warning: Member MakeBooleanChecker() (function) of namespace ns3 is not documented.
.../boolean.h:86: warning: Member MakeBooleanAccessor(T1 a1) (function) of namespace ns3 is not documented.
.../boolean.h:86: warning: Member MakeBooleanAccessor(T1 a1, T2 a2) (function) of namespace ns3 is not documented.
.../string.cc:30: warning: Member MakeStringChecker() (function) of namespace ns3 is not documented.
.../string.h:57: warning: Member MakeStringAccessor(T1 a1) (function) of namespace ns3 is not documented.
.../string.h:57: warning: Member MakeStringAccessor(T1 a1, T2 a2) (function) of namespace ns3 is not documented.
.../string.cc:30: warning: Member MakeStringChecker() (function) of namespace ns3 is not documented.
I looked at the first warning a bit in detail and in the source code of boolean.cc we see here:
ATTRIBUTE_CHECKER_IMPLEMENT_WITH_NAME(Boolean, "bool");
and in the file attribute-helper.h:
/**
* \ingroup attributehelper
*
* Define the \c MaketypeChecker function for class \pname{type}.
*
* \param [in] type The name of the class.
* \param [in] name The string name of the underlying type.
*
* This macro implements the \c MaketypeChecker function
* for class \pname{type}.
*
* Typically invoked in the source file..
*/
#define ATTRIBUTE_CHECKER_IMPLEMENT_WITH_NAME(type, name) \
Ptr<const AttributeChecker> Make##type##Checker() \
{ \
return MakeSimpleAttributeChecker<type##Value, type##Checker>(#type "Value", name); \
}
In the source code this translates (using the debug option preprocessor i.e. doxygen -d preprocessor) into (for all versions):
Ptr<const AttributeChecker> MakeBooleanChecker() { return MakeSimpleAttributeChecker< BooleanValue, BooleanChecker>("Boolean" "Value", "bool" ); };
so it is not documented and I think it was an omission that there was no warning.
Interesting discussion in this might also be #7359.
(Note I don't think the closing ; is necessary and some pedantic setting checkers) might complain about it.
Looks like to be even a bit more complicated as I see now there should be documentation in introspected-doxygen.h as:
/*!
\fn ns3::Ptr<const ns3::AttributeChecker> ns3::MakeBooleanChecker ()
\returns The AttributeChecker.
\see AttributeChecker
*/
Thanks for the quick replies.
Your analysis is correct. It's not documented in the code (because it's a generated function), but the documentation should have been picked from introspected-doxygen.h
The signature of the functions looks right to me, except maybe the missing "ns3" namespace. Note that there are more functions and classes documented there, and these are totally ok.
The only ones that are creating warnings are Make[something]Checker and Make[something]Accessor.
My best (and wild) guess is that the Doxygen preprocessor doesn't add the "ns3" namespace to the classes/functions, and this might create a signature mismatch.
@TommyPec The preprocessor should not add the ns3 namespace. The parser should find the result of preprocessing in the correct namespace (you can see this by running doxygen with the -d preprocessor option).
Note that if I set EXTRACT_ALL to YES the problem disappears, so it looks like a symbol is not documented, that should be documented in order to find the match between declaration and definition. Haven't checked in detail which one.
I've been able to condense the example to this:
/*!
* @defgroup mygrp My Group
* My own group
*/
/*!
\fn ns3::Ptr<const ns3::AttributeChecker> ns3::MakeBooleanChecker()
\returns The AttributeChecker.
\see AttributeChecker
\ingroup mygrp
*/
#include <string>
/**
* Define the \c MaketypeChecker function for class \pname{type}.
*/
#define ATTRIBUTE_CHECKER_IMPLEMENT_WITH_NAME(type, name) \
Ptr<const AttributeChecker> Make##type##Checker() \
{ \
return MakeSimpleAttributeChecker<type##Value, type##Checker>(#type "Value", name); \
}
/**
* Declare the AttributeChecker class \pname{typeChecker}
* and the \c MaketypeChecker function for class \pname{type}.
*
*/
#define ATTRIBUTE_CHECKER_DEFINE(type) \
class type##Checker : public AttributeChecker \
{ \
}; \
Ptr<const AttributeChecker> Make##type##Checker()
/// ns3
namespace ns3
{
/// smart pointer
template <typename T>
class Ptr { };
/// empty class
class Empty { };
/// default deleter
template <typename T>
struct DefaultDeleter { };
/// ref counter
template <typename T, typename PARENT = Empty, typename DELETER = DefaultDeleter<T>>
class SimpleRefCount : public PARENT { };
/// attribute value
class AttributeValue : public SimpleRefCount<AttributeValue> { };
/**
* \brief Represent the type of an attribute
*/
class AttributeChecker : public SimpleRefCount<AttributeChecker> { };
/// make checker
template <typename T, typename BASE>
Ptr<const AttributeChecker> MakeSimpleAttributeChecker(std::string name, std::string underlying) { return Ptr<const AttributeChecker>(); };
// Doxygen for this class is auto-generated by
// utils/print-introspected-doxygen.h
class BooleanValue : public AttributeValue { };
ATTRIBUTE_CHECKER_DEFINE(Boolean);
ATTRIBUTE_CHECKER_IMPLEMENT_WITH_NAME(Boolean, "bool");
} // namespace ns3
If I remove the \ingroup command, the MakeBooleanChecker() is documented, otherwise it is not. Need to dig deeper.
Re the "extra" ';' after the macro invocation: if we don't include it some editors get confused about indentation level, since they see the macro as a function call and unterminated statement. AFAIK extra ';' are just null statements; we haven't seen any linters complain (yet).
@pdbj Some static analyzers give a warning about it (I'm not sure which ones but I think sonarcloud.) Also I think some compilers when using some pedantic mode might complain.
(It is still legal code and it just gives the "null" statement).
Looks like https://github.com/doxygen/doxygen/pull/9952 introduced the problem, in particular the below guard in doxygen.cpp prevents the documentation to be associated with the namespace member.
// If the entry has groups, then restrict the search to members which are
// in one of the groups of the entry.
if (!root->groups.empty() && !isEntryInGroupOfMember(root, md.get()))
{
continue;
}
Need to find out why this was added. @sebhub any info you can add would be welcomed.
@TommyPec Please verify if the referenced commit fixes the problem for you. Do not close the issue, this will be done automatically when the next official release becomes available.
I have no idea of what the commit did. I tried to understand the changes in the code, and they're as obscure (to me) as something written in Malbolge. But I guess it's ok, you can't grasp the internal functions of Doxygen in 2 days while also grading your students.
Anyway, I checked the results.
- The warnings are gone.
- The output is correct (see attached screenshot).
- I'm super happy, and you rock.
@albert-github I have a small update on this, and it seems that there is a further issue (sorry).
We have some macros-of macros, like:
#define ATTRIBUTE_HELPER_HEADER(type) \
ATTRIBUTE_VALUE_DEFINE(type); \
ATTRIBUTE_ACCESSOR_DEFINE(type); \
ATTRIBUTE_CHECKER_DEFINE(type)
We have the following in our configuration:
EXPAND_AS_DEFINED = ATTRIBUTE_ACCESSOR_DEFINE \
ATTRIBUTE_CHECKER_DEFINE \
ATTRIBUTE_CHECKER_IMPLEMENT \
ATTRIBUTE_CHECKER_IMPLEMENT_WITH_NAME \
ATTRIBUTE_CONVERTER_DEFINE \
ATTRIBUTE_HELPER_CPP \
ATTRIBUTE_HELPER_HEADER \
ATTRIBUTE_VALUE_DEFINE \
ATTRIBUTE_VALUE_DEFINE_WITH_NAME \
ATTRIBUTE_VALUE_IMPLEMENT \
ATTRIBUTE_VALUE_IMPLEMENT_WITH_NAME \
NS_UNUSED_GLOBAL
It looks like the macros are not expanded recursively. Shall I open another issue?
It looks like the macros are not expanded recursively. Shall I open another issue?
Yes please open a new issue (with a small example) so this issue can stay to be fort the dedicated fixed issue.
This issue was previously marked 'fixed but not released', which means it should be fixed in doxygen version 1.11.0. Please verify if this is indeed the case. Reopen the issue if you think it is not fixed and please include any additional information that you think can be relevant (preferably in the form of a self-contained example).