ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 "TMetaUtils.h"
31 #include "TCling.h"
32 #include "ThreadLocalStorage.h"
33 
34 #include "cling/Interpreter/Interpreter.h"
35 #include "cling/Utils/AST.h"
36 
37 #include "clang/AST/ASTContext.h"
38 #include "clang/AST/Decl.h"
39 #include "clang/AST/DeclCXX.h"
40 #include "clang/AST/DeclTemplate.h"
41 #include "clang/AST/GlobalDecl.h"
42 #include "clang/AST/Mangle.h"
43 #include "clang/AST/PrettyPrinter.h"
44 #include "clang/AST/Type.h"
45 #include "clang/Basic/IdentifierTable.h"
46 #include "clang/Sema/Sema.h"
47 
48 #include "llvm/Support/Casting.h"
49 #include "llvm/Support/raw_ostream.h"
50 
51 #include <string>
52 
53 using namespace clang;
54 
55 class TClingMethodInfo::SpecIterator
56 {
57 public:
58  typedef clang::FunctionTemplateDecl::spec_iterator Iterator;
59 
60  SpecIterator(Iterator begin, Iterator end) : fIter(begin), fEnd(end) {}
61  explicit SpecIterator(clang::FunctionTemplateDecl *decl) : fIter(decl->spec_begin()), fEnd(decl->spec_end()) {}
62 
63  FunctionDecl *operator* () const { return *fIter; }
64  FunctionDecl *operator-> () const { return *fIter; }
65  SpecIterator & operator++ () { ++fIter; return *this; }
66  SpecIterator operator++ (int) {
67  SpecIterator tmp(fIter,fEnd);
68  ++(*this);
69  return tmp;
70  }
71  bool operator!() { return fIter == fEnd; }
72  operator bool() { return fIter != fEnd; }
73 
74 private:
75 
76  Iterator fIter;
77  Iterator fEnd;
78 };
79 
81  fInterp(rhs.fInterp),
82  fContexts(rhs.fContexts),
83  fFirstTime(rhs.fFirstTime),
84  fContextIdx(rhs.fContextIdx),
85  fIter(rhs.fIter),
86  fTitle(rhs.fTitle),
87  fTemplateSpecIter(nullptr),
88  fSingleDecl(rhs.fSingleDecl)
89 {
90  if (rhs.fTemplateSpecIter) {
91  // The SpecIterator query the decl.
93  fTemplateSpecIter = new SpecIterator(*rhs.fTemplateSpecIter);
94  }
95 }
96 
97 
98 TClingMethodInfo::TClingMethodInfo(cling::Interpreter *interp,
99  TClingClassInfo *ci)
100  : fInterp(interp), fFirstTime(true), fContextIdx(0U), fTitle(""),
101  fTemplateSpecIter(0), fSingleDecl(0)
102 {
104 
105  if (!ci || !ci->IsValid()) {
106  return;
107  }
108  clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::Decl*>(ci->GetDecl()));
109  if (cxxdecl) {
110  // Make sure we have an entry for all the implicit function.
111 
112  // Could trigger deserialization of decls.
113  cling::Interpreter::PushTransactionRAII RAII(interp);
114 
115  fInterp->getSema().ForceDeclarationOfImplicitMembers(cxxdecl);
116  }
117  clang::DeclContext *dc =
118  llvm::cast<clang::DeclContext>(const_cast<clang::Decl*>(ci->GetDecl()));
119  dc->collectAllContexts(fContexts);
120  // Could trigger deserialization of decls.
121  cling::Interpreter::PushTransactionRAII RAII(interp);
122  fIter = dc->decls_begin();
123  InternalNext();
124  fFirstTime = true;
125 }
126 
127 TClingMethodInfo::TClingMethodInfo(cling::Interpreter *interp,
128  const clang::FunctionDecl *FD)
129  : fInterp(interp), fFirstTime(true), fContextIdx(0U), fTitle(""),
130  fTemplateSpecIter(0), fSingleDecl(FD)
131 {
132 
133 }
134 
136 {
137  delete fTemplateSpecIter;
138 }
139 
141 {
142  if (!IsValid()) {
143  return TDictionary::DeclId_t();
144  }
145  return (const clang::Decl*)(GetMethodDecl()->getCanonicalDecl());
146 }
147 
148 const clang::FunctionDecl *TClingMethodInfo::GetMethodDecl() const
149 {
150  if (!IsValid()) {
151  return 0;
152  }
153 
154  if (fSingleDecl)
155  return fSingleDecl;
156 
157  if (fTemplateSpecIter)
158  return *(*fTemplateSpecIter);
159 
160  return llvm::dyn_cast<clang::FunctionDecl>(*fIter);
161 }
162 
164 {
165  signature = "(";
166  if (!IsValid()) {
167  signature += ")";
168  return;
169  }
170 
172  TClingMethodArgInfo arg(fInterp, this);
173 
174  int idx = 0;
175  while (arg.Next()) {
176  if (idx) {
177  signature += ", ";
178  }
179  signature += arg.Type()->Name();
180  if (arg.Name() && strlen(arg.Name())) {
181  signature += " ";
182  signature += arg.Name();
183  }
184  if (arg.DefaultValue()) {
185  signature += " = ";
186  signature += arg.DefaultValue();
187  }
188  ++idx;
189  }
190  signature += ")";
191 }
192 
193 void TClingMethodInfo::Init(const clang::FunctionDecl *decl)
194 {
195  fContexts.clear();
196  fFirstTime = true;
197  fContextIdx = 0U;
198  fIter = clang::DeclContext::decl_iterator();
199  delete fTemplateSpecIter;
200  fTemplateSpecIter = 0;
201  fSingleDecl = decl;
202 }
203 
205 {
206  if (!IsValid()) {
207  return 0;
208  }
210  TClingCallFunc cf(fInterp,normCtxt);
211  cf.SetFunc(this);
212  return cf.InterfaceMethod();
213 }
214 
216 {
217  if (fSingleDecl) return fSingleDecl;
218  else if (fTemplateSpecIter) {
219  // Could trigger deserialization of decls.
221  cling::Interpreter::PushTransactionRAII RAII(fInterp);
222  return *(*fTemplateSpecIter);
223  }
224  return *fIter;
225 }
226 
228 {
229  if (!IsValid()) {
230  return -1;
231  }
232  const clang::FunctionDecl *fd = GetMethodDecl();
233  unsigned num_params = fd->getNumParams();
234  // Truncate cast to fit cint interface.
235  return static_cast<int>(num_params);
236 }
237 
239 {
240  if (!IsValid()) {
241  return -1;
242  }
243  const clang::FunctionDecl *fd = GetMethodDecl();
244  unsigned num_params = fd->getNumParams();
245  unsigned min_args = fd->getMinRequiredArguments();
246  unsigned defaulted_params = num_params - min_args;
247  // Truncate cast to fit cint interface.
248  return static_cast<int>(defaulted_params);
249 }
250 
252 {
253 
254  assert(!fSingleDecl && "This is not an iterator!");
255 
256  if (!fFirstTime && !*fIter) {
257  // Iterator is already invalid.
258  return 0;
259  }
260  while (true) {
261  // Advance to the next decl.
262  if (fFirstTime) {
263  // The cint semantics are weird.
264  fFirstTime = false;
265  }
266  else {
267  if (fTemplateSpecIter) {
268  ++(*fTemplateSpecIter);
269  if ( !(*fTemplateSpecIter) ) {
270  // We reached the end of the template specialization.
271  delete fTemplateSpecIter;
272  fTemplateSpecIter = 0;
273  ++fIter;
274  } else {
275  return 1;
276  }
277  } else {
278  ++fIter;
279  }
280  }
281  // Fix it if we have gone past the end of the current decl context.
282  while (!*fIter) {
283  ++fContextIdx;
284  if (fContextIdx >= fContexts.size()) {
285  // Iterator is now invalid.
286  return 0;
287  }
288  clang::DeclContext *dc = fContexts[fContextIdx];
289  // Could trigger deserialization of decls.
290 
291  cling::Interpreter::PushTransactionRAII RAII(fInterp);
292  fIter = dc->decls_begin();
293  if (*fIter) {
294  // Good, a non-empty context.
295  break;
296  }
297  }
298 
299  clang::FunctionTemplateDecl *templateDecl =
300  llvm::dyn_cast<clang::FunctionTemplateDecl>(*fIter);
301  if ( templateDecl ) {
302  // SpecIterator calls clang::FunctionTemplateDecl::spec_begin
303  // which calls clang::FunctionTemplateDecl::LoadLazySpecializations
304  cling::Interpreter::PushTransactionRAII RAII(fInterp);
305  SpecIterator subiter(templateDecl);
306  if (subiter) {
307  delete fTemplateSpecIter;
308  fTemplateSpecIter = new SpecIterator(templateDecl);
309  return 1;
310  }
311  }
312 
313  // Return if this decl is a function or method.
314  if (llvm::isa<clang::FunctionDecl>(*fIter)) {
315  // Iterator is now valid.
316  return 1;
317  }
318 // if (clang::FunctionDecl *fdecl = llvm::dyn_cast<clang::FunctionDecl>(*fIter)) {
319 // if (fdecl->getAccess() == clang::AS_public || fdecl->getAccess() == clang::AS_none) {
320 // // Iterator is now valid.
321 // return 1;
322 // }
323 // }
324  }
325 }
326 
328 {
329  return InternalNext();
330 }
331 
333 {
334  if (!IsValid()) {
335  return 0L;
336  }
337  long property = 0L;
338  property |= kIsCompiled;
339  const clang::FunctionDecl *fd = GetMethodDecl();
340  switch (fd->getAccess()) {
341  case clang::AS_public:
342  property |= kIsPublic;
343  break;
344  case clang::AS_protected:
345  property |= kIsProtected;
346  break;
347  case clang::AS_private:
348  property |= kIsPrivate;
349  break;
350  case clang::AS_none:
351  if (fd->getDeclContext()->isNamespace())
352  property |= kIsPublic;
353  break;
354  default:
355  // IMPOSSIBLE
356  break;
357  }
358  if (fd->getStorageClass() == clang::SC_Static) {
359  property |= kIsStatic;
360  }
361  clang::QualType qt = fd->getReturnType().getCanonicalType();
362  if (qt.isConstQualified()) {
363  property |= kIsConstant;
364  }
365  while (1) {
366  if (qt->isArrayType()) {
367  qt = llvm::cast<clang::ArrayType>(qt)->getElementType();
368  continue;
369  }
370  else if (qt->isReferenceType()) {
371  property |= kIsReference;
372  qt = llvm::cast<clang::ReferenceType>(qt)->getPointeeType();
373  continue;
374  }
375  else if (qt->isPointerType()) {
376  property |= kIsPointer;
377  if (qt.isConstQualified()) {
378  property |= kIsConstPointer;
379  }
380  qt = llvm::cast<clang::PointerType>(qt)->getPointeeType();
381  continue;
382  }
383  else if (qt->isMemberPointerType()) {
384  qt = llvm::cast<clang::MemberPointerType>(qt)->getPointeeType();
385  continue;
386  }
387  break;
388  }
389  if (qt.isConstQualified()) {
390  property |= kIsConstant;
391  }
392  if (const clang::CXXMethodDecl *md =
393  llvm::dyn_cast<clang::CXXMethodDecl>(fd)) {
394  if (md->getTypeQualifiers() & clang::Qualifiers::Const) {
395  property |= kIsConstant | kIsConstMethod;
396  }
397  if (md->isVirtual()) {
398  property |= kIsVirtual;
399  }
400  if (md->isPure()) {
401  property |= kIsPureVirtual;
402  }
403  if (const clang::CXXConstructorDecl *cd =
404  llvm::dyn_cast<clang::CXXConstructorDecl>(md)) {
405  if (cd->isExplicit()) {
406  property |= kIsExplicit;
407  }
408  }
409  else if (const clang::CXXConversionDecl *cd =
410  llvm::dyn_cast<clang::CXXConversionDecl>(md)) {
411  if (cd->isExplicit()) {
412  property |= kIsExplicit;
413  }
414  }
415  }
416  return property;
417 }
418 
420 {
421  // Return the property not already defined in Property
422  // See TDictionary's EFunctionProperty
423  if (!IsValid()) {
424  return 0L;
425  }
426  long property = 0;
427  const clang::FunctionDecl *fd = GetMethodDecl();
428  if (fd->isOverloadedOperator()) {
429  property |= kIsOperator;
430  }
431  else if (llvm::isa<clang::CXXConversionDecl>(fd)) {
432  property |= kIsConversion;
433  } else if (llvm::isa<clang::CXXConstructorDecl>(fd)) {
434  property |= kIsConstructor;
435  } else if (llvm::isa<clang::CXXDestructorDecl>(fd)) {
436  property |= kIsDestructor;
437  }
438  return property;
439 }
440 
442 {
443  TTHREAD_TLS_DECL_ARG( TClingTypeInfo, ti, fInterp );
444  if (!IsValid()) {
445  ti.Init(clang::QualType());
446  return &ti;
447  }
448  if (llvm::isa<clang::CXXConstructorDecl>(GetMethodDecl())) {
449  // CINT claims that constructors return the class object.
450  const clang::TypeDecl* ctorClass = llvm::dyn_cast_or_null<clang::TypeDecl>
451  (GetMethodDecl()->getDeclContext());
452  if (!ctorClass) {
453  Error("TClingMethodInfo::Type", "Cannot find DeclContext for constructor!");
454  } else {
455  clang::QualType qt(ctorClass->getTypeForDecl(), 0);
456  ti.Init(qt);
457  }
458  } else {
459  clang::QualType qt = GetMethodDecl()->getReturnType();
460  ti.Init(qt);
461  }
462  return &ti;
463 }
464 
466 {
467  if (!IsValid()) {
468  return "";
469  }
470  std::string mangled_name;
471  mangled_name.clear();
472  const FunctionDecl* D = GetMethodDecl();
473 
475  GlobalDecl GD;
476  if (const CXXConstructorDecl* Ctor = dyn_cast<CXXConstructorDecl>(D))
477  GD = GlobalDecl(Ctor, Ctor_Complete);
478  else if (const CXXDestructorDecl* Dtor = dyn_cast<CXXDestructorDecl>(D))
479  GD = GlobalDecl(Dtor, Dtor_Deleting);
480  else
481  GD = GlobalDecl(D);
482 
483  cling::utils::Analyze::maybeMangleDeclName(GD, mangled_name);
484  return mangled_name;
485 }
486 
488 {
489  if (!IsValid()) {
490  return 0;
491  }
492  TTHREAD_TLS_DECL( std::string, buf );
493  buf.clear();
494  buf += Type()->Name();
495  buf += ' ';
496  if (const clang::TypeDecl *td = llvm::dyn_cast<clang::TypeDecl>(GetMethodDecl()->getDeclContext())) {
497  std::string name;
498  clang::QualType qualType(td->getTypeForDecl(),0);
500  buf += name;
501  buf += "::";
502  } else if (const clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(GetMethodDecl()->getDeclContext())) {
503  std::string name;
504  clang::PrintingPolicy policy(GetMethodDecl()->getASTContext().getPrintingPolicy());
505  llvm::raw_string_ostream stream(name);
506  nd->getNameForDiagnostic(stream, policy, /*Qualified=*/true);
507  stream.flush();
508  buf += name;
509  buf += "::";
510  }
511  buf += Name(normCtxt);
512  buf += '(';
513  TClingMethodArgInfo arg(fInterp, this);
514  int idx = 0;
515  while (arg.Next()) {
516  if (idx) {
517  buf += ", ";
518  }
519  buf += arg.Type()->Name();
520  if (arg.Name() && strlen(arg.Name())) {
521  buf += ' ';
522  buf += arg.Name();
523  }
524  if (arg.DefaultValue()) {
525  buf += " = ";
526  buf += arg.DefaultValue();
527  }
528  ++idx;
529  }
530  buf += ')';
531  if (const clang::CXXMethodDecl *md =
532  llvm::dyn_cast<clang::CXXMethodDecl>( GetMethodDecl())) {
533  if (md->getTypeQualifiers() & clang::Qualifiers::Const) {
534  buf += " const";
535  }
536  }
537  return buf.c_str();
538 }
539 
541 {
542  if (!IsValid()) {
543  return 0;
544  }
545  TTHREAD_TLS_DECL( std::string, buf );
546  ((TCling*)gCling)->GetFunctionName(GetMethodDecl(),buf);
547  return buf.c_str();
548 }
549 
550 const char *TClingMethodInfo::TypeName() const
551 {
552  if (!IsValid()) {
553  // FIXME: Cint does not check!
554  return 0;
555  }
556  return Type()->Name();
557 }
558 
560 {
561  if (!IsValid()) {
562  return 0;
563  }
564 
565  //NOTE: We can't use it as a cache due to the "thoughtful" self iterator
566  //if (fTitle.size())
567  // return fTitle.c_str();
568 
569  // Try to get the comment either from the annotation or the header file if present
570 
571  // Iterate over the redeclarations, we can have multiple definitions in the
572  // redecl chain (came from merging of pcms).
573  const FunctionDecl *FD = GetMethodDecl();
574 
576 
577  // Could trigger deserialization of decls.
578  cling::Interpreter::PushTransactionRAII RAII(fInterp);
579  if (const FunctionDecl *AnnotFD
581  if (AnnotateAttr *A = AnnotFD->getAttr<AnnotateAttr>()) {
582  fTitle = A->getAnnotation().str();
583  return fTitle.c_str();
584  }
585  }
586  if (!FD->isFromASTFile()) {
587  // Try to get the comment from the header file if present
588  // but not for decls from AST file, where rootcling would have
589  // created an annotation
591  }
592 
593  return fTitle.c_str();
594 }
595 
bool IsValid() const
const char * GetPrototype(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
RooArgList L(const RooAbsArg &v1)
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:46
const char * Name() const
#define assert(cond)
Definition: unittest.h:542
void SetFunc(const TClingClassInfo *info, const char *method, const char *arglist, long *poffset)
llvm::SmallVector< clang::DeclContext *, 2 > fContexts
Emulation of the CINT MethodInfo class.
int NDefaultArg() const
const TClingTypeInfo * Type() const
clang::DeclContext::decl_iterator fIter
Basic string class.
Definition: TString.h:137
TClingTypeInfo * Type() const
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
const char * Title()
static double A[]
Emulation of the CINT CallFunc class.
const void * DeclId_t
Definition: TDictionary.h:209
void CreateSignature(TString &signature) const
bool IsValid() const
Emulation of the CINT TypeInfo class.
This class defines an interface to the cling C++ interpreter.
Definition: TCling.h:92
void Error(const char *location, const char *msgfmt,...)
void * InterfaceMethod()
long ExtraProperty() const
SpecIterator * fTemplateSpecIter
const char * Name() const
TCut operator!(const TCut &rhs)
Logical negation.
Definition: TCut.cxx:290
void Init(const clang::FunctionDecl *)
unsigned int fContextIdx
void * InterfaceMethod(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
const clang::FunctionDecl * GetMethodDecl() const
TTime operator*(const TTime &t1, const TTime &t2)
Definition: TTime.h:87
const char * DefaultValue() const
const T * GetAnnotatedRedeclarable(const T *Redecl)
Definition: TMetaUtils.h:616
std::string fTitle
TDictionary::DeclId_t GetDeclId() const
const char * TypeName() const
std::string GetMangledName() const
const char * Name(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
const clang::Decl * GetDecl() const
const clang::FunctionDecl * fSingleDecl
Emulation of the CINT MethodInfo class.
Emulation of the CINT ClassInfo class.
#define R__LOCKGUARD(mutex)
#define name(a, b)
Definition: linkTestLib0.cpp:5
TClingMethodInfo(cling::Interpreter *interp)
llvm::StringRef GetComment(const clang::Decl &decl, clang::SourceLocation *loc=0)
Returns the comment (// striped away), annotating declaration in a meaningful for ROOT IO way...
#define nullptr
Definition: Rtypes.h:87
long Property() const
R__EXTERN TInterpreter * gCling
Definition: TInterpreter.h:504
cling::Interpreter * fInterp
const char * cd(char *path=0)
Definition: rootalias.C:45