diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/code.l | 393 | ||||
-rw-r--r-- | src/pycode.l | 215 | ||||
-rw-r--r-- | src/scopedtypevariant.h | 292 |
3 files changed, 463 insertions, 437 deletions
@@ -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 |