summaryrefslogtreecommitdiffstats
path: root/src/util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.cpp')
-rw-r--r--src/util.cpp3896
1 files changed, 1097 insertions, 2799 deletions
diff --git a/src/util.cpp b/src/util.cpp
index abcd910..7fcd5ed 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,11 +1,11 @@
/*****************************************************************************
- *
+ *
*
* Copyright (C) 1997-2015 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby
- * granted. No representations are made about the suitability of this software
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
@@ -19,6 +19,11 @@
#include <errno.h>
#include <math.h>
#include <limits.h>
+#include <cinttypes>
+#include <string.h>
+
+#include <mutex>
+#include <unordered_set>
#include "md5.h"
@@ -26,7 +31,6 @@
#include <qfileinfo.h>
#include <qdir.h>
#include <qdatetime.h>
-#include <qcache.h>
#include "util.h"
#include "message.h"
@@ -63,6 +67,7 @@
#include "membergroup.h"
#include "dirdef.h"
#include "htmlentity.h"
+#include "symbolresolver.h"
#define ENABLE_TRACINGSUPPORT 0
@@ -78,29 +83,20 @@
//------------------------------------------------------------------------
-// selects one of the name to sub-dir mapping algorithms that is used
-// to select a sub directory when CREATE_SUBDIRS is set to YES.
-
-#define ALGO_COUNT 1
-#define ALGO_CRC16 2
-#define ALGO_MD5 3
-
-//#define MAP_ALGO ALGO_COUNT
-//#define MAP_ALGO ALGO_CRC16
-#define MAP_ALGO ALGO_MD5
-
#define REL_PATH_TO_ROOT "../../"
+static const char *hex = "0123456789ABCDEF";
+
//------------------------------------------------------------------------
// TextGeneratorOLImpl implementation
//------------------------------------------------------------------------
-TextGeneratorOLImpl::TextGeneratorOLImpl(OutputDocInterface &od) : m_od(od)
+TextGeneratorOLImpl::TextGeneratorOLImpl(OutputDocInterface &od) : m_od(od)
{
}
void TextGeneratorOLImpl::writeString(const char *s,bool keepSpaces) const
-{
+{
if (s==0) return;
//printf("TextGeneratorOlImpl::writeString('%s',%d)\n",s,keepSpaces);
if (keepSpaces)
@@ -113,19 +109,19 @@ void TextGeneratorOLImpl::writeString(const char *s,bool keepSpaces) const
cs[1]='\0';
while ((c=*p++))
{
- if (c==' ') m_od.writeNonBreakableSpace(1);
+ if (c==' ') m_od.writeNonBreakableSpace(1);
else cs[0]=c,m_od.docify(cs);
}
}
}
else
{
- m_od.docify(s);
+ m_od.docify(s);
}
}
void TextGeneratorOLImpl::writeBreak(int indent) const
-{
+{
m_od.lineBreak("typebreak");
int i;
for (i=0;i<indent;i++)
@@ -146,9 +142,9 @@ void TextGeneratorOLImpl::writeLink(const char *extRef,const char *file,
//------------------------------------------------------------------------
// an inheritance tree of depth of 100000 should be enough for everyone :-)
-const int maxInheritanceDepth = 100000;
+const int maxInheritanceDepth = 100000;
-/*!
+/*!
Removes all anonymous scopes from string s
Possible examples:
\verbatim
@@ -177,9 +173,9 @@ QCString removeAnonymousScopes(const QCString &s)
while (c<i+l && s.at(c)!='@') if (s.at(c++)==':') b1=TRUE;
c=i+l-1;
while (c>=i && s.at(c)!='@') if (s.at(c--)==':') b2=TRUE;
- if (b1 && b2)
- {
- result+="::";
+ if (b1 && b2)
+ {
+ result+="::";
}
p=i+l;
}
@@ -224,7 +220,7 @@ QCString stripAnonymousNamespaceScope(const QCString &s)
while ((i=getScopeFragment(s,p,&l))!=-1)
{
//printf("Scope fragment %s\n",s.mid(i,l).data());
- if (Doxygen::namespaceSDict->find(s.left(i+l))!=0)
+ if (Doxygen::namespaceLinkedMap->find(s.left(i+l))!=0)
{
if (s.at(i)!='@')
{
@@ -248,7 +244,7 @@ done:
void writePageRef(OutputDocInterface &od,const char *cn,const char *mn)
{
od.pushGeneratorState();
-
+
od.disable(OutputGenerator::Html);
od.disable(OutputGenerator::Man);
od.disable(OutputGenerator::Docbook);
@@ -273,22 +269,20 @@ QCString generateMarker(int id)
return result;
}
-static QCString stripFromPath(const QCString &path,QStrList &l)
+static QCString stripFromPath(const QCString &path,const StringVector &l)
{
- // look at all the strings in the list and strip the longest match
- const char *s=l.first();
+ // look at all the strings in the list and strip the longest match
QCString potential;
unsigned int length = 0;
- while (s)
+ for (const auto &s : l)
{
- QCString prefix = s;
+ QCString prefix = s.c_str();
if (prefix.length() > length &&
qstricmp(path.left(prefix.length()),prefix)==0) // case insensitive compare
{
length = prefix.length();
potential = path.right(path.length()-prefix.length());
}
- s = l.next();
}
if (length) return potential;
return path;
@@ -311,7 +305,7 @@ QCString stripFromIncludePath(const QCString &path)
}
/*! try to determine if \a name is a source or a header file name by looking
- * at the extension. A number of variations is allowed in both upper and
+ * at the extension. A number of variations is allowed in both upper and
* lower case) If anyone knows or uses another extension please let me know :-)
*/
int guessSection(const char *name)
@@ -331,7 +325,7 @@ int guessSection(const char *name)
n.right(4)==".i++" ||
n.right(4)==".inl" ||
n.right(4)==".xml" ||
- n.right(4)==".sql"
+ n.right(4)==".sql"
) return Entry::SOURCE_SEC;
if (n.right(2)==".h" || // header
n.right(3)==".hh" ||
@@ -352,7 +346,7 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
//printf("<<resolveTypeDef(%s,%s)\n",
// context ? context->name().data() : "<none>",qualifiedName.data());
QCString result;
- if (qualifiedName.isEmpty())
+ if (qualifiedName.isEmpty())
{
//printf(" qualified name empty!\n");
return result;
@@ -374,12 +368,12 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
return result;
}
}
- MemberDef *md=0;
+ const MemberDef *md=0;
while (mContext && md==0)
{
// step 1: get the right scope
const Definition *resScope=mContext;
- if (scopeIndex!=-1)
+ if (scopeIndex!=-1)
{
// split-off scope part
QCString resScopeName = qualifiedName.left(scopeIndex);
@@ -400,35 +394,35 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
}
}
//printf("resScope=%s\n",resScope?resScope->name().data():"<none>");
-
+
// step 2: get the member
- if (resScope) // no scope or scope found in the current context
+ if (resScope) // no scope or scope found in the current context
{
//printf("scope found: %s, look for typedef %s\n",
// resScope->qualifiedName().data(),resName.data());
- MemberNameSDict *mnd=0;
+ MemberNameLinkedMap *mnd=0;
if (resScope->definitionType()==Definition::TypeClass)
{
- mnd=Doxygen::memberNameSDict;
+ mnd=Doxygen::memberNameLinkedMap;
}
else
{
- mnd=Doxygen::functionNameSDict;
+ mnd=Doxygen::functionNameLinkedMap;
}
MemberName *mn=mnd->find(resName);
if (mn)
{
- MemberNameIterator mni(*mn);
- MemberDef *tmd=0;
int minDist=-1;
- for (;(tmd=mni.current());++mni)
+ for (const auto &tmd_p : *mn)
{
+ const MemberDef *tmd = tmd_p.get();
//printf("Found member %s resScope=%s outerScope=%s mContext=%p\n",
- // tmd->name().data(), resScope->name().data(),
+ // tmd->name().data(), resScope->name().data(),
// tmd->getOuterScope()->name().data(), mContext);
if (tmd->isTypedef() /*&& tmd->getOuterScope()==resScope*/)
{
- int dist=isAccessibleFrom(resScope,0,tmd);
+ SymbolResolver resolver;
+ int dist=resolver.isAccessibleFrom(resScope,tmd);
if (dist!=-1 && (md==0 || dist<minDist))
{
md = tmd;
@@ -465,747 +459,43 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
// qualifiedName.data(),context ? context->name().data() : "<global>");
}
return result;
-
+
}
-/*! Get a class definition given its name.
+/*! Get a class definition given its name.
* Returns 0 if the class is not found.
*/
ClassDef *getClass(const char *n)
{
if (n==0 || n[0]=='\0') return 0;
- QCString name=n;
- ClassDef *result = Doxygen::classSDict->find(name);
- //if (result==0 && !exact) // also try generic and protocol versions
- //{
- // result = Doxygen::classSDict->find(name+"-g");
- // if (result==0)
- // {
- // result = Doxygen::classSDict->find(name+"-p");
- // }
- //}
- //printf("getClass(%s)=%s\n",n,result?result->name().data():"<none>");
- return result;
+ return Doxygen::classLinkedMap->find(n);
}
NamespaceDef *getResolvedNamespace(const char *name)
{
if (name==0 || name[0]=='\0') return 0;
- QCString *subst = Doxygen::namespaceAliasDict[name];
- if (subst)
+ auto it = Doxygen::namespaceAliasMap.find(name);
+ if (it!=Doxygen::namespaceAliasMap.end())
{
int count=0; // recursion detection guard
- QCString *newSubst;
- while ((newSubst=Doxygen::namespaceAliasDict[*subst]) && count<10)
+ StringUnorderedMap::iterator it2;
+ while ((it2=Doxygen::namespaceAliasMap.find(it->second))!=Doxygen::namespaceAliasMap.end() &&
+ count<10)
{
- subst=newSubst;
+ it=it2;
count++;
}
if (count==10)
{
warn_uncond("possible recursive namespace alias detected for %s!\n",name);
}
- return Doxygen::namespaceSDict->find(subst->data());
+ return Doxygen::namespaceLinkedMap->find(it->second.data());
}
else
{
- return Doxygen::namespaceSDict->find(name);
- }
-}
-
-static QDict<MemberDef> g_resolvedTypedefs;
-static QDict<Definition> g_visitedNamespaces;
-
-// forward declaration
-static const ClassDef *getResolvedClassRec(const Definition *scope,
- const FileDef *fileScope,
- const char *n,
- const MemberDef **pTypeDef,
- QCString *pTemplSpec,
- QCString *pResolvedType
- );
-int isAccessibleFromWithExpScope(const Definition *scope,const FileDef *fileScope,const Definition *item,
- const QCString &explicitScopePart);
-
-/*! Returns the class representing the value of the typedef represented by \a md
- * within file \a fileScope.
- *
- * 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.
- */
-const ClassDef *newResolveTypedef(const FileDef *fileScope,
- const MemberDef *md,
- const MemberDef **pMemType,
- QCString *pTemplSpec,
- QCString *pResolvedType,
- const ArgumentList *actTemplParams)
-{
- //printf("newResolveTypedef(md=%p,cachedVal=%p)\n",md,md->getCachedTypedefVal());
- bool isCached = md->isTypedefValCached(); // value already cached
- if (isCached)
- {
- //printf("Already cached %s->%s [%s]\n",
- // md->name().data(),
- // md->getCachedTypedefVal()?md->getCachedTypedefVal()->name().data():"<none>",
- // md->getCachedResolvedTypedef()?md->getCachedResolvedTypedef().data():"<none>");
-
- if (pTemplSpec) *pTemplSpec = md->getCachedTypedefTemplSpec();
- if (pResolvedType) *pResolvedType = md->getCachedResolvedTypedef();
- return md->getCachedTypedefVal();
- }
- //printf("new typedef\n");
- QCString qname = md->qualifiedName();
- if (g_resolvedTypedefs.find(qname)) return 0; // typedef already done
-
- g_resolvedTypedefs.insert(qname,md); // put on the trace list
-
- const ClassDef *typeClass = md->getClassDef();
- QCString type = md->typeString(); // get the "value" of the typedef
- if (typeClass && typeClass->isTemplate() &&
- actTemplParams && !actTemplParams->empty())
- {
- type = substituteTemplateArgumentsInString(type,
- typeClass->templateArguments(),*actTemplParams);
- }
- QCString typedefValue = type;
- int tl=type.length();
- int ip=tl-1; // remove * and & at the end
- while (ip>=0 && (type.at(ip)=='*' || type.at(ip)=='&' || type.at(ip)==' '))
- {
- ip--;
- }
- type=type.left(ip+1);
- type.stripPrefix("const "); // strip leading "const"
- type.stripPrefix("struct "); // strip leading "struct"
- type.stripPrefix("union "); // strip leading "union"
- int sp=0;
- tl=type.length(); // length may have been changed
- while (sp<tl && type.at(sp)==' ') sp++;
- const MemberDef *memTypeDef = 0;
- const ClassDef *result = getResolvedClassRec(md->getOuterScope(),
- fileScope,type,&memTypeDef,0,pResolvedType);
- // if type is a typedef then return what it resolves to.
- if (memTypeDef && memTypeDef->isTypedef())
- {
- result=newResolveTypedef(fileScope,memTypeDef,pMemType,pTemplSpec);
- goto done;
- }
- else if (memTypeDef && memTypeDef->isEnumerate() && pMemType)
- {
- *pMemType = memTypeDef;
- }
-
- //printf("type=%s result=%p\n",type.data(),result);
- if (result==0)
- {
- // try unspecialized version if type is template
- int si=type.findRev("::");
- int i=type.find('<');
- if (si==-1 && i!=-1) // typedef of a template => try the unspecialized version
- {
- if (pTemplSpec) *pTemplSpec = type.mid(i);
- result = getResolvedClassRec(md->getOuterScope(),fileScope,
- type.left(i),0,0,pResolvedType);
- //printf("result=%p pRresolvedType=%s sp=%d ip=%d tl=%d\n",
- // result,pResolvedType?pResolvedType->data():"<none>",sp,ip,tl);
- }
- else if (si!=-1) // A::B
- {
- i=type.find('<',si);
- if (i==-1) // Something like A<T>::B => lookup A::B
- {
- i=type.length();
- }
- else // Something like A<T>::B<S> => lookup A::B, spec=<S>
- {
- if (pTemplSpec) *pTemplSpec = type.mid(i);
- }
- result = getResolvedClassRec(md->getOuterScope(),fileScope,
- stripTemplateSpecifiersFromScope(type.left(i),FALSE),0,0,
- pResolvedType);
- }
-
- //if (result) ip=si+sp+1;
- }
-
-done:
- if (pResolvedType)
- {
- if (result)
- {
- *pResolvedType=result->qualifiedName();
- //printf("*pResolvedType=%s\n",pResolvedType->data());
- if (sp>0) pResolvedType->prepend(typedefValue.left(sp));
- if (ip<tl-1) pResolvedType->append(typedefValue.right(tl-ip-1));
- }
- else
- {
- *pResolvedType=typedefValue;
- }
- }
-
- // remember computed value for next time
- if (result && result->getDefFileName()!="<code>")
- // this check is needed to prevent that temporary classes that are
- // introduced while parsing code fragments are being cached here.
- {
- //printf("setting cached typedef %p in result %p\n",md,result);
- //printf("==> %s (%s,%d)\n",result->name().data(),result->getDefFileName().data(),result->getDefLine());
- //printf("*pResolvedType=%s\n",pResolvedType?pResolvedType->data():"<none>");
- const_cast<MemberDef*>(md)->cacheTypedefVal(result,
- pTemplSpec ? *pTemplSpec : QCString(),
- pResolvedType ? *pResolvedType : QCString()
- );
- }
-
- 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.
- */
-static QCString substTypedef(const Definition *scope,const FileDef *fileScope,const QCString &name,
- const MemberDef **pTypeDef=0)
-{
- QCString result=name;
- if (name.isEmpty()) return result;
-
- // lookup scope fragment in the symbol map
- DefinitionIntf *di = Doxygen::symbolMap->find(name);
- if (di==0) return result; // no matches
-
- MemberDef *bestMatch=0;
- if (di->definitionType()==DefinitionIntf::TypeSymbolList) // multi symbols
- {
- // search for the best match
- DefinitionListIterator dli(*(DefinitionList*)di);
- Definition *d;
- int minDistance=10000; // init at "infinite"
- for (dli.toFirst();(d=dli.current());++dli) // foreach definition
- {
- // only look at members
- if (d->definitionType()==Definition::TypeMember)
- {
- // that are also typedefs
- MemberDef *md = dynamic_cast<MemberDef *>(d);
- if (md->isTypedef()) // d is a typedef
- {
- // test accessibility of typedef within scope.
- int distance = isAccessibleFromWithExpScope(scope,fileScope,d,"");
- if (distance!=-1 && distance<minDistance)
- // definition is accessible and a better match
- {
- minDistance=distance;
- bestMatch = md;
- }
- }
- }
- }
- }
- else if (di->definitionType()==DefinitionIntf::TypeMember) // single symbol
- {
- Definition *d = (Definition*)di;
- // that are also typedefs
- MemberDef *md = dynamic_cast<MemberDef *>(di);
- if (md->isTypedef()) // d is a typedef
- {
- // test accessibility of typedef within scope.
- int distance = isAccessibleFromWithExpScope(scope,fileScope,d,"");
- if (distance!=-1) // definition is accessible
- {
- bestMatch = md;
- }
- }
+ return Doxygen::namespaceLinkedMap->find(name);
}
- if (bestMatch)
- {
- result = bestMatch->typeString();
- if (pTypeDef) *pTypeDef=bestMatch;
- }
-
- //printf("substTypedef(%s,%s)=%s\n",scope?scope->name().data():"<global>",
- // name.data(),result.data());
- return result;
-}
-
-static const Definition *endOfPathIsUsedClass(const SDict<Definition> *cl,const QCString &localName)
-{
- if (cl)
- {
- SDict<Definition>::Iterator cli(*cl);
- Definition *cd;
- for (cli.toFirst();(cd=cli.current());++cli)
- {
- if (cd->localName()==localName)
- {
- return cd;
- }
- }
- }
- return 0;
-}
-
-/*! 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 const Definition *followPath(const Definition *start,const FileDef *fileScope,const QCString &path)
-{
- int is,ps;
- int l;
- const Definition *current=start;
- ps=0;
- //printf("followPath: start='%s' path='%s'\n",start?start->name().data():"<none>",path.data());
- // for each part of the explicit scope
- while ((is=getScopeFragment(path,ps,&l))!=-1)
- {
- // try to resolve the part if it is a typedef
- const MemberDef *typeDef=0;
- QCString qualScopePart = substTypedef(current,fileScope,path.mid(is,l),&typeDef);
- //printf(" qualScopePart=%s\n",qualScopePart.data());
- if (typeDef)
- {
- const ClassDef *type = newResolveTypedef(fileScope,typeDef);
- if (type)
- {
- //printf("Found type %s\n",type->name().data());
- return type;
- }
- }
- const Definition *next = current->findInnerCompound(qualScopePart);
- //printf("++ Looking for %s inside %s result %s\n",
- // qualScopePart.data(),
- // current->name().data(),
- // next?next->name().data():"<null>");
- if (next==0) // failed to follow the path
- {
- //printf("==> next==0!\n");
- if (current->definitionType()==Definition::TypeNamespace)
- {
- next = endOfPathIsUsedClass(
- (dynamic_cast<const NamespaceDef *>(current))->getUsedClasses(),qualScopePart);
- }
- else if (current->definitionType()==Definition::TypeFile)
- {
- next = endOfPathIsUsedClass(
- (dynamic_cast<const FileDef *>(current))->getUsedClasses(),qualScopePart);
- }
- current = next;
- if (current==0) break;
- }
- else // continue to follow scope
- {
- current = next;
- //printf("==> current = %p\n",current);
- }
- ps=is+l;
- }
- //printf("followPath(start=%s,path=%s) result=%s\n",
- // start->name().data(),path.data(),current?current->name().data():"<null>");
- return current; // path could be followed
-}
-
-bool accessibleViaUsingClass(const SDict<Definition> *cl,
- const FileDef *fileScope,
- const Definition *item,
- const QCString &explicitScopePart=""
- )
-{
- //printf("accessibleViaUsingClass(%p)\n",cl);
- if (cl) // see if the class was imported via a using statement
- {
- SDict<Definition>::Iterator cli(*cl);
- Definition *ucd;
- bool explicitScopePartEmpty = explicitScopePart.isEmpty();
- for (cli.toFirst();(ucd=cli.current());++cli)
- {
- //printf("Trying via used class %s\n",ucd->name().data());
- const Definition *sc = explicitScopePartEmpty ? ucd : followPath(ucd,fileScope,explicitScopePart);
- if (sc && sc==item) return TRUE;
- //printf("Try via used class done\n");
- }
- }
- return FALSE;
-}
-
-bool accessibleViaUsingNamespace(const NamespaceSDict *nl,
- const FileDef *fileScope,
- const Definition *item,
- const QCString &explicitScopePart="")
-{
- static QDict<void> visitedDict;
- if (nl) // check used namespaces for the class
- {
- NamespaceSDict::Iterator nli(*nl);
- NamespaceDef *und;
- int count=0;
- for (nli.toFirst();(und=nli.current());++nli,count++)
- {
- //printf("[Trying via used namespace %s: count=%d/%d\n",und->name().data(),
- // count,nl->count());
- const Definition *sc = explicitScopePart.isEmpty() ? und : followPath(und,fileScope,explicitScopePart);
- if (sc && item->getOuterScope()==sc)
- {
- //printf("] found it\n");
- return TRUE;
- }
- if (item->getLanguage()==SrcLangExt_Cpp)
- {
- QCString key=und->name();
- if (und->getUsedNamespaces() && visitedDict.find(key)==0)
- {
- visitedDict.insert(key,(void *)0x08);
-
- if (accessibleViaUsingNamespace(und->getUsedNamespaces(),fileScope,item,explicitScopePart))
- {
- //printf("] found it via recursion\n");
- return TRUE;
- }
-
- visitedDict.remove(key);
- }
- }
- //printf("] Try via used namespace done\n");
- }
- }
- return FALSE;
-}
-
-const int MAX_STACK_SIZE = 1000;
-
-/** Helper class representing the stack of items considered while resolving
- * the scope.
- */
-class AccessStack
-{
- public:
- AccessStack() : m_index(0) {}
- void push(const Definition *scope,const FileDef *fileScope,const Definition *item)
- {
- if (m_index<MAX_STACK_SIZE)
- {
- m_elements[m_index].scope = scope;
- m_elements[m_index].fileScope = fileScope;
- m_elements[m_index].item = item;
- m_index++;
- }
- }
- void push(const Definition *scope,const FileDef *fileScope,const Definition *item,const QCString &expScope)
- {
- if (m_index<MAX_STACK_SIZE)
- {
- m_elements[m_index].scope = scope;
- m_elements[m_index].fileScope = fileScope;
- m_elements[m_index].item = item;
- m_elements[m_index].expScope = expScope;
- m_index++;
- }
- }
- void pop()
- {
- if (m_index>0) m_index--;
- }
- bool find(const Definition *scope,const FileDef *fileScope, const Definition *item)
- {
- int i=0;
- for (i=0;i<m_index;i++)
- {
- AccessElem *e = &m_elements[i];
- if (e->scope==scope && e->fileScope==fileScope && e->item==item)
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- bool find(const Definition *scope,const FileDef *fileScope, const Definition *item,const QCString &expScope)
- {
- int i=0;
- for (i=0;i<m_index;i++)
- {
- AccessElem *e = &m_elements[i];
- if (e->scope==scope && e->fileScope==fileScope && e->item==item && e->expScope==expScope)
- {
- return TRUE;
- }
- }
- return FALSE;
- }
-
- private:
- /** Element in the stack. */
- struct AccessElem
- {
- const Definition *scope;
- const FileDef *fileScope;
- const Definition *item;
- QCString expScope;
- };
- int m_index;
- AccessElem m_elements[MAX_STACK_SIZE];
-};
-
-/* Returns the "distance" (=number of levels up) from item to scope, or -1
- * if item in not inside scope.
- */
-int isAccessibleFrom(const Definition *scope,const FileDef *fileScope,const Definition *item)
-{
- //printf("<isAccessibleFrom(scope=%s,item=%s itemScope=%s)\n",
- // scope->name().data(),item->name().data(),item->getOuterScope()->name().data());
-
- static AccessStack accessStack;
- if (accessStack.find(scope,fileScope,item))
- {
- return -1;
- }
- accessStack.push(scope,fileScope,item);
-
- int result=0; // assume we found it
- int i;
-
- Definition *itemScope=item->getOuterScope();
- bool memberAccessibleFromScope =
- (item->definitionType()==Definition::TypeMember && // a member
- itemScope && itemScope->definitionType()==Definition::TypeClass && // of a class
- scope->definitionType()==Definition::TypeClass && // accessible
- (dynamic_cast<const ClassDef*>(scope))->isAccessibleMember(dynamic_cast<const MemberDef *>(item)) // from scope
- );
- bool nestedClassInsideBaseClass =
- (item->definitionType()==Definition::TypeClass && // a nested class
- itemScope && itemScope->definitionType()==Definition::TypeClass && // inside a base
- scope->definitionType()==Definition::TypeClass && // class of scope
- (dynamic_cast<const ClassDef*>(scope))->isBaseClass(dynamic_cast<ClassDef*>(itemScope),TRUE)
- );
-
- if (itemScope==scope || memberAccessibleFromScope || nestedClassInsideBaseClass)
- {
- //printf("> found it\n");
- if (nestedClassInsideBaseClass) result++; // penalty for base class to prevent
- // this is preferred over nested class in this class
- // see bug 686956
- }
- else if (scope==Doxygen::globalScope)
- {
- if (fileScope)
- {
- SDict<Definition> *cl = fileScope->getUsedClasses();
- if (accessibleViaUsingClass(cl,fileScope,item))
- {
- //printf("> found via used class\n");
- goto done;
- }
- NamespaceSDict *nl = fileScope->getUsedNamespaces();
- if (accessibleViaUsingNamespace(nl,fileScope,item))
- {
- //printf("> found via used namespace\n");
- goto done;
- }
- }
- //printf("> reached global scope\n");
- result=-1; // not found in path to globalScope
- }
- else // keep searching
- {
- // check if scope is a namespace, which is using other classes and namespaces
- if (scope->definitionType()==Definition::TypeNamespace)
- {
- const NamespaceDef *nscope = dynamic_cast<const NamespaceDef*>(scope);
- //printf(" %s is namespace with %d used classes\n",nscope->name().data(),nscope->getUsedClasses());
- const SDict<Definition> *cl = nscope->getUsedClasses();
- if (accessibleViaUsingClass(cl,fileScope,item))
- {
- //printf("> found via used class\n");
- goto done;
- }
- const NamespaceSDict *nl = nscope->getUsedNamespaces();
- if (accessibleViaUsingNamespace(nl,fileScope,item))
- {
- //printf("> found via used namespace\n");
- goto done;
- }
- }
- // repeat for the parent scope
- i=isAccessibleFrom(scope->getOuterScope(),fileScope,item);
- //printf("> result=%d\n",i);
- result= (i==-1) ? -1 : i+2;
- }
-done:
- accessStack.pop();
- //Doxygen::lookupCache.insert(key,new int(result));
- return result;
-}
-
-
-/* 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 (or its parent scope(s)) plus the explicit part.
- * Example:
- *
- * class A { public: class I {}; };
- * class B { public: class J {}; };
- *
- * - Looking for item=='J' inside scope=='B' will return 0.
- * - Looking for item=='I' inside scope=='B' will return -1
- * (as it is not found in B nor in the global scope).
- * - Looking for item=='A::I' inside scope=='B', first the match B::A::I is tried but
- * not found and then A::I is searched in the global scope, which matches and
- * thus the result is 1.
- */
-int isAccessibleFromWithExpScope(const Definition *scope,const FileDef *fileScope,
- const Definition *item,const QCString &explicitScopePart)
-{
- if (explicitScopePart.isEmpty())
- {
- // handle degenerate case where there is no explicit scope.
- return isAccessibleFrom(scope,fileScope,item);
- }
-
- static AccessStack accessStack;
- if (accessStack.find(scope,fileScope,item,explicitScopePart))
- {
- return -1;
- }
- accessStack.push(scope,fileScope,item,explicitScopePart);
-
-
- //printf(" <isAccessibleFromWithExpScope(%s,%s,%s)\n",scope?scope->name().data():"<global>",
- // item?item->name().data():"<none>",
- // explicitScopePart.data());
- int result=0; // assume we found it
- const Definition *newScope = followPath(scope,fileScope,explicitScopePart);
- if (newScope) // explicitScope is inside scope => newScope is the result
- {
- Definition *itemScope = item->getOuterScope();
- //printf(" scope traversal successful %s<->%s!\n",itemScope->name().data(),newScope->name().data());
- //if (newScope && newScope->definitionType()==Definition::TypeClass)
- //{
- // ClassDef *cd = (ClassDef *)newScope;
- // printf("---> Class %s: bases=%p\n",cd->name().data(),cd->baseClasses());
- //}
- if (itemScope==newScope) // exact match of scopes => distance==0
- {
- //printf("> found it\n");
- }
- else if (itemScope && newScope &&
- itemScope->definitionType()==Definition::TypeClass &&
- newScope->definitionType()==Definition::TypeClass &&
- (dynamic_cast<const ClassDef*>(newScope))->isBaseClass(dynamic_cast<const ClassDef*>(itemScope),TRUE,0)
- )
- {
- // inheritance is also ok. Example: looking for B::I, where
- // class A { public: class I {} };
- // class B : public A {}
- // but looking for B::I, where
- // class A { public: class I {} };
- // class B { public: class I {} };
- // will find A::I, so we still prefer a direct match and give this one a distance of 1
- result=1;
-
- //printf("scope(%s) is base class of newScope(%s)\n",
- // scope->name().data(),newScope->name().data());
- }
- else
- {
- int i=-1;
- if (newScope->definitionType()==Definition::TypeNamespace)
- {
- g_visitedNamespaces.insert(newScope->name(),newScope);
- // this part deals with the case where item is a class
- // A::B::C but is explicit referenced as A::C, where B is imported
- // in A via a using directive.
- //printf("newScope is a namespace: %s!\n",newScope->name().data());
- const NamespaceDef *nscope = dynamic_cast<const NamespaceDef*>(newScope);
- const SDict<Definition> *cl = nscope->getUsedClasses();
- if (cl)
- {
- SDict<Definition>::Iterator cli(*cl);
- const Definition *cd;
- for (cli.toFirst();(cd=cli.current());++cli)
- {
- //printf("Trying for class %s\n",cd->name().data());
- if (cd==item)
- {
- //printf("> class is used in this scope\n");
- goto done;
- }
- }
- }
- const NamespaceSDict *nl = nscope->getUsedNamespaces();
- if (nl)
- {
- NamespaceSDict::Iterator nli(*nl);
- const NamespaceDef *nd;
- for (nli.toFirst();(nd=nli.current());++nli)
- {
- if (g_visitedNamespaces.find(nd->name())==0)
- {
- //printf("Trying for namespace %s\n",nd->name().data());
- i = isAccessibleFromWithExpScope(scope,fileScope,item,nd->name());
- if (i!=-1)
- {
- //printf("> found via explicit scope of used namespace\n");
- goto done;
- }
- }
- }
- }
- }
- // repeat for the parent scope
- if (scope!=Doxygen::globalScope)
- {
- i = isAccessibleFromWithExpScope(scope->getOuterScope(),fileScope,
- item,explicitScopePart);
- }
- //printf(" | result=%d\n",i);
- result = (i==-1) ? -1 : i+2;
- }
- }
- else // failed to resolve explicitScope
- {
- //printf(" failed to resolve: scope=%s\n",scope->name().data());
- if (scope->definitionType()==Definition::TypeNamespace)
- {
- const NamespaceDef *nscope = dynamic_cast<const NamespaceDef*>(scope);
- const NamespaceSDict *nl = nscope->getUsedNamespaces();
- if (accessibleViaUsingNamespace(nl,fileScope,item,explicitScopePart))
- {
- //printf("> found in used namespace\n");
- goto done;
- }
- }
- if (scope==Doxygen::globalScope)
- {
- if (fileScope)
- {
- const NamespaceSDict *nl = fileScope->getUsedNamespaces();
- if (accessibleViaUsingNamespace(nl,fileScope,item,explicitScopePart))
- {
- //printf("> found in used namespace\n");
- goto done;
- }
- }
- //printf("> not found\n");
- result=-1;
- }
- else // continue by looking into the parent scope
- {
- int i=isAccessibleFromWithExpScope(scope->getOuterScope(),fileScope,
- item,explicitScopePart);
- //printf("> result=%d\n",i);
- result= (i==-1) ? -1 : i+2;
- }
- }
-
-done:
- //printf(" > result=%d\n",result);
- accessStack.pop();
- //Doxygen::lookupCache.insert(key,new int(result));
- return result;
}
int computeQualifiedIndex(const QCString &name)
@@ -1214,448 +504,11 @@ int computeQualifiedIndex(const QCString &name)
return name.findRev("::",i==-1 ? name.length() : i);
}
-static void getResolvedSymbol(const Definition *scope,
- const FileDef *fileScope,
- Definition *d,
- const QCString &explicitScopePart,
- ArgumentList *actTemplParams,
- int &minDistance,
- const ClassDef *&bestMatch,
- const MemberDef *&bestTypedef,
- QCString &bestTemplSpec,
- QCString &bestResolvedType
- )
-{
- //printf(" => found type %x name=%s d=%p\n",
- // d->definitionType(),d->name().data(),d);
-
- // only look at classes and members that are enums or typedefs
- if (d->definitionType()==Definition::TypeClass ||
- (d->definitionType()==Definition::TypeMember &&
- ((dynamic_cast<MemberDef*>(d))->isTypedef() || (dynamic_cast<MemberDef*>(d))->isEnumerate())
- )
- )
- {
- g_visitedNamespaces.clear();
- // test accessibility of definition within scope.
- int distance = isAccessibleFromWithExpScope(scope,fileScope,d,explicitScopePart);
- //printf(" %s; distance %s (%p) is %d\n",scope->name().data(),d->name().data(),d,distance);
- if (distance!=-1) // definition is accessible
- {
- // see if we are dealing with a class or a typedef
- if (d->definitionType()==Definition::TypeClass) // d is a class
- {
- ClassDef *cd = dynamic_cast<ClassDef *>(d);
- //printf("cd=%s\n",cd->name().data());
- if (!cd->isTemplateArgument()) // skip classes that
- // are only there to
- // represent a template
- // argument
- {
- //printf("is not a templ arg\n");
- if (distance<minDistance) // found a definition that is "closer"
- {
- minDistance=distance;
- bestMatch = cd;
- bestTypedef = 0;
- bestTemplSpec.resize(0);
- bestResolvedType = cd->qualifiedName();
- }
- else if (distance==minDistance &&
- fileScope && bestMatch &&
- fileScope->getUsedNamespaces() &&
- d->getOuterScope()->definitionType()==Definition::TypeNamespace &&
- bestMatch->getOuterScope()==Doxygen::globalScope
- )
- {
- // in case the distance is equal it could be that a class X
- // is defined in a namespace and in the global scope. When searched
- // in the global scope the distance is 0 in both cases. We have
- // to choose one of the definitions: we choose the one in the
- // namespace if the fileScope imports namespaces and the definition
- // found was in a namespace while the best match so far isn't.
- // Just a non-perfect heuristic but it could help in some situations
- // (kdecore code is an example).
- minDistance=distance;
- bestMatch = cd;
- bestTypedef = 0;
- bestTemplSpec.resize(0);
- bestResolvedType = cd->qualifiedName();
- }
- }
- else
- {
- //printf(" is a template argument!\n");
- }
- }
- else if (d->definitionType()==Definition::TypeMember)
- {
- MemberDef *md = dynamic_cast<MemberDef *>(d);
- //printf(" member isTypedef()=%d\n",md->isTypedef());
- if (md->isTypedef()) // d is a typedef
- {
- QCString args=md->argsString();
- if (args.isEmpty()) // do not expand "typedef t a[4];"
- {
- //printf(" found typedef!\n");
-
- // 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)
- {
- QCString spec;
- QCString type;
- minDistance=distance;
- const MemberDef *enumType = 0;
- const ClassDef *cd = newResolveTypedef(fileScope,md,&enumType,&spec,&type,actTemplParams);
- if (cd) // type resolves to a class
- {
- //printf(" bestTypeDef=%p spec=%s type=%s\n",md,spec.data(),type.data());
- bestMatch = cd;
- bestTypedef = md;
- bestTemplSpec = spec;
- bestResolvedType = type;
- }
- else if (enumType) // type resolves to a enum
- {
- //printf(" is enum\n");
- bestMatch = 0;
- bestTypedef = enumType;
- bestTemplSpec = "";
- bestResolvedType = enumType->qualifiedName();
- }
- else if (md->isReference()) // external reference
- {
- bestMatch = 0;
- bestTypedef = md;
- bestTemplSpec = spec;
- bestResolvedType = type;
- }
- else
- {
- bestMatch = 0;
- bestTypedef = md;
- bestTemplSpec.resize(0);
- bestResolvedType.resize(0);
- //printf(" no match\n");
- }
- }
- else
- {
- //printf(" not the best match %d min=%d\n",distance,minDistance);
- }
- }
- else
- {
- //printf(" not a simple typedef\n")
- }
- }
- else if (md->isEnumerate())
- {
- if (distance<minDistance)
- {
- minDistance=distance;
- bestMatch = 0;
- bestTypedef = md;
- bestTemplSpec = "";
- bestResolvedType = md->qualifiedName();
- }
- }
- }
- } // if definition accessible
- else
- {
- //printf(" Not accessible!\n");
- }
- } // if definition is a class or member
- //printf(" bestMatch=%p bestResolvedType=%s\n",bestMatch,bestResolvedType.data());
-}
-
-/* Find the fully qualified class name referred 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.
- */
-static const ClassDef *getResolvedClassRec(const Definition *scope,
- const FileDef *fileScope,
- const char *n,
- const MemberDef **pTypeDef,
- QCString *pTemplSpec,
- QCString *pResolvedType
- )
-{
- //printf("[getResolvedClassRec(%s,%s)\n",scope?scope->name().data():"<global>",n);
- QCString name;
- QCString explicitScopePart;
- QCString strippedTemplateParams;
- name=stripTemplateSpecifiersFromScope
- (removeRedundantWhiteSpace(n),TRUE,
- &strippedTemplateParams);
- ArgumentList actTemplParams;
- if (!strippedTemplateParams.isEmpty()) // template part that was stripped
- {
- stringToArgumentList(scope->getLanguage(),strippedTemplateParams,actTemplParams);
- }
-
- int qualifierIndex = computeQualifiedIndex(name);
- //printf("name=%s qualifierIndex=%d\n",name.data(),qualifierIndex);
- 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())
- {
- //printf("] empty name\n");
- return 0; // empty name
- }
-
- //printf("Looking for symbol %s\n",name.data());
- DefinitionIntf *di = Doxygen::symbolMap->find(name);
- // the -g (for C# generics) and -p (for ObjC protocols) are now already
- // stripped from the key used in the symbolMap, so that is not needed here.
- if (di==0)
- {
- //di = Doxygen::symbolMap->find(name+"-g");
- //if (di==0)
- //{
- di = Doxygen::symbolMap->find(name+"-p");
- if (di==0)
- {
- //printf("no such symbol!\n");
- return 0;
- }
- //}
- }
- //printf("found symbol!\n");
-
- bool hasUsingStatements =
- (fileScope && ((fileScope->getUsedNamespaces() &&
- fileScope->getUsedNamespaces()->count()>0) ||
- (fileScope->getUsedClasses() &&
- fileScope->getUsedClasses()->count()>0))
- );
- //printf("hasUsingStatements=%d\n",hasUsingStatements);
- // Since it is often the case that the same name is searched in the same
- // scope over an over again (especially for the linked source code generation)
- // we use a cache to collect previous results. This is possible since the
- // result of a lookup is deterministic. As the key we use the concatenated
- // scope, the name to search for and the explicit scope prefix. The speedup
- // achieved by this simple cache can be enormous.
- int scopeNameLen = scope->name().length()+1;
- int nameLen = name.length()+1;
- int explicitPartLen = explicitScopePart.length();
- int fileScopeLen = hasUsingStatements ? 1+fileScope->absFilePath().length() : 0;
-
- // below is a more efficient coding of
- // QCString key=scope->name()+"+"+name+"+"+explicitScopePart;
- QCString key(scopeNameLen+nameLen+explicitPartLen+fileScopeLen+1);
- char *p=key.rawData();
- qstrcpy(p,scope->name()); *(p+scopeNameLen-1)='+';
- p+=scopeNameLen;
- qstrcpy(p,name); *(p+nameLen-1)='+';
- p+=nameLen;
- qstrcpy(p,explicitScopePart);
- p+=explicitPartLen;
-
- // if a file scope is given and it contains using statements we should
- // also use the file part in the key (as a class name can be in
- // two different namespaces and a using statement in a file can select
- // one of them).
- if (hasUsingStatements)
- {
- // below is a more efficient coding of
- // key+="+"+fileScope->name();
- *p++='+';
- qstrcpy(p,fileScope->absFilePath());
- p+=fileScopeLen-1;
- }
- *p='\0';
-
- LookupInfo *pval=Doxygen::lookupCache->find(key);
- //printf("Searching for %s result=%p\n",key.data(),pval);
- if (pval)
- {
- //printf("LookupInfo %p %p '%s' %p\n",
- // pval->classDef, pval->typeDef, pval->templSpec.data(),
- // pval->resolvedType.data());
- if (pTemplSpec) *pTemplSpec=pval->templSpec;
- if (pTypeDef) *pTypeDef=pval->typeDef;
- if (pResolvedType) *pResolvedType=pval->resolvedType;
- //printf("] cachedMatch=%s\n",
- // pval->classDef?pval->classDef->name().data():"<none>");
- //if (pTemplSpec)
- // printf("templSpec=%s\n",pTemplSpec->data());
- return pval->classDef;
- }
- else // not found yet; we already add a 0 to avoid the possibility of
- // endless recursion.
- {
- Doxygen::lookupCache->insert(key,new LookupInfo);
- }
-
- const ClassDef *bestMatch=0;
- const MemberDef *bestTypedef=0;
- QCString bestTemplSpec;
- QCString bestResolvedType;
- int minDistance=10000; // init at "infinite"
-
- if (di->definitionType()==DefinitionIntf::TypeSymbolList) // not a unique name
- {
- //printf(" name is not unique\n");
- DefinitionListIterator dli(*(DefinitionList*)di);
- Definition *d;
- int count=0;
- for (dli.toFirst();(d=dli.current());++dli,++count) // foreach definition
- {
- getResolvedSymbol(scope,fileScope,d,explicitScopePart,&actTemplParams,
- minDistance,bestMatch,bestTypedef,bestTemplSpec,
- bestResolvedType);
- }
- }
- else // unique name
- {
- //printf(" name is unique\n");
- Definition *d = (Definition *)di;
- getResolvedSymbol(scope,fileScope,d,explicitScopePart,&actTemplParams,
- minDistance,bestMatch,bestTypedef,bestTemplSpec,
- bestResolvedType);
- }
-
- if (pTypeDef)
- {
- *pTypeDef = bestTypedef;
- }
- if (pTemplSpec)
- {
- *pTemplSpec = bestTemplSpec;
- }
- if (pResolvedType)
- {
- *pResolvedType = bestResolvedType;
- }
- //printf("getResolvedClassRec: bestMatch=%p pval->resolvedType=%s\n",
- // bestMatch,bestResolvedType.data());
-
- pval=Doxygen::lookupCache->find(key);
- if (pval)
- {
- pval->classDef = bestMatch;
- pval->typeDef = bestTypedef;
- pval->templSpec = bestTemplSpec;
- pval->resolvedType = bestResolvedType;
- }
- else
- {
- Doxygen::lookupCache->insert(key,new LookupInfo(bestMatch,bestTypedef,bestTemplSpec,bestResolvedType));
- }
- //printf("] bestMatch=%s distance=%d\n",
- // bestMatch?bestMatch->name().data():"<none>",minDistance);
- //if (pTemplSpec)
- // printf("templSpec=%s\n",pTemplSpec->data());
- return bestMatch;
-}
-
-/* Find the fully qualified class name referred 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.
- */
-const ClassDef *getResolvedClass(const Definition *scope,
- const FileDef *fileScope,
- const char *n,
- const MemberDef **pTypeDef,
- QCString *pTemplSpec,
- bool mayBeUnlinkable,
- bool mayBeHidden,
- QCString *pResolvedType
- )
-{
- static bool optimizeOutputVhdl = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
- g_resolvedTypedefs.clear();
- if (scope==0 ||
- (scope->definitionType()!=Definition::TypeClass &&
- scope->definitionType()!=Definition::TypeNamespace
- ) ||
- (scope->getLanguage()==SrcLangExt_Java && QCString(n).find("::")!=-1)
- )
- {
- scope=Doxygen::globalScope;
- }
- //printf("------------ getResolvedClass(scope=%s,file=%s,name=%s,mayUnlinkable=%d)\n",
- // scope?scope->name().data():"<global>",
- // fileScope?fileScope->name().data():"<none>",
- // n,
- // mayBeUnlinkable
- // );
- const ClassDef *result;
- if (optimizeOutputVhdl)
- {
- result = getClass(n);
- }
- else
- {
- result = getResolvedClassRec(scope,fileScope,n,pTypeDef,pTemplSpec,pResolvedType);
- }
- if (result==0) // for nested classes imported via tag files, the scope may not
- // present, so we check the class name directly as well.
- // See also bug701314
- {
- result = getClass(n);
- }
- if (!mayBeUnlinkable && result && !result->isLinkable())
- {
- if (!mayBeHidden || !result->isHidden())
- {
- //printf("result was %s\n",result?result->name().data():"<none>");
- result=0; // don't link to artificial/hidden classes unless explicitly allowed
- }
- }
- //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);
- if (b==-1) return FALSE; // not found
- b+=8;
- while (b<i) // check if there are only spaces in between
- // the operator and the >
- {
- if (!isspace((uchar)s.at(b))) return FALSE;
- b++;
- }
- return TRUE;
-}
-
-static bool findOperator2(const QCString &s,int i)
-{
- int b = s.findRev("operator",i);
- if (b==-1) return FALSE; // not found
- b+=8;
- while (b<i) // check if there are only non-ascii
- // characters in front of the operator
- {
- if (isId((uchar)s.at(b))) return FALSE;
- b++;
- }
- return TRUE;
-}
-
static const char constScope[] = { 'c', 'o', 'n', 's', 't', ':' };
static const char virtualScope[] = { 'v', 'i', 'r', 't', 'u', 'a', 'l', ':' };
static const char operatorScope[] = { 'o', 'p', 'e', 'r', 'a', 't', 'o', 'r', '?', '?', '?' };
@@ -1664,30 +517,30 @@ struct CharAroundSpace
{
CharAroundSpace()
{
- charMap['('].before=FALSE;
- charMap['='].before=FALSE;
- charMap['&'].before=FALSE;
- charMap['*'].before=FALSE;
- charMap['['].before=FALSE;
- charMap['|'].before=FALSE;
- charMap['+'].before=FALSE;
- charMap[';'].before=FALSE;
- charMap[':'].before=FALSE;
- charMap['/'].before=FALSE;
-
- charMap['='].after=FALSE;
- charMap[' '].after=FALSE;
- charMap['['].after=FALSE;
- charMap[']'].after=FALSE;
- charMap['\t'].after=FALSE;
- charMap['\n'].after=FALSE;
- charMap[')'].after=FALSE;
- charMap[','].after=FALSE;
- charMap['<'].after=FALSE;
- charMap['|'].after=FALSE;
- charMap['+'].after=FALSE;
- charMap['('].after=FALSE;
- charMap['/'].after=FALSE;
+ charMap[static_cast<int>('(')].before=FALSE;
+ charMap[static_cast<int>('=')].before=FALSE;
+ charMap[static_cast<int>('&')].before=FALSE;
+ charMap[static_cast<int>('*')].before=FALSE;
+ charMap[static_cast<int>('[')].before=FALSE;
+ charMap[static_cast<int>('|')].before=FALSE;
+ charMap[static_cast<int>('+')].before=FALSE;
+ charMap[static_cast<int>(';')].before=FALSE;
+ charMap[static_cast<int>(':')].before=FALSE;
+ charMap[static_cast<int>('/')].before=FALSE;
+
+ charMap[static_cast<int>('=')].after=FALSE;
+ charMap[static_cast<int>(' ')].after=FALSE;
+ charMap[static_cast<int>('[')].after=FALSE;
+ charMap[static_cast<int>(']')].after=FALSE;
+ charMap[static_cast<int>('\t')].after=FALSE;
+ charMap[static_cast<int>('\n')].after=FALSE;
+ charMap[static_cast<int>(')')].after=FALSE;
+ charMap[static_cast<int>(',')].after=FALSE;
+ charMap[static_cast<int>('<')].after=FALSE;
+ charMap[static_cast<int>('|')].after=FALSE;
+ charMap[static_cast<int>('+')].after=FALSE;
+ charMap[static_cast<int>('(')].after=FALSE;
+ charMap[static_cast<int>('/')].after=FALSE;
}
struct CharElem
{
@@ -1704,15 +557,16 @@ static CharAroundSpace g_charAroundSpace;
// Note: this function is not reentrant due to the use of static buffer!
QCString removeRedundantWhiteSpace(const QCString &s)
{
- static bool cliSupport = Config_getBool(CPP_CLI_SUPPORT);
- static bool vhdl = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
+ bool cliSupport = Config_getBool(CPP_CLI_SUPPORT);
+ bool vhdl = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
if (s.isEmpty() || vhdl) return s;
// We use a static character array to
// improve the performance of this function
- static char *growBuf = 0;
- static int growBufLen = 0;
+ // and thread_local is needed to make it multi-thread safe
+ static THREAD_LOCAL char *growBuf = 0;
+ static THREAD_LOCAL int growBufLen = 0;
if ((int)s.length()*3>growBufLen) // For input character we produce at most 3 output characters,
{
growBufLen = s.length()*3;
@@ -1866,7 +720,7 @@ QCString removeRedundantWhiteSpace(const QCString &s)
{
if (nc != '=')
// avoid splitting operator&=
- {
+ {
*dst++=' ';
}
}
@@ -1994,10 +848,10 @@ bool rightScopeMatch(const QCString &scope, const QCString &name)
{
int sl=scope.length();
int nl=name.length();
- return (name==scope || // equal
- (scope.right(nl)==name && // substring
+ return (name==scope || // equal
+ (scope.right(nl)==name && // substring
sl-nl>1 && scope.at(sl-nl-1)==':' && scope.at(sl-nl-2)==':' // scope
- )
+ )
);
}
@@ -2005,10 +859,10 @@ bool leftScopeMatch(const QCString &scope, const QCString &name)
{
int sl=scope.length();
int nl=name.length();
- return (name==scope || // equal
- (scope.left(nl)==name && // substring
+ return (name==scope || // equal
+ (scope.left(nl)==name && // substring
sl>nl+1 && scope.at(nl)==':' && scope.at(nl+1)==':' // scope
- )
+ )
);
}
@@ -2021,8 +875,10 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
//printf("linkify='%s'\n",text);
static QRegExp regExp("[a-z_A-Z\\x80-\\xFF][~!a-z_A-Z0-9$\\\\.:\\x80-\\xFF]*");
static QRegExp regExpSplit("(?!:),");
+ if (text==0) return;
QCString txtStr=text;
int strLen = txtStr.length();
+ if (strLen==0) return;
//printf("linkifyText scope=%s fileScope=%s strtxt=%s strlen=%d external=%d\n",
// scope?scope->name().data():"<none>",
// fileScope?fileScope->name().data():"<none>",
@@ -2032,7 +888,6 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
int newIndex;
int skipIndex=0;
int floatingIndex=0;
- if (strLen==0) return;
// read a word from the text string
while ((newIndex=regExp.match(txtStr,index,&matchLen))!=-1)
{
@@ -2045,11 +900,11 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
}
// add non-word part to the result
- bool insideString=FALSE;
+ bool insideString=FALSE;
int i;
- for (i=index;i<newIndex;i++)
- {
- if (txtStr.at(i)=='"') insideString=!insideString;
+ for (i=index;i<newIndex;i++)
+ {
+ if (txtStr.at(i)=='"') insideString=!insideString;
}
//printf("floatingIndex=%d strlen=%d autoBreak=%d\n",floatingIndex,strLen,autoBreak);
@@ -2069,16 +924,16 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
out.writeBreak(indentLevel==0 ? 0 : indentLevel+1);
out.writeString(splitText.right(splitLength-i-offset),keepSpaces);
floatingIndex=splitLength-i-offset+matchLen;
- }
+ }
else
{
- out.writeString(splitText,keepSpaces);
+ out.writeString(splitText,keepSpaces);
}
}
else
{
- //ol.docify(txtStr.mid(skipIndex,newIndex-skipIndex));
- out.writeString(txtStr.mid(skipIndex,newIndex-skipIndex),keepSpaces);
+ //ol.docify(txtStr.mid(skipIndex,newIndex-skipIndex));
+ out.writeString(txtStr.mid(skipIndex,newIndex-skipIndex),keepSpaces);
}
// get word from string
QCString word=txtStr.mid(newIndex,matchLen);
@@ -2095,8 +950,9 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
const GroupDef *gd=0;
//printf("** Match word '%s'\n",matchWord.data());
- const MemberDef *typeDef=0;
- cd=getResolvedClass(scope,fileScope,matchWord,&typeDef);
+ SymbolResolver resolver(fileScope);
+ cd=resolver.resolveClass(scope,matchWord);
+ const MemberDef *typeDef = resolver.getTypedef();
if (typeDef) // First look at typedef then class, see bug 584184.
{
//printf("Found typedef %s\n",typeDef->name().data());
@@ -2112,7 +968,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
}
}
}
- if (!found && (cd || (cd=getClass(matchWord))))
+ if (!found && (cd || (cd=getClass(matchWord))))
{
//printf("Found class %s\n",cd->name().data());
// add link to the result
@@ -2156,10 +1012,10 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
int m = matchWord.findRev("::");
QCString scopeName;
- if (scope &&
- (scope->definitionType()==Definition::TypeClass ||
+ if (scope &&
+ (scope->definitionType()==Definition::TypeClass ||
scope->definitionType()==Definition::TypeNamespace
- )
+ )
)
{
scopeName=scope->name();
@@ -2171,19 +1027,19 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
}
//printf("ScopeName=%s\n",scopeName.data());
- //if (!found) printf("Trying to link %s in %s\n",word.data(),scopeName.data());
- if (!found &&
- getDefs(scopeName,matchWord,0,md,cd,fd,nd,gd) &&
- //(md->isTypedef() || md->isEnumerate() ||
+ //if (!found) printf("Trying to link %s in %s\n",word.data(),scopeName.data());
+ if (!found &&
+ getDefs(scopeName,matchWord,0,md,cd,fd,nd,gd) &&
+ //(md->isTypedef() || md->isEnumerate() ||
// md->isReference() || md->isVariable()
- //) &&
- (external ? md->isLinkable() : md->isLinkableInProject())
+ //) &&
+ (external ? md->isLinkable() : md->isLinkableInProject())
)
{
//printf("Found ref scope=%s\n",d?d->name().data():"<global>");
//ol.writeObjectLink(d->getReference(),d->getOutputFileBase(),
// md->anchor(),word);
- if (md!=self && (self==0 || md->name()!=self->name()))
+ if (md!=self && (self==0 || md->name()!=self->name()))
// name check is needed for overloaded members, where getDefs just returns one
{
/* in case of Fortran scop and the variable is a non Fortran variable: don't link,
@@ -2214,9 +1070,9 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
}
-void writeExample(OutputList &ol,ExampleSDict *ed)
+void writeExamples(OutputList &ol,const ExampleList &list)
{
- QCString exampleLine=theTranslator->trWriteList(ed->count());
+ QCString exampleLine=theTranslator->trWriteList((int)list.size());
//bool latexEnabled = ol.isEnabled(OutputGenerator::Latex);
//bool manEnabled = ol.isEnabled(OutputGenerator::Man);
@@ -2229,9 +1085,9 @@ void writeExample(OutputList &ol,ExampleSDict *ed)
bool ok;
ol.parseText(exampleLine.mid(index,newIndex-index));
uint entryIndex = exampleLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
- Example *e=ed->at(entryIndex);
- if (ok && e)
+ if (ok && entryIndex<list.size())
{
+ const auto &e = list[entryIndex];
ol.pushGeneratorState();
//if (latexEnabled) ol.disable(OutputGenerator::Latex);
ol.disable(OutputGenerator::Latex);
@@ -2239,7 +1095,7 @@ void writeExample(OutputList &ol,ExampleSDict *ed)
ol.disable(OutputGenerator::Docbook);
// link for Html / man
//printf("writeObjectLink(file=%s)\n",e->file.data());
- ol.writeObjectLink(0,e->file,e->anchor,e->name);
+ ol.writeObjectLink(0,e.file,e.anchor,e.name);
ol.popGeneratorState();
ol.pushGeneratorState();
@@ -2248,13 +1104,13 @@ void writeExample(OutputList &ol,ExampleSDict *ed)
ol.disable(OutputGenerator::Html);
// link for Latex / pdf with anchor because the sources
// are not hyperlinked (not possible with a verbatim environment).
- ol.writeObjectLink(0,e->file,0,e->name);
+ ol.writeObjectLink(0,e.file,0,e.name);
//if (manEnabled) ol.enable(OutputGenerator::Man);
//if (htmlEnabled) ol.enable(OutputGenerator::Html);
ol.popGeneratorState();
}
index=newIndex+matchLen;
- }
+ }
ol.parseText(exampleLine.right(exampleLine.length()-index));
ol.writeString(".");
}
@@ -2296,94 +1152,72 @@ QCString argListToString(const ArgumentList &al,bool useCanonicalType,bool showD
if (it!=al.end()) result+=", ";
}
result+=")";
- if (al.constSpecifier) result+=" const";
- if (al.volatileSpecifier) result+=" volatile";
- if (al.refQualifier==RefQualifierLValue) result+=" &";
- else if (al.refQualifier==RefQualifierRValue) result+=" &&";
- if (!al.trailingReturnType.isEmpty()) result+=" -> "+al.trailingReturnType;
- if (al.pureSpecifier) result+=" =0";
+ if (al.constSpecifier()) result+=" const";
+ if (al.volatileSpecifier()) result+=" volatile";
+ if (al.refQualifier()==RefQualifierLValue) result+=" &";
+ else if (al.refQualifier()==RefQualifierRValue) result+=" &&";
+ if (!al.trailingReturnType().isEmpty()) result+=al.trailingReturnType();
+ if (al.pureSpecifier()) result+=" =0";
return removeRedundantWhiteSpace(result);
}
-QCString tempArgListToString(const ArgumentList &al,SrcLangExt lang)
+QCString tempArgListToString(const ArgumentList &al,SrcLangExt lang,bool includeDefault)
{
QCString result;
if (al.empty()) return result;
result="<";
- auto it = al.begin();
- while (it!=al.end())
+ bool first=true;
+ for (const auto &a : al)
{
- Argument a = *it;
- if (!a.name.isEmpty()) // add template argument name
+ if (a.defval.isEmpty() || includeDefault)
{
- if (a.type.left(4)=="out") // C# covariance
+ if (!first) result+=", ";
+ if (!a.name.isEmpty()) // add template argument name
{
- result+="out ";
- }
- else if (a.type.left(3)=="in") // C# contravariance
- {
- result+="in ";
- }
- if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
- {
- result+=a.type+" ";
+ if (a.type.left(4)=="out") // C# covariance
+ {
+ result+="out ";
+ }
+ else if (a.type.left(3)=="in") // C# contravariance
+ {
+ result+="in ";
+ }
+ if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
+ {
+ result+=a.type+" ";
+ }
+ result+=a.name;
}
- result+=a.name;
- }
- else // extract name from type
- {
- int i=a.type.length()-1;
- while (i>=0 && isId(a.type.at(i))) i--;
- if (i>0)
+ else // extract name from type
{
- result+=a.type.right(a.type.length()-i-1);
- if (a.type.find("...")!=-1)
+ int i=a.type.length()-1;
+ while (i>=0 && isId(a.type.at(i))) i--;
+ if (i>0)
+ {
+ result+=a.type.right(a.type.length()-i-1);
+ if (a.type.find("...")!=-1)
+ {
+ result+="...";
+ }
+ }
+ else // nothing found -> take whole name
{
- result+="...";
+ result+=a.type;
}
}
- else // nothing found -> take whole name
+ if (!a.typeConstraint.isEmpty() && lang==SrcLangExt_Java)
{
- result+=a.type;
+ result+=" extends "; // TODO: now Java specific, C# has where...
+ result+=a.typeConstraint;
}
+ first=false;
}
- if (!a.typeConstraint.isEmpty() && lang==SrcLangExt_Java)
- {
- result+=" extends "; // TODO: now Java specific, C# has where...
- result+=a.typeConstraint;
- }
- ++it;
- if (it!=al.end()) result+=", ";
}
result+=">";
return removeRedundantWhiteSpace(result);
}
-// compute the HTML anchors for a list of members
-void setAnchors(MemberList *ml)
-{
- //int count=0;
- if (ml==0) return;
- MemberListIterator mli(*ml);
- MemberDef *md;
- for (;(md=mli.current());++mli)
- {
- if (!md->isReference())
- {
- //QCString anchor;
- //if (groupId==-1)
- // anchor.sprintf("%c%d",id,count++);
- //else
- // anchor.sprintf("%c%d_%d",id,groupId,count++);
- //if (cd) anchor.prepend(escapeCharsInString(cd->name(),FALSE));
- md->setAnchor();
- //printf("setAnchors(): Member %s outputFileBase=%s anchor %s result %s\n",
- // md->name().data(),md->getOutputFileBase().data(),anchor.data(),md->anchor().data());
- }
- }
-}
-
//----------------------------------------------------------------------------
/*! takes the \a buf of the given length \a len and converts CR LF (DOS)
@@ -2404,7 +1238,7 @@ int filterCRLF(char *buf,int len)
{
c = '\n'; // each CR to LF
if (src<len && buf[src] == '\n')
- ++src; // skip LF just after CR (DOS)
+ ++src; // skip LF just after CR (DOS)
}
else if ( c == '\0' && src<len-1) // filter out internal \0 characters, as it will confuse the parser
{
@@ -2415,21 +1249,19 @@ int filterCRLF(char *buf,int len)
return dest; // length of the valid part of the buf
}
-static QCString getFilterFromList(const char *name,const QStrList &filterList,bool &found)
+static QCString getFilterFromList(const char *name,const StringVector &filterList,bool &found)
{
found=FALSE;
// compare the file name to the filter pattern list
- QStrListIterator sli(filterList);
- char* filterStr;
- for (sli.toFirst(); (filterStr = sli.current()); ++sli)
+ for (const auto &filterStr : filterList)
{
- QCString fs = filterStr;
+ QCString fs = filterStr.c_str();
int i_equals=fs.find('=');
if (i_equals!=-1)
{
QCString filterPattern = fs.left(i_equals);
- QRegExp fpat(filterPattern,Portable::fileSystemIsCaseSensitive(),TRUE);
- if (fpat.match(name)!=-1)
+ QRegExp fpat(filterPattern,Portable::fileSystemIsCaseSensitive(),TRUE);
+ if (fpat.match(name)!=-1)
{
// found a match!
QCString filterName = fs.mid(i_equals+1);
@@ -2457,12 +1289,12 @@ QCString getFileFilter(const char* name,bool isSourceCode)
// sanity check
if (name==0) return "";
- QStrList& filterSrcList = Config_getList(FILTER_SOURCE_PATTERNS);
- QStrList& filterList = Config_getList(FILTER_PATTERNS);
+ const StringVector& filterSrcList = Config_getList(FILTER_SOURCE_PATTERNS);
+ const StringVector& filterList = Config_getList(FILTER_PATTERNS);
QCString filterName;
bool found=FALSE;
- if (isSourceCode && !filterSrcList.isEmpty())
+ if (isSourceCode && !filterSrcList.empty())
{ // first look for source filter pattern list
filterName = getFilterFromList(name,filterSrcList,found);
}
@@ -2497,7 +1329,7 @@ QCString transcodeCharacterStringToUTF8(const QCString &input)
int outputSize=inputSize*4+1;
QCString output(outputSize);
void *cd = portable_iconv_open(outputEncoding,inputEncoding);
- if (cd==(void *)(-1))
+ if (cd==(void *)(-1))
{
err("unsupported character conversion: '%s'->'%s'\n",
inputEncoding.data(),outputEncoding);
@@ -2529,7 +1361,7 @@ QCString transcodeCharacterStringToUTF8(const QCString &input)
/*! reads a file with name \a name and returns it as a string. If \a filter
* is TRUE the file will be filtered by any user specified input filter.
- * If \a name is "-" the string will be read from standard input.
+ * If \a name is "-" the string will be read from standard input.
*/
QCString fileToString(const char *name,bool filter,bool isSourceCode)
{
@@ -2543,13 +1375,13 @@ QCString fileToString(const char *name,bool filter,bool isSourceCode)
if (fileOpened)
{
const int bSize=4096;
- QCString contents(bSize);
+ QCString contents(bSize+1);
int totalSize=0;
int size;
while ((size=f.readBlock(contents.rawData()+totalSize,bSize))==bSize)
{
totalSize+=bSize;
- contents.resize(totalSize+bSize);
+ contents.resize(totalSize+bSize+1);
}
totalSize = filterCRLF(contents.rawData(),totalSize+size)+2;
contents.resize(totalSize);
@@ -2579,7 +1411,7 @@ QCString fileToString(const char *name,bool filter,bool isSourceCode)
return buf.data();
}
}
- if (!fileOpened)
+ if (!fileOpened)
{
err("cannot open file '%s' for reading\n",name);
}
@@ -2609,7 +1441,7 @@ static QDateTime getCurrentDateTime()
static bool warnedOnce=FALSE;
if (!warnedOnce)
{
- warn_uncond("Environment variable SOURCE_DATE_EPOCH must have a value smaller than or equal to %llu; actual value %llu\n",UINT_MAX,epoch);
+ warn_uncond("Environment variable SOURCE_DATE_EPOCH must have a value smaller than or equal to %d; actual value %" PRIu64 "\n",UINT_MAX, (uint64_t)epoch);
warnedOnce=TRUE;
}
}
@@ -2643,46 +1475,41 @@ QCString yearToString()
}
//----------------------------------------------------------------------
-// recursive function that returns the number of branches in the
+// recursive function that returns the number of branches in the
// inheritance tree that the base class 'bcd' is below the class 'cd'
int minClassDistance(const ClassDef *cd,const ClassDef *bcd,int level)
{
- if (bcd->categoryOf()) // use class that is being extended in case of
+ if (bcd->categoryOf()) // use class that is being extended in case of
// an Objective-C category
{
bcd=bcd->categoryOf();
}
- if (cd==bcd) return level;
+ if (cd==bcd) return level;
if (level==256)
{
warn_uncond("class %s seem to have a recursive "
"inheritance relation!\n",cd->name().data());
return -1;
}
- int m=maxInheritanceDepth;
- if (cd->baseClasses())
+ int m=maxInheritanceDepth;
+ for (const auto &bcdi : cd->baseClasses())
{
- BaseClassListIterator bcli(*cd->baseClasses());
- BaseClassDef *bcdi;
- for (;(bcdi=bcli.current());++bcli)
- {
- int mc=minClassDistance(bcdi->classDef,bcd,level+1);
- if (mc<m) m=mc;
- if (m<0) break;
- }
+ int mc=minClassDistance(bcdi.classDef,bcd,level+1);
+ if (mc<m) m=mc;
+ if (m<0) break;
}
return m;
}
Protection classInheritedProtectionLevel(const ClassDef *cd,const ClassDef *bcd,Protection prot,int level)
{
- if (bcd->categoryOf()) // use class that is being extended in case of
+ if (bcd->categoryOf()) // use class that is being extended in case of
// an Objective-C category
{
bcd=bcd->categoryOf();
}
- if (cd==bcd)
+ if (cd==bcd)
{
goto exit;
}
@@ -2691,14 +1518,12 @@ Protection classInheritedProtectionLevel(const ClassDef *cd,const ClassDef *bcd,
err("Internal inconsistency: found class %s seem to have a recursive "
"inheritance relation! Please send a bug report to doxygen@gmail.com\n",cd->name().data());
}
- else if (cd->baseClasses())
+ else if (prot!=Private)
{
- BaseClassListIterator bcli(*cd->baseClasses());
- const BaseClassDef *bcdi;
- for (;(bcdi=bcli.current()) && prot!=Private;++bcli)
+ for (const auto &bcdi : cd->baseClasses())
{
- Protection baseProt = classInheritedProtectionLevel(bcdi->classDef,bcd,bcdi->prot,level+1);
- if (baseProt==Private) prot=Private;
+ Protection baseProt = classInheritedProtectionLevel(bcdi.classDef,bcd,bcdi.prot,level+1);
+ if (baseProt==Private) prot=Private;
else if (baseProt==Protected) prot=Protected;
}
}
@@ -2707,173 +1532,12 @@ exit:
return prot;
}
-#ifndef NEWMATCH
-// strip any template specifiers that follow className in string s
-static QCString trimTemplateSpecifiers(
- const QCString &namespaceName,
- const QCString &className,
- const QCString &s
- )
-{
- //printf("trimTemplateSpecifiers(%s,%s,%s)\n",namespaceName.data(),className.data(),s.data());
- QCString scopeName=mergeScopes(namespaceName,className);
- ClassDef *cd=getClass(scopeName);
- if (cd==0) return s; // should not happen, but guard anyway.
-
- QCString result=s;
-
- int i=className.length()-1;
- if (i>=0 && className.at(i)=='>') // template specialization
- {
- // replace unspecialized occurrences in s, with their specialized versions.
- int count=1;
- int cl=i+1;
- while (i>=0)
- {
- char c=className.at(i);
- if (c=='>') count++,i--;
- else if (c=='<') { count--; if (count==0) break; }
- else i--;
- }
- QCString unspecClassName=className.left(i);
- int l=i;
- int p=0;
- while ((i=result.find(unspecClassName,p))!=-1)
- {
- if (result.at(i+l)!='<') // unspecialized version
- {
- result=result.left(i)+className+result.right(result.length()-i-l);
- l=cl;
- }
- p=i+l;
- }
- }
-
- //printf("result after specialization: %s\n",result.data());
-
- QCString qualName=cd->qualifiedNameWithTemplateParameters();
- //printf("QualifiedName = %s\n",qualName.data());
- // We strip the template arguments following className (if any)
- if (!qualName.isEmpty()) // there is a class name
- {
- int is,ps=0;
- int p=0,l,i;
-
- while ((is=getScopeFragment(qualName,ps,&l))!=-1)
- {
- QCString qualNamePart = qualName.right(qualName.length()-is);
- //printf("qualNamePart=%s\n",qualNamePart.data());
- while ((i=result.find(qualNamePart,p))!=-1)
- {
- int ql=qualNamePart.length();
- result=result.left(i)+cd->name()+result.right(result.length()-i-ql);
- p=i+cd->name().length();
- }
- ps=is+l;
- }
- }
- //printf("result=%s\n",result.data());
-
- return result.stripWhiteSpace();
-}
-
-/*!
- * @param pattern pattern to look for
- * @param s string to search in
- * @param p position to start
- * @param len resulting pattern length
- * @returns position on which string is found, or -1 if not found
- */
-static int findScopePattern(const QCString &pattern,const QCString &s,
- int p,int *len)
-{
- int sl=s.length();
- int pl=pattern.length();
- int sp=0;
- *len=0;
- while (p<sl)
- {
- sp=p; // start of match
- int pp=0; // pattern position
- while (p<sl && pp<pl)
- {
- if (s.at(p)=='<') // skip template arguments while matching
- {
- int bc=1;
- //printf("skipping pos=%d c=%c\n",p,s.at(p));
- p++;
- while (p<sl)
- {
- if (s.at(p)=='<') bc++;
- else if (s.at(p)=='>')
- {
- bc--;
- if (bc==0)
- {
- p++;
- break;
- }
- }
- //printf("skipping pos=%d c=%c\n",p,s.at(p));
- p++;
- }
- }
- else if (s.at(p)==pattern.at(pp))
- {
- //printf("match at position p=%d pp=%d c=%c\n",p,pp,s.at(p));
- p++;
- pp++;
- }
- else // no match
- {
- //printf("restarting at %d c=%c pat=%s\n",p,s.at(p),pattern.data());
- p=sp+1;
- break;
- }
- }
- if (pp==pl) // whole pattern matches
- {
- *len=p-sp;
- return sp;
- }
- }
- return -1;
-}
-
-static QCString trimScope(const QCString &name,const QCString &s)
-{
- int scopeOffset=name.length();
- QCString result=s;
- do // for each scope
- {
- QCString tmp;
- QCString scope=name.left(scopeOffset)+"::";
- //printf("Trying with scope='%s'\n",scope.data());
-
- int i,p=0,l;
- while ((i=findScopePattern(scope,result,p,&l))!=-1) // for each occurrence
- {
- tmp+=result.mid(p,i-p); // add part before pattern
- p=i+l;
- }
- tmp+=result.right(result.length()-p); // add trailing part
-
- scopeOffset=name.findRev("::",scopeOffset-1);
- result = tmp;
- } while (scopeOffset>0);
- //printf("trimScope(name=%s,scope=%s)=%s\n",name.data(),s.data(),result.data());
- return result;
-}
-#endif
-
-void trimBaseClassScope(BaseClassList *bcl,QCString &s,int level=0)
+void trimBaseClassScope(const BaseClassList &bcl,QCString &s,int level=0)
{
//printf("trimBaseClassScope level=%d '%s'\n",level,s.data());
- BaseClassListIterator bcli(*bcl);
- BaseClassDef *bcd;
- for (;(bcd=bcli.current());++bcli)
+ for (const auto &bcd : bcl)
{
- ClassDef *cd=bcd->classDef;
+ ClassDef *cd=bcd.classDef;
//printf("Trying class %s\n",cd->name().data());
int spos=s.find(cd->name()+"::");
if (spos!=-1)
@@ -2883,8 +1547,10 @@ void trimBaseClassScope(BaseClassList *bcl,QCString &s,int level=0)
);
}
//printf("base class '%s'\n",cd->name().data());
- if (cd->baseClasses())
- trimBaseClassScope(cd->baseClasses(),s,level+1);
+ if (!cd->baseClasses().empty())
+ {
+ trimBaseClassScope(cd->baseClasses(),s,level+1);
+ }
}
}
@@ -2982,7 +1648,7 @@ static void stripIrrelevantString(QCString &target,const QCString &str)
if (i1==-1 && i2==-1)
{
// strip str from target at index i
- target=target.left(i)+target.right(target.length()-i-l);
+ target=target.left(i)+target.right(target.length()-i-l);
changed=TRUE;
i-=l;
}
@@ -3011,8 +1677,8 @@ static void stripIrrelevantString(QCString &target,const QCString &str)
\code
const T param -> T param // not relevant
- const T& param -> const T& param // const needed
- T* const param -> T* param // not relevant
+ const T& param -> const T& param // const needed
+ T* const param -> T* param // not relevant
const T* param -> const T* param // const needed
\endcode
*/
@@ -3032,276 +1698,6 @@ void stripIrrelevantConstVolatile(QCString &s)
//#define MATCH printf("Match at line %d\n",__LINE__);
//#define NOMATCH printf("Nomatch at line %d\n",__LINE__);
-#ifndef NEWMATCH
-static bool matchArgument(const Argument *srcA,const Argument *dstA,
- const QCString &className,
- const QCString &namespaceName,
- NamespaceSDict *usingNamespaces,
- SDict<Definition> *usingClasses)
-{
- //printf("match argument start '%s|%s' <-> '%s|%s' using nsp=%p class=%p\n",
- // srcA->type.data(),srcA->name.data(),
- // dstA->type.data(),dstA->name.data(),
- // usingNamespaces,
- // usingClasses);
-
- // TODO: resolve any typedefs names that are part of srcA->type
- // before matching. This should use className and namespaceName
- // and usingNamespaces and usingClass to determine which typedefs
- // are in-scope, so it will not be very efficient :-(
-
- QCString srcAType=trimTemplateSpecifiers(namespaceName,className,srcA->type);
- QCString dstAType=trimTemplateSpecifiers(namespaceName,className,dstA->type);
- QCString srcAName=srcA->name.stripWhiteSpace();
- QCString dstAName=dstA->name.stripWhiteSpace();
- srcAType.stripPrefix("class ");
- dstAType.stripPrefix("class ");
-
- // allow distinguishing "const A" from "const B" even though
- // from a syntactic point of view they would be two names of the same
- // type "const". This is not fool prove of course, but should at least
- // catch the most common cases.
- if ((srcAType=="const" || srcAType=="volatile") && !srcAName.isEmpty())
- {
- srcAType+=" ";
- srcAType+=srcAName;
- }
- if ((dstAType=="const" || dstAType=="volatile") && !dstAName.isEmpty())
- {
- dstAType+=" ";
- dstAType+=dstAName;
- }
- if (srcAName=="const" || srcAName=="volatile")
- {
- srcAType+=srcAName;
- srcAName.resize(0);
- }
- else if (dstA->name=="const" || dstA->name=="volatile")
- {
- dstAType+=dstA->name;
- dstAName.resize(0);
- }
-
- stripIrrelevantConstVolatile(srcAType);
- stripIrrelevantConstVolatile(dstAType);
-
- // strip typename keyword
- if (qstrncmp(srcAType,"typename ",9)==0)
- {
- srcAType = srcAType.right(srcAType.length()-9);
- }
- if (qstrncmp(dstAType,"typename ",9)==0)
- {
- dstAType = dstAType.right(dstAType.length()-9);
- }
-
- srcAType = removeRedundantWhiteSpace(srcAType);
- dstAType = removeRedundantWhiteSpace(dstAType);
-
- //srcAType=stripTemplateSpecifiersFromScope(srcAType,FALSE);
- //dstAType=stripTemplateSpecifiersFromScope(dstAType,FALSE);
-
- //printf("srcA='%s|%s' dstA='%s|%s'\n",srcAType.data(),srcAName.data(),
- // dstAType.data(),dstAName.data());
-
- if (srcA->array!=dstA->array) // nomatch for char[] against char
- {
- NOMATCH
- return FALSE;
- }
- if (srcAType!=dstAType) // check if the argument only differs on name
- {
-
- // remove a namespace scope that is only in one type
- // (assuming a using statement was used)
- //printf("Trimming %s<->%s: %s\n",srcAType.data(),dstAType.data(),namespaceName.data());
- //trimNamespaceScope(srcAType,dstAType,namespaceName);
- //printf("After Trimming %s<->%s\n",srcAType.data(),dstAType.data());
-
- //QCString srcScope;
- //QCString dstScope;
-
- // strip redundant scope specifiers
- if (!className.isEmpty())
- {
- srcAType=trimScope(className,srcAType);
- dstAType=trimScope(className,dstAType);
- //printf("trimScope: '%s' <=> '%s'\n",srcAType.data(),dstAType.data());
- ClassDef *cd;
- if (!namespaceName.isEmpty())
- cd=getClass(namespaceName+"::"+className);
- else
- cd=getClass(className);
- if (cd && cd->baseClasses())
- {
- trimBaseClassScope(cd->baseClasses(),srcAType);
- trimBaseClassScope(cd->baseClasses(),dstAType);
- }
- //printf("trimBaseClassScope: '%s' <=> '%s'\n",srcAType.data(),dstAType.data());
- }
- if (!namespaceName.isEmpty())
- {
- srcAType=trimScope(namespaceName,srcAType);
- dstAType=trimScope(namespaceName,dstAType);
- }
- //printf("#usingNamespace=%d\n",usingNamespaces->count());
- if (usingNamespaces && usingNamespaces->count()>0)
- {
- NamespaceSDict::Iterator nli(*usingNamespaces);
- NamespaceDef *nd;
- for (;(nd=nli.current());++nli)
- {
- srcAType=trimScope(nd->name(),srcAType);
- dstAType=trimScope(nd->name(),dstAType);
- }
- }
- //printf("#usingClasses=%d\n",usingClasses->count());
- if (usingClasses && usingClasses->count()>0)
- {
- SDict<Definition>::Iterator cli(*usingClasses);
- Definition *cd;
- for (;(cd=cli.current());++cli)
- {
- srcAType=trimScope(cd->name(),srcAType);
- dstAType=trimScope(cd->name(),dstAType);
- }
- }
-
- //printf("2. srcA=%s|%s dstA=%s|%s\n",srcAType.data(),srcAName.data(),
- // dstAType.data(),dstAName.data());
-
- if (!srcAName.isEmpty() && !dstA->type.isEmpty() &&
- (srcAType+" "+srcAName)==dstAType)
- {
- MATCH
- return TRUE;
- }
- else if (!dstAName.isEmpty() && !srcA->type.isEmpty() &&
- (dstAType+" "+dstAName)==srcAType)
- {
- MATCH
- return TRUE;
- }
-
-
- uint srcPos=0,dstPos=0;
- bool equal=TRUE;
- while (srcPos<srcAType.length() && dstPos<dstAType.length() && equal)
- {
- equal=srcAType.at(srcPos)==dstAType.at(dstPos);
- if (equal) srcPos++,dstPos++;
- }
- uint srcATypeLen=srcAType.length();
- uint dstATypeLen=dstAType.length();
- if (srcPos<srcATypeLen && dstPos<dstATypeLen)
- {
- // if nothing matches or the match ends in the middle or at the
- // end of a string then there is no match
- if (srcPos==0 || dstPos==0)
- {
- NOMATCH
- return FALSE;
- }
- if (isId(srcAType.at(srcPos)) && isId(dstAType.at(dstPos)))
- {
- //printf("partial match srcPos=%d dstPos=%d!\n",srcPos,dstPos);
- // check if a name if already found -> if no then there is no match
- if (!srcAName.isEmpty() || !dstAName.isEmpty())
- {
- NOMATCH
- return FALSE;
- }
- // types only
- while (srcPos<srcATypeLen && isId(srcAType.at(srcPos))) srcPos++;
- while (dstPos<dstATypeLen && isId(dstAType.at(dstPos))) dstPos++;
- if (srcPos<srcATypeLen ||
- dstPos<dstATypeLen ||
- (srcPos==srcATypeLen && dstPos==dstATypeLen)
- )
- {
- NOMATCH
- return FALSE;
- }
- }
- else
- {
- // otherwise we assume that a name starts at the current position.
- while (srcPos<srcATypeLen && isId(srcAType.at(srcPos))) srcPos++;
- while (dstPos<dstATypeLen && isId(dstAType.at(dstPos))) dstPos++;
-
- // if nothing more follows for both types then we assume we have
- // found a match. Note that now 'signed int' and 'signed' match, but
- // seeing that int is not a name can only be done by looking at the
- // semantics.
-
- if (srcPos!=srcATypeLen || dstPos!=dstATypeLen)
- {
- NOMATCH
- return FALSE;
- }
- }
- }
- else if (dstPos<dstAType.length())
- {
- if (!isspace((uchar)dstAType.at(dstPos))) // maybe the names differ
- {
- if (!dstAName.isEmpty()) // dst has its name separated from its type
- {
- NOMATCH
- return FALSE;
- }
- while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
- if (dstPos!=dstAType.length())
- {
- NOMATCH
- return FALSE; // more than a difference in name -> no match
- }
- }
- else // maybe dst has a name while src has not
- {
- dstPos++;
- while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
- if (dstPos!=dstAType.length() || !srcAName.isEmpty())
- {
- NOMATCH
- return FALSE; // nope not a name -> no match
- }
- }
- }
- else if (srcPos<srcAType.length())
- {
- if (!isspace((uchar)srcAType.at(srcPos))) // maybe the names differ
- {
- if (!srcAName.isEmpty()) // src has its name separated from its type
- {
- NOMATCH
- return FALSE;
- }
- while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
- if (srcPos!=srcAType.length())
- {
- NOMATCH
- return FALSE; // more than a difference in name -> no match
- }
- }
- else // maybe src has a name while dst has not
- {
- srcPos++;
- while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
- if (srcPos!=srcAType.length() || !dstAName.isEmpty())
- {
- NOMATCH
- return FALSE; // nope not a name -> no match
- }
- }
- }
- }
- MATCH
- return TRUE;
-}
-
-#endif
-
static QCString stripDeclKeywords(const QCString &s)
{
int i=s.find(" class ");
@@ -3320,11 +1716,11 @@ static QCString extractCanonicalType(const Definition *d,const FileDef *fs,QCStr
QCString getCanonicalTemplateSpec(const Definition *d,const FileDef *fs,const QCString& spec)
{
-
+
QCString templSpec = spec.stripWhiteSpace();
// this part had been commented out before... but it is needed to match for instance
// std::list<std::string> against list<string> so it is now back again!
- if (!templSpec.isEmpty() && templSpec.at(0) == '<')
+ if (!templSpec.isEmpty() && templSpec.at(0) == '<')
{
templSpec = "< " + extractCanonicalType(d,fs,templSpec.right(templSpec.length()-1).stripWhiteSpace());
}
@@ -3345,8 +1741,7 @@ static QCString getCanonicalTypeForIdentifier(
if (count>10) return word; // oops recursion
QCString symName,result,templSpec,tmpName;
- //DefinitionList *defList=0;
- if (tSpec && !tSpec->isEmpty())
+ if (tSpec && !tSpec->isEmpty())
templSpec = stripDeclKeywords(getCanonicalTemplateSpec(d,fs,*tSpec));
if (word.findRev("::")!=-1 && !(tmpName=stripScope(word)).isEmpty())
@@ -3357,21 +1752,26 @@ static QCString getCanonicalTypeForIdentifier(
{
symName=word;
}
- //printf("getCanonicalTypeForIdentifier(%s,[%s->%s]) start\n",
- // word.data(),tSpec?tSpec->data():"<none>",templSpec.data());
-
- const ClassDef *cd = 0;
- const MemberDef *mType = 0;
- QCString ts;
- QCString resolvedType;
+ //printf("getCanonicalTypeForIdentifier(%s d=%s fs=%s ,[%s->%s]) start\n",
+ // word.data(),
+ // d ? d->name().data() : "<null>",fs ? fs->name().data() : "<null>",
+ // tSpec?tSpec->data():"<none>",templSpec.data());
// lookup class / class template instance
- cd = getResolvedClass(d,fs,word+templSpec,&mType,&ts,TRUE,TRUE,&resolvedType);
+ SymbolResolver resolver(fs);
+ const ClassDef *cd = resolver.resolveClass(d,word+templSpec,true,true);
+ const MemberDef *mType = resolver.getTypedef();
+ QCString ts = resolver.getTemplateSpec();
+ QCString resolvedType = resolver.getResolvedType();
+
bool isTemplInst = cd && !templSpec.isEmpty();
if (!cd && !templSpec.isEmpty())
{
// class template specialization not known, look up class template
- cd = getResolvedClass(d,fs,word,&mType,&ts,TRUE,TRUE,&resolvedType);
+ cd = resolver.resolveClass(d,word,true,true);
+ mType = resolver.getTypedef();
+ ts = resolver.getTemplateSpec();
+ resolvedType = resolver.getResolvedType();
}
if (cd && cd->isUsedOnly()) cd=0; // ignore types introduced by usage relations
@@ -3451,7 +1851,13 @@ static QCString getCanonicalTypeForIdentifier(
//printf("word=%s typeString=%s\n",word.data(),mType->typeString());
if (word!=mType->typeString())
{
- result = getCanonicalTypeForIdentifier(d,fs,mType->typeString(),tSpec,count+1);
+ QCString type = mType->typeString();
+ if (type.startsWith("typename "))
+ {
+ type.stripPrefix("typename ");
+ type = stripTemplateSpecifiersFromScope(type,FALSE);
+ }
+ result = getCanonicalTypeForIdentifier(d,fs,type,tSpec,count+1);
}
else
{
@@ -3504,11 +1910,10 @@ static QCString extractCanonicalType(const Definition *d,const FileDef *fs,QCStr
//printf(" i=%d p=%d\n",i,p);
if (i>pp) canType += type.mid(pp,i-pp);
-
QCString ct = getCanonicalTypeForIdentifier(d,fs,word,&templSpec);
// in case the ct is empty it means that "word" represents scope "d"
- // and this does not need to be added to the canonical
+ // and this does not need to be added to the canonical
// type (it is redundant), so/ we skip it. This solves problem 589616.
if (ct.isEmpty() && type.mid(p,2)=="::")
{
@@ -3522,7 +1927,7 @@ static QCString extractCanonicalType(const Definition *d,const FileDef *fs,QCStr
// word.data(),templSpec.data(),canType.data(),ct.data());
if (!templSpec.isEmpty()) // if we didn't use up the templSpec already
// (i.e. type is not a template specialization)
- // then resolve any identifiers inside.
+ // then resolve any identifiers inside.
{
static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
int tp=0,tl,ti;
@@ -3550,11 +1955,11 @@ static QCString extractCanonicalArgType(const Definition *d,const FileDef *fs,co
QCString type = arg.type.stripWhiteSpace();
QCString name = arg.name;
//printf("----- extractCanonicalArgType(type=%s,name=%s)\n",type.data(),name.data());
- if ((type=="const" || type=="volatile") && !name.isEmpty())
+ if ((type=="const" || type=="volatile") && !name.isEmpty())
{ // name is part of type => correct
type+=" ";
type+=name;
- }
+ }
if (name=="const" || name=="volatile")
{ // name is part of type => correct
if (!type.isEmpty()) type+=" ";
@@ -3575,9 +1980,9 @@ static bool matchArgument2(
{
//printf(">> match argument: %s::'%s|%s' (%s) <-> %s::'%s|%s' (%s)\n",
// srcScope ? srcScope->name().data() : "",
- // srcA->type.data(),srcA->name.data(),srcA->canType.data(),
+ // srcA.type.data(),srcA.name.data(),srcA.canType.data(),
// dstScope ? dstScope->name().data() : "",
- // dstA->type.data(),dstA->name.data(),dstA->canType.data());
+ // dstA.type.data(),dstA.name.data(),dstA.canType.data());
//if (srcA->array!=dstA->array) // nomatch for char[] against char
//{
@@ -3630,34 +2035,46 @@ static bool matchArgument2(
// new algorithm for argument matching
-bool matchArguments2(const Definition *srcScope,const FileDef *srcFileScope,const ArgumentList &inSrcAl,
- const Definition *dstScope,const FileDef *dstFileScope,const ArgumentList &inDstAl,
+bool matchArguments2(const Definition *srcScope,const FileDef *srcFileScope,const ArgumentList *srcAl,
+ const Definition *dstScope,const FileDef *dstFileScope,const ArgumentList *dstAl,
bool checkCV)
{
ASSERT(srcScope!=0 && dstScope!=0);
- ArgumentList srcAl = inSrcAl;
- ArgumentList dstAl = inDstAl;
+ if (srcAl==0 || dstAl==0)
+ {
+ bool match = srcAl==dstAl;
+ if (match)
+ {
+ MATCH
+ return TRUE;
+ }
+ else
+ {
+ NOMATCH
+ return FALSE;
+ }
+ }
// handle special case with void argument
- if ( srcAl.empty() && dstAl.size()==1 && dstAl.front().type=="void" )
+ if ( srcAl->empty() && dstAl->size()==1 && dstAl->front().type=="void" )
{ // special case for finding match between func() and func(void)
Argument a;
a.type = "void";
- srcAl.push_back(a);
+ const_cast<ArgumentList*>(srcAl)->push_back(a);
MATCH
return TRUE;
}
- if ( dstAl.empty() && srcAl.size()==1 && srcAl.front().type=="void" )
+ if ( dstAl->empty() && srcAl->size()==1 && srcAl->front().type=="void" )
{ // special case for finding match between func(void) and func()
Argument a;
a.type = "void";
- dstAl.push_back(a);
+ const_cast<ArgumentList*>(dstAl)->push_back(a);
MATCH
return TRUE;
}
- if (srcAl.size() != dstAl.size())
+ if (srcAl->size() != dstAl->size())
{
NOMATCH
return FALSE; // different number of arguments -> no match
@@ -3665,19 +2082,19 @@ bool matchArguments2(const Definition *srcScope,const FileDef *srcFileScope,cons
if (checkCV)
{
- if (srcAl.constSpecifier != dstAl.constSpecifier)
+ if (srcAl->constSpecifier() != dstAl->constSpecifier())
{
NOMATCH
return FALSE; // one member is const, the other not -> no match
}
- if (srcAl.volatileSpecifier != dstAl.volatileSpecifier)
+ if (srcAl->volatileSpecifier() != dstAl->volatileSpecifier())
{
NOMATCH
return FALSE; // one member is volatile, the other not -> no match
}
}
- if (srcAl.refQualifier != dstAl.refQualifier)
+ if (srcAl->refQualifier() != dstAl->refQualifier())
{
NOMATCH
return FALSE; // one member is has a different ref-qualifier than the other
@@ -3685,12 +2102,12 @@ bool matchArguments2(const Definition *srcScope,const FileDef *srcFileScope,cons
// so far the argument list could match, so we need to compare the types of
// all arguments.
- auto srcIt = srcAl.begin();
- auto dstIt = dstAl.begin();
- for (;srcIt!=srcAl.end() && dstIt!=dstAl.end();++srcIt,++dstIt)
+ auto srcIt = srcAl->begin();
+ auto dstIt = dstAl->begin();
+ for (;srcIt!=srcAl->end() && dstIt!=dstAl->end();++srcIt,++dstIt)
{
- Argument &srcA = *srcIt;
- Argument &dstA = *dstIt;
+ Argument &srcA = const_cast<Argument&>(*srcIt);
+ Argument &dstA = const_cast<Argument&>(*dstIt);
if (!matchArgument2(srcScope,srcFileScope,srcA,
dstScope,dstFileScope,dstA)
)
@@ -3700,7 +2117,7 @@ bool matchArguments2(const Definition *srcScope,const FileDef *srcFileScope,cons
}
}
MATCH
- return TRUE; // all arguments match
+ return TRUE; // all arguments match
}
@@ -3843,44 +2260,40 @@ void mergeArguments(ArgumentList &srcAl,ArgumentList &dstAl,bool forceNameOverwr
}
}
-static void findMembersWithSpecificName(MemberName *mn,
+static void findMembersWithSpecificName(const MemberName *mn,
const char *args,
bool checkStatics,
const FileDef *currentFile,
bool checkCV,
- const char *forceTagFile,
QList<MemberDef> &members)
{
//printf(" Function with global scope name '%s' args='%s'\n",
// mn->memberName(),args);
- MemberNameIterator mli(*mn);
- const MemberDef *md = 0;
- for (mli.toFirst();(md=mli.current());++mli)
+ for (const auto &md_p : *mn)
{
+ const MemberDef *md = md_p.get();
const FileDef *fd=md->getFileDef();
const GroupDef *gd=md->getGroupDef();
//printf(" md->name()='%s' md->args='%s' fd=%p gd=%p current=%p ref=%s\n",
// md->name().data(),args,fd,gd,currentFile,md->getReference().data());
if (
- ((gd && gd->isLinkable()) || (fd && fd->isLinkable()) || md->isReference()) &&
+ ((gd && gd->isLinkable()) || (fd && fd->isLinkable()) || md->isReference()) &&
md->getNamespaceDef()==0 && md->isLinkable() &&
- (!checkStatics || (!md->isStatic() && !md->isDefine()) ||
+ (!checkStatics || (!md->isStatic() && !md->isDefine()) ||
currentFile==0 || fd==currentFile) // statics must appear in the same file
- )
+ )
{
bool match=TRUE;
- ArgumentList *argList=0;
if (args && !md->isDefine() && qstrcmp(args,"()")!=0)
{
const ArgumentList &mdAl = md->argumentList();
- ArgumentList argList;
- stringToArgumentList(md->getLanguage(),args,argList);
+ auto argList_p = stringToArgumentList(md->getLanguage(),args);
match=matchArguments2(
- md->getOuterScope(),fd,mdAl,
- Doxygen::globalScope,fd,argList,
+ md->getOuterScope(),fd,&mdAl,
+ Doxygen::globalScope,fd,argList_p.get(),
checkCV);
}
- if (match && (forceTagFile==0 || md->getReference()==forceTagFile))
+ if (match)
{
//printf("Found match!\n");
members.append(md);
@@ -3894,17 +2307,17 @@ static void findMembersWithSpecificName(MemberName *mn,
* memberName may also include a (partial) scope to indicate the scope
* in which the member is located.
*
- * The parameter 'scName' is a string representing the name of the scope in
+ * The parameter 'scName' is a string representing the name of the scope in
* which the link was found.
*
- * In case of a function args contains a string representation of the
- * argument list. Passing 0 means the member has no arguments.
+ * In case of a function args contains a string representation of the
+ * argument list. Passing 0 means the member has no arguments.
* Passing "()" means any argument list will do, but "()" is preferred.
*
* The function returns TRUE if the member is known and documented or
* FALSE if it is not.
- * If TRUE is returned parameter 'md' contains a pointer to the member
- * definition. Furthermore exactly one of the parameter 'cd', 'nd', or 'fd'
+ * If TRUE is returned parameter 'md' contains a pointer to the member
+ * definition. Furthermore exactly one of the parameter 'cd', 'nd', or 'fd'
* will be non-zero:
* - if 'cd' is non zero, the member was found in a class pointed to by cd.
* - if 'nd' is non zero, the member was found in a namespace pointed to by nd.
@@ -3912,17 +2325,16 @@ static void findMembersWithSpecificName(MemberName *mn,
* file fd.
*/
bool getDefs(const QCString &scName,
- const QCString &mbName,
+ const QCString &mbName,
const char *args,
- const MemberDef *&md,
- const ClassDef *&cd,
- const FileDef *&fd,
- const NamespaceDef *&nd,
+ const MemberDef *&md,
+ const ClassDef *&cd,
+ const FileDef *&fd,
+ const NamespaceDef *&nd,
const GroupDef *&gd,
bool forceEmptyScope,
const FileDef *currentFile,
- bool checkCV,
- const char *forceTagFile
+ bool checkCV
)
{
fd=0, md=0, cd=0, nd=0, gd=0;
@@ -3937,12 +2349,12 @@ bool getDefs(const QCString &scName,
int is,im=0,pm=0;
// strip common part of the scope from the scopeName
- while ((is=scopeName.findRev("::"))!=-1 &&
+ while ((is=scopeName.findRev("::"))!=-1 &&
(im=memberName.find("::",pm))!=-1 &&
(scopeName.right(scopeName.length()-is-2)==memberName.mid(pm,im-pm))
)
{
- scopeName=scopeName.left(is);
+ scopeName=scopeName.left(is);
pm=im+2;
}
//printf("result after scope corrections scope=%s name=%s\n",
@@ -3952,11 +2364,11 @@ bool getDefs(const QCString &scName,
QCString mScope;
if (memberName.left(9)!="operator " && // treat operator conversion methods
// as a special case
- (im=memberName.findRev("::"))!=-1 &&
+ (im=memberName.findRev("::"))!=-1 &&
im<(int)memberName.length()-2 // not A::
)
{
- mScope=memberName.left(im);
+ mScope=memberName.left(im);
mName=memberName.right(memberName.length()-im-2);
}
@@ -3965,7 +2377,7 @@ bool getDefs(const QCString &scName,
//printf("mScope='%s' mName='%s'\n",mScope.data(),mName.data());
- MemberName *mn = Doxygen::memberNameSDict->find(mName);
+ MemberName *mn = Doxygen::memberNameLinkedMap->find(mName);
//printf("mName=%s mn=%p\n",mName.data(),mn);
if ((!forceEmptyScope || scopeName.isEmpty()) && // this was changed for bug638856, forceEmptyScope => empty scopeName
@@ -3985,41 +2397,43 @@ bool getDefs(const QCString &scName,
className=mScope;
}
- const MemberDef *tmd=0;
- const ClassDef *fcd=getResolvedClass(Doxygen::globalScope,0,className,&tmd);
+ SymbolResolver resolver;
+ const ClassDef *fcd=resolver.resolveClass(Doxygen::globalScope,className);
+ const MemberDef *tmd=resolver.getTypedef();
+
if (fcd==0 && className.find('<')!=-1) // try without template specifiers as well
{
QCString nameWithoutTemplates = stripTemplateSpecifiersFromScope(className,FALSE);
- fcd=getResolvedClass(Doxygen::globalScope,0,nameWithoutTemplates,&tmd);
+ fcd=resolver.resolveClass(Doxygen::globalScope,nameWithoutTemplates);
+ tmd=resolver.getTypedef();
}
//printf("Trying class scope %s: fcd=%p tmd=%p\n",className.data(),fcd,tmd);
// todo: fill in correct fileScope!
if (fcd && // is it a documented class
- fcd->isLinkable()
+ fcd->isLinkable()
)
{
//printf(" Found fcd=%p\n",fcd);
- MemberNameIterator mmli(*mn);
- MemberDef *mmd;
- int mdist=maxInheritanceDepth;
- ArgumentList argList;
+ int mdist=maxInheritanceDepth;
+ std::unique_ptr<ArgumentList> argList;
if (args)
{
- stringToArgumentList(fcd->getLanguage(),args,argList);
+ argList = stringToArgumentList(fcd->getLanguage(),args);
}
- for (mmli.toFirst();(mmd=mmli.current());++mmli)
+ for (const auto &mmd_p : *mn)
{
+ MemberDef *mmd = mmd_p.get();
if (!mmd->isStrongEnumValue())
{
const ArgumentList &mmdAl = mmd->argumentList();
bool match=args==0 ||
- matchArguments2(mmd->getOuterScope(),mmd->getFileDef(),mmdAl,
- fcd, fcd->getFileDef(),argList,
+ matchArguments2(mmd->getOuterScope(),mmd->getFileDef(),&mmdAl,
+ fcd, fcd->getFileDef(),argList.get(),
checkCV);
//printf("match=%d\n",match);
if (match)
{
- ClassDef *mcd=mmd->getClassDef();
+ const ClassDef *mcd=mmd->getClassDef();
if (mcd)
{
int m=minClassDistance(fcd,mcd);
@@ -4037,11 +2451,12 @@ bool getDefs(const QCString &scName,
// no exact match found, but if args="()" an arbitrary member will do
{
//printf(" >Searching for arbitrary member\n");
- for (mmli.toFirst();(mmd=mmli.current());++mmli)
+ for (const auto &mmd_p : *mn)
{
+ MemberDef *mmd = mmd_p.get();
//if (mmd->isLinkable())
//{
- ClassDef *mcd=mmd->getClassDef();
+ const ClassDef *mcd=mmd->getClassDef();
//printf(" >Class %s found\n",mcd->name().data());
if (mcd)
{
@@ -4058,9 +2473,9 @@ bool getDefs(const QCString &scName,
}
}
//printf(" >Success=%d\n",mdist<maxInheritanceDepth);
- if (mdist<maxInheritanceDepth)
+ if (mdist<maxInheritanceDepth)
{
- if (!md->isLinkable() || md->isStrongEnumValue())
+ if (!md->isLinkable() || md->isStrongEnumValue())
{
md=0; // avoid returning things we cannot link to
cd=0;
@@ -4073,7 +2488,7 @@ bool getDefs(const QCString &scName,
return TRUE; /* found match */
}
}
- }
+ }
if (tmd && tmd->isEnumerate() && tmd->isStrong()) // scoped enum
{
//printf("Found scoped enum!\n");
@@ -4117,18 +2532,18 @@ bool getDefs(const QCString &scName,
if (mn && scopeName.isEmpty() && mScope.isEmpty()) // Maybe a related function?
{
//printf("Global symbol\n");
- MemberNameIterator mmli(*mn);
- MemberDef *mmd, *fuzzy_mmd = 0;
- ArgumentList argList;
+ const MemberDef *fuzzy_mmd = 0;
+ std::unique_ptr<ArgumentList> argList;
bool hasEmptyArgs = args && qstrcmp(args, "()") == 0;
if (args)
{
- stringToArgumentList(SrcLangExt_Cpp, args, argList);
+ argList = stringToArgumentList(SrcLangExt_Cpp, args);
}
- for (mmli.toFirst(); (mmd = mmli.current()); ++mmli)
+ for (const auto &mmd_p : *mn)
{
+ const MemberDef *mmd = mmd_p.get();
if (!mmd->isLinkable() || (!mmd->isRelated() && !mmd->isForeign()) ||
!mmd->getClassDef())
{
@@ -4137,16 +2552,18 @@ bool getDefs(const QCString &scName,
if (!args)
{
+ fuzzy_mmd = mmd;
break;
}
- ArgumentList &mmdAl = mmd->argumentList();
- if (matchArguments2(mmd->getOuterScope(),mmd->getFileDef(),mmdAl,
- Doxygen::globalScope,mmd->getFileDef(),argList,
+ const ArgumentList &mmdAl = mmd->argumentList();
+ if (matchArguments2(mmd->getOuterScope(),mmd->getFileDef(),&mmdAl,
+ Doxygen::globalScope,mmd->getFileDef(),argList.get(),
checkCV
)
)
{
+ fuzzy_mmd = mmd;
break;
}
@@ -4156,12 +2573,10 @@ bool getDefs(const QCString &scName,
}
}
- mmd = mmd ? mmd : fuzzy_mmd;
-
- if (mmd && !mmd->isStrongEnumValue())
+ if (fuzzy_mmd && !fuzzy_mmd->isStrongEnumValue())
{
- md = mmd;
- cd = mmd->getClassDef();
+ md = fuzzy_mmd;
+ cd = fuzzy_mmd->getClassDef();
return TRUE;
}
}
@@ -4170,7 +2585,7 @@ bool getDefs(const QCString &scName,
// maybe an namespace, file or group member ?
//printf("Testing for global symbol scopeName='%s' mScope='%s' :: mName='%s'\n",
// scopeName.data(),mScope.data(),mName.data());
- if ((mn=Doxygen::functionNameSDict->find(mName))) // name is known
+ if ((mn=Doxygen::functionNameLinkedMap->find(mName))) // name is known
{
//printf(" >symbol name found\n");
NamespaceDef *fnd=0;
@@ -4187,31 +2602,31 @@ bool getDefs(const QCString &scName,
namespaceName=mScope.copy();
}
//printf("Trying namespace %s\n",namespaceName.data());
- if (!namespaceName.isEmpty() &&
- (fnd=Doxygen::namespaceSDict->find(namespaceName)) &&
+ if (!namespaceName.isEmpty() &&
+ (fnd=Doxygen::namespaceLinkedMap->find(namespaceName)) &&
fnd->isLinkable()
)
{
//printf("Symbol inside existing namespace '%s' count=%d\n",
// namespaceName.data(),mn->count());
bool found=FALSE;
- MemberNameIterator mmli(*mn);
- const MemberDef *mmd;
- for (mmli.toFirst();((mmd=mmli.current()) && !found);++mmli)
+ for (const auto &mmd_p : *mn)
{
+ const MemberDef *mmd = mmd_p.get();
//printf("mmd->getNamespaceDef()=%p fnd=%p\n",
// mmd->getNamespaceDef(),fnd);
const MemberDef *emd = mmd->getEnumScope();
if (emd && emd->isStrong())
{
//printf("yes match %s<->%s!\n",mScope.data(),emd->localName().data());
- if (emd->getNamespaceDef()==fnd &&
+ if (emd->getNamespaceDef()==fnd &&
rightScopeMatch(mScope,emd->localName()))
{
//printf("found it!\n");
nd=fnd;
md=mmd;
found=TRUE;
+ break;
}
else
{
@@ -4223,14 +2638,13 @@ bool getDefs(const QCString &scName,
else if (mmd->getOuterScope()==fnd /* && mmd->isLinkable() */ )
{ // namespace is found
bool match=TRUE;
- ArgumentList argList;
if (args && qstrcmp(args,"()")!=0)
{
const ArgumentList &mmdAl = mmd->argumentList();
- stringToArgumentList(mmd->getLanguage(),args,argList);
+ auto argList_p = stringToArgumentList(mmd->getLanguage(),args);
match=matchArguments2(
- mmd->getOuterScope(),mmd->getFileDef(),mmdAl,
- fnd,mmd->getFileDef(),argList,
+ mmd->getOuterScope(),mmd->getFileDef(),&mmdAl,
+ fnd,mmd->getFileDef(),argList_p.get(),
checkCV);
}
if (match)
@@ -4238,26 +2652,29 @@ bool getDefs(const QCString &scName,
nd=fnd;
md=mmd;
found=TRUE;
+ break;
}
}
}
- if (!found && args && !qstrcmp(args,"()"))
- // no exact match found, but if args="()" an arbitrary
+ if (!found && args && !qstrcmp(args,"()"))
+ // no exact match found, but if args="()" an arbitrary
// member will do
{
- for (mmli.toFirst();((mmd=mmli.current()) && !found);++mmli)
+ for (const auto &mmd_p : *mn)
{
+ const MemberDef *mmd = mmd_p.get();
if (mmd->getNamespaceDef()==fnd /*&& mmd->isLinkable() */ )
{
nd=fnd;
md=mmd;
found=TRUE;
+ break;
}
}
}
if (found)
{
- if (!md->isLinkable())
+ if (!md->isLinkable())
{
md=0; // avoid returning things we cannot link to
nd=0;
@@ -4274,10 +2691,9 @@ bool getDefs(const QCString &scName,
else
{
//printf("not a namespace\n");
- MemberNameIterator mmli(*mn);
- MemberDef *mmd;
- for (mmli.toFirst();(mmd=mmli.current());++mmli)
+ for (const auto &mmd_p : *mn)
{
+ const MemberDef *mmd = mmd_p.get();
const MemberDef *tmd = mmd->getEnumScope();
//printf("try member %s tmd=%s\n",mmd->name().data(),tmd?tmd->name().data():"<none>");
int ni=namespaceName.findRev("::");
@@ -4314,31 +2730,34 @@ bool getDefs(const QCString &scName,
{
QList<MemberDef> members;
// search for matches with strict static checking
- findMembersWithSpecificName(mn,args,TRUE,currentFile,checkCV,forceTagFile,members);
+ findMembersWithSpecificName(mn,args,TRUE,currentFile,checkCV,members);
if (members.count()==0) // nothing found
{
// search again without strict static checking
- findMembersWithSpecificName(mn,args,FALSE,currentFile,checkCV,forceTagFile,members);
+ findMembersWithSpecificName(mn,args,FALSE,currentFile,checkCV,members);
}
//printf("found %d members\n",members.count());
if (members.count()!=1 && args && !qstrcmp(args,"()"))
{
// no exact match found, but if args="()" an arbitrary
// member will do
- MemberNameIterator mni(*mn);
- for (mni.toLast();(md=mni.current());--mni)
+ //MemberNameIterator mni(*mn);
+ //for (mni.toLast();(md=mni.current());--mni)
+ for (auto it = mn->rbegin(); it!=mn->rend(); ++it)
{
- //printf("Found member '%s'\n",md->name().data());
- //printf("member is linkable md->name()='%s'\n",md->name().data());
- fd=md->getFileDef();
- gd=md->getGroupDef();
- const MemberDef *tmd = md->getEnumScope();
+ const auto &mmd_p = *it;
+ const MemberDef *mmd = mmd_p.get();
+ //printf("Found member '%s'\n",mmd->name().data());
+ //printf("member is linkable mmd->name()='%s'\n",mmd->name().data());
+ fd=mmd->getFileDef();
+ gd=mmd->getGroupDef();
+ const MemberDef *tmd = mmd->getEnumScope();
if (
(gd && gd->isLinkable()) || (fd && fd->isLinkable()) ||
(tmd && tmd->isStrong())
)
{
- members.append(md);
+ members.append(mmd);
}
}
}
@@ -4351,7 +2770,7 @@ bool getDefs(const QCString &scName,
QListIterator<MemberDef> mit(members);
for (mit.toFirst();(md=mit.current());++mit)
{
- if (md->getFileDef() && md->getFileDef()->name() == currentFile->name())
+ if (md->getFileDef() && md->getFileDef()->name() == currentFile->name())
{
break; // found match in the current file
}
@@ -4366,7 +2785,7 @@ bool getDefs(const QCString &scName,
md=members.getLast();
}
}
- if (md && (md->getEnumScope()==0 || !md->getEnumScope()->isStrong()))
+ if (md && (md->getEnumScope()==0 || !md->getEnumScope()->isStrong()))
// found a matching global member, that is not a scoped enum value (or uniquely matches)
{
fd=md->getFileDef();
@@ -4384,14 +2803,14 @@ bool getDefs(const QCString &scName,
/*!
* Searches for a scope definition given its name as a string via parameter
- * `scope`.
+ * `scope`.
*
- * The parameter `docScope` is a string representing the name of the scope in
+ * The parameter `docScope` is a string representing the name of the scope in
* which the `scope` string was found.
*
* The function returns TRUE if the scope is known and documented or
* FALSE if it is not.
- * If TRUE is returned exactly one of the parameter `cd`, `nd`
+ * If TRUE is returned exactly one of the parameter `cd`, `nd`
* will be non-zero:
* - if `cd` is non zero, the scope was a class pointed to by cd.
* - if `nd` is non zero, the scope was a namespace pointed to by nd.
@@ -4408,7 +2827,7 @@ static bool getScopeDefs(const char *docScope,const char *scope,
bool explicitGlobalScope=FALSE;
if (scopeName.at(0)==':' && scopeName.at(1)==':')
{
- scopeName=scopeName.right(scopeName.length()-2);
+ scopeName=scopeName.right(scopeName.length()-2);
explicitGlobalScope=TRUE;
}
if (scopeName.isEmpty())
@@ -4429,11 +2848,11 @@ static bool getScopeDefs(const char *docScope,const char *scope,
//(cd=getClass(fullName+"-g")) // C# generic
) && cd->isLinkable())
{
- return TRUE; // class link written => quit
+ return TRUE; // class link written => quit
}
- else if ((nd=Doxygen::namespaceSDict->find(fullName)) && nd->isLinkable())
+ else if ((nd=Doxygen::namespaceLinkedMap->find(fullName)) && nd->isLinkable())
{
- return TRUE; // namespace link written => quit
+ return TRUE; // namespace link written => quit
}
if (scopeOffset==0)
{
@@ -4454,10 +2873,10 @@ static bool isLowerCase(QCString &s)
if (p==0) return TRUE;
int c;
while ((c=*p++)) if (!islower(c)) return FALSE;
- return TRUE;
+ return TRUE;
}
-/*! Returns an object to reference to given its name and context
+/*! Returns an object to reference to given its name and context
* @post return value TRUE implies *resContext!=0 or *resMember!=0
*/
bool resolveRef(/* in */ const char *scName,
@@ -4501,10 +2920,10 @@ bool resolveRef(/* in */ const char *scName,
ClassDef *cd=0;
NamespaceDef *nd=0;
- // the following if() was commented out for releases in the range
+ // the following if() was commented out for releases in the range
// 1.5.2 to 1.6.1, but has been restored as a result of bug report 594787.
if (!inSeeBlock && scopePos==-1 && isLowerCase(tsName))
- { // link to lower case only name => do not try to autolink
+ { // link to lower case only name => do not try to autolink
return FALSE;
}
@@ -4524,7 +2943,7 @@ bool resolveRef(/* in */ const char *scName,
}
return TRUE;
}
- else if (scName==fullName || (!inSeeBlock && scopePos==-1))
+ else if (scName==fullName || (!inSeeBlock && scopePos==-1))
// nothing to link => output plain text
{
//printf("found scName=%s fullName=%s scName==fullName=%d "
@@ -4544,7 +2963,7 @@ bool resolveRef(/* in */ const char *scName,
if (bracePos!=-1) argsStr=fullName.right(fullName.length()-bracePos);
// strip template specifier
- // TODO: match against the correct partial template instantiation
+ // TODO: match against the correct partial template instantiation
int templPos=nameStr.find('<');
bool tryUnspecializedVersion = FALSE;
if (templPos!=-1 && nameStr.find("operator")==-1)
@@ -4584,11 +3003,11 @@ bool resolveRef(/* in */ const char *scName,
)
{
//printf("after getDefs checkScope=%d nameStr=%s cd=%p nd=%p\n",checkScope,nameStr.data(),cd,nd);
- if (checkScope && md && md->getOuterScope()==Doxygen::globalScope &&
+ if (checkScope && md && md->getOuterScope()==Doxygen::globalScope &&
!md->isStrongEnumValue() &&
(!scopeStr.isEmpty() || nameStr.find("::")>0))
{
- // we did find a member, but it is a global one while we were explicitly
+ // we did find a member, but it is a global one while we were explicitly
// looking for a scoped variable. See bug 616387 for an example why this check is needed.
// note we do need to support autolinking to "::symbol" hence the >0
//printf("not global member!\n");
@@ -4607,7 +3026,7 @@ bool resolveRef(/* in */ const char *scName,
// md->name().data(),md,md->anchor().data(),md->isLinkable(),(*resContext)->name().data());
return TRUE;
}
- else if (inSeeBlock && !nameStr.isEmpty() && (gd=Doxygen::groupSDict->find(nameStr)))
+ else if (inSeeBlock && !nameStr.isEmpty() && (gd=Doxygen::groupLinkedMap->find(nameStr)))
{ // group link
*resContext=gd;
return TRUE;
@@ -4615,7 +3034,7 @@ bool resolveRef(/* in */ const char *scName,
else if (tsName.find('.')!=-1) // maybe a link to a file
{
bool ambig;
- fd=findFileDef(Doxygen::inputNameDict,tsName,ambig);
+ fd=findFileDef(Doxygen::inputNameLinkedMap,tsName,ambig);
if (fd && !ambig)
{
*resContext=fd;
@@ -4667,20 +3086,20 @@ QCString linkToText(SrcLangExt lang,const char *link,bool isFileName)
#if 0
/*
* generate a reference to a class, namespace or member.
- * 'scName' is the name of the scope that contains the documentation
+ * 'scName' is the name of the scope that contains the documentation
* string that is returned.
* 'name' is the name that we want to link to.
* 'name' may have the following formats:
* 1) "ScopeName"
- * 2) "memberName()" one of the (overloaded) function or define
+ * 2) "memberName()" one of the (overloaded) function or define
* with name memberName.
- * 3) "memberName(...)" a specific (overloaded) function or define
+ * 3) "memberName(...)" a specific (overloaded) function or define
* with name memberName
* 4) "::name a global variable or define
* 4) "\#memberName member variable, global variable or define
- * 5) ("ScopeName::")+"memberName()"
- * 6) ("ScopeName::")+"memberName(...)"
- * 7) ("ScopeName::")+"memberName"
+ * 5) ("ScopeName::")+"memberName()"
+ * 6) ("ScopeName::")+"memberName(...)"
+ * 7) ("ScopeName::")+"memberName"
* instead of :: the \# symbol may also be used.
*/
@@ -4752,20 +3171,20 @@ bool resolveLink(/* in */ const char *scName,
const ClassDef *cd;
const DirDef *dir;
const NamespaceDef *nd;
- SectionInfo *si=0;
+ const SectionInfo *si=0;
bool ambig;
if (linkRef.isEmpty()) // no reference name!
{
return FALSE;
}
- else if ((pd=Doxygen::pageSDict->find(linkRef))) // link to a page
+ else if ((pd=Doxygen::pageLinkedMap->find(linkRef))) // link to a page
{
- const GroupDef *gd = pd->getGroupDef();
+ gd = pd->getGroupDef();
if (gd)
{
- if (!pd->name().isEmpty()) si=Doxygen::sectionDict->find(pd->name());
+ if (!pd->name().isEmpty()) si=SectionManager::instance().find(pd->name());
*resContext=gd;
- if (si) resAnchor = si->label;
+ if (si) resAnchor = si->label();
}
else
{
@@ -4773,23 +3192,23 @@ bool resolveLink(/* in */ const char *scName,
}
return TRUE;
}
- else if ((si=Doxygen::sectionDict->find(linkRef)))
+ else if ((si=SectionManager::instance().find(linkRef)))
{
- *resContext=si->definition;
- resAnchor = si->label;
+ *resContext=si->definition();
+ resAnchor = si->label();
return TRUE;
}
- else if ((pd=Doxygen::exampleSDict->find(linkRef))) // link to an example
+ else if ((pd=Doxygen::exampleLinkedMap->find(linkRef))) // link to an example
{
*resContext=pd;
return TRUE;
}
- else if ((gd=Doxygen::groupSDict->find(linkRef))) // link to a group
+ else if ((gd=Doxygen::groupLinkedMap->find(linkRef))) // link to a group
{
*resContext=gd;
return TRUE;
}
- else if ((fd=findFileDef(Doxygen::inputNameDict,linkRef,ambig)) // file link
+ else if ((fd=findFileDef(Doxygen::inputNameLinkedMap,linkRef,ambig)) // file link
&& fd->isLinkable())
{
*resContext=fd;
@@ -4819,12 +3238,12 @@ bool resolveLink(/* in */ const char *scName,
// resAnchor=cd->anchor();
// return TRUE;
// }
- else if ((nd=Doxygen::namespaceSDict->find(linkRef)))
+ else if ((nd=Doxygen::namespaceLinkedMap->find(linkRef)))
{
*resContext=nd;
return TRUE;
}
- else if ((dir=Doxygen::directories->find(QFileInfo(linkRef).absFilePath().utf8()+"/"))
+ else if ((dir=Doxygen::dirLinkedMap->find(QFileInfo(linkRef).absFilePath().utf8()+"/"))
&& dir->isLinkable()) // TODO: make this location independent like filedefs
{
*resContext=dir;
@@ -4842,7 +3261,7 @@ bool resolveLink(/* in */ const char *scName,
//----------------------------------------------------------------------
// General function that generates the HTML code for a reference to some
-// file, class or member from text 'lr' within the context of class 'clName'.
+// file, class or member from text 'lr' within the context of class 'clName'.
// This link has the text 'lt' (if not 0), otherwise 'lr' is used as a
// basis for the link's text.
// returns TRUE if a link could be generated.
@@ -4860,14 +3279,14 @@ bool generateLink(OutputDocInterface &od,const char *clName,
if (compound) // link to compound
{
if (lt==0 && anchor.isEmpty() && /* compound link */
- compound->definitionType()==Definition::TypeGroup /* is group */
+ compound->definitionType()==Definition::TypeGroup /* is group */
)
{
- linkText=(dynamic_cast<const GroupDef *>(compound))->groupTitle(); // use group's title as link
+ linkText=(toGroupDef(compound))->groupTitle(); // use group's title as link
}
else if (compound->definitionType()==Definition::TypeFile)
{
- linkText=linkToText(compound->getLanguage(),lt,TRUE);
+ linkText=linkToText(compound->getLanguage(),lt,TRUE);
}
od.writeObjectLink(compound->getReference(),
compound->getOutputFileBase(),anchor,linkText);
@@ -4896,12 +3315,12 @@ void generateFileRef(OutputDocInterface &od,const char *name,const char *text)
//FileInfo *fi;
FileDef *fd;
bool ambig;
- if ((fd=findFileDef(Doxygen::inputNameDict,name,ambig)) &&
- fd->isLinkable())
+ if ((fd=findFileDef(Doxygen::inputNameLinkedMap,name,ambig)) &&
+ fd->isLinkable())
// link to documented input file
od.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,linkText);
else
- od.docify(linkText);
+ od.docify(linkText);
}
//----------------------------------------------------------------------
@@ -4942,21 +3361,24 @@ struct FindFileCacheElem
bool isAmbig;
};
-static QCache<FindFileCacheElem> g_findFileDefCache(5000);
+static Cache<std::string,FindFileCacheElem> g_findFileDefCache(5000);
-FileDef *findFileDef(const FileNameDict *fnDict,const char *n,bool &ambig)
+static std::mutex g_findFileDefMutex;
+
+FileDef *findFileDef(const FileNameLinkedMap *fnMap,const char *n,bool &ambig)
{
ambig=FALSE;
if (n==0) return 0;
+ std::unique_lock<std::mutex> lock(g_findFileDefMutex);
+
const int maxAddrSize = 20;
char addr[maxAddrSize];
- qsnprintf(addr,maxAddrSize,"%p:",fnDict);
+ qsnprintf(addr,maxAddrSize,"%p:",(void*)fnMap);
QCString key = addr;
key+=n;
- g_findFileDefCache.setAutoDelete(TRUE);
- FindFileCacheElem *cachedResult = g_findFileDefCache.find(key);
+ FindFileCacheElem *cachedResult = g_findFileDefCache.find(key.str());
//printf("key=%s cachedResult=%p\n",key.data(),cachedResult);
if (cachedResult)
{
@@ -4966,63 +3388,56 @@ FileDef *findFileDef(const FileNameDict *fnDict,const char *n,bool &ambig)
}
else
{
- cachedResult = new FindFileCacheElem(0,FALSE);
+ cachedResult = g_findFileDefCache.insert(key.str(),FindFileCacheElem(0,FALSE));
}
QCString name=QDir::cleanDirPath(n).utf8();
QCString path;
int slashPos;
- FileName *fn;
+ const FileName *fn;
if (name.isEmpty()) goto exit;
slashPos=QMAX(name.findRev('/'),name.findRev('\\'));
if (slashPos!=-1)
{
path=name.left(slashPos+1);
- name=name.right(name.length()-slashPos-1);
+ name=name.right(name.length()-slashPos-1);
//printf("path=%s name=%s\n",path.data(),name.data());
}
if (name.isEmpty()) goto exit;
- if ((fn=(*fnDict)[name]))
+ if ((fn=fnMap->find(name)))
{
//printf("fn->count()=%d\n",fn->count());
- if (fn->count()==1)
+ if (fn->size()==1)
{
- FileDef *fd = fn->getFirst();
-#if defined(_WIN32) || defined(__MACOSX__) || defined(__CYGWIN__) // Windows or MacOSX
- bool isSamePath = fd->getPath().right(path.length()).lower()==path.lower();
-#else // Unix
- bool isSamePath = fd->getPath().right(path.length())==path;
-#endif
+ const std::unique_ptr<FileDef> &fd = fn->front();
+ bool isSamePath = Portable::fileSystemIsCaseSensitive() ?
+ fd->getPath().right(path.length())==path :
+ fd->getPath().right(path.length()).lower()==path.lower();
if (path.isEmpty() || isSamePath)
{
- cachedResult->fileDef = fd;
- g_findFileDefCache.insert(key,cachedResult);
- //printf("=1 ===> add to cache %p\n",fd);
- return fd;
+ cachedResult->fileDef = fd.get();
+ return fd.get();
}
}
else // file name alone is ambiguous
{
int count=0;
- FileNameIterator fni(*fn);
- FileDef *fd;
FileDef *lastMatch=0;
QCString pathStripped = stripFromIncludePath(path);
- for (fni.toFirst();(fd=fni.current());++fni)
+ for (const auto &fd_p : *fn)
{
+ FileDef *fd = fd_p.get();
QCString fdStripPath = stripFromIncludePath(fd->getPath());
- if (path.isEmpty() || fdStripPath.right(pathStripped.length())==pathStripped)
- {
- count++;
- lastMatch=fd;
+ if (path.isEmpty() || fdStripPath.right(pathStripped.length())==pathStripped)
+ {
+ count++;
+ lastMatch=fd;
}
}
- //printf(">1 ===> add to cache %p\n",fd);
ambig=(count>1);
cachedResult->isAmbig = ambig;
cachedResult->fileDef = lastMatch;
- g_findFileDefCache.insert(key,cachedResult);
return lastMatch;
}
}
@@ -5031,15 +3446,13 @@ FileDef *findFileDef(const FileNameDict *fnDict,const char *n,bool &ambig)
//printf("not found!\n");
}
exit:
- //printf("0 ===> add to cache %p: %s\n",cachedResult,n);
- g_findFileDefCache.insert(key,cachedResult);
//delete cachedResult;
return 0;
}
//----------------------------------------------------------------------
-QCString showFileDefMatches(const FileNameDict *fnDict,const char *n)
+QCString showFileDefMatches(const FileNameLinkedMap *fnMap,const char *n)
{
QCString result;
QCString name=n;
@@ -5048,14 +3461,12 @@ QCString showFileDefMatches(const FileNameDict *fnDict,const char *n)
if (slashPos!=-1)
{
path=name.left(slashPos+1);
- name=name.right(name.length()-slashPos-1);
+ name=name.right(name.length()-slashPos-1);
}
- FileName *fn;
- if ((fn=(*fnDict)[name]))
+ const FileName *fn;
+ if ((fn=fnMap->find(name)))
{
- FileNameIterator fni(*fn);
- FileDef *fd;
- for (fni.toFirst();(fd=fni.current());++fni)
+ for (const auto &fd : *fn)
{
if (path.isEmpty() || fd->getPath().right(path.length())==path)
{
@@ -5068,118 +3479,6 @@ QCString showFileDefMatches(const FileNameDict *fnDict,const char *n)
//----------------------------------------------------------------------
-/// substitute all occurrences of \a src in \a s by \a dst
-QCString substitute(const QCString &s,const QCString &src,const QCString &dst)
-{
- if (s.isEmpty() || src.isEmpty()) return s;
- const char *p, *q;
- int srcLen = src.length();
- int dstLen = dst.length();
- int resLen;
- if (srcLen!=dstLen)
- {
- int count;
- for (count=0, p=s.data(); (q=strstr(p,src))!=0; p=q+srcLen) count++;
- resLen = s.length()+count*(dstLen-srcLen);
- }
- else // result has same size as s
- {
- resLen = s.length();
- }
- QCString result(resLen+1);
- char *r;
- for (r=result.rawData(), p=s; (q=strstr(p,src))!=0; p=q+srcLen)
- {
- int l = (int)(q-p);
- memcpy(r,p,l);
- r+=l;
-
- if (dst) memcpy(r,dst,dstLen);
- r+=dstLen;
- }
- qstrcpy(r,p);
- //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
- return result;
-}
-
-
-/// substitute all occurrences of \a src in \a s by \a dst, but skip
-/// each consecutive sequence of \a src where the number consecutive
-/// \a src matches \a skip_seq; if \a skip_seq is negative, skip any
-/// number of consecutive \a src
-QCString substitute(const QCString &s,const QCString &src,const QCString &dst,int skip_seq)
-{
- if (s.isEmpty() || src.isEmpty()) return s;
- const char *p, *q;
- int srcLen = src.length();
- int dstLen = dst.length();
- int resLen;
- if (srcLen!=dstLen)
- {
- int count;
- for (count=0, p=s.data(); (q=strstr(p,src))!=0; p=q+srcLen) count++;
- resLen = s.length()+count*(dstLen-srcLen);
- }
- else // result has same size as s
- {
- resLen = s.length();
- }
- QCString result(resLen+1);
- char *r;
- for (r=result.rawData(), p=s; (q=strstr(p,src))!=0; p=q+srcLen)
- {
- // search a consecutive sequence of src
- int seq = 0, skip = 0;
- if (skip_seq)
- {
- for (const char *n=q+srcLen; qstrncmp(n,src,srcLen)==0; seq=1+skip, n+=srcLen)
- ++skip; // number of consecutive src after the current one
-
- // verify the allowed number of consecutive src to skip
- if (skip_seq > 0 && skip_seq != seq)
- seq = skip = 0;
- }
-
- // skip a consecutive sequence of src when necessary
- int l = (int)((q + seq * srcLen)-p);
- memcpy(r,p,l);
- r+=l;
-
- if (skip)
- {
- // skip only the consecutive src found after the current one
- q += skip * srcLen;
- // the next loop will skip the current src, aka (p=q+srcLen)
- continue;
- }
-
- if (dst) memcpy(r,dst,dstLen);
- r+=dstLen;
- }
- qstrcpy(r,p);
- result.resize(strlen(result.data())+1);
- //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
- return result;
-}
-
-/// substitute all occurrences of \a srcChar in \a s by \a dstChar
-QCString substitute(const QCString &s,char srcChar,char dstChar)
-{
- int l=s.length();
- QCString result(l+1);
- char *q=result.rawData();
- if (l>0)
- {
- const char *p=s.data();
- char c;
- while ((c=*p++)) *q++ = (c==srcChar) ? dstChar : c;
- }
- *q='\0';
- return result;
-}
-
-//----------------------------------------------------------------------
-
QCString substituteKeywords(const QCString &s,const char *title,
const char *projName,const char *projNum,const char *projBrief)
{
@@ -5188,7 +3487,7 @@ QCString substituteKeywords(const QCString &s,const char *title,
result = substitute(result,"$datetime",dateToString(TRUE));
result = substitute(result,"$date",dateToString(FALSE));
result = substitute(result,"$year",yearToString());
- result = substitute(result,"$doxygenversion",getVersion());
+ result = substitute(result,"$doxygenversion",getDoxygenVersion());
result = substitute(result,"$projectname",projName);
result = substitute(result,"$projectnumber",projNum);
result = substitute(result,"$projectbrief",projBrief);
@@ -5201,15 +3500,14 @@ QCString substituteKeywords(const QCString &s,const char *title,
/*! Returns the character index within \a name of the first prefix
* in Config_getList(IGNORE_PREFIX) that matches \a name at the left hand side,
* or zero if no match was found
- */
+ */
int getPrefixIndex(const QCString &name)
{
if (name.isEmpty()) return 0;
- static QStrList &sl = Config_getList(IGNORE_PREFIX);
- char *s = sl.first();
- while (s)
+ const StringVector &sl = Config_getList(IGNORE_PREFIX);
+ for (const auto &s : sl)
{
- const char *ps=s;
+ const char *ps=s.c_str();
const char *pd=name.data();
int i=0;
while (*ps!=0 && *pd!=0 && *ps==*pd) ps++,pd++,i++;
@@ -5217,48 +3515,30 @@ int getPrefixIndex(const QCString &name)
{
return i;
}
- s = sl.next();
}
return 0;
}
//----------------------------------------------------------------------------
-static void initBaseClassHierarchy(BaseClassList *bcl)
-{
- if (bcl==0) return;
- BaseClassListIterator bcli(*bcl);
- for ( ; bcli.current(); ++bcli)
- {
- ClassDef *cd=bcli.current()->classDef;
- if (cd->baseClasses()==0) // no base classes => new root
- {
- initBaseClassHierarchy(cd->baseClasses());
- }
- cd->setVisited(FALSE);
- }
-}
-//----------------------------------------------------------------------------
-
bool classHasVisibleChildren(const ClassDef *cd)
{
- BaseClassList *bcl;
+ BaseClassList bcl;
if (cd->getLanguage()==SrcLangExt_VHDL) // reverse baseClass/subClass relation
{
- if (cd->baseClasses()==0) return FALSE;
+ if (cd->baseClasses().empty()) return FALSE;
bcl=cd->baseClasses();
}
- else
+ else
{
- if (cd->subClasses()==0) return FALSE;
+ if (cd->subClasses().empty()) return FALSE;
bcl=cd->subClasses();
}
- BaseClassListIterator bcli(*bcl);
- for ( ; bcli.current() ; ++bcli)
+ for (const auto &bcd : bcl)
{
- if (bcli.current()->classDef->isVisibleInHierarchy())
+ if (bcd.classDef->isVisibleInHierarchy())
{
return TRUE;
}
@@ -5266,48 +3546,90 @@ bool classHasVisibleChildren(const ClassDef *cd)
return FALSE;
}
-
//----------------------------------------------------------------------------
-void initClassHierarchy(ClassSDict *cl)
+bool hasVisibleRoot(const BaseClassList &bcl)
{
- ClassSDict::Iterator cli(*cl);
- ClassDef *cd;
- for ( ; (cd=cli.current()); ++cli)
+ for (const auto &bcd : bcl)
{
- cd->setVisited(FALSE);
- initBaseClassHierarchy(cd->baseClasses());
+ const ClassDef *cd=bcd.classDef;
+ if (cd->isVisibleInHierarchy()) return true;
+ if (hasVisibleRoot(cd->baseClasses())) return true;
}
+ return false;
}
-//----------------------------------------------------------------------------
+//----------------------------------------------------------------------
-bool hasVisibleRoot(const BaseClassList *bcl)
+// copies the next UTF8 character from input stream into buffer ids
+// returns the size of the character in bytes (or 0 if it is invalid)
+// the character itself will be copied as a UTF-8 encoded string to ids.
+int getUtf8Char(const char *input,char ids[MAX_UTF8_CHAR_SIZE],CaseModifier modifier)
{
- if (bcl)
+ int inputLen=1;
+ const unsigned char uc = (unsigned char)*input;
+ bool validUTF8Char = false;
+ if (uc <= 0xf7)
{
- BaseClassListIterator bcli(*bcl);
- for ( ; bcli.current(); ++bcli)
+ const char* pt = input+1;
+ int l = 0;
+ if ((uc&0x80)==0x00)
+ {
+ switch (modifier)
+ {
+ case CaseModifier::None: ids[0]=*input; break;
+ case CaseModifier::ToUpper: ids[0]=(char)toupper(*input); break;
+ case CaseModifier::ToLower: ids[0]=(char)tolower(*input); break;
+ }
+ l=1; // 0xxx.xxxx => normal single byte ascii character
+ }
+ else
+ {
+ ids[ 0 ] = *input;
+ if ((uc&0xE0)==0xC0)
+ {
+ l=2; // 110x.xxxx: >=2 byte character
+ }
+ if ((uc&0xF0)==0xE0)
+ {
+ l=3; // 1110.xxxx: >=3 byte character
+ }
+ if ((uc&0xF8)==0xF0)
+ {
+ l=4; // 1111.0xxx: >=4 byte character
+ }
+ }
+ validUTF8Char = l>0;
+ for (int m=1; m<l && validUTF8Char; ++m)
{
- const ClassDef *cd=bcli.current()->classDef;
- if (cd->isVisibleInHierarchy()) return TRUE;
- hasVisibleRoot(cd->baseClasses());
+ unsigned char ct = (unsigned char)*pt;
+ if (ct==0 || (ct&0xC0)!=0x80) // invalid unicode character
+ {
+ validUTF8Char=false;
+ }
+ else
+ {
+ ids[ m ] = *pt++;
+ }
+ }
+ if (validUTF8Char) // got a valid unicode character
+ {
+ ids[ l ] = 0;
+ inputLen=l;
}
}
- return FALSE;
+ return inputLen;
}
-//----------------------------------------------------------------------
// note that this function is not reentrant due to the use of static growBuf!
QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscore)
{
- static bool caseSenseNames = Config_getBool(CASE_SENSE_NAMES);
- static bool allowUnicodeNames = Config_getBool(ALLOW_UNICODE_NAMES);
- static GrowBuf growBuf;
- growBuf.clear();
+ bool caseSenseNames = Config_getBool(CASE_SENSE_NAMES);
+ bool allowUnicodeNames = Config_getBool(ALLOW_UNICODE_NAMES);
if (name==0) return "";
- char c;
+ GrowBuf growBuf;
+ signed char c;
const char *p=name;
while ((c=*p++)!=0)
{
@@ -5340,57 +3662,29 @@ QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscor
case '@': growBuf.addStr("_0d"); break;
case ']': growBuf.addStr("_0e"); break;
case '[': growBuf.addStr("_0f"); break;
- default:
+ case '#': growBuf.addStr("_0g"); break;
+ default:
if (c<0)
{
- char ids[5];
- const unsigned char uc = (unsigned char)c;
- bool doEscape = TRUE;
- if (allowUnicodeNames && uc <= 0xf7)
+ char ids[MAX_UTF8_CHAR_SIZE];
+ bool doEscape = true;
+ if (allowUnicodeNames)
{
- const char* pt = p;
- ids[ 0 ] = c;
- int l = 0;
- if ((uc&0xE0)==0xC0)
- {
- l=2; // 11xx.xxxx: >=2 byte character
- }
- if ((uc&0xF0)==0xE0)
- {
- l=3; // 111x.xxxx: >=3 byte character
- }
- if ((uc&0xF8)==0xF0)
+ int charLen = getUtf8Char(p-1,ids);
+ if (charLen>0)
{
- l=4; // 1111.xxxx: >=4 byte character
- }
- doEscape = l==0;
- for (int m=1; m<l && !doEscape; ++m)
- {
- unsigned char ct = (unsigned char)*pt;
- if (ct==0 || (ct&0xC0)!=0x80) // invalid unicode character
- {
- doEscape=TRUE;
- }
- else
- {
- ids[ m ] = *pt++;
- }
- }
- if ( !doEscape ) // got a valid unicode character
- {
- ids[ l ] = 0;
- growBuf.addStr( ids );
- p += l - 1;
+ growBuf.addStr(ids);
+ p+=charLen-1;
+ doEscape = false;
}
}
if (doEscape) // not a valid unicode char or escaping needed
{
- static char map[] = "0123456789ABCDEF";
unsigned char id = (unsigned char)c;
ids[0]='_';
ids[1]='x';
- ids[2]=map[id>>4];
- ids[3]=map[id&0xF];
+ ids[2]=hex[id>>4];
+ ids[3]=hex[id&0xF];
ids[4]=0;
growBuf.addStr(ids);
}
@@ -5402,7 +3696,7 @@ QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscor
else
{
growBuf.addChar('_');
- growBuf.addChar(tolower(c));
+ growBuf.addChar((char)tolower(c));
}
break;
}
@@ -5454,6 +3748,7 @@ QCString unescapeCharsInString(const char *s)
case 'd': result+='@'; p+=2; break; // _0d -> '@'
case 'e': result+=']'; p+=2; break; // _0e -> ']'
case 'f': result+='['; p+=2; break; // _0f -> '['
+ case 'g': result+='#'; p+=2; break; // _0g -> '#'
default: // unknown escape, just pass underscore character as-is
result+=c;
break;
@@ -5462,7 +3757,7 @@ QCString unescapeCharsInString(const char *s)
default:
if (!caseSenseNames && c>='a' && c<='z') // lower to upper case escape, _a -> 'A'
{
- result+=toupper(*p);
+ result+=(char)toupper(*p);
p++;
}
else // unknown escape, pass underscore character as-is
@@ -5482,7 +3777,7 @@ QCString unescapeCharsInString(const char *s)
}
/*! This function determines the file name on disk of an item
- * given its name, which could be a class name with template
+ * given its name, which could be a class name with template
* arguments, so special characters need to be escaped.
*/
QCString convertNameToFile(const char *name,bool allowDots,bool allowUnderscore)
@@ -5508,7 +3803,7 @@ QCString convertNameToFile(const char *name,bool allowDots,bool allowUnderscore)
{
num = *value;
}
- result.sprintf("a%05d",num);
+ result.sprintf("a%05d",num);
}
else // long names
{
@@ -5521,47 +3816,19 @@ QCString convertNameToFile(const char *name,bool allowDots,bool allowUnderscore)
QCString sigStr(33);
MD5Buffer((const unsigned char *)result.data(),resultLen,md5_sig);
MD5SigToString(md5_sig,sigStr.rawData(),33);
- result=result.left(128-32)+sigStr;
+ result=result.left(128-32)+sigStr;
}
}
if (createSubdirs)
{
int l1Dir=0,l2Dir=0;
-#if MAP_ALGO==ALGO_COUNT
- // old algorithm, has the problem that after regeneration the
- // output can be located in a different dir.
- if (Doxygen::htmlDirMap==0)
- {
- Doxygen::htmlDirMap=new QDict<int>(100003);
- Doxygen::htmlDirMap->setAutoDelete(TRUE);
- }
- static int curDirNum=0;
- int *dirNum = Doxygen::htmlDirMap->find(result);
- if (dirNum==0) // new name
- {
- Doxygen::htmlDirMap->insert(result,new int(curDirNum));
- l1Dir = (curDirNum)&0xf; // bits 0-3
- l2Dir = (curDirNum>>4)&0xff; // bits 4-11
- curDirNum++;
- }
- else // existing name
- {
- l1Dir = (*dirNum)&0xf; // bits 0-3
- l2Dir = ((*dirNum)>>4)&0xff; // bits 4-11
- }
-#elif MAP_ALGO==ALGO_CRC16
- // second algorithm based on CRC-16 checksum
- int dirNum = qChecksum(result,result.length());
- l1Dir = dirNum&0xf;
- l2Dir = (dirNum>>4)&0xff;
-#elif MAP_ALGO==ALGO_MD5
- // third algorithm based on MD5 hash
+ // compute md5 hash to determine sub directory to use
uchar md5_sig[16];
MD5Buffer((const unsigned char *)result.data(),result.length(),md5_sig);
l1Dir = md5_sig[14]&0xf;
l2Dir = md5_sig[15];
-#endif
+
result.prepend(QCString().sprintf("d%x/d%02x/",l1Dir,l2Dir));
}
//printf("*** convertNameToFile(%s)->%s\n",name,result.data());
@@ -5598,10 +3865,20 @@ void createSubDirs(QDir &d)
int l1,l2;
for (l1=0;l1<16;l1++)
{
- d.mkdir(QCString().sprintf("d%x",l1));
+ QCString subdir;
+ subdir.sprintf("d%x",l1);
+ if (!d.exists(subdir) && !d.mkdir(subdir))
+ {
+ term("Failed to create output directory '%s'\n",subdir.data());
+ }
for (l2=0;l2<256;l2++)
{
- d.mkdir(QCString().sprintf("d%x/d%02x",l1,l2));
+ QCString subsubdir;
+ subsubdir.sprintf("d%x/d%02x",l1,l2);
+ if (!d.exists(subsubdir) && !d.mkdir(subsubdir))
+ {
+ term("Failed to create output directory '%s'\n",subsubdir.data());
+ }
}
}
}
@@ -5624,7 +3901,7 @@ void extractNamespaceName(const QCString &scopeName,
goto done;
}
p=clName.length()-2;
- while (p>=0 && (i=clName.findRev("::",p))!=-1)
+ while (p>=0 && (i=clName.findRev("::",p))!=-1)
// see if the first part is a namespace (and not a class)
{
//printf("Trying %s\n",clName.left(i).data());
@@ -5634,7 +3911,7 @@ void extractNamespaceName(const QCString &scopeName,
namespaceName=nd->name().copy();
className=clName.right(clName.length()-i-2);
goto done;
- }
+ }
p=i-2; // try a smaller piece of the scope
}
//printf("not found!\n");
@@ -5671,12 +3948,12 @@ QCString insertTemplateSpecifierInScope(const QCString &scope,const QCString &te
((cd=getClass(scope.left(si)))==0 || cd->templateArguments().empty())
)
{
- //printf("Tried '%s'\n",(scope.left(si)+templ).data());
- pi=si+2;
+ //printf("Tried '%s'\n",(scope.left(si)+templ).data());
+ pi=si+2;
}
if (si==-1) // not nested => append template specifier
{
- result+=templ;
+ result+=templ;
}
else // nested => insert template specifier before after first class name
{
@@ -5688,7 +3965,7 @@ QCString insertTemplateSpecifierInScope(const QCString &scope,const QCString &te
return result;
}
-#if 0 // original version
+
/*! Strips the scope from a name. Examples: A::B will return A
* and A<T>::B<N::C<D> > will return A<T>.
*/
@@ -5696,55 +3973,11 @@ QCString stripScope(const char *name)
{
QCString result = name;
int l=result.length();
- int p=l-1;
- bool done;
- int count;
-
- while (p>=0)
- {
- char c=result.at(p);
- switch (c)
- {
- case ':':
- //printf("stripScope(%s)=%s\n",name,result.right(l-p-1).data());
- return result.right(l-p-1);
- case '>':
- count=1;
- done=FALSE;
- //printf("pos < = %d\n",p);
- p--;
- while (p>=0 && !done)
- {
- c=result.at(p--);
- switch (c)
- {
- case '>': count++; break;
- case '<': count--; if (count<=0) done=TRUE; break;
- default:
- //printf("c=%c count=%d\n",c,count);
- break;
- }
- }
- //printf("pos > = %d\n",p+1);
- break;
- default:
- p--;
- }
- }
- //printf("stripScope(%s)=%s\n",name,name);
- return name;
-}
-#endif
-
-// new version by Davide Cesari which also works for Fortran
-QCString stripScope(const char *name)
-{
- QCString result = name;
- int l=result.length();
int p;
bool done = FALSE;
bool skipBracket=FALSE; // if brackets do not match properly, ignore them altogether
int count=0;
+ int round=0;
do
{
@@ -5754,10 +3987,13 @@ QCString stripScope(const char *name)
char c=result.at(p);
switch (c)
{
- case ':':
+ case ':':
// only exit in the case of ::
//printf("stripScope(%s)=%s\n",name,result.right(l-p-1).data());
- if (p>0 && result.at(p-1)==':') return result.right(l-p-1);
+ if (p>0 && result.at(p-1)==':' && (count==0 || skipBracket))
+ {
+ return result.right(l-p-1);
+ }
p--;
break;
case '>':
@@ -5781,22 +4017,31 @@ QCString stripScope(const char *name)
c=result.at(p--);
switch (c)
{
- case '>':
- count++;
+ case ')':
+ round++;
+ break;
+ case '(':
+ round--;
break;
- case '<':
- if (p>0)
+ case '>': // ignore > inside (...) to support e.g. (sizeof(T)>0) inside template parameters
+ if (round==0) count++;
+ break;
+ case '<':
+ if (round==0)
{
- if (result.at(p-1) == '<') // skip << operator
+ if (p>0)
{
- p--;
- break;
+ if (result.at(p-1) == '<') // skip << operator
+ {
+ p--;
+ break;
+ }
}
+ count--;
+ foundMatch = count==0;
}
- count--;
- foundMatch = count==0;
break;
- default:
+ default:
//printf("c=%c count=%d\n",c,count);
break;
}
@@ -5819,10 +4064,8 @@ QCString stripScope(const char *name)
/*! Converts a string to a HTML id string */
QCString convertToId(const char *s)
{
- static const char hex[] = "0123456789ABCDEF";
- static GrowBuf growBuf;
- growBuf.clear();
if (s==0) return "";
+ GrowBuf growBuf;
const char *p=s;
char c;
bool first=TRUE;
@@ -5848,12 +4091,21 @@ QCString convertToId(const char *s)
return growBuf.get();
}
+/*! Some strings have been corrected but the requirement regarding the fact
+ * that an id cannot have a digit at the first position. To overcome problems
+ * with double labels we always place an "a" in front
+ */
+QCString correctId(QCString s)
+{
+ if (s.isEmpty()) return s;
+ return "a" + s;
+}
+
/*! Converts a string to an XML-encoded string */
QCString convertToXML(const char *s, bool keepEntities)
{
- static GrowBuf growBuf;
- growBuf.clear();
if (s==0) return "";
+ GrowBuf growBuf;
const char *p=s;
char c;
while ((c=*p++))
@@ -5886,7 +4138,7 @@ QCString convertToXML(const char *s, bool keepEntities)
growBuf.addStr("&amp;");
}
break;
- case '\'': growBuf.addStr("&apos;"); break;
+ case '\'': growBuf.addStr("&apos;"); break;
case '"': growBuf.addStr("&quot;"); break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18:
@@ -5903,9 +4155,8 @@ QCString convertToXML(const char *s, bool keepEntities)
/*! Converts a string to an DocBook-encoded string */
QCString convertToDocBook(const char *s)
{
- static GrowBuf growBuf;
- growBuf.clear();
if (s==0) return "";
+ GrowBuf growBuf;
const unsigned char *q;
int cnt;
const unsigned char *p=(const unsigned char *)s;
@@ -5947,13 +4198,18 @@ QCString convertToDocBook(const char *s)
break;
case '\'': growBuf.addStr("&apos;"); break;
case '"': growBuf.addStr("&quot;"); break;
- case '\007': growBuf.addStr("&#x2407;"); break;
- case 1: case 2: case 3: case 4: case 5: case 6: case 8:
- case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18:
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+ case 11: case 12: case 14: case 15: case 16: case 17: case 18:
case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26:
case 27: case 28: case 29: case 30: case 31:
- break; // skip invalid XML characters (see http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char)
- default: growBuf.addChar(c); break;
+ growBuf.addStr("&#x24");
+ growBuf.addChar(hex[static_cast<uchar>(c)>>4]);
+ growBuf.addChar(hex[static_cast<uchar>(c)&0xF]);
+ growBuf.addChar(';');
+ break;
+ default:
+ growBuf.addChar(c);
+ break;
}
}
growBuf.addChar(0);
@@ -5963,9 +4219,8 @@ QCString convertToDocBook(const char *s)
/*! Converts a string to a HTML-encoded string */
QCString convertToHtml(const char *s,bool keepEntities)
{
- static GrowBuf growBuf;
- growBuf.clear();
if (s==0) return "";
+ GrowBuf growBuf;
growBuf.addStr(getHtmlDirEmbeddingChar(getTextDirByConfig(s)));
const char *p=s;
char c;
@@ -5996,12 +4251,27 @@ QCString convertToHtml(const char *s,bool keepEntities)
}
else
{
- growBuf.addStr("&amp;");
+ growBuf.addStr("&amp;");
}
break;
- case '\'': growBuf.addStr("&#39;"); break;
+ case '\'': growBuf.addStr("&#39;"); break;
case '"': growBuf.addStr("&quot;"); break;
- default: growBuf.addChar(c); break;
+ default:
+ {
+ uchar uc = static_cast<uchar>(c);
+ if (uc<32 && !isspace(c))
+ {
+ growBuf.addStr("&#x24");
+ growBuf.addChar(hex[uc>>4]);
+ growBuf.addChar(hex[uc&0xF]);
+ growBuf.addChar(';');
+ }
+ else
+ {
+ growBuf.addChar(c);
+ }
+ }
+ break;
}
}
growBuf.addChar(0);
@@ -6010,9 +4280,8 @@ QCString convertToHtml(const char *s,bool keepEntities)
QCString convertToJSString(const char *s, bool applyTextDir)
{
- static GrowBuf growBuf;
- growBuf.clear();
if (s==0) return "";
+ GrowBuf growBuf;
if (applyTextDir)
growBuf.addStr(getJsDirEmbeddingChar(getTextDirByConfig(s)));
const char *p=s;
@@ -6032,9 +4301,8 @@ QCString convertToJSString(const char *s, bool applyTextDir)
QCString convertToPSString(const char *s)
{
- static GrowBuf growBuf;
- growBuf.clear();
if (s==0) return "";
+ GrowBuf growBuf;
const char *p=s;
char c;
while ((c=*p++))
@@ -6054,7 +4322,7 @@ QCString convertToLaTeX(const QCString &s,bool insideTabbing,bool keepSpaces)
{
QGString result;
FTextStream t(&result);
- filterLatexString(t,s,insideTabbing,FALSE,FALSE,keepSpaces);
+ filterLatexString(t,s,insideTabbing,false,false,false,keepSpaces);
return result.data();
}
@@ -6066,8 +4334,7 @@ QCString convertCharEntitiesToUTF8(const QCString &s)
static QRegExp entityPat("&[a-zA-Z]+[0-9]*;");
if (s.length()==0) return result;
- static GrowBuf growBuf;
- growBuf.clear();
+ GrowBuf growBuf;
int p,i=0,l;
while ((p=entityPat.match(s,i,&l))!=-1)
{
@@ -6106,11 +4373,11 @@ QCString getOverloadDocs()
}
void addMembersToMemberGroup(MemberList *ml,
- MemberGroupSDict **ppMemberGroupSDict,
+ MemberGroupList *pMemberGroups,
const Definition *context)
{
ASSERT(context!=0);
- //printf("addMemberToMemberGroup()\n");
+ //printf("addMemberToMemberGroup() context=%s\n",context->name().data());
if (ml==0) return;
MemberListIterator mli(*ml);
MemberDef *md;
@@ -6129,30 +4396,34 @@ void addMembersToMemberGroup(MemberList *ml,
int groupId=fmd->getMemberGroupId();
if (groupId!=-1)
{
- MemberGroupInfo *info = Doxygen::memGrpInfoDict[groupId];
- //QCString *pGrpHeader = Doxygen::memberHeaderDict[groupId];
- //QCString *pDocs = Doxygen::memberDocDict[groupId];
- if (info)
+ auto it = Doxygen::memberGroupInfoMap.find(groupId);
+ if (it!=Doxygen::memberGroupInfoMap.end())
{
- if (*ppMemberGroupSDict==0)
+ auto &info = it->second;
+ auto mg_it = std::find_if(pMemberGroups->begin(),
+ pMemberGroups->end(),
+ [&groupId](const auto &g)
+ { return g->groupId()==groupId; }
+ );
+ MemberGroup *mg_ptr = 0;
+ if (mg_it==pMemberGroups->end())
{
- *ppMemberGroupSDict = new MemberGroupSDict;
- (*ppMemberGroupSDict)->setAutoDelete(TRUE);
+ auto mg = std::make_unique<MemberGroup>(
+ context,
+ groupId,
+ info->header,
+ info->doc,
+ info->docFile,
+ info->docLine);
+ mg_ptr = mg.get();
+ pMemberGroups->push_back(std::move(mg));
}
- MemberGroup *mg = (*ppMemberGroupSDict)->find(groupId);
- if (mg==0)
+ else
{
- mg = new MemberGroup(
- groupId,
- info->header,
- info->doc,
- info->docFile,
- info->docLine
- );
- (*ppMemberGroupSDict)->append(groupId,mg);
+ mg_ptr = (*mg_it).get();
}
- mg->insertMember(fmd); // insert in member group
- fmd->setMemberGroup(mg);
+ mg_ptr->insertMember(fmd); // insert in member group
+ fmd->setMemberGroup(mg_ptr);
}
}
}
@@ -6161,32 +4432,36 @@ void addMembersToMemberGroup(MemberList *ml,
int groupId=md->getMemberGroupId();
if (groupId!=-1)
{
- MemberGroupInfo *info = Doxygen::memGrpInfoDict[groupId];
- //QCString *pGrpHeader = Doxygen::memberHeaderDict[groupId];
- //QCString *pDocs = Doxygen::memberDocDict[groupId];
- if (info)
- {
- if (*ppMemberGroupSDict==0)
+ auto it = Doxygen::memberGroupInfoMap.find(groupId);
+ if (it!=Doxygen::memberGroupInfoMap.end())
+ {
+ auto &info = it->second;
+ auto mg_it = std::find_if(pMemberGroups->begin(),
+ pMemberGroups->end(),
+ [&groupId](const auto &g)
+ { return g->groupId()==groupId; }
+ );
+ MemberGroup *mg_ptr = 0;
+ if (mg_it==pMemberGroups->end())
{
- *ppMemberGroupSDict = new MemberGroupSDict;
- (*ppMemberGroupSDict)->setAutoDelete(TRUE);
+ auto mg = std::make_unique<MemberGroup>(
+ context,
+ groupId,
+ info->header,
+ info->doc,
+ info->docFile,
+ info->docLine);
+ mg_ptr = mg.get();
+ pMemberGroups->push_back(std::move(mg));
}
- MemberGroup *mg = (*ppMemberGroupSDict)->find(groupId);
- if (mg==0)
+ else
{
- mg = new MemberGroup(
- groupId,
- info->header,
- info->doc,
- info->docFile,
- info->docLine
- );
- (*ppMemberGroupSDict)->append(groupId,mg);
+ mg_ptr = (*mg_it).get();
}
md = ml->take(index); // remove from member list
- mg->insertMember(md); // insert in member group
- mg->setRefItems(info->m_sli);
- md->setMemberGroup(mg);
+ mg_ptr->insertMember(md->resolveAlias()); // insert in member group
+ mg_ptr->setRefItems(info->m_sli);
+ md->setMemberGroup(mg_ptr);
continue;
}
}
@@ -6241,11 +4516,11 @@ int extractClassNameFromType(const QCString &type,int &pos,QCString &name,QCStri
int brCount=1;
while (te<typeLen && brCount!=0)
{
- if (type.at(te)=='<')
+ if (type.at(te)=='<')
{
if (te<typeLen-1 && type.at(te+1)=='<') te++; else brCount++;
}
- if (type.at(te)=='>')
+ if (type.at(te)=='>')
{
if (te<typeLen-1 && type.at(te+1)=='>') te++; else brCount--;
}
@@ -6253,7 +4528,7 @@ int extractClassNameFromType(const QCString &type,int &pos,QCString &name,QCStri
}
}
name = type.mid(i,l);
- if (te>ts)
+ if (te>ts)
{
templSpec = type.mid(ts,te-ts),tl+=te-ts;
pos=i+l+tl;
@@ -6292,7 +4567,7 @@ QCString normalizeNonTemplateArgumentsInString(
result += name.mid(p,i-p);
QCString n = name.mid(i,l);
bool found=FALSE;
- for (const Argument formArg : formalArgs)
+ for (const Argument &formArg : formalArgs)
{
if (formArg.name == n)
{
@@ -6303,7 +4578,8 @@ QCString normalizeNonTemplateArgumentsInString(
if (!found)
{
// try to resolve the type
- const ClassDef *cd = getResolvedClass(context,0,n);
+ SymbolResolver resolver;
+ const ClassDef *cd = resolver.resolveClass(context,n);
if (cd)
{
result+=cd->name();
@@ -6334,21 +4610,24 @@ QCString normalizeNonTemplateArgumentsInString(
QCString substituteTemplateArgumentsInString(
const QCString &name,
const ArgumentList &formalArgs,
- const ArgumentList &actualArgs)
+ const std::unique_ptr<ArgumentList> &actualArgs)
{
//printf("substituteTemplateArgumentsInString(name=%s formal=%s actualArg=%s)\n",
// name.data(),argListToString(formalArgs).data(),argListToString(actualArgs).data());
if (formalArgs.empty()) return name;
QCString result;
- static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
+ static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9:\\x80-\\xFF]*");
int p=0,l,i;
// for each identifier in the base class name (e.g. B<T> -> B and T)
while ((i=re.match(name,p,&l))!=-1)
{
result += name.mid(p,i-p);
QCString n = name.mid(i,l);
- auto formIt = formalArgs.begin();
- auto actIt = actualArgs.begin();
+ ArgumentList::iterator actIt;
+ if (actualArgs)
+ {
+ actIt = actualArgs->begin();
+ }
// if n is a template argument, then we substitute it
// for its template instance argument.
@@ -6360,7 +4639,7 @@ QCString substituteTemplateArgumentsInString(
{
Argument formArg = *formIt;
Argument actArg;
- if (actIt!=actualArgs.end())
+ if (actualArgs && actIt!=actualArgs->end())
{
actArg = *actIt;
}
@@ -6378,35 +4657,35 @@ QCString substituteTemplateArgumentsInString(
{
//printf("n=%s formArg->type='%s' formArg->name='%s' formArg->defval='%s'\n",
// n.data(),formArg->type.data(),formArg->name.data(),formArg->defval.data());
- //printf(">> formArg->name='%s' actArg->type='%s' actArg->name='%s'\n",
- // formArg->name.data(),actArg ? actArg->type.data() : "",actArg ? actArg->name.data() : ""
+ //printf(">> n='%s' formArg->name='%s' actArg->type='%s' actArg->name='%s'\n",
+ // n.data(),formArg.name.data(),actIt!=actualArgs.end() ? actIt->type.data() : "",actIt!=actualArgs.end() ? actIt->name.data() : ""
// );
- if (formArg.name==n && actIt!=actualArgs.end() && !actArg.type.isEmpty()) // base class is a template argument
+ if (formArg.name==n && actualArgs && actIt!=actualArgs->end() && !actArg.type.isEmpty()) // base class is a template argument
{
// replace formal argument with the actual argument of the instance
- if (!leftScopeMatch(actArg.type,n))
- // the scope guard is to prevent recursive lockup for
- // template<class A> class C : public<A::T>,
- // where A::T would become A::T::T here,
+ if (!leftScopeMatch(actArg.type,n))
+ // the scope guard is to prevent recursive lockup for
+ // template<class A> class C : public<A::T>,
+ // where A::T would become A::T::T here,
// since n==A and actArg->type==A::T
// see bug595833 for an example
{
if (actArg.name.isEmpty())
{
- result += actArg.type+" ";
+ result += actArg.type+" ";
found=TRUE;
}
- else
+ else
// for case where the actual arg is something like "unsigned int"
// the "int" part is in actArg->name.
{
- result += actArg.type+" "+actArg.name+" ";
+ result += actArg.type+" "+actArg.name+" ";
found=TRUE;
}
}
}
else if (formArg.name==n &&
- actIt==actualArgs.end() &&
+ (actualArgs==nullptr || actIt==actualArgs->end()) &&
!formArg.defval.isEmpty() &&
formArg.defval!=name /* to prevent recursion */
)
@@ -6416,7 +4695,7 @@ QCString substituteTemplateArgumentsInString(
}
}
else if (formArg.name==n &&
- actIt==actualArgs.end() &&
+ (actualArgs==nullptr || actIt==actualArgs->end()) &&
!formArg.defval.isEmpty() &&
formArg.defval!=name /* to prevent recursion */
)
@@ -6424,7 +4703,7 @@ QCString substituteTemplateArgumentsInString(
result += substituteTemplateArgumentsInString(formArg.defval,formalArgs,actualArgs)+" ";
found=TRUE;
}
- if (actIt!=actualArgs.end())
+ if (actualArgs && actIt!=actualArgs->end())
{
actIt++;
}
@@ -6441,62 +4720,45 @@ QCString substituteTemplateArgumentsInString(
return result.stripWhiteSpace();
}
-#if 0
-/*! Makes a deep copy of the list of argument lists \a srcLists.
- * Will allocate memory, that is owned by the caller.
- */
-QList<ArgumentList> *copyArgumentLists(const QList<ArgumentList> *srcLists)
-{
- ASSERT(srcLists!=0);
- QList<ArgumentList> *dstLists = new QList<ArgumentList>;
- dstLists->setAutoDelete(TRUE);
- QListIterator<ArgumentList> sli(*srcLists);
- ArgumentList *sl;
- for (;(sl=sli.current());++sli)
- {
- dstLists->append(sl->deepCopy());
- }
- return dstLists;
-}
-#endif
-/*! Strips template specifiers from scope \a fullName, except those
- * that make up specialized classes. The switch \a parentOnly
- * determines whether or not a template "at the end" of a scope
- * should be considered, e.g. with \a parentOnly is \c TRUE, A<T>::B<S> will
- * try to strip \<T\> and not \<S\>, while \a parentOnly is \c FALSE will
- * strip both unless A<T> or B<S> are specialized template classes.
+/*! Strips template specifiers from scope \a fullName, except those
+ * that make up specialized classes. The switch \a parentOnly
+ * determines whether or not a template "at the end" of a scope
+ * should be considered, e.g. with \a parentOnly is \c TRUE, \c A<T>::B<S> will
+ * try to strip `<T>` and not `<S>`, while \a parentOnly is \c FALSE will
+ * strip both unless `A<T>` or `B<S>` are specialized template classes.
*/
QCString stripTemplateSpecifiersFromScope(const QCString &fullName,
bool parentOnly,
QCString *pLastScopeStripped)
{
+ int i=fullName.find('<');
+ if (i==-1) return fullName;
QCString result;
int p=0;
int l=fullName.length();
- int i=fullName.find('<');
while (i!=-1)
{
//printf("1:result+=%s\n",fullName.mid(p,i-p).data());
int e=i+1;
- bool done=FALSE;
int count=1;
- while (e<l && !done)
+ int round=0;
+ while (e<l && count>0)
{
char c=fullName.at(e++);
- if (c=='<')
- {
- count++;
- }
- else if (c=='>')
+ switch (c)
{
- count--;
- done = count==0;
+ case '(': round++; break;
+ case ')': if (round>0) round--; break;
+ case '<': if (round==0) count++; break;
+ case '>': if (round==0) count--; break;
+ default:
+ break;
}
}
int si= fullName.find("::",e);
- if (parentOnly && si==-1) break;
+ if (parentOnly && si==-1) break;
// we only do the parent scope, so we stop here if needed
result+=fullName.mid(p,i-p);
@@ -6523,10 +4785,10 @@ QCString stripTemplateSpecifiersFromScope(const QCString &fullName,
* Example1: \c A::B and \c B::C will result in \c A::B::C <br>
* Example2: \c A and \c B will be \c A::B <br>
* Example3: \c A::B and B will be \c A::B
- *
+ *
* @param leftScope the left hand part of the scope.
* @param rightScope the right hand part of the scope.
- * @returns the merged scope.
+ * @returns the merged scope.
*/
QCString mergeScopes(const QCString &leftScope,const QCString &rightScope)
{
@@ -6588,7 +4850,7 @@ int getScopeFragment(const QCString &s,int p,int *l)
while (sp<sl && !done)
{
// TODO: deal with << and >> operators!
- char c=s.at(sp++);
+ c=s.at(sp++);
switch(c)
{
case '<': count++; break;
@@ -6612,8 +4874,10 @@ found:
PageDef *addRelatedPage(const char *name,const QCString &ptitle,
const QCString &doc,
- const char *fileName,int startLine,
- const std::vector<ListItemInfo> &sli,
+ const char *fileName,
+ int docLine,
+ int startLine,
+ const RefItemVector &sli,
GroupDef *gd,
const TagInfo *tagInfo,
bool xref,
@@ -6622,12 +4886,16 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
{
PageDef *pd=0;
//printf("addRelatedPage(name=%s gd=%p)\n",name,gd);
- if ((pd=Doxygen::pageSDict->find(name)) && !tagInfo)
+ QCString title=ptitle.stripWhiteSpace();
+ if ((pd=Doxygen::pageLinkedMap->find(name)) && !tagInfo)
{
- if (!xref) warn(fileName,startLine,"multiple use of page label '%s', (other occurrence: %s, line: %d)",
- name,pd->docFile().data(),pd->docLine());
+ if (!xref && !title.isEmpty() && pd->title()!=title)
+ {
+ warn(fileName,startLine,"multiple use of page label '%s', (other occurrence: %s, line: %d)",
+ name,pd->docFile().data(),pd->getStartBodyLine());
+ }
// append documentation block to the page.
- pd->setDocumentation(doc,fileName,startLine);
+ pd->setDocumentation(doc,fileName,docLine);
//printf("Adding page docs '%s' pi=%p name=%s\n",doc.data(),pd,name);
// append (x)refitems to the page.
pd->setRefItems(sli);
@@ -6635,13 +4903,16 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
else // new page
{
QCString baseName=name;
- if (baseName.right(4)==".tex")
+ if (baseName.right(4)==".tex")
baseName=baseName.left(baseName.length()-4);
else if (baseName.right(Doxygen::htmlFileExtension.length())==Doxygen::htmlFileExtension)
baseName=baseName.left(baseName.length()-Doxygen::htmlFileExtension.length());
- QCString title=ptitle.stripWhiteSpace();
- pd=createPageDef(fileName,startLine,baseName,doc,title);
+ //printf("Appending page '%s'\n",baseName.data());
+ pd = Doxygen::pageLinkedMap->add(baseName,
+ std::unique_ptr<PageDef>(
+ createPageDef(fileName,docLine,baseName,doc,title)));
+ pd->setBodySegment(startLine,startLine,-1);
pd->setRefItems(sli);
pd->setLanguage(lang);
@@ -6652,8 +4923,6 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
pd->setFileName(tagInfo->fileName);
}
- //printf("Appending page '%s'\n",baseName.data());
- Doxygen::pageSDict->append(baseName,pd);
if (gd) gd->addPage(pd);
@@ -6663,36 +4932,40 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
// a page name is a label as well!
QCString file;
+ QCString orgFile;
+ int line = -1;
if (gd)
{
file=gd->getOutputFileBase();
+ orgFile=gd->getOutputFileBase();
}
- else
+ else
{
file=pd->getOutputFileBase();
+ orgFile=pd->docFile();
+ line = pd->getStartBodyLine();
}
- SectionInfo *si = Doxygen::sectionDict->find(pd->name());
+ const SectionInfo *si = SectionManager::instance().find(pd->name());
if (si)
{
- if (si->lineNr != -1)
+ if (si->lineNr() != -1)
{
- warn(file,-1,"multiple use of section label '%s', (first occurrence: %s, line %d)",pd->name().data(),si->fileName.data(),si->lineNr);
+ warn(orgFile,line,"multiple use of section label '%s', (first occurrence: %s, line %d)",pd->name().data(),si->fileName().data(),si->lineNr());
}
else
{
- warn(file,-1,"multiple use of section label '%s', (first occurrence: %s)",pd->name().data(),si->fileName.data());
+ warn(orgFile,line,"multiple use of section label '%s', (first occurrence: %s)",pd->name().data(),si->fileName().data());
}
}
else
{
- si=new SectionInfo(
- file,-1,pd->name(),pd->title(),SectionInfo::Page,0,pd->getReference());
+ SectionManager::instance().add(pd->name(),
+ file,-1,pd->title(),SectionType::Page,0,pd->getReference());
//printf("si->label='%s' si->definition=%s si->fileName='%s'\n",
// si->label.data(),si->definition?si->definition->name().data():"<none>",
// si->fileName.data());
//printf(" SectionInfo: sec=%p sec->fileName=%s\n",si,si->fileName.data());
//printf("Adding section key=%s si->fileName=%s\n",pageName.data(),si->fileName.data());
- Doxygen::sectionDict->append(pd->name(),si);
}
}
}
@@ -6701,47 +4974,28 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
//----------------------------------------------------------------------------
-void addRefItem(const std::vector<ListItemInfo> &sli,
- const char *key,
- const char *prefix, const char *name,const char *title,const char *args,Definition *scope)
+void addRefItem(const RefItemVector &sli,
+ const char *key,
+ const char *prefix, const char *name,const char *title,const char *args,const Definition *scope)
{
- //printf("addRefItem(sli=%p,key=%s,prefix=%s,name=%s,title=%s,args=%s)\n",sli,key,prefix,name,title,args);
+ //printf("addRefItem(sli=%d,key=%s,prefix=%s,name=%s,title=%s,args=%s)\n",(int)sli.size(),key,prefix,name,title,args);
if (key && key[0]!='@') // check for @ to skip anonymous stuff (see bug427012)
{
- for (const ListItemInfo &lii : sli)
- {
- RefList *refList = Doxygen::xrefLists->find(lii.type);
- if (refList
- &&
- (
- // either not a built-in list or the list is enabled
- (lii.type!="todo" || Config_getBool(GENERATE_TODOLIST)) &&
- (lii.type!="test" || Config_getBool(GENERATE_TESTLIST)) &&
- (lii.type!="bug" || Config_getBool(GENERATE_BUGLIST)) &&
- (lii.type!="deprecated" || Config_getBool(GENERATE_DEPRECATEDLIST))
- )
- )
- {
- RefItem *item = refList->getRefItem(lii.itemId);
- ASSERT(item!=0);
-
- item->prefix = prefix;
- item->scope = scope;
- item->name = name;
- item->title = title;
- item->args = args;
-
- refList->insertIntoList(key,item);
-
- }
+ for (RefItem *item : sli)
+ {
+ item->setPrefix(prefix);
+ item->setScope(scope);
+ item->setName(name);
+ item->setTitle(title);
+ item->setArgs(args);
+ item->setGroup(key);
}
}
}
bool recursivelyAddGroupListToTitle(OutputList &ol,const Definition *d,bool root)
{
- GroupList *groups = d->partOfGroups();
- if (groups) // write list of group to which this definition belongs
+ if (!d->partOfGroups().empty()) // write list of group to which this definition belongs
{
if (root)
{
@@ -6749,16 +5003,14 @@ bool recursivelyAddGroupListToTitle(OutputList &ol,const Definition *d,bool root
ol.disableAllBut(OutputGenerator::Html);
ol.writeString("<div class=\"ingroups\">");
}
- GroupListIterator gli(*groups);
- GroupDef *gd;
bool first=true;
- for (gli.toFirst();(gd=gli.current());++gli)
+ for (const auto &gd : d->partOfGroups())
{
+ if (!first) { ol.writeString(" &#124; "); } else first=false;
if (recursivelyAddGroupListToTitle(ol, gd, FALSE))
{
ol.writeString(" &raquo; ");
}
- if (!first) { ol.writeString(" &#124; "); } else first=FALSE;
ol.writeObjectLink(gd->getReference(),gd->getOutputFileBase(),0,gd->groupTitle());
}
if (root)
@@ -6777,7 +5029,7 @@ void addGroupListToTitle(OutputList &ol,const Definition *d)
}
void filterLatexString(FTextStream &t,const char *str,
- bool insideTabbing,bool insidePre,bool insideItem,bool keepSpaces)
+ bool insideTabbing,bool insidePre,bool insideItem,bool insideTable,bool keepSpaces)
{
if (str==0) return;
//if (strlen(str)<2) stackTrace();
@@ -6812,13 +5064,15 @@ void filterLatexString(FTextStream &t,const char *str,
case '%': t << "\\%"; break;
case '#': t << "\\#"; break;
case '$': t << "\\$"; break;
+ case '"': t << "\"{}"; break;
case '-': t << "-\\/"; break;
- case '^': (usedTableLevels()>0) ? t << "\\string^" : t << (char)c; break;
+ case '^': insideTable ? t << "\\string^" : t << (char)c; break;
case '~': t << "\\string~"; break;
case ' ': if (keepSpaces) t << "~"; else t << ' ';
break;
default:
- t << (char)c;
+ if (c<32) t << ' '; // non printable control character
+ else t << (char)c;
break;
}
}
@@ -6870,9 +5124,9 @@ void filterLatexString(FTextStream &t,const char *str,
}
break;
case '*': t << "$\\ast$"; break;
- case '_': if (!insideTabbing) t << "\\+";
- t << "\\_";
- if (!insideTabbing) t << "\\+";
+ case '_': if (!insideTabbing) t << "\\+";
+ t << "\\_";
+ if (!insideTabbing) t << "\\+";
break;
case '{': t << "\\{"; break;
case '}': t << "\\}"; break;
@@ -6880,8 +5134,8 @@ void filterLatexString(FTextStream &t,const char *str,
case '>': t << "$>$"; break;
case '|': t << "$\\vert$"; break;
case '~': t << "$\\sim$"; break;
- case '[': if (Config_getBool(PDF_HYPERLINKS) || insideItem)
- t << "\\mbox{[}";
+ case '[': if (Config_getBool(PDF_HYPERLINKS) || insideItem)
+ t << "\\mbox{[}";
else
t << "[";
break;
@@ -6889,12 +5143,12 @@ void filterLatexString(FTextStream &t,const char *str,
if (Config_getBool(PDF_HYPERLINKS) || insideItem)
t << "\\mbox{]}";
else
- t << "]";
+ t << "]";
break;
case '-': t << "-\\/";
break;
case '\\': t << "\\textbackslash{}";
- break;
+ break;
case '"': t << "\\char`\\\"{}";
break;
case '`': t << "\\`{}";
@@ -6904,15 +5158,22 @@ void filterLatexString(FTextStream &t,const char *str,
case ' ': if (keepSpaces) { if (insideTabbing) t << "\\>"; else t << '~'; } else t << ' ';
break;
- default:
+ default:
//if (!insideTabbing && forceBreaks && c!=' ' && *p!=' ')
- if (!insideTabbing &&
- ((c>='A' && c<='Z' && pc!=' ' && pc!='\0' && *p) || (c==':' && pc!=':') || (pc=='.' && isId(c)))
+ if (!insideTabbing &&
+ ((c>='A' && c<='Z' && pc!=' ' && !(pc>='A' && pc <= 'Z') && pc!='\0' && *p) || (c==':' && pc!=':') || (pc=='.' && isId(c)))
)
{
t << "\\+";
}
- t << (char)c;
+ if (c<32)
+ {
+ t << ' '; // non-printable control character
+ }
+ else
+ {
+ t << (char)c;
+ }
}
}
pc = c;
@@ -6940,7 +5201,7 @@ QCString latexEscapeLabelName(const char *s)
case '}': t << "\\rcurly{}"; break;
case '~': t << "````~"; break; // to get it a bit better in index together with other special characters
// NOTE: adding a case here, means adding it to while below as well!
- default:
+ default:
i=0;
// collect as long string as possible, before handing it to docify
tmp[i++]=c;
@@ -6950,7 +5211,13 @@ QCString latexEscapeLabelName(const char *s)
p++;
}
tmp[i]=0;
- filterLatexString(t,tmp,TRUE);
+ filterLatexString(t,tmp,
+ true, // insideTabbing
+ false, // insidePre
+ false, // insideItem
+ false, // insideTable
+ false // keepSpaces
+ );
break;
}
}
@@ -6979,7 +5246,7 @@ QCString latexEscapeIndexChars(const char *s)
case '{': t << "\\lcurly{}"; break;
case '}': t << "\\rcurly{}"; break;
// NOTE: adding a case here, means adding it to while below as well!
- default:
+ default:
i=0;
// collect as long string as possible, before handing it to docify
tmp[i++]=c;
@@ -6989,7 +5256,13 @@ QCString latexEscapeIndexChars(const char *s)
p++;
}
tmp[i]=0;
- filterLatexString(t,tmp.data(),TRUE);
+ filterLatexString(t,tmp.data(),
+ true, // insideTabbing
+ false, // insidePre
+ false, // insideItem
+ false, // insideTable
+ false // keepSpaces
+ );
break;
}
}
@@ -7026,7 +5299,7 @@ QCString latexFilterURL(const char *s)
if (s==0) return "";
QGString result;
FTextStream t(&result);
- const char *p=s;
+ const signed char *p=(const signed char*)s;
char c;
while ((c=*p++))
{
@@ -7036,7 +5309,15 @@ QCString latexFilterURL(const char *s)
case '%': t << "\\%"; break;
case '\\': t << "\\\\"; break;
default:
- t << c;
+ if (c<0)
+ {
+ unsigned char id = (unsigned char)c;
+ t << "\\%" << hex[id>>4] << hex[id&0xF];
+ }
+ else
+ {
+ t << c;
+ }
break;
}
}
@@ -7081,6 +5362,7 @@ QCString rtfFormatBmkStr(const char *name)
}
}
+ //printf("Name = %s RTF_tag = %s\n",name,(*tag).data());
return *tag;
}
@@ -7091,7 +5373,9 @@ bool checkExtension(const char *fName, const char *ext)
QCString addHtmlExtensionIfMissing(const char *fName)
{
- if (QFileInfo(fName).extension(FALSE).isEmpty())
+ if (fName==0) return fName;
+ const char *p = strchr(fName,'.');
+ if (p==nullptr) // no extension
{
return QCString(fName)+Doxygen::htmlFileExtension;
}
@@ -7118,11 +5402,14 @@ void replaceNamespaceAliases(QCString &scope,int i)
while (i>0)
{
QCString ns = scope.left(i);
- QCString *s = Doxygen::namespaceAliasDict[ns];
- if (s)
+ if (!ns.isEmpty())
{
- scope=*s+scope.right(scope.length()-i);
- i=s->length();
+ auto it = Doxygen::namespaceAliasMap.find(ns.data());
+ if (it!=Doxygen::namespaceAliasMap.end())
+ {
+ scope=it->second.data()+scope.right(scope.length()-i);
+ i=static_cast<int>(it->second.length());
+ }
}
if (i>0 && ns==scope.left(i)) break;
}
@@ -7163,9 +5450,9 @@ bool findAndRemoveWord(QCString &s,const QCString &word)
int p=0,i,l;
while ((i=wordExp.match(s,p,&l))!=-1)
{
- if (s.mid(i,l)==word)
+ if (s.mid(i,l)==word)
{
- if (i>0 && isspace((uchar)s.at(i-1)))
+ if (i>0 && isspace((uchar)s.at(i-1)))
i--,l++;
else if (i+l<(int)s.length() && isspace((uchar)s.at(i+l)))
l++;
@@ -7193,10 +5480,11 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine)
// search for leading empty lines
int i=0,li=-1,l=s.length();
char c;
- while ((c=*p++))
+ while ((c=*p))
{
- if (c==' ' || c=='\t' || c=='\r') i++;
- else if (c=='\n') i++,li=i,docLine++;
+ if (c==' ' || c=='\t' || c=='\r') i++,p++;
+ else if (c=='\\' && qstrncmp(p,"\\ilinebr",8)==0) i+=8,li=i,p+=8;
+ else if (c=='\n') i++,li=i,docLine++,p++;
else break;
}
@@ -7205,9 +5493,10 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine)
p=s.data()+b;
while (b>=0)
{
- c=*p; p--;
- if (c==' ' || c=='\t' || c=='\r') b--;
- else if (c=='\n') bi=b,b--;
+ c=*p;
+ if (c==' ' || c=='\t' || c=='\r') b--,p--;
+ else if (c=='r' && b>=7 && qstrncmp(p-7,"\\ilinebr",8)==0) bi=b-7,b-=8,p-=8;
+ else if (c=='\n') bi=b,b--,p--;
else break;
}
@@ -7218,6 +5507,7 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine)
if (bi==-1) bi=l;
if (li==-1) li=0;
if (bi<=li) return 0; // only empty lines
+ //printf("docLine='%s' len=%d li=%d bi=%d\n",s.data(),s.length(),li,bi);
return s.mid(li,bi-li);
}
@@ -7249,7 +5539,7 @@ static struct Lang2ExtMap
const char *langName;
const char *parserName;
SrcLangExt parserId;
-}
+}
g_lang2extMap[] =
{
// language parser parser option
@@ -7270,7 +5560,6 @@ g_lang2extMap[] =
{ "vhdl", "vhdl", SrcLangExt_VHDL },
{ "xml", "xml", SrcLangExt_XML },
{ "sql", "sql", SrcLangExt_SQL },
- { "tcl", "tcl", SrcLangExt_Tcl },
{ "md", "md", SrcLangExt_Markdown },
{ 0, 0, (SrcLangExt)0 }
};
@@ -7361,9 +5650,9 @@ void initDefaultExtensionMapping()
updateLanguageMapping(".f95", "fortran");
updateLanguageMapping(".f03", "fortran");
updateLanguageMapping(".f08", "fortran");
+ updateLanguageMapping(".f18", "fortran");
updateLanguageMapping(".vhd", "vhdl");
updateLanguageMapping(".vhdl", "vhdl");
- updateLanguageMapping(".tcl", "tcl");
updateLanguageMapping(".ucf", "vhdl");
updateLanguageMapping(".qsf", "vhdl");
updateLanguageMapping(".md", "md");
@@ -7404,7 +5693,7 @@ QCString getFileNameExtension(QCString fn)
//--------------------------------------------------------------------------
-MemberDef *getMemberFromSymbol(const Definition *scope,const FileDef *fileScope,
+static MemberDef *getMemberFromSymbol(const Definition *scope,const FileDef *fileScope,
const char *n)
{
if (scope==0 ||
@@ -7420,8 +5709,8 @@ MemberDef *getMemberFromSymbol(const Definition *scope,const FileDef *fileScope,
if (name.isEmpty())
return 0; // no name was given
- DefinitionIntf *di = Doxygen::symbolMap->find(name);
- if (di==0)
+ auto range = Doxygen::symbolMap.find(name);
+ if (range.first==range.second)
return 0; // could not find any matching symbols
// mostly copied from getResolvedClassRec()
@@ -7438,40 +5727,21 @@ MemberDef *getMemberFromSymbol(const Definition *scope,const FileDef *fileScope,
int minDistance = 10000;
MemberDef *bestMatch = 0;
- if (di->definitionType()==DefinitionIntf::TypeSymbolList)
+ for (auto it=range.first; it!=range.second; ++it)
{
- //printf("multiple matches!\n");
- // find the closest closest matching definition
- DefinitionListIterator dli(*(DefinitionList*)di);
- Definition *d;
- for (dli.toFirst();(d=dli.current());++dli)
+ Definition *d = it->second;
+ if (d->definitionType()==Definition::TypeMember)
{
- if (d->definitionType()==Definition::TypeMember)
+ SymbolResolver resolver(fileScope);
+ int distance = resolver.isAccessibleFromWithExpScope(scope,d,explicitScopePart);
+ if (distance!=-1 && distance<minDistance)
{
- g_visitedNamespaces.clear();
- int distance = isAccessibleFromWithExpScope(scope,fileScope,d,explicitScopePart);
- if (distance!=-1 && distance<minDistance)
- {
- minDistance = distance;
- bestMatch = dynamic_cast<MemberDef *>(d);
- //printf("new best match %s distance=%d\n",bestMatch->qualifiedName().data(),distance);
- }
+ minDistance = distance;
+ bestMatch = toMemberDef(d);
+ //printf("new best match %s distance=%d\n",bestMatch->qualifiedName().data(),distance);
}
}
}
- else if (di->definitionType()==Definition::TypeMember)
- {
- //printf("unique match!\n");
- Definition *d = (Definition *)di;
- g_visitedNamespaces.clear();
- int distance = isAccessibleFromWithExpScope(scope,fileScope,d,explicitScopePart);
- if (distance!=-1 && distance<minDistance)
- {
- minDistance = distance;
- bestMatch = dynamic_cast<MemberDef *>(d);
- //printf("new best match %s distance=%d\n",bestMatch->qualifiedName().data(),distance);
- }
- }
return bestMatch;
}
@@ -7488,9 +5758,9 @@ bool checkIfTypedef(const Definition *scope,const FileDef *fileScope,const char
const char *writeUtf8Char(FTextStream &t,const char *s)
{
- char c=*s++;
- t << c;
- if (c<0) // multibyte character
+ uchar c=(uchar)*s++;
+ t << (char)c;
+ if (c>=0x80) // multibyte character
{
if (((uchar)c&0xE0)==0xC0)
{
@@ -7516,12 +5786,12 @@ const char *writeUtf8Char(FTextStream &t,const char *s)
return s;
}
-int nextUtf8CharPosition(const QCString &utf8Str,int len,int startPos)
+int nextUtf8CharPosition(const QCString &utf8Str,uint len,uint startPos)
{
int bytes=1;
if (startPos>=len) return len;
- char c = utf8Str[startPos];
- if (c<0) // multibyte utf-8 character
+ uchar c = (uchar)utf8Str[startPos];
+ if (c>=0x80) // multibyte utf-8 character
{
if (((uchar)c&0xE0)==0xC0)
{
@@ -7570,7 +5840,8 @@ QCString parseCommentAsText(const Definition *scope,const MemberDef *md,
if (doc.isEmpty()) return s.data();
FTextStream t(&s);
DocNode *root = validatingParseDoc(fileName,lineNr,
- (Definition*)scope,(MemberDef*)md,doc,FALSE,FALSE);
+ (Definition*)scope,(MemberDef*)md,doc,FALSE,FALSE,
+ 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
TextDocVisitor *visitor = new TextDocVisitor(t);
root->accept(visitor);
delete visitor;
@@ -7605,9 +5876,8 @@ QCString parseCommentAsText(const Definition *scope,const MemberDef *md,
//--------------------------------------------------------------------------------------
-static QDict<void> aliasesProcessed;
-
-static QCString expandAliasRec(const QCString s,bool allowRecursion=FALSE);
+static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,
+ const QCString s,bool allowRecursion=FALSE);
struct Marker
{
@@ -7617,8 +5887,8 @@ struct Marker
int size; // size of the marker
};
-/** For a string \a s that starts with a command name, returns the character
- * offset within that string representing the first character after the
+/** For a string \a s that starts with a command name, returns the character
+ * offset within that string representing the first character after the
* command. For an alias with argument, this is the offset to the
* character just after the argument list.
*
@@ -7640,30 +5910,30 @@ static int findEndOfCommand(const char *s)
QCString args = extractAliasArgs(p,0);
i+=args.length();
}
- i+=p-s;
+ i+=(int)(p-s);
}
return i;
}
-/** Replaces the markers in an alias definition \a aliasValue
- * with the corresponding values found in the comma separated argument
+/** Replaces the markers in an alias definition \a aliasValue
+ * with the corresponding values found in the comma separated argument
* list \a argList and the returns the result after recursive alias expansion.
*/
-static QCString replaceAliasArguments(const QCString &aliasValue,const QCString &argList)
+static QCString replaceAliasArguments(StringUnorderedSet &aliasesProcessed,
+ const QCString &aliasValue,const QCString &argList)
{
//printf("----- replaceAliasArguments(val=[%s],args=[%s])\n",aliasValue.data(),argList.data());
// first make a list of arguments from the comma separated argument list
- QList<QCString> args;
- args.setAutoDelete(TRUE);
+ std::vector<QCString> args;
int i,l=(int)argList.length();
int s=0;
for (i=0;i<l;i++)
{
char c = argList.at(i);
- if (c==',' && (i==0 || argList.at(i-1)!='\\'))
+ if (c==',' && (i==0 || argList.at(i-1)!='\\'))
{
- args.append(new QCString(argList.mid(s,i-s)));
+ args.push_back(QCString(argList.mid(s,i-s)));
s=i+1; // start of next argument
}
else if (c=='@' || c=='\\')
@@ -7672,68 +5942,58 @@ static QCString replaceAliasArguments(const QCString &aliasValue,const QCString
i+=findEndOfCommand(argList.data()+i+1);
}
}
- if (l>s) args.append(new QCString(argList.right(l-s)));
+ if (l>s) args.push_back(QCString(argList.right(l-s)));
//printf("found %d arguments\n",args.count());
// next we look for the positions of the markers and add them to a list
- QList<Marker> markerList;
- markerList.setAutoDelete(TRUE);
+ std::vector<Marker> markerList;
l = aliasValue.length();
+ char pc='\0';
+ bool insideMarkerId=false;
int markerStart=0;
- int markerEnd=0;
- for (i=0;i<l;i++)
+ auto isDigit = [](char c) { return c>='0' && c<='9'; };
+ for (i=0;i<=l;i++)
{
- if (markerStart==0 && aliasValue.at(i)=='\\') // start of a \xx marker
+ char c = i<l ? aliasValue.at(i) : '\0';
+ if (insideMarkerId && !isDigit(c)) // found end of a markerId
{
- markerStart=i+1;
+ insideMarkerId = false;
+ int markerLen = i-markerStart;
+ markerList.push_back(Marker(markerStart-1,
+ atoi(aliasValue.mid(markerStart,markerLen)),
+ markerLen+1));
}
- else if (markerStart>0 && aliasValue.at(i)>='0' && aliasValue.at(i)<='9')
+ if (c=='\\' && (pc=='@' || pc=='\\')) // found escaped backslash
{
- // read digit that make up the marker number
- markerEnd=i+1;
+ // skip
+ pc = '\0';
}
else
{
- if (markerStart>0 && markerEnd>markerStart) // end of marker
+ if (isDigit(c) && pc=='\\') // found start of a markerId
{
- int markerLen = markerEnd-markerStart;
- markerList.append(new Marker(markerStart-1, // include backslash
- atoi(aliasValue.mid(markerStart,markerLen)),markerLen+1));
- //printf("found marker at %d with len %d and number %d\n",
- // markerStart-1,markerLen+1,atoi(aliasValue.mid(markerStart,markerLen)));
+ insideMarkerId=true;
+ markerStart=i;
}
- markerStart=0; // outside marker
- markerEnd=0;
+ pc = c;
}
}
- if (markerStart>0)
- {
- markerEnd=l;
- }
- if (markerStart>0 && markerEnd>markerStart)
- {
- int markerLen = markerEnd-markerStart;
- markerList.append(new Marker(markerStart-1, // include backslash
- atoi(aliasValue.mid(markerStart,markerLen)),markerLen+1));
- //printf("found marker at %d with len %d and number %d\n",
- // markerStart-1,markerLen+1,atoi(aliasValue.mid(markerStart,markerLen)));
- }
// then we replace the markers with the corresponding arguments in one pass
QCString result;
int p=0;
- for (i=0;i<(int)markerList.count();i++)
+ for (i=0;i<(int)markerList.size();i++)
{
- Marker *m = markerList.at(i);
- result+=aliasValue.mid(p,m->pos-p);
+ const Marker &m = markerList.at(i);
+ result+=aliasValue.mid(p,m.pos-p);
//printf("part before marker %d: '%s'\n",i,aliasValue.mid(p,m->pos-p).data());
- if (m->number>0 && m->number<=(int)args.count()) // valid number
+ if (m.number>0 && m.number<=(int)args.size()) // valid number
{
- result+=expandAliasRec(*args.at(m->number-1),TRUE);
+ result+=expandAliasRec(aliasesProcessed,args.at(m.number-1),TRUE);
//printf("marker index=%d pos=%d number=%d size=%d replacement %s\n",i,m->pos,m->number,m->size,
// args.at(m->number-1)->data());
}
- p=m->pos+m->size; // continue after the marker
+ p=m.pos+m.size; // continue after the marker
}
result+=aliasValue.right(l-p); // append remainder
//printf("string after replacement of markers: '%s'\n",result.data());
@@ -7741,7 +6001,7 @@ static QCString replaceAliasArguments(const QCString &aliasValue,const QCString
// expand the result again
result = substitute(result,"\\{","{");
result = substitute(result,"\\}","}");
- result = expandAliasRec(substitute(result,"\\,",","));
+ result = expandAliasRec(aliasesProcessed,substitute(result,"\\,",","));
return result;
}
@@ -7768,7 +6028,7 @@ static QCString escapeCommas(const QCString &s)
return result.data();
}
-static QCString expandAliasRec(const QCString s,bool allowRecursion)
+static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,const QCString s,bool allowRecursion)
{
QCString result;
static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*");
@@ -7789,8 +6049,8 @@ static QCString expandAliasRec(const QCString s,bool allowRecursion)
cmd += QCString().sprintf("{%d}",numArgs); // alias name + {n}
}
QCString *aliasText=Doxygen::aliasDict.find(cmd);
- if (numArgs>1 && aliasText==0)
- { // in case there is no command with numArgs parameters, but there is a command with 1 parameter,
+ if (numArgs>1 && aliasText==0)
+ { // in case there is no command with numArgs parameters, but there is a command with 1 parameter,
// we also accept all text as the argument of that command (so you don't have to escape commas)
aliasText=Doxygen::aliasDict.find(cmdNoArgs+"{1}");
if (aliasText)
@@ -7801,19 +6061,20 @@ static QCString expandAliasRec(const QCString s,bool allowRecursion)
}
//printf("Found command s='%s' cmd='%s' numArgs=%d args='%s' aliasText=%s\n",
// s.data(),cmd.data(),numArgs,args.data(),aliasText?aliasText->data():"<none>");
- if ((allowRecursion || aliasesProcessed.find(cmd)==0) && aliasText) // expand the alias
+ if ((allowRecursion || aliasesProcessed.find(cmd.str())==aliasesProcessed.end()) &&
+ aliasText) // expand the alias
{
//printf("is an alias!\n");
- if (!allowRecursion) aliasesProcessed.insert(cmd,(void *)0x8);
+ if (!allowRecursion) aliasesProcessed.insert(cmd.str());
QCString val = *aliasText;
if (hasArgs)
{
- val = replaceAliasArguments(val,args);
+ val = replaceAliasArguments(aliasesProcessed,val,args);
//printf("replace '%s'->'%s' args='%s'\n",
// aliasText->data(),val.data(),args.data());
}
- result+=expandAliasRec(val);
- if (!allowRecursion) aliasesProcessed.remove(cmd);
+ result+=expandAliasRec(aliasesProcessed,val);
+ if (!allowRecursion) aliasesProcessed.erase(cmd.str());
p=i+l;
if (hasArgs) p+=argsLen+2;
}
@@ -7836,7 +6097,7 @@ int countAliasArguments(const QCString argList)
int count=1;
int l = argList.length();
int i;
- for (i=0;i<l;i++)
+ for (i=0;i<l;i++)
{
char c = argList.at(i);
if (c==',' && (i==0 || argList.at(i-1)!='\\')) count++;
@@ -7870,7 +6131,7 @@ QCString extractAliasArgs(const QCString &args,int pos)
prevChar=0;
}
- if (bc==0)
+ if (bc==0)
{
//printf("extractAliasArgs('%s')->'%s'\n",args.data(),args.mid(pos+1,i-pos-1).data());
return args.mid(pos+1,i-pos-1);
@@ -7883,9 +6144,9 @@ QCString extractAliasArgs(const QCString &args,int pos)
QCString resolveAliasCmd(const QCString aliasCmd)
{
QCString result;
- aliasesProcessed.clear();
+ StringUnorderedSet aliasesProcessed;
//printf("Expanding: '%s'\n",aliasCmd.data());
- result = expandAliasRec(aliasCmd);
+ result = expandAliasRec(aliasesProcessed,aliasCmd);
//printf("Expanding result: '%s'->'%s'\n",aliasCmd.data(),result.data());
return result;
}
@@ -7893,12 +6154,12 @@ QCString resolveAliasCmd(const QCString aliasCmd)
QCString expandAlias(const QCString &aliasName,const QCString &aliasValue)
{
QCString result;
- aliasesProcessed.clear();
+ StringUnorderedSet aliasesProcessed;
// avoid expanding this command recursively
- aliasesProcessed.insert(aliasName,(void *)0x8);
+ aliasesProcessed.insert(aliasName.str());
// expand embedded commands
//printf("Expanding: '%s'->'%s'\n",aliasName.data(),aliasValue.data());
- result = expandAliasRec(aliasValue);
+ result = expandAliasRec(aliasesProcessed,aliasValue);
//printf("Expanding result: '%s'->'%s'\n",aliasName.data(),result.data());
return result;
}
@@ -7906,7 +6167,7 @@ QCString expandAlias(const QCString &aliasName,const QCString &aliasValue)
void writeTypeConstraints(OutputList &ol,const Definition *d,const ArgumentList &al)
{
if (al.empty()) return;
- ol.startConstraintList(theTranslator->trTypeConstraints());
+ ol.startConstraintList(theTranslator->trTypeConstraints());
for (const Argument &a : al)
{
ol.startConstraintParam();
@@ -7916,7 +6177,8 @@ void writeTypeConstraints(OutputList &ol,const Definition *d,const ArgumentList
linkifyText(TextGeneratorOLImpl(ol),d,0,0,a.type);
ol.endConstraintType();
ol.startConstraintDocs();
- ol.generateDoc(d->docFile(),d->docLine(),d,0,a.docs,TRUE,FALSE);
+ ol.generateDoc(d->docFile(),d->docLine(),d,0,a.docs,TRUE,FALSE,
+ 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
ol.endConstraintDocs();
}
ol.endConstraintList();
@@ -7932,27 +6194,19 @@ void stackTrace()
static char cmd[40960];
char *p = cmd;
p += sprintf(p,"/usr/bin/atos -p %d ", (int)getpid());
- for (int x = 0; x < frameCount; x++)
+ for (int x = 0; x < frameCount; x++)
{
p += sprintf(p,"%p ", backtraceFrames[x]);
}
fprintf(stderr,"========== STACKTRACE START ==============\n");
- #if defined(_WIN32) && !defined(__CYGWIN__)
- if (FILE *fp = _popen(cmd, "r"))
- #else
- if (FILE *fp = ::popen(cmd, "r"))
- #endif
+ if (FILE *fp = Portable::popen(cmd, "r"))
{
char resBuf[512];
while (size_t len = fread(resBuf, 1, sizeof(resBuf), fp))
{
fwrite(resBuf, 1, len, stderr);
}
- #if defined(_WIN32) && !defined(__CYGWIN__)
- _pclose(fp);
- #else
- ::pclose(fp);
- #endif
+ Portable::pclose(fp);
}
fprintf(stderr,"============ STACKTRACE END ==============\n");
//fprintf(stderr,"%s\n", frameStrings[x]);
@@ -7965,7 +6219,7 @@ static int transcodeCharacterBuffer(const char *fileName,BufStr &srcBuf,int size
if (inputEncoding==0 || outputEncoding==0) return size;
if (qstricmp(inputEncoding,outputEncoding)==0) return size;
void *cd = portable_iconv_open(outputEncoding,inputEncoding);
- if (cd==(void *)(-1))
+ if (cd==(void *)(-1))
{
term("unsupported character conversion: '%s'->'%s': %s\n"
"Check the INPUT_ENCODING setting in the config file!\n",
@@ -8111,27 +6365,26 @@ QCString filterTitle(const QCString &title)
// returns TRUE if the name of the file represented by 'fi' matches
// one of the file patterns in the 'patList' list.
-bool patternMatch(const QFileInfo &fi,const QStrList *patList)
+bool patternMatch(const QFileInfo &fi,const StringVector &patList)
{
- static bool caseSenseNames = Config_getBool(CASE_SENSE_NAMES);
+ bool caseSenseNames = Config_getBool(CASE_SENSE_NAMES);
bool found = FALSE;
- // For Windows/Mac, always do the case insensitive match
-#if defined(_WIN32) || defined(__MACOSX__) || defined(__CYGWIN__)
- caseSenseNames = FALSE;
-#endif
-
- if (patList)
+ // For platforms where the file system is non case sensitive overrule the setting
+ if (!Portable::fileSystemIsCaseSensitive())
{
- QStrListIterator it(*patList);
- QCString pattern;
+ caseSenseNames = FALSE;
+ }
+ if (!patList.empty())
+ {
QCString fn = fi.fileName().data();
QCString fp = fi.filePath().data();
QCString afp= fi.absFilePath().data();
- for (it.toFirst();(pattern=it.current());++it)
+ for (const auto &pat: patList)
{
+ QCString pattern = pat.c_str();
if (!pattern.isEmpty())
{
int i=pattern.find('=');
@@ -8181,10 +6434,15 @@ void writeSummaryLink(OutputList &ol,const char *label,const char *title,
}
#endif
-QCString externalLinkTarget()
+QCString externalLinkTarget(const bool parent)
{
static bool extLinksInWindow = Config_getBool(EXT_LINKS_IN_WINDOW);
- if (extLinksInWindow) return "target=\"_blank\" "; else return "";
+ if (extLinksInWindow)
+ return "target=\"_blank\" ";
+ else if (parent)
+ return "target=\"_parent\" ";
+ else
+ return "";
}
QCString externalRef(const QCString &relPath,const QCString &ref,bool href)
@@ -8213,7 +6471,7 @@ QCString externalRef(const QCString &relPath,const QCString &ref,bool href)
return result;
}
-/** Writes the intensity only bitmap represented by \a data as an image to
+/** Writes the intensity only bitmap represented by \a data as an image to
* directory \a dir using the colors defined by HTML_COLORSTYLE_*.
*/
void writeColoredImgData(const char *dir,ColoredImgDataItem data[])
@@ -8242,8 +6500,8 @@ void writeColoredImgData(const char *dir,ColoredImgDataItem data[])
}
/** Replaces any markers of the form \#\#AA in input string \a str
- * by new markers of the form \#AABBCC, where \#AABBCC represents a
- * valid color, based on the intensity represented by hex number AA
+ * by new markers of the form \#AABBCC, where \#AABBCC represents a
+ * valid color, based on the intensity represented by hex number AA
* and the current HTML_COLORSTYLE_* settings.
*/
QCString replaceColorMarkers(const char *str)
@@ -8252,7 +6510,6 @@ QCString replaceColorMarkers(const char *str)
QCString s=str;
if (s.isEmpty()) return result;
static QRegExp re("##[0-9A-Fa-f][0-9A-Fa-f]");
- static const char hex[] = "0123456789ABCDEF";
static int hue = Config_getInt(HTML_COLORSTYLE_HUE);
static int sat = Config_getInt(HTML_COLORSTYLE_SAT);
static int gamma = Config_getInt(HTML_COLORSTYLE_GAMMA);
@@ -8264,7 +6521,7 @@ QCString replaceColorMarkers(const char *str)
#define HEXTONUM(x) (((x)>='0' && (x)<='9') ? ((x)-'0') : \
((x)>='a' && (x)<='f') ? ((x)-'a'+10) : \
((x)>='A' && (x)<='F') ? ((x)-'A'+10) : 0)
-
+
double r,g,b;
int red,green,blue;
int level = HEXTONUM(lumStr[0])*16+HEXTONUM(lumStr[1]);
@@ -8290,7 +6547,7 @@ QCString replaceColorMarkers(const char *str)
return result;
}
-/** Copies the contents of file with name \a src to the newly created
+/** Copies the contents of file with name \a src to the newly created
* file with name \a dest. Returns TRUE if successful.
*/
bool copyFile(const QCString &src,const QCString &dest)
@@ -8322,7 +6579,7 @@ bool copyFile(const QCString &src,const QCString &dest)
return TRUE;
}
-/** Returns the section of text, in between a pair of markers.
+/** Returns the section of text, in between a pair of markers.
* Full lines are returned, excluding the lines on which the markers appear.
* \sa routine lineBlock
*/
@@ -8410,7 +6667,6 @@ QCString langToString(SrcLangExt lang)
case SrcLangExt_VHDL: return "VHDL";
case SrcLangExt_XML: return "XML";
case SrcLangExt_SQL: return "SQL";
- case SrcLangExt_Tcl: return "Tcl";
case SrcLangExt_Markdown: return "Markdown";
case SrcLangExt_Slice: return "Slice";
}
@@ -8433,17 +6689,15 @@ QCString getLanguageSpecificSeparator(SrcLangExt lang,bool classScope)
return "::";
}
}
-QCString replaceScopeSeparator(QCString str)
-{
- // we don't know about the language so we have to go for the worse
- return substitute(substitute(str,"\\","::"),".","::"); // PHP and Java, CSharp, VHDL, Python
-}
/** Checks whether the given url starts with a supported protocol */
bool isURL(const QCString &url)
{
QCString loc_url = url.stripWhiteSpace();
- return loc_url.left(5)=="http:" || loc_url.left(6)=="https:" ||
- loc_url.left(4)=="ftp:" || loc_url.left(5)=="file:";
+ return loc_url.left(5)=="http:" || loc_url.left(6)=="https:" ||
+ loc_url.left(4)=="ftp:" || loc_url.left(5)=="ftps:" ||
+ loc_url.left(5)=="sftp:" || loc_url.left(5)=="file:" ||
+ loc_url.left(5)=="news:" || loc_url.left(4)=="irc:" ||
+ loc_url.left(5)=="ircs:";
}
/** Corrects URL \a url according to the relative path \a relPath.
* Returns the corrected URL. For absolute URLs no correction will be done.
@@ -8465,8 +6719,8 @@ bool protectionLevelVisible(Protection prot)
static bool extractPrivate = Config_getBool(EXTRACT_PRIVATE);
static bool extractPackage = Config_getBool(EXTRACT_PACKAGE);
- return (prot!=Private && prot!=Package) ||
- (prot==Private && extractPrivate) ||
+ return (prot!=Private && prot!=Package) ||
+ (prot==Private && extractPrivate) ||
(prot==Package && extractPackage);
}
@@ -8489,7 +6743,7 @@ QCString stripIndentation(const QCString &s)
if (c=='\t') indent+=tabSize - (indent%tabSize);
else if (c=='\n') indent=0,searchIndent=TRUE;
else if (c==' ') indent++;
- else if (searchIndent)
+ else if (searchIndent)
{
searchIndent=FALSE;
if (indent<minIndent) minIndent=indent;
@@ -8538,6 +6792,55 @@ QCString stripIndentation(const QCString &s)
return result.data();
}
+// strip up to \a indentationLevel spaces from each line in \a doc (excluding the first line)
+void stripIndentation(QCString &doc,const int indentationLevel)
+{
+ if (indentationLevel <= 0 || doc.isEmpty()) return; // nothing to strip
+
+ // by stripping content the string will only become shorter so we write the results
+ // back into the input string and then resize it at the end.
+ char c;
+ const char *src = doc.data();
+ char *dst = doc.rawData();
+ bool insideIndent = false; // skip the initial line from stripping
+ int cnt = 0;
+ while ((c=*src++)!=0)
+ {
+ // invariant: dst<=src
+ switch(c)
+ {
+ case '\n':
+ *dst++ = c;
+ insideIndent = true;
+ cnt = indentationLevel;
+ break;
+ case ' ':
+ if (insideIndent)
+ {
+ if (cnt>0) // count down the spacing until the end of the indent
+ {
+ cnt--;
+ }
+ else // reached the end of the indent, start of the part of the line to keep
+ {
+ insideIndent = false;
+ *dst++ = c;
+ }
+ }
+ else // part after indent, copy to the output
+ {
+ *dst++ = c;
+ }
+ break;
+ default:
+ insideIndent = false;
+ *dst++ = c;
+ break;
+ }
+ }
+ doc.resize(dst-doc.data()+1);
+}
+
bool fileVisibleInIndex(const FileDef *fd,bool &genSourceFile)
{
@@ -8546,49 +6849,11 @@ bool fileVisibleInIndex(const FileDef *fd,bool &genSourceFile)
genSourceFile = !isDocFile && fd->generateSourceFile();
return ( ((allExternals && fd->isLinkable()) ||
fd->isLinkableInProject()
- ) &&
+ ) &&
!isDocFile
);
}
-void addDocCrossReference(MemberDef *src,MemberDef *dst)
-{
- //printf("--> addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
- if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
- if ((dst->hasReferencedByRelation() || dst->hasCallerGraph()) &&
- src->showInCallGraph()
- )
- {
- dst->addSourceReferencedBy(src);
- MemberDef *mdDef = dst->memberDefinition();
- if (mdDef)
- {
- mdDef->addSourceReferencedBy(src);
- }
- MemberDef *mdDecl = dst->memberDeclaration();
- if (mdDecl)
- {
- mdDecl->addSourceReferencedBy(src);
- }
- }
- if ((src->hasReferencesRelation() || src->hasCallGraph()) &&
- src->showInCallGraph()
- )
- {
- src->addSourceReferences(dst);
- MemberDef *mdDef = src->memberDefinition();
- if (mdDef)
- {
- mdDef->addSourceReferences(dst);
- }
- MemberDef *mdDecl = src->memberDeclaration();
- if (mdDecl)
- {
- mdDecl->addSourceReferences(dst);
- }
- }
-}
-
//--------------------------------------------------------------------------------------
/*! @brief Get one unicode character as an unsigned integer from utf-8 string
@@ -8627,7 +6892,7 @@ uint getUtf8Code( const QCString& s, int idx )
}
-/*! @brief Returns one unicode character as an unsigned integer
+/*! @brief Returns one unicode character as an unsigned integer
* from utf-8 string, making the character lower case if it was upper case.
*
* @param s utf-8 encoded string
@@ -8642,7 +6907,7 @@ uint getUtf8CodeToLower( const QCString& s, int idx )
}
-/*! @brief Returns one unicode character as an unsigned integer
+/*! @brief Returns one unicode character as an unsigned integer
* from utf-8 string, making the character upper case if it was lower case.
*
* @param s utf-8 encoded string
@@ -8657,55 +6922,54 @@ uint getUtf8CodeToUpper( const QCString& s, int idx )
}
//--------------------------------------------------------------------------------------
+//
+bool namespaceHasNestedNamespace(const NamespaceDef *nd)
+{
+ for (const auto &cnd : nd->getNamespaces())
+ {
+ if (cnd->isLinkableInProject() && !cnd->isAnonymous())
+ {
+ return true;
+ }
+ }
+ return false;
+}
-bool namespaceHasVisibleChild(const NamespaceDef *nd,bool includeClasses,bool filterClasses,ClassDef::CompoundType ct)
+bool namespaceHasNestedClass(const NamespaceDef *nd,bool filterClasses,ClassDef::CompoundType ct)
{
- if (nd->getNamespaceSDict())
+ //printf(">namespaceHasVisibleChild(%s,includeClasses=%d)\n",nd->name().data(),includeClasses);
+ for (const auto &cnd : nd->getNamespaces())
{
- NamespaceSDict::Iterator cnli(*nd->getNamespaceSDict());
- const NamespaceDef *cnd;
- for (cnli.toFirst();(cnd=cnli.current());++cnli)
+ if (namespaceHasNestedClass(cnd,filterClasses,ct))
{
- if (cnd->isLinkableInProject() && !cnd->isAnonymous())
- {
- return TRUE;
- }
- else if (namespaceHasVisibleChild(cnd,includeClasses,filterClasses,ct))
- {
- return TRUE;
- }
+ //printf("<namespaceHasVisibleChild(%s,includeClasses=%d): case2\n",nd->name().data(),includeClasses);
+ return TRUE;
}
}
- if (includeClasses)
+
+ ClassLinkedRefMap list = nd->getClasses();
+ if (filterClasses)
{
- const ClassSDict *d = nd->getClassSDict();
- if (filterClasses)
+ if (ct == ClassDef::Interface)
{
- if (ct == ClassDef::Interface)
- {
- d = nd->getInterfaceSDict();
- }
- else if (ct == ClassDef::Struct)
- {
- d = nd->getStructSDict();
- }
- else if (ct == ClassDef::Exception)
- {
- d = nd->getExceptionSDict();
- }
+ list = nd->getInterfaces();
+ }
+ else if (ct == ClassDef::Struct)
+ {
+ list = nd->getStructs();
+ }
+ else if (ct == ClassDef::Exception)
+ {
+ list = nd->getExceptions();
}
+ }
- if (d)
+ for (const auto &cd : list)
+ {
+ if (cd->isLinkableInProject() && cd->templateMaster()==0)
{
- ClassSDict::Iterator cli(*d);
- const ClassDef *cd;
- for (;(cd=cli.current());++cli)
- {
- if (cd->isLinkableInProject() && cd->templateMaster()==0)
- {
- return TRUE;
- }
- }
+ //printf("<namespaceHasVisibleChild(%s,includeClasses=%d): case3\n",nd->name().data(),includeClasses);
+ return TRUE;
}
}
return FALSE;
@@ -8723,20 +6987,22 @@ bool classVisibleInIndex(const ClassDef *cd)
QCString extractDirection(QCString &docs)
{
- QRegExp re("\\[[^\\]]+\\]"); // [...]
+ QRegExp re("\\[[ inout,]+\\]"); // [...]
int l=0;
- if (re.match(docs,0,&l)==0)
+ if (re.match(docs,0,&l)==0 && l>2)
{
- int inPos = docs.find("in", 1,FALSE);
- int outPos = docs.find("out",1,FALSE);
- bool input = inPos!=-1 && inPos<l;
- bool output = outPos!=-1 && outPos<l;
- if (input || output) // in,out attributes
+ // make dir the part inside [...] without separators
+ QCString dir=substitute(substitute(docs.mid(1,l-2)," ",""),",","");
+ int inIndex, outIndex;
+ unsigned char ioMask=0;
+ if (( inIndex=dir.find( "in"))!=-1) dir.remove (inIndex,2),ioMask|=(1<<0);
+ if ((outIndex=dir.find("out"))!=-1) dir.remove(outIndex,3),ioMask|=(1<<1);
+ if (dir.isEmpty() && ioMask!=0) // only in and/or out attributes found
{
docs = docs.mid(l); // strip attributes
- if (input && output) return "[in,out]";
- else if (input) return "[in]";
- else if (output) return "[out]";
+ if (ioMask==((1<<0)|(1<<1))) return "[in,out]";
+ else if (ioMask==(1<<0)) return "[in]";
+ else if (ioMask==(1<<1)) return "[out]";
}
}
return QCString();
@@ -8938,7 +7204,7 @@ bool mainPageHasTitle()
return Doxygen::mainPage!=0 && Doxygen::mainPage->hasTitle();
}
-QCString getDotImageExtension(void)
+QCString getDotImageExtension()
{
QCString imgExt = Config_getEnum(DOT_IMAGE_FORMAT);
int i= imgExt.find(':'); // strip renderer part when using e.g. 'png:cairo:gd' as format
@@ -8963,7 +7229,7 @@ bool openOutputFile(const char *outFile,QFile &f)
if (backup.exists()) // remove existing backup
dir.remove(backup.fileName());
dir.rename(fi.fileName(),fi.fileName()+".bak");
- }
+ }
f.setName(outFile);
fileOpened = f.open(IO_WriteOnly|IO_Translate);
}
@@ -8973,18 +7239,16 @@ bool openOutputFile(const char *outFile,QFile &f)
void writeExtraLatexPackages(FTextStream &t)
{
// User-specified packages
- QStrList &extraPackages = Config_getList(EXTRA_PACKAGES);
- if (!extraPackages.isEmpty())
+ const StringVector &extraPackages = Config_getList(EXTRA_PACKAGES);
+ if (!extraPackages.empty())
{
t << "% Packages requested by user\n";
- const char *pkgName=extraPackages.first();
- while (pkgName)
+ for (const auto &pkgName : extraPackages)
{
if ((pkgName[0] == '[') || (pkgName[0] == '{'))
- t << "\\usepackage" << pkgName << "\n";
+ t << "\\usepackage" << pkgName.c_str() << "\n";
else
- t << "\\usepackage{" << pkgName << "}\n";
- pkgName=extraPackages.next();
+ t << "\\usepackage{" << pkgName.c_str() << "}\n";
}
t << "\n";
}
@@ -9017,22 +7281,56 @@ void writeLatexSpecialFormulaChars(FTextStream &t)
}
//------------------------------------------------------
+// simplified way to know if this is fixed form
+bool recognizeFixedForm(const char* contents, FortranFormat format)
+{
+ int column=0;
+ bool skipLine=FALSE;
-static int g_usedTableLevels = 0;
+ if (format == FortranFormat_Fixed) return TRUE;
+ if (format == FortranFormat_Free) return FALSE;
-void incUsedTableLevels()
-{
- g_usedTableLevels++;
-}
-void decUsedTableLevels()
-{
- g_usedTableLevels--;
-}
-int usedTableLevels()
-{
- return g_usedTableLevels;
+ for(int i=0;;i++) {
+ column++;
+
+ switch(contents[i]) {
+ case '\n':
+ column=0;
+ skipLine=FALSE;
+ break;
+ case ' ':
+ break;
+ case '\000':
+ return FALSE;
+ case '#':
+ skipLine=TRUE;
+ break;
+ case 'C':
+ case 'c':
+ case '*':
+ if (column==1) return TRUE;
+ if (skipLine) break;
+ return FALSE;
+ case '!':
+ if (column>1 && column<7) return FALSE;
+ skipLine=TRUE;
+ break;
+ default:
+ if (skipLine) break;
+ if (column>=7) return TRUE;
+ return FALSE;
+ }
+ }
+ return FALSE;
}
-//------------------------------------------------------
+FortranFormat convertFileNameFortranParserCode(QCString fn)
+{
+ QCString ext = getFileNameExtension(fn);
+ QCString parserName = Doxygen::parserManager->getParserName(ext.data());
+ if (parserName == "fortranfixed") return FortranFormat_Fixed;
+ else if (parserName == "fortranfree") return FortranFormat_Free;
+ return FortranFormat_Unknown;
+}