diff options
author | Dimitri van Heesch <dimitri@stack.nl> | 2003-08-24 20:42:56 (GMT) |
---|---|---|
committer | Dimitri van Heesch <dimitri@stack.nl> | 2003-08-24 20:42:56 (GMT) |
commit | 5b0de0b4249965d3ae2ca3e67f40ef810e0a9598 (patch) | |
tree | bfd280ef12015bf793b71236c30364c6618cbaf8 /src | |
parent | 8626ab32d671ffcdc75dffce04dd05a671cfb42c (diff) | |
download | Doxygen-5b0de0b4249965d3ae2ca3e67f40ef810e0a9598.zip Doxygen-5b0de0b4249965d3ae2ca3e67f40ef810e0a9598.tar.gz Doxygen-5b0de0b4249965d3ae2ca3e67f40ef810e0a9598.tar.bz2 |
Release-1.3.3-20030824
Diffstat (limited to 'src')
-rw-r--r-- | src/classdef.cpp | 1 | ||||
-rw-r--r-- | src/classlist.cpp | 10 | ||||
-rw-r--r-- | src/classlist.h | 2 | ||||
-rw-r--r-- | src/code.l | 32 | ||||
-rw-r--r-- | src/config.h | 11 | ||||
-rw-r--r-- | src/config.l | 274 | ||||
-rw-r--r-- | src/definition.cpp | 67 | ||||
-rw-r--r-- | src/docparser.cpp | 17 | ||||
-rw-r--r-- | src/doxygen.cpp | 243 | ||||
-rw-r--r-- | src/doxygen.h | 1 | ||||
-rw-r--r-- | src/entry.cpp | 3 | ||||
-rw-r--r-- | src/entry.h | 1 | ||||
-rw-r--r-- | src/filedef.cpp | 64 | ||||
-rw-r--r-- | src/filedef.h | 9 | ||||
-rw-r--r-- | src/latexgen.cpp | 1 | ||||
-rw-r--r-- | src/memberdef.cpp | 9 | ||||
-rw-r--r-- | src/memberdef.h | 14 | ||||
-rw-r--r-- | src/namespacedef.cpp | 54 | ||||
-rw-r--r-- | src/namespacedef.h | 11 | ||||
-rw-r--r-- | src/pre.l | 1 | ||||
-rw-r--r-- | src/scanner.l | 47 | ||||
-rw-r--r-- | src/searchindex.cpp | 110 | ||||
-rw-r--r-- | src/sortdict.h | 69 | ||||
-rw-r--r-- | src/translator_cz.h | 80 | ||||
-rw-r--r-- | src/translator_en.h | 5 | ||||
-rw-r--r-- | src/translator_es.h | 130 | ||||
-rw-r--r-- | src/util.cpp | 805 | ||||
-rw-r--r-- | src/util.h | 16 |
28 files changed, 1490 insertions, 597 deletions
diff --git a/src/classdef.cpp b/src/classdef.cpp index e20e9d6..315e7aa 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -891,6 +891,7 @@ void ClassDef::writeDocumentation(OutputList &ol) { ol.startTypewriter(); bool isIDLorJava = nm.right(4)==".idl" || + nm.right(5)==".pidl" || nm.right(5)==".java"; if (isIDLorJava) { diff --git a/src/classlist.cpp b/src/classlist.cpp index 60ac20c..35d35cd 100644 --- a/src/classlist.cpp +++ b/src/classlist.cpp @@ -95,7 +95,15 @@ void ClassSDict::writeDeclaration(OutputList &ol,const ClassDef::CompoundType *f } ol.startMemberItem(FALSE); QCString tmp = cd->compoundTypeString(); - QCString cname = substitute(cd->className(),"::","."); + QCString cname; + if (Config_getBool("OPTIMIZE_OUTPUT_JAVA")) + { + cname = substitute(cd->className(),"::","."); + } + else + { + cname = cd->className(); + } ol.writeString(tmp); ol.writeString(" "); ol.insertMemberAlign(); diff --git a/src/classlist.h b/src/classlist.h index 720f721..0e22864 100644 --- a/src/classlist.h +++ b/src/classlist.h @@ -49,7 +49,7 @@ class ClassDict : public QDict<ClassDef> class ClassSDict : public SDict<ClassDef> { public: - ClassSDict(int size) : SDict<ClassDef>(size) {} + ClassSDict(int size=17) : SDict<ClassDef>(size) {} ~ClassSDict() {} int compareItems(GCI item1,GCI item2); void writeDeclaration(OutputList &ol,const ClassDef::CompoundType *filter=0, @@ -185,7 +185,7 @@ void VariableContext::addVariable(const QCString &type,const QCString &name) int i=0; if ( (varType=g_codeClassSDict[ltype]) || // look for class definitions inside the code block - (varType=getResolvedClass(g_currentDefinition,ltype)) // look for global class definitions + (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions ) { DBG_CTX((stderr,"** AddVariable type=%s name=%s\n",ltype.data(),lname.data())); @@ -507,11 +507,11 @@ static ClassDef *stripClassName(const char *s) ClassDef *cd=0; if (!g_classScope.isEmpty()) { - cd=getResolvedClass(g_currentDefinition,g_classScope+"::"+clName); + cd=getResolvedClass(g_currentDefinition,g_sourceFileDef,g_classScope+"::"+clName); } if (cd==0) { - cd=getResolvedClass(g_currentDefinition,clName); + cd=getResolvedClass(g_currentDefinition,g_sourceFileDef,clName); } //printf("stripClass trying `%s' = %p\n",clName.data(),cd); if (cd) @@ -651,14 +651,16 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName, if (!g_theVarContext.findVariable(className)) // not a local variable { - //printf("not a local var!\n"); Definition *d = g_currentDefinition; - cd = getResolvedClass(d,className); + cd = getResolvedClass(d,g_sourceFileDef,className); if (cd==0 && (i=className.find('<'))!=-1) { - cd=getResolvedClass(d,className.left(i)); + cd=getResolvedClass(d,g_sourceFileDef,className.left(i)); } } + else + { + } if (cd && cd->isLinkable()) // is it a linkable class { //printf("is linkable class %s\n",clName); @@ -678,12 +680,13 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName, } else { + //printf("class %s not linkable! cd=%p\n",clName,cd); //printf("typeOnly=%d\n",typeOnly); if (cd==0 && !typeOnly) // not a class, see if it is a global enum/variable/typedef. { MemberDef *md = setCallContextForVar(clName); - //printf("is a global md=%p\n",md); - if (md) + //printf("is a global md=%p g_currentDefinition=%s\n",md,g_currentDefinition?g_currentDefinition->name().data():"<none>"); + if (md && (g_currentDefinition==0 || isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md)!=-1)) { Definition *d = md->getOuterScope()==Doxygen::globalScope ? md->getBodyDef() : md->getOuterScope(); @@ -849,7 +852,7 @@ static void generateMemberLink(BaseCodeDocInterface &ol,const QCString &varName, } else // variable not in current context, maybe it is in a parent context { - vcd = getResolvedClass(g_currentDefinition,g_classScope); + vcd = getResolvedClass(g_currentDefinition,g_sourceFileDef,g_classScope); if (vcd && vcd->isLinkable()) { //printf("Found class %s for variable `%s'\n",g_classScope.data(),varName.data()); @@ -1166,7 +1169,10 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" { g_insideBody=FALSE; g_currentMemberDef=0; - g_currentDefinition=0; + if (g_currentDefinition) + g_currentDefinition=g_currentDefinition->getOuterScope(); + else + g_currentDefinition=0; } BEGIN(Body); } @@ -1232,7 +1238,7 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" g_scopeStack.push(CLASSBLOCK); pushScope(g_curClassName); //printf("***** g_curClassName=%s\n",g_curClassName.data()); - if (getResolvedClass(g_currentDefinition,g_curClassName)==0) + if (getResolvedClass(g_currentDefinition,g_sourceFileDef,g_curClassName)==0) { g_curClassDef=new ClassDef("<code>",1, g_curClassName,ClassDef::Class); @@ -1243,7 +1249,7 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" { ClassDef *bcd; bcd=g_codeClassSDict[s]; - if (bcd==0) bcd=getResolvedClass(g_currentDefinition,s); + if (bcd==0) bcd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s); if (bcd) { g_curClassDef->insertBaseClass(bcd,s,Public,Normal); @@ -1631,7 +1637,7 @@ TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned" int index = g_name.findRev("::"); if (index!=-1) { - ClassDef *cd=getResolvedClass(Doxygen::globalScope,g_name.left(index)); + ClassDef *cd=getResolvedClass(Doxygen::globalScope,g_sourceFileDef,g_name.left(index)); if (cd) { setClassScope(cd->name()); diff --git a/src/config.h b/src/config.h index 5bd4209..0201329 100644 --- a/src/config.h +++ b/src/config.h @@ -497,6 +497,7 @@ class Config { ConfigObsolete *option = new ConfigObsolete(ConfigOption::O_Obsolete); m_dict->insert(name,option); + m_obsolete->append(option); return option; } /*! @} */ @@ -539,23 +540,29 @@ class Config * to the configuration object */ void create(); + protected: + Config() { - m_options = new QList<ConfigOption>; - m_dict = new QDict<ConfigOption>(257); + m_options = new QList<ConfigOption>; + m_obsolete = new QList<ConfigOption>; + m_dict = new QDict<ConfigOption>(257); m_options->setAutoDelete(TRUE); + m_obsolete->setAutoDelete(TRUE); m_initialized = FALSE; create(); } ~Config() { delete m_options; + delete m_obsolete; delete m_dict; } private: QList<ConfigOption> *m_options; + QList<ConfigOption> *m_obsolete; QDict<ConfigOption> *m_dict; static Config *m_instance; bool m_initialized; diff --git a/src/config.l b/src/config.l index a22e4de..f07ba8a 100644 --- a/src/config.l +++ b/src/config.l @@ -1270,7 +1270,7 @@ void Config::create() // option definitions //----------------------------------------------------------------------------------------------- - addInfo("General","General configuration options"); + addInfo("Project","Project related configuration options"); //----------------------------------------------------------------------------------------------- @@ -1404,6 +1404,143 @@ void Config::create() #endif ); cb = addBool( + "BRIEF_MEMBER_DESC", + "If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \n" + "include brief member descriptions after the members that are listed in \n" + "the file and class documentation (similar to JavaDoc). \n" + "Set to NO to disable this. \n", + TRUE + ); + cb = addBool( + "REPEAT_BRIEF", + "If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \n" + "the brief description of a member or function before the detailed description. \n" + "Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \n" + "brief descriptions will be completely suppressed. \n", + TRUE + ); + cb = addBool( + "ALWAYS_DETAILED_SEC", + "If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \n" + "Doxygen will generate a detailed section even if there is only a brief \n" + "description. \n", + FALSE + ); + cb = addBool( + "INLINE_INHERITED_MEMB", + "If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited \n" + "members of a class in the documentation of that class as if those members were \n" + "ordinary class members. Constructors, destructors and assignment operators of \n" + "the base classes will not be shown. \n", + FALSE + ); + cb = addBool( + "FULL_PATH_NAMES", + "If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \n" + "path before files name in the file list and in the header files. If set \n" + "to NO the shortest path that makes the file name unique will be used. \n", + FALSE + ); + cl = addList( + "STRIP_FROM_PATH", + "If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \n" + "can be used to strip a user-defined part of the path. Stripping is \n" + "only done if one of the specified strings matches the left-hand part of \n" + "the path. It is allowed to use relative paths in the argument list.\n" + ); + cl->addDependency("FULL_PATH_NAMES"); + cb = addBool( + "SHORT_NAMES", + "If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \n" + "(but less readable) file names. This can be useful is your file systems \n" + "doesn't support long names like on DOS, Mac, or CD-ROM. \n", + FALSE + ); + cb = addBool( + "JAVADOC_AUTOBRIEF", + "If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \n" + "will interpret the first line (until the first dot) of a JavaDoc-style \n" + "comment as the brief description. If set to NO, the JavaDoc \n" + "comments will behave just like the Qt-style comments (thus requiring an \n" + "explict @brief command for a brief description. \n", + FALSE + ); + cb = addBool( + "MULTILINE_CPP_IS_BRIEF", + "The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \n" + "treat a multi-line C++ special comment block (i.e. a block of //! or /// \n" + "comments) as a brief description. This used to be the default behaviour. \n" + "The new default is to treat a multi-line C++ comment block as a detailed \n" + "description. Set this tag to YES if you prefer the old behaviour instead. \n", + FALSE + ); + cb = addBool( + "DETAILS_AT_TOP", + "If the DETAILS_AT_TOP tag is set to YES then Doxygen \n" + "will output the detailed description near the top, like JavaDoc.\n" + "If set to NO, the detailed description appears after the member \n" + "documentation. \n", + FALSE + ); + cb = addBool( + "INHERIT_DOCS", + "If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \n" + "member inherits the documentation from any documented member that it \n" + "reimplements. \n", + TRUE + ); + cb = addBool( + "DISTRIBUTE_GROUP_DOC", + "If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \n" + "tag is set to YES, then doxygen will reuse the documentation of the first \n" + "member in the group (if any) for the other members of the group. By default \n" + "all members of a group must be documented explicitly.\n", + FALSE + ); + ci = addInt( + "TAB_SIZE", + "The TAB_SIZE tag can be used to set the number of spaces in a tab. \n" + "Doxygen uses this value to replace tabs by spaces in code fragments. \n", + 1,16,8 + ); + cl = addList( + "ALIASES", + "This tag can be used to specify a number of aliases that acts \n" + "as commands in the documentation. An alias has the form \"name=value\". \n" + "For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to \n" + "put the command \\sideeffect (or @sideeffect) in the documentation, which \n" + "will result in a user-defined paragraph with heading \"Side Effects:\". \n" + "You can put \\n's in the value part of an alias to insert newlines. \n" + ); + cb = addBool( + "OPTIMIZE_OUTPUT_FOR_C", + "Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources \n" + "only. Doxygen will then generate output that is more tailored for C. \n" + "For instance, some of the names that are used will be different. The list \n" + "of all members will be omitted, etc. \n", + FALSE + ); + cb = addBool( + "OPTIMIZE_OUTPUT_JAVA", + "Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources \n" + "only. Doxygen will then generate output that is more tailored for Java. \n" + "For instance, namespaces will be presented as packages, qualified scopes \n" + "will look different, etc. \n", + FALSE + ); + cb = addBool( + "SUBGROUPING", + "Set the SUBGROUPING tag to YES (the default) to allow class member groups of \n" + "the same type (for instance a group of public functions) to be put as a \n" + "subgroup of that type (e.g. under the Public Functions section). Set it to \n" + "NO to prevent subgrouping. Alternatively, this can be done per class using \n" + "the \\nosubgrouping command. \n", + TRUE + ); + //----------------------------------------------------------------------------------------------- + addInfo("Build","Build related configuration options"); + //----------------------------------------------------------------------------------------------- + cb = addBool( "EXTRACT_ALL", "If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \n" "documentation are documented, even if no documentation was available. \n" @@ -1464,52 +1601,6 @@ void Config::create() FALSE ); cb = addBool( - "BRIEF_MEMBER_DESC", - "If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \n" - "include brief member descriptions after the members that are listed in \n" - "the file and class documentation (similar to JavaDoc). \n" - "Set to NO to disable this. \n", - TRUE - ); - cb = addBool( - "REPEAT_BRIEF", - "If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \n" - "the brief description of a member or function before the detailed description. \n" - "Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \n" - "brief descriptions will be completely suppressed. \n", - TRUE - ); - cb = addBool( - "ALWAYS_DETAILED_SEC", - "If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \n" - "Doxygen will generate a detailed section even if there is only a brief \n" - "description. \n", - FALSE - ); - cb = addBool( - "INLINE_INHERITED_MEMB", - "If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited \n" - "members of a class in the documentation of that class as if those members were \n" - "ordinary class members. Constructors, destructors and assignment operators of \n" - "the base classes will not be shown. \n", - FALSE - ); - cb = addBool( - "FULL_PATH_NAMES", - "If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \n" - "path before files name in the file list and in the header files. If set \n" - "to NO the shortest path that makes the file name unique will be used. \n", - FALSE - ); - cl = addList( - "STRIP_FROM_PATH", - "If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \n" - "can be used to strip a user-defined part of the path. Stripping is \n" - "only done if one of the specified strings matches the left-hand part of \n" - "the path. It is allowed to use relative paths in the argument list.\n" - ); - cl->addDependency("FULL_PATH_NAMES"); - cb = addBool( "INTERNAL_DOCS", "The INTERNAL_DOCS tag determines if documentation \n" "that is typed after a \\internal command is included. If the tag is set \n" @@ -1527,13 +1618,6 @@ void Config::create() TRUE ); cb = addBool( - "SHORT_NAMES", - "If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \n" - "(but less readable) file names. This can be useful is your file systems \n" - "doesn't support long names like on DOS, Mac, or CD-ROM. \n", - FALSE - ); - cb = addBool( "HIDE_SCOPE_NAMES", "If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \n" "will show members with their full class and namespace scopes in the \n" @@ -1548,39 +1632,6 @@ void Config::create() TRUE ); cb = addBool( - "JAVADOC_AUTOBRIEF", - "If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \n" - "will interpret the first line (until the first dot) of a JavaDoc-style \n" - "comment as the brief description. If set to NO, the JavaDoc \n" - "comments will behave just like the Qt-style comments (thus requiring an \n" - "explict @brief command for a brief description. \n", - FALSE - ); - cb = addBool( - "MULTILINE_CPP_IS_BRIEF", - "The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \n" - "treat a multi-line C++ special comment block (i.e. a block of //! or /// \n" - "comments) as a brief description. This used to be the default behaviour. \n" - "The new default is to treat a multi-line C++ comment block as a detailed \n" - "description. Set this tag to YES if you prefer the old behaviour instead. \n", - FALSE - ); - cb = addBool( - "DETAILS_AT_TOP", - "If the DETAILS_AT_TOP tag is set to YES then Doxygen \n" - "will output the detailed description near the top, like JavaDoc.\n" - "If set to NO, the detailed description appears after the member \n" - "documentation. \n", - FALSE - ); - cb = addBool( - "INHERIT_DOCS", - "If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \n" - "member inherits the documentation from any documented member that it \n" - "reimplements. \n", - TRUE - ); - cb = addBool( "INLINE_INFO", "If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \n" "is inserted in the documentation for inline members. \n", @@ -1595,20 +1646,6 @@ void Config::create() TRUE ); cb = addBool( - "DISTRIBUTE_GROUP_DOC", - "If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \n" - "tag is set to YES, then doxygen will reuse the documentation of the first \n" - "member in the group (if any) for the other members of the group. By default \n" - "all members of a group must be documented explicitly.\n", - FALSE - ); - ci = addInt( - "TAB_SIZE", - "The TAB_SIZE tag can be used to set the number of spaces in a tab. \n" - "Doxygen uses this value to replace tabs by spaces in code fragments. \n", - 1,16,8 - ); - cb = addBool( "GENERATE_TODOLIST", "The GENERATE_TODOLIST tag can be used to enable (YES) or \n" "disable (NO) the todo list. This list is created by putting \\todo \n" @@ -1637,15 +1674,6 @@ void Config::create() TRUE ); cl = addList( - "ALIASES", - "This tag can be used to specify a number of aliases that acts \n" - "as commands in the documentation. An alias has the form \"name=value\". \n" - "For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to \n" - "put the command \\sideeffect (or @sideeffect) in the documentation, which \n" - "will result in a user-defined paragraph with heading \"Side Effects:\". \n" - "You can put \\n's in the value part of an alias to insert newlines. \n" - ); - cl = addList( "ENABLED_SECTIONS", "The ENABLED_SECTIONS tag can be used to enable conditional \n" "documentation sections, marked by \\if sectionname ... \\endif. \n" @@ -1662,37 +1690,13 @@ void Config::create() 0,10000,30 ); cb = addBool( - "OPTIMIZE_OUTPUT_FOR_C", - "Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources \n" - "only. Doxygen will then generate output that is more tailored for C. \n" - "For instance, some of the names that are used will be different. The list \n" - "of all members will be omitted, etc. \n", - FALSE - ); - cb = addBool( - "OPTIMIZE_OUTPUT_JAVA", - "Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources \n" - "only. Doxygen will then generate output that is more tailored for Java. \n" - "For instance, namespaces will be presented as packages, qualified scopes \n" - "will look different, etc. \n", - FALSE - ); - cb = addBool( "SHOW_USED_FILES", "Set the SHOW_USED_FILES tag to NO to disable the list of files generated \n" "at the bottom of the documentation of classes and structs. If set to YES the \n" "list will mention the files that were used to generate the documentation. \n", TRUE ); - cb = addBool( - "SUBGROUPING", - "Set the SUBGROUPING tag to YES (the default) to allow class member groups of \n" - "the same type (for instance a group of public functions) to be put as a \n" - "subgroup of that type (e.g. under the Public Functions section). Set it to \n" - "NO to prevent subgrouping. Alternatively, this can be done per class using \n" - "the \\nosubgrouping command. \n", - TRUE - ); + //----------------------------------------------------------------------------------------------- addInfo( "Messages","configuration options related to warning and progress messages"); //----------------------------------------------------------------------------------------------- diff --git a/src/definition.cpp b/src/definition.cpp index 75c2931..2733ab3 100644 --- a/src/definition.cpp +++ b/src/definition.cpp @@ -18,6 +18,8 @@ #include "qtbc.h" #include <ctype.h> #include <qregexp.h> +#include <stdio.h> +#include <stdlib.h> #include "config.h" #include "definition.h" #include "doxygen.h" @@ -29,6 +31,47 @@ #include "groupdef.h" #include "section.h" +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define popen _popen +#define pclose _pclose +#endif + +static void addToMap(const char *name,Definition *d) +{ + QCString symbolName = name; + int index=symbolName.findRev("::"); + if (index!=-1) symbolName=symbolName.mid(index+2); + if (!symbolName.isEmpty()) + { + DefinitionList *dl=Doxygen::symbolMap->find(symbolName); + if (dl==0) + { + dl = new DefinitionList; + Doxygen::symbolMap->append(symbolName,dl); + } + //printf("******* adding symbol `%s'\n",symbolName.data()); + dl->append(d); + } +} + +static void removeFromMap(Definition *d) +{ + QCString symbolName = d->name(); + int index=symbolName.findRev("::"); + if (index!=-1) symbolName=symbolName.mid(index+2); + if (!symbolName.isEmpty()) + { + //printf("******* removing symbol `%s'\n",symbolName.data()); + DefinitionList *dl=Doxygen::symbolMap->find(symbolName); + if (dl) + { + ASSERT(dl!=0); + bool b = dl->removeRef(d); + ASSERT(b==TRUE); + } + } +} + Definition::Definition(const char *df,int dl, const char *name,const char *b,const char *d) { @@ -64,10 +107,12 @@ Definition::Definition(const char *df,int dl, m_briefFile=(QCString)"<"+name+">"; m_docLine=1; m_docFile=(QCString)"<"+name+">"; + addToMap(name,this); } Definition::~Definition() { + removeFromMap(this); delete m_sectionDict; delete m_sourceRefByDict; delete m_sourceRefsDict; @@ -196,26 +241,27 @@ static bool readCodeFragment(const char *fileName, { //printf("readCodeFragment(%s,%d,%d)\n",fileName,startLine,endLine); if (fileName==0 || fileName[0]==0) return FALSE; // not a valid file name - QFile f(fileName); - if (f.open(IO_ReadOnly)) + QCString cmd=Config_getString("INPUT_FILTER")+" \""+fileName+"\""; + FILE *f = Config_getBool("FILTER_SOURCE_FILES") ? popen(cmd,"r") : fopen(fileName,"r"); + if (f) { int c=0; int col=0; int lineNr=1; // skip until the startLine has reached - while (lineNr<startLine && !f.atEnd()) + while (lineNr<startLine && !feof(f)) { - while ((c=f.getch())!='\n' && c!=-1) /* skip */; + while ((c=fgetc(f))!='\n' && c==EOF) /* skip */; lineNr++; } - if (!f.atEnd()) + if (!feof(f)) { // skip until the opening bracket or lonely : is found bool found=FALSE; char cn=0; - while (lineNr<=endLine && !f.atEnd() && !found) + while (lineNr<=endLine && !feof(f) && !found) { - while ((c=f.getch())!='{' && c!=':' && c!=-1) + while ((c=fgetc(f))!='{' && c!=':' && c!=EOF) { if (c=='\n') { @@ -232,7 +278,7 @@ static bool readCodeFragment(const char *fileName, } if (c==':') { - cn=f.getch(); + cn=fgetc(f); if (cn!=':') found=TRUE; } else if (c=='{') @@ -262,12 +308,13 @@ static bool readCodeFragment(const char *fileName, int size_read; do { // read up to maxLineLength-1 bytes, the last byte being zero - size_read = f.readLine(lineStr, maxLineLength); + char *p = fgets(lineStr, maxLineLength,f); + if (p) size_read=qstrlen(p); else size_read=-1; result+=lineStr; } while (size_read == (maxLineLength-1)); lineNr++; - } while (lineNr<=endLine && !f.atEnd()); + } while (lineNr<=endLine && !feof(f)); // strip stuff after closing bracket int newLineIndex = result.findRev('\n'); diff --git a/src/docparser.cpp b/src/docparser.cpp index 4cbb0a7..a66f659 100644 --- a/src/docparser.cpp +++ b/src/docparser.cpp @@ -572,12 +572,15 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children, g_token->name.data(),cmdName.data()); break; case TK_SYMBOL: - warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found", - g_token->name.data()); + warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found while handling command %s", + g_token->name.data(),cmdName.data()); + break; + case TK_HTMLTAG: + return tok; break; default: - warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s", - tokToString(tok)); + warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s while handling command %s", + tokToString(tok),cmdName.data()); break; } break; @@ -789,7 +792,7 @@ reparsetoken: children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE)); if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," ")); if (tok==TK_NEWPARA) goto handlepara; - else if (tok==TK_WORD) goto reparsetoken; + else if (tok==TK_WORD || tok==TK_HTMLTAG) goto reparsetoken; } break; case CMD_BOLD: @@ -799,7 +802,7 @@ reparsetoken: children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE)); if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," ")); if (tok==TK_NEWPARA) goto handlepara; - else if (tok==TK_WORD) goto reparsetoken; + else if (tok==TK_WORD || tok==TK_HTMLTAG) goto reparsetoken; } break; case CMD_CODE: @@ -809,7 +812,7 @@ reparsetoken: children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE)); if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," ")); if (tok==TK_NEWPARA) goto handlepara; - else if (tok==TK_WORD) goto reparsetoken; + else if (tok==TK_WORD || tok==TK_HTMLTAG) goto reparsetoken; } break; case CMD_HTMLONLY: diff --git a/src/doxygen.cpp b/src/doxygen.cpp index fbfe2e2..76ab5de 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -108,7 +108,7 @@ QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the me PageDef *Doxygen::mainPage = 0; bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page? QTextStream Doxygen::tagFile; -NamespaceDef *Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>"); +NamespaceDef *Doxygen::globalScope; QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists @@ -116,6 +116,7 @@ bool Doxygen::parseSourcesNeeded = FALSE; double Doxygen::sysElapsedTime = 0.0; QTime Doxygen::runningTime; SearchIndex * Doxygen::searchIndex=0; +SDict<DefinitionList> *Doxygen::symbolMap; static StringList inputFiles; static StringDict excludeNameDict(1009); // sections @@ -184,7 +185,7 @@ void statistics() static void addMemberDocs(Entry *root,MemberDef *md, const char *funcDecl, - ArgumentList *al,bool over_load,NamespaceList *nl=0); + ArgumentList *al,bool over_load,NamespaceSDict *nl=0); const char idMask[] = "[A-Za-z_][A-Za-z_0-9]*"; QCString spaces; @@ -1186,28 +1187,32 @@ static void findUsingDeclarations(Entry *root) // the possible scopes in which the using statement was found, starting // with the most inner scope and going to the most outer scope (i.e. // file scope). - int scopeOffset = scName.length(); - do - { - QCString scope=scopeOffset>0 ? - scName.left(scopeOffset)+"::" : QCString(); - //printf("Trying with scope=`%s'\n",scope.data()); - usingCd = getClass(scope+root->name); - if (scopeOffset==0) - { - scopeOffset=-1; - } - else if ((scopeOffset=scName.findRev("::",scopeOffset-1))==-1) - { - scopeOffset=0; - } - } while (scopeOffset>=0 && usingCd==0); +// int scopeOffset = scName.length(); +// do +// { +// QCString scope=scopeOffset>0 ? +// scName.left(scopeOffset)+"::" : QCString(); +// //printf("Trying with scope=`%s'\n",scope.data()); +// usingCd = getClass(scope+root->name); +// if (scopeOffset==0) +// { +// scopeOffset=-1; +// } +// else if ((scopeOffset=scName.findRev("::",scopeOffset-1))==-1) +// { +// scopeOffset=0; +// } +// } while (scopeOffset>=0 && usingCd==0); + + usingCd = getResolvedClass(nd,fd,root->name); //printf("%s -> %p\n",root->name.data(),usingCd); if (usingCd==0) // definition not in the input => add an artificial class { + Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n", + root->name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1); usingCd = new ClassDef( - "<generated>",1, + "<using>",1, root->name,ClassDef::Class); Doxygen::hiddenClasses.append(root->name,usingCd); usingCd->setClassIsArtificial(); @@ -1260,7 +1265,7 @@ static void findUsingDeclImports(Entry *root) { QCString scope=root->name.left(i); QCString memName=root->name.right(root->name.length()-i-2); - ClassDef *bcd = getResolvedClass(cd,scope); + ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter if (bcd) { //printf("found class %s\n",bcd->name().data()); @@ -1721,7 +1726,7 @@ static bool isVarWithConstructor(Entry *root) if (root->parent->name) ctx=Doxygen::namespaceSDict.find(root->parent->name); type = root->type; if (type.left(6)=="const ") type=type.right(type.length()-6); - typeIsClass=getResolvedClass(ctx,type)!=0; + typeIsClass=getResolvedClass(ctx,fd,type)!=0; if (typeIsClass) // now we still have to check if the arguments are // types or values. Since we do not have complete type info // we need to rely on heuristics :-( @@ -1743,7 +1748,7 @@ static bool isVarWithConstructor(Entry *root) result=FALSE; // arg has (type,name) pair -> function prototype goto done; } - if (a->type.isEmpty() || getResolvedClass(ctx,a->type)!=0) + if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) { result=FALSE; // arg type is a known type goto done; @@ -2144,12 +2149,13 @@ static void buildFunctionList(Entry *root) { Debug::print(Debug::Functions,0, "FUNCTION_SEC:\n" - " `%s' `%s'::`%s' `%s' relates=`%s' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d memSpec=%d proto=%d docFile=%s\n", + " `%s' `%s'::`%s' `%s' relates=`%s' relatesDup=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d memSpec=%d proto=%d docFile=%s\n", root->type.data(), root->parent->name.data(), root->name.data(), root->args.data(), root->relates.data(), + root->relatesDup, root->fileName.data(), root->startLine, root->bodyLine, @@ -2213,7 +2219,7 @@ static void buildFunctionList(Entry *root) else if (root->parent && !(root->parent->section & Entry::COMPOUND_MASK) && !isMember && - root->relates.isEmpty() && + (root->relates.isEmpty() || root->relatesDup) && root->type.left(7)!="extern " && root->type.left(8)!="typedef " ) @@ -2243,8 +2249,8 @@ static void buildFunctionList(Entry *root) QCString nsName,rnsName; if (nd) nsName = nd->name().copy(); if (rnd) rnsName = rnd->name().copy(); - NamespaceList *unl = fd ? fd->getUsedNamespaces() : 0; - ClassList *ucl = fd ? fd->getUsedClasses() : 0; + NamespaceSDict *unl = fd ? fd->getUsedNamespaces() : 0; + ClassSDict *ucl = fd ? fd->getUsedClasses() : 0; //printf("matching arguments for %s%s %s%s\n", // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data()); if ( @@ -2455,7 +2461,13 @@ static void buildFunctionList(Entry *root) Doxygen::functionNameSDict.append(name,mn); } addMemberToGroups(root,md); - root->section = Entry::EMPTY_SEC; + if (!root->relatesDup) // if this is a relatesalso command, allow find + // Member to pick it up + { + root->section = Entry::EMPTY_SEC; // Otherwise we have finished + // with this entry. + + } } else { @@ -2832,7 +2844,10 @@ static void transferRelatedFunctionDocumentation() ) { //printf(" Found related member `%s'\n",md->name().data()); - md->makeRelated(); + if (rmd->relatedAlso()) + md->setRelatedAlso(rmd->relatedAlso()); + else + md->makeRelated(); } } } @@ -2892,27 +2907,27 @@ static ClassDef *findClassWithinClassContext(ClassDef *cd,const QCString &name) if (nd) // class is inside a namespace { QCString fName = nd->name()+"::"+name; - result = getResolvedClass(cd,fName); + result = getResolvedClass(cd,fd,fName); if (result && result!=cd) { return result; } - NamespaceList *nl = nd->getUsedNamespaces(); + NamespaceSDict *nl = nd->getUsedNamespaces(); if (nl) // try to prepend any of the using namespace scopes. { - NamespaceListIterator nli(*nl); + NamespaceSDict::Iterator nli(*nl); NamespaceDef *nd; for (nli.toFirst() ; (nd=nli.current()) ; ++nli) { fName = nd->name()+"::"+name; - result = getResolvedClass(cd,fName); + result = getResolvedClass(cd,fd,fName); if (result && result!=cd) return result; } } - ClassList *cl = nd->getUsedClasses(); + ClassSDict *cl = nd->getUsedClasses(); if (cl) { - ClassListIterator cli(*cl); + ClassSDict::Iterator cli(*cl); ClassDef *ucd; for (cli.toFirst(); (ucd=cli.current()) ; ++cli) { @@ -2925,10 +2940,10 @@ static ClassDef *findClassWithinClassContext(ClassDef *cd,const QCString &name) // TODO: check any inbetween namespaces as well! if (fd) // and in the global namespace { - ClassList *cl = fd->getUsedClasses(); + ClassSDict *cl = fd->getUsedClasses(); if (cl) { - ClassListIterator cli(*cl); + ClassSDict::Iterator cli(*cl); ClassDef *ucd; for (cli.toFirst(); (ucd=cli.current()); ++cli) { @@ -2946,25 +2961,25 @@ static ClassDef *findClassWithinClassContext(ClassDef *cd,const QCString &name) { // look for the using statement in this file in which the // class was found - NamespaceList *nl = fd->getUsedNamespaces(); + NamespaceSDict *nl = fd->getUsedNamespaces(); if (nl) // try to prepend any of the using namespace scopes. { - NamespaceListIterator nli(*nl); + NamespaceSDict::Iterator nli(*nl); NamespaceDef *nd; for (nli.toFirst() ; (nd=nli.current()) ; ++nli) { QCString fName = nd->name()+"::"+name; - result=getResolvedClass(cd,fName); + result=getResolvedClass(cd,fd,fName); if (result && result!=cd) { return result; } } } - ClassList *cl = fd->getUsedClasses(); + ClassSDict *cl = fd->getUsedClasses(); if (cl) { - ClassListIterator cli(*cl); + ClassSDict::Iterator cli(*cl); ClassDef *ucd; for (cli.toFirst(); (ucd=cli.current()) ; ++cli) { @@ -2976,7 +2991,7 @@ static ClassDef *findClassWithinClassContext(ClassDef *cd,const QCString &name) } } - return getResolvedClass(cd,name); + return getResolvedClass(cd,fd,name); } enum FindBaseClassRelation_Mode @@ -3325,7 +3340,11 @@ static bool findClassRelation( (removeRedundantWhiteSpace(baseClassName)); bool baseClassIsTypeDef; QCString templSpec; - ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? 0 : cd,baseClassName,&baseClassIsTypeDef,&templSpec); + ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? 0 : cd, + cd->getFileDef(), // todo: is this ok? + baseClassName, + &baseClassIsTypeDef, + &templSpec); //printf("baseClassName=%s baseClass=%p cd=%p\n",baseClassName.data(),baseClass,cd); //printf(" root->name=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n", // root->name.data(), @@ -3374,7 +3393,7 @@ static bool findClassRelation( { templSpec=baseClassName.mid(i,e-i); baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e); - baseClass=getResolvedClass(cd,baseClassName); + baseClass=getResolvedClass(cd,cd->getFileDef(),baseClassName); //printf("baseClass=%p -> baseClass=%s templSpec=%s\n", // baseClass,baseClassName.data(),templSpec.data()); } @@ -3386,7 +3405,7 @@ static bool findClassRelation( { // replace any namespace aliases replaceNamespaceAliases(baseClassName,i); - baseClass=getResolvedClass(cd,baseClassName); + baseClass=getResolvedClass(cd,cd->getFileDef(),baseClassName); found=baseClass!=0 && baseClass!=cd; } @@ -3818,7 +3837,7 @@ static void addMemberDocs(Entry *root, MemberDef *md, const char *funcDecl, ArgumentList *al, bool over_load, - NamespaceList *nl + NamespaceSDict *nl ) { //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' memSpec=%d\n", @@ -3966,7 +3985,7 @@ static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, ClassDef *tcd = getClass(scopeName); if (tcd==0) // try using declaration { - ClassList *cl = 0; + ClassSDict *cl = 0; if (nd) { cl=nd->getUsedClasses(); @@ -3977,7 +3996,7 @@ static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, } if (cl) { - ClassListIterator cli(*cl); + ClassSDict::Iterator cli(*cl); ClassDef *cd; for (;(cd=cli.current()) && tcd==0;++cli) { @@ -3999,7 +4018,7 @@ static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, } if (tcd==0) // try using directive { - NamespaceList *nl = 0; + NamespaceSDict *nl = 0; if (nd) { nl=nd->getUsedNamespaces(); @@ -4010,7 +4029,7 @@ static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, } if (nl) { - NamespaceListIterator nli(*nl); + NamespaceSDict::Iterator nli(*nl); NamespaceDef *nd; for (;(nd=nli.current()) && tcd==0;++nli) { @@ -4061,13 +4080,13 @@ static bool findGlobalMember(Entry *root, // namespaceName.data(),nd ? nd->name().data() : "<none>"); FileDef *fd=findFileDef(Doxygen::inputNameDict,root->fileName,ambig); //printf("File %s\n",fd ? fd->name().data() : "<none>"); - NamespaceList *nl = fd ? fd->getUsedNamespaces() : 0; - ClassList *cl = fd ? fd->getUsedClasses() : 0; + NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0; + ClassSDict *cl = fd ? fd->getUsedClasses() : 0; //printf("NamespaceList %p\n",nl); // search in the list of namespaces that are imported via a // using declaration - bool viaUsingDirective = nl && nd && nl->find(nd)!=-1; + bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0; if ((namespaceName.isEmpty() && nd==0) || // not in a namespace (nd && nd->name()==namespaceName) || // or in the same namespace @@ -4566,58 +4585,58 @@ static void findMember(Entry *root, // list of namespaces using in the file/namespace that this // member definition is part of - NamespaceList *nl = new NamespaceList; + NamespaceSDict *nl = new NamespaceSDict; if (nd) { - NamespaceList *nnl = nd->getUsedNamespaces(); + NamespaceSDict *nnl = nd->getUsedNamespaces(); if (nnl) { - NamespaceDef *nnd = nnl->first(); - while (nnd) + NamespaceDef *nnd; + NamespaceSDict::Iterator nsdi(*nnl); + for (nsdi.toFirst();(nnd=nsdi.current());++nsdi) { - nl->append(nnd); - nnd = nnl->next(); + nl->append(nnd->qualifiedName(),nnd); } } } if (fd) { - NamespaceList *fnl = fd->getUsedNamespaces(); + NamespaceSDict *fnl = fd->getUsedNamespaces(); if (fnl) { - NamespaceDef *fnd = fnl->first(); - while (fnd) + NamespaceDef *fnd; + NamespaceSDict::Iterator nsdi(*fnl); + for (nsdi.toFirst();(fnd=nsdi.current());++nsdi) { - nl->append(fnd); - fnd = fnl->next(); + nl->append(fnd->qualifiedName(),fnd); } } } - ClassList *cl = new ClassList; + ClassSDict *cl = new ClassSDict(17); if (nd) { - ClassList *ncl = nd->getUsedClasses(); + ClassSDict *ncl = nd->getUsedClasses(); if (ncl) { - ClassDef *ncd = ncl->first(); - while (ncd) + ClassSDict::Iterator csdi(*ncl); + ClassDef *ncd; + for (csdi.toFirst();(ncd=csdi.current());++csdi) { - cl->append(ncd); - ncd = ncl->next(); + cl->append(ncd->qualifiedName(),ncd); } } } if (fd) { - ClassList *fcl = fd->getUsedClasses(); + ClassSDict *fcl = fd->getUsedClasses(); if (fcl) { - ClassDef *fcd = fcl->first(); - while (fcd) + ClassSDict::Iterator csdi(*fcl); + ClassDef *fcd; + for (csdi.toFirst();(fcd=csdi.current());++csdi) { - cl->append(fcd); - fcd = fcl->next(); + cl->append(fcd->qualifiedName(),fcd); } } } @@ -4804,7 +4823,8 @@ static void findMember(Entry *root, } else if (isRelated && !root->relates.isEmpty()) { - Debug::print(Debug::FindMembers,0,"2. related function\n"); + Debug::print(Debug::FindMembers,0,"2. related function\n" + " scopeName=%s className=%s\n",scopeName.data(),className.data()); if (className.isEmpty()) className=root->relates.copy(); ClassDef *cd; //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); @@ -4938,6 +4958,7 @@ static void findMember(Entry *root, cd->insertMember(md); cd->insertUsedFile(root->fileName); md->setRefItems(root->sli); + if (root->relatesDup) md->setRelatedAlso(cd); addMemberToGroups(root,md); //printf("Adding member=%s\n",md->name().data()); if (newMemberName) @@ -4992,7 +5013,7 @@ static void findMemberDocumentation(Entry *root) { int i=-1,l; Debug::print(Debug::FindMembers,0, - "root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->memSpec=%d root->mGrpId=%d\n", + "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->memSpec=%d root->mGrpId=%d\n", root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->memSpec,root->mGrpId ); bool isFunc=TRUE; @@ -5825,6 +5846,45 @@ static void inheritDocumentation() //---------------------------------------------------------------------------- +static void combineUsingRelations() +{ + // for each file + FileNameListIterator fnli(Doxygen::inputNameList); + FileName *fn; + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (fni.toFirst();(fd=fni.current());++fni) + { + fd->visited=FALSE; + } + } + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (fni.toFirst();(fd=fni.current());++fni) + { + fd->combineUsingRelations(); + } + } + + // for each namespace + NamespaceSDict::Iterator nli(Doxygen::namespaceSDict); + NamespaceDef *nd; + for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) + { + nd->visited=FALSE; + } + for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) + { + nd->combineUsingRelations(); + } +} + +//---------------------------------------------------------------------------- + static void addMembersToMemberGroup() { // for each class @@ -7151,7 +7211,10 @@ void initDoxygen() #if QT_VERSION >= 200 setlocale(LC_ALL,""); setlocale(LC_NUMERIC,"C"); -#endif +#endif + Doxygen::symbolMap = new SDict<DefinitionList>(1000); + Doxygen::symbolMap->setAutoDelete(TRUE); + Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>"); Doxygen::runningTime.start(); initPreprocessor(); @@ -7188,6 +7251,10 @@ void cleanUpDoxygen() delete outputList; CmdMapper::freeInstance(); HtmlTagMapper::freeInstance(); + //delete Doxygen::symbolMap; <- we cannot do this unless all static lists + // (such as Doxygen::namespaceSDict) + // with objects based on Definition are made + // dynamic first } void readConfiguration(int argc, char **argv) @@ -7927,7 +7994,6 @@ void parseInput() buildClassList(root); buildClassDocList(root); resolveClassNestingRelations(); - findUsingDeclarations(root); msg("Building example list...\n"); buildExampleList(root); @@ -7968,6 +8034,7 @@ void parseInput() msg("Searching for members imported via using declarations...\n"); findUsingDeclImports(root); + findUsingDeclarations(root); msg("Building page list...\n"); buildPageList(root); @@ -8026,6 +8093,21 @@ void generateOutput() * Initialize output generators * **************************************************************************/ + //// dump all symbols + //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap); + //DefinitionList *dl; + //for (sdi.toFirst();(dl=sdi.current());++sdi) + //{ + // DefinitionListIterator dli(*dl); + // Definition *d; + // printf("Symbol: "); + // for (dli.toFirst();(d=dli.current());++dli) + // { + // printf("%s ",d->qualifiedName().data()); + // } + // printf("\n"); + //} + initDocParser(); //{ @@ -8119,6 +8201,9 @@ void generateOutput() msg("Resolving user defined references...\n"); resolveUserReferences(); + msg("Combining using relations...\n"); + combineUsingRelations(); + msg("Finding anchors and sections in the documentation...\n"); findSectionsInDocumentation(); diff --git a/src/doxygen.h b/src/doxygen.h index 9cca76d..429ce0e 100644 --- a/src/doxygen.h +++ b/src/doxygen.h @@ -99,6 +99,7 @@ class Doxygen static double sysElapsedTime; static QTime runningTime; static SearchIndex *searchIndex; + static SDict<DefinitionList> *symbolMap; }; void initDoxygen(); diff --git a/src/entry.cpp b/src/entry.cpp index 276e433..21489c5 100644 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -42,6 +42,7 @@ Entry::Entry() mGrpId = -1; tagInfo = 0; sli = 0; + relatesDup = FALSE; groupDocType = GROUPDOC_NORMAL; reset(); } @@ -69,6 +70,7 @@ Entry::Entry(const Entry &e) docLine = e.docLine; docFile = e.docFile.copy(); relates = e.relates.copy(); + relatesDup = e.relatesDup; brief = e.brief.copy(); briefLine = e.briefLine; briefFile = e.briefFile.copy(); @@ -227,6 +229,7 @@ void Entry::reset() docFile.resize(0); docLine=-1; relates.resize(0); + relatesDup=FALSE; brief.resize(0); briefFile.resize(0); briefLine=-1; diff --git a/src/entry.h b/src/entry.h index ef50658..16d00fb 100644 --- a/src/entry.h +++ b/src/entry.h @@ -275,6 +275,7 @@ class Entry int briefLine; //!< line number at which the brief desc. was found QCString briefFile; //!< file in which the brief desc. was found QCString relates; //!< related class (doc block) + bool relatesDup; //!< keep duplicate doc in original file also QCString inside; //!< name of the class in which documents are found QCString exception; //!< throw specification int bodyLine; //!< line number of the definition in the source diff --git a/src/filedef.cpp b/src/filedef.cpp index 0278688..2a94da2 100644 --- a/src/filedef.cpp +++ b/src/filedef.cpp @@ -263,6 +263,7 @@ void FileDef::writeDocumentation(OutputList &ol) if (fd) { isIDLorJava = fd->name().right(4)==".idl" || + fd->name().right(5)==".pidl" || fd->name().right(5)==".java"; } ol.startTypewriter(); @@ -648,18 +649,24 @@ void FileDef::addUsingDirective(NamespaceDef *nd) { if (usingDirList==0) { - usingDirList = new NamespaceList; + usingDirList = new NamespaceSDict; + } + if (usingDirList->find(nd->qualifiedName())==0) + { + usingDirList->append(nd->qualifiedName(),nd); } - usingDirList->append(nd); } void FileDef::addUsingDeclaration(ClassDef *cd) { if (usingDeclList==0) { - usingDeclList = new ClassList; + usingDeclList = new ClassSDict; + } + if (usingDeclList->find(cd->qualifiedName())==0) + { + usingDeclList->append(cd->qualifiedName(),cd); } - usingDeclList->append(cd); } void FileDef::addIncludeDependency(FileDef *fd,const char *incName,bool local) @@ -706,18 +713,18 @@ void FileDef::addIncludedUsingDirectives() { if (ii->fileDef && ii->fileDef!=this) { - NamespaceList *unl = ii->fileDef->usingDirList; + NamespaceSDict *unl = ii->fileDef->usingDirList; if (unl) { - NamespaceListIterator nli(*unl); + NamespaceSDict::Iterator nli(*unl); NamespaceDef *nd; for (nli.toLast();(nd=nli.current());--nli) { // append each using directive found in a #include file - if (usingDirList==0) usingDirList = new NamespaceList; + if (usingDirList==0) usingDirList = new NamespaceSDict; //printf("Prepending used namespace %s to the list of file %s\n", // nd->name().data(),name().data()); - usingDirList->prepend(nd); + usingDirList->prepend(nd->qualifiedName(),nd); } } } @@ -994,3 +1001,44 @@ void generateFileTree(QTextStream &t) delete root; } +void FileDef::combineUsingRelations() +{ + if (visited) return; // already done + visited=TRUE; + if (usingDirList) + { + NamespaceSDict::Iterator nli(*usingDirList); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + { + nd->combineUsingRelations(); + } + for (nli.toFirst();(nd=nli.current());++nli) + { + // add used namespaces of namespace nd to this namespace + if (nd->getUsedNamespaces()) + { + NamespaceSDict::Iterator unli(*nd->getUsedNamespaces()); + NamespaceDef *und; + for (unli.toFirst();(und=unli.current());++unli) + { + //printf("Adding namespace %s to the using list of %s\n",und->qualifiedName().data(),qualifiedName().data()); + addUsingDirective(und); + } + } + // add used classes of namespace nd to this namespace + if (nd->getUsedClasses()) + { + ClassSDict::Iterator cli(*nd->getUsedClasses()); + ClassDef *ucd; + for (cli.toFirst();(ucd=cli.current());++cli) + { + //printf("Adding class %s to the using list of %s\n",cd->qualifiedName().data(),qualifiedName().data()); + addUsingDeclaration(ucd); + } + } + } + } +} + + diff --git a/src/filedef.h b/src/filedef.h index d0e7c02..1d2d121 100644 --- a/src/filedef.h +++ b/src/filedef.h @@ -133,9 +133,10 @@ class FileDef : public Definition PackageDef *packageDef() const { return package; } void addUsingDirective(NamespaceDef *nd); - NamespaceList *getUsedNamespaces() const { return usingDirList; } + NamespaceSDict *getUsedNamespaces() const { return usingDirList; } void addUsingDeclaration(ClassDef *cd); - ClassList *getUsedClasses() const { return usingDeclList; } + ClassSDict *getUsedClasses() const { return usingDeclList; } + void combineUsingRelations(); bool generateSourceFile() const; @@ -186,8 +187,8 @@ class FileDef : public Definition QList<IncludeInfo> *includeList; QDict<IncludeInfo> *includedByDict; QList<IncludeInfo> *includedByList; - NamespaceList *usingDirList; - ClassList *usingDeclList; + NamespaceSDict *usingDirList; + ClassSDict *usingDeclList; //DefineList *defineList; QCString path; QCString filepath; diff --git a/src/latexgen.cpp b/src/latexgen.cpp index c931954..d425404 100644 --- a/src/latexgen.cpp +++ b/src/latexgen.cpp @@ -401,6 +401,7 @@ static void writeDefaultStyleSheetPart3(QTextStream &t) t << "\\setlength{\\parskip}{0.2cm}\n"; t << "\\addtocounter{secnumdepth}{1}\n"; t << "\\sloppy\n"; + t << "\\usepackage[T1]{fontenc}\n"; } void LatexGenerator::writeHeaderFile(QFile &f) diff --git a/src/memberdef.cpp b/src/memberdef.cpp index 3fd6791..139002e 100644 --- a/src/memberdef.cpp +++ b/src/memberdef.cpp @@ -271,6 +271,7 @@ MemberDef::MemberDef(const char *df,int dl, classDef=0; fileDef=0; redefines=0; + m_relatedAlso=0; redefinedBy=0; nspace=0; memDef=0; @@ -370,9 +371,11 @@ MemberDef::MemberDef(const char *df,int dl, { declArgList = 0; } - m_templateMaster=0; - classSectionSDict=0; - docsForDefinition=TRUE; + m_templateMaster = 0; + classSectionSDict = 0; + docsForDefinition = TRUE; + m_isTypedefValCached = FALSE; + m_cachedTypedefValue = 0; } /*! Destroys the member definition. */ diff --git a/src/memberdef.h b/src/memberdef.h index 4fe2ee0..cba40d1 100644 --- a/src/memberdef.h +++ b/src/memberdef.h @@ -175,6 +175,10 @@ class MemberDef : public Definition MemberDef *reimplements() const; MemberList *reimplementedBy() const; + // For function documentation that can also be found in a class's related func section. + void setRelatedAlso(ClassDef *cd) { m_relatedAlso=cd; } + ClassDef *relatedAlso() const { return m_relatedAlso; } + // enumeration specific members void insertEnumField(MemberDef *md); void setEnumScope(MemberDef *md); @@ -248,6 +252,11 @@ class MemberDef : public Definition void setBodyMember(MemberDef *md) { bodyMemb = md; } void setDocsForDefinition(bool b) { docsForDefinition = b; } + // cached typedef functions + bool isTypedefValCached() const { return m_isTypedefValCached; } + ClassDef *getCachedTypedefVal() const { return m_cachedTypedefValue; } + void cacheTypedefVal(ClassDef *val) { m_isTypedefValCached=TRUE; m_cachedTypedefValue=val; } + // declaration <-> definition relation void setMemberDefinition(MemberDef *md) { memDef=md; } void setMemberDeclaration(MemberDef *md) { memDec=md; } @@ -270,6 +279,7 @@ class MemberDef : public Definition MemberList *redefinedBy; // the list of members that redefine this one MemberDef *memDef; // member definition for this declaration MemberDef *memDec; // member declaration for this definition + ClassDef *m_relatedAlso; // points to class marked by relatedAlso ExampleSDict *exampleSDict; // a dictionary of all examples for quick access @@ -332,6 +342,10 @@ class MemberDef : public Definition MemberDef(const MemberDef &); MemberDef &operator=(const MemberDef &); static int s_indentLevel; + + bool m_isTypedefValCached; + ClassDef *m_cachedTypedefValue; + }; #endif diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp index edd0add..1146924 100644 --- a/src/namespacedef.cpp +++ b/src/namespacedef.cpp @@ -363,18 +363,24 @@ void NamespaceDef::addUsingDirective(NamespaceDef *nd) { if (usingDirList==0) { - usingDirList = new NamespaceList; + usingDirList = new NamespaceSDict; + } + if (usingDirList->find(nd->qualifiedName())==0) + { + usingDirList->append(nd->qualifiedName(),nd); } - usingDirList->append(nd); } void NamespaceDef::addUsingDeclaration(ClassDef *cd) { if (usingDeclList==0) { - usingDeclList = new ClassList; + usingDeclList = new ClassSDict; + } + if (usingDeclList->find(cd->qualifiedName())==0) + { + usingDeclList->append(cd->qualifiedName(),cd); } - usingDeclList->append(cd); } QCString NamespaceDef::getOutputFileBase() const @@ -418,3 +424,43 @@ QCString NamespaceDef::displayName() const return result; } +void NamespaceDef::combineUsingRelations() +{ + if (visited) return; // already done + visited=TRUE; + if (usingDirList) + { + NamespaceSDict::Iterator nli(*usingDirList); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + { + nd->combineUsingRelations(); + } + for (nli.toFirst();(nd=nli.current());++nli) + { + // add used namespaces of namespace nd to this namespace + if (nd->getUsedNamespaces()) + { + NamespaceSDict::Iterator unli(*nd->getUsedNamespaces()); + NamespaceDef *und; + for (unli.toFirst();(und=unli.current());++unli) + { + //printf("Adding namespace %s to the using list of %s\n",und->qualifiedName().data(),qualifiedName().data()); + addUsingDirective(und); + } + } + // add used classes of namespace nd to this namespace + if (nd->getUsedClasses()) + { + ClassSDict::Iterator cli(*nd->getUsedClasses()); + ClassDef *ucd; + for (cli.toFirst();(ucd=cli.current());++cli) + { + //printf("Adding class %s to the using list of %s\n",cd->qualifiedName().data(),qualifiedName().data()); + addUsingDeclaration(ucd); + } + } + } + } +} + diff --git a/src/namespacedef.h b/src/namespacedef.h index 34da0d5..4b3a3b3 100644 --- a/src/namespacedef.h +++ b/src/namespacedef.h @@ -54,9 +54,10 @@ class NamespaceDef : public Definition void computeAnchors(); int countMembers(); void addUsingDirective(NamespaceDef *nd); - NamespaceList *getUsedNamespaces() const { return usingDirList; } + NamespaceSDict *getUsedNamespaces() const { return usingDirList; } void addUsingDeclaration(ClassDef *cd); - ClassList *getUsedClasses() const { return usingDeclList; } + ClassSDict *getUsedClasses() const { return usingDeclList; } + void combineUsingRelations(); QCString displayName() const; bool isLinkableInProject() const @@ -108,14 +109,16 @@ class NamespaceDef : public Definition /*! Namespaces inside this namespace */ NamespaceSDict *namespaceSDict; + bool visited; + private: //QCString reference; QCString fileName; QStrList files; - NamespaceList *usingDirList; - ClassList *usingDeclList; + NamespaceSDict *usingDirList; + ClassSDict *usingDeclList; SDict<Definition> *m_innerCompounds; MemberList allMemberList; @@ -22,7 +22,6 @@ */ #include <stdio.h> -//#include <iostream.h> #include <assert.h> #include <ctype.h> diff --git a/src/scanner.l b/src/scanner.l index 1c33319..a895292 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -58,6 +58,7 @@ static int lastContext; static int lastCContext; static int lastDocContext; static int lastDocRelContext; +static int lastDocRelAlsoContext; static int lastCPPContext; static int lastSkipSharpContext; static int lastSkipRoundContext; @@ -428,7 +429,8 @@ static QCString extractName(const QCString &s) static void setContext() { QCString fileName = yyFileName; - insideIDL = fileName.right(4)==".idl" || fileName.right(4)==".odl"; + insideIDL = fileName.right(4)==".idl" || fileName.right(5)==".pidl" || + fileName.right(4)==".odl"; insideJava = fileName.right(5)==".java"; insideCS = fileName.right(3)==".cs"; insidePHP = fileName.right(4)==".php" || fileName.right(5)==".php4" || @@ -587,6 +589,7 @@ PHPKW ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;] %x ClassDocFuncExc %x ClassDocDefine %x ClassDocRelates +%x ClassDocRelatesAlso %x ClassDocBrief %x ClassDocOverload %x ClassDefineArgs @@ -1320,6 +1323,35 @@ PHPKW ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;] current->name = yytext; else current->name += yytext; + if (current->name.left(7)=="static ") + { + current->stat = TRUE; + current->name= current->name.mid(7); + } + else if (current->name.left(7)=="inline ") + { + if (current->type.isEmpty()) + { + current->type="inline"; + } + else + { + current->type+="inline "; + } + current->name= current->name.mid(7); + } + else if (current->name.left(6)=="const ") + { + if (current->type.isEmpty()) + { + current->type="const"; + } + else + { + current->type+="const "; + } + current->name=current->name.mid(6); + } } QCString tmp=yytext; if (nameIsOperator(tmp)) @@ -3617,6 +3649,19 @@ PHPKW ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;] } BEGIN( lastDocRelContext ); } +<ClassDoc,Doc,JavaDoc>{B}*{CMD}"relate"[sd]"also"{B}* { + lastDocRelAlsoContext = YY_START; + BEGIN( ClassDocRelatesAlso ); + } +<ClassDocRelatesAlso>({ID}"::")*{ID} { + current->relatesDup = TRUE; + current->relates = yytext; + if (current->mGrpId!=NOGROUP) + { + memberGroupRelates = yytext; + } + BEGIN( lastDocRelAlsoContext ); + } <NameSpaceDocArg1>{SCOPENAME} { current->name = yytext; newDocState(); diff --git a/src/searchindex.cpp b/src/searchindex.cpp index 36b416c..dcb86bc 100644 --- a/src/searchindex.cpp +++ b/src/searchindex.cpp @@ -19,116 +19,6 @@ #include "searchindex.h" #include <qfile.h> -#if 0 -#include "suffixtree.h" - -SearchIndex::SearchIndex() : refDict(10007), nameIndex(10007) -{ - indexCount=1; - //indexTree = new IndexTree; - suffixTree = new SuffixTree; -} - -SearchIndex::~SearchIndex() -{ - //delete indexTree; - delete suffixTree; -} - -void SearchIndex::addReference(const char *key,const char *ref) -{ - DocRef *dr=new DocRef(indexCount,key,ref); - nameIndex.insert(indexCount,dr); - refList.append(dr); - refDict.insert(key,dr); - indexCount++; -} - -bool SearchIndex::addWord(const char *key,const char *word,bool special) -{ - DocRef *dr=0; - if (word && key && strlen(key)>0 && (dr=refDict[key])) - { - suffixTree->insertWord(((QCString)word).lower(),dr->index(),special); - return TRUE; - } - else if (word) - { - printf("SearchIndex::addWord() key `%s' not found!\n",key); - return FALSE; - } - else - { - printf("SearchIndex::addWord() trying to insert word with length 0\n"); - return FALSE; - } -} - -bool SearchIndex::saveIndex(const char *fileName) -{ - QFile f(fileName); - if (!f.open(IO_WriteOnly)) return FALSE; - - // write header - if (f.writeBlock("DOXI",4)!=4) return FALSE; // write header - - // compute forward offsets for all children of each node. - suffixTree->resolveForwardReferences(); - - // compute offset to the reference index table - int offset=suffixTree->size()+9; - - // write the offset - if (writeNumber(f,offset)) return FALSE; - - // write the suffix tree - if (!suffixTree->write(f)) return FALSE; - - f.putch(0); - - // write the index reference table - DocRef *dr=refList.first(); - offset+=refList.count()*4; - while (dr) - { - writeNumber(f,offset); - offset+=strlen(dr->name())+strlen(dr->url())+2; - dr=refList.next(); - } - - // write the references - dr=refList.first(); - while (dr) - { - writeString(f,dr->name()); - writeString(f,dr->url()); - dr=refList.next(); - } - - //printf("Building index tree\n"); - printf("Size of the suffix tree is %d bytes\n",suffixTree->size()); - printf("Number of tree nodes is %d\n",suffixTree->numberOfNodes()); - printf("Number of links %d\n",indexCount); - //suffixTree->buildIndex(); - //printf("Computing reference offsets\n"); - //int offset=suffixTree->size()+8; - //indexTree->setOffsets(&nameIndex); - //printf("Saving suffix tree\n"); - //printf("Saving index tree\n"); - //result&=indexTree->write(f); - //printf("Saving reference list\n"); - //dr=refList.first(); - //while (dr) - //{ - // result&=!writeString(f,dr->name()); - // result&=!writeString(f,dr->url()); - // dr=refList.next(); - //} - //suffixTree->dump(); - return TRUE; -} -#endif - // file format: // 4 byte header diff --git a/src/sortdict.h b/src/sortdict.h index 5659d71..f019432 100644 --- a/src/sortdict.h +++ b/src/sortdict.h @@ -109,13 +109,15 @@ class SDict m_dict = new QDict<T>(size); #endif } + /*! Destroys the dictionary */ virtual ~SDict() { delete m_list; delete m_dict; } - /*! Appends a compound to the dictionary. The element is owned by the + + /*! Appends an element to the dictionary. The element is owned by the * dictionary. * \param key The unique key to use to quicky find the item later on. * \param d The compound to add. @@ -132,12 +134,32 @@ class SDict } #endif } + + /*! Prepends an element to the dictionary. The element is owned by the + * dictionary. + * \param key The unique key to use to quicky find the item later on. + * \param d The compound to add. + * \sa find() + */ + void prepend(const char *key,const T *d) + { + m_list->prepend(d); + m_dict->insert(key,d); +#if AUTORESIZE + if (m_dict->size()>SDict_primes[m_sizeIndex]) + { + m_dict->resize(SDict_primes[++m_sizeIndex]); + } +#endif + } + /*! Remove an item from the dictionary */ bool remove(const char *key) { T *item = m_dict->take(key); return item ? m_list->remove(item) : FALSE; } + /*! Sorts the members of the dictionary. First appending a number * of members and then sorting them is faster (O(NlogN) than using * inSort() for each member (O(N^2)). @@ -162,11 +184,13 @@ class SDict } #endif } + /*! Indicates whether or not the dictionary owns its elements */ void setAutoDelete(bool val) { m_list->setAutoDelete(val); } + /*! Looks up a compound given its key. * \param key The key to identify this element. * \return The requested compound or zero if it cannot be found. @@ -188,6 +212,7 @@ class SDict { return m_list->at(i); } + /*! Function that is used to compare two items when sorting. * Overload this to properly sort items. * \sa inSort() @@ -196,6 +221,7 @@ class SDict { return item1!=item2; } + /*! Clears the dictionary. Will delete items if setAutoDelete() was * set to \c TRUE. * \sa setAutoDelete @@ -205,6 +231,7 @@ class SDict m_list->clear(); m_dict->clear(); } + /*! Returns the number of items stored in the dictionary */ int count() @@ -225,11 +252,13 @@ class SDict { m_li = new QListIterator<T>(*dict.m_list); } + /*! Destroys the dictionary */ virtual ~Iterator() { delete m_li; } + /*! Set the iterator to the first element in the list. * \return The first compound, or zero if the list was empty. */ @@ -237,6 +266,7 @@ class SDict { return m_li->toFirst(); } + /*! Set the iterator to the last element in the list. * \return The first compound, or zero if the list was empty. */ @@ -244,11 +274,13 @@ class SDict { return m_li->toLast(); } + /*! Returns the current compound */ T *current() const { return m_li->current(); } + /*! Moves the iterator to the next element. * \return the new "current" element, or zero if the iterator was * already pointing at the last element. @@ -257,6 +289,7 @@ class SDict { return m_li->operator++(); } + /*! Moves the iterator to the previous element. * \return the new "current" element, or zero if the iterator was * already pointing at the first element. @@ -315,12 +348,14 @@ class SIntDict m_dict = new QIntDict<T>(size); #endif } + /*! Destroys the dictionary */ virtual ~SIntDict() { delete m_list; delete m_dict; } + /*! Appends a compound to the dictionary. The element is owned by the * dictionary. * \param key The unique key to use to quicky find the item later on. @@ -338,12 +373,32 @@ class SIntDict } #endif } + + /*! Prepend a compound to the dictionary. The element is owned by the + * dictionary. + * \param key The unique key to use to quicky find the item later on. + * \param d The compound to add. + * \sa find() + */ + void prepend(int key,const T *d) + { + m_list->prepend(d); + m_dict->insert(key,d); +#if AUTORESIZE + if (m_dict->size()>SDict_primes[m_sizeIndex]) + { + m_dict->resize(SDict_primes[++m_sizeIndex]); + } +#endif + } + /*! Remove an item from the dictionary */ bool remove(int key) { T *item = m_dict->take(key); return item ? m_list->remove(item) : FALSE; } + /*! Sorts the members of the dictionary. First appending a number * of members and then sorting them is faster (O(NlogN) than using * inSort() for each member (O(N^2)). @@ -352,6 +407,7 @@ class SIntDict { m_list->sort(); } + /*! Inserts a compound into the dictionary in a sorted way. * \param key The unique key to use to quicky find the item later on. * \param d The compound to add. @@ -368,11 +424,13 @@ class SIntDict } #endif } + /*! Indicates whether or not the dictionary owns its elements */ void setAutoDelete(bool val) { m_list->setAutoDelete(val); } + /*! Looks up a compound given its key. * \param key The key to identify this element. * \return The requested compound or zero if it cannot be found. @@ -394,6 +452,7 @@ class SIntDict { return m_list->at(i); } + /*! Function that is used to compare two items when sorting. * Overload this to properly sort items. * \sa inSort() @@ -402,6 +461,7 @@ class SIntDict { return item1!=item2; } + /*! Clears the dictionary. Will delete items if setAutoDelete() was * set to \c TRUE. * \sa setAutoDelete @@ -411,6 +471,7 @@ class SIntDict m_list->clear(); m_dict->clear(); } + /*! Returns the number of items stored in the dictionary */ int count() @@ -431,11 +492,13 @@ class SIntDict { m_li = new QListIterator<T>(*dict.m_list); } + /*! Destroys the dictionary */ virtual ~Iterator() { delete m_li; } + /*! Set the iterator to the first element in the list. * \return The first compound, or zero if the list was empty. */ @@ -443,6 +506,7 @@ class SIntDict { return m_li->toFirst(); } + /*! Set the iterator to the last element in the list. * \return The first compound, or zero if the list was empty. */ @@ -450,11 +514,13 @@ class SIntDict { return m_li->toLast(); } + /*! Returns the current compound */ T *current() const { return m_li->current(); } + /*! Moves the iterator to the next element. * \return the new "current" element, or zero if the iterator was * already pointing at the last element. @@ -463,6 +529,7 @@ class SIntDict { return m_li->operator++(); } + /*! Moves the iterator to the previous element. * \return the new "current" element, or zero if the iterator was * already pointing at the first element. diff --git a/src/translator_cz.h b/src/translator_cz.h index c2eb801..a4647ce 100644 --- a/src/translator_cz.h +++ b/src/translator_cz.h @@ -105,7 +105,7 @@ // use the approach. // - Removed the obsolete method trFiles(). // -// 2001/05/18 +// 2001/05/18 // - The trRelatedPagesDescription() content updated to fit // the context better. // - Implemented new method trAuthor(params). @@ -116,28 +116,16 @@ // - The trReimplementedInList() updated to fit the context better. // - The trReimplementedFromList() updated to fit the context better. // -// 2001/07/16 -// - trClassDocumentation() updated as in the English translator. -// -// 2001/11/06 -// - trReferences() implemented. -// -// 2002/01/23 -// - trImplementedFromList() and trImplementedInList() implemented -// (new since 1.2.13) -// -// 2002/03/05 -// - ... forgot to replace TranslatorAdapter... base class by Translator. -// -// 2002/07/08 (my birthday! ;) -// - The new trRTFTableOfContents() implemented. -// -// 2002/07/29 -// - The new trDeprecatedList() implemented. -// +// 2001/07/16 - trClassDocumentation() updated as in the English translator. +// 2001/11/06 - trReferences() implemented. +// 2002/01/23 - Two new methods "since 1.2.13" implemented. +// 2002/03/05 - ... forgot to replace TranslatorAdapter... by Translator. +// 2002/07/08 (my birthday! ;) - The new trRTFTableOfContents() implemented. +// 2002/07/29 - The new trDeprecatedList() implemented. // 2002/10/15 - The new trEvents() and trEventDocumentation() implemented. // 2003/04/28 - Five new methods "since 1.3" implemented. // 2003/06/10 - Two new methods "since 1.3.1" implemented. +// 2003/08/13 - Four new "since 1.3.3" implemented. // Todo // ---- @@ -157,7 +145,7 @@ // Windows version. The version which does not call the function is // probably slightly faster. -class TranslatorCzech : public TranslatorAdapter_1_3_3 +class TranslatorCzech : public Translator { private: /*! The decode() inline assumes the source written in the @@ -1608,6 +1596,56 @@ class TranslatorCzech : public TranslatorAdapter_1_3_3 return decode("Graf volání této funkce:"); } +////////////////////////////////////////////////////////////////////////// +// new since 1.3.3 +////////////////////////////////////////////////////////////////////////// + + /*! When the search engine is enabled this text is put in the index + * of each page before the search field. + */ + virtual QCString trSearchForIndex() + { + return decode("Vyhledat"); + } + /*! This string is used as the title for the page listing the search + * results. + */ + virtual QCString trSearchResultsTitle() + { + return decode("Výsledky vyhledávání"); + } + /*! This string is put just before listing the search results. The + * text can be different depending on the number of documents found. + * Inside the text you can put the special marker $num to insert + * the number representing the actual number of search results. + * The @a numDocuments parameter can be either 0, 1 or 2, where the + * value 2 represents 2 or more matches. HTML markup is allowed inside + * the returned string. + */ + virtual QCString trSearchResults(int numDocuments) + { + if (numDocuments==0) + { + return decode("Lituji. Vašemu dotazu neodpovídá žádný dokument."); + } + else if (numDocuments==1) + { + return decode("Nalezen jediný dokument, který vyhovuje vašemu dotazu."); + } + else + { + return decode("Nalezeno <b>$num</b> dokumentù, které vyhovují vašemu " + "dotazu. Nejlépe odpovídající dokumenty jsou zobrazeny " + "jako první."); + } + } + /*! This string is put before the list of matched words, for each search + * result. What follows is the list of words that matched the query. + */ + virtual QCString trSearchMatches() + { + return decode("Nalezená slova:"); + } }; #endif // TRANSLATOR_CZ_H diff --git a/src/translator_en.h b/src/translator_en.h index b22bd27..8ec8baa 100644 --- a/src/translator_en.h +++ b/src/translator_en.h @@ -1493,8 +1493,9 @@ class TranslatorEnglish : public Translator // new since 1.3.3 ////////////////////////////////////////////////////////////////////////// - /*! When the search engine is enabled this text is put in the index - * of each page before the search field. + /*! When the search engine is enabled this text is put in the header + * of each page before the field where one can enter the text to search + * for. */ virtual QCString trSearchForIndex() { diff --git a/src/translator_es.h b/src/translator_es.h index c3d39e2..0ba6422 100644 --- a/src/translator_es.h +++ b/src/translator_es.h @@ -25,7 +25,7 @@ #ifndef TRANSLATOR_ES_H #define TRANSLATOR_ES_H -class TranslatorSpanish : public TranslatorAdapter_1_2_7 +class TranslatorSpanish : public TranslatorAdapter_1_3_3 { public: virtual QCString idLanguage() @@ -355,9 +355,14 @@ class TranslatorSpanish : public TranslatorAdapter_1_2_7 virtual QCString trEnumerationValues() { return "Valores de la enumeración"; } - /*! This is used in man pages as the author section. */ - virtual QCString trAuthor() - { return "Autor"; } + /*! This text is generated when the \\author command is used and + * for the author section in man pages. */ + virtual QCString trAuthor(bool first_capital, bool singular) + { + QCString result((first_capital ? "Author" : "author")); + if (!singular) result+="s"; + return result; + } /*! This is used in the documentation of a file before the list of * documentation blocks for defines @@ -1221,7 +1226,122 @@ class TranslatorSpanish : public TranslatorAdapter_1_2_7 if (!singular) result+="es"; return result; } - + + /*! This text is put before the list of members referenced by a member + */ + virtual QCString trReferences() + { + return "Hace referencia a"; + } + + /*! used in member documentation blocks to produce a list of + * members that are implemented by this one. + */ + virtual QCString trImplementedFromList(int numEntries) + { + return "Implementa "+trWriteList(numEntries)+"."; + } + + /*! used in member documentation blocks to produce a list of + * all members that implement this abstract member. + */ + virtual QCString trImplementedInList(int numEntries) + { + return "Implementado en "+trWriteList(numEntries)+"."; + } + + /*! used in RTF documentation as a heading for the Table + * of Contents. + */ + virtual QCString trRTFTableOfContents() + { + return "Tabla de Contenidos"; + } + + /*! Used as the header of the list of item that have been + * flagged deprecated + */ + virtual QCString trDeprecatedList() + { + return "Lista de Desaprobados"; + } + + /*! Used as a header for declaration section of the events found in + * a C# program + */ + virtual QCString trEvents() + { + return "Eventos"; + } + + /*! Header used for the documentation section of a class' events. */ + virtual QCString trEventDocumentation() + { + return "Documentación de los Eventos"; + } + + /*! Used as a heading for a list of Java class types with package scope. + */ + virtual QCString trPackageTypes() + { + return "Tipos del Paquete"; + } + + /*! Used as a heading for a list of Java class functions with package + * scope. + */ + virtual QCString trPackageMembers() + { + return "Funciones del Paquete"; + } + + /*! Used as a heading for a list of static Java class functions with + * package scope. + */ + virtual QCString trStaticPackageMembers() + { + return "Funciones Estáticas del Paquete"; + } + + /*! Used as a heading for a list of Java class variables with package + * scope. + */ + virtual QCString trPackageAttribs() + { + return "Atributos del Paquete"; + } + + /*! Used as a heading for a list of static Java class variables with + * package scope. + */ + virtual QCString trStaticPackageAttribs() + { + return "Atributos Estáticos del Paquete"; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.3.1 +////////////////////////////////////////////////////////////////////////// + + /*! Used in the quick index of a class/file/namespace member list page + * to link to the unfiltered list of all members. + */ + virtual QCString trAll() + { + return "Todo"; + } + + /*! Put in front of the call graph for a function. */ + virtual QCString trCallGraph() + { + return "Gráfico de llamadas para esta función:"; + } + +////////////////////////////////////////////////////////////////////////// +// new since 1.3.3 +////////////////////////////////////////////////////////////////////////// + + }; diff --git a/src/util.cpp b/src/util.cpp index bab9314..d0a5635 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -399,7 +399,8 @@ int guessSection(const char *name) n.right(4)==".hxx" || n.right(4)==".hpp" || n.right(4)==".h++" || - n.right(4)==".idl" + n.right(4)==".idl" || + n.right(5)==".pidl" ) return Entry::HEADER_SEC; return 0; } @@ -542,180 +543,615 @@ NamespaceDef *getResolvedNamespace(const char *name) } } -static QDict<Definition> g_resolvedScopes; +//static QDict<Definition> g_resolvedScopes; +// +///* +// * find the fully qualified class name refered to by the input class +// * or typedef name against the input scope. +// * loops through scope and each of its parent scopes looking for a +// * match against the input name. Also recursively calls itself to check +// * against any imported namespaces in each scope being checked. +// */ +//ClassDef *getResolvedClassRecursive( +// Definition *scope, +// const char *n, +// bool *pIsTypeDef, +// QCString *pTemplSpec +// ) +//{ +// QCString name = n; +// // bail out if there is no name +// if (name.isEmpty()) return 0; +// // use the global scope if no scope was passed +// if (scope==0) scope=Doxygen::globalScope; +// ClassDef *cd=0; +// +// //printf("===================\n"); +// Definition *typedefScope = 0; +// //printf("-----------------------------------------------------\n"); +// QCString subst = resolveTypeDef(scope,name,&typedefScope); +// //printf("trying getResolvedClass(%s,%s) => subst=%s\n", +// // scope ? scope->name().data() : "<none>", name.data(),subst.data()); +// +// if (!subst.isEmpty()) +// { +// //printf(" typedef value=%s typedefScope=%s\n",subst.data(), +// // typedefScope?typedefScope->qualifiedName().data():0); +// +// // strip * and & from n +// int ip=subst.length()-1; +// while (ip>=0 && (subst.at(ip)=='*' || subst.at(ip)=='&' || +// subst.at(ip)==' ')) ip--; +// subst=subst.left(ip+1); +// +// if (pIsTypeDef) *pIsTypeDef=TRUE; +// if (subst==name) // avoid resolving "typedef struct foo foo"; +// { +// cd = Doxygen::classSDict.find(name); +// if (cd) goto found; +// } +// else +// { +// int count=0; // recursion detection guard +// QCString newSubst; +// QCString typeName = subst; +// //printf( "---> subst=%s\n",subst.data()); +// +// while (!(newSubst=resolveTypeDef(typedefScope,typeName)).isEmpty() +// && count<10) +// { +// //printf( "---> newSubst=%s\n",newSubst.data()); +// if (typeName==newSubst) +// { +// cd = Doxygen::classSDict.find(subst); // for breaking typedef struct A A; +// //printf(" getClass: exit `%s' %p\n",subst.data(),cd); +// if (cd) goto found; +// break; +// } +// subst=newSubst; +// // strip * and & from n +// int ip=subst.length()-1; +// while (ip>=0 && subst.at(ip)=='*' || subst.at(ip)=='&' || subst.at(ip)==' ') ip--; +// subst=subst.left(ip+1); +// //printf(" getResolvedClass `%s'->`%s'\n",name.data(),subst.data()); +// +// typeName=newSubst; +// //if (index!=-1) typeName.prepend(name.left(index)+"::"); +// count++; +// } +// if (count==10) +// { +// warn_cont("Warning: possible recursive typedef dependency detected for %s!\n",n); +// cd = Doxygen::classSDict.find(name); +// if (cd) goto found; +// } +// else +// { +// int i; +// if (typedefScope) +// { +// cd = Doxygen::classSDict.find(typedefScope->qualifiedName()+"::"+typeName); +// } +// if (cd==0) +// { +// cd = Doxygen::classSDict.find(typeName); +// } +// //printf(" getClass: subst %s->%s cd=%p\n",name.data(),typeName.data(),cd); +// if (cd==0 && (i=typeName.find('<'))>0) // try unspecialized version as well +// { +// if (pTemplSpec) *pTemplSpec = typeName.right(typeName.length()-i); +// cd = Doxygen::classSDict.find(typeName.left(i)); +// } +// //if (cd) goto found; +// } +// } +// // whether we found something or not, we stop searching to prevent +// // finding false positives. +// goto found; +// } +// else // not a typedef +// { +// do +// { +// //printf(" %s is not a typedef value in scope %s\n",name.data(),scope?scope->name().data():"<global>"); +// if (pIsTypeDef) *pIsTypeDef=FALSE; +// if (scope!=Doxygen::globalScope) +// { +// cd = Doxygen::classSDict.find(scope->name()+"::"+name); +// } +// else +// { +// cd = Doxygen::classSDict.find(name); +// } +// if (cd==0) +// { +// if (scope->definitionType()==Definition::TypeNamespace) +// { +// NamespaceDef *nscope = (NamespaceDef*)scope; +// ClassSDict *cl = nscope->getUsedClasses(); +// if (cl) // see if the class was imported via a using statement +// { +// ClassSDict::Iterator cli(*cl); +// ClassDef *ucd; +// for (cli.toFirst();(ucd=cli.current());++cli) +// { +// //printf("comparing %s<->%s\n",ucd->name().data(),name.data()); +// if (rightScopeMatch(ucd->name(),name)) +// { +// cd=ucd; +// break; +// } +// } +// } +// NamespaceSDict *nl = nscope->getUsedNamespaces(); +// if (nl) // check used namespaces for the class +// { +// NamespaceSDict::Iterator nli(*nl); +// NamespaceDef *und; +// for (nli.toFirst();(und=nli.current());++nli) +// { +// if (g_resolvedScopes.find(und->name())==0) +// { +// g_resolvedScopes.insert(und->name(),und); +// cd = getResolvedClassRecursive(und,name,pIsTypeDef,pTemplSpec); +// g_resolvedScopes.remove(und->name()); +// if (cd) break; +// } +// } +// } +// } +// } +// if (cd) goto found; +// +// if (scope==Doxygen::globalScope) scope=0; +// else if (scope) scope=scope->getOuterScope(); +// //fprintf(stderr,"scope=%p\n",scope); +// } while (scope); +// } +// +//found: +// //printf("getResolvedClass()=%s\n",cd?cd->name().data():"<none>"); +// return cd; +//} +// +// +//ClassDef *getOldResolvedClass( +// Definition *scope, +// const char *n, +// bool *pIsTypeDef, +// QCString *pTemplSpec +// ) +//{ +// g_resolvedScopes.clear(); +// return getResolvedClassRecursive(scope,n,pIsTypeDef,pTemplSpec); +//} +// + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + +static QDict<MemberDef> g_resolvedTypedefs; + +// forward declaration +ClassDef *getResolvedClassRec(Definition *scope, + FileDef *fileScope, + const char *n, + bool *pIsTypeDef, + QCString *pTemplSpec + ); +int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item, + const QCString &explicitScopePart); + +/*! Returns the class representing the value of the typedef represented by md. + * + * Example: typedef A T; will return the class representing A if it is a class. + * + * Example: typedef int T; will return 0, since "int" is not a class. + */ +ClassDef *newResolveTypedef(FileDef *fileScope,MemberDef *md,QCString *pTemplSpec) +{ + bool isCached = md->isTypedefValCached(); // value already cached + if (isCached) + { + return md->getCachedTypedefVal(); + } + QCString qname = md->qualifiedName(); + if (g_resolvedTypedefs.find(qname)) return 0; // typedef already done -ClassDef *getResolvedClassRecursive( - Definition *scope, - const char *n, - bool *pIsTypeDef, - QCString *pTemplSpec - ) + g_resolvedTypedefs.insert(qname,md); // put on the trace list + + QCString type = md->typeString(); // get the "value" of the typedef + int ip=type.length()-1; // remove * and & at the end + while (ip>=0 && (type.at(ip)=='*' || type.at(ip)=='&' || type.at(ip)==' ')) + { + ip--; + } + type=type.left(ip+1); + if (type.left(6)=="const ") // strip leading "const" + { + type=type.mid(6); + } + if (type.left(7)=="struct ") // strip leading "struct" + { + } + else if (type.left(6)=="union ") // or strip leading "union" + { + } + type=type.stripWhiteSpace(); // strip leading and trailing whitespace + ClassDef *result = getResolvedClassRec(md->getOuterScope(),fileScope,type,0,0); + if (result==0) + { + // try unspecialized version if type is template + int i=type.find('<'); + if (i!=-1) // typedef of a template => try the unspecialized version + { + *pTemplSpec = type.mid(i); + result = getResolvedClassRec(md->getOuterScope(),fileScope,type.left(i),0,0); + } + } + + // remember computed value for next time + md->cacheTypedefVal(result); + + g_resolvedTypedefs.remove(qname); // remove from the trace list + + return result; +} + +/*! Substitutes a simple unqualified \a name within \a scope. Returns the + * value of the typedef or \a name if no typedef was found. + */ +QCString substTypedef(Definition *scope,FileDef *fileScope,const QCString &name) { - QCString name = n; - if (scope==0) scope=Doxygen::globalScope; - if (name.isEmpty()) return 0; - ClassDef *cd=0; - - //printf("===================\n"); - do - { - Definition *typedefScope = 0; - //printf("-----------------------------------------------------\n"); - QCString subst = resolveTypeDef(scope,name,&typedefScope); - //printf("trying getResolvedClass(%s,%s) => subst=%s\n", - // scope ? scope->name().data() : "<none>", name.data(),subst.data()); - - if (!subst.isEmpty()) - { - //printf(" typedef value=%s typedefScope=%s\n",subst.data(), - // typedefScope?typedefScope->qualifiedName().data():0); - - // strip * and & from n - int ip=subst.length()-1; - while (ip>=0 && (subst.at(ip)=='*' || subst.at(ip)=='&' || - subst.at(ip)==' ')) ip--; - subst=subst.left(ip+1); - - if (pIsTypeDef) *pIsTypeDef=TRUE; - if (subst==name) // avoid resolving "typedef struct foo foo"; - { - cd = Doxygen::classSDict.find(name); - if (cd) goto found; - } - else + QCString result=name; + if (name.isEmpty()) return result; + + // lookup scope fragment in the symbol map + DefinitionList *dl = Doxygen::symbolMap->find(name); + if (dl==0) return result; // no matches + + // search for the best match + DefinitionListIterator dli(*dl); + Definition *d; + int minDistance=10000; // init at "infinite" + MemberDef *bestMatch=0; + for (dli.toFirst();(d=dli.current());++dli) // foreach definition + { + // only look at members + if (d->definitionType()==Definition::TypeMember) + { + // that are also typedefs + MemberDef *md = (MemberDef *)d; + if (md->isTypedef()) // d is a typedef { - int count=0; // recursion detection guard - QCString newSubst; - QCString typeName = subst; - //printf( "---> subst=%s\n",subst.data()); - - while (!(newSubst=resolveTypeDef(typedefScope,typeName)).isEmpty() - && count<10) + // test accessibility of typedef within scope. + int distance = isAccessibleFrom(scope,fileScope,d,""); + if (distance!=-1 && distance<minDistance) + // definition is accessible and a better match { - //printf( "---> newSubst=%s\n",newSubst.data()); - if (typeName==newSubst) - { - cd = Doxygen::classSDict.find(subst); // for breaking typedef struct A A; - //printf(" getClass: exit `%s' %p\n",subst.data(),cd); - if (cd) goto found; - break; - } - subst=newSubst; - // strip * and & from n - int ip=subst.length()-1; - while (ip>=0 && subst.at(ip)=='*' || subst.at(ip)=='&' || subst.at(ip)==' ') ip--; - subst=subst.left(ip+1); - //printf(" getResolvedClass `%s'->`%s'\n",name.data(),subst.data()); - - typeName=newSubst; - //if (index!=-1) typeName.prepend(name.left(index)+"::"); - count++; + minDistance=distance; + bestMatch = md; } - if (count==10) - { - warn_cont("Warning: possible recursive typedef dependency detected for %s!\n",n); - cd = Doxygen::classSDict.find(name); - if (cd) goto found; - } - else + } + } + } + if (bestMatch) result = bestMatch->typeString(); + //printf("substTypedef(%s,%s)=%s\n",scope?scope->name().data():"<global>", + // name.data(),result.data()); + return result; +} + +/*! Starting with scope \a start, the string \a path is interpreted as + * a part of a qualified scope name (e.g. A::B::C), and the scope is + * searched. If found the scope definition is returned, otherwise 0 + * is returned. + */ +static Definition *followPath(Definition *start,FileDef *fileScope,const QCString &path) +{ + int is,ps=0; + int l; + Definition *current=start; + // for each part of the explicit scope + while ((is=getScopeFragment(path,ps,&l))!=-1) + { + // try to resolve the part if it is a typedef + QCString qualScopePart = substTypedef(current,fileScope,path.mid(is,l)); + current = current->findInnerCompound(qualScopePart); + if (current==0) break; // failed to follow the path + ps=is+l; + } + return current; // path could be followed +} + +bool accessibleViaUsingClass(const ClassSDict *cl,FileDef *fileScope,Definition *item,const QCString &explicitScopePart="") +{ + if (cl) // see if the class was imported via a using statement + { + ClassSDict::Iterator cli(*cl); + ClassDef *ucd; + for (cli.toFirst();(ucd=cli.current());++cli) + { + Definition *sc = explicitScopePart.isEmpty() ? ucd : followPath(ucd,fileScope,explicitScopePart); + if (item->definitionType()==Definition::TypeMember) + { + MemberDef *md = (MemberDef *)item; + if (md->isTypedef()) // d is a typedef { - int i; - if (typedefScope) - { - cd = Doxygen::classSDict.find(typedefScope->qualifiedName()+"::"+typeName); - } - if (cd==0) - { - cd = Doxygen::classSDict.find(typeName); - } - //printf(" getClass: subst %s->%s cd=%p\n",name.data(),typeName.data(),cd); - if (cd==0 && (i=typeName.find('<'))>0) // try unspecialized version as well - { - if (pTemplSpec) *pTemplSpec = typeName.right(typeName.length()-i); - cd = Doxygen::classSDict.find(typeName.left(i)); - } - //if (cd) goto found; + QCString spec; + ClassDef *typedefClass = newResolveTypedef(fileScope,md,&spec); + if (sc && sc==typedefClass) return TRUE; } } - // whether we found something or not, we stop searching to prevent - // finding false positives. - goto found; + else // item is a class + { + if (sc && sc==item) return TRUE; + } + } + } + return FALSE; +} + +bool accessibleViaUsingNamespace(const NamespaceSDict *nl,FileDef *fileScope,Definition *item,const QCString &explicitScopePart="") +{ + if (nl) // check used namespaces for the class + { + NamespaceSDict::Iterator nli(*nl); + NamespaceDef *und; + for (nli.toFirst();(und=nli.current());++nli) + { + Definition *sc = explicitScopePart.isEmpty() ? und : followPath(und,fileScope,explicitScopePart); + if (sc && item->getOuterScope()==sc) return TRUE; } - else // not a typedef + } + return FALSE; +} + +/* Returns the "distance" (=number of levels up) from item to scope, or -1 + * if item in not inside scope. + */ +int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item) +{ + //printf("<isAccesibleFrom(%s,%s)\n",scope?scope->name().data():"<global>", + // item?item->name().data():"<none>"); + if (item->getOuterScope()==scope) + { + //printf("> found it\n"); + return 0; // found it + } + else if (scope==Doxygen::globalScope) + { + if (fileScope) + { + ClassSDict *cl = fileScope->getUsedClasses(); + if (accessibleViaUsingClass(cl,fileScope,item)) return 0; + NamespaceSDict *nl = fileScope->getUsedNamespaces(); + if (accessibleViaUsingNamespace(nl,fileScope,item)) return 0; + } + return -1; // not found in path to globalScope + //printf("> reached global scope\n"); + } + else // keep searching + { + // check if scope is a namespace, which is using other classes and namespaces + if (scope->definitionType()==Definition::TypeNamespace) + { + NamespaceDef *nscope = (NamespaceDef*)scope; + ClassSDict *cl = nscope->getUsedClasses(); + if (accessibleViaUsingClass(cl,fileScope,item)) return 0; + NamespaceSDict *nl = nscope->getUsedNamespaces(); + if (accessibleViaUsingNamespace(nl,fileScope,item)) return 0; + } + + // repeat for the parent scope + int i=isAccessibleFrom(scope->getOuterScope(),fileScope,item); + //printf("> continue\n"); + return (i==-1) ? -1 : i+1; + } +} + + +/* Returns the "distance" (=number of levels up) from item to scope, or -1 + * if item in not in this scope. The explicitScopePart limits the search + * to scopes that match \a scope plus the explicit part. + */ +int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item, + const QCString &explicitScopePart) +{ + if (explicitScopePart.isEmpty()) + { + // handle degenerate case where there is no explicit scope. + return isAccessibleFrom(scope,fileScope,item); + } + //printf("<isAccesibleFrom(%s,%s,%s)\n",scope?scope->name().data():"<global>", + // item?item->name().data():"<none>", + // explicitScopePart.data()); + Definition *newScope = followPath(scope,fileScope,explicitScopePart); + if (newScope) // explicitScope is inside scope => newScope is the result + { + //printf("scope traversal successful!\n"); + if (item->getOuterScope()==newScope) + { + //printf("> found it\n"); + return 0; // found it + } + else { - //printf(" %s is not a typedef value in scope %s\n",name.data(),scope?scope->name().data():"<global>"); - if (pIsTypeDef) *pIsTypeDef=FALSE; - if (scope!=Doxygen::globalScope) + // repeat for the parent scope + int i=-1; + if (scope!=Doxygen::globalScope) { - cd = Doxygen::classSDict.find(scope->name()+"::"+name); + i = isAccessibleFrom(scope->getOuterScope(),fileScope,item,explicitScopePart); } - else + //printf("> continue\n"); + return (i==-1) ? -1 : i+1; + } + } + else // failed to resolve explicitScope + { + //printf("failed to resolve: scope=%s\n",scope->name().data()); + if (scope->definitionType()==Definition::TypeNamespace) + { + NamespaceDef *nscope = (NamespaceDef*)scope; + ClassSDict *cl = nscope->getUsedClasses(); + if (accessibleViaUsingClass(cl,fileScope,item,explicitScopePart)) return 0; + NamespaceSDict *nl = nscope->getUsedNamespaces(); + if (accessibleViaUsingNamespace(nl,fileScope,item,explicitScopePart)) return 0; + } + if (scope==Doxygen::globalScope) + { + if (fileScope) { - cd = Doxygen::classSDict.find(name); + ClassSDict *cl = fileScope->getUsedClasses(); + if (accessibleViaUsingClass(cl,fileScope,item,explicitScopePart)) return 0; + NamespaceSDict *nl = fileScope->getUsedNamespaces(); + if (accessibleViaUsingNamespace(nl,fileScope,item,explicitScopePart)) return 0; } - if (cd==0) + //printf("> reached global scope\n"); + return -1; + } + else // continue by looking into the parent scope + { + int i=isAccessibleFrom(scope->getOuterScope(),fileScope,item,explicitScopePart); + //printf("> continue\n"); + return (i==-1) ? -1 : i+1; + } + } +} + +/* Find the fully qualified class name refered to by the input class + * or typedef name against the input scope. + * Loops through scope and each of its parent scopes looking for a + * match against the input name. Can recursively call itself when + * resolving typedefs. + */ +ClassDef *getResolvedClassRec(Definition *scope, + FileDef *fileScope, + const char *n, + bool *pIsTypeDef, + QCString *pTemplSpec + ) +{ + //printf("[getResolvedClassRec(%s,%s)\n",scope?scope->name().data():"<global>",n); + QCString name=n; + QCString explicitScopePart; + + int qualifierIndex = name.findRev("::"); // todo: deal with cases like A<B::C> + if (qualifierIndex!=-1) // qualified name + { + // split off the explicit scope part + explicitScopePart=name.left(qualifierIndex); + // todo: improve namespace alias substitution + replaceNamespaceAliases(explicitScopePart,explicitScopePart.length()); + name=name.mid(qualifierIndex+2); + } + if (name.isEmpty()) return 0; // empty name + + DefinitionList *dl = Doxygen::symbolMap->find(name); + //printf("Looking for symbol %s result=%p\n",name.data(),dl); + if (dl==0) return 0; // symbol not found + + //printf(" found %d symbol with name %s\n",dl->count(),name.data()); + // now we look int the list of Definitions and determine which one is the "best" + DefinitionListIterator dli(*dl); + Definition *d; + ClassDef *bestMatch=0; + bool bestIsTypedef=FALSE; + QCString bestTemplSpec; + int minDistance=10000; // init at "infinite" + for (dli.toFirst();(d=dli.current());++dli) // foreach definition + { + //printf(" found type %x name=%s\n",d->definitionType(),d->name().data()); + // only look at classes and members + if (d->definitionType()==Definition::TypeClass || + d->definitionType()==Definition::TypeMember) + { + // test accessibility of definition within scope. + int distance = isAccessibleFrom(scope,fileScope,d,explicitScopePart); + if (distance!=-1) // definition is accessible { - if (scope->definitionType()==Definition::TypeNamespace) + // see if we are dealing with a class or a typedef + if (d->definitionType()==Definition::TypeClass) // d is a class { - NamespaceDef *nscope = (NamespaceDef*)scope; - ClassList *cl = nscope->getUsedClasses(); - if (cl) // see if the class was imported via a using statement + if (distance<minDistance) // found a definition that is "closer" { - ClassListIterator cli(*cl); - ClassDef *ucd; - for (cli.toFirst();(ucd=cli.current());++cli) - { - //printf("comparing %s<->%s\n",ucd->name().data(),name.data()); - if (rightScopeMatch(ucd->name(),name)) - { - cd=ucd; - break; - } - } + minDistance=distance; + bestMatch = (ClassDef *)d; + bestIsTypedef = FALSE; + bestTemplSpec.resize(0); } - NamespaceList *nl = nscope->getUsedNamespaces(); - if (nl) // check used namespaces for the class + } + else if (d->definitionType()==Definition::TypeMember) + { + MemberDef *md = (MemberDef *)d; + if (md->isTypedef()) // d is a typedef { - NamespaceListIterator nli(*nl); - NamespaceDef *und; - for (nli.toFirst();(und=nli.current());++nli) + QCString spec; + ClassDef *typedefClass = newResolveTypedef(fileScope,md,&spec); + + // we found a symbol at this distance, but if it didn't + // resolve to a class, we still have to make sure that + // something at a greater distance does not match, since + // that symbol is hidden by this one. + if (distance<minDistance) { - if (g_resolvedScopes.find(und->name())==0) - { - g_resolvedScopes.insert(und->name(),und); - cd = getResolvedClassRecursive(und,name,pIsTypeDef,pTemplSpec); - g_resolvedScopes.remove(und->name()); - if (cd) break; - } + minDistance=distance; + bestMatch = typedefClass; + bestIsTypedef = TRUE; + bestTemplSpec = spec; } + } } - } - if (cd) goto found; - } - - if (scope==Doxygen::globalScope) scope=0; - else if (scope) scope=scope->getOuterScope(); - //fprintf(stderr,"scope=%p\n",scope); - } while (scope); - -found: - //printf("getResolvedClass()=%s\n",cd?cd->name().data():"<none>"); - return cd; + } // if definition accessible + } // if definition is a class or member + } // foreach definition + if (pIsTypeDef) + { + *pIsTypeDef = bestIsTypedef; + } + if (pTemplSpec) + { + *pTemplSpec = bestTemplSpec; + } + //printf("] bestMatch=%s\n",bestMatch?bestMatch->name().data():"<none>"); + return bestMatch; } - -ClassDef *getResolvedClass( - Definition *scope, +/* Find the fully qualified class name refered to by the input class + * or typedef name against the input scope. + * Loops through scope and each of its parent scopes looking for a + * match against the input name. + */ +ClassDef *getResolvedClass(Definition *scope, + FileDef *fileScope, const char *n, bool *pIsTypeDef, QCString *pTemplSpec ) { - g_resolvedScopes.clear(); - return getResolvedClassRecursive(scope,n,pIsTypeDef,pTemplSpec); + g_resolvedTypedefs.clear(); + if (scope==0 || + (scope->definitionType()!=Definition::TypeClass && + scope->definitionType()!=Definition::TypeNamespace + ) + ) + { + scope=Doxygen::globalScope; + } + ClassDef *result = getResolvedClassRec(scope,fileScope,n,pIsTypeDef,pTemplSpec); + if (result && !result->isLinkable()) result=0; // don't link to artifical classes + //printf("getResolvedClass(%s,%s)=%s\n",scope?scope->name().data():"<global>", + // n,result?result->name().data():"<none>"); + return result; } +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + static bool findOperator(const QCString &s,int i) { int b = s.findRev("operator",i); @@ -773,7 +1209,12 @@ QCString removeRedundantWhiteSpace(const QCString &s) result+=' '; result+=s.at(i); } - else if (c==':' && csp==6) + else if (c=='t' && csp==5) // prevent const ::A from being converted to const::A + { + result+="t "; + csp=0; + } + else if (c==':' && csp==6) // replace const::A by const ::A { result+=" :"; csp=0; @@ -882,25 +1323,26 @@ void linkifyText(const TextGeneratorIntf &out,Definition *scope,const char * /*n //printf("word=`%s' scope=`%s'\n", // word.data(),scope ? scope->name().data() : "<none>" // ); - Definition *curScope = scope; +// Definition *curScope = scope; // check if `word' is a documented class name //int scopeOffset=scopeName.length(); - do // for each scope (starting with full scope and going to empty scope) - { +// do // for each scope (starting with full scope and going to empty scope) +// { //printf("Searching %s in %s...\n",word.data(),curScope?curScope->name().data():"<global>"); - QCString fullName = word; - QCString prefix; - replaceNamespaceAliases(fullName,fullName.length()); - //if (scopeOffset>0) - if (curScope && curScope!=Doxygen::globalScope) - { - prefix = curScope->name(); - replaceNamespaceAliases(prefix,prefix.length()); - fullName.prepend(prefix+"::"); - } - - bool isTypeDef=FALSE; - if ((cd=getResolvedClass(scope,fullName,&isTypeDef))) +// QCString fullName = word; +// QCString prefix; +// replaceNamespaceAliases(fullName,fullName.length()); +// //if (scopeOffset>0) +// if (curScope && curScope!=Doxygen::globalScope) +// { +// prefix = curScope->name(); +// replaceNamespaceAliases(prefix,prefix.length()); +// fullName.prepend(prefix+"::"); +// } + +// bool isTypeDef=FALSE; + if ((cd=getResolvedClass(scope,0,word/*fullName,&isTypeDef*/))) + // todo: fill in fileScope { // add link to the result if (external ? cd->isLinkable() : cd->isLinkableInProject()) @@ -909,16 +1351,16 @@ void linkifyText(const TextGeneratorIntf &out,Definition *scope,const char * /*n found=TRUE; } } - else if (isTypeDef) - { - goto endloop; - } +// else if (isTypeDef) +// { +// goto endloop; +// } - if (curScope) curScope = curScope->getOuterScope(); - } //while (!found && scopeOffset>=0); - while (!found && curScope); +// if (curScope) curScope = curScope->getOuterScope(); +// } //while (!found && scopeOffset>=0); +// while (!found && curScope); -endloop: +//endloop: if (scope && (scope->definitionType()==Definition::TypeClass || scope->definitionType()==Definition::TypeNamespace @@ -1551,10 +1993,10 @@ void stripIrrelevantConstVolatile(QCString &s) if (s=="volatile") { s.resize(0); return; } // strip occurrences of const - int constLen=6; + int constLen=5+1; i = s.find("const "); if (i==-1 && s.right(5)=="const") { i=s.length()-5;constLen=5; } - if (i!=-1) + while (i!=-1) { // no & or * after the const int i1=s.find('*',i+constLen); @@ -1562,19 +2004,21 @@ void stripIrrelevantConstVolatile(QCString &s) if (i1==-1 && i2==-1) { s=s.left(i)+s.right(s.length()-i-constLen); + i-=constLen; } else if ((i1!=-1 && i<i1) || (i2!=-1 && i<i2)) // const before * or & { // move const to front s=(QCString)"const "+s.left(i)+s.right(s.length()-i-constLen); } + i = s.find("const ",i+constLen); } // strip occurrences of volatile - int volatileLen=6; + int volatileLen=8+1; i = s.find("volatile "); if (i==-1 && s.right(8)=="volatile") { i=s.length()-8;constLen=8; } - if (i!=-1) + while (i!=-1) { // no & or * after the volatile int i1=s.find('*',i+volatileLen); @@ -1582,12 +2026,14 @@ void stripIrrelevantConstVolatile(QCString &s) if (i1==-1 && i2==-1) { s=s.left(i)+s.right(s.length()-i-volatileLen); + i-=volatileLen; } else if ((i1!=-1 && i<i1) || (i2!=-1 && i<i2)) // volatile before * or & { // move volatile to front s=(QCString)"volatile "+s.left(i)+s.right(s.length()-i-volatileLen); } + i = s.find("volatile ",i+volatileLen); } //printf("%s\n",s.data()); } @@ -1602,8 +2048,8 @@ void stripIrrelevantConstVolatile(QCString &s) static bool matchArgument(const Argument *srcA,const Argument *dstA, const QCString &className, const QCString &namespaceName, - NamespaceList *usingNamespaces, - ClassList *usingClasses) + NamespaceSDict *usingNamespaces, + ClassSDict *usingClasses) { //printf("match argument start %s:%s <-> %s:%s using nsp=%p class=%p\n", // srcA->type.data(),srcA->name.data(), @@ -1707,7 +2153,7 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA, } if (usingNamespaces && usingNamespaces->count()>0) { - NamespaceListIterator nli(*usingNamespaces); + NamespaceSDict::Iterator nli(*usingNamespaces); NamespaceDef *nd; for (;(nd=nli.current());++nli) { @@ -1717,7 +2163,7 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA, } if (usingClasses && usingClasses->count()>0) { - ClassListIterator cli(*usingClasses); + ClassSDict::Iterator cli(*usingClasses); ClassDef *cd; for (;(cd=cli.current());++cli) { @@ -1869,8 +2315,8 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA, */ bool matchArguments(ArgumentList *srcAl,ArgumentList *dstAl, const char *cl,const char *ns,bool checkCV, - NamespaceList *usingNamespaces, - ClassList *usingClasses) + NamespaceSDict *usingNamespaces, + ClassSDict *usingClasses) { QCString className=cl; QCString namespaceName=ns; @@ -2162,7 +2608,8 @@ bool getDefs(const QCString &scName,const QCString &memberName, //printf("Trying class scope %s\n",className.data()); ClassDef *fcd=0; - if ((fcd=getResolvedClass(Doxygen::globalScope,className)) && // is it a documented class + // todo: fill in correct fileScope! + if ((fcd=getResolvedClass(Doxygen::globalScope,0,className)) && // is it a documented class fcd->isLinkable() ) { @@ -40,7 +40,7 @@ class ExampleSDict; class ClassSDict; class BaseClassList; class GroupDef; -class NamespaceList; +class NamespaceSDict; class ClassList; class MemberGroupSDict; class Definition; @@ -121,17 +121,18 @@ void writePageRef(OutputDocInterface &od,const char *cn,const char *mn); bool matchArguments(ArgumentList *,ArgumentList *, const char *cl=0,const char *ns=0,bool checkCV=TRUE, - NamespaceList *usingNamespaces=0, - ClassList *usingClasses=0); + NamespaceSDict *usingNamespaces=0, + ClassSDict *usingClasses=0); void mergeArguments(ArgumentList *,ArgumentList *,bool forceNameOverwrite=FALSE); QCString substituteClassNames(const QCString &s); QCString substitute(const char *s,const char *src,const char *dst); QCString resolveDefines(const char *n); ClassDef *getClass(const char *key); ClassDef *getResolvedClass(Definition *scope, - const char *key, - bool *pIsTypeDef=0, - QCString *pTemplSpec=0); + FileDef *fileScope, + const char *key, + bool *pIsTypeDef=0, + QCString *pTemplSpec=0); NamespaceDef *getResolvedNamespace(const char *key); FileDef *findFileDef(const FileNameDict *fnDict,const char *n, bool &ambig); @@ -201,6 +202,9 @@ QCString rtfFormatBmkStr(const char *name); QCString linkToText(const char *link,bool isFileName); QCString stripExtension(const char *fName); void replaceNamespaceAliases(QCString &scope,int i); +int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item); +int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item, + const QCString &explicitScopePart); #endif |