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 (VisitedKeys &visitedKeys, const Definition *scope, const QCString &n, const MemberDef **pTypeDef, QCString *pTemplSpec, QCString *pResolvedType)
const DefinitiongetResolvedSymbolRec (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 (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 (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 112 of file symbolresolver.cpp.

Constructor & Destructor Documentation

◆ Private()

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

Definition at line 115 of file symbolresolver.cpp.

115: 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 1350 of file symbolresolver.cpp.

1354{
1355 AUTO_TRACE("item={} explicitScopePart={}",item?item->name():QCString(), explicitScopePart);
1356 for (const auto &ud : dl)
1357 {
1358 AUTO_TRACE_ADD("trying via used definition '{}'",ud->name());
1359 const Definition *sc = explicitScopePart.isEmpty() ? ud : followPath(visitedKeys,ud,explicitScopePart);
1360 if (sc && sc==item)
1361 {
1362 AUTO_TRACE_EXIT("true");
1363 return true;
1364 }
1365 }
1366 AUTO_TRACE_EXIT("false");
1367 return false;
1368}
virtual const QCString & name() const =0
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
#define AUTO_TRACE_ADD(...)
Definition docnode.cpp:47
#define AUTO_TRACE(...)
Definition docnode.cpp:46
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
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 1312 of file symbolresolver.cpp.

1319{
1320 AUTO_TRACE("item={} explicitScopePart={} level={}",item?item->name():QCString(), explicitScopePart, level);
1321 for (const auto &und : nl) // check used namespaces for the class
1322 {
1323 AUTO_TRACE_ADD("trying via used namespace '{}'",und->name());
1324 const Definition *sc = explicitScopePart.isEmpty() ? und : followPath(visitedKeys,und,explicitScopePart);
1325 if (sc && item->getOuterScope()==sc)
1326 {
1327 AUTO_TRACE_EXIT("true");
1328 return true;
1329 }
1330 if (item->getLanguage()==SrcLangExt::Cpp)
1331 {
1332 QCString key=und->qualifiedName();
1333 if (!und->getUsedNamespaces().empty() && std::find(visitedNamespaces.begin(),visitedNamespaces.end(),key.str())==std::end(visitedNamespaces))
1334 {
1335 visitedNamespaces.push_back(key.str());
1336 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaces,und->getUsedNamespaces(),item,explicitScopePart,level+1))
1337 {
1338 AUTO_TRACE_EXIT("true");
1339 return true;
1340 }
1341
1342 }
1343 }
1344 }
1345 AUTO_TRACE_EXIT("false");
1346 return false;
1347}
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:552
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 1300 of file symbolresolver.cpp.

1301{
1302 for (const auto &d : dl)
1303 {
1304 if (d->localName()==localName)
1305 {
1306 return d;
1307 }
1308 }
1309 return nullptr;
1310}

Referenced by followPath().

◆ fileScope()

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

Definition at line 127 of file symbolresolver.cpp.

127{ 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 1195 of file symbolresolver.cpp.

1197{
1198 AUTO_TRACE("start={},path={}",start?start->name():QCString(), path);
1199 int is=0,ps=0,l=0;
1200
1201 const Definition *current=start;
1202 // for each part of the explicit scope
1203 while ((is=getScopeFragment(path,ps,&l))!=-1)
1204 {
1205 // try to resolve the part if it is a typedef
1206 const MemberDef *memTypeDef=nullptr;
1207 QCString qualScopePart = substTypedef(visitedKeys,current,path.mid(is,l),&memTypeDef);
1208 AUTO_TRACE_ADD("qualScopePart={} memTypeDef={}",qualScopePart,memTypeDef?memTypeDef->name():"");
1209 const Definition *next = nullptr;
1210 if (memTypeDef)
1211 {
1212 const ClassDef *type = newResolveTypedef(visitedKeys,m_fileScope,memTypeDef,nullptr,nullptr,nullptr);
1213 if (type)
1214 {
1215 AUTO_TRACE_EXIT("type={}",type->name());
1216 return type;
1217 }
1218 }
1219 else if (m_fileScope)
1220 {
1221 next = endOfPathIsUsedClass(m_fileScope->getUsedDefinitions(),qualScopePart);
1222 }
1223 if (next==nullptr)
1224 {
1225 next = current->findInnerCompound(qualScopePart);
1226 }
1227 AUTO_TRACE_ADD("Looking for {} inside {} result={}",
1228 qualScopePart, current->name(), next?next->name():QCString());
1229 if (next==nullptr)
1230 {
1231 next = current->findInnerCompound(qualScopePart+"-p");
1232 }
1233 if (current->definitionType()==Definition::TypeClass)
1234 {
1235 const MemberDef *classMember = toClassDef(current)->getMemberByName(qualScopePart);
1236 if (classMember && classMember->isEnumerate())
1237 {
1238 next = classMember;
1239 }
1240 }
1241 else if (current!=Doxygen::globalScope && current->definitionType()==Definition::TypeNamespace)
1242 {
1243 const MemberDef *namespaceMember = toNamespaceDef(current)->getMemberByName(qualScopePart);
1244 if (namespaceMember && namespaceMember->isEnumerate())
1245 {
1246 next = namespaceMember;
1247 }
1248 }
1249 else if (current==Doxygen::globalScope || current->definitionType()==Definition::TypeFile)
1250 {
1251 auto &range = Doxygen::symbolMap->find(qualScopePart);
1252 for (Definition *def : range)
1253 {
1254 const Definition *outerScope = def->getOuterScope();
1255 if (
1256 (outerScope==Doxygen::globalScope || // global scope or
1257 (outerScope && // anonymous namespace in the global scope
1258 outerScope->name().startsWith("anonymous_namespace{") &&
1259 outerScope->getOuterScope()==Doxygen::globalScope
1260 )
1261 ) &&
1262 (def->definitionType()==Definition::TypeClass ||
1263 def->definitionType()==Definition::TypeMember ||
1264 def->definitionType()==Definition::TypeNamespace
1265 )
1266 )
1267 {
1268 next=def;
1269 break;
1270 }
1271 }
1272 }
1273 if (next==nullptr) // failed to follow the path
1274 {
1276 {
1277 next = endOfPathIsUsedClass(
1278 (toNamespaceDef(current))->getUsedDefinitions(),qualScopePart);
1279 }
1280 else if (current->definitionType()==Definition::TypeFile)
1281 {
1282 next = endOfPathIsUsedClass(
1283 (toFileDef(current))->getUsedDefinitions(),qualScopePart);
1284 }
1285 current = next;
1286 if (current==nullptr) break;
1287 }
1288 else // continue to follow scope
1289 {
1290 current = next;
1291 AUTO_TRACE_ADD("current={}",current->name());
1292 }
1293 ps=is+l;
1294 }
1295
1296 AUTO_TRACE_EXIT("result={}",current?current->name():QCString());
1297 return current; // path could be followed
1298}
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 bool isEnumerate() const =0
virtual const MemberDef * getMemberByName(const QCString &) const =0
bool startsWith(const char *s) const
Definition qcstring.h:507
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:241
const VectorPtr & find(const QCString &name)
Definition symbolmap.h:75
ClassDef * toClassDef(Definition *d)
FileDef * toFileDef(Definition *d)
Definition filedef.cpp:1954
NamespaceDef * toNamespaceDef(Definition *d)
const ClassDef * newResolveTypedef(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)
int getScopeFragment(const QCString &s, int p, int *l)
Definition util.cpp:4549

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, Definition::definitionType(), endOfPathIsUsedClass(), Definition::findInnerCompound(), ClassDef::getMemberByName(), NamespaceDef::getMemberByName(), Definition::getOuterScope(), getScopeFragment(), 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 755 of file symbolresolver.cpp.

771{
772 AUTO_TRACE("scope={} sym={}",scope->name(),d->qualifiedName());
773 // only look at classes and members that are enums or typedefs
774 VisitedNamespaces visitedNamespaces;
775 AccessStack accessStack;
776 // test accessibility of definition within scope.
777 int distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,d,explicitScopePart+strippedTemplateParams);
778 if (distance==-1 && !strippedTemplateParams.isEmpty())
779 {
780 distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,d,explicitScopePart);
781 }
782 AUTO_TRACE_ADD("distance={}",distance);
783 if (distance!=-1) // definition is accessible
784 {
785 // see if we are dealing with a class or a typedef
786 if (args.isEmpty() && !forceCallable && d->definitionType()==Definition::TypeClass) // d is a class
787 {
788 const ClassDef *cd = toClassDef(d);
789 if (!cd->isTemplateArgument()) // skip classes that
790 // are only there to
791 // represent a template
792 // argument
793 {
794 if (distance<minDistance) // found a definition that is "closer"
795 {
796 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",d->name(),distance,minDistance);
797 minDistance=distance;
798 bestMatch = d;
799 bestTypedef = nullptr;
800 bestTemplSpec.clear();
801 bestResolvedType = cd->qualifiedName();
802 }
803 else if (distance==minDistance &&
804 m_fileScope && bestMatch &&
805 !m_fileScope->getUsedNamespaces().empty() &&
808 )
809 {
810 // in case the distance is equal it could be that a class X
811 // is defined in a namespace and in the global scope. When searched
812 // in the global scope the distance is 0 in both cases. We have
813 // to choose one of the definitions: we choose the one in the
814 // namespace if the fileScope imports namespaces and the definition
815 // found was in a namespace while the best match so far isn't.
816 // Just a non-perfect heuristic but it could help in some situations
817 // (kdecore code is an example).
818 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",d->name(),distance,minDistance);
819 minDistance=distance;
820 bestMatch = d;
821 bestTypedef = nullptr;
822 bestTemplSpec.clear();
823 bestResolvedType = cd->qualifiedName();
824 }
825 }
826 else
827 {
828 AUTO_TRACE_ADD("class with template arguments");
829 }
830 }
832 {
833 const MemberDef *md = toMemberDef(d);
834
835 bool match = true;
836 AUTO_TRACE_ADD("member={} args={} isCallable()={}",md->name(),argListToString(md->argumentList()),md->isCallable());
837 if (md->isCallable() && !args.isEmpty())
838 {
839 QCString actArgs;
840 if (md->isArtificial() && md->formalTemplateArguments()) // for members of an instantiated template we need to replace
841 // the formal arguments by the actual ones before matching
842 // See issue #10640
843 {
845 }
846 else
847 {
848 actArgs = args;
849 }
850 std::unique_ptr<ArgumentList> argList = stringToArgumentList(md->getLanguage(),actArgs);
851 const ArgumentList &mdAl = md->argumentList();
852 match = matchArguments2(md->getOuterScope(),md->getFileDef(),&mdAl,
853 scope, md->getFileDef(),argList.get(),
854 checkCV,md->getLanguage());
855 AUTO_TRACE_ADD("match={}",match);
856 }
857
858 if (match && distance<minDistance)
859 {
860 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",md->name(),distance,minDistance);
861 minDistance=distance;
862 bestMatch = md;
863 bestTypedef = md;
864 bestTemplSpec = "";
865 bestResolvedType = md->qualifiedName();
866 }
867 }
871 {
872 if (distance<minDistance) // found a definition that is "closer"
873 {
874 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",d->name(),distance,minDistance);
875 minDistance=distance;
876 bestMatch = d;
877 bestTypedef = nullptr;
878 bestTemplSpec.clear();
879 bestResolvedType.clear();
880 }
881 }
882 } // if definition accessible
883 else
884 {
885 AUTO_TRACE_ADD("not accessible");
886 }
887 AUTO_TRACE_EXIT("bestMatch sym={} distance={}",
888 bestMatch?bestMatch->name():QCString("<none>"),bestResolvedType);
889}
virtual bool isTemplateArgument() const =0
virtual QCString qualifiedName() const =0
virtual bool isArtificial() 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:182
std::unique_ptr< ArgumentList > stringToArgumentList(SrcLangExt lang, const QCString &argsString, QCString *extraTypeChars=nullptr)
Definition defargs.l:809
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:759
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
QCString substituteTemplateArgumentsInString(const QCString &nm, const ArgumentList &formalArgs, const ArgumentList *actualArgs)
Definition util.cpp:4275
bool matchArguments2(const Definition *srcScope, const FileDef *srcFileScope, const ArgumentList *srcAl, const Definition *dstScope, const FileDef *dstFileScope, const ArgumentList *dstAl, bool checkCV, SrcLangExt lang)
Definition util.cpp:1956
QCString argListToString(const ArgumentList &al, bool useCanonicalType, bool showDefVals)
Definition util.cpp:1199

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, and Definition::TypeNamespace.

Referenced by getResolvedSymbolRec().

◆ getResolvedSymbolRec()

const Definition * SymbolResolver::Private::getResolvedSymbolRec ( 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 391 of file symbolresolver.cpp.

402{
403 AUTO_TRACE("scope={} name={} args={} checkCV={} insideCode={}",
404 scope->name(),n,args,checkCV,insideCode);
405 if (n.isEmpty()) return nullptr;
406 QCString explicitScopePart;
407 QCString strippedTemplateParams;
408 QCString scopeName=scope!=Doxygen::globalScope ? scope->name() : QCString();
409 QCString name=stripTemplateSpecifiersFromScope(n,TRUE,&strippedTemplateParams,scopeName);
410 std::unique_ptr<ArgumentList> actTemplParams;
411 if (!strippedTemplateParams.isEmpty()) // template part that was stripped
412 {
413 actTemplParams = stringToArgumentList(scope->getLanguage(),strippedTemplateParams);
414 }
415
416 int qualifierIndex = computeQualifiedIndex(name);
417 //printf("name=%s qualifierIndex=%d\n",qPrint(name),qualifierIndex);
418 if (qualifierIndex!=-1) // qualified name
419 {
420 // split off the explicit scope part
421 explicitScopePart=name.left(qualifierIndex);
422 // todo: improve namespace alias substitution
423 replaceNamespaceAliases(explicitScopePart);
424 name=name.mid(qualifierIndex+2);
425 }
426 AUTO_TRACE_ADD("qualifierIndex={} name={} explicitScopePart={} strippedTemplateParams={}",
427 qualifierIndex,name,explicitScopePart,strippedTemplateParams);
428
429 if (name.isEmpty())
430 {
431 AUTO_TRACE_EXIT("empty name qualifierIndex={}",qualifierIndex);
432 return nullptr; // empty name
433 }
434
435 int i=0;
436 const auto &range1 = Doxygen::symbolMap->find(name);
437 const auto &range = (range1.empty() && (i=name.find('<'))!=-1) ? Doxygen::symbolMap->find(name.left(i)) : range1;
438 if (range.empty())
439 {
440 AUTO_TRACE_ADD("no symbols with name '{}' (including unspecialized)",name);
441 return nullptr;
442 }
443 AUTO_TRACE_ADD("{} -> {} candidates",name,range.size());
444
445 bool hasUsingStatements =
446 (m_fileScope && (!m_fileScope->getUsedNamespaces().empty() ||
447 !m_fileScope->getUsedDefinitions().empty())
448 );
449 // Since it is often the case that the same name is searched in the same
450 // scope over an over again (especially for the linked source code generation)
451 // we use a cache to collect previous results. This is possible since the
452 // result of a lookup is deterministic. As the key we use the concatenated
453 // scope, the name to search for and the explicit scope prefix. The speedup
454 // achieved by this simple cache can be enormous.
455 size_t scopeNameLen = scope!=Doxygen::globalScope ? scope->name().length()+1 : 0;
456 size_t nameLen = name.length()+1;
457 size_t explicitPartLen = explicitScopePart.length();
458 size_t strippedTemplateParamsLen = strippedTemplateParams.length();
459 size_t fileScopeLen = hasUsingStatements ? 1+m_fileScope->absFilePath().length() : 0;
460 size_t argsLen = args.length()+1;
461
462 // below is a more efficient coding of
463 // QCString key=scope->name()+"+"+name+"+"+explicitScopePart+args+typesOnly?'T':'F';
464 std::string key;
465 key.reserve(scopeNameLen+nameLen+explicitPartLen+strippedTemplateParamsLen+fileScopeLen+argsLen);
466 if (scope!=Doxygen::globalScope)
467 {
468 key+=scope->name().str();
469 key+='+';
470 }
471 key+=name.str();
472 key+='+';
473 key+=explicitScopePart.str();
474 key+=strippedTemplateParams.str();
475
476 // if a file scope is given and it contains using statements we should
477 // also use the file part in the key (as a class name can be in
478 // two different namespaces and a using statement in a file can select
479 // one of them).
480 if (hasUsingStatements)
481 {
482 // below is a more efficient coding of
483 // key+="+"+m_fileScope->name();
484 key+='+';
485 key+=m_fileScope->absFilePath().str();
486 }
487 if (argsLen>0)
488 {
489 key+='+';
490 key+=args.str();
491 }
492
493 const Definition *bestMatch=nullptr;
494 {
495 if (std::find(visitedKeys.begin(),visitedKeys.end(),key)!=std::end(visitedKeys))
496 {
497 // we are already in the middle of find the definition for this key.
498 // avoid recursion
499 return nullptr;
500 }
501 // remember the key
502 visitedKeys.push_back(key);
503 LookupInfo *pval = nullptr;
504 {
505 std::lock_guard lock(g_cacheMutex);
506 pval = Doxygen::symbolLookupCache->find(key);
507 }
508 AUTO_TRACE_ADD("key={} found={}",key,pval!=nullptr);
509 if (pval)
510 {
511 if (pTemplSpec) *pTemplSpec=pval->templSpec;
512 if (pTypeDef) *pTypeDef=pval->typeDef;
513 if (pResolvedType) *pResolvedType=pval->resolvedType;
514 AUTO_TRACE_EXIT("found cached name={} templSpec={} typeDef={} resolvedTypedef={}",
515 pval->definition?pval->definition->name():QCString(),
516 pval->templSpec,
517 pval->typeDef?pval->typeDef->name():QCString(),
518 pval->resolvedType);
519 return pval->definition;
520 }
521
522 const MemberDef *bestTypedef=nullptr;
523 QCString bestTemplSpec;
524 QCString bestResolvedType;
525 int minDistance=10000; // init at "infinite"
526
527 for (Definition *d : range)
528 {
529 if (isCodeSymbol(d->definitionType()) &&
530 (!onlyLinkable ||
531 d->isLinkable() ||
532 d->isLinkableInProject() ||
533 (d->definitionType()==Definition::TypeFile &&
534 (toFileDef(d))->generateSourceFile()
535 ) // undocumented file that has source code we can link to
536 )
537 )
538 {
539 getResolvedSymbol(visitedKeys,scope,d,args,checkCV,insideCode,explicitScopePart,strippedTemplateParams,false,
540 minDistance,bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
541 }
542 if (minDistance==0) break; // we can stop reaching if we already reached distance 0
543 }
544
545 // in case we are looking for e.g. func() and the real function is func(int x) we also
546 // accept func(), see example 036 in the test set.
547 if (bestMatch==nullptr && args=="()")
548 {
549 for (Definition *d : range)
550 {
551 if (isCodeSymbol(d->definitionType()))
552 {
553 getResolvedSymbol(visitedKeys,scope,d,QCString(),false,insideCode,explicitScopePart,strippedTemplateParams,true,
554 minDistance,bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
555 }
556 if (minDistance==0) break; // we can stop reaching if we already reached distance 0
557 }
558 }
559
560 if (pTypeDef)
561 {
562 *pTypeDef = bestTypedef;
563 }
564 if (pTemplSpec)
565 {
566 *pTemplSpec = bestTemplSpec;
567 }
568 if (pResolvedType)
569 {
570 *pResolvedType = bestResolvedType;
571 }
572
573 {
574 LookupInfo lookupInfo(bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
575 std::lock_guard lock(g_cacheMutex);
576 // we need to insert the item in the cache again, as it could be removed in the meantime
577 Doxygen::symbolLookupCache->insert(key,std::move(lookupInfo));
578 }
579 visitedKeys.erase(std::remove(visitedKeys.begin(),visitedKeys.end(),key),visitedKeys.end());
580
581 AUTO_TRACE_EXIT("found name={} templSpec={} typeDef={} resolvedTypedef={}",
582 bestMatch?bestMatch->name():QCString(),
583 bestTemplSpec,
584 bestTypedef?bestTypedef->name():QCString(),
585 bestResolvedType);
586 }
587 return bestMatch;
588}
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
static Cache< std::string, LookupInfo > * symbolLookupCache
Definition doxygen.h:128
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
QCString left(size_t len) const
Definition qcstring.h:229
void replaceNamespaceAliases(QCString &name)
#define TRUE
Definition qcstring.h:37
QCString resolvedType
Definition doxygen.h:63
const Definition * definition
Definition doxygen.h:60
QCString templSpec
Definition doxygen.h:62
const MemberDef * typeDef
Definition doxygen.h:61
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)
static std::mutex g_cacheMutex
int computeQualifiedIndex(const QCString &name)
Return the index of the last :: in the string name that is still before the first <.
Definition util.cpp:6734
QCString stripTemplateSpecifiersFromScope(const QCString &fullName, bool parentOnly, QCString *pLastScopeStripped, QCString scopeName, bool allowArtificial)
Definition util.cpp:4437

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, computeQualifiedIndex(), LookupInfo::definition, QCString::find(), g_cacheMutex, Definition::getLanguage(), getResolvedSymbol(), Doxygen::globalScope, isCodeSymbol(), QCString::isEmpty(), QCString::left(), QCString::length(), m_fileScope, QCString::mid(), Definition::name(), replaceNamespaceAliases(), LookupInfo::resolvedType, QCString::size(), QCString::str(), stringToArgumentList(), stripTemplateSpecifiersFromScope(), Doxygen::symbolLookupCache, Doxygen::symbolMap, LookupInfo::templSpec, toFileDef(), TRUE, LookupInfo::typeDef, and Definition::TypeFile.

◆ getResolvedType()

void SymbolResolver::Private::getResolvedType ( 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 590 of file symbolresolver.cpp.

602{
603 AUTO_TRACE("scope={} sym={} explicitScope={}",scope->name(),d->qualifiedName(),explicitScopePart);
604 // only look at classes and members that are enums or typedefs
607 ((toMemberDef(d))->isTypedef() ||
608 (toMemberDef(d))->isEnumerate())
609 )
610 )
611 {
612 VisitedNamespaces visitedNamespaces;
613 AccessStack accessStack;
614 // test accessibility of definition within scope.
615 int distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,
616 accessStack,scope,d,explicitScopePart);
617 AUTO_TRACE_ADD("distance={}",distance);
618 if (distance!=-1) // definition is accessible
619 {
620 // see if we are dealing with a class or a typedef
621 if (d->definitionType()==Definition::TypeClass) // d is a class
622 {
623 const ClassDef *cd = toClassDef(d);
624 //printf("cd=%s\n",qPrint(cd->name()));
625 if (!cd->isTemplateArgument()) // skip classes that
626 // are only there to
627 // represent a template
628 // argument
629 {
630 //printf("is not a templ arg\n");
631 if (distance<minDistance) // found a definition that is "closer"
632 {
633 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",cd->name(),distance,minDistance);
634 minDistance=distance;
635 bestMatch = cd;
636 bestTypedef = nullptr;
637 bestTemplSpec.clear();
638 bestResolvedType = cd->qualifiedName();
639 }
640 else if (distance==minDistance &&
641 m_fileScope && bestMatch &&
642 !m_fileScope->getUsedNamespaces().empty() &&
645 )
646 {
647 // in case the distance is equal it could be that a class X
648 // is defined in a namespace and in the global scope. When searched
649 // in the global scope the distance is 0 in both cases. We have
650 // to choose one of the definitions: we choose the one in the
651 // namespace if the fileScope imports namespaces and the definition
652 // found was in a namespace while the best match so far isn't.
653 // Just a non-perfect heuristic but it could help in some situations
654 // (kdecore code is an example).
655 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",cd->name(),distance,minDistance);
656 minDistance=distance;
657 bestMatch = cd;
658 bestTypedef = nullptr;
659 bestTemplSpec.clear();
660 bestResolvedType = cd->qualifiedName();
661 }
662 }
663 else
664 {
665 //printf(" is a template argument!\n");
666 }
667 }
669 {
670 const MemberDef *md = toMemberDef(d);
671 AUTO_TRACE_ADD("member={} isTypeDef={}",md->name(),md->isTypedef());
672 if (md->isTypedef()) // d is a typedef
673 {
674 QCString args=md->argsString();
675 if (args.isEmpty()) // do not expand "typedef t a[4];"
676 {
677 // we found a symbol at this distance, but if it didn't
678 // resolve to a class, we still have to make sure that
679 // something at a greater distance does not match, since
680 // that symbol is hidden by this one.
681 if (distance<minDistance)
682 {
683 QCString spec;
684 QCString type;
685 minDistance=distance;
686 const MemberDef *enumType = nullptr;
687 const ClassDef *cd = newResolveTypedef(visitedKeys,scope,md,&enumType,&spec,&type,actTemplParams);
688 if (cd) // type resolves to a class
689 {
690 AUTO_TRACE_ADD("found symbol={} at distance={} minDistance={}",cd->name(),distance,minDistance);
691 bestMatch = cd;
692 bestTypedef = md;
693 bestTemplSpec = spec;
694 bestResolvedType = type;
695 }
696 else if (enumType) // type resolves to a member type
697 {
698 AUTO_TRACE_ADD("found enum");
699 bestMatch = nullptr;
700 bestTypedef = enumType;
701 bestTemplSpec = "";
702 bestResolvedType = enumType->qualifiedName();
703 }
704 else if (md->isReference()) // external reference
705 {
706 AUTO_TRACE_ADD("found external reference");
707 bestMatch = nullptr;
708 bestTypedef = md;
709 bestTemplSpec = spec;
710 bestResolvedType = type;
711 }
712 else
713 {
714 AUTO_TRACE_ADD("no match");
715 bestMatch = nullptr;
716 bestTypedef = md;
717 bestTemplSpec.clear();
718 bestResolvedType.clear();
719 }
720 }
721 else
722 {
723 //printf(" not the best match %d min=%d\n",distance,minDistance);
724 }
725 }
726 else
727 {
728 AUTO_TRACE_ADD("skipping complex typedef");
729 }
730 }
731 else if (md->isEnumerate())
732 {
733 if (distance<minDistance)
734 {
735 AUTO_TRACE_ADD("found enum={} at distance={} minDistance={}",md->name(),distance,minDistance);
736 minDistance=distance;
737 bestMatch = nullptr;
738 bestTypedef = md;
739 bestTemplSpec = "";
740 bestResolvedType = md->qualifiedName();
741 }
742 }
743 }
744 } // if definition accessible
745 else
746 {
747 AUTO_TRACE_ADD("not accessible");
748 }
749 } // if definition is a class or member
750 AUTO_TRACE_EXIT("bestMatch sym={} type={}",
751 bestMatch?bestMatch->name():QCString("<none>"),bestResolvedType);
752}
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 ( VisitedKeys & visitedKeys,
const Definition * scope,
const QCString & n,
const MemberDef ** pTypeDef,
QCString * pTemplSpec,
QCString * pResolvedType )

Definition at line 231 of file symbolresolver.cpp.

238{
239 AUTO_TRACE("scope={} name={}",scope->name(),n);
240 if (n.isEmpty()) return nullptr;
241 QCString explicitScopePart;
242 QCString strippedTemplateParams;
243 QCString scopeName=scope!=Doxygen::globalScope ? scope->name() : QCString();
244 QCString name=stripTemplateSpecifiersFromScope(n,TRUE,&strippedTemplateParams,scopeName);
245 std::unique_ptr<ArgumentList> actTemplParams;
246 if (!strippedTemplateParams.isEmpty()) // template part that was stripped
247 {
248 actTemplParams = stringToArgumentList(scope->getLanguage(),strippedTemplateParams);
249 }
250
251 int qualifierIndex = computeQualifiedIndex(name);
252 //printf("name=%s qualifierIndex=%d\n",qPrint(name),qualifierIndex);
253 if (qualifierIndex!=-1) // qualified name
254 {
255 // split off the explicit scope part
256 explicitScopePart=name.left(qualifierIndex);
257 // todo: improve namespace alias substitution
258 replaceNamespaceAliases(explicitScopePart);
259 name=name.mid(qualifierIndex+2);
260 }
261
262 if (name.isEmpty())
263 {
264 AUTO_TRACE_EXIT("empty name");
265 return nullptr; // empty name
266 }
267
268 auto &range = Doxygen::symbolMap->find(name);
269 if (range.empty())
270 {
271 AUTO_TRACE_EXIT("no symbol with this name");
272 return nullptr;
273 }
274
275 bool hasUsingStatements =
276 (m_fileScope && (!m_fileScope->getUsedNamespaces().empty() ||
277 !m_fileScope->getUsedDefinitions().empty())
278 );
279 // Since it is often the case that the same name is searched in the same
280 // scope over an over again (especially for the linked source code generation)
281 // we use a cache to collect previous results. This is possible since the
282 // result of a lookup is deterministic. As the key we use the concatenated
283 // scope, the name to search for and the explicit scope prefix. The speedup
284 // achieved by this simple cache can be enormous.
285 size_t scopeNameLen = scope->name().length()+1;
286 size_t nameLen = name.length()+1;
287 size_t explicitPartLen = explicitScopePart.length();
288 size_t fileScopeLen = hasUsingStatements ? 1+m_fileScope->absFilePath().length() : 0;
289
290 // below is a more efficient coding of
291 // QCString key=scope->name()+"+"+name+"+"+explicitScopePart+args+typesOnly?'T':'F';
292 QCString key(scopeNameLen+nameLen+explicitPartLen+fileScopeLen, QCString::ExplicitSize);
293 char *pk=key.rawData();
294 qstrcpy(pk,scope->name().data()); *(pk+scopeNameLen-1)='+';
295 pk+=scopeNameLen;
296 qstrcpy(pk,name.data()); *(pk+nameLen-1)='+';
297 pk+=nameLen;
298 qstrcpy(pk,explicitScopePart.data());
299 pk+=explicitPartLen;
300
301 // if a file scope is given and it contains using statements we should
302 // also use the file part in the key (as a class name can be in
303 // two different namespaces and a using statement in a file can select
304 // one of them).
305 if (hasUsingStatements)
306 {
307 // below is a more efficient coding of
308 // key+="+"+m_fileScope->name();
309 *pk++='+';
310 qstrcpy(pk,m_fileScope->absFilePath().data());
311 pk+=fileScopeLen-1;
312 }
313 *pk='\0';
314
315 const ClassDef *bestMatch=nullptr;
316 {
317 if (std::find(visitedKeys.begin(),visitedKeys.end(),key.str())!=std::end(visitedKeys))
318 {
319 // we are already in the middle of find the definition for this key.
320 // avoid recursion
321 AUTO_TRACE_EXIT("recursion detected");
322 return nullptr;
323 }
324 // remember the key
325 visitedKeys.push_back(key.str());
326
327 LookupInfo *pval = nullptr;
328 {
329 std::lock_guard lock(g_cacheMutex);
330 pval = Doxygen::typeLookupCache->find(key.str());
331 }
332 AUTO_TRACE_ADD("key={} found={}",key,pval!=nullptr);
333 if (pval)
334 {
335 if (pTemplSpec) *pTemplSpec=pval->templSpec;
336 if (pTypeDef) *pTypeDef=pval->typeDef;
337 if (pResolvedType) *pResolvedType=pval->resolvedType;
338 AUTO_TRACE_EXIT("found cached name={} templSpec={} typeDef={} resolvedTypedef={}",
339 pval->definition?pval->definition->name():QCString(),
340 pval->templSpec,
341 pval->typeDef?pval->typeDef->name():QCString(),
342 pval->resolvedType);
343
344 return toClassDef(pval->definition);
345 }
346
347 const MemberDef *bestTypedef=nullptr;
348 QCString bestTemplSpec;
349 QCString bestResolvedType;
350 int minDistance=10000; // init at "infinite"
351
352 for (Definition *d : range)
353 {
354 if (isCodeSymbol(d->definitionType()))
355 {
356 getResolvedType(visitedKeys,scope,d,explicitScopePart,actTemplParams.get(),
357 minDistance,bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
358 }
359 if (minDistance==0) break; // we can stop reaching if we already reached distance 0
360 }
361
362 if (pTypeDef)
363 {
364 *pTypeDef = bestTypedef;
365 }
366 if (pTemplSpec)
367 {
368 *pTemplSpec = bestTemplSpec;
369 }
370 if (pResolvedType)
371 {
372 *pResolvedType = bestResolvedType;
373 }
374
375 {
376 std::lock_guard lock(g_cacheMutex);
378 LookupInfo(bestMatch,bestTypedef,bestTemplSpec,bestResolvedType));
379 }
380 visitedKeys.erase(std::remove(visitedKeys.begin(), visitedKeys.end(), key.str()), visitedKeys.end());
381
382 AUTO_TRACE_EXIT("found name={} templSpec={} typeDef={} resolvedTypedef={}",
383 bestMatch?bestMatch->name():QCString(),
384 bestTemplSpec,
385 bestTypedef?bestTypedef->name():QCString(),
386 bestResolvedType);
387 }
388 return bestMatch;
389}
static Cache< std::string, LookupInfo > * typeLookupCache
Definition doxygen.h:127
@ ExplicitSize
Definition qcstring.h:146
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:172
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:61

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, computeQualifiedIndex(), QCString::data(), LookupInfo::definition, QCString::ExplicitSize, g_cacheMutex, Definition::getLanguage(), SymbolResolver::getResolvedType(), Doxygen::globalScope, 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(), TRUE, LookupInfo::typeDef, and Doxygen::typeLookupCache.

Referenced by newResolveTypedef().

◆ isAccessibleFrom()

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

Definition at line 1370 of file symbolresolver.cpp.

1374{
1375 AUTO_TRACE("scope={} item={} item.definitionType={}",
1376 scope?scope->name():QCString(), item?item->name():QCString(),
1377 item?(int)item->definitionType():-1);
1378
1379 if (accessStack.find(scope,m_fileScope,item))
1380 {
1381 AUTO_TRACE_EXIT("already processed!");
1382 return -1;
1383 }
1384 accessStack.push(scope,m_fileScope,item);
1385
1386 int result=0; // assume we found it
1387 int i=0;
1388
1389 const Definition *itemScope=item->getOuterScope();
1390 bool itemIsMember = item->definitionType()==Definition::TypeMember;
1391 bool itemIsClass = item->definitionType()==Definition::TypeClass;
1392
1393 // if item is a global member and scope points to a specific file
1394 // we adjust the scope so the file gets preference over members with the same name in
1395 // other files.
1396 if ((itemIsMember || itemIsClass) &&
1397 (itemScope==Doxygen::globalScope || // global
1398 (itemScope && itemScope->name().startsWith("anonymous_namespace{")) // member of an anonymous namespace
1399 ) &&
1401 {
1402 if (itemIsMember)
1403 {
1404 itemScope = toMemberDef(item)->getFileDef();
1405 }
1406 else if (itemIsClass)
1407 {
1408 itemScope = toClassDef(item)->getFileDef();
1409 }
1410 AUTO_TRACE_ADD("adjusting scope to {}",itemScope?itemScope->name():QCString());
1411 }
1412
1413 bool memberAccessibleFromScope =
1414 (itemIsMember && // a member
1415 itemScope && itemScope->definitionType()==Definition::TypeClass && // of a class
1416 scope->definitionType()==Definition::TypeClass && // accessible
1417 (toClassDef(scope))->isAccessibleMember(toMemberDef(item)) // from scope
1418 );
1419 bool nestedClassInsideBaseClass =
1420 (itemIsClass && // a nested class
1421 itemScope && itemScope->definitionType()==Definition::TypeClass && // inside a base
1422 scope->definitionType()==Definition::TypeClass && // class of scope
1423 (toClassDef(scope))->isBaseClass(toClassDef(itemScope),TRUE)
1424 );
1425 bool enumValueOfStrongEnum =
1426 (itemIsMember &&
1427 toMemberDef(item)->isStrongEnumValue() &&
1429 toMemberDef(scope)->isEnumerate() &&
1430 scope==toMemberDef(item)->getEnumScope()
1431 );
1432
1433 if (itemScope==scope || memberAccessibleFromScope || nestedClassInsideBaseClass || enumValueOfStrongEnum)
1434 {
1435 AUTO_TRACE_ADD("memberAccessibleFromScope={} nestedClassInsideBaseClass={} enumValueOfStrongEnum={}",
1436 memberAccessibleFromScope, nestedClassInsideBaseClass, enumValueOfStrongEnum);
1437 int distanceToBase=0;
1438 if (nestedClassInsideBaseClass)
1439 {
1440 result++; // penalty for base class to prevent
1441 // this is preferred over nested class in this class
1442 // see bug 686956
1443 }
1444 else if (memberAccessibleFromScope &&
1445 itemScope &&
1446 itemScope->definitionType()==Definition::TypeClass &&
1448 (distanceToBase=toClassDef(scope)->isBaseClass(toClassDef(itemScope),TRUE))>0
1449 )
1450 {
1451 result+=distanceToBase; // penalty if member is accessible via a base class
1452 }
1453 }
1454 else if (scope==Doxygen::globalScope)
1455 {
1456 if (itemScope &&
1458 toNamespaceDef(itemScope)->isAnonymous() &&
1459 itemScope->getOuterScope()==Doxygen::globalScope)
1460 { // item is in an anonymous namespace in the global scope and we are
1461 // looking in the global scope
1462 AUTO_TRACE_ADD("found in anonymous namespace");
1463 result++;
1464 goto done;
1465 }
1466 if (m_fileScope)
1467 {
1468 if (accessibleViaUsingDefinition(visitedKeys,m_fileScope->getUsedDefinitions(),item))
1469 {
1470 AUTO_TRACE_ADD("found via used class");
1471 goto done;
1472 }
1473 VisitedNamespaceKeys visitedNamespaceKeys;
1474 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaceKeys,m_fileScope->getUsedNamespaces(),item))
1475 {
1476 AUTO_TRACE_ADD("found via used namespace");
1477 goto done;
1478 }
1479 }
1480 AUTO_TRACE_ADD("reached global scope");
1481 result=-1; // not found in path to globalScope
1482 }
1483 else // keep searching
1484 {
1485 // check if scope is a namespace, which is using other classes and namespaces
1487 {
1488 const NamespaceDef *nscope = toNamespaceDef(scope);
1489 if (accessibleViaUsingDefinition(visitedKeys,nscope->getUsedDefinitions(),item))
1490 {
1491 AUTO_TRACE_ADD("found via used class");
1492 goto done;
1493 }
1494 VisitedNamespaceKeys visitedNamespaceKeys;
1495 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaceKeys,nscope->getUsedNamespaces(),item,QCString()))
1496 {
1497 AUTO_TRACE_ADD("found via used namespace");
1498 goto done;
1499 }
1500 }
1501 else if (scope->definitionType()==Definition::TypeFile)
1502 {
1503 const FileDef *nfile = toFileDef(scope);
1504 if (accessibleViaUsingDefinition(visitedKeys,nfile->getUsedDefinitions(),item))
1505 {
1506 AUTO_TRACE_ADD("found via used class");
1507 goto done;
1508 }
1509 VisitedNamespaceKeys visitedNamespaceKeys;
1510 if (accessibleViaUsingNamespace(visitedKeys,visitedNamespaceKeys,nfile->getUsedNamespaces(),item,QCString()))
1511 {
1512 AUTO_TRACE_ADD("found via used namespace");
1513 goto done;
1514 }
1515 }
1516 // repeat for the parent scope
1517 const Definition *parentScope = scope->getOuterScope();
1518 if (parentScope==Doxygen::globalScope)
1519 {
1521 {
1522 const FileDef *fd = toClassDef(scope)->getFileDef();
1523 if (fd)
1524 {
1525 parentScope = fd;
1526 }
1527 }
1528 }
1529 i=isAccessibleFrom(visitedKeys,accessStack,parentScope,item);
1530 result= (i==-1) ? -1 : i+2;
1531 }
1532done:
1533 AUTO_TRACE_EXIT("result={}",result);
1534 accessStack.pop();
1535 return result;
1536}
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 const LinkedRefMap< NamespaceDef > & getUsedNamespaces() const =0
virtual const LinkedRefMap< const Definition > & getUsedDefinitions() const =0
virtual bool isStrongEnumValue() const =0
virtual const MemberDef * getEnumScope() 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(), TRUE, 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 1039 of file symbolresolver.cpp.

1046{
1047 int result=0; // assume we found it
1048 AUTO_TRACE("scope={} item={} explictScopePart={}",
1049 scope?scope->name():QCString(), item?item->name():QCString(), explicitScopePart);
1050 if (explicitScopePart.isEmpty())
1051 {
1052 // handle degenerate case where there is no explicit scope.
1053 result = isAccessibleFrom(visitedKeys,accessStack,scope,item);
1054 AUTO_TRACE_EXIT("result={}",result);
1055 return result;
1056 }
1057
1058 if (accessStack.find(scope,m_fileScope,item,explicitScopePart))
1059 {
1060 AUTO_TRACE_EXIT("already found");
1061 return -1;
1062 }
1063 accessStack.push(scope,m_fileScope,item,explicitScopePart);
1064
1065 const Definition *newScope = followPath(visitedKeys,scope,explicitScopePart);
1066 if (newScope) // explicitScope is inside scope => newScope is the result
1067 {
1068 Definition *itemScope = item->getOuterScope();
1069
1070 AUTO_TRACE_ADD("scope traversal successful newScope={}",newScope->name());
1071
1072 bool nestedClassInsideBaseClass =
1073 itemScope &&
1074 itemScope->definitionType()==Definition::TypeClass &&
1076 (toClassDef(newScope))->isBaseClass(toClassDef(itemScope),TRUE);
1077
1078 bool enumValueWithinEnum =
1080 toMemberDef(item)->isEnumValue() &&
1081 toMemberDef(item)->getEnumScope()==newScope;
1082
1083 if (itemScope==newScope) // exact match of scopes => distance==0
1084 {
1085 AUTO_TRACE_ADD("found scope match");
1086 }
1087 else if (nestedClassInsideBaseClass)
1088 {
1089 // inheritance is also ok. Example: looking for B::I, where
1090 // class A { public: class I {} };
1091 // class B : public A {}
1092 // but looking for B::I, where
1093 // class A { public: class I {} };
1094 // class B { public: class I {} };
1095 // will find A::I, so we still prefer a direct match and give this one a distance of 1
1096 result=1;
1097
1098 AUTO_TRACE_ADD("{} is a bass class of {}",scope->name(),newScope->name());
1099 }
1100 else if (enumValueWithinEnum)
1101 {
1102 AUTO_TRACE_ADD("found enum value inside enum");
1103 result=1;
1104 }
1105 else
1106 {
1107 int i=-1;
1109 {
1110 visitedNamespaces.emplace(newScope->name().str(),newScope);
1111 // this part deals with the case where item is a class
1112 // A::B::C but is explicit referenced as A::C, where B is imported
1113 // in A via a using directive.
1114 //printf("newScope is a namespace: %s!\n",qPrint(newScope->name()));
1115 const NamespaceDef *nscope = toNamespaceDef(newScope);
1116 for (const auto &ud : nscope->getUsedDefinitions())
1117 {
1118 if (ud==item)
1119 {
1120 AUTO_TRACE_ADD("found in used definition {}",ud->name());
1121 goto done;
1122 }
1123 }
1124 for (const auto &nd : nscope->getUsedNamespaces())
1125 {
1126 if (visitedNamespaces.find(nd->name().str())==visitedNamespaces.end())
1127 {
1128 i = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,item,nd->name());
1129 if (i!=-1)
1130 {
1131 AUTO_TRACE_ADD("found in used namespace {}",nd->name());
1132 goto done;
1133 }
1134 }
1135 }
1136 }
1137#if 0 // this caused problems resolving A::f() in the docs when there was a A::f(int) but also a
1138 // global function f() that exactly matched the argument list.
1139 else if (isParentScope(scope,newScope) && newScope->definitionType()==Definition::TypeClass)
1140 {
1141 // if we a look for a type B and have explicit scope A, then it is also fine if B
1142 // is found at the global scope.
1143 result = 1;
1144 goto done;
1145 }
1146#endif
1147 // repeat for the parent scope
1148 if (scope!=Doxygen::globalScope)
1149 {
1150 i = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope->getOuterScope(),item,explicitScopePart);
1151 }
1152 result = (i==-1) ? -1 : i+2;
1153 }
1154 }
1155 else // failed to resolve explicitScope
1156 {
1157 AUTO_TRACE_ADD("failed to resolve explicitScope");
1159 {
1160 const NamespaceDef *nscope = toNamespaceDef(scope);
1161 VisitedNamespaceKeys locVisitedNamespaceKeys;
1162 if (accessibleViaUsingNamespace(visitedKeys,locVisitedNamespaceKeys,nscope->getUsedNamespaces(),item,explicitScopePart))
1163 {
1164 AUTO_TRACE_ADD("found in used class");
1165 goto done;
1166 }
1167 }
1168 if (scope==Doxygen::globalScope)
1169 {
1170 if (m_fileScope)
1171 {
1172 VisitedNamespaceKeys locVisitedNamespaceKeys;
1173 if (accessibleViaUsingNamespace(visitedKeys,locVisitedNamespaceKeys,m_fileScope->getUsedNamespaces(),item,explicitScopePart))
1174 {
1175 AUTO_TRACE_ADD("found in used namespace");
1176 goto done;
1177 }
1178 }
1179 AUTO_TRACE_ADD("not found in this scope");
1180 result=-1;
1181 }
1182 else // continue by looking into the parent scope
1183 {
1184 int i=isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope->getOuterScope(),item,explicitScopePart);
1185 result= (i==-1) ? -1 : i+2;
1186 }
1187 }
1188
1189done:
1190 AUTO_TRACE_EXIT("result={}",result);
1191 accessStack.pop();
1192 return result;
1193}
virtual bool isEnumValue() const =0

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(), TRUE, Definition::TypeClass, Definition::TypeMember, and Definition::TypeNamespace.

◆ newResolveTypedef()

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

Definition at line 892 of file symbolresolver.cpp.

900{
901 AUTO_TRACE("md={}",md->qualifiedName());
902 std::lock_guard<std::recursive_mutex> lock(g_cacheTypedefMutex);
903 bool isCached = md->isTypedefValCached(); // value already cached
904 if (isCached)
905 {
906 AUTO_TRACE_EXIT("cached typedef={} resolvedTypedef={} templSpec={}",
907 md->getCachedTypedefVal() ? md->getCachedTypedefVal()->name() : QCString(),
910
911 if (pTemplSpec) *pTemplSpec = md->getCachedTypedefTemplSpec();
912 if (pResolvedType) *pResolvedType = md->getCachedResolvedTypedef();
913 return md->getCachedTypedefVal();
914 }
915
916 QCString qname = md->qualifiedName();
917 if (m_resolvedTypedefs.find(qname.str())!=m_resolvedTypedefs.end())
918 {
919 AUTO_TRACE_EXIT("already being processed");
920 return nullptr; // typedef already done
921 }
922
923 auto typedef_it = m_resolvedTypedefs.emplace(qname.str(),md).first; // put on the trace list
924
925 const ClassDef *typeClass = md->getClassDef();
926 QCString type = md->typeString(); // get the "value" of the typedef
927 if (typeClass && typeClass->isTemplate() &&
928 actTemplParams && !actTemplParams->empty())
929 {
931 typeClass->templateArguments(),actTemplParams);
932 }
933 QCString typedefValue = type;
934 int tl=static_cast<int>(type.length());
935 int ip=tl-1; // remove * and & at the end
936 while (ip>=0 && (type.at(ip)=='*' || type.at(ip)=='&' || type.at(ip)==' '))
937 {
938 ip--;
939 }
940 type=type.left(ip+1);
941 type.stripPrefix("const "); // strip leading "const"
942 type.stripPrefix("volatile "); // strip leading "volatile"
943 type.stripPrefix("struct "); // strip leading "struct"
944 type.stripPrefix("union "); // strip leading "union"
945 int sp=0;
946 tl=static_cast<int>(type.length()); // length may have been changed
947 while (sp<tl && type.at(sp)==' ') sp++;
948 const MemberDef *memTypeDef = nullptr;
949 const ClassDef *result = getResolvedTypeRec(visitedKeys,md->getOuterScope(),type,
950 &memTypeDef,nullptr,pResolvedType);
951 // if type is a typedef then return what it resolves to.
952 if (memTypeDef && memTypeDef->isTypedef())
953 {
954 AUTO_TRACE_ADD("resolving typedef");
955 result=newResolveTypedef(visitedKeys,m_fileScope,memTypeDef,pMemType,pTemplSpec,nullptr);
956 goto done;
957 }
958 else if (memTypeDef && memTypeDef->isEnumerate() && pMemType)
959 {
960 *pMemType = memTypeDef;
961 }
962
963 if (result==nullptr)
964 {
965 // try unspecialized version if type is template
966 int si=type.findRev("::");
967 int i=type.find('<');
968 if (si==-1 && i!=-1) // typedef of a template => try the unspecialized version
969 {
970 if (pTemplSpec) *pTemplSpec = type.mid(i);
971 result = getResolvedTypeRec(visitedKeys,md->getOuterScope(),type.left(i),nullptr,nullptr,pResolvedType);
972 }
973 else if (si!=-1) // A::B
974 {
975 i=type.find('<',si);
976 if (i==-1) // Something like A<T>::B => lookup A::B
977 {
978 i=static_cast<int>(type.length());
979 }
980 else // Something like A<T>::B<S> => lookup A::B, spec=<S>
981 {
982 if (pTemplSpec) *pTemplSpec = type.mid(i);
983 }
984 result = getResolvedTypeRec(visitedKeys,md->getOuterScope(),
985 stripTemplateSpecifiersFromScope(type.left(i),FALSE),nullptr,nullptr,pResolvedType);
986 }
987 }
988
989done:
990 if (pResolvedType)
991 {
992 if (result && result->definitionType()==Definition::TypeClass)
993 {
994 *pResolvedType = result->qualifiedName();
995 if (sp>0) pResolvedType->prepend(typedefValue.left(sp));
996 if (ip<tl-1) pResolvedType->append(typedefValue.right(tl-ip-1));
997 }
998 else
999 {
1000 *pResolvedType = typedefValue;
1001 }
1002 }
1003
1004 // remember computed value for next time
1005 if (result && result->getDefFileName()!="<code>")
1006 // this check is needed to prevent that temporary classes that are
1007 // introduced while parsing code fragments are being cached here.
1008 {
1009 AUTO_TRACE_ADD("caching typedef relation {}->{}",md->name(),result->name());
1010 MemberDefMutable *mdm = toMemberDefMutable(const_cast<MemberDef*>(md));
1011 if (mdm)
1012 {
1013 mdm->cacheTypedefVal(result,
1014 pTemplSpec ? *pTemplSpec : QCString(),
1015 pResolvedType ? *pResolvedType : QCString()
1016 );
1017 }
1018 }
1019
1020 m_resolvedTypedefs.erase(typedef_it); // remove from the trace list
1021
1022 AUTO_TRACE_EXIT("result={} pTemplSpec={} pResolvedType={}",
1023 result ? result->name() : QCString(),
1024 pTemplSpec ? *pTemplSpec : "<nullptr>",
1025 pResolvedType ? *pResolvedType : "<nullptr>"
1026 );
1027 return result;
1028}
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 typeString() const =0
virtual QCString getCachedResolvedTypedef() const =0
virtual const ClassDef * getCachedTypedefVal() const =0
virtual const ClassDef * getClassDef() 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:422
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:593
QCString & append(char c)
Definition qcstring.h:396
QCString right(size_t len) const
Definition qcstring.h:234
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:96
bool stripPrefix(const QCString &prefix)
Definition qcstring.h:213
MemberDefMutable * toMemberDefMutable(Definition *d)
#define FALSE
Definition qcstring.h:34
const ClassDef * getResolvedTypeRec(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(), FALSE, 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 116 of file symbolresolver.cpp.

117 {
118 m_resolvedTypedefs.clear();
119 resolvedType.clear();
120 typeDef = nullptr;
121 templateSpec.clear();
122 }
const MemberDef * typeDef

References m_resolvedTypedefs, resolvedType, templateSpec, and typeDef.

◆ setFileScope()

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

Definition at line 123 of file symbolresolver.cpp.

124 {
126 }
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 1538 of file symbolresolver.cpp.

1542{
1543 AUTO_TRACE("scope={} name={}",scope?scope->name():QCString(), name);
1544 QCString result=name;
1545 if (name.isEmpty()) return result;
1546
1547 auto &range = Doxygen::symbolMap->find(name);
1548 if (range.empty())
1549 return result; // no matches
1550
1551 MemberDef *bestMatch=nullptr;
1552 int minDistance=10000; // init at "infinite"
1553
1554 std::string key;
1555 const int maxAddrSize = 20;
1556 char ptr_str[maxAddrSize];
1557 int num = qsnprintf(ptr_str,maxAddrSize,"%p:",(void *)scope);
1558 assert(num>0);
1559 key.reserve(num+name.length()+1);
1560 key+=ptr_str;
1561 key+=name.str();
1562 {
1563 std::lock_guard lock(g_substMapMutex);
1564 auto it = g_substMap.find(key);
1565 if (it!=g_substMap.end())
1566 {
1567 if (pTypeDef) *pTypeDef = it->second.second;
1568 return it->second.first;
1569 }
1570 }
1571
1572 for (Definition *d : range)
1573 {
1574 // only look at members
1575 if (d->definitionType()==Definition::TypeMember)
1576 {
1577 // that are also typedefs
1578 MemberDef *md = toMemberDef(d);
1579 if (md->isTypedef()) // d is a typedef
1580 {
1581 VisitedNamespaces visitedNamespaces;
1582 AccessStack accessStack;
1583 // test accessibility of typedef within scope.
1584 int distance = isAccessibleFromWithExpScope(visitedKeys,visitedNamespaces,accessStack,scope,d,"");
1585 if (distance!=-1 && distance<minDistance)
1586 // definition is accessible and a better match
1587 {
1588 minDistance=distance;
1589 bestMatch = md;
1590 }
1591 }
1592 }
1593 }
1594
1595 if (bestMatch)
1596 {
1597 result = bestMatch->typeString();
1598 if (pTypeDef) *pTypeDef=bestMatch;
1599 }
1600
1601 // cache the result of the computation to give a faster answers next time, especially relevant
1602 // if `range` has many arguments (i.e. there are many symbols with the same name in different contexts)
1603 {
1604 std::lock_guard lock(g_substMapMutex);
1605 g_substMap.emplace(key,std::make_pair(result,bestMatch));
1606 }
1607
1608 AUTO_TRACE_EXIT("result={}",result);
1609 return result;
1610}
#define qsnprintf
Definition qcstring.h:49
static std::mutex g_substMapMutex
static std::unordered_map< std::string, std::pair< QCString, const MemberDef * > > g_substMap

References AUTO_TRACE, AUTO_TRACE_EXIT, g_substMap, g_substMapMutex, 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 226 of file symbolresolver.cpp.

Referenced by newResolveTypedef(), and reset().

◆ resolvedType

QCString SymbolResolver::Private::resolvedType

Definition at line 129 of file symbolresolver.cpp.

Referenced by reset().

◆ templateSpec

QCString SymbolResolver::Private::templateSpec

Definition at line 131 of file symbolresolver.cpp.

Referenced by reset().

◆ typeDef

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

Definition at line 130 of file symbolresolver.cpp.

Referenced by reset().


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