summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/code.l393
-rw-r--r--src/pycode.l215
-rw-r--r--src/scopedtypevariant.h292
3 files changed, 463 insertions, 437 deletions
diff --git a/src/code.l b/src/code.l
index 9374b40..a614140 100644
--- a/src/code.l
+++ b/src/code.l
@@ -26,12 +26,14 @@
* includes
*/
+#include <utility>
#include <memory>
#include <algorithm>
#include <unordered_map>
#include <stack>
#include <vector>
#include <string>
+#include <mutex>
#include <stdio.h>
#include <assert.h>
@@ -55,6 +57,7 @@
#include "filename.h"
#include "namespacedef.h"
#include "tooltip.h"
+#include "scopedtypevariant.h"
// Toggle for some debugging info
//#define DBG_CTX(x) fprintf x
@@ -68,10 +71,6 @@
#define USE_STATE2STRING 0
-/* -----------------------------------------------------------------
- * statics
- */
-
// context for an Objective-C method call
struct ObjCCallCtx
{
@@ -87,116 +86,11 @@ struct ObjCCallCtx
int braceCount;
};
-/*! Represents a stack of variable to class mappings as found in the
- * code. Each scope is enclosed in pushScope() and popScope() calls.
- * Variables are added by calling addVariables() and one can search
- * for variable using findVariable().
- */
-class VariableContext
-{
- public:
- static const ClassDef *dummyContext;
-
- using Scope = std::unordered_map<std::string,const ClassDef*>;
-
- void pushScope()
- {
- m_scopes.push_back(Scope());
- DBG_CTX((stderr,"** Push var context %zu\n",m_scopes.size()));
- }
-
- void popScope()
- {
- if (!m_scopes.empty())
- {
- DBG_CTX((stderr,"** Pop var context %zu\n",m_scopes.size()));
- m_scopes.pop_back();
- }
- else
- {
- DBG_CTX((stderr,"** ILLEGAL: Pop var context\n"));
- }
- }
-
- void clear()
- {
- m_scopes.clear();
- m_globalScope.clear();
- }
-
- void addVariable(yyscan_t yyscanner,const QCString &type,const QCString &name);
- const ClassDef *findVariable(const QCString &name);
-
- private:
- Scope m_globalScope;
- std::vector<Scope> m_scopes;
-};
-
-//-------------------------------------------------------------------
-
-class CallContext
-{
- public:
- struct Ctx
- {
- Ctx(QCString name_, QCString type_) : name(name_), type(type_) {}
- QCString name;
- QCString type;
- const Definition *d = 0;
- };
-
- CallContext()
- {
- clear();
- }
-
- void setScope(const Definition *d)
- {
- Ctx &ctx = m_defList.back();
- DBG_CTX((stderr,"** Set call context %s (%p)\n",d==0 ? "<null>" : d->name().data(),d));
- ctx.d=d;
- }
- void pushScope(QCString name_, QCString type_)
- {
- m_defList.push_back(Ctx(name_,type_));
- DBG_CTX((stderr,"** Push call context %zu\n",m_defList.size()));
- }
- void popScope(QCString &name_, QCString &type_)
- {
- if (m_defList.size()>1)
- {
- DBG_CTX((stderr,"** Pop call context %zu\n",m_defList.size()));
- const Ctx &ctx = m_defList.back();
- name_ = ctx.name;
- type_ = ctx.type;
- m_defList.pop_back();
- }
- else
- {
- DBG_CTX((stderr,"** ILLEGAL: Pop call context\n"));
- }
- }
- void clear()
- {
- DBG_CTX((stderr,"** Clear call context\n"));
- m_defList.clear();
- m_defList.push_back(Ctx("",""));
- }
- const Definition *getScope() const
- {
- return m_defList.back().d;
- }
-
- private:
- std::vector<Ctx> m_defList;
-};
-
-
struct codeYY_state
{
CodeOutputInterface * code = 0;
- std::unordered_map< std::string, std::unique_ptr<ClassDef> > codeClassMap;
+ std::unordered_map< std::string, ScopedTypeVariant > codeClassMap;
QCString curClassName;
QStrList curClassBases;
@@ -260,7 +154,7 @@ struct codeYY_state
std::stack<int> classScopeLengthStack;
- int prefixed_with_this_keyword = FALSE;
+ int isPrefixedWithThis = FALSE;
const Definition *searchCtx = 0;
bool collectXRefs = FALSE;
@@ -312,7 +206,7 @@ static void addParmType(yyscan_t yyscanner);
static void addUsingDirective(yyscan_t yyscanner,const char *name);
static void setParameterList(yyscan_t yyscanner,const MemberDef *md);
static const ClassDef *stripClassName(yyscan_t yyscanner,const char *s,const Definition *d);
-static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name);
+static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name);
static void updateCallContextForSmartPointer(yyscan_t yyscanner);
static bool getLinkInScope(yyscan_t yyscanner,const QCString &c, // scope
const QCString &m, // member
@@ -342,7 +236,12 @@ static QCString escapeWord(yyscan_t yyscanner,const char *s);
static QCString escapeComment(yyscan_t yyscanner,const char *s);
static bool skipLanguageSpecificKeyword(yyscan_t yyscanner,const QCString &kw);
static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
+static void addVariable(yyscan_t yyscanner,QCString type,QCString name);
+//-------------------------------------------------------------------
+
+static std::mutex g_searchIndexMutex;
+static std::mutex g_tooltipMutex;
/* -----------------------------------------------------------------
*/
@@ -551,7 +450,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
<ObjCParams>{ID} {
yyextra->code->codify(yytext);
yyextra->parmName=yytext;
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
yyextra->parmType.resize(0);yyextra->parmName.resize(0);
}
<ObjCMethod,ObjCParams,ObjCParamType>{ID} {
@@ -827,7 +726,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
yyextra->name = yytext;
if (yyextra->insideBody)
{
- yyextra->theVarContext.addVariable(yyscanner,yyextra->type,yyextra->name);
+ addVariable(yyscanner,yyextra->type,yyextra->name);
}
generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
}
@@ -860,8 +759,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
if (getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,yyextra->curClassName)==0)
{
DBG_CTX((stderr,"Adding new class %s\n",yyextra->curClassName.data()));
- std::unique_ptr<ClassDef> ncd { createClassDef("<code>",1,1,
- yyextra->curClassName,ClassDef::Class,0,0,FALSE) };
+ ScopedTypeVariant var(yyextra->curClassName);
// insert base classes.
char *s=yyextra->curClassBases.first();
while (s)
@@ -870,16 +768,16 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
auto it = yyextra->codeClassMap.find(s);
if (it!=yyextra->codeClassMap.end())
{
- bcd=it->second.get();
+ bcd = dynamic_cast<const ClassDef*>(it->second.globalDef());
}
if (bcd==0) bcd=getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,s);
- if (bcd && bcd!=ncd.get())
+ if (bcd && bcd->name()!=yyextra->curClassName)
{
- ncd->insertBaseClass(const_cast<ClassDef*>(bcd),s,Public,Normal);
+ var.localDef()->insertBaseClass(bcd->name());
}
s=yyextra->curClassBases.next();
}
- yyextra->codeClassMap.emplace(std::make_pair(yyextra->curClassName.str(),std::move(ncd)));
+ yyextra->codeClassMap.emplace(std::make_pair(yyextra->curClassName.str(),std::move(var)));
}
//printf("yyextra->codeClassList.count()=%d\n",yyextra->codeClassList.count());
}
@@ -1005,7 +903,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
<UsingName>\n { codifyLines(yyscanner,yytext); BEGIN(Body); }
<UsingName>. { codifyLines(yyscanner,yytext); BEGIN(Body); }
<Body,FuncCall>"$"?"this"("->"|".") { yyextra->code->codify(yytext); // this-> for C++, this. for C#
- yyextra->prefixed_with_this_keyword = TRUE;
+ yyextra->isPrefixedWithThis = TRUE;
}
<Body>{KEYWORD}/([^a-z_A-Z0-9]) {
if (yyextra->lang==SrcLangExt_Java && qstrcmp("internal",yytext) ==0) REJECT;
@@ -1039,7 +937,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
endFontClass(yyscanner);
// insert the variable in the parent scope, see bug 546158
yyextra->theVarContext.popScope();
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
yyextra->theVarContext.pushScope();
yyextra->name.resize(0);yyextra->type.resize(0);
}
@@ -1359,9 +1257,9 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
BEGIN( MemberCall );
}
<MemberCall>{SCOPETNAME}/{BN}*"(" {
- if (yyextra->theCallContext.getScope())
+ if (yyextra->theCallContext.getScope().globalDef())
{
- if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope(),yytext))
+ if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
{
yyextra->code->codify(yytext);
addToSearchIndex(yyscanner,yytext);
@@ -1385,10 +1283,10 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
}
}
<MemberCall>{SCOPENAME}/{B}* {
- if (yyextra->theCallContext.getScope())
+ if (yyextra->theCallContext.getScope().globalDef())
{
- DBG_CTX((stderr,"yyextra->theCallContext.getClass()=%p\n",yyextra->theCallContext.getScope()));
- if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope(),yytext))
+ DBG_CTX((stderr,"yyextra->theCallContext.getClass()=%p\n",yyextra->theCallContext.getScope().globalDef()));
+ if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
{
yyextra->code->codify(yytext);
addToSearchIndex(yyscanner,yytext);
@@ -1435,7 +1333,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
{
//printf("AddVariable: '%s' '%s' context=%d\n",
// yyextra->type.data(),yyextra->name.data(),yyextra->theVarContext.count());
- yyextra->theVarContext.addVariable(yyscanner,yyextra->type,yyextra->name);
+ addVariable(yyscanner,yyextra->type,yyextra->name);
}
yyextra->name.resize(0);
}
@@ -1665,7 +1563,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
}
<MemberCall2,FuncCall>, {
yyextra->code->codify(yytext);
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
yyextra->parmType.resize(0);yyextra->parmName.resize(0);
}
<MemberCall2,FuncCall>"{" {
@@ -1727,13 +1625,13 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
yyextra->parmType=yyextra->parmName;
yyextra->parmName.resize(0);
}
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
}
else
{
yyextra->parmType = yyextra->parmName;
yyextra->parmName.resize(0);
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
}
yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
yyextra->inForEachExpression = FALSE;
@@ -1762,10 +1660,10 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
if (!yyextra->type.isEmpty())
{
DBG_CTX((stderr,"add variable yyextra->type=%s yyextra->name=%s)\n",yyextra->type.data(),yyextra->name.data()));
- yyextra->theVarContext.addVariable(yyscanner,yyextra->type,yyextra->name);
+ addVariable(yyscanner,yyextra->type,yyextra->name);
}
yyextra->parmType.resize(0);yyextra->parmName.resize(0);
- yyextra->theCallContext.setScope(0);
+ yyextra->theCallContext.setScope(ScopedTypeVariant());
if (*yytext==';' || yyextra->insideBody)
{
if (!yyextra->insideBody)
@@ -1791,7 +1689,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
{
yyextra->theVarContext.pushScope();
}
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
//yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
yyextra->parmType.resize(0);yyextra->parmName.resize(0);
int index = yyextra->name.findRev("::");
@@ -1865,7 +1763,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
}
<OldStyleArgs>[,;] {
yyextra->code->codify(yytext);
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
if (*yytext==';') yyextra->parmType.resize(0);
yyextra->parmName.resize(0);
}
@@ -2290,7 +2188,7 @@ NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
/*@ ----------------------------------------------------------------------------
*/
-void VariableContext::addVariable(yyscan_t yyscanner,const QCString &type,const QCString &name)
+static void addVariable(yyscan_t yyscanner,QCString type,QCString name)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
//printf("VariableContext::addVariable(%s,%s)\n",type.data(),name.data());
@@ -2307,102 +2205,44 @@ void VariableContext::addVariable(yyscan_t yyscanner,const QCString &type,const
if (ltype.isEmpty() || lname.isEmpty()) return;
DBG_CTX((stderr,"** addVariable trying: type='%s' name='%s' currentDefinition=%s\n",
ltype.data(),lname.data(),yyextra->currentDefinition?yyextra->currentDefinition->name().data():"<none>"));
- Scope *scope = m_scopes.empty() ? &m_globalScope : &m_scopes.back();
- const ClassDef *varType = 0;
auto it = yyextra->codeClassMap.find(ltype.str());
if (it!=yyextra->codeClassMap.end()) // look for class definitions inside the code block
{
- varType = it->second.get();
- }
- if (varType==0) // look for global class definitions
- {
- varType = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,ltype);
- }
- int i=0;
- if (varType)
- {
DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",ltype.data(),lname.data()));
- scope->emplace(std::make_pair(lname.str(),varType)); // add it to a list
+ yyextra->theVarContext.addVariable(lname,std::move(it->second)); // add it to a list
}
- else if ((i=ltype.find('<'))!=-1)
+ else
{
- // probably a template class
- QCString typeName(ltype.left(i));
- const ClassDef* newDef = 0;
- QCString templateArgs(ltype.right(ltype.length() - i));
- it = yyextra->codeClassMap.find(typeName.str());
- if (!typeName.isEmpty())
- {
- if (it!=yyextra->codeClassMap.end()) // look for class definitions inside the code block
- {
- varType = it->second.get();
- }
- else // otherwise look for global class definitions
- {
- varType = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,typeName,0,0,TRUE,TRUE);
- }
- }
- if (varType && !varType->templateArguments().empty()) // and it must be a template
- {
- newDef = varType->getVariableInstance( templateArgs );
- }
- if (newDef)
+ const ClassDef *varDef = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,ltype);
+ int i=0;
+ if (varDef)
{
- DBG_CTX((stderr,"** addVariable type='%s' templ='%s' name='%s'\n",typeName.data(),templateArgs.data(),lname.data()));
- scope->emplace(std::make_pair(lname.str(), newDef));
+ DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",ltype.data(),lname.data()));
+ yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varDef)); // add it to a list
}
- else
+ else if ((i=ltype.find('<'))!=-1)
{
- // Doesn't seem to be a template. Try just the base name.
+ // probably a template class
+ QCString typeName(ltype.left(i));
addVariable(yyscanner,typeName,name);
}
- }
- else
- {
- if (!m_scopes.empty()) // for local variables add a dummy entry so the name
- // is hidden to avoid false links to global variables with the same name
- // TODO: make this work for namespaces as well!
- {
- DBG_CTX((stderr,"** addVariable: dummy context for '%s'\n",lname.data()));
- scope->emplace(std::make_pair(lname.str(),dummyContext));
- }
else
{
- DBG_CTX((stderr,"** addVariable: not adding variable!\n"));
- }
- }
-}
-
-const ClassDef *VariableContext::findVariable(const QCString &name)
-{
- if (name.isEmpty()) return 0;
- const ClassDef *result = 0;
-
- // search from inner to outer scope
- auto it = std::rbegin(m_scopes);
- while (it != std::rend(m_scopes))
- {
- auto it2 = it->find(name.str());
- if (it2 != std::end(*it))
- {
- result = it2->second;
- DBG_CTX((stderr,"** findVariable(%s)=%p\n",name.data(),result));
- return result;
+ if (!yyextra->theVarContext.atGlobalScope()) // for local variables add a dummy entry so the name
+ // is hidden to avoid false links to global variables with the same name
+ // TODO: make this work for namespaces as well!
+ {
+ DBG_CTX((stderr,"** addVariable: dummy context for '%s'\n",lname.data()));
+ yyextra->theVarContext.addVariable(lname,ScopedTypeVariant());
+ }
+ else
+ {
+ DBG_CTX((stderr,"** addVariable: not adding variable!\n"));
+ }
}
- ++it;
}
- // nothing found -> also try the global scope
- auto it2 = m_globalScope.find(name.str());
- if (it2 != m_globalScope.end())
- {
- result = it2->second;
- }
- DBG_CTX((stderr,"** findVariable(%s)=%p\n",name.data(),result));
- return result;
}
-const ClassDef *VariableContext::dummyContext = (ClassDef*)0x8;
-
//-------------------------------------------------------------------
/*! add class/namespace name s to the scope */
@@ -2445,6 +2285,7 @@ static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
if (Doxygen::searchIndex)
{
+ std::lock_guard<std::mutex> lock(g_searchIndexMutex);
if (yyextra->searchCtx)
{
yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
@@ -2461,6 +2302,7 @@ static void addToSearchIndex(yyscan_t yyscanner,const char *text)
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
if (Doxygen::searchIndex)
{
+ std::lock_guard<std::mutex> lock(g_searchIndexMutex);
yyextra->code->addWord(text,FALSE);
}
}
@@ -2621,7 +2463,10 @@ static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
- TooltipManager::instance()->addTooltip(d);
+ {
+ std::lock_guard<std::mutex> lock(g_tooltipMutex);
+ TooltipManager::instance()->addTooltip(d);
+ }
QCString ref = d->getReference();
QCString file = d->getOutputFileBase();
QCString anchor = d->anchor();
@@ -2702,7 +2547,7 @@ static void setParameterList(yyscan_t yyscanner,const MemberDef *md)
if (i!=-1) yyextra->parmType = yyextra->parmType.left(i);
yyextra->parmType.stripPrefix("const ");
yyextra->parmType=yyextra->parmType.stripWhiteSpace();
- yyextra->theVarContext.addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
+ addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
}
}
@@ -2735,7 +2580,7 @@ static const ClassDef *stripClassName(yyscan_t yyscanner,const char *s,const Def
return 0;
}
-static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
+static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
{
if (name.isEmpty()) return 0;
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
@@ -2754,7 +2599,7 @@ static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
if (md)
{
//printf("name=%s scope=%s\n",locName.data(),scope.data());
- yyextra->theCallContext.setScope(stripClassName(yyscanner,md->typeString(),md->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
return md;
}
}
@@ -2767,7 +2612,7 @@ static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
if (md)
{
//printf("name=%s scope=%s\n",locName.data(),scope.data());
- yyextra->theCallContext.setScope(stripClassName(yyscanner,md->typeString(),md->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
return md;
}
}
@@ -2775,32 +2620,32 @@ static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
}
const MemberName *mn;
- const ClassDef *mcd = yyextra->theVarContext.findVariable(name);
- if (mcd) // local variable
+ const ScopedTypeVariant *mcv = yyextra->theVarContext.findVariable(name);
+ if (mcv)
{
DBG_CTX((stderr,"local variable?\n"));
- if (mcd!=VariableContext::dummyContext)
+ if (mcv->type()!=ScopedTypeVariant::Dummy) // locally found variable
{
- DBG_CTX((stderr,"local var '%s' mcd=%s\n",name.data(),mcd->name().data()));
- yyextra->theCallContext.setScope(mcd);
+ DBG_CTX((stderr,"local var '%s' mcd=%s\n",name.data(),mcv.name().data()));
+ yyextra->theCallContext.setScope(*mcv);
}
}
else
{
DBG_CTX((stderr,"class member? scope=%s\n",yyextra->classScope.data()));
// look for a class member
- mcd = getClass(yyextra->classScope);
+ const ClassDef *mcd = getClass(yyextra->classScope);
if (mcd)
{
DBG_CTX((stderr,"Inside class %s\n",mcd->name().data()));
- MemberDef *md=mcd->getMemberByName(name);
+ const MemberDef *md=mcd->getMemberByName(name);
if (md)
{
DBG_CTX((stderr,"Found member %s\n",md->name().data()));
if (yyextra->scopeStack.empty() || yyextra->scopeStack.top()!=CLASSBLOCK)
{
DBG_CTX((stderr,"class member '%s' mcd=%s\n",name.data(),mcd->name().data()));
- yyextra->theCallContext.setScope(stripClassName(yyscanner,md->typeString(),md->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
}
return md;
}
@@ -2816,7 +2661,7 @@ static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
const std::unique_ptr<MemberDef> &md=mn->front();
if (!md->isStatic() || md->getBodyDef()==yyextra->sourceFileDef)
{
- yyextra->theCallContext.setScope(stripClassName(yyscanner,md->typeString(),md->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
return md.get();
}
return 0;
@@ -2836,7 +2681,7 @@ static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
(yyextra->forceTagReference.isEmpty() || yyextra->forceTagReference==md->getReference())
)
{
- yyextra->theCallContext.setScope(stripClassName(yyscanner,md->typeString(),md->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
//printf("returning member %s in source file %s\n",md->name().data(),yyextra->sourceFileDef->name().data());
return md.get();
}
@@ -2850,7 +2695,7 @@ static MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
static void updateCallContextForSmartPointer(yyscan_t yyscanner)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
- const Definition *d = yyextra->theCallContext.getScope();
+ const Definition *d = yyextra->theCallContext.getScope().globalDef();
//printf("updateCallContextForSmartPointer() cd=%s\n",cd ? d->name().data() : "<none>");
const MemberDef *md;
if (d && d->definitionType()==Definition::TypeClass && (md=(dynamic_cast<const ClassDef*>(d))->isSmartPointer()))
@@ -2858,7 +2703,7 @@ static void updateCallContextForSmartPointer(yyscan_t yyscanner)
const ClassDef *ncd = stripClassName(yyscanner,md->typeString(),md->getOuterScope());
if (ncd)
{
- yyextra->theCallContext.setScope(ncd);
+ yyextra->theCallContext.setScope(ScopedTypeVariant(ncd));
//printf("Found smart pointer call %s->%s!\n",cd->name().data(),ncd->name().data());
}
}
@@ -2904,7 +2749,7 @@ static bool getLinkInScope(yyscan_t yyscanner,
if (md->resolveAlias()->getGroupDef()) d = md->resolveAlias()->getGroupDef();
if (d && d->isLinkable())
{
- yyextra->theCallContext.setScope(stripClassName(yyscanner,md->typeString(),md->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
//printf("yyextra->currentDefinition=%p yyextra->currentMemberDef=%p yyextra->insideBody=%d\n",
// yyextra->currentDefinition,yyextra->currentMemberDef,yyextra->insideBody);
@@ -2981,12 +2826,13 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
{
className = substitute(className,".","::"); // for PHP namespaces
}
- const ClassDef *cd=0,*lcd=0;
+ const ScopedTypeVariant *lcd=0;
+ const ClassDef *cd=0;
const MemberDef *md=0;
bool isLocal=FALSE;
//printf("generateClassOrGlobalLink(className=%s)\n",className.data());
- if (!yyextra->prefixed_with_this_keyword || (lcd=yyextra->theVarContext.findVariable(className))==0) // not a local variable
+ if (!yyextra->isPrefixedWithThis || (lcd=yyextra->theVarContext.findVariable(className))==0) // not a local variable
{
const Definition *d = yyextra->currentDefinition;
//printf("d=%s yyextra->sourceFileDef=%s\n",d?d->name().data():"<none>",yyextra->sourceFileDef?yyextra->sourceFileDef->name().data():"<none>");
@@ -3006,7 +2852,7 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
const NamespaceDef *nd = getResolvedNamespace(className);
if (nd && nd->isLinkable())
{
- yyextra->theCallContext.setScope(nd);
+ yyextra->theCallContext.setScope(ScopedTypeVariant(nd));
addToSearchIndex(yyscanner,className);
writeMultiLineCodeLink(yyscanner,*yyextra->code,nd,clName);
return;
@@ -3026,10 +2872,10 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
else
{
//printf("local variable!\n");
- if (lcd!=VariableContext::dummyContext)
+ if (lcd->type()!=ScopedTypeVariant::Dummy)
{
//printf("non-dummy context lcd=%s!\n",lcd->name().data());
- yyextra->theCallContext.setScope(lcd);
+ yyextra->theCallContext.setScope(*lcd);
// to following is needed for links to a global variable, but is
// no good for a link to a local variable that is also a global symbol.
@@ -3042,7 +2888,7 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
isLocal=TRUE;
DBG_CTX((stderr,"is a local variable cd=%p!\n",cd));
}
- yyextra->prefixed_with_this_keyword = FALSE; // discard the "this" prefix for the next calls
+ yyextra->isPrefixedWithThis = FALSE; // discard the "this" prefix for the next calls
if (cd && cd->isLinkable()) // is it a linkable class
{
@@ -3061,7 +2907,7 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
}
writeMultiLineCodeLink(yyscanner,ol,cd,clName);
addToSearchIndex(yyscanner,className);
- yyextra->theCallContext.setScope(cd);
+ yyextra->theCallContext.setScope(ScopedTypeVariant(cd));
if (md)
{
const Definition *d = md->getOuterScope()==Doxygen::globalScope ?
@@ -3165,7 +3011,7 @@ static bool generateClassMemberLink(yyscan_t yyscanner,
const ClassDef *typeClass = stripClassName(yyscanner,removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope());
DBG_CTX((stderr,"%s -> typeName=%p\n",xmd->typeString(),typeClass));
- yyextra->theCallContext.setScope(typeClass);
+ yyextra->theCallContext.setScope(ScopedTypeVariant(typeClass));
const Definition *xd = xmd->getOuterScope()==Doxygen::globalScope ?
xmd->getFileDef() : xmd->getOuterScope();
@@ -3216,7 +3062,7 @@ static bool generateClassMemberLink(yyscan_t yyscanner,
const Definition *innerDef = cd->findInnerCompound(memName);
if (innerDef)
{
- yyextra->theCallContext.setScope(innerDef);
+ yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
addToSearchIndex(yyscanner,memName);
writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
return TRUE;
@@ -3230,7 +3076,7 @@ static bool generateClassMemberLink(yyscan_t yyscanner,
const Definition *innerDef = nd->findInnerCompound(memName);
if (innerDef)
{
- yyextra->theCallContext.setScope(innerDef);
+ yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
addToSearchIndex(yyscanner,memName);
writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
return TRUE;
@@ -3251,23 +3097,22 @@ static void generateMemberLink(yyscan_t yyscanner,
if (varName.isEmpty()) return;
// look for the variable in the current context
- const ClassDef *vcd = yyextra->theVarContext.findVariable(varName);
- if (vcd)
+ const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(varName);
+ if (stv)
{
- if (vcd!=VariableContext::dummyContext)
+ if (stv->type()!=ScopedTypeVariant::Dummy)
{
//printf("Class found!\n");
- if (getLink(yyscanner,vcd->name(),memName,ol))
+ if (getLink(yyscanner,stv->name(),memName,ol))
{
//printf("Found result!\n");
return;
}
- if (vcd->baseClasses())
+ if (stv->localDef() && !stv->localDef()->baseClasses().empty())
{
- BaseClassListIterator bcli(*vcd->baseClasses());
- for ( ; bcli.current() ; ++bcli)
+ for (const auto &bcName : stv->localDef()->baseClasses())
{
- if (getLink(yyscanner,bcli.current()->classDef->name(),memName,ol))
+ if (getLink(yyscanner,bcName,memName,ol))
{
//printf("Found result!\n");
return;
@@ -3278,7 +3123,7 @@ static void generateMemberLink(yyscan_t yyscanner,
}
else // variable not in current context, maybe it is in a parent context
{
- vcd = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,yyextra->classScope);
+ const ClassDef *vcd = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,yyextra->classScope);
if (vcd && vcd->isLinkable())
{
//printf("Found class %s for variable '%s'\n",yyextra->classScope.data(),varName.data());
@@ -3350,7 +3195,6 @@ static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,cons
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
//CodeClassDef *ccd=0;
- const ClassDef *ccd=0;
QCString locScope=yyextra->classScope;
QCString locFunc=removeRedundantWhiteSpace(funcName);
if (yyextra->lang==SrcLangExt_PHP && locFunc.startsWith("self::")) locFunc=locFunc.mid(4);
@@ -3416,37 +3260,31 @@ static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,cons
auto it = yyextra->codeClassMap.find(fullScope.str());
if (it!=yyextra->codeClassMap.end())
{
- ccd = it->second.get();
- }
- if (ccd && ccd->baseClasses())
- {
- BaseClassListIterator bcli(*ccd->baseClasses());
- for ( ; bcli.current() ; ++bcli)
+ ScopedTypeVariant ccd = it->second;
+ if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
{
- if (getLink(yyscanner,bcli.current()->classDef->name(),locFunc,ol,funcName))
+ for (const auto &bcName : ccd.localDef()->baseClasses())
{
- goto exit;
+ if (getLink(yyscanner,bcName,locFunc,ol,funcName))
+ {
+ goto exit;
+ }
}
}
}
}
- if (!locScope.isEmpty())
+ if (!locScope.isEmpty() && fullScope!=locScope)
{
auto it = yyextra->codeClassMap.find(locScope.str());
if (it!=yyextra->codeClassMap.end())
{
- ccd = it->second.get();
- }
- if (fullScope!=locScope && ccd)
- {
- //printf("using classScope %s\n",yyextra->classScope.data());
- if (ccd->baseClasses())
+ ScopedTypeVariant ccd = it->second;
+ if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
{
- BaseClassListIterator bcli(*ccd->baseClasses());
- for ( ; bcli.current() ; ++bcli)
+ for (const auto &bcName : ccd.localDef()->baseClasses())
{
- if (getLink(yyscanner,bcli.current()->classDef->name(),funcWithScope,ol,funcName))
+ if (getLink(yyscanner,bcName,funcWithScope,ol,funcName))
{
goto exit;
}
@@ -3519,8 +3357,8 @@ static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx)
{
//printf("Looking for object=%s method=%s\n",ctx->objectTypeOrName.data(),
// ctx->methodName.data());
- const ClassDef *cd = yyextra->theVarContext.findVariable(ctx->objectTypeOrName);
- if (cd==0) // not a local variable
+ const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(ctx->objectTypeOrName);
+ if (stv==0) // not a local variable
{
if (ctx->objectTypeOrName=="self")
{
@@ -3569,9 +3407,13 @@ static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx)
else // local variable
{
//printf(" object is local variable\n");
- if (cd!=VariableContext::dummyContext && !ctx->methodName.isEmpty())
+ if (stv->globalDef() && !ctx->methodName.isEmpty())
{
- ctx->method = cd->getMemberByName(ctx->methodName);
+ const ClassDef *cd = dynamic_cast<const ClassDef *>(stv->globalDef());
+ if (cd)
+ {
+ ctx->method = cd->getMemberByName(ctx->methodName);
+ }
//printf(" class=%p method=%p\n",cd,ctx->method);
}
}
@@ -3690,7 +3532,6 @@ static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx)
}
}
else if (ctx->objectType &&
- ctx->objectType!=VariableContext::dummyContext &&
ctx->objectType->isLinkable()
) // object is class name
{
diff --git a/src/pycode.l b/src/pycode.l
index 68ec265..ea314da 100644
--- a/src/pycode.l
+++ b/src/pycode.l
@@ -52,6 +52,7 @@
#include "filedef.h"
#include "namespacedef.h"
#include "tooltip.h"
+#include "scopedtypevariant.h"
// Toggle for some debugging info
//#define DBG_CTX(x) fprintf x
@@ -62,103 +63,10 @@
#define USE_STATE2STRING 0
-/*! Represents a stack of variable to class mappings as found in the
- * code. Each scope is enclosed in pushScope() and popScope() calls.
- * Variables are added by calling addVariables() and one can search
- * for variable using findVariable().
- */
-class PyVariableContext
-{
- public:
- static const ClassDef *dummyContext;
-
- using Scope = std::unordered_map<std::string,const ClassDef *>;
-
- void pushScope()
- {
- m_scopes.push_back(Scope());
- }
-
- void popScope()
- {
- if (!m_scopes.empty())
- {
- m_scopes.pop_back();
- }
- }
-
- void clear()
- {
- m_scopes.clear();
- m_globalScope.clear();
- }
-
- void clearExceptGlobal()
- {
- m_scopes.clear();
- }
-
- void addVariable(yyscan_t yyscanner, const QCString &type,const QCString &name);
- const ClassDef *findVariable(const QCString &name);
-
- private:
- Scope m_globalScope;
- std::vector<Scope> m_scopes;
-};
-
-class PyCallContext
-{
- public:
- struct Ctx
- {
- Ctx(QCString name_,QCString type_) : name(name_), type(type_) {}
- QCString name;
- QCString type;
- const ClassDef *cd = 0;
- };
-
- PyCallContext()
- {
- clear();
- }
-
- void setClass(const ClassDef *cd)
- {
- Ctx &ctx = m_classList.back();
- ctx.cd=cd;
- }
- void pushScope(const QCString &name_,const QCString type_)
- {
- m_classList.push_back(Ctx(name_,type_));
- }
- void popScope(QCString &name_,QCString &type_)
- {
- if (m_classList.size()>1)
- {
- const Ctx &ctx = m_classList.back();
- name_ = ctx.name;
- type_ = ctx.type;
- m_classList.pop_back();
- }
- }
- void clear()
- {
- m_classList.clear();
- m_classList.push_back(Ctx("",""));
- }
- const ClassDef *getClass() const
- {
- return m_classList.back().cd;
- }
-
- private:
- std::vector<Ctx> m_classList;
-};
-
struct pycodeYY_state
{
- std::unordered_map< std::string, std::unique_ptr<ClassDef> > codeClassMap;
+ std::unordered_map< std::string, ScopedTypeVariant > codeClassMap;
QCString curClassName;
QStrList curClassBases;
@@ -196,8 +104,8 @@ struct pycodeYY_state
QCString docBlock; //!< contents of all lines of a documentation block
bool endComment = FALSE;
- PyVariableContext theVarContext;
- PyCallContext theCallContext;
+ VariableContext theVarContext;
+ CallContext theCallContext;
};
@@ -205,9 +113,6 @@ struct pycodeYY_state
static const char *stateToString(int state);
#endif
-const ClassDef *PyVariableContext::dummyContext = (ClassDef*)0x8;
-
-
static void startCodeLine(yyscan_t yyscanner);
static int countLines(yyscan_t yyscanner);
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor);
@@ -235,6 +140,16 @@ static void findMemberLink(yyscan_t yyscanner, CodeOutputInterface &ol,
static void adjustScopesAndSuites(yyscan_t yyscanner,unsigned indentLength);
static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
+#if 0 // TODO: call me to store local variables and get better syntax highlighting, see code.l
+static void addVariable(yyscan_t yyscanner, QCString type, QCString name);
+#endif
+
+//-------------------------------------------------------------------
+
+static std::mutex g_searchIndexMutex;
+static std::mutex g_tooltipMutex;
+
+//-------------------------------------------------------------------
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
@@ -471,6 +386,7 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBU
// Push a class scope
std::unique_ptr<ClassDef> classDefToAdd { createClassDef("<code>",1,1,yyextra->curClassName,ClassDef::Class,0,0,FALSE) };
+ ScopedTypeVariant var(yyextra->curClassName);
char *s=yyextra->curClassBases.first();
while (s)
{
@@ -479,7 +395,7 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBU
auto it = yyextra->codeClassMap.find(s);
if (it != yyextra->codeClassMap.end())
{
- baseDefToAdd = it->second.get();
+ baseDefToAdd = dynamic_cast<const ClassDef*>(it->second.globalDef());
}
// Try to find class in global scope
if (baseDefToAdd==0)
@@ -487,14 +403,14 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBU
baseDefToAdd=getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,s);
}
- if (baseDefToAdd && baseDefToAdd!=classDefToAdd.get())
+ if (baseDefToAdd && baseDefToAdd->name()!=yyextra->curClassName)
{
- classDefToAdd->insertBaseClass(const_cast<ClassDef*>(baseDefToAdd),s,Public,Normal);
+ var.localDef()->insertBaseClass(baseDefToAdd->name());
}
s=yyextra->curClassBases.next();
}
- yyextra->codeClassMap.emplace(std::make_pair(yyextra->curClassName.str(),std::move(classDefToAdd)));
+ yyextra->codeClassMap.emplace(std::make_pair(yyextra->curClassName.str(),std::move(var)));
// Reset class-parsing variables.
yyextra->curClassName.resize(0);
@@ -892,63 +808,36 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBU
/*@ ----------------------------------------------------------------------------
*/
-void PyVariableContext::addVariable(yyscan_t yyscanner, const QCString &type,const QCString &name)
+#if 0 // TODO: call me to store local variables and get better syntax highlighting, see code.l
+static void addVariable(yyscan_t yyscanner, QCString type, QCString name)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
//printf("PyVariableContext::addVariable(%s,%s)\n",type.data(),name.data());
QCString ltype = type.simplifyWhiteSpace();
QCString lname = name.simplifyWhiteSpace();
- Scope *scope = m_scopes.empty() ? &m_globalScope : &m_scopes.back();
- const ClassDef *varType = 0;
auto it = yyextra->codeClassMap.find(ltype.str());
if (it!=yyextra->codeClassMap.end())
{
- varType = it->second.get();
- }
- if (varType==0)
- {
- varType = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,ltype); // look for global class definitions
- }
- if (varType)
- {
- scope->emplace(std::make_pair(lname.str(),varType)); // add it to a list
+ yyextra->theVarContext.addVariable(lname,std::move(it->second));
}
else
{
- if (!m_scopes.empty()) // for local variable add a dummy entry to avoid linking to a global that is
- // shadowed.
+ const ClassDef *varType = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,ltype); // look for global class definitions
+ if (varType)
{
- scope->emplace(std::make_pair(lname.str(),dummyContext));
+ yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varType));
}
- }
-}
-
-const ClassDef *PyVariableContext::findVariable(const QCString &name)
-{
- if (name.isEmpty()) return 0;
- const ClassDef *result = 0;
-
- // search from inner to outer scope
- auto it = std::rbegin(m_scopes);
- while (it != std::rend(m_scopes))
- {
- auto it2 = it->find(name.str());
- if (it2 != std::end(*it))
+ else
{
- result = it2->second;
- return result;
+ if (!yyextra->theVarContext.atGlobalScope()) // for local variable add a dummy entry to avoid linking to a global that is shadowed.
+ {
+ yyextra->theVarContext.addVariable(lname.str(),ScopedTypeVariant());
+ }
}
- ++it;
- }
- // nothing found -> also try the global scope
- auto it2 = m_globalScope.find(name.str());
- if (it2 != m_globalScope.end())
- {
- result = it2->second;
}
- return result;
}
+#endif
//-------------------------------------------------------------------------------
@@ -1031,6 +920,7 @@ static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
if (Doxygen::searchIndex)
{
+ std::lock_guard<std::mutex> lock(g_searchIndexMutex);
if (yyextra->searchCtx)
{
yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
@@ -1049,6 +939,7 @@ static void addToSearchIndex(yyscan_t yyscanner, const char *text)
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
if (Doxygen::searchIndex)
{
+ std::lock_guard<std::mutex> lock(g_searchIndexMutex);
yyextra->code->addWord(text,FALSE);
}
}
@@ -1189,7 +1080,10 @@ static void writeMultiLineCodeLink(yyscan_t yyscanner,
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
- TooltipManager::instance()->addTooltip(d);
+ {
+ std::lock_guard<std::mutex> lock(g_tooltipMutex);
+ TooltipManager::instance()->addTooltip(d);
+ }
QCString ref = d->getReference();
QCString file = d->getOutputFileBase();
QCString anchor = d->anchor();
@@ -1310,7 +1204,7 @@ static bool getLinkInScope(yyscan_t yyscanner,
if (md->getGroupDef()) d = md->getGroupDef();
if (d && d->isLinkable())
{
- yyextra->theCallContext.setClass(stripClassName(yyscanner,md->typeString(),md->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
//printf("yyextra->currentDefinition=%p yyextra->currentMemberDef=%p\n",
// yyextra->currentDefinition,yyextra->currentMemberDef);
@@ -1372,8 +1266,9 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
DBG_CTX((stderr,"generateClassOrGlobalLink(className=%s)\n",className.data()));
- const ClassDef *cd=0,*lcd=0; /** Class def that we may find */
- const MemberDef *md=0; /** Member def that we may find */
+ const ScopedTypeVariant *lcd = 0;
+ const ClassDef *cd=0; // Class def that we may find
+ const MemberDef *md=0; // Member def that we may find
//bool isLocal=FALSE;
if ((lcd=yyextra->theVarContext.findVariable(className))==0) // not a local variable
@@ -1405,9 +1300,9 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
}
else
{
- if (lcd!=PyVariableContext::dummyContext)
+ if (lcd->type()!=ScopedTypeVariant::Dummy)
{
- yyextra->theCallContext.setClass(lcd);
+ yyextra->theCallContext.setScope(*lcd);
}
//isLocal=TRUE;
DBG_CTX((stderr,"is a local variable cd=%p!\n",cd));
@@ -1443,7 +1338,7 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
MemberDef *mmd = mcd->getMemberByName(locName);
if (mmd)
{
- yyextra->theCallContext.setClass(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope())));
writeMultiLineCodeLink(yyscanner,ol,mmd,clName);
addToSearchIndex(yyscanner,className);
const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ?
@@ -1466,7 +1361,7 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
if (mmd)
{
//printf("name=%s scope=%s\n",locName.data(),scope.data());
- yyextra->theCallContext.setClass(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope()));
+ yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope())));
writeMultiLineCodeLink(yyscanner,ol,mmd,clName);
addToSearchIndex(yyscanner,className);
const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ?
@@ -1503,8 +1398,7 @@ static void generateFunctionLink(yyscan_t yyscanner,
const char *funcName)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
- const ClassDef *ccd=0;
- QCString locScope=yyextra->classScope.copy();
+ QCString locScope=yyextra->classScope;
QCString locFunc=removeRedundantWhiteSpace(funcName);
DBG_CTX((stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data()));
int i=locFunc.findRev("::");
@@ -1519,17 +1413,16 @@ static void generateFunctionLink(yyscan_t yyscanner,
auto it = yyextra->codeClassMap.find(locScope.str());
if (it!=yyextra->codeClassMap.end())
{
- ccd = it->second.get();
- }
- //printf("using classScope %s\n",yyextra->classScope.data());
- if (ccd && ccd->baseClasses())
- {
- BaseClassListIterator bcli(*ccd->baseClasses());
- for ( ; bcli.current() ; ++bcli)
+ ScopedTypeVariant ccd = it->second;
+ //printf("using classScope %s\n",yyextra->classScope.data());
+ if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
{
- if (getLink(yyscanner,bcli.current()->classDef->name(),locFunc,ol,funcName))
+ for (const auto &bcName : ccd.localDef()->baseClasses())
{
- return;
+ if (getLink(yyscanner,bcName,locFunc,ol,funcName))
+ {
+ return;
+ }
}
}
}
diff --git a/src/scopedtypevariant.h b/src/scopedtypevariant.h
new file mode 100644
index 0000000..5f7a358
--- /dev/null
+++ b/src/scopedtypevariant.h
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1997-2020 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
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#ifndef SCOPEDTYPEVARIANT_H
+#define SCOPEDTYPEVARIANT_H
+
+#include <utility>
+#include <vector>
+#include <qcstring.h>
+#include "definition.h"
+
+//! Class representing a local class definition found while
+//! generating syntax highlighted code.
+class LocalDef
+{
+ public:
+ void insertBaseClass(QCString name) { m_baseClasses.push_back(name); }
+ std::vector<QCString> baseClasses() const { return m_baseClasses; }
+ private:
+ std::vector<QCString> m_baseClasses;
+};
+
+//-----------------------------------------------------------------------------
+
+/*! Variant class for a scoped type.
+ *
+ * Variants:
+ * - Dummy: a type used for hiding a global type.
+ * - Local: a locally defined type (e.g. found inside a function)
+ * - Global: a globally defined type (processed by doxygen in an earlier pass).
+ */
+class ScopedTypeVariant
+{
+ public:
+ //! possible variant types
+ enum Variant
+ {
+ Global,
+ Local,
+ Dummy
+ };
+ //! default constructor for creating a variant of type Dummy
+ ScopedTypeVariant() : m_variant(Dummy)
+ {
+ m_u.globalDef = 0;
+ }
+ //! constructor for creating a variant of type Global
+ explicit ScopedTypeVariant(const Definition *d)
+ {
+ if (d)
+ {
+ m_name = d->name();
+ m_variant = Global;
+ m_u.globalDef = d;
+ }
+ else
+ {
+ m_variant = Dummy;
+ m_u.globalDef = 0;
+ }
+ }
+ //! constructor for creating a variant of type Local
+ explicit ScopedTypeVariant(QCString name)
+ {
+ m_name = name;
+ m_variant = Local;
+ m_u.localDef = new LocalDef;
+ }
+ //! copy contructor
+ ScopedTypeVariant(const ScopedTypeVariant &stv)
+ {
+ m_variant = stv.m_variant;
+ m_name = stv.m_name;
+ if (m_variant==Local)
+ {
+ m_u.localDef = new LocalDef(*stv.m_u.localDef);
+ }
+ else if (m_variant==Global)
+ {
+ m_u.globalDef = stv.m_u.globalDef;
+ }
+ }
+ //! move constructor
+ ScopedTypeVariant(ScopedTypeVariant && stv) noexcept : ScopedTypeVariant()
+ {
+ swap(*this,stv);
+ }
+ //! assignment operator
+ ScopedTypeVariant &operator=(ScopedTypeVariant stv)
+ {
+ swap(*this,stv);
+ return *this;
+ }
+ //! destructor
+ ~ScopedTypeVariant()
+ {
+ if (m_variant==Local)
+ {
+ delete m_u.localDef;
+ }
+ }
+ //! swap function
+ friend void swap(ScopedTypeVariant &first,ScopedTypeVariant &second)
+ {
+ using std::swap; // enable ADL
+ swap(first.m_variant,second.m_variant);
+ swap(first.m_name,second.m_name);
+ swap(first.m_u.globalDef,second.m_u.globalDef);
+ }
+ //! Turn the variant into a Global type
+ void setGlobal(const Definition *def)
+ {
+ if (m_variant==Local)
+ {
+ delete m_u.localDef;
+ }
+ m_variant = Global;
+ m_name = def->name();
+ m_u.globalDef = def;
+ }
+ //! Turn the variant into a Local type
+ LocalDef *setLocal(QCString name)
+ {
+ if (m_variant==Local)
+ {
+ delete m_u.localDef;
+ }
+ m_variant = Local;
+ m_name = name;
+ m_u.localDef = new LocalDef;
+ return m_u.localDef;
+ }
+ //! Turn the variant into a Dummy type
+ void setDummy()
+ {
+ if (m_variant==Local)
+ {
+ delete m_u.localDef;
+ }
+ m_variant = Dummy;
+ m_name = "";
+ m_u.localDef=0;
+ }
+ Variant type() const { return m_variant; }
+ QCString name() const { return m_name; }
+ LocalDef *localDef() const { return m_variant==Local ? m_u.localDef : 0; }
+ const Definition *globalDef() const { return m_variant==Global ? m_u.globalDef : 0; }
+
+ private:
+ Variant m_variant;
+ QCString m_name;
+ union
+ {
+ const Definition *globalDef;
+ LocalDef *localDef;
+ } m_u;
+};
+
+//-----------------------------------------------------------------------------
+
+/*! Represents a stack of variable to class mappings as found in the
+ * code. Each scope is enclosed in pushScope() and popScope() calls.
+ * Variables are added by calling addVariables() and one can search
+ * for variable using findVariable().
+ */
+class VariableContext
+{
+ public:
+ using Scope = std::unordered_map<std::string,ScopedTypeVariant>;
+
+ void pushScope()
+ {
+ m_scopes.push_back(Scope());
+ }
+ void popScope()
+ {
+ if (!m_scopes.empty())
+ {
+ m_scopes.pop_back();
+ }
+ }
+ void clear()
+ {
+ m_scopes.clear();
+ m_globalScope.clear();
+ }
+ void clearExceptGlobal()
+ {
+ m_scopes.clear();
+ }
+ void addVariable(QCString name,ScopedTypeVariant stv)
+ {
+ Scope *scope = m_scopes.empty() ? &m_globalScope : &m_scopes.back();
+ scope->emplace(std::make_pair(name.str(),std::move(stv))); // add it to a list
+ }
+ const ScopedTypeVariant *findVariable(QCString name)
+ {
+ const ScopedTypeVariant *result = 0;
+ if (name.isEmpty()) return result;
+
+ // search from inner to outer scope
+ auto it = std::rbegin(m_scopes);
+ while (it != std::rend(m_scopes))
+ {
+ auto it2 = it->find(name.str());
+ if (it2 != std::end(*it))
+ {
+ result = &it2->second;
+ return result;
+ }
+ ++it;
+ }
+ // nothing found -> also try the global scope
+ auto it2 = m_globalScope.find(name.str());
+ if (it2 != m_globalScope.end())
+ {
+ result = &it2->second;
+ }
+ return result;
+ }
+ bool atGlobalScope() const { return m_scopes.empty(); }
+
+ private:
+ Scope m_globalScope;
+ std::vector<Scope> m_scopes;
+};
+
+//-----------------------------------------------------------------------------
+
+/** Represents the call context */
+class CallContext
+{
+ public:
+ struct Ctx
+ {
+ Ctx(QCString name_,QCString type_) : name(name_), type(type_) {}
+ QCString name;
+ QCString type;
+ ScopedTypeVariant stv;
+ };
+
+ CallContext()
+ {
+ clear();
+ }
+ void setScope(ScopedTypeVariant stv)
+ {
+ Ctx &ctx = m_stvList.back();
+ ctx.stv=std::move(stv);
+ }
+ void pushScope(const QCString &name_,const QCString type_)
+ {
+ m_stvList.push_back(Ctx(name_,type_));
+ }
+ void popScope(QCString &name_,QCString &type_)
+ {
+ if (m_stvList.size()>1)
+ {
+ const Ctx &ctx = m_stvList.back();
+ name_ = ctx.name;
+ type_ = ctx.type;
+ m_stvList.pop_back();
+ }
+ }
+ void clear()
+ {
+ m_stvList.clear();
+ m_stvList.push_back(Ctx("",""));
+ }
+ const ScopedTypeVariant getScope() const
+ {
+ return m_stvList.back().stv;
+ }
+
+ private:
+ std::vector<Ctx> m_stvList;
+};
+
+
+#endif