GNOME Bugzilla – Bug 494521
PATCH INCLUDED : Doxygen unable to process files generated by EDoc++
Last modified: 2012-11-18 11:13:10 UTC
The above summary is not as concise as it could be. This is because in the one patch I have included fixes for a few smaller problems which is easier to attach to a single report than submitting a report for each problem and breaking the patch up. =============================================== * Function prototypes fail to match with template types In the example below Doxygen is unable to determine that the "\fn ..." identifies the provided function prototype declared previously. template <typename T, typename U = float> class Test {}; void ExatcMatchWithDefaults(Test<int> one); /** \fn ExatcMatchWithDefaults(Test<int, float>) * * \brief ExatcMatchWithDefaults Brief. * * ExatcMatchWithDefaults Detailed. */ =============================================== * Order of processing for files can not be easily modified by user If the user wishes to process source files in a particular order there is no way to achieve it except by renaming the files as doxygen currently processes in alphabetical order. This was not a problem in earlier versions but now when doxygen encounters multiple document blocks for a single entity it will append the documentation of the second encountered block after the first. By allowing the user to modify the order of files being processed, the order of the documentation blocks seen can also be controlled. Example: Create three files: --- file.h --- void FirstBriefDualDetail(); --- filea.cpp --- /** \fn FirstBriefDualDetail() * * \brief FirstBriefDualDetail brief a. * * FirstBriefDualDetail detailed a. */ --- fileb.cpp --- /** \fn FirstBriefDualDetail() * * \brief FirstBriefDualDetail brief b. * * FirstBriefDualDetail detailed b. */ Now create two doxygen configuration files setting the input field as shown below --- ab.dox --- INPUT = file.h filea.cpp fileb.cpp --- ba.dox --- INPUT = file.h fileb.cpp filea.cpp If you run doxygen with ab.dox and then again with ba.dox the documentation in the two is the same. This gives the user less control over thedocumentation that is generated (and in the case of EDoc++ causesissues with the order of information presented). =============================================== * Patch also includes a few lines that provide DESTDIR installs which are helpful for generating packages. I.e. ./configure --prefix=/usr/local && make && make DESTDIR=$HOME/staging will build for /usr/local but install to $HOME/staging =============================================== =============================================== Patch below was generated using svn head revision: 593 using: svn diff >../edoc.patch This should produce a unified diff and there are no new files. ---- Snip: edoc.patch ---- Index: configure =================================================================== --- configure (revision 593) +++ configure (working copy) @@ -435,6 +435,7 @@ configPWD=`pwd` cat > .makeconfig <<EOF +DESTDIR = DOXYGEN = $configPWD TMAKEPATH = $configPWD/tmake/lib/$f_platform ENV = env TMAKEPATH=\$(TMAKEPATH) @@ -444,7 +445,7 @@ RM = rm -f CP = cp VERSION = `cat VERSION` -INSTALL = $f_prefix +INSTALL = \$(DESTDIR)$f_prefix INSTTOOL = $f_insttool DOXYDOCS = .. DOCDIR = $f_docdir Index: src/util.cpp =================================================================== --- src/util.cpp (revision 593) +++ src/util.cpp (working copy) @@ -27,6 +27,7 @@ #include <qdir.h> #include <qdatetime.h> #include <qcache.h> +#include <qvaluelist.h> #include "util.h" #include "message.h" @@ -3183,6 +3184,156 @@ return extractCanonicalType(d,fs,type); } +static bool BreakUpType(QString type, QString& prefix, QValueList<QString>& params, QString& suffix) +{ + //printf("Breaking up type: %s\n", type.data()); + params.clear(); + + size_t depth = 0; + size_t start_param = -1; + for (size_t i = 0; i < type.length(); i++) + { + if (type[i] == '<') + { + //printf("< index: %d, depth: %d\n", i, depth); + depth++; + if (depth == 1) + { + // Then we have a prefix. + prefix = type.left(i).stripWhiteSpace(); + //printf("Prefix: %s, index: %d\n", prefix.data(), i); + start_param = i + 1; + } + } + else if (type[i] == '>') + { + //printf("> index: %d, depth: %d\n", i, depth); + depth--; + if (depth == 0) + { + if (start_param != (size_t)-1) + { + params.append(type.mid(start_param, i - start_param).stripWhiteSpace()); + //printf("Added param: %s, index: %d, start_param: %d\n", params.last().data(), i, start_param); + } + // Then we have finished parsing template params, lets obtain the suffix and return. + suffix = type.mid(i + 1).stripWhiteSpace(); + //printf("Suffix: %s, index: %d\n", suffix.data(), i); + return true; + } + } + else if (type[i] == ',') + { + // If inside top level template then we have a new parameter. + if (depth == 1) + { + params.append(type.mid(start_param, i - start_param).stripWhiteSpace()); + //printf("Added param: %s, index: %d, start_param: %d\n", params.last().data(), i, start_param); + start_param = i + 1; + } + } + } + + prefix = type.stripWhiteSpace(); + //printf("No template info found. Returning prefix: %s\n", prefix.data()); + return false; +} + +// This function will return true if the two types are considered the same. +// It differs from comparison of canonical names in that it breaks the +// canonical names into various parts for template types and will match types +// where default template parameters have been specified explicitly with those +// that have not been. +static bool sameType(const QString& left, const QString& right) +{ + QString left_prefix; + QString left_suffix; + QValueList<QString> left_params; + + QString right_prefix; + QString right_suffix; + QValueList<QString> right_params; + + BreakUpType(left, left_prefix, left_params, left_suffix); + BreakUpType(right, right_prefix, right_params, right_suffix); + + // @@@It seems doxygen has trouble determining the namespace of + // items inside template parameters. In order to get some sembelance of + // correct matching i will use the shortest of the two strings as a + // reference, and if the longer ends with the same contents then there is + // a GOOD chance that it is a match. This will fail if for example in two + // different namespaces there is a class defined called Blah. This method + // may be unable to determine the difference between the two types of Blah, + // but only when used in an overloaded function prototype. + + + + // Note: We will consider reference and value types as the same too. + // This is due to the way EDoc++ emits funciton names. If the compiler has + // decided that the function can have the value passed as a const reference + // then EDoc++ will not know that the user requested a pass by value, but + // will just see a pass by reference instead. In the end by considering + // reference types the same as value types for this purpose there is little + // difference. + + // So first we remove trailing " &" from the prefix. + if (left_prefix.length() >= 1 && left_prefix.mid(left_prefix.length() - 1) == "&") + { + left_prefix = left_prefix.mid(0, left_prefix.length() - 1).stripWhiteSpace(); + } + if (right_prefix.length() >= 1 && right_prefix.mid(right_prefix.length() - 1) == "&") + { + right_prefix = right_prefix.mid(0, right_prefix.length() - 1).stripWhiteSpace(); + } + + //printf("Obtaining min size of prefixes.\n"); + size_t min = left_prefix.length(); + min = (right_prefix.length() < min ? right_prefix.length() : min); + + // Check for zero length prefixes. If one is 0 and the other is not then + // assume a failed match in case we are comparing a type ending in & with + // a compound type. + if (!min && left_prefix.length() != right_prefix.length()) + { + return false; + } + + //printf("Finally getting proper values.\n"); + left_prefix = left_prefix.mid(left_prefix.length() - min).stripWhiteSpace(); + right_prefix = right_prefix.mid(right_prefix.length() - min).stripWhiteSpace(); + + // If the prefixes differ then the types do not match. + if (left_prefix != right_prefix) + { + return false; + } + + + QValueList<QString>::Iterator lt = left_params.begin(); + QValueList<QString>::Iterator rt = right_params.begin(); + for (; lt != left_params.end() && rt != right_params.end(); lt++, rt++) + { + // if the template parameter types are not considered the same then there is a failed match. + if (!sameType((*lt), QString(*rt))) + { + return false; + } + } + + // If the suffix types differ then the types do not match. + if (right_suffix != left_suffix) + { + if (!sameType(left_suffix, right_suffix)) + { + return false; + } + } + + // otherwise the two types are considered the same. + return true; +} + + static bool matchArgument2( Definition *srcScope,FileDef *srcFileScope,Argument *srcA, Definition *dstScope,FileDef *dstFileScope,Argument *dstA @@ -3229,7 +3380,10 @@ dstA->canType = extractCanonicalArgType(dstScope,dstFileScope,dstA); } - if (srcA->canType==dstA->canType) + // Changed from comparison of canonical type names to a more + // complex comparison of types to allow template types with specified default + // params to match "more correctly" + if (sameType(srcA->canType, dstA->canType)) { MATCH return TRUE; Index: src/doxygen.cpp =================================================================== --- src/doxygen.cpp (revision 593) +++ src/doxygen.cpp (working copy) @@ -6899,28 +6899,26 @@ static void generateFileSources() { if (documentedHtmlFiles==0) return; - if (Doxygen::inputNameList->count()>0) + // Ensure that sources are parsed in the order they are specified in the + // configuration file and not alphabetical order as was done in the past. + for (size_t i = 0; i < Doxygen::inputNameList->count(); i++) { - FileNameListIterator fnli(*Doxygen::inputNameList); - FileName *fn; - for (;(fn=fnli.current());++fnli) + FileName *fn = Doxygen::inputNameList->at(i); + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) { - FileNameIterator fni(*fn); - FileDef *fd; - for (;(fd=fni.current());++fni) + if (fd->generateSourceFile()) // sources need to be shown in the output { - if (fd->generateSourceFile()) // sources need to be shown in the output - { - msg("Generating code for file %s...\n",fd->docName().data()); - fd->writeSource(*outputList); - } - else if (!fd->isReference() && Doxygen::parseSourcesNeeded) - // we needed to parse the sources even if we do not show them - { - msg("Parsing code for file %s...\n",fd->docName().data()); - fd->parseSource(); - } + msg("Generating code for file %s...\n",fd->docName().data()); + fd->writeSource(*outputList); } + else if (!fd->isReference() && Doxygen::parseSourcesNeeded) + // we needed to parse the sources even if we do not show them + { + msg("Parsing code for file %s...\n",fd->docName().data()); + fd->parseSource(); + } } } } @@ -8391,9 +8389,11 @@ } } - QCString *s=inputFiles.first(); - while (s) + // Process files in order specified in the configuration + // file, not just based on the iterator order. + for (size_t i = 0; i < inputFiles.count(); i++) { + QCString* s = inputFiles.at(i); QCString fileName=*s; QCString extension; int ei = fileName.findRev('.'); @@ -8438,8 +8438,6 @@ FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig); ASSERT(fd!=0); root->createNavigationIndex(rootNav,g_storage,fd); - - s=inputFiles.next(); } } @@ -8598,7 +8596,7 @@ { fn = new FileName(fi.absFilePath(),name); fn->append(fd); - if (fnList) fnList->inSort(fn); + if (fnList) fnList->append(fn); fnDict->insert(name,fn); } } ---- Snip: edoc.patch ----
*** This bug has been marked as a duplicate of 494519 ***