Skip to content

Commit 4d3c07d

Browse files
committed
issue #9274: Automatic links not working in examples that use C++ source [Potential Bug]
1 parent 648e62c commit 4d3c07d

File tree

1 file changed

+64
-30
lines changed

1 file changed

+64
-30
lines changed

src/code.l

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ struct codeYY_state
179179
std::unordered_map< int, QCString> commentMap;
180180
int braceCount=0;
181181

182+
using UsingContext = std::map<std::string,const NamespaceDef*>;
183+
182184
VariableContext theVarContext;
185+
UsingContext theUsingContext;
183186
CallContext theCallContext;
184187
SymbolResolver symbolResolver;
185188
TooltipManager tooltipManager;
@@ -258,7 +261,6 @@ static std::mutex g_searchIndexMutex;
258261
static std::mutex g_docCrossReferenceMutex;
259262
static std::mutex g_addExampleMutex;
260263
static std::mutex g_countFlowKeywordsMutex;
261-
static std::mutex g_usingDirectiveMutex;
262264

263265
/* -----------------------------------------------------------------
264266
*/
@@ -932,6 +934,12 @@ ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"seale
932934
endFontClass(yyscanner);
933935
BEGIN(UsingName);
934936
}
937+
<Body>"using"{BN}+ {
938+
startFontClass(yyscanner,"keyword");
939+
codifyLines(yyscanner,yytext);
940+
endFontClass(yyscanner);
941+
BEGIN(UsingName);
942+
}
935943
<ConceptName>{ID}("::"{ID})* {
936944
addUsingDirective(yyscanner,yytext);
937945
generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
@@ -2208,20 +2216,34 @@ static void addVariable(yyscan_t yyscanner,QCString type,QCString name)
22082216
}
22092217
else
22102218
{
2211-
const ClassDef *varDef = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,ltype);
2212-
int i=0;
2213-
if (varDef)
2219+
auto findVariableType = [&yyscanner,&yyg,&ltype,&lname,&name](const Definition *d) -> const ClassDef *
22142220
{
2215-
DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2216-
yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varDef)); // add it to a list
2217-
}
2218-
else if ((i=ltype.find('<'))!=-1)
2221+
const ClassDef *varDef = yyextra->symbolResolver.resolveClass(d,ltype);
2222+
int i=0;
2223+
if (varDef)
2224+
{
2225+
DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2226+
yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varDef)); // add it to a list
2227+
}
2228+
else if ((i=ltype.find('<'))!=-1)
2229+
{
2230+
// probably a template class
2231+
QCString typeName(ltype.left(i));
2232+
addVariable(yyscanner,typeName,name);
2233+
}
2234+
return varDef;
2235+
};
2236+
const ClassDef *varDef = findVariableType(yyextra->currentDefinition);
2237+
if (varDef==0)
22192238
{
2220-
// probably a template class
2221-
QCString typeName(ltype.left(i));
2222-
addVariable(yyscanner,typeName,name);
2239+
// also check via using directive
2240+
for (const auto &kv : yyextra->theUsingContext)
2241+
{
2242+
varDef = findVariableType(kv.second);
2243+
if (varDef!=0) break;
2244+
}
22232245
}
2224-
else
2246+
if (varDef==0)
22252247
{
22262248
if (!yyextra->theVarContext.atGlobalScope()) // for local variables add a dummy entry so the name
22272249
// is hidden to avoid false links to global variables with the same name
@@ -2544,17 +2566,15 @@ static void addParmType(yyscan_t yyscanner)
25442566
yyextra->parmName.resize(0) ;
25452567
}
25462568

2547-
// TODO: make this have a scope only effect, at least not modifying the FileDef object.
25482569
static void addUsingDirective(yyscan_t yyscanner,const char *name)
25492570
{
2550-
std::lock_guard<std::mutex> lock(g_usingDirectiveMutex);
25512571
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
25522572
if (yyextra->sourceFileDef && name)
25532573
{
25542574
const NamespaceDef *nd = Doxygen::namespaceLinkedMap->find(name);
25552575
if (nd)
25562576
{
2557-
const_cast<FileDef*>(yyextra->sourceFileDef)->addUsingDirective(nd);
2577+
yyextra->theUsingContext.insert(std::make_pair(std::string(name),nd));
25582578
}
25592579
}
25602580
}
@@ -2834,7 +2854,6 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
28342854
bool varOnly)
28352855
{
28362856
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2837-
int i=0;
28382857
QCString className=clName;
28392858
if (!className.isEmpty() && className[0]=='~') // correct for matching negated values i.s.o. destructors.
28402859
{
@@ -2865,25 +2884,40 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,
28652884
DBG_CTX((stderr,"generateClassOrGlobalLink(className=%s)\n",qPrint(className)));
28662885
if (!yyextra->isPrefixedWithThis || (lcd=yyextra->theVarContext.findVariable(className))==0) // not a local variable
28672886
{
2868-
const Definition *d = yyextra->currentDefinition;
2869-
DBG_CTX((stderr,"d=%s yyextra->sourceFileDef=%s\n",d?qPrint(d->name()):"<none>",yyextra->sourceFileDef?qPrint(yyextra->sourceFileDef->name()):"<none>"));
2870-
cd = yyextra->symbolResolver.resolveClass(d,className);
2871-
md = yyextra->symbolResolver.getTypedef();
2872-
DBG_CTX((stderr,"non-local variable name=%s cd=%s md=%s!\n",
2873-
qPrint(className),cd?qPrint(cd->name()):"<none>",
2874-
md?qPrint(md->name()):"<none>"));
2875-
i=className.find('<');
2887+
int i=className.find('<');
28762888
QCString bareName = className;
28772889
if (i!=-1) bareName = bareName.left(i);
2878-
if (cd==0 && md==0 && i!=-1)
2890+
2891+
auto checkForClass = [&yyg,&md,&cd,&bareName,&className](const Definition *d)
2892+
{
2893+
cd = yyextra->symbolResolver.resolveClass(d,className);
2894+
md = yyextra->symbolResolver.getTypedef();
2895+
DBG_CTX((stderr,"non-local variable name=%s cd=%s md=%s!\n",
2896+
qPrint(className),cd?qPrint(cd->name()):"<none>",
2897+
md?qPrint(md->name()):"<none>"));
2898+
if (cd==0 && md==0 && !bareName.isEmpty())
2899+
{
2900+
DBG_CTX((stderr,"bareName=%s\n",qPrint(bareName)));
2901+
if (bareName!=className)
2902+
{
2903+
cd = yyextra->symbolResolver.resolveClass(d,bareName); // try unspecialized version
2904+
md = yyextra->symbolResolver.getTypedef();
2905+
}
2906+
}
2907+
};
2908+
const Definition *d = yyextra->currentDefinition;
2909+
DBG_CTX((stderr,"d=%s yyextra->sourceFileDef=%s\n",d?qPrint(d->name()):"<none>",yyextra->sourceFileDef?qPrint(yyextra->sourceFileDef->name()):"<none>"));
2910+
checkForClass(d);
2911+
if (cd==0 && md==0)
28792912
{
2880-
DBG_CTX((stderr,"bareName=%s\n",qPrint(bareName)));
2881-
if (bareName!=className)
2913+
// also check via using directive
2914+
for (const auto &kv : yyextra->theUsingContext)
28822915
{
2883-
cd = yyextra->symbolResolver.resolveClass(d,bareName); // try unspecialized version
2884-
md = yyextra->symbolResolver.getTypedef();
2916+
checkForClass(kv.second);
2917+
if (cd!=0 || md!=0) break;
28852918
}
28862919
}
2920+
28872921
const NamespaceDef *nd = getResolvedNamespace(className);
28882922
if (nd && nd->isLinkable())
28892923
{
@@ -3902,7 +3936,7 @@ void CCodeParser::parseCode(CodeOutputInterface &od,const QCString &className,co
39023936

39033937
if (s.isEmpty()) return;
39043938

3905-
printlex(yy_flex_debug, TRUE, __FILE__, fd ? qPrint(fd->fileName()): NULL);
3939+
printlex(yy_flex_debug, TRUE, __FILE__, fd ? qPrint(fd->fileName()): !exName.isEmpty() ? qPrint(exName) : NULL);
39063940

39073941
yyextra->code = &od;
39083942
yyextra->inputString = s.data();

0 commit comments

Comments
 (0)