Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TClingMethodInfo.cxx
Go to the documentation of this file.
1 // @(#)root/core/meta:$Id$
2 // Author: Paul Russo 30/07/2012
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TClingMethodInfo
13 Emulation of the CINT MethodInfo class.
14 
15 The CINT C++ interpreter provides an interface to metadata about
16 a function through the MethodInfo class. This class provides the
17 same functionality, using an interface as close as possible to
18 MethodInfo but the typedef metadata comes from the Clang C++
19 compiler, not CINT.
20 */
21 
22 #include "TClingMethodInfo.h"
23 
24 #include "TClingCallFunc.h"
25 #include "TClingClassInfo.h"
26 #include "TClingMethodArgInfo.h"
27 #include "TDictionary.h"
28 #include "TClingTypeInfo.h"
29 #include "TError.h"
30 #include "TClingUtils.h"
31 #include "TCling.h"
32 #include "ThreadLocalStorage.h"
33 
34 #include "cling/Interpreter/Interpreter.h"
35 #include "cling/Interpreter/LookupHelper.h"
36 #include "cling/Utils/AST.h"
37 
38 #include "clang/AST/ASTContext.h"
39 #include "clang/AST/Decl.h"
40 #include "clang/AST/DeclCXX.h"
41 #include "clang/AST/DeclTemplate.h"
42 #include "clang/AST/ExprCXX.h"
43 #include "clang/AST/GlobalDecl.h"
44 #include "clang/AST/Mangle.h"
45 #include "clang/AST/PrettyPrinter.h"
46 #include "clang/AST/Type.h"
47 #include "clang/Basic/IdentifierTable.h"
48 #include "clang/Sema/Lookup.h"
49 #include "clang/Sema/Sema.h"
50 #include "clang/Sema/Template.h"
51 #include "clang/Sema/TemplateDeduction.h"
52 
53 #include "llvm/Support/Casting.h"
54 #include "llvm/Support/raw_ostream.h"
55 
56 #include <string>
57 
58 using namespace clang;
59 
60 TClingMethodInfo::TClingMethodInfo(const TClingMethodInfo &rhs) :
61  TClingDeclInfo(rhs),
62  fInterp(rhs.fInterp),
63  fContexts(rhs.fContexts),
64  fFirstTime(rhs.fFirstTime),
65  fContextIdx(rhs.fContextIdx),
66  fIter(rhs.fIter),
67  fTitle(rhs.fTitle),
68  fTemplateSpec(rhs.fTemplateSpec)
69 {
70 }
71 
72 
73 TClingMethodInfo& TClingMethodInfo::operator=(const TClingMethodInfo &rhs) {
74  if (this == &rhs)
75  return *this;
76 
77  this->TClingDeclInfo::operator=(rhs);
78  fInterp = rhs.fInterp;
79  fContexts = rhs.fContexts;
80  fFirstTime = rhs.fFirstTime;
81  fContextIdx = rhs.fContextIdx;
82  fIter = rhs.fIter;
83  fTitle = rhs.fTitle;
84  fTemplateSpec = rhs.fTemplateSpec;
85 
86  return *this;
87 }
88 
89 
90 TClingMethodInfo::TClingMethodInfo(cling::Interpreter *interp,
91  TClingClassInfo *ci)
92  : TClingDeclInfo(nullptr), fInterp(interp), fFirstTime(true), fContextIdx(0U), fTitle(""),
93  fTemplateSpec(0)
94 {
95  R__LOCKGUARD(gInterpreterMutex);
96 
97  if (!ci || !ci->IsValid()) {
98  return;
99  }
100  clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::Decl*>(ci->GetDecl()));
101  if (cxxdecl) {
102  // Make sure we have an entry for all the implicit function.
103 
104  // Could trigger deserialization of decls.
105  cling::Interpreter::PushTransactionRAII RAII(interp);
106 
107  fInterp->getSema().ForceDeclarationOfImplicitMembers(cxxdecl);
108  }
109  clang::DeclContext *dc =
110  llvm::cast<clang::DeclContext>(const_cast<clang::Decl*>(ci->GetDecl()));
111  dc->collectAllContexts(fContexts);
112  // Could trigger deserialization of decls.
113  cling::Interpreter::PushTransactionRAII RAII(interp);
114  fIter = dc->decls_begin();
115  InternalNext();
116  fFirstTime = true;
117 }
118 
119 TClingMethodInfo::TClingMethodInfo(cling::Interpreter *interp,
120  const clang::FunctionDecl *FD)
121  : TClingDeclInfo(FD), fInterp(interp), fFirstTime(true), fContextIdx(0U), fTitle(""),
122  fTemplateSpec(0)
123 {
124 
125 }
126 
127 TClingMethodInfo::~TClingMethodInfo()
128 {
129  delete fTemplateSpec;
130 }
131 
132 TDictionary::DeclId_t TClingMethodInfo::GetDeclId() const
133 {
134  if (!IsValid()) {
135  return TDictionary::DeclId_t();
136  }
137  return (const clang::Decl*)(GetMethodDecl()->getCanonicalDecl());
138 }
139 
140 const clang::FunctionDecl *TClingMethodInfo::GetMethodDecl() const
141 {
142  return cast_or_null<FunctionDecl>(GetDecl());
143 }
144 
145 void TClingMethodInfo::CreateSignature(TString &signature) const
146 {
147  signature = "(";
148  if (!IsValid()) {
149  signature += ")";
150  return;
151  }
152 
153  R__LOCKGUARD(gInterpreterMutex);
154  TClingMethodArgInfo arg(fInterp, this);
155 
156  int idx = 0;
157  while (arg.Next()) {
158  if (idx) {
159  signature += ", ";
160  }
161  signature += arg.Type()->Name();
162  if (arg.Name() && strlen(arg.Name())) {
163  signature += " ";
164  signature += arg.Name();
165  }
166  if (arg.DefaultValue()) {
167  signature += " = ";
168  signature += arg.DefaultValue();
169  }
170  ++idx;
171  }
172  auto decl = GetMethodDecl();
173  if (decl && decl->isVariadic())
174  signature += ",...";
175 
176  signature += ")";
177 }
178 
179 void TClingMethodInfo::Init(const clang::FunctionDecl *decl)
180 {
181  fContexts.clear();
182  fFirstTime = true;
183  fContextIdx = 0U;
184  fIter = clang::DeclContext::decl_iterator();
185  fTemplateSpec = 0;
186  fDecl = decl;
187 }
188 
189 void *TClingMethodInfo::InterfaceMethod(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
190 {
191  if (!IsValid()) {
192  return 0;
193  }
194  R__LOCKGUARD(gInterpreterMutex);
195  TClingCallFunc cf(fInterp,normCtxt);
196  cf.SetFunc(this);
197  return cf.InterfaceMethod();
198 }
199 
200 const clang::Decl* TClingMethodInfo::GetDeclSlow() const
201 {
202  if (fTemplateSpec) {
203  return fTemplateSpec;
204  }
205  return *fIter;
206 }
207 
208 int TClingMethodInfo::NArg() const
209 {
210  if (!IsValid()) {
211  return -1;
212  }
213  const clang::FunctionDecl *fd = GetMethodDecl();
214  unsigned num_params = fd->getNumParams();
215  // Truncate cast to fit cint interface.
216  return static_cast<int>(num_params);
217 }
218 
219 int TClingMethodInfo::NDefaultArg() const
220 {
221  if (!IsValid()) {
222  return -1;
223  }
224  const clang::FunctionDecl *fd = GetMethodDecl();
225  unsigned num_params = fd->getNumParams();
226  unsigned min_args = fd->getMinRequiredArguments();
227  unsigned defaulted_params = num_params - min_args;
228  // Truncate cast to fit cint interface.
229  return static_cast<int>(defaulted_params);
230 }
231 
232 /*
233 static bool HasUnexpandedParameterPack(clang::QualType QT, clang::Sema& S) {
234  if (llvm::isa<PackExpansionType>(*QT)) {
235  // We are not going to expand the pack here...
236  return true;
237  }
238  SmallVector<UnexpandedParameterPack, 4> Unexpanded;
239  S.collectUnexpandedParameterPacks (QT, Unexpanded);
240 
241  return !Unexpanded.empty();
242 }
243  */
244 
245 static const clang::FunctionDecl *
246 GetOrInstantiateFuncTemplateWithDefaults(clang::FunctionTemplateDecl* FTDecl,
247  clang::Sema& S,
248  const cling::LookupHelper& LH) {
249  // Force instantiation if it doesn't exist yet, by looking it up.
250  using namespace clang;
251 
252  auto templateParms = FTDecl->getTemplateParameters();
253  if (templateParms->containsUnexpandedParameterPack())
254  return nullptr;
255 
256  if (templateParms->getMinRequiredArguments() > 0)
257  return nullptr;
258 
259  if (templateParms->size() > 0) {
260  NamedDecl *arg0 = *templateParms->begin();
261  if (arg0->isTemplateParameterPack())
262  return nullptr;
263  if (auto TTP = dyn_cast<TemplateTypeParmDecl>(*templateParms->begin())) {
264  if (!TTP->hasDefaultArgument())
265  return nullptr;
266  } else if (auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(
267  *templateParms->begin())) {
268  if (!NTTP->hasDefaultArgument())
269  return nullptr;
270  } else {
271  // TemplateTemplateParmDecl, pack
272  return nullptr;
273  }
274  }
275 
276  FunctionDecl *templatedDecl = FTDecl->getTemplatedDecl();
277  Decl *declCtxDecl = dyn_cast<Decl>(FTDecl->getDeclContext());
278 
279  // We have a function template
280  // template <class X = int, int i = 7> void func(int a0, X a1[i], X::type a2[i])
281  // which has defaults for all its template parameters `X` and `i`. To
282  // instantiate it we have to do a lookup, which in turn needs the function
283  // argument types, e.g. `int[12]`.
284  // If the function argument type is dependent (a1 and a2) we need to
285  // substitute the types first, using the template arguments derived from the
286  // template parameters' defaults.
287  llvm::SmallVector<TemplateArgument, 8> defaultTemplateArgs(templateParms->size());
288  for (int iParam = 0, nParams = templateParms->size(); iParam < nParams; ++iParam) {
289  const NamedDecl* templateParm = templateParms->getParam(iParam);
290  if (templateParm->isTemplateParameterPack()) {
291  // shouldn't end up here
292  assert(0 && "unexpected template parameter pack");
293  return nullptr;
294  } if (auto TTP = dyn_cast<TemplateTypeParmDecl>(templateParm)) {
295  if (!TTP->hasDefaultArgument())
296  return nullptr;
297  defaultTemplateArgs[iParam] = TemplateArgument(TTP->getDefaultArgument());
298  } else if (auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(templateParm)) {
299  if (!NTTP->hasDefaultArgument())
300  return nullptr;
301  defaultTemplateArgs[iParam] = TemplateArgument(NTTP->getDefaultArgument());
302  } else if (auto TTP = dyn_cast<TemplateTemplateParmDecl>(templateParm)) {
303  if (!TTP->hasDefaultArgument())
304  return nullptr;
305  defaultTemplateArgs[iParam] = TemplateArgument(TTP->getDefaultArgument().getArgument());
306  } else {
307  // shouldn't end up here
308  assert(0 && "unexpected template parameter kind");
309  return nullptr;
310  }
311  }
312 
313  // Now substitute the dependent function parameter types given defaultTemplateArgs.
314  llvm::SmallVector<QualType, 8> paramTypes;
315  // Provide an instantiation context that suppresses errors:
316  // DeducedTemplateArgumentSubstitution! (ROOT-8422)
317  SmallVector<DeducedTemplateArgument, 4> DeducedArgs;
318  sema::TemplateDeductionInfo Info{SourceLocation()};
319 
320  Sema::InstantiatingTemplate Inst(S, Info.getLocation(), FTDecl,
321  defaultTemplateArgs,
322  Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
323  Info);
324 
325  // Collect the function arguments of the templated function, substituting
326  // dependent types as possible.
327  TemplateArgumentList templArgList(TemplateArgumentList::OnStack, defaultTemplateArgs);
328  MultiLevelTemplateArgumentList MLTAL{templArgList};
329  for (const clang::ParmVarDecl *param: templatedDecl->parameters()) {
330  QualType paramType = param->getOriginalType();
331 
332  // If the function type is dependent, try to resolve it through the class's
333  // template arguments. If that fails, skip this function.
334  if (paramType->isDependentType()) {
335  /*if (HasUnexpandedParameterPack(paramType, S)) {
336  // We are not going to expand the pack here...
337  skip = true;
338  break;
339  }*/
340 
341  paramType = S.SubstType(paramType, MLTAL, SourceLocation(),
342  templatedDecl->getDeclName());
343 
344  if (paramType.isNull() || paramType->isDependentType()) {
345  // Even after resolving the types through the surrounding template
346  // this argument type is still dependent: do not look it up.
347  return nullptr;
348  }
349  }
350  paramTypes.push_back(paramType);
351  }
352 
353  return LH.findFunctionProto(declCtxDecl, FTDecl->getNameAsString(),
354  paramTypes, LH.NoDiagnostics,
355  templatedDecl->getType().isConstQualified());
356 }
357 
358 int TClingMethodInfo::InternalNext()
359 {
360 
361  assert(!fDecl && "This is not an iterator!");
362 
363  fNameCache.clear(); // invalidate the cache.
364 
365  if (!fFirstTime && !*fIter) {
366  // Iterator is already invalid.
367  return 0;
368  }
369  while (true) {
370  // If we had fTemplateSpec we don't need it anymore, but advance
371  // to the next decl.
372  fTemplateSpec = nullptr;
373 
374  // Advance to the next decl.
375  if (fFirstTime) {
376  // The cint semantics are weird.
377  fFirstTime = false;
378  }
379  else {
380  ++fIter;
381  }
382  // Fix it if we have gone past the end of the current decl context.
383  while (!*fIter) {
384  ++fContextIdx;
385  if (fContextIdx >= fContexts.size()) {
386  // Iterator is now invalid.
387  return 0;
388  }
389  clang::DeclContext *dc = fContexts[fContextIdx];
390  // Could trigger deserialization of decls.
391 
392  cling::Interpreter::PushTransactionRAII RAII(fInterp);
393  fIter = dc->decls_begin();
394  if (*fIter) {
395  // Good, a non-empty context.
396  break;
397  }
398  }
399 
400  if (const auto templateDecl = llvm::dyn_cast<clang::FunctionTemplateDecl>(*fIter)) {
401  // Instantiation below can trigger deserialization.
402  cling::Interpreter::PushTransactionRAII RAII(fInterp);
403 
404  // If this function template can be instantiated without template
405  // arguments then it's worth having it. This commonly happens for
406  // enable_if'ed functions.
407  fTemplateSpec = GetOrInstantiateFuncTemplateWithDefaults(templateDecl, fInterp->getSema(),
408  fInterp->getLookupHelper());
409  if (fTemplateSpec)
410  return 1;
411  }
412 
413  // Return if this decl is a function or method.
414  if (llvm::isa<clang::FunctionDecl>(*fIter)) {
415  // Iterator is now valid.
416  return 1;
417  }
418 
419  // Collect internal `__cling_N5xxx' inline namespaces; they will be traversed later
420  if (auto NS = dyn_cast<NamespaceDecl>(*fIter)) {
421  if (NS->getDeclContext()->isTranslationUnit() && NS->isInlineNamespace())
422  fContexts.push_back(NS);
423  }
424 // if (clang::FunctionDecl *fdecl = llvm::dyn_cast<clang::FunctionDecl>(*fIter)) {
425 // if (fdecl->getAccess() == clang::AS_public || fdecl->getAccess() == clang::AS_none) {
426 // // Iterator is now valid.
427 // return 1;
428 // }
429 // }
430  }
431 }
432 
433 int TClingMethodInfo::Next()
434 {
435  return InternalNext();
436 }
437 
438 long TClingMethodInfo::Property() const
439 {
440  if (!IsValid()) {
441  return 0L;
442  }
443  long property = 0L;
444  property |= kIsCompiled;
445  const clang::FunctionDecl *fd = GetMethodDecl();
446  if (fd->isConstexpr())
447  property |= kIsConstexpr;
448  switch (fd->getAccess()) {
449  case clang::AS_public:
450  property |= kIsPublic;
451  break;
452  case clang::AS_protected:
453  property |= kIsProtected;
454  break;
455  case clang::AS_private:
456  property |= kIsPrivate;
457  break;
458  case clang::AS_none:
459  if (fd->getDeclContext()->isNamespace())
460  property |= kIsPublic;
461  break;
462  default:
463  // IMPOSSIBLE
464  break;
465  }
466  if (fd->getStorageClass() == clang::SC_Static) {
467  property |= kIsStatic;
468  }
469  clang::QualType qt = fd->getReturnType().getCanonicalType();
470  if (qt.isConstQualified()) {
471  property |= kIsConstant;
472  }
473  while (1) {
474  if (qt->isArrayType()) {
475  qt = llvm::cast<clang::ArrayType>(qt)->getElementType();
476  continue;
477  }
478  else if (qt->isReferenceType()) {
479  property |= kIsReference;
480  qt = llvm::cast<clang::ReferenceType>(qt)->getPointeeType();
481  continue;
482  }
483  else if (qt->isPointerType()) {
484  property |= kIsPointer;
485  if (qt.isConstQualified()) {
486  property |= kIsConstPointer;
487  }
488  qt = llvm::cast<clang::PointerType>(qt)->getPointeeType();
489  continue;
490  }
491  else if (qt->isMemberPointerType()) {
492  qt = llvm::cast<clang::MemberPointerType>(qt)->getPointeeType();
493  continue;
494  }
495  break;
496  }
497  if (qt.isConstQualified()) {
498  property |= kIsConstant;
499  }
500  if (const clang::CXXMethodDecl *md =
501  llvm::dyn_cast<clang::CXXMethodDecl>(fd)) {
502  if (md->getTypeQualifiers() & clang::Qualifiers::Const) {
503  property |= kIsConstant | kIsConstMethod;
504  }
505  if (md->isVirtual()) {
506  property |= kIsVirtual;
507  }
508  if (md->isPure()) {
509  property |= kIsPureVirtual;
510  }
511  if (const clang::CXXConstructorDecl *cd =
512  llvm::dyn_cast<clang::CXXConstructorDecl>(md)) {
513  if (cd->isExplicit()) {
514  property |= kIsExplicit;
515  }
516  }
517  else if (const clang::CXXConversionDecl *cd =
518  llvm::dyn_cast<clang::CXXConversionDecl>(md)) {
519  if (cd->isExplicit()) {
520  property |= kIsExplicit;
521  }
522  }
523  }
524  return property;
525 }
526 
527 long TClingMethodInfo::ExtraProperty() const
528 {
529  // Return the property not already defined in Property
530  // See TDictionary's EFunctionProperty
531  if (!IsValid()) {
532  return 0L;
533  }
534  long property = 0;
535  const clang::FunctionDecl *fd = GetMethodDecl();
536  if (fd->isOverloadedOperator())
537  property |= kIsOperator;
538  if (llvm::isa<clang::CXXConversionDecl>(fd))
539  property |= kIsConversion;
540  if (llvm::isa<clang::CXXConstructorDecl>(fd))
541  property |= kIsConstructor;
542  if (llvm::isa<clang::CXXDestructorDecl>(fd))
543  property |= kIsDestructor;
544  if (fd->isInlined())
545  property |= kIsInlined;
546  return property;
547 }
548 
549 TClingTypeInfo *TClingMethodInfo::Type() const
550 {
551  TTHREAD_TLS_DECL_ARG( TClingTypeInfo, ti, fInterp );
552  if (!IsValid()) {
553  ti.Init(clang::QualType());
554  return &ti;
555  }
556  if (llvm::isa<clang::CXXConstructorDecl>(GetMethodDecl())) {
557  // CINT claims that constructors return the class object.
558  const clang::TypeDecl* ctorClass = llvm::dyn_cast_or_null<clang::TypeDecl>
559  (GetMethodDecl()->getDeclContext());
560  if (!ctorClass) {
561  Error("TClingMethodInfo::Type", "Cannot find DeclContext for constructor!");
562  } else {
563  clang::QualType qt(ctorClass->getTypeForDecl(), 0);
564  ti.Init(qt);
565  }
566  } else {
567  clang::QualType qt = GetMethodDecl()->getReturnType();
568  ti.Init(qt);
569  }
570  return &ti;
571 }
572 
573 std::string TClingMethodInfo::GetMangledName() const
574 {
575  if (!IsValid()) {
576  return "";
577  }
578  std::string mangled_name;
579  mangled_name.clear();
580  const FunctionDecl* D = GetMethodDecl();
581 
582  R__LOCKGUARD(gInterpreterMutex);
583  cling::Interpreter::PushTransactionRAII RAII(fInterp);
584  GlobalDecl GD;
585  if (const CXXConstructorDecl* Ctor = dyn_cast<CXXConstructorDecl>(D))
586  GD = GlobalDecl(Ctor, Ctor_Complete);
587  else if (const CXXDestructorDecl* Dtor = dyn_cast<CXXDestructorDecl>(D))
588  GD = GlobalDecl(Dtor, Dtor_Deleting);
589  else
590  GD = GlobalDecl(D);
591 
592  cling::utils::Analyze::maybeMangleDeclName(GD, mangled_name);
593  return mangled_name;
594 }
595 
596 const char *TClingMethodInfo::GetPrototype()
597 {
598  if (!IsValid()) {
599  return 0;
600  }
601  TTHREAD_TLS_DECL( std::string, buf );
602  buf.clear();
603  buf += Type()->Name();
604  buf += ' ';
605  if (const clang::TypeDecl *td = llvm::dyn_cast<clang::TypeDecl>(GetMethodDecl()->getDeclContext())) {
606  std::string name;
607  clang::QualType qualType(td->getTypeForDecl(),0);
608  ROOT::TMetaUtils::GetFullyQualifiedTypeName(name,qualType,*fInterp);
609  buf += name;
610  buf += "::";
611  } else if (const clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(GetMethodDecl()->getDeclContext())) {
612  std::string name;
613  clang::PrintingPolicy policy(GetMethodDecl()->getASTContext().getPrintingPolicy());
614  llvm::raw_string_ostream stream(name);
615  nd->getNameForDiagnostic(stream, policy, /*Qualified=*/true);
616  stream.flush();
617  buf += name;
618  buf += "::";
619  }
620  buf += Name();
621 
622  TString signature;
623  CreateSignature(signature);
624  buf += signature;
625 
626  if (const clang::CXXMethodDecl *md =
627  llvm::dyn_cast<clang::CXXMethodDecl>( GetMethodDecl())) {
628  if (md->getTypeQualifiers() & clang::Qualifiers::Const) {
629  buf += " const";
630  }
631  }
632  return buf.c_str();
633 }
634 
635 const char *TClingMethodInfo::Name()
636 {
637  if (!IsValid()) {
638  return 0;
639  }
640  if (!fNameCache.empty())
641  return fNameCache.c_str();
642 
643  ((TCling*)gCling)->GetFunctionName(GetMethodDecl(), fNameCache);
644  return fNameCache.c_str();
645 }
646 
647 const char *TClingMethodInfo::TypeName() const
648 {
649  if (!IsValid()) {
650  // FIXME: Cint does not check!
651  return 0;
652  }
653  return Type()->Name();
654 }
655 
656 const char *TClingMethodInfo::Title()
657 {
658  if (!IsValid()) {
659  return 0;
660  }
661 
662  //NOTE: We can't use it as a cache due to the "thoughtful" self iterator
663  //if (fTitle.size())
664  // return fTitle.c_str();
665 
666  // Try to get the comment either from the annotation or the header file if present
667 
668  // Iterate over the redeclarations, we can have multiple definitions in the
669  // redecl chain (came from merging of pcms).
670  const FunctionDecl *FD = GetMethodDecl();
671 
672  R__LOCKGUARD(gInterpreterMutex);
673 
674  // Could trigger deserialization of decls.
675  cling::Interpreter::PushTransactionRAII RAII(fInterp);
676  if (const FunctionDecl *AnnotFD
677  = ROOT::TMetaUtils::GetAnnotatedRedeclarable(FD)) {
678  if (AnnotateAttr *A = AnnotFD->getAttr<AnnotateAttr>()) {
679  fTitle = A->getAnnotation().str();
680  return fTitle.c_str();
681  }
682  }
683  if (!FD->isFromASTFile()) {
684  // Try to get the comment from the header file if present
685  // but not for decls from AST file, where rootcling would have
686  // created an annotation
687  fTitle = ROOT::TMetaUtils::GetComment(*FD).str();
688  }
689 
690  return fTitle.c_str();
691 }
692