Doxygen
symbolresolver.cpp
浏览该文件的文档.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2020 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 
16 #include <unordered_map>
17 #include <string>
18 #include <vector>
19 
20 #include "symbolresolver.h"
21 #include "util.h"
22 #include "doxygen.h"
23 #include "namespacedef.h"
24 #include "config.h"
25 #include "defargs.h"
26 
27 static std::mutex g_cacheMutex;
28 static std::recursive_mutex g_cacheTypedefMutex;
29 
30 //--------------------------------------------------------------------------------------
31 
32 /** Helper class representing the stack of items considered while resolving
33  * the scope.
34  */
36 {
37  /** Element in the stack. */
38  struct AccessElem
39  {
40  AccessElem(const Definition *d,const FileDef *f,const Definition *i,QCString e = QCString()) : scope(d), fileScope(f), item(i), expScope(e) {}
41  const Definition *scope;
43  const Definition *item;
45  };
46  public:
47  void push(const Definition *scope,const FileDef *fileScope,const Definition *item)
48  {
49  m_elements.push_back(AccessElem(scope,fileScope,item));
50  }
51  void push(const Definition *scope,const FileDef *fileScope,const Definition *item,const QCString &expScope)
52  {
53  m_elements.push_back(AccessElem(scope,fileScope,item,expScope));
54  }
55  void pop()
56  {
57  if (!m_elements.empty()) m_elements.pop_back();
58  }
59  bool find(const Definition *scope,const FileDef *fileScope, const Definition *item)
60  {
61  auto it = std::find_if(m_elements.begin(),m_elements.end(),
62  [&](const AccessElem &e) { return e.scope==scope && e.fileScope==fileScope && e.item==item; });
63  return it!=m_elements.end();
64  }
65  bool find(const Definition *scope,const FileDef *fileScope, const Definition *item,const QCString &expScope)
66  {
67  auto it = std::find_if(m_elements.begin(),m_elements.end(),
68  [&](const AccessElem &e) { return e.scope==scope && e.fileScope==fileScope && e.item==item && e.expScope==expScope; });
69  return it!=m_elements.end();
70  }
71  void clear()
72  {
73  m_elements.clear();
74  }
75 
76  private:
77  std::vector<AccessElem> m_elements;
78 };
79 
80 //--------------------------------------------------------------------------------------
81 
82 using VisitedNamespaces = std::unordered_map<std::string,const Definition *>;
83 
84 //--------------------------------------------------------------------------------------
85 
87 {
88  public:
89  Private(const FileDef *f) : m_fileScope(f) {}
90  void reset()
91  {
92  m_resolvedTypedefs.clear();
94  typeDef = 0;
96  }
97  void setFileScope(const FileDef *fileScope)
98  {
99  m_fileScope = fileScope;
100  }
101 
103  const MemberDef *typeDef = 0;
105 
107  const Definition *scope, // in
108  const QCString &n, // in
109  const MemberDef **pTypeDef, // out
110  QCString *pTemplSpec, // out
111  QCString *pResolvedType); // out
112 
113  int isAccessibleFrom( AccessStack &accessStack,
114  const Definition *scope,
115  const Definition *item);
116 
118  VisitedNamespaces &visitedNamespaces,
119  AccessStack &accessStack,
120  const Definition *scope,
121  const Definition *item,
122  const QCString &explicitScopePart);
123 
124  private:
125  void getResolvedSymbol(const Definition *scope, // in
126  const Definition *d, // in
127  const QCString &explicitScopePart, // in
128  const std::unique_ptr<ArgumentList> &actTemplParams, // in
129  int &minDistance, // input
130  const ClassDef *&bestMatch, // out
131  const MemberDef *&bestTypedef, // out
132  QCString &bestTemplSpec, // out
133  QCString &bestResolvedType // out
134  );
135 
137  const Definition *scope, // in
138  const MemberDef *md, // in
139  const MemberDef **pMemType, // out
140  QCString *pTemplSpec, // out
141  QCString *pResolvedType, // out
142  const std::unique_ptr<ArgumentList> &actTemplParams = std::unique_ptr<ArgumentList>()
143  );
144 
145  const Definition *followPath(const Definition *start,const QCString &path);
146 
148 
151  const Definition *item,
152  const QCString &explicitScopePart="");
154  const Definition *item,
155  const QCString &explicitScopePart=""
156  );
157  QCString substTypedef(const Definition *scope,const QCString &name,
158  const MemberDef **pTypeDef=0);
159 
161  std::unordered_map<std::string,const MemberDef*> m_resolvedTypedefs;
162 };
163 
164 
165 
167  const Definition *scope,
168  const QCString &n,
169  const MemberDef **pTypeDef,
170  QCString *pTemplSpec,
171  QCString *pResolvedType)
172 {
173  if (n.isEmpty()) return 0;
174  //static int level=0;
175  //fprintf(stderr,"%d [getResolvedClassRec(%s,%s)\n",level++,scope?qPrint(scope->name()):"<global>",n);
176  QCString name;
177  QCString explicitScopePart;
178  QCString strippedTemplateParams;
181  &strippedTemplateParams);
182  std::unique_ptr<ArgumentList> actTemplParams;
183  if (!strippedTemplateParams.isEmpty()) // template part that was stripped
184  {
185  actTemplParams = stringToArgumentList(scope->getLanguage(),strippedTemplateParams);
186  }
187 
188  int qualifierIndex = computeQualifiedIndex(name);
189  //printf("name=%s qualifierIndex=%d\n",qPrint(name),qualifierIndex);
190  if (qualifierIndex!=-1) // qualified name
191  {
192  // split off the explicit scope part
193  explicitScopePart=name.left(qualifierIndex);
194  // todo: improve namespace alias substitution
195  replaceNamespaceAliases(explicitScopePart,explicitScopePart.length());
196  name=name.mid(qualifierIndex+2);
197  }
198 
199  if (name.isEmpty())
200  {
201  //fprintf(stderr,"%d ] empty name\n",--level);
202  return 0; // empty name
203  }
204 
205  //printf("Looking for symbol %s\n",qPrint(name));
206  auto range = Doxygen::symbolMap->find(name);
207  // the -g (for C# generics) and -p (for ObjC protocols) are now already
208  // stripped from the key used in the symbolMap, so that is not needed here.
209  if (range.first==range.second)
210  {
211  range = Doxygen::symbolMap->find(name+"-p");
212  if (range.first==range.second)
213  {
214  //fprintf(stderr,"%d ] no such symbol!\n",--level);
215  return 0;
216  }
217  }
218  //printf("found symbol!\n");
219 
220  bool hasUsingStatements =
223  );
224  //printf("hasUsingStatements=%d\n",hasUsingStatements);
225  // Since it is often the case that the same name is searched in the same
226  // scope over an over again (especially for the linked source code generation)
227  // we use a cache to collect previous results. This is possible since the
228  // result of a lookup is deterministic. As the key we use the concatenated
229  // scope, the name to search for and the explicit scope prefix. The speedup
230  // achieved by this simple cache can be enormous.
231  int scopeNameLen = scope->name().length()+1;
232  int nameLen = name.length()+1;
233  int explicitPartLen = explicitScopePart.length();
234  int fileScopeLen = hasUsingStatements ? 1+m_fileScope->absFilePath().length() : 0;
235 
236  // below is a more efficient coding of
237  // QCString key=scope->name()+"+"+name+"+"+explicitScopePart;
238  QCString key(scopeNameLen+nameLen+explicitPartLen+fileScopeLen+1);
239  char *pk=key.rawData();
240  qstrcpy(pk,scope->name().data()); *(pk+scopeNameLen-1)='+';
241  pk+=scopeNameLen;
242  qstrcpy(pk,name.data()); *(pk+nameLen-1)='+';
243  pk+=nameLen;
244  qstrcpy(pk,explicitScopePart.data());
245  pk+=explicitPartLen;
246 
247  // if a file scope is given and it contains using statements we should
248  // also use the file part in the key (as a class name can be in
249  // two different namespaces and a using statement in a file can select
250  // one of them).
251  if (hasUsingStatements)
252  {
253  // below is a more efficient coding of
254  // key+="+"+m_fileScope->name();
255  *pk++='+';
257  pk+=fileScopeLen-1;
258  }
259  *pk='\0';
260 
261  LookupInfo *pval = 0;
262  {
263  std::lock_guard<std::mutex> lock(g_cacheMutex);
264  pval=Doxygen::lookupCache->find(key.str());
265  //printf("Searching for %s result=%p\n",qPrint(key),pval);
266  if (pval)
267  {
268  //printf("LookupInfo %p %p '%s' %p\n",
269  // pval->classDef, pval->typeDef, qPrint(pval->templSpec),
270  // qPrint(pval->resolvedType));
271  if (pTemplSpec) *pTemplSpec=pval->templSpec;
272  if (pTypeDef) *pTypeDef=pval->typeDef;
273  if (pResolvedType) *pResolvedType=pval->resolvedType;
274  //fprintf(stderr,"%d ] cachedMatch=%s\n",--level,
275  // pval->classDef?qPrint(pval->classDef->name()):"<none>");
276  //if (pTemplSpec)
277  // printf("templSpec=%s\n",pTemplSpec->data());
278  return pval->classDef;
279  }
280  else // not found yet; we already add a 0 to avoid the possibility of
281  // endless recursion.
282  {
283  pval = Doxygen::lookupCache->insert(key.str(),LookupInfo());
284  }
285  }
286 
287  const ClassDef *bestMatch=0;
288  const MemberDef *bestTypedef=0;
289  QCString bestTemplSpec;
290  QCString bestResolvedType;
291  int minDistance=10000; // init at "infinite"
292 
293  for (auto it=range.first ; it!=range.second; ++it)
294  {
295  Definition *d = it->second;
296  getResolvedSymbol(scope,d,explicitScopePart,actTemplParams,
297  minDistance,bestMatch,bestTypedef,bestTemplSpec,bestResolvedType);
298  }
299 
300  if (pTypeDef)
301  {
302  *pTypeDef = bestTypedef;
303  }
304  if (pTemplSpec)
305  {
306  *pTemplSpec = bestTemplSpec;
307  }
308  if (pResolvedType)
309  {
310  *pResolvedType = bestResolvedType;
311  }
312 
313  //printf("getResolvedClassRec: bestMatch=%p pval->resolvedType=%s\n",
314  // bestMatch,qPrint(bestResolvedType));
315 
316  if (pval)
317  {
318  std::lock_guard<std::mutex> lock(g_cacheMutex);
319  pval->classDef = bestMatch;
320  pval->typeDef = bestTypedef;
321  pval->templSpec = bestTemplSpec;
322  pval->resolvedType = bestResolvedType;
323  }
324  //fprintf(stderr,"%d ] bestMatch=%s distance=%d\n",--level,
325  // bestMatch?qPrint(bestMatch->name()):"<none>",minDistance);
326  //if (pTemplSpec)
327  // printf("templSpec=%s\n",pTemplSpec->data());
328  return bestMatch;
329 }
330 
332  const Definition *scope, // in
333  const Definition *d, // in
334  const QCString &explicitScopePart, // in
335  const std::unique_ptr<ArgumentList> &actTemplParams, // in
336  int &minDistance, // inout
337  const ClassDef *&bestMatch, // out
338  const MemberDef *&bestTypedef, // out
339  QCString &bestTemplSpec, // out
340  QCString &bestResolvedType // out
341  )
342 {
343  //fprintf(stderr,"getResolvedSymbol(%s,%s)\n",qPrint(scope->name()),qPrint(d->qualifiedName()));
344  // only look at classes and members that are enums or typedefs
347  ((toMemberDef(d))->isTypedef() ||
348  (toMemberDef(d))->isEnumerate())
349  )
350  )
351  {
352  VisitedNamespaces visitedNamespaces;
353  AccessStack accessStack;
354  // test accessibility of definition within scope.
355  int distance = isAccessibleFromWithExpScope(visitedNamespaces,accessStack,scope,d,explicitScopePart);
356  //fprintf(stderr," %s; distance %s (%p) is %d\n",qPrint(scope->name()),qPrint(d->name()),d,distance);
357  if (distance!=-1) // definition is accessible
358  {
359  // see if we are dealing with a class or a typedef
360  if (d->definitionType()==Definition::TypeClass) // d is a class
361  {
362  const ClassDef *cd = toClassDef(d);
363  //printf("cd=%s\n",qPrint(cd->name()));
364  if (!cd->isTemplateArgument()) // skip classes that
365  // are only there to
366  // represent a template
367  // argument
368  {
369  //printf("is not a templ arg\n");
370  if (distance<minDistance) // found a definition that is "closer"
371  {
372  minDistance=distance;
373  bestMatch = cd;
374  bestTypedef = 0;
375  bestTemplSpec.resize(0);
376  bestResolvedType = cd->qualifiedName();
377  }
378  else if (distance==minDistance &&
379  m_fileScope && bestMatch &&
380  !m_fileScope->getUsedNamespaces().empty() &&
382  bestMatch->getOuterScope()==Doxygen::globalScope
383  )
384  {
385  // in case the distance is equal it could be that a class X
386  // is defined in a namespace and in the global scope. When searched
387  // in the global scope the distance is 0 in both cases. We have
388  // to choose one of the definitions: we choose the one in the
389  // namespace if the fileScope imports namespaces and the definition
390  // found was in a namespace while the best match so far isn't.
391  // Just a non-perfect heuristic but it could help in some situations
392  // (kdecore code is an example).
393  minDistance=distance;
394  bestMatch = cd;
395  bestTypedef = 0;
396  bestTemplSpec.resize(0);
397  bestResolvedType = cd->qualifiedName();
398  }
399  }
400  else
401  {
402  //printf(" is a template argument!\n");
403  }
404  }
405  else if (d->definitionType()==Definition::TypeMember)
406  {
407  const MemberDef *md = toMemberDef(d);
408  //fprintf(stderr," member isTypedef()=%d\n",md->isTypedef());
409  if (md->isTypedef()) // d is a typedef
410  {
411  QCString args=md->argsString();
412  if (args.isEmpty()) // do not expand "typedef t a[4];"
413  {
414  //printf(" found typedef!\n");
415 
416  // we found a symbol at this distance, but if it didn't
417  // resolve to a class, we still have to make sure that
418  // something at a greater distance does not match, since
419  // that symbol is hidden by this one.
420  if (distance<minDistance)
421  {
422  QCString spec;
423  QCString type;
424  minDistance=distance;
425  const MemberDef *enumType = 0;
426  const ClassDef *cd = newResolveTypedef(scope,md,&enumType,&spec,&type,actTemplParams);
427  if (cd) // type resolves to a class
428  {
429  //printf(" bestTypeDef=%p spec=%s type=%s\n",md,qPrint(spec),qPrint(type));
430  bestMatch = cd;
431  bestTypedef = md;
432  bestTemplSpec = spec;
433  bestResolvedType = type;
434  }
435  else if (enumType) // type resolves to a member type
436  {
437  //printf(" is enum\n");
438  bestMatch = 0;
439  bestTypedef = enumType;
440  bestTemplSpec = "";
441  bestResolvedType = enumType->qualifiedName();
442  }
443  else if (md->isReference()) // external reference
444  {
445  bestMatch = 0;
446  bestTypedef = md;
447  bestTemplSpec = spec;
448  bestResolvedType = type;
449  }
450  else
451  {
452  bestMatch = 0;
453  bestTypedef = md;
454  bestTemplSpec.resize(0);
455  bestResolvedType.resize(0);
456  //printf(" no match\n");
457  }
458  }
459  else
460  {
461  //printf(" not the best match %d min=%d\n",distance,minDistance);
462  }
463  }
464  else
465  {
466  //printf(" not a simple typedef\n")
467  }
468  }
469  else if (md->isEnumerate())
470  {
471  if (distance<minDistance)
472  {
473  minDistance=distance;
474  bestMatch = 0;
475  bestTypedef = md;
476  bestTemplSpec = "";
477  bestResolvedType = md->qualifiedName();
478  }
479  }
480  }
481  } // if definition accessible
482  else
483  {
484  //printf(" Not accessible!\n");
485  }
486  } // if definition is a class or member
487  //printf(" bestMatch=%p bestResolvedType=%s\n",bestMatch,qPrint(bestResolvedType));
488 }
489 
491  const Definition *scope, // in
492  const MemberDef *md, // in
493  const MemberDef **pMemType, // out
494  QCString *pTemplSpec, // out
495  QCString *pResolvedType, // out
496  const std::unique_ptr<ArgumentList> &actTemplParams) // in
497 {
498  std::lock_guard<std::recursive_mutex> lock(g_cacheTypedefMutex);
499  //printf("newResolveTypedef(md=%p,cachedVal=%p)\n",md,md->getCachedTypedefVal());
500  bool isCached = md->isTypedefValCached(); // value already cached
501  if (isCached)
502  {
503  //printf("Already cached %s->%s [%s]\n",
504  // qPrint(md->name()),
505  // md->getCachedTypedefVal()?qPrint(md->getCachedTypedefVal()->name()):"<none>",
506  // md->getCachedResolvedTypedef()?qPrint(md->getCachedResolvedTypedef()):"<none>");
507 
508  if (pTemplSpec) *pTemplSpec = md->getCachedTypedefTemplSpec();
509  if (pResolvedType) *pResolvedType = md->getCachedResolvedTypedef();
510  return md->getCachedTypedefVal();
511  }
512  //printf("new typedef\n");
513  QCString qname = md->qualifiedName();
514  if (m_resolvedTypedefs.find(qname.str())!=m_resolvedTypedefs.end())
515  {
516  return 0; // typedef already done
517  }
518 
519  auto typedef_it = m_resolvedTypedefs.insert({qname.str(),md}).first; // put on the trace list
520 
521  const ClassDef *typeClass = md->getClassDef();
522  QCString type = md->typeString(); // get the "value" of the typedef
523  if (typeClass && typeClass->isTemplate() &&
524  actTemplParams && !actTemplParams->empty())
525  {
527  typeClass->templateArguments(),actTemplParams);
528  }
529  QCString typedefValue = type;
530  int tl=type.length();
531  int ip=tl-1; // remove * and & at the end
532  while (ip>=0 && (type.at(ip)=='*' || type.at(ip)=='&' || type.at(ip)==' '))
533  {
534  ip--;
535  }
536  type=type.left(ip+1);
537  type.stripPrefix("const "); // strip leading "const"
538  type.stripPrefix("volatile "); // strip leading "volatile"
539  type.stripPrefix("struct "); // strip leading "struct"
540  type.stripPrefix("union "); // strip leading "union"
541  int sp=0;
542  tl=type.length(); // length may have been changed
543  while (sp<tl && type.at(sp)==' ') sp++;
544  const MemberDef *memTypeDef = 0;
545  const ClassDef *result = getResolvedClassRec(md->getOuterScope(),type,
546  &memTypeDef,0,pResolvedType);
547  // if type is a typedef then return what it resolves to.
548  if (memTypeDef && memTypeDef->isTypedef())
549  {
550  result=newResolveTypedef(m_fileScope,memTypeDef,pMemType,pTemplSpec,0);
551  goto done;
552  }
553  else if (memTypeDef && memTypeDef->isEnumerate() && pMemType)
554  {
555  *pMemType = memTypeDef;
556  }
557 
558  //printf("type=%s result=%p\n",qPrint(type),result);
559  if (result==0)
560  {
561  // try unspecialized version if type is template
562  int si=type.findRev("::");
563  int i=type.find('<');
564  if (si==-1 && i!=-1) // typedef of a template => try the unspecialized version
565  {
566  if (pTemplSpec) *pTemplSpec = type.mid(i);
567  result = getResolvedClassRec(md->getOuterScope(),type.left(i),0,0,pResolvedType);
568  //printf("result=%p pRresolvedType=%s sp=%d ip=%d tl=%d\n",
569  // result,pResolvedType?pResolvedType->data():"<none>",sp,ip,tl);
570  }
571  else if (si!=-1) // A::B
572  {
573  i=type.find('<',si);
574  if (i==-1) // Something like A<T>::B => lookup A::B
575  {
576  i=type.length();
577  }
578  else // Something like A<T>::B<S> => lookup A::B, spec=<S>
579  {
580  if (pTemplSpec) *pTemplSpec = type.mid(i);
581  }
582  result = getResolvedClassRec(md->getOuterScope(),
583  stripTemplateSpecifiersFromScope(type.left(i),FALSE),0,0,pResolvedType);
584  }
585 
586  //if (result) ip=si+sp+1;
587  }
588 
589 done:
590  if (pResolvedType)
591  {
592  if (result)
593  {
594  *pResolvedType = result->qualifiedName();
595  //printf("*pResolvedType=%s\n",pResolvedType->data());
596  if (sp>0) pResolvedType->prepend(typedefValue.left(sp));
597  if (ip<tl-1) pResolvedType->append(typedefValue.right(tl-ip-1));
598  }
599  else
600  {
601  *pResolvedType = typedefValue;
602  }
603  }
604 
605  // remember computed value for next time
606  if (result && result->getDefFileName()!="<code>")
607  // this check is needed to prevent that temporary classes that are
608  // introduced while parsing code fragments are being cached here.
609  {
610  //printf("setting cached typedef %p in result %p\n",md,result);
611  //printf("==> %s (%s,%d)\n",qPrint(result->name()),qPrint(result->getDefFileName()),result->getDefLine());
612  //printf("*pResolvedType=%s\n",pResolvedType?pResolvedType->data():"<none>");
614  if (mdm)
615  {
616  mdm->cacheTypedefVal(result,
617  pTemplSpec ? *pTemplSpec : QCString(),
618  pResolvedType ? *pResolvedType : QCString()
619  );
620  }
621  }
622 
623  m_resolvedTypedefs.erase(typedef_it); // remove from the trace list
624 
625  return result;
626 }
627 
629  VisitedNamespaces &visitedNamespaces,
630  AccessStack &accessStack,
631  const Definition *scope,
632  const Definition *item,
633  const QCString &explicitScopePart)
634 {
635  if (explicitScopePart.isEmpty())
636  {
637  // handle degenerate case where there is no explicit scope.
638  return isAccessibleFrom(accessStack,scope,item);
639  }
640 
641  if (accessStack.find(scope,m_fileScope,item,explicitScopePart))
642  {
643  return -1;
644  }
645  accessStack.push(scope,m_fileScope,item,explicitScopePart);
646 
647 
648  //printf(" <isAccessibleFromWithExpScope(%s,%s,%s)\n",scope?qPrint(scope->name()):"<global>",
649  // item?qPrint(item->name()):"<none>",
650  // qPrint(explicitScopePart));
651  int result=0; // assume we found it
652  const Definition *newScope = followPath(scope,explicitScopePart);
653  if (newScope) // explicitScope is inside scope => newScope is the result
654  {
655  Definition *itemScope = item->getOuterScope();
656  //printf(" scope traversal successful %s<->%s!\n",qPrint(itemScope->name()),qPrint(newScope->name()));
657  //if (newScope && newScope->definitionType()==Definition::TypeClass)
658  //{
659  // ClassDef *cd = (ClassDef *)newScope;
660  // printf("---> Class %s: bases=%p\n",qPrint(cd->name()),cd->baseClasses());
661  //}
662  if (itemScope==newScope) // exact match of scopes => distance==0
663  {
664  //printf("> found it\n");
665  }
666  else if (itemScope && newScope &&
667  itemScope->definitionType()==Definition::TypeClass &&
668  newScope->definitionType()==Definition::TypeClass &&
669  (toClassDef(newScope))->isBaseClass(toClassDef(itemScope),TRUE,0)
670  )
671  {
672  // inheritance is also ok. Example: looking for B::I, where
673  // class A { public: class I {} };
674  // class B : public A {}
675  // but looking for B::I, where
676  // class A { public: class I {} };
677  // class B { public: class I {} };
678  // will find A::I, so we still prefer a direct match and give this one a distance of 1
679  result=1;
680 
681  //printf("scope(%s) is base class of newScope(%s)\n",
682  // qPrint(scope->name()),qPrint(newScope->name()));
683  }
684  else
685  {
686  int i=-1;
687  if (newScope->definitionType()==Definition::TypeNamespace)
688  {
689  visitedNamespaces.insert({newScope->name().str(),newScope});
690  // this part deals with the case where item is a class
691  // A::B::C but is explicit referenced as A::C, where B is imported
692  // in A via a using directive.
693  //printf("newScope is a namespace: %s!\n",qPrint(newScope->name()));
694  const NamespaceDef *nscope = toNamespaceDef(newScope);
695  for (const auto &cd : nscope->getUsedClasses())
696  {
697  //printf("Trying for class %s\n",qPrint(cd->name()));
698  if (cd==item)
699  {
700  goto done;
701  }
702  }
703  for (const auto &nd : nscope->getUsedNamespaces())
704  {
705  if (visitedNamespaces.find(nd->name().str())==visitedNamespaces.end())
706  {
707  //printf("Trying for namespace %s\n",qPrint(nd->name()));
708  i = isAccessibleFromWithExpScope(visitedNamespaces,accessStack,scope,item,nd->name());
709  if (i!=-1)
710  {
711  //printf("> found via explicit scope of used namespace\n");
712  goto done;
713  }
714  }
715  }
716  }
717  // repeat for the parent scope
718  if (scope!=Doxygen::globalScope)
719  {
720  i = isAccessibleFromWithExpScope(visitedNamespaces,accessStack,scope->getOuterScope(),item,explicitScopePart);
721  }
722  //printf(" | result=%d\n",i);
723  result = (i==-1) ? -1 : i+2;
724  }
725  }
726  else // failed to resolve explicitScope
727  {
728  //printf(" failed to resolve: scope=%s\n",qPrint(scope->name()));
730  {
731  const NamespaceDef *nscope = toNamespaceDef(scope);
732  StringUnorderedSet visited;
733  if (accessibleViaUsingNamespace(visited,nscope->getUsedNamespaces(),item,explicitScopePart))
734  {
735  //printf("> found in used namespace\n");
736  goto done;
737  }
738  }
739  if (scope==Doxygen::globalScope)
740  {
741  if (m_fileScope)
742  {
743  StringUnorderedSet visited;
744  if (accessibleViaUsingNamespace(visited,m_fileScope->getUsedNamespaces(),item,explicitScopePart))
745  {
746  //printf("> found in used namespace\n");
747  goto done;
748  }
749  }
750  //printf("> not found\n");
751  result=-1;
752  }
753  else // continue by looking into the parent scope
754  {
755  int i=isAccessibleFromWithExpScope(visitedNamespaces,accessStack,scope->getOuterScope(),item,explicitScopePart);
756  //printf("> result=%d\n",i);
757  result= (i==-1) ? -1 : i+2;
758  }
759  }
760 
761 done:
762  //printf(" > result=%d\n",result);
763  accessStack.pop();
764  return result;
765 }
766 
768 {
769  int is,ps;
770  int l;
771  const Definition *current=start;
772  ps=0;
773  //printf("followPath: start='%s' path='%s'\n",start?qPrint(start->name()):"<none>",qPrint(path));
774  // for each part of the explicit scope
775  while ((is=getScopeFragment(path,ps,&l))!=-1)
776  {
777  // try to resolve the part if it is a typedef
778  const MemberDef *memTypeDef=0;
779  QCString qualScopePart = substTypedef(current,path.mid(is,l),&memTypeDef);
780  //printf(" qualScopePart=%s\n",qPrint(qualScopePart));
781  if (memTypeDef)
782  {
783  const ClassDef *type = newResolveTypedef(m_fileScope,memTypeDef,0,0,0);
784  if (type)
785  {
786  //printf("Found type %s\n",qPrint(type->name()));
787  return type;
788  }
789  }
790  const Definition *next = current->findInnerCompound(qualScopePart);
791  //printf("++ Looking for %s inside %s result %s\n",
792  // qPrint(qualScopePart),
793  // qPrint(current->name()),
794  // next?qPrint(next->name()):"<null>");
795  if (next==0) // failed to follow the path
796  {
797  //printf("==> next==0!\n");
799  {
800  next = endOfPathIsUsedClass(
801  (toNamespaceDef(current))->getUsedClasses(),qualScopePart);
802  }
803  else if (current->definitionType()==Definition::TypeFile)
804  {
805  next = endOfPathIsUsedClass(
806  (toFileDef(current))->getUsedClasses(),qualScopePart);
807  }
808  current = next;
809  if (current==0) break;
810  }
811  else // continue to follow scope
812  {
813  current = next;
814  //printf("==> current = %p\n",current);
815  }
816  ps=is+l;
817  }
818  //printf("followPath(start=%s,path=%s) result=%s\n",
819  // qPrint(start->name()),qPrint(path),current?qPrint(current->name()):"<null>");
820  return current; // path could be followed
821 }
822 
824 {
825  for (const auto &cd : cl)
826  {
827  if (cd->localName()==localName)
828  {
829  return cd;
830  }
831  }
832  return 0;
833 }
834 
837  const Definition *item,
838  const QCString &explicitScopePart)
839 {
840  for (const auto &und : nl) // check used namespaces for the class
841  {
842  //printf("[Trying via used namespace %s: count=%d/%d\n",qPrint(und->name()),
843  // count,nl->count());
844  const Definition *sc = explicitScopePart.isEmpty() ? und : followPath(und,explicitScopePart);
845  if (sc && item->getOuterScope()==sc)
846  {
847  //printf("] found it\n");
848  return true;
849  }
850  if (item->getLanguage()==SrcLangExt_Cpp)
851  {
852  QCString key=und->name();
853  if (!und->getUsedNamespaces().empty() && visited.find(key.str())==visited.end())
854  {
855  visited.insert(key.str());
856 
857  if (accessibleViaUsingNamespace(visited,und->getUsedNamespaces(),item,explicitScopePart))
858  {
859  //printf("] found it via recursion\n");
860  return true;
861  }
862 
863  visited.erase(key.str());
864  }
865  }
866  //printf("] Try via used namespace done\n");
867  }
868  return false;
869 }
870 
871 
873  const Definition *item,
874  const QCString &explicitScopePart)
875 {
876  for (const auto &ucd : cl)
877  {
878  //printf("Trying via used class %s\n",qPrint(ucd->name()));
879  const Definition *sc = explicitScopePart.isEmpty() ? ucd : followPath(ucd,explicitScopePart);
880  if (sc && sc==item) return true;
881  //printf("Try via used class done\n");
882  }
883  return false;
884 }
885 
887  const Definition *scope,
888  const Definition *item)
889 {
890  //printf("<isAccessibleFrom(scope=%s,item=%s itemScope=%s)\n",
891  // qPrint(scope->name()),qPrint(item->name()),qPrint(item->getOuterScope()->name()));
892 
893  if (accessStack.find(scope,m_fileScope,item))
894  {
895  return -1;
896  }
897  accessStack.push(scope,m_fileScope,item);
898 
899  int result=0; // assume we found it
900  int i;
901 
902  Definition *itemScope=item->getOuterScope();
903  bool memberAccessibleFromScope =
904  (item->definitionType()==Definition::TypeMember && // a member
905  itemScope && itemScope->definitionType()==Definition::TypeClass && // of a class
906  scope->definitionType()==Definition::TypeClass && // accessible
907  (toClassDef(scope))->isAccessibleMember(toMemberDef(item)) // from scope
908  );
909  bool nestedClassInsideBaseClass =
910  (item->definitionType()==Definition::TypeClass && // a nested class
911  itemScope && itemScope->definitionType()==Definition::TypeClass && // inside a base
912  scope->definitionType()==Definition::TypeClass && // class of scope
913  (toClassDef(scope))->isBaseClass(toClassDef(itemScope),TRUE)
914  );
915 
916  if (itemScope==scope || memberAccessibleFromScope || nestedClassInsideBaseClass)
917  {
918  //printf("> found it\n");
919  if (nestedClassInsideBaseClass) result++; // penalty for base class to prevent
920  // this is preferred over nested class in this class
921  // see bug 686956
922  }
923  else if (scope==Doxygen::globalScope)
924  {
925  if (m_fileScope)
926  {
927  if (accessibleViaUsingClass(m_fileScope->getUsedClasses(),item))
928  {
929  //printf("> found via used class\n");
930  goto done;
931  }
932  StringUnorderedSet visited;
933  if (accessibleViaUsingNamespace(visited,m_fileScope->getUsedNamespaces(),item))
934  {
935  //printf("> found via used namespace\n");
936  goto done;
937  }
938  }
939  //printf("> reached global scope\n");
940  result=-1; // not found in path to globalScope
941  }
942  else // keep searching
943  {
944  // check if scope is a namespace, which is using other classes and namespaces
946  {
947  const NamespaceDef *nscope = toNamespaceDef(scope);
948  //printf(" %s is namespace with %d used classes\n",qPrint(nscope->name()),nscope->getUsedClasses());
949  if (accessibleViaUsingClass(nscope->getUsedClasses(),item))
950  {
951  //printf("> found via used class\n");
952  goto done;
953  }
954  StringUnorderedSet visited;
955  if (accessibleViaUsingNamespace(visited,nscope->getUsedNamespaces(),item))
956  {
957  //printf("> found via used namespace\n");
958  goto done;
959  }
960  }
961  // repeat for the parent scope
962  i=isAccessibleFrom(accessStack,scope->getOuterScope(),item);
963  //printf("> result=%d\n",i);
964  result= (i==-1) ? -1 : i+2;
965  }
966 done:
967  accessStack.pop();
968  return result;
969 }
970 
972  const Definition *scope,const QCString &name,
973  const MemberDef **pTypeDef)
974 {
975  QCString result=name;
976  if (name.isEmpty()) return result;
977 
978  auto range = Doxygen::symbolMap->find(name);
979  if (range.first==range.second)
980  return result; // no matches
981 
982  MemberDef *bestMatch=0;
983  int minDistance=10000; // init at "infinite"
984 
985  for (auto it = range.first; it!=range.second; ++it)
986  {
987  Definition *d = it->second;
988  // only look at members
990  {
991  // that are also typedefs
992  MemberDef *md = toMemberDef(d);
993  if (md->isTypedef()) // d is a typedef
994  {
995  VisitedNamespaces visitedNamespaces;
996  AccessStack accessStack;
997  // test accessibility of typedef within scope.
998  int distance = isAccessibleFromWithExpScope(visitedNamespaces,accessStack,scope,d,"");
999  if (distance!=-1 && distance<minDistance)
1000  // definition is accessible and a better match
1001  {
1002  minDistance=distance;
1003  bestMatch = md;
1004  }
1005  }
1006  }
1007  }
1008 
1009  if (bestMatch)
1010  {
1011  result = bestMatch->typeString();
1012  if (pTypeDef) *pTypeDef=bestMatch;
1013  }
1014 
1015  //printf("substTypedef(%s,%s)=%s\n",scope?qPrint(scope->name()):"<global>",
1016  // qPrint(name),qPrint(result));
1017  return result;
1018 }
1019 
1020 //----------------------------------------------------------------------------------------------
1021 
1022 
1024  : p(std::make_unique<Private>(fileScope))
1025 {
1026 }
1027 
1029 {
1030 }
1031 
1032 
1034  const QCString &name,
1035  bool mayBeUnlinkable,
1036  bool mayBeHidden)
1037 {
1038  p->reset();
1039 
1040  if (scope==0 ||
1043  ) ||
1044  (scope->getLanguage()==SrcLangExt_Java && QCString(name).find("::")!=-1)
1045  )
1046  {
1047  scope=Doxygen::globalScope;
1048  }
1049  //fprintf(stderr,"------------ resolveClass(scope=%s,name=%s,mayUnlinkable=%d)\n",
1050  // scope?qPrint(scope->name()):"<global>",
1051  // name,
1052  // mayBeUnlinkable
1053  // );
1054  const ClassDef *result;
1055  if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
1056  {
1057  result = getClass(name);
1058  }
1059  else
1060  {
1061  result = p->getResolvedClassRec(scope,name,&p->typeDef,&p->templateSpec,&p->resolvedType);
1062  if (result==0) // for nested classes imported via tag files, the scope may not
1063  // present, so we check the class name directly as well.
1064  // See also bug701314
1065  {
1066  result = getClass(name);
1067  }
1068  }
1069  if (!mayBeUnlinkable && result && !result->isLinkable())
1070  {
1071  if (!mayBeHidden || !result->isHidden())
1072  {
1073  //printf("result was %s\n",result?qPrint(result->name()):"<none>");
1074  result=0; // don't link to artificial/hidden classes unless explicitly allowed
1075  }
1076  }
1077  //fprintf(stderr,"ResolvedClass(%s,%s)=%s\n",scope?qPrint(scope->name()):"<global>",
1078  // name,result?qPrint(result->name()):"<none>");
1079  return result;
1080 }
1081 
1083 {
1084  p->reset();
1085  AccessStack accessStack;
1086  return p->isAccessibleFrom(accessStack,scope,item);
1087 }
1088 
1090  const QCString &explicitScopePart)
1091 {
1092  p->reset();
1093  VisitedNamespaces visitedNamespaces;
1094  AccessStack accessStack;
1095  return p->isAccessibleFromWithExpScope(visitedNamespaces,accessStack,scope,item,explicitScopePart);
1096 }
1097 
1099 {
1100  p->setFileScope(fileScope);
1101 }
1102 
1104 {
1105  return p->typeDef;
1106 }
1107 
1109 {
1110  return p->templateSpec;
1111 }
1112 
1114 {
1115  return p->resolvedType;
1116 }
1117 
AccessStack
Helper class representing the stack of items considered while resolving the scope.
Definition: symbolresolver.cpp:35
LinkedRefMap::empty
bool empty() const
Definition: linkedmap.h:374
MemberDef::isTypedef
virtual bool isTypedef() const =0
SymbolResolver::Private::getResolvedClassRec
const ClassDef * getResolvedClassRec(const Definition *scope, const QCString &n, const MemberDef **pTypeDef, QCString *pTemplSpec, QCString *pResolvedType)
Definition: symbolresolver.cpp:166
LinkedRefMap< const ClassDef >
SymbolResolver::getTemplateSpec
QCString getTemplateSpec() const
In case a call to resolveClass() points to a template specialization, the template part is return via...
Definition: symbolresolver.cpp:1108
SymbolResolver::setFileScope
void setFileScope(const FileDef *fd)
Sets or updates the file scope using when resolving symbols.
Definition: symbolresolver.cpp:1098
NamespaceDef::getUsedNamespaces
virtual LinkedRefMap< const NamespaceDef > getUsedNamespaces() const =0
toMemberDefMutable
MemberDefMutable * toMemberDefMutable(Definition *d)
Definition: memberdef.cpp:6125
QCString::rawData
char * rawData()
Returns a writable pointer to the data.
Definition: qcstring.h:157
AccessStack::AccessElem::expScope
QCString expScope
Definition: symbolresolver.cpp:44
MemberDef::argsString
virtual QCString argsString() const =0
Definition::TypeMember
@ TypeMember
Definition: definition.h:90
Definition
The common base class of all entity definitions found in the sources.
Definition: definition.h:76
NamespaceDef
An abstract interface of a namespace symbol.
Definition: namespacedef.h:54
SymbolResolver::Private::substTypedef
QCString substTypedef(const Definition *scope, const QCString &name, const MemberDef **pTypeDef=0)
Definition: symbolresolver.cpp:971
MemberDefMutable::cacheTypedefVal
virtual void cacheTypedefVal(const ClassDef *val, const QCString &templSpec, const QCString &resolvedType)=0
SymbolResolver::Private::followPath
const Definition * followPath(const Definition *start, const QCString &path)
Definition: symbolresolver.cpp:767
substituteTemplateArgumentsInString
QCString substituteTemplateArgumentsInString(const QCString &nm, const ArgumentList &formalArgs, const std::unique_ptr< ArgumentList > &actualArgs)
Definition: util.cpp:4477
SymbolResolver::isAccessibleFromWithExpScope
int isAccessibleFromWithExpScope(const Definition *scope, const Definition *item, const QCString &explicitScopePart)
Check if symbol item is accessible from within scope, where it has to match the explicitScopePart.
Definition: symbolresolver.cpp:1089
QCString::length
uint length() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:147
LookupInfo::resolvedType
QCString resolvedType
Definition: doxygen.h:66
QCString::findRev
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition: qcstring.cpp:86
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
Definition::findInnerCompound
virtual const Definition * findInnerCompound(const QCString &name) const =0
namespacedef.h
SymbolResolver::Private::isAccessibleFrom
int isAccessibleFrom(AccessStack &accessStack, const Definition *scope, const Definition *item)
Definition: symbolresolver.cpp:886
qstrcpy
char * qstrcpy(char *dst, const char *src)
Definition: qcstring.h:71
AccessStack::push
void push(const Definition *scope, const FileDef *fileScope, const Definition *item, const QCString &expScope)
Definition: symbolresolver.cpp:51
AccessStack::AccessElem::scope
const Definition * scope
Definition: symbolresolver.cpp:41
toMemberDef
MemberDef * toMemberDef(Definition *d)
Definition: memberdef.cpp:6088
SymbolResolver::~SymbolResolver
~SymbolResolver()
Definition: symbolresolver.cpp:1028
FileDef::getUsedClasses
virtual LinkedRefMap< const ClassDef > getUsedClasses() const =0
AccessStack::clear
void clear()
Definition: symbolresolver.cpp:71
Doxygen::globalScope
static NamespaceDefMutable * globalScope
Definition: doxygen.h:102
stripTemplateSpecifiersFromScope
QCString stripTemplateSpecifiersFromScope(const QCString &fullName, bool parentOnly, QCString *pLastScopeStripped)
Definition: util.cpp:4605
SymbolResolver::Private::endOfPathIsUsedClass
const Definition * endOfPathIsUsedClass(LinkedRefMap< const ClassDef > cl, const QCString &localName)
Definition: symbolresolver.cpp:823
QCString::str
std::string str() const
Definition: qcstring.h:442
LookupInfo::templSpec
QCString templSpec
Definition: doxygen.h:65
Definition::isHidden
virtual bool isHidden() const =0
SymbolResolver::Private::isAccessibleFromWithExpScope
int isAccessibleFromWithExpScope(VisitedNamespaces &visitedNamespaces, AccessStack &accessStack, const Definition *scope, const Definition *item, const QCString &explicitScopePart)
Definition: symbolresolver.cpp:628
SymbolResolver::Private::typeDef
const MemberDef * typeDef
Definition: symbolresolver.cpp:103
SrcLangExt_Java
@ SrcLangExt_Java
Definition: types.h:45
QCString::at
char & at(size_t i)
Returns a reference to the character at index i.
Definition: qcstring.h:477
VisitedNamespaces
std::unordered_map< std::string, const Definition * > VisitedNamespaces
Definition: symbolresolver.cpp:82
QCString::find
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:38
MemberDefMutable
Definition: memberdef.h:296
getClass
ClassDef * getClass(const QCString &n)
Definition: classdef.cpp:4974
SymbolResolver::Private::newResolveTypedef
const ClassDef * newResolveTypedef(const Definition *scope, const MemberDef *md, const MemberDef **pMemType, QCString *pTemplSpec, QCString *pResolvedType, const std::unique_ptr< ArgumentList > &actTemplParams=std::unique_ptr< ArgumentList >())
Definition: symbolresolver.cpp:490
Definition::getLanguage
virtual SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
Doxygen::symbolMap
static SymbolMap< Definition > * symbolMap
Definition: doxygen.h:106
FileDef::getUsedNamespaces
virtual LinkedRefMap< const NamespaceDef > getUsedNamespaces() const =0
SymbolMap::find
std::pair< const_iterator, const_iterator > find(const QCString &name) const
Find the list of symbols stored under key name Returns a pair of iterators pointing to the start and ...
Definition: symbolmap.h:69
StringUnorderedSet
std::unordered_set< std::string > StringUnorderedSet
Definition: containers.h:28
SymbolResolver::Private::templateSpec
QCString templateSpec
Definition: symbolresolver.cpp:104
MemberDef::isTypedefValCached
virtual bool isTypedefValCached() const =0
AccessStack::AccessElem::AccessElem
AccessElem(const Definition *d, const FileDef *f, const Definition *i, QCString e=QCString())
Definition: symbolresolver.cpp:40
Definition::qualifiedName
virtual QCString qualifiedName() const =0
NamespaceDef::getUsedClasses
virtual LinkedRefMap< const ClassDef > getUsedClasses() const =0
MemberDef
A model of a class/file/namespace member symbol.
Definition: memberdef.h:45
SymbolResolver::SymbolResolver
SymbolResolver(const FileDef *fileScope=0)
Definition: symbolresolver.cpp:1023
Definition::TypeNamespace
@ TypeNamespace
Definition: definition.h:89
ClassDef
A abstract class representing of a compound symbol.
Definition: classdef.h:103
MemberDef::getCachedTypedefVal
virtual const ClassDef * getCachedTypedefVal() const =0
QCString::left
QCString left(size_t len) const
Definition: qcstring.h:212
QCString::insert
QCString & insert(size_t index, const QCString &s)
Definition: qcstring.h:274
SymbolResolver::p
std::unique_ptr< Private > p
Definition: symbolresolver.h:101
SymbolResolver::Private::resolvedType
QCString resolvedType
Definition: symbolresolver.cpp:102
Definition::TypeFile
@ TypeFile
Definition: definition.h:88
AccessStack::pop
void pop()
Definition: symbolresolver.cpp:55
AccessStack::push
void push(const Definition *scope, const FileDef *fileScope, const Definition *item)
Definition: symbolresolver.cpp:47
MemberDef::isReference
virtual bool isReference() const =0
removeRedundantWhiteSpace
QCString removeRedundantWhiteSpace(const QCString &s)
Definition: util.cpp:544
Cache::insert
V * insert(const K &key, V &&value)
Inserts value under key in the cache
Definition: cache.h:56
SymbolResolver::isAccessibleFrom
int isAccessibleFrom(const Definition *scope, const Definition *item)
Checks if symbol item is accessible from within scope.
Definition: symbolresolver.cpp:1082
Definition::name
virtual QCString name() const =0
SrcLangExt_Cpp
@ SrcLangExt_Cpp
Definition: types.h:50
doxygen.h
AccessStack::AccessElem
Element in the stack.
Definition: symbolresolver.cpp:38
MemberDef::getClassDef
virtual const ClassDef * getClassDef() const =0
computeQualifiedIndex
int computeQualifiedIndex(const QCString &name)
Definition: util.cpp:486
symbolresolver.h
defargs.h
TRUE
#define TRUE
Definition: qcstring.h:36
SymbolResolver::getTypedef
const MemberDef * getTypedef() const
In case a call to resolveClass() resolves to a type member (e.g.
Definition: symbolresolver.cpp:1103
toClassDef
ClassDef * toClassDef(Definition *d)
Definition: classdef.cpp:4907
SymbolResolver::getResolvedType
QCString getResolvedType() const
In case a call to resolveClass() points to a typedef or using declaration.
Definition: symbolresolver.cpp:1113
SymbolResolver::Private::setFileScope
void setFileScope(const FileDef *fileScope)
Definition: symbolresolver.cpp:97
Definition::TypeClass
@ TypeClass
Definition: definition.h:87
Definition::definitionType
virtual DefType definitionType() const =0
SymbolResolver::Private::reset
void reset()
Definition: symbolresolver.cpp:90
LookupInfo::typeDef
const MemberDef * typeDef
Definition: doxygen.h:64
MemberDef::qualifiedName
virtual QCString qualifiedName() const =0
AccessStack::AccessElem::fileScope
const FileDef * fileScope
Definition: symbolresolver.cpp:42
QCString::mid
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition: qcstring.h:224
MemberDef::getCachedResolvedTypedef
virtual QCString getCachedResolvedTypedef() const =0
Config_getBool
#define Config_getBool(name)
Definition: config.h:33
QCString::append
QCString & append(char c)
Definition: qcstring.h:318
toNamespaceDef
NamespaceDef * toNamespaceDef(Definition *d)
Definition: namespacedef.cpp:1541
MemberDef::isEnumerate
virtual bool isEnumerate() const =0
Definition::getOuterScope
virtual Definition * getOuterScope() const =0
AccessStack::find
bool find(const Definition *scope, const FileDef *fileScope, const Definition *item, const QCString &expScope)
Definition: symbolresolver.cpp:65
FileDef::absFilePath
virtual QCString absFilePath() const =0
Definition::getDefFileName
virtual QCString getDefFileName() const =0
Cache::find
V * find(const K &key)
Finds a value in the cache given the corresponding key.
Definition: cache.h:99
SymbolResolver::Private::getResolvedSymbol
void getResolvedSymbol(const Definition *scope, const Definition *d, const QCString &explicitScopePart, const std::unique_ptr< ArgumentList > &actTemplParams, int &minDistance, const ClassDef *&bestMatch, const MemberDef *&bestTypedef, QCString &bestTemplSpec, QCString &bestResolvedType)
Definition: symbolresolver.cpp:331
config.h
QCString::data
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:153
SymbolResolver::Private::Private
Private(const FileDef *f)
Definition: symbolresolver.cpp:89
Doxygen::lookupCache
static Cache< std::string, LookupInfo > * lookupCache
Definition: doxygen.h:108
LookupInfo::classDef
const ClassDef * classDef
Definition: doxygen.h:63
FileDef
A model of a file symbol.
Definition: filedef.h:73
toFileDef
FileDef * toFileDef(Definition *d)
Definition: filedef.cpp:1778
SymbolResolver::Private::accessibleViaUsingNamespace
bool accessibleViaUsingNamespace(StringUnorderedSet &visited, const LinkedRefMap< const NamespaceDef > &nl, const Definition *item, const QCString &explicitScopePart="")
Definition: symbolresolver.cpp:835
g_cacheTypedefMutex
static std::recursive_mutex g_cacheTypedefMutex
Definition: symbolresolver.cpp:28
ClassDef::isTemplateArgument
virtual bool isTemplateArgument() const =0
SymbolResolver::resolveClass
const ClassDef * resolveClass(const Definition *scope, const QCString &name, bool maybeUnlinkable=false, bool mayBeHidden=false)
Find the class definition matching name within the scope set.
Definition: symbolresolver.cpp:1033
AccessStack::AccessElem::item
const Definition * item
Definition: symbolresolver.cpp:43
SymbolResolver::Private::m_resolvedTypedefs
std::unordered_map< std::string, const MemberDef * > m_resolvedTypedefs
Definition: symbolresolver.cpp:161
AccessStack::find
bool find(const Definition *scope, const FileDef *fileScope, const Definition *item)
Definition: symbolresolver.cpp:59
SymbolResolver::Private
Definition: symbolresolver.cpp:86
getScopeFragment
int getScopeFragment(const QCString &s, int p, int *l)
Definition: util.cpp:4702
util.h
A bunch of utility functions.
replaceNamespaceAliases
void replaceNamespaceAliases(QCString &scope, int i)
Definition: util.cpp:5300
MemberDef::typeString
virtual QCString typeString() const =0
ClassDef::isLinkable
virtual bool isLinkable() const =0
return TRUE iff a link to this class is possible (either within this project, or as a cross-reference...
stringToArgumentList
std::unique_ptr< ArgumentList > stringToArgumentList(SrcLangExt lang, const QCString &argsString, QCString *extraTypeChars=0)
QCString::stripPrefix
bool stripPrefix(const QCString &prefix)
Definition: qcstring.h:197
QCString::right
QCString right(size_t len) const
Definition: qcstring.h:217
QCString::prepend
QCString & prepend(const char *s)
Definition: qcstring.h:339
QCString::resize
bool resize(size_t newlen)
Resizes the string to hold newlen characters (this value should also count the 0-terminator).
Definition: qcstring.h:164
g_cacheMutex
static std::mutex g_cacheMutex
Definition: symbolresolver.cpp:27
AccessStack::m_elements
std::vector< AccessElem > m_elements
Definition: symbolresolver.cpp:77
LookupInfo
Definition: doxygen.h:58
ClassDef::templateArguments
virtual const ArgumentList & templateArguments() const =0
Returns the template arguments of this class
FALSE
#define FALSE
Definition: qcstring.h:33
SymbolResolver::Private::accessibleViaUsingClass
bool accessibleViaUsingClass(const LinkedRefMap< const ClassDef > &cl, const Definition *item, const QCString &explicitScopePart="")
Definition: symbolresolver.cpp:872
ClassDef::isTemplate
virtual bool isTemplate() const =0
Returns TRUE if this class is a template
SymbolResolver::Private::m_fileScope
const FileDef * m_fileScope
Definition: symbolresolver.cpp:160
MemberDef::getCachedTypedefTemplSpec
virtual QCString getCachedTypedefTemplSpec() const =0
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108