Doxygen
Loading...
Searching...
No Matches
SymbolResolver::Private Struct Reference
Collaboration diagram for SymbolResolver::Private:

Public Member Functions

 Private (const FileDef *f)
void reset ()
void setFileScope (const FileDef *fileScope)
const FileDeffileScope () const
const ClassDefgetResolvedTypeRec (LookupCache &cache, VisitedKeys &visitedKeys, const Definition *scope, const QCString &n, const MemberDef **pTypeDef, QCString *pTemplSpec, QCString *pResolvedType)
const DefinitiongetResolvedSymbolRec (LookupCache &cache, VisitedKeys &visitedKeys, const Definition *scope, const QCString &n, const QCString &args, bool checkCV, bool insideCode, bool onlyLinkable, const MemberDef **pTypeDef, QCString *pTemplSpec, QCString *pResolvedType)
int isAccessibleFrom (VisitedKeys &visitedKeys, AccessStack &accessStack, const Definition *scope, const Definition *item)
int isAccessibleFromWithExpScope (VisitedKeys &visitedKeys, VisitedNamespaces &visitedNamespaces, AccessStack &accessStack, const Definition *scope, const Definition *item, const QCString &explicitScopePart)

Public Attributes

QCString resolvedType
const MemberDeftypeDef = nullptr
QCString templateSpec

Private Member Functions

void getResolvedType (LookupCache &cache, VisitedKeys &visitedKeys, const Definition *scope, const Definition *d, const QCString &explicitScopePart, const ArgumentList *actTemplParams, int &minDistance, const ClassDef *&bestMatch, const MemberDef *&bestTypedef, QCString &bestTemplSpec, QCString &bestResolvedType)
void getResolvedSymbol (VisitedKeys &visitedKeys, const Definition *scope, const Definition *d, const QCString &args, bool checkCV, bool insideCode, const QCString &explicitScopePart, const QCString &strippedTemplateParams, bool forceCallable, int &minDistance, const Definition *&bestMatch, const MemberDef *&bestTypedef, QCString &bestTemplSpec, QCString &bestResolvedType)
const ClassDefnewResolveTypedef (LookupCache &cache, VisitedKeys &visitedKeys, const Definition *scope, const MemberDef *md, const MemberDef **pMemType, QCString *pTemplSpec, QCString *pResolvedType, const ArgumentList *actTemplParams=nullptr)
const DefinitionfollowPath (VisitedKeys &visitedKeys, const Definition *start, const QCString &path)
const DefinitionendOfPathIsUsedClass (const LinkedRefMap< const Definition > &dl, const QCString &localName)
bool accessibleViaUsingNamespace (VisitedKeys &visitedKeys, VisitedNamespaceKeys &visitedNamespaces, const LinkedRefMap< NamespaceDef > &nl, const Definition *item, const QCString &explicitScopePart="", int level=0)
bool accessibleViaUsingDefinition (VisitedKeys &visitedKeys, const LinkedRefMap< const Definition > &dl, const Definition *item, const QCString &explicitScopePart="")
QCString substTypedef (VisitedKeys &visitedKeys, const Definition *scope, const QCString &name, const MemberDef **pTypeDef=nullptr)

Private Attributes

const FileDefm_fileScope
std::unordered_map< std::string, const MemberDef * > m_resolvedTypedefs

Detailed Description

Definition at line 169 of file symbolresolver.cpp.

Constructor & Destructor Documentation

◆ Private()

SymbolResolver::Private::Private ( const FileDef * f)
inline

Definition at line 172 of file symbolresolver.cpp.

172: m_fileScope(f) {}

References m_fileScope.

Member Function Documentation

◆ accessibleViaUsingDefinition()

bool SymbolResolver::Private::accessibleViaUsingDefinition ( VisitedKeys & visitedKeys,
const LinkedRefMap< const Definition > & dl,
const Definition * item,
const QCString & explicitScopePart = "" )
private

Definition at line 1417 of file symbolresolver.cpp.

1421{
1422 AUTO_TRACE("item={} explicitScopePart={}",item?item->name():QCString(), explicitScopePart);
1423 for (const auto &ud : dl)
1424 {
1425 AUTO_TRACE_ADD("trying via used definition '{}'",ud->name());
1426 const Definition *sc = explicitScopePart.isEmpty() ? ud : followPath(visitedKeys,ud,explicitScopePart);
1427 if (sc && sc==item)
1428 {
1429 AUTO_TRACE_EXIT("true");
1430 return true;
1431 }
1432 }
1433 AUTO_TRACE_EXIT("false");
1434 return false;
1435}
virtual const QCString & name() const =0
bool isEmpty() const
Returns true iff the string is empty.
Definition qcstring.h:161
#define AUTO_TRACE_ADD(...)
Definition docnode.cpp:49
#define AUTO_TRACE(...)
Definition docnode.cpp:48
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:50
const Definition * followPath(VisitedKeys &visitedKeys, const Definition *start, const QCString &path)

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, followPath(), QCString::isEmpty(), and Definition::name().

Referenced by isAccessibleFrom().

◆ accessibleViaUsingNamespace()

bool SymbolResolver::Private::accessibleViaUsingNamespace ( VisitedKeys & visitedKeys,
VisitedNamespaceKeys & visitedNamespaces,
const LinkedRefMap< NamespaceDef > & nl,
const Definition * item,
const QCString & explicitScopePart = "",
int level = 0 )
private

Definition at line 1379 of file symbolresolver.cpp.

1386{
1387 AUTO_TRACE("item={} explicitScopePart={} level={}",item?item->name():QCString(), explicitScopePart, level);
1388 for (const auto &und : nl) // check used namespaces for the class
1389 {
1390 AUTO_TRACE_ADD("trying via used namespace '{}'",und->name());
1391 const Definition *sc = explicitScopePart.isEmpty() ? und : followPath(visitedKeys,und,explicitScopePart);
1392 if (sc && item->getOuterScope()==sc)
1393 {
1394 AUTO_TRACE_EXIT("true");
1395 return true;
1396 }
1397 if (item->getLanguage()==SrcLangExt::Cpp)
1398 {
1399 QCString key=und->qualifiedName();
1400 if (!und->getUsedNamespaces().empty() && std::find(visitedNamespaces.begin(),visitedNamespaces.end(),key.str())==std::end(visitedNamespaces))
1401 {
1402 visitedNamespaces.push_back(key.str());
1403 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaces,und->getUsedNamespaces(),item,explicitScopePart,level+1))
1404 {
1405 AUTO_TRACE_EXIT("true");
1406 return true;
1407 }
1408
1409 }
1410 }
1411 }
1412 AUTO_TRACE_EXIT("false");
1413 return false;
1414}
virtual SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
virtual Definition * getOuterScope() const =0
const std::string & str() const
Definition qcstring.h:550
bool accessibleViaUsingNamespace(VisitedKeys &visitedKeys, VisitedNamespaceKeys &visitedNamespaces, const LinkedRefMap< NamespaceDef > &nl, const Definition *item, const QCString &explicitScopePart="", int level=0)

References accessibleViaUsingNamespace(), AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, followPath(), Definition::getLanguage(), Definition::getOuterScope(), QCString::isEmpty(), Definition::name(), and QCString::str().

Referenced by accessibleViaUsingNamespace(), isAccessibleFrom(), and isAccessibleFromWithExpScope().

◆ endOfPathIsUsedClass()

const Definition * SymbolResolver::Private::endOfPathIsUsedClass ( const LinkedRefMap< const Definition > & dl,
const QCString & localName )
private

Definition at line 1367 of file symbolresolver.cpp.

1368{
1369 for (const auto &d : dl)
1370 {
1371 if (d->localName()==localName)
1372 {
1373 return d;
1374 }
1375 }
1376 return nullptr;
1377}

Referenced by followPath().

◆ fileScope()

const FileDef * SymbolResolver::Private::fileScope ( ) const
inline

Definition at line 184 of file symbolresolver.cpp.

184{ return m_fileScope; }

References m_fileScope.

Referenced by setFileScope().

◆ followPath()

const Definition * SymbolResolver::Private::followPath ( VisitedKeys & visitedKeys,
const Definition * start,
const QCString & path )
private

Definition at line 1262 of file symbolresolver.cpp.

1264{
1265 AUTO_TRACE("start={},path={}",start?start->name():QCString(), path);
1266 int is=0,ps=0,l=0;
1267
1268 const Definition *current=start;
1269 // for each part of the explicit scope
1270 while ((is=getScopeFragment(path,ps,&l))!=-1)
1271 {
1272 // try to resolve the part if it is a typedef
1273 const MemberDef *memTypeDef=nullptr;
1274 QCString qualScopePart = substTypedef(visitedKeys,current,path.mid(is,l),&memTypeDef);
1275 AUTO_TRACE_ADD("qualScopePart={} memTypeDef={}",qualScopePart,memTypeDef?memTypeDef->name():"");
1276 const Definition *next = nullptr;
1277 if (memTypeDef)
1278 {
1279 const ClassDef *type = newResolveTypedef(getTypeLookupCache(),visitedKeys,m_fileScope,memTypeDef,nullptr,nullptr,nullptr);
1280 if (type)
1281 {
1282 AUTO_TRACE_EXIT("type={}",type->name());
1283 return type;
1284 }
1285 }
1286 else if (m_fileScope)
1287 {
1288 next = endOfPathIsUsedClass(m_fileScope->getUsedDefinitions(),qualScopePart);
1289 }
1290 if (next==nullptr)
1291 {
1292 next = current->findInnerCompound(qualScopePart);
1293 }
1294 AUTO_TRACE_ADD("Looking for {} inside {} result={}",
1295 qualScopePart, current->name(), next?next->name():QCString());
1296 if (next==nullptr)
1297 {
1298 next = current->findInnerCompound(qualScopePart+"-p");
1299 }
1300 if (current->definitionType()==Definition::TypeClass)
1301 {
1302 const MemberDef *classMember = toClassDef(current)->getMemberByName(qualScopePart);
1303 if (classMember && classMember->isEnumerate())
1304 {
1305 next = classMember;
1306 }
1307 }
1308 else if (current!=Doxygen::globalScope && current->definitionType()==Definition::TypeNamespace)
1309 {
1310 const MemberDef *namespaceMember = toNamespaceDef(current)->getMemberByName(qualScopePart);
1311 if (namespaceMember && namespaceMember->isEnumerate())
1312 {
1313 next = namespaceMember;
1314 }
1315 }
1316 else if (current==Doxygen::globalScope || current->definitionType()==Definition::TypeFile)
1317 {
1318 auto &range = Doxygen::symbolMap->find(qualScopePart);
1319 for (Definition *def : range)
1320 {
1321 const Definition *outerScope = def->getOuterScope();
1322 if (
1323 (outerScope==Doxygen::globalScope || // global scope or
1324 (outerScope && // anonymous namespace in the global scope
1325 outerScope->name().startsWith("anonymous_namespace{") &&
1326 outerScope->getOuterScope()==Doxygen::globalScope
1327 )
1328 ) &&
1329 (def->definitionType()==Definition::TypeClass ||
1330 def->definitionType()==Definition::TypeMember ||
1331 def->definitionType()==Definition::TypeNamespace
1332 )
1333 )
1334 {
1335 next=def;
1336 break;
1337 }
1338 }
1339 }
1340 if (next==nullptr) // failed to follow the path
1341 {
1343 {
1344 next = endOfPathIsUsedClass(
1345 (toNamespaceDef(current))->getUsedDefinitions(),qualScopePart);
1346 }
1347 else if (current->definitionType()==Definition::TypeFile)
1348 {
1349 next = endOfPathIsUsedClass(
1350 (toFileDef(current))->getUsedDefinitions(),qualScopePart);
1351 }
1352 current = next;
1353 if (current==nullptr) break;
1354 }
1355 else // continue to follow scope
1356 {
1357 current = next;
1358 AUTO_TRACE_ADD("current={}",current->name());
1359 }
1360 ps=is+l;
1361 }
1362
1363 AUTO_TRACE_EXIT("result={}",current?current->name():QCString());
1364 return current; // path could be followed
1365}
virtual const MemberDef * getMemberByName(const QCString &) const =0
Returns the member with the given name.
virtual DefType definitionType() const =0
virtual const Definition * findInnerCompound(const QCString &name) const =0
static NamespaceDefMutable * globalScope
Definition doxygen.h:121
static SymbolMap< Definition > * symbolMap
Definition doxygen.h:125
virtual const LinkedRefMap< const Definition > & getUsedDefinitions() const =0
virtual bool isEnumerate() const =0
virtual const MemberDef * getMemberByName(const QCString &) const =0
bool startsWith(const char *s) const
Definition qcstring.h:505
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:239
const VectorPtr & find(const QCString &name)
Definition symbolmap.h:75
ClassDef * toClassDef(Definition *d)
FileDef * toFileDef(Definition *d)
Definition filedef.cpp:1966
NamespaceDef * toNamespaceDef(Definition *d)
const ClassDef * newResolveTypedef(LookupCache &cache, VisitedKeys &visitedKeys, const Definition *scope, const MemberDef *md, const MemberDef **pMemType, QCString *pTemplSpec, QCString *pResolvedType, const ArgumentList *actTemplParams=nullptr)
const Definition * endOfPathIsUsedClass(const LinkedRefMap< const Definition > &dl, const QCString &localName)
QCString substTypedef(VisitedKeys &visitedKeys, const Definition *scope, const QCString &name, const MemberDef **pTypeDef=nullptr)
static LookupCache & getTypeLookupCache()
int getScopeFragment(const QCString &s, int p, int *l)
Definition util.cpp:4682

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, Definition::definitionType(), endOfPathIsUsedClass(), SymbolMap< T >::find(), Definition::findInnerCompound(), ClassDef::getMemberByName(), NamespaceDef::getMemberByName(), Definition::getOuterScope(), getScopeFragment(), getTypeLookupCache(), Doxygen::globalScope, MemberDef::isEnumerate(), m_fileScope, QCString::mid(), Definition::name(), newResolveTypedef(), QCString::startsWith(), substTypedef(), Doxygen::symbolMap, toClassDef(), toFileDef(), toNamespaceDef(), Definition::TypeClass, Definition::TypeFile, Definition::TypeMember, and Definition::TypeNamespace.

Referenced by accessibleViaUsingDefinition(), accessibleViaUsingNamespace(), and isAccessibleFromWithExpScope().

◆ getResolvedSymbol()

void SymbolResolver::Private::getResolvedSymbol ( VisitedKeys & visitedKeys,
const Definition * scope,
const Definition * d,
const QCString & args,
bool checkCV,
bool insideCode,
const QCString & explicitScopePart,
const QCString & strippedTemplateParams,
bool forceCallable,
int & minDistance,
const Definition *& bestMatch,
const MemberDef *& bestTypedef,
QCString & bestTemplSpec,
QCString & bestResolvedType )
private

Definition at line 830 of file symbolresolver.cpp.

846{
847 AUTO_TRACE("scope={} sym={}",scope->name(),d->qualifiedName());
848 // only look at classes and members that are enums or typedefs
849 VisitedNamespaces visitedNamespaces;
850 AccessStack accessStack;
851 // test accessibility of definition within scope.
852 int distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,d,explicitScopePart+strippedTemplateParams);
853 if (distance==-1 && !strippedTemplateParams.isEmpty())
854 {
855 distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,d,explicitScopePart);
856 }
857 AUTO_TRACE_ADD("distance={}",distance);
858 if (distance!=-1) // definition is accessible
859 {
860 // see if we are dealing with a class or a typedef
861 if (args.isEmpty() && !forceCallable && d->definitionType()==Definition::TypeClass) // d is a class
862 {
863 const ClassDef *cd = toClassDef(d);
864 if (!cd->isTemplateArgument()) // skip classes that
865 // are only there to
866 // represent a template
867 // argument
868 {
869 if (distance<minDistance) // found a definition that is "closer"
870 {
871 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",d->name(),distance,minDistance);
872 minDistance=distance;
873 bestMatch = d;
874 bestTypedef = nullptr;
875 bestTemplSpec.clear();
876 bestResolvedType = cd->qualifiedName();
877 }
878 else if (distance==minDistance &&
879 m_fileScope && bestMatch &&
883 )
884 {
885 // in case the distance is equal it could be that a class X
886 // is defined in a namespace and in the global scope. When searched
887 // in the global scope the distance is 0 in both cases. We have
888 // to choose one of the definitions: we choose the one in the
889 // namespace if the fileScope imports namespaces and the definition
890 // found was in a namespace while the best match so far isn't.
891 // Just a non-perfect heuristic but it could help in some situations
892 // (kdecore code is an example).
893 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",d->name(),distance,minDistance);
894 minDistance=distance;
895 bestMatch = d;
896 bestTypedef = nullptr;
897 bestTemplSpec.clear();
898 bestResolvedType = cd->qualifiedName();
899 }
900 }
901 else
902 {
903 AUTO_TRACE_ADD("class with template arguments");
904 }
905 }
907 {
908 const MemberDef *md = toMemberDef(d);
909
910 bool match = true;
911 AUTO_TRACE_ADD("member={} args={} isCallable()={}",md->name(),argListToString(md->argumentList()),md->isCallable());
912 if (md->isCallable() && !args.isEmpty())
913 {
914 QCString actArgs;
915 if (md->isArtificial() && md->formalTemplateArguments()) // for members of an instantiated template we need to replace
916 // the formal arguments by the actual ones before matching
917 // See issue #10640
918 {
920 }
921 else
922 {
923 actArgs = args;
924 }
925 std::unique_ptr<ArgumentList> argList = stringToArgumentList(md->getLanguage(),actArgs);
926 const ArgumentList &mdAl = md->argumentList();
927 match = matchArguments2(md->getOuterScope(),md->getFileDef(),md->typeString(),&mdAl,
928 scope, md->getFileDef(),md->typeString(),argList.get(),
929 checkCV,md->getLanguage());
930 AUTO_TRACE_ADD("match={}",match);
931 }
932
933 if (match && distance<minDistance)
934 {
935 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",md->name(),distance,minDistance);
936 minDistance=distance;
937 bestMatch = md;
938 bestTypedef = md;
939 bestTemplSpec = "";
940 bestResolvedType = md->qualifiedName();
941 }
942 }
946 {
947 if (distance<minDistance) // found a definition that is "closer"
948 {
949 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",d->name(),distance,minDistance);
950 minDistance=distance;
951 bestMatch = d;
952 bestTypedef = nullptr;
953 bestTemplSpec.clear();
954 bestResolvedType.clear();
955 }
956 }
957 } // if definition accessible
958 else
959 {
960 AUTO_TRACE_ADD("not accessible");
961 }
962 AUTO_TRACE_EXIT("bestMatch sym={} distance={}",
963 bestMatch?bestMatch->name():QCString("<none>"),bestResolvedType);
964}
virtual bool isTemplateArgument() const =0
virtual QCString qualifiedName() const =0
virtual bool isArtificial() const =0
virtual const LinkedRefMap< NamespaceDef > & getUsedNamespaces() const =0
bool empty() const
Definition linkedmap.h:374
virtual QCString typeString() const =0
virtual const FileDef * getFileDef() const =0
virtual const ArgumentList & argumentList() const =0
virtual std::optional< ArgumentList > formalTemplateArguments() const =0
virtual bool isCallable() const =0
void clear()
Definition qcstring.h:180
std::unique_ptr< ArgumentList > stringToArgumentList(SrcLangExt lang, const QCString &argsString, QCString *extraTypeChars=nullptr)
Definition defargs.l:826
MemberDef * toMemberDef(Definition *d)
bool match(std::string_view str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition regex.cpp:858
int isAccessibleFromWithExpScope(VisitedKeys &visitedKeys, VisitedNamespaces &visitedNamespaces, AccessStack &accessStack, const Definition *scope, const Definition *item, const QCString &explicitScopePart)
std::unordered_map< std::string, const Definition * > VisitedNamespaces
bool matchArguments2(const Definition *srcScope, const FileDef *srcFileScope, const QCString &srcReturnType, const ArgumentList *srcAl, const Definition *dstScope, const FileDef *dstFileScope, const QCString &dstReturnType, const ArgumentList *dstAl, bool checkCV, SrcLangExt lang)
Definition util.cpp:2031
QCString substituteTemplateArgumentsInString(const QCString &nm, const ArgumentList &formalArgs, const ArgumentList *actualArgs)
Definition util.cpp:4408
QCString argListToString(const ArgumentList &al, bool useCanonicalType, bool showDefVals)
Definition util.cpp:1254

References argListToString(), MemberDef::argumentList(), AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, QCString::clear(), Definition::definitionType(), MemberDef::formalTemplateArguments(), MemberDef::getFileDef(), Definition::getLanguage(), Definition::getOuterScope(), Doxygen::globalScope, SymbolResolver::isAccessibleFromWithExpScope(), Definition::isArtificial(), MemberDef::isCallable(), QCString::isEmpty(), ClassDef::isTemplateArgument(), m_fileScope, matchArguments2(), Definition::name(), Definition::qualifiedName(), stringToArgumentList(), substituteTemplateArgumentsInString(), toClassDef(), toMemberDef(), Definition::TypeClass, Definition::TypeFile, Definition::TypeMember, Definition::TypeModule, Definition::TypeNamespace, and MemberDef::typeString().

Referenced by getResolvedSymbolRec().

◆ getResolvedSymbolRec()

const Definition * SymbolResolver::Private::getResolvedSymbolRec ( LookupCache & cache,
VisitedKeys & visitedKeys,
const Definition * scope,
const QCString & n,
const QCString & args,
bool checkCV,
bool insideCode,
bool onlyLinkable,
const MemberDef ** pTypeDef,
QCString * pTemplSpec,
QCString * pResolvedType )

Definition at line 445 of file symbolresolver.cpp.

457{
458 AUTO_TRACE("scope={} name={} args={} checkCV={} insideCode={}",
459 scope->name(),n,args,checkCV,insideCode);
460 if (n.isEmpty()) return nullptr;
461 QCString explicitScopePart;
462 QCString strippedTemplateParams;
463 QCString scopeName=scope!=Doxygen::globalScope ? scope->name() : QCString();
464 QCString name=stripTemplateSpecifiersFromScope(n,true,&strippedTemplateParams,scopeName);
465 std::unique_ptr<ArgumentList> actTemplParams;
466 if (!strippedTemplateParams.isEmpty()) // template part that was stripped
467 {
468 actTemplParams = stringToArgumentList(scope->getLanguage(),strippedTemplateParams);
469 }
470
471 int qualifierIndex = computeQualifiedIndex(name);
472 //printf("name=%s qualifierIndex=%d\n",qPrint(name),qualifierIndex);
473 if (qualifierIndex!=-1) // qualified name
474 {
475 // split off the explicit scope part
476 explicitScopePart=name.left(qualifierIndex);
477 // todo: improve namespace alias substitution
478 replaceNamespaceAliases(explicitScopePart);
479 name=name.mid(qualifierIndex+2);
480 }
481 AUTO_TRACE_ADD("qualifierIndex={} name={} explicitScopePart={} strippedTemplateParams={}",
482 qualifierIndex,name,explicitScopePart,strippedTemplateParams);
483
484 if (name.isEmpty())
485 {
486 AUTO_TRACE_EXIT("empty name qualifierIndex={}",qualifierIndex);
487 return nullptr; // empty name
488 }
489
490 int i=0;
491 const auto &range1 = Doxygen::symbolMap->find(name);
492 const auto &range = (range1.empty() && (i=name.find('<'))!=-1) ? Doxygen::symbolMap->find(name.left(i)) : range1;
493 if (range.empty())
494 {
495 AUTO_TRACE_ADD("no symbols with name '{}' (including unspecialized)",name);
496 return nullptr;
497 }
498 AUTO_TRACE_ADD("{} -> {} candidates",name,range.size());
499
500 bool hasUsingStatements =
501 (m_fileScope && (!m_fileScope->getUsedNamespaces().empty() ||
503 );
504 // Since it is often the case that the same name is searched in the same
505 // scope over an over again (especially for the linked source code generation)
506 // we use a cache to collect previous results. This is possible since the
507 // result of a lookup is deterministic. As the key we use the concatenated
508 // scope, the name to search for and the explicit scope prefix. The speedup
509 // achieved by this simple cache can be enormous.
510 size_t scopeNameLen = scope!=Doxygen::globalScope ? scope->name().length()+1 : 0;
511 size_t nameLen = name.length()+1;
512 size_t explicitPartLen = explicitScopePart.length();
513 size_t strippedTemplateParamsLen = strippedTemplateParams.length();
514 size_t fileScopeLen = hasUsingStatements ? 1+m_fileScope->absFilePath().length() : 0;
515 size_t argsLen = args.length()+1;
516
517 // below is a more efficient coding of
518 // QCString key=scope->name()+"+"+name+"+"+explicitScopePart+args+typesOnly?'T':'F';
519 std::string key;
520 key.reserve(scopeNameLen+nameLen+explicitPartLen+strippedTemplateParamsLen+fileScopeLen+argsLen);
521 if (scope!=Doxygen::globalScope)
522 {
523 key+=scope->name().str();
524 key+='+';
525 }
526 key+=name.str();
527 key+='+';
528 key+=explicitScopePart.str();
529 key+=strippedTemplateParams.str();
530
531 // if a file scope is given and it contains using statements we should
532 // also use the file part in the key (as a class name can be in
533 // two different namespaces and a using statement in a file can select
534 // one of them).
535 if (hasUsingStatements)
536 {
537 // below is a more efficient coding of
538 // key+="+"+m_fileScope->name();
539 key+='+';
540 key+=m_fileScope->absFilePath().str();
541 }
542 if (argsLen>0)
543 {
544 key+='+';
545 key+=args.str();
546 }
547
548 const Definition *bestMatch=nullptr;
549 {
550 if (std::find(visitedKeys.begin(),visitedKeys.end(),key)!=std::end(visitedKeys))
551 {
552 // we are already in the middle of find the definition for this key.
553 // avoid recursion
554 return nullptr;
555 }
556 // remember the key
557 visitedKeys.push_back(key);
558 LookupInfo *pval = cache.find(key);
559 AUTO_TRACE_ADD("key={} found={}",key,pval!=nullptr);
560 if (pval)
561 {
562 if (pTemplSpec) *pTemplSpec=pval->templSpec;
563 if (pTypeDef) *pTypeDef=pval->typeDef;
564 if (pResolvedType) *pResolvedType=pval->resolvedType;
565 AUTO_TRACE_EXIT("found cached name={} templSpec={} typeDef={} resolvedTypedef={}",
566 pval->definition?pval->definition->name():QCString(),
567 pval->templSpec,
568 pval->typeDef?pval->typeDef->name():QCString(),
569 pval->resolvedType);
570 return pval->definition;
571 }
572
573 const MemberDef *bestTypedef=nullptr;
574 QCString bestTemplSpec;
575 QCString bestResolvedType;
576 int minDistance=10000; // init at "infinite"
577
578 // helper to skip symbol definitions that should not be considered for lookup
579 auto skipDefinition = [this,&explicitScopePart](const Definition *d) -> bool {
580 if (d->definitionType()==Definition::TypeMember)
581 {
582 const MemberDef *emd = dynamic_cast<const MemberDef *>(d);
583 if (emd &&
584 emd->isEnumValue() &&
585 emd->getEnumScope() &&
586 emd->getEnumScope()->isStrong() &&
587 explicitScopePart.isEmpty())
588 {
589 // skip lookup for strong enum values without explicit scope, see issue #11799
590 return true;
591 }
592 if (emd &&
593 emd->isStatic() && // a static function or variable
594 emd->getClassDef()==nullptr && // not a class member
595 emd->getFileDef()!=m_fileScope) // defined in a different file
596 {
597 // skip lookup for static members that are not in the current file scope
598 return true;
599 }
600 }
601 return false;
602 };
603
604 for (Definition *d : range)
605 {
606 if (isCodeSymbol(d->definitionType()) &&
607 (!onlyLinkable ||
608 d->isLinkable() ||
609 d->isLinkableInProject() ||
610 (d->definitionType()==Definition::TypeFile &&
611 (toFileDef(d))->generateSourceFile()
612 ) // undocumented file that has source code we can link to
613 )
614 )
615 {
616 if (skipDefinition(d)) continue;
617 getResolvedSymbol(visitedKeys,scope,d,args,checkCV,insideCode,explicitScopePart,strippedTemplateParams,false,
618 minDistance,bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
619 }
620 if (minDistance==0) break; // we can stop reaching if we already reached distance 0
621 }
622
623 // in case we are looking for e.g. func() and the real function is func(int x) we also
624 // accept func(), see example 036 in the test set.
625 if (bestMatch==nullptr && args=="()")
626 {
627 for (Definition *d : range)
628 {
629 if (isCodeSymbol(d->definitionType()))
630 {
631 if (skipDefinition(d)) continue;
632 getResolvedSymbol(visitedKeys,scope,d,QCString(),false,insideCode,explicitScopePart,strippedTemplateParams,true,
633 minDistance,bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
634 }
635 if (minDistance==0) break; // we can stop reaching if we already reached distance 0
636 }
637 }
638
639 if (pTypeDef)
640 {
641 *pTypeDef = bestTypedef;
642 }
643 if (pTemplSpec)
644 {
645 *pTemplSpec = bestTemplSpec;
646 }
647 if (pResolvedType)
648 {
649 *pResolvedType = bestResolvedType;
650 }
651
652 cache.insert(key,LookupInfo(bestMatch,bestTypedef,bestTemplSpec,bestResolvedType));
653 visitedKeys.erase(std::remove(visitedKeys.begin(),visitedKeys.end(),key),visitedKeys.end());
654
655 AUTO_TRACE_EXIT("found name={} templSpec={} typeDef={} resolvedTypedef={}",
656 bestMatch?bestMatch->name():QCString(),
657 bestTemplSpec,
658 bestTypedef?bestTypedef->name():QCString(),
659 bestResolvedType);
660 }
661 return bestMatch;
662}
V * insert(const K &key, V &&value)
Inserts value under key in the cache.
Definition cache.h:44
V * find(const K &key)
Definition cache.h:105
virtual QCString absFilePath() const =0
virtual const ClassDef * getClassDef() const =0
virtual bool isStatic() const =0
virtual bool isStrong() const =0
virtual const MemberDef * getEnumScope() const =0
virtual bool isEnumValue() const =0
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:164
int find(char c, int index=0, bool cs=true) const
Definition qcstring.cpp:43
QCString left(size_t len) const
Definition qcstring.h:227
void replaceNamespaceAliases(QCString &name)
QCString resolvedType
Definition doxygen.h:62
const Definition * definition
Definition doxygen.h:59
QCString templSpec
Definition doxygen.h:61
const MemberDef * typeDef
Definition doxygen.h:60
void getResolvedSymbol(VisitedKeys &visitedKeys, const Definition *scope, const Definition *d, const QCString &args, bool checkCV, bool insideCode, const QCString &explicitScopePart, const QCString &strippedTemplateParams, bool forceCallable, int &minDistance, const Definition *&bestMatch, const MemberDef *&bestTypedef, QCString &bestTemplSpec, QCString &bestResolvedType)
static bool isCodeSymbol(Definition::DefType defType)
int computeQualifiedIndex(const QCString &name)
Return the index of the last :: in the string name that is still before the first <.
Definition util.cpp:6864
QCString stripTemplateSpecifiersFromScope(const QCString &fullName, bool parentOnly, QCString *pLastScopeStripped, QCString scopeName, bool allowArtificial)
Definition util.cpp:4570

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, computeQualifiedIndex(), LookupInfo::definition, Cache< K, V >::find(), QCString::find(), SymbolMap< T >::find(), MemberDef::getClassDef(), MemberDef::getEnumScope(), MemberDef::getFileDef(), Definition::getLanguage(), getResolvedSymbol(), Doxygen::globalScope, Cache< K, V >::insert(), isCodeSymbol(), QCString::isEmpty(), MemberDef::isEnumValue(), MemberDef::isStatic(), MemberDef::isStrong(), QCString::left(), QCString::length(), m_fileScope, QCString::mid(), Definition::name(), replaceNamespaceAliases(), LookupInfo::resolvedType, QCString::size(), QCString::str(), stringToArgumentList(), stripTemplateSpecifiersFromScope(), Doxygen::symbolMap, LookupInfo::templSpec, toFileDef(), LookupInfo::typeDef, Definition::TypeFile, and Definition::TypeMember.

◆ getResolvedType()

void SymbolResolver::Private::getResolvedType ( LookupCache & cache,
VisitedKeys & visitedKeys,
const Definition * scope,
const Definition * d,
const QCString & explicitScopePart,
const ArgumentList * actTemplParams,
int & minDistance,
const ClassDef *& bestMatch,
const MemberDef *& bestTypedef,
QCString & bestTemplSpec,
QCString & bestResolvedType )
private

Definition at line 664 of file symbolresolver.cpp.

677{
678 AUTO_TRACE("scope={} sym={} explicitScope={}",scope->name(),d->qualifiedName(),explicitScopePart);
679 // only look at classes and members that are enums or typedefs
682 ((toMemberDef(d))->isTypedef() ||
683 (toMemberDef(d))->isEnumerate())
684 )
685 )
686 {
687 VisitedNamespaces visitedNamespaces;
688 AccessStack accessStack;
689 // test accessibility of definition within scope.
690 int distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,
691 accessStack,scope,d,explicitScopePart);
692 AUTO_TRACE_ADD("distance={}",distance);
693 if (distance!=-1) // definition is accessible
694 {
695 // see if we are dealing with a class or a typedef
696 if (d->definitionType()==Definition::TypeClass) // d is a class
697 {
698 const ClassDef *cd = toClassDef(d);
699 //printf("cd=%s\n",qPrint(cd->name()));
700 if (!cd->isTemplateArgument()) // skip classes that
701 // are only there to
702 // represent a template
703 // argument
704 {
705 //printf("is not a templ arg\n");
706 if (distance<minDistance) // found a definition that is "closer"
707 {
708 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",cd->name(),distance,minDistance);
709 minDistance=distance;
710 bestMatch = cd;
711 bestTypedef = nullptr;
712 bestTemplSpec.clear();
713 bestResolvedType = cd->qualifiedName();
714 }
715 else if (distance==minDistance &&
716 m_fileScope && bestMatch &&
720 )
721 {
722 // in case the distance is equal it could be that a class X
723 // is defined in a namespace and in the global scope. When searched
724 // in the global scope the distance is 0 in both cases. We have
725 // to choose one of the definitions: we choose the one in the
726 // namespace if the fileScope imports namespaces and the definition
727 // found was in a namespace while the best match so far isn't.
728 // Just a non-perfect heuristic but it could help in some situations
729 // (kdecore code is an example).
730 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",cd->name(),distance,minDistance);
731 minDistance=distance;
732 bestMatch = cd;
733 bestTypedef = nullptr;
734 bestTemplSpec.clear();
735 bestResolvedType = cd->qualifiedName();
736 }
737 }
738 else
739 {
740 //printf(" is a template argument!\n");
741 }
742 }
744 {
745 const MemberDef *md = toMemberDef(d);
746 AUTO_TRACE_ADD("member={} isTypeDef={}",md->name(),md->isTypedef());
747 if (md->isTypedef()) // d is a typedef
748 {
749 QCString args=md->argsString();
750 if (args.isEmpty()) // do not expand "typedef t a[4];"
751 {
752 // we found a symbol at this distance, but if it didn't
753 // resolve to a class, we still have to make sure that
754 // something at a greater distance does not match, since
755 // that symbol is hidden by this one.
756 if (distance<minDistance)
757 {
758 QCString spec;
759 QCString type;
760 minDistance=distance;
761 const MemberDef *enumType = nullptr;
762 const ClassDef *cd = newResolveTypedef(cache,visitedKeys,scope,md,&enumType,&spec,&type,actTemplParams);
763 if (cd) // type resolves to a class
764 {
765 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",cd->name(),distance,minDistance);
766 bestMatch = cd;
767 bestTypedef = md;
768 bestTemplSpec = spec;
769 bestResolvedType = type;
770 }
771 else if (enumType) // type resolves to a member type
772 {
773 AUTO_TRACE_ADD("found enum");
774 bestMatch = nullptr;
775 bestTypedef = enumType;
776 bestTemplSpec = "";
777 bestResolvedType = enumType->qualifiedName();
778 }
779 else if (md->isReference()) // external reference
780 {
781 AUTO_TRACE_ADD("found external reference");
782 bestMatch = nullptr;
783 bestTypedef = md;
784 bestTemplSpec = spec;
785 bestResolvedType = type;
786 }
787 else
788 {
789 AUTO_TRACE_ADD("no match");
790 bestMatch = nullptr;
791 bestTypedef = md;
792 bestTemplSpec.clear();
793 bestResolvedType.clear();
794 }
795 }
796 else
797 {
798 //printf(" not the best match %d min=%d\n",distance,minDistance);
799 }
800 }
801 else
802 {
803 AUTO_TRACE_ADD("skipping complex typedef");
804 }
805 }
806 else if (md->isEnumerate())
807 {
808 if (distance<minDistance)
809 {
810 AUTO_TRACE_ADD("found enum={} at distance={} minDistance={}",md->name(),distance,minDistance);
811 minDistance=distance;
812 bestMatch = nullptr;
813 bestTypedef = md;
814 bestTemplSpec = "";
815 bestResolvedType = md->qualifiedName();
816 }
817 }
818 }
819 } // if definition accessible
820 else
821 {
822 AUTO_TRACE_ADD("not accessible");
823 }
824 } // if definition is a class or member
825 AUTO_TRACE_EXIT("bestMatch sym={} type={}",
826 bestMatch?bestMatch->name():QCString("<none>"),bestResolvedType);
827}
virtual bool isReference() const =0
virtual bool isTypedef() const =0
virtual QCString argsString() const =0

References MemberDef::argsString(), AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, QCString::clear(), Definition::definitionType(), Definition::getOuterScope(), Doxygen::globalScope, SymbolResolver::isAccessibleFromWithExpScope(), QCString::isEmpty(), MemberDef::isEnumerate(), Definition::isReference(), ClassDef::isTemplateArgument(), MemberDef::isTypedef(), m_fileScope, Definition::name(), newResolveTypedef(), Definition::qualifiedName(), toClassDef(), toMemberDef(), Definition::TypeClass, Definition::TypeMember, and Definition::TypeNamespace.

◆ getResolvedTypeRec()

const ClassDef * SymbolResolver::Private::getResolvedTypeRec ( LookupCache & cache,
VisitedKeys & visitedKeys,
const Definition * scope,
const QCString & n,
const MemberDef ** pTypeDef,
QCString * pTemplSpec,
QCString * pResolvedType )

Definition at line 292 of file symbolresolver.cpp.

300{
301 AUTO_TRACE("scope={} name={}",scope->name(),n);
302 if (n.isEmpty()) return nullptr;
303 QCString explicitScopePart;
304 QCString strippedTemplateParams;
305 QCString scopeName=scope!=Doxygen::globalScope ? scope->name() : QCString();
306 QCString name=stripTemplateSpecifiersFromScope(n,true,&strippedTemplateParams,scopeName);
307 std::unique_ptr<ArgumentList> actTemplParams;
308 if (!strippedTemplateParams.isEmpty()) // template part that was stripped
309 {
310 actTemplParams = stringToArgumentList(scope->getLanguage(),strippedTemplateParams);
311 }
312
313 int qualifierIndex = computeQualifiedIndex(name);
314 //printf("name=%s qualifierIndex=%d\n",qPrint(name),qualifierIndex);
315 if (qualifierIndex!=-1) // qualified name
316 {
317 // split off the explicit scope part
318 explicitScopePart=name.left(qualifierIndex);
319 // todo: improve namespace alias substitution
320 replaceNamespaceAliases(explicitScopePart);
321 name=name.mid(qualifierIndex+2);
322 }
323
324 if (name.isEmpty())
325 {
326 AUTO_TRACE_EXIT("empty name");
327 return nullptr; // empty name
328 }
329
330 auto &range = Doxygen::symbolMap->find(name);
331 if (range.empty())
332 {
333 AUTO_TRACE_EXIT("no symbol with this name");
334 return nullptr;
335 }
336
337 bool hasUsingStatements =
338 (m_fileScope && (!m_fileScope->getUsedNamespaces().empty() ||
340 );
341 // Since it is often the case that the same name is searched in the same
342 // scope over an over again (especially for the linked source code generation)
343 // we use a cache to collect previous results. This is possible since the
344 // result of a lookup is deterministic. As the key we use the concatenated
345 // scope, the name to search for and the explicit scope prefix. The speedup
346 // achieved by this simple cache can be enormous.
347 size_t scopeNameLen = scope->name().length()+1;
348 size_t nameLen = name.length()+1;
349 size_t explicitPartLen = explicitScopePart.length();
350 size_t fileScopeLen = hasUsingStatements ? 1+m_fileScope->absFilePath().length() : 0;
351
352 // below is a more efficient coding of
353 // QCString key=scope->name()+"+"+name+"+"+explicitScopePart+args+typesOnly?'T':'F';
354 QCString key(scopeNameLen+nameLen+explicitPartLen+fileScopeLen, QCString::ExplicitSize);
355 char *pk=key.rawData();
356 qstrcpy(pk,scope->name().data()); *(pk+scopeNameLen-1)='+';
357 pk+=scopeNameLen;
358 qstrcpy(pk,name.data()); *(pk+nameLen-1)='+';
359 pk+=nameLen;
360 qstrcpy(pk,explicitScopePart.data());
361 pk+=explicitPartLen;
362
363 // if a file scope is given and it contains using statements we should
364 // also use the file part in the key (as a class name can be in
365 // two different namespaces and a using statement in a file can select
366 // one of them).
367 if (hasUsingStatements)
368 {
369 // below is a more efficient coding of
370 // key+="+"+m_fileScope->name();
371 *pk++='+';
373 pk+=fileScopeLen-1;
374 }
375 *pk='\0';
376
377 const ClassDef *bestMatch=nullptr;
378 {
379 if (std::find(visitedKeys.begin(),visitedKeys.end(),key.str())!=std::end(visitedKeys))
380 {
381 // we are already in the middle of find the definition for this key.
382 // avoid recursion
383 AUTO_TRACE_EXIT("recursion detected");
384 return nullptr;
385 }
386 // remember the key
387 visitedKeys.push_back(key.str());
388
389 LookupInfo *pval = cache.find(key.str());
390 AUTO_TRACE_ADD("key={} found={}",key,pval!=nullptr);
391 if (pval)
392 {
393 if (pTemplSpec) *pTemplSpec=pval->templSpec;
394 if (pTypeDef) *pTypeDef=pval->typeDef;
395 if (pResolvedType) *pResolvedType=pval->resolvedType;
396 AUTO_TRACE_EXIT("found cached name={} templSpec={} typeDef={} resolvedTypedef={}",
397 pval->definition?pval->definition->name():QCString(),
398 pval->templSpec,
399 pval->typeDef?pval->typeDef->name():QCString(),
400 pval->resolvedType);
401
402 return toClassDef(pval->definition);
403 }
404
405 const MemberDef *bestTypedef=nullptr;
406 QCString bestTemplSpec;
407 QCString bestResolvedType;
408 int minDistance=10000; // init at "infinite"
409
410 for (Definition *d : range)
411 {
412 if (isCodeSymbol(d->definitionType()))
413 {
414 getResolvedType(cache,visitedKeys,scope,d,explicitScopePart,actTemplParams.get(),
415 minDistance,bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
416 }
417 if (minDistance==0) break; // we can stop reaching if we already reached distance 0
418 }
419
420 if (pTypeDef)
421 {
422 *pTypeDef = bestTypedef;
423 }
424 if (pTemplSpec)
425 {
426 *pTemplSpec = bestTemplSpec;
427 }
428 if (pResolvedType)
429 {
430 *pResolvedType = bestResolvedType;
431 }
432
433 cache.insert(key.str(),LookupInfo(bestMatch,bestTypedef,bestTemplSpec,bestResolvedType));
434 visitedKeys.erase(std::remove(visitedKeys.begin(), visitedKeys.end(), key.str()), visitedKeys.end());
435
436 AUTO_TRACE_EXIT("found name={} templSpec={} typeDef={} resolvedTypedef={}",
437 bestMatch?bestMatch->name():QCString(),
438 bestTemplSpec,
439 bestTypedef?bestTypedef->name():QCString(),
440 bestResolvedType);
441 }
442 return bestMatch;
443}
@ ExplicitSize
Definition qcstring.h:144
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:170
QCString getResolvedType() const
In case a call to resolveClass() points to a typedef or using declaration.
char * qstrcpy(char *dst, const char *src)
Definition qcstring.h:55

References FileDef::absFilePath(), AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, computeQualifiedIndex(), QCString::data(), LookupInfo::definition, LinkedRefMap< T, Hash, KeyEqual, Map >::empty(), QCString::ExplicitSize, Cache< K, V >::find(), SymbolMap< T >::find(), Definition::getLanguage(), SymbolResolver::getResolvedType(), FileDef::getUsedDefinitions(), FileDef::getUsedNamespaces(), Doxygen::globalScope, Cache< K, V >::insert(), isCodeSymbol(), QCString::isEmpty(), QCString::left(), QCString::length(), m_fileScope, QCString::mid(), Definition::name(), qstrcpy(), QCString::rawData(), replaceNamespaceAliases(), LookupInfo::resolvedType, QCString::str(), stringToArgumentList(), stripTemplateSpecifiersFromScope(), Doxygen::symbolMap, LookupInfo::templSpec, toClassDef(), and LookupInfo::typeDef.

Referenced by newResolveTypedef().

◆ isAccessibleFrom()

int SymbolResolver::Private::isAccessibleFrom ( VisitedKeys & visitedKeys,
AccessStack & accessStack,
const Definition * scope,
const Definition * item )

Definition at line 1437 of file symbolresolver.cpp.

1441{
1442 AUTO_TRACE("scope={} item={} item.definitionType={}",
1443 scope?scope->name():QCString(), item?item->name():QCString(),
1444 item?(int)item->definitionType():-1);
1445
1446 if (accessStack.find(scope,m_fileScope,item))
1447 {
1448 AUTO_TRACE_EXIT("already processed!");
1449 return -1;
1450 }
1451 accessStack.push(scope,m_fileScope,item);
1452
1453 int result=0; // assume we found it
1454 int i=0;
1455
1456 const Definition *itemScope=item->getOuterScope();
1457 bool itemIsMember = item->definitionType()==Definition::TypeMember;
1458 bool itemIsClass = item->definitionType()==Definition::TypeClass;
1459
1460 // if item is a global member and scope points to a specific file
1461 // we adjust the scope so the file gets preference over members with the same name in
1462 // other files.
1463 if ((itemIsMember || itemIsClass) &&
1464 (itemScope==Doxygen::globalScope || // global
1465 (itemScope && itemScope->name().startsWith("anonymous_namespace{")) // member of an anonymous namespace
1466 ) &&
1468 {
1469 if (itemIsMember)
1470 {
1471 itemScope = toMemberDef(item)->getFileDef();
1472 }
1473 else if (itemIsClass)
1474 {
1475 itemScope = toClassDef(item)->getFileDef();
1476 }
1477 AUTO_TRACE_ADD("adjusting scope to {}",itemScope?itemScope->name():QCString());
1478 }
1479
1480 bool memberAccessibleFromScope =
1481 (itemIsMember && // a member
1482 itemScope && itemScope->definitionType()==Definition::TypeClass && // of a class
1483 scope->definitionType()==Definition::TypeClass && // accessible
1484 (toClassDef(scope))->isAccessibleMember(toMemberDef(item)) // from scope
1485 );
1486 bool nestedClassInsideBaseClass =
1487 (itemIsClass && // a nested class
1488 itemScope && itemScope->definitionType()==Definition::TypeClass && // inside a base
1489 scope->definitionType()==Definition::TypeClass && // class of scope
1490 (toClassDef(scope))->isBaseClass(toClassDef(itemScope),true)
1491 );
1492 bool enumValueOfStrongEnum =
1493 (itemIsMember &&
1494 toMemberDef(item)->isStrongEnumValue() &&
1496 toMemberDef(scope)->isEnumerate() &&
1497 scope==toMemberDef(item)->getEnumScope()
1498 );
1499
1500 if (itemScope==scope || memberAccessibleFromScope || nestedClassInsideBaseClass || enumValueOfStrongEnum)
1501 {
1502 AUTO_TRACE_ADD("memberAccessibleFromScope={} nestedClassInsideBaseClass={} enumValueOfStrongEnum={}",
1503 memberAccessibleFromScope, nestedClassInsideBaseClass, enumValueOfStrongEnum);
1504 int distanceToBase=0;
1505 if (nestedClassInsideBaseClass)
1506 {
1507 result++; // penalty for base class to prevent
1508 // this is preferred over nested class in this class
1509 // see bug 686956
1510 }
1511 else if (memberAccessibleFromScope &&
1512 itemScope &&
1513 itemScope->definitionType()==Definition::TypeClass &&
1515 (distanceToBase=toClassDef(scope)->isBaseClass(toClassDef(itemScope),true))>0
1516 )
1517 {
1518 result+=distanceToBase; // penalty if member is accessible via a base class
1519 }
1520 }
1521 else if (scope==Doxygen::globalScope)
1522 {
1523 if (itemScope &&
1525 toNamespaceDef(itemScope)->isAnonymous() &&
1526 itemScope->getOuterScope()==Doxygen::globalScope)
1527 { // item is in an anonymous namespace in the global scope and we are
1528 // looking in the global scope
1529 AUTO_TRACE_ADD("found in anonymous namespace");
1530 result++;
1531 goto done;
1532 }
1533 if (m_fileScope)
1534 {
1536 {
1537 AUTO_TRACE_ADD("found via used class");
1538 goto done;
1539 }
1540 VisitedNamespaceKeys visitedNamespaceKeys;
1541 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaceKeys,m_fileScope->getUsedNamespaces(),item))
1542 {
1543 AUTO_TRACE_ADD("found via used namespace");
1544 goto done;
1545 }
1546 }
1547 AUTO_TRACE_ADD("reached global scope");
1548 result=-1; // not found in path to globalScope
1549 }
1550 else // keep searching
1551 {
1552 // check if scope is a namespace, which is using other classes and namespaces
1554 {
1555 const NamespaceDef *nscope = toNamespaceDef(scope);
1556 if (accessibleViaUsingDefinition(visitedKeys,nscope->getUsedDefinitions(),item))
1557 {
1558 AUTO_TRACE_ADD("found via used class");
1559 goto done;
1560 }
1561 VisitedNamespaceKeys visitedNamespaceKeys;
1562 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaceKeys,nscope->getUsedNamespaces(),item,QCString()))
1563 {
1564 AUTO_TRACE_ADD("found via used namespace");
1565 goto done;
1566 }
1567 }
1568 else if (scope->definitionType()==Definition::TypeFile)
1569 {
1570 const FileDef *nfile = toFileDef(scope);
1571 if (accessibleViaUsingDefinition(visitedKeys,nfile->getUsedDefinitions(),item))
1572 {
1573 AUTO_TRACE_ADD("found via used class");
1574 goto done;
1575 }
1576 VisitedNamespaceKeys visitedNamespaceKeys;
1577 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaceKeys,nfile->getUsedNamespaces(),item,QCString()))
1578 {
1579 AUTO_TRACE_ADD("found via used namespace");
1580 goto done;
1581 }
1582 }
1583 // repeat for the parent scope
1584 const Definition *parentScope = scope->getOuterScope();
1585 if (parentScope==Doxygen::globalScope)
1586 {
1588 {
1589 const FileDef *fd = toClassDef(scope)->getFileDef();
1590 if (fd)
1591 {
1592 parentScope = fd;
1593 }
1594 }
1595 }
1596 i=isAccessibleFrom(visitedKeys,accessStack,parentScope,item);
1597 result= (i==-1) ? -1 : i+2;
1598 }
1599done:
1600 AUTO_TRACE_EXIT("result={}",result);
1601 accessStack.pop();
1602 return result;
1603}
bool find(const Definition *scope, const FileDef *fileScope, const Definition *item)
void push(const Definition *scope, const FileDef *fileScope, const Definition *item)
virtual FileDef * getFileDef() const =0
Returns the namespace this compound is in, or 0 if it has a global scope.
virtual bool isStrongEnumValue() const =0
virtual const LinkedRefMap< NamespaceDef > & getUsedNamespaces() const =0
virtual const LinkedRefMap< const Definition > & getUsedDefinitions() const =0
bool accessibleViaUsingDefinition(VisitedKeys &visitedKeys, const LinkedRefMap< const Definition > &dl, const Definition *item, const QCString &explicitScopePart="")
int isAccessibleFrom(VisitedKeys &visitedKeys, AccessStack &accessStack, const Definition *scope, const Definition *item)
StringVector VisitedNamespaceKeys

References accessibleViaUsingDefinition(), accessibleViaUsingNamespace(), AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, Definition::definitionType(), AccessStack::find(), MemberDef::getEnumScope(), ClassDef::getFileDef(), MemberDef::getFileDef(), Definition::getOuterScope(), FileDef::getUsedDefinitions(), NamespaceDef::getUsedDefinitions(), FileDef::getUsedNamespaces(), NamespaceDef::getUsedNamespaces(), Doxygen::globalScope, SymbolResolver::isAccessibleFrom(), MemberDef::isEnumerate(), MemberDef::isStrongEnumValue(), m_fileScope, Definition::name(), AccessStack::pop(), AccessStack::push(), QCString::startsWith(), toClassDef(), toFileDef(), toMemberDef(), toNamespaceDef(), Definition::TypeClass, Definition::TypeFile, Definition::TypeMember, and Definition::TypeNamespace.

◆ isAccessibleFromWithExpScope()

int SymbolResolver::Private::isAccessibleFromWithExpScope ( VisitedKeys & visitedKeys,
VisitedNamespaces & visitedNamespaces,
AccessStack & accessStack,
const Definition * scope,
const Definition * item,
const QCString & explicitScopePart )

Definition at line 1106 of file symbolresolver.cpp.

1113{
1114 int result=0; // assume we found it
1115 AUTO_TRACE("scope={} item={} explictScopePart={}",
1116 scope?scope->name():QCString(), item?item->name():QCString(), explicitScopePart);
1117 if (explicitScopePart.isEmpty())
1118 {
1119 // handle degenerate case where there is no explicit scope.
1120 result = isAccessibleFrom(visitedKeys,accessStack,scope,item);
1121 AUTO_TRACE_EXIT("result={}",result);
1122 return result;
1123 }
1124
1125 if (accessStack.find(scope,m_fileScope,item,explicitScopePart))
1126 {
1127 AUTO_TRACE_EXIT("already found");
1128 return -1;
1129 }
1130 accessStack.push(scope,m_fileScope,item,explicitScopePart);
1131
1132 const Definition *newScope = followPath(visitedKeys,scope,explicitScopePart);
1133 if (newScope) // explicitScope is inside scope => newScope is the result
1134 {
1135 Definition *itemScope = item->getOuterScope();
1136
1137 AUTO_TRACE_ADD("scope traversal successful newScope={}",newScope->name());
1138
1139 bool nestedClassInsideBaseClass =
1140 itemScope &&
1141 itemScope->definitionType()==Definition::TypeClass &&
1143 (toClassDef(newScope))->isBaseClass(toClassDef(itemScope),true);
1144
1145 bool enumValueWithinEnum =
1147 toMemberDef(item)->isEnumValue() &&
1148 toMemberDef(item)->getEnumScope()==newScope;
1149
1150 if (itemScope==newScope) // exact match of scopes => distance==0
1151 {
1152 AUTO_TRACE_ADD("found scope match");
1153 }
1154 else if (nestedClassInsideBaseClass)
1155 {
1156 // inheritance is also ok. Example: looking for B::I, where
1157 // class A { public: class I {} };
1158 // class B : public A {}
1159 // but looking for B::I, where
1160 // class A { public: class I {} };
1161 // class B { public: class I {} };
1162 // will find A::I, so we still prefer a direct match and give this one a distance of 1
1163 result=1;
1164
1165 AUTO_TRACE_ADD("{} is a bass class of {}",scope->name(),newScope->name());
1166 }
1167 else if (enumValueWithinEnum)
1168 {
1169 AUTO_TRACE_ADD("found enum value inside enum");
1170 result=1;
1171 }
1172 else
1173 {
1174 int i=-1;
1176 {
1177 visitedNamespaces.emplace(newScope->name().str(),newScope);
1178 // this part deals with the case where item is a class
1179 // A::B::C but is explicit referenced as A::C, where B is imported
1180 // in A via a using directive.
1181 //printf("newScope is a namespace: %s!\n",qPrint(newScope->name()));
1182 const NamespaceDef *nscope = toNamespaceDef(newScope);
1183 for (const auto &ud : nscope->getUsedDefinitions())
1184 {
1185 if (ud==item)
1186 {
1187 AUTO_TRACE_ADD("found in used definition {}",ud->name());
1188 goto done;
1189 }
1190 }
1191 for (const auto &nd : nscope->getUsedNamespaces())
1192 {
1193 if (visitedNamespaces.find(nd->name().str())==visitedNamespaces.end())
1194 {
1195 i = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,item,nd->name());
1196 if (i!=-1)
1197 {
1198 AUTO_TRACE_ADD("found in used namespace {}",nd->name());
1199 goto done;
1200 }
1201 }
1202 }
1203 }
1204#if 0 // this caused problems resolving A::f() in the docs when there was a A::f(int) but also a
1205 // global function f() that exactly matched the argument list.
1206 else if (isParentScope(scope,newScope) && newScope->definitionType()==Definition::TypeClass)
1207 {
1208 // if we a look for a type B and have explicit scope A, then it is also fine if B
1209 // is found at the global scope.
1210 result = 1;
1211 goto done;
1212 }
1213#endif
1214 // repeat for the parent scope
1215 if (scope!=Doxygen::globalScope)
1216 {
1217 i = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope->getOuterScope(),item,explicitScopePart);
1218 }
1219 result = (i==-1) ? -1 : i+2;
1220 }
1221 }
1222 else // failed to resolve explicitScope
1223 {
1224 AUTO_TRACE_ADD("failed to resolve explicitScope");
1226 {
1227 const NamespaceDef *nscope = toNamespaceDef(scope);
1228 VisitedNamespaceKeys locVisitedNamespaceKeys;
1229 if (accessibleViaUsingNamespace(visitedKeys,locVisitedNamespaceKeys,nscope->getUsedNamespaces(),item,explicitScopePart))
1230 {
1231 AUTO_TRACE_ADD("found in used class");
1232 goto done;
1233 }
1234 }
1235 if (scope==Doxygen::globalScope)
1236 {
1237 if (m_fileScope)
1238 {
1239 VisitedNamespaceKeys locVisitedNamespaceKeys;
1240 if (accessibleViaUsingNamespace(visitedKeys,locVisitedNamespaceKeys,m_fileScope->getUsedNamespaces(),item,explicitScopePart))
1241 {
1242 AUTO_TRACE_ADD("found in used namespace");
1243 goto done;
1244 }
1245 }
1246 AUTO_TRACE_ADD("not found in this scope");
1247 result=-1;
1248 }
1249 else // continue by looking into the parent scope
1250 {
1251 int i=isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope->getOuterScope(),item,explicitScopePart);
1252 result= (i==-1) ? -1 : i+2;
1253 }
1254 }
1255
1256done:
1257 AUTO_TRACE_EXIT("result={}",result);
1258 accessStack.pop();
1259 return result;
1260}

References accessibleViaUsingNamespace(), AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, Definition::definitionType(), AccessStack::find(), followPath(), MemberDef::getEnumScope(), Definition::getOuterScope(), NamespaceDef::getUsedDefinitions(), NamespaceDef::getUsedNamespaces(), Doxygen::globalScope, SymbolResolver::isAccessibleFrom(), SymbolResolver::isAccessibleFromWithExpScope(), QCString::isEmpty(), MemberDef::isEnumValue(), m_fileScope, Definition::name(), AccessStack::pop(), AccessStack::push(), QCString::str(), toClassDef(), toMemberDef(), toNamespaceDef(), Definition::TypeClass, Definition::TypeMember, and Definition::TypeNamespace.

◆ newResolveTypedef()

const ClassDef * SymbolResolver::Private::newResolveTypedef ( LookupCache & cache,
VisitedKeys & visitedKeys,
const Definition * scope,
const MemberDef * md,
const MemberDef ** pMemType,
QCString * pTemplSpec,
QCString * pResolvedType,
const ArgumentList * actTemplParams = nullptr )
private

Definition at line 967 of file symbolresolver.cpp.

976{
977 AUTO_TRACE("md={}",md->qualifiedName());
978 std::lock_guard lock(g_cacheTypedefMutex);
979 bool isCached = md->isTypedefValCached(); // value already cached
980 if (isCached)
981 {
982 AUTO_TRACE_EXIT("cached typedef={} resolvedTypedef={} templSpec={}",
983 md->getCachedTypedefVal() ? md->getCachedTypedefVal()->name() : QCString(),
986
987 if (pTemplSpec) *pTemplSpec = md->getCachedTypedefTemplSpec();
988 if (pResolvedType) *pResolvedType = md->getCachedResolvedTypedef();
989 return md->getCachedTypedefVal();
990 }
991
992 QCString qname = md->qualifiedName();
993 if (m_resolvedTypedefs.find(qname.str())!=m_resolvedTypedefs.end())
994 {
995 AUTO_TRACE_EXIT("already being processed");
996 return nullptr; // typedef already done
997 }
998
999 auto typedef_it = m_resolvedTypedefs.emplace(qname.str(),md).first; // put on the trace list
1000
1001 const ClassDef *typeClass = md->getClassDef();
1002 QCString type = md->typeString(); // get the "value" of the typedef
1003 if (typeClass && typeClass->isTemplate() &&
1004 actTemplParams && !actTemplParams->empty())
1005 {
1007 typeClass->templateArguments(),actTemplParams);
1008 }
1009 QCString typedefValue = type;
1010 int tl=static_cast<int>(type.length());
1011 int ip=tl-1; // remove * and & at the end
1012 while (ip>=0 && (type.at(ip)=='*' || type.at(ip)=='&' || type.at(ip)==' '))
1013 {
1014 ip--;
1015 }
1016 type=type.left(ip+1);
1017 type.stripPrefix("const "); // strip leading "const"
1018 type.stripPrefix("volatile "); // strip leading "volatile"
1019 type.stripPrefix("struct "); // strip leading "struct"
1020 type.stripPrefix("union "); // strip leading "union"
1021 int sp=0;
1022 tl=static_cast<int>(type.length()); // length may have been changed
1023 while (sp<tl && type.at(sp)==' ') sp++;
1024 const MemberDef *memTypeDef = nullptr;
1025 const ClassDef *result = getResolvedTypeRec(cache,visitedKeys,md->getOuterScope(),type,
1026 &memTypeDef,nullptr,pResolvedType);
1027 // if type is a typedef then return what it resolves to.
1028 if (memTypeDef && memTypeDef->isTypedef())
1029 {
1030 AUTO_TRACE_ADD("resolving typedef");
1031 result=newResolveTypedef(cache,visitedKeys,m_fileScope,memTypeDef,pMemType,pTemplSpec,nullptr);
1032 goto done;
1033 }
1034 else if (memTypeDef && memTypeDef->isEnumerate() && pMemType)
1035 {
1036 *pMemType = memTypeDef;
1037 }
1038
1039 if (result==nullptr)
1040 {
1041 // try unspecialized version if type is template
1042 int si=type.findRev("::");
1043 int i=type.find('<');
1044 if (si==-1 && i!=-1) // typedef of a template => try the unspecialized version
1045 {
1046 if (pTemplSpec) *pTemplSpec = type.mid(i);
1047 result = getResolvedTypeRec(cache,visitedKeys,md->getOuterScope(),type.left(i),nullptr,nullptr,pResolvedType);
1048 }
1049 else if (si!=-1) // A::B
1050 {
1051 i=type.find('<',si);
1052 if (i==-1) // Something like A<T>::B => lookup A::B
1053 {
1054 i=static_cast<int>(type.length());
1055 }
1056 else // Something like A<T>::B<S> => lookup A::B, spec=<S>
1057 {
1058 if (pTemplSpec) *pTemplSpec = type.mid(i);
1059 }
1060 result = getResolvedTypeRec(cache,visitedKeys,md->getOuterScope(),
1061 stripTemplateSpecifiersFromScope(type.left(i),false),nullptr,nullptr,pResolvedType);
1062 }
1063 }
1064
1065done:
1066 if (pResolvedType)
1067 {
1068 if (result && result->definitionType()==Definition::TypeClass)
1069 {
1070 *pResolvedType = result->qualifiedName();
1071 if (sp>0) pResolvedType->prepend(typedefValue.left(sp));
1072 if (ip<tl-1) pResolvedType->append(typedefValue.right(tl-ip-1));
1073 }
1074 else
1075 {
1076 *pResolvedType = typedefValue;
1077 }
1078 }
1079
1080 // remember computed value for next time
1081 if (result && result->getDefFileName()!="<code>")
1082 // this check is needed to prevent that temporary classes that are
1083 // introduced while parsing code fragments are being cached here.
1084 {
1085 AUTO_TRACE_ADD("caching typedef relation {}->{}",md->name(),result->name());
1086 MemberDefMutable *mdm = toMemberDefMutable(const_cast<MemberDef*>(md));
1087 if (mdm)
1088 {
1089 mdm->cacheTypedefVal(result,
1090 pTemplSpec ? *pTemplSpec : QCString(),
1091 pResolvedType ? *pResolvedType : QCString()
1092 );
1093 }
1094 }
1095
1096 m_resolvedTypedefs.erase(typedef_it); // remove from the trace list
1097
1098 AUTO_TRACE_EXIT("result={} pTemplSpec={} pResolvedType={}",
1099 result ? result->name() : QCString(),
1100 pTemplSpec ? *pTemplSpec : "<nullptr>",
1101 pResolvedType ? *pResolvedType : "<nullptr>"
1102 );
1103 return result;
1104}
bool empty() const
Definition arguments.h:99
virtual const ArgumentList & templateArguments() const =0
Returns the template arguments of this class.
virtual bool isTemplate() const =0
Returns true if this class is a template.
virtual QCString getDefFileName() const =0
virtual QCString getCachedResolvedTypedef() const =0
virtual const ClassDef * getCachedTypedefVal() const =0
virtual QCString getCachedTypedefTemplSpec() const =0
virtual bool isTypedefValCached() const =0
virtual void cacheTypedefVal(const ClassDef *val, const QCString &templSpec, const QCString &resolvedType)=0
QCString & prepend(const char *s)
Definition qcstring.h:420
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:591
QCString & append(char c)
Definition qcstring.h:394
QCString right(size_t len) const
Definition qcstring.h:232
int findRev(char c, int index=-1, bool cs=true) const
Definition qcstring.cpp:96
bool stripPrefix(const QCString &prefix)
Definition qcstring.h:211
MemberDefMutable * toMemberDefMutable(Definition *d)
const ClassDef * getResolvedTypeRec(LookupCache &cache, VisitedKeys &visitedKeys, const Definition *scope, const QCString &n, const MemberDef **pTypeDef, QCString *pTemplSpec, QCString *pResolvedType)
std::unordered_map< std::string, const MemberDef * > m_resolvedTypedefs
static std::recursive_mutex g_cacheTypedefMutex

References QCString::append(), QCString::at(), AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, MemberDefMutable::cacheTypedefVal(), Definition::definitionType(), ArgumentList::empty(), QCString::find(), QCString::findRev(), g_cacheTypedefMutex, MemberDef::getCachedResolvedTypedef(), MemberDef::getCachedTypedefTemplSpec(), MemberDef::getCachedTypedefVal(), MemberDef::getClassDef(), Definition::getDefFileName(), Definition::getOuterScope(), getResolvedTypeRec(), MemberDef::isEnumerate(), ClassDef::isTemplate(), MemberDef::isTypedef(), MemberDef::isTypedefValCached(), QCString::left(), QCString::length(), m_fileScope, m_resolvedTypedefs, QCString::mid(), Definition::name(), newResolveTypedef(), QCString::prepend(), Definition::qualifiedName(), QCString::right(), QCString::str(), QCString::stripPrefix(), stripTemplateSpecifiersFromScope(), substituteTemplateArgumentsInString(), ClassDef::templateArguments(), toMemberDefMutable(), Definition::TypeClass, and MemberDef::typeString().

Referenced by followPath(), getResolvedType(), and newResolveTypedef().

◆ reset()

void SymbolResolver::Private::reset ( )
inline

Definition at line 173 of file symbolresolver.cpp.

174 {
175 m_resolvedTypedefs.clear();
177 typeDef = nullptr;
179 }
const MemberDef * typeDef

References QCString::clear(), m_resolvedTypedefs, resolvedType, templateSpec, and typeDef.

◆ setFileScope()

void SymbolResolver::Private::setFileScope ( const FileDef * fileScope)
inline

Definition at line 180 of file symbolresolver.cpp.

181 {
183 }
const FileDef * fileScope() const

References fileScope(), and m_fileScope.

◆ substTypedef()

QCString SymbolResolver::Private::substTypedef ( VisitedKeys & visitedKeys,
const Definition * scope,
const QCString & name,
const MemberDef ** pTypeDef = nullptr )
private

Definition at line 1605 of file symbolresolver.cpp.

1609{
1610 AUTO_TRACE("scope={} name={}",scope?scope->name():QCString(), name);
1611 QCString result=name;
1612 if (name.isEmpty()) return result;
1613
1614 auto &range = Doxygen::symbolMap->find(name);
1615 if (range.empty())
1616 return result; // no matches
1617
1618 MemberDef *bestMatch=nullptr;
1619 int minDistance=10000; // init at "infinite"
1620
1621 std::string key;
1622 const int maxAddrSize = 20;
1623 char ptr_str[maxAddrSize];
1624 int num = qsnprintf(ptr_str,maxAddrSize,"%p:",(void *)scope);
1625 assert(num>0);
1626 key.reserve(num+name.length()+1);
1627 key+=ptr_str;
1628 key+=name.str();
1629 {
1630 auto it = g_substMap.find(key);
1631 if (it!=g_substMap.end())
1632 {
1633 if (pTypeDef) *pTypeDef = it->second.second;
1634 return it->second.first;
1635 }
1636 }
1637
1638 for (Definition *d : range)
1639 {
1640 // only look at members
1641 if (d->definitionType()==Definition::TypeMember)
1642 {
1643 // that are also typedefs
1644 MemberDef *md = toMemberDef(d);
1645 if (md->isTypedef()) // d is a typedef
1646 {
1647 VisitedNamespaces visitedNamespaces;
1648 AccessStack accessStack;
1649 // test accessibility of typedef within scope.
1650 int distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,d,"");
1651 if (distance!=-1 && distance<minDistance)
1652 // definition is accessible and a better match
1653 {
1654 minDistance=distance;
1655 bestMatch = md;
1656 }
1657 }
1658 }
1659 }
1660
1661 if (bestMatch)
1662 {
1663 result = bestMatch->typeString();
1664 if (pTypeDef) *pTypeDef=bestMatch;
1665 }
1666
1667 // cache the result of the computation to give a faster answers next time, especially relevant
1668 // if `range` has many arguments (i.e. there are many symbols with the same name in different contexts)
1669 {
1670 g_substMap.emplace(key,std::make_pair(result,bestMatch));
1671 }
1672
1673 AUTO_TRACE_EXIT("result={}",result);
1674 return result;
1675}
#define qsnprintf
Definition qcstring.h:43
THREAD_LOCAL std::unordered_map< std::string, std::pair< QCString, const MemberDef * > > g_substMap

References AUTO_TRACE, AUTO_TRACE_EXIT, SymbolMap< T >::find(), g_substMap, SymbolResolver::isAccessibleFromWithExpScope(), QCString::isEmpty(), MemberDef::isTypedef(), QCString::length(), Definition::name(), qsnprintf, QCString::str(), Doxygen::symbolMap, toMemberDef(), Definition::TypeMember, and MemberDef::typeString().

Referenced by followPath().

Member Data Documentation

◆ m_fileScope

◆ m_resolvedTypedefs

std::unordered_map<std::string,const MemberDef*> SymbolResolver::Private::m_resolvedTypedefs
private

Definition at line 287 of file symbolresolver.cpp.

Referenced by newResolveTypedef(), and reset().

◆ resolvedType

QCString SymbolResolver::Private::resolvedType

Definition at line 186 of file symbolresolver.cpp.

Referenced by reset().

◆ templateSpec

QCString SymbolResolver::Private::templateSpec

Definition at line 188 of file symbolresolver.cpp.

Referenced by reset().

◆ typeDef

const MemberDef* SymbolResolver::Private::typeDef = nullptr

Definition at line 187 of file symbolresolver.cpp.

Referenced by reset().


The documentation for this struct was generated from the following file: