Logo ROOT   6.07/09
Reference Guide
TClingTypedefInfo.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 TClingTypedefInfo
13 Emulation of the CINT TypedefInfo class.
14 
15 The CINT C++ interpreter provides an interface to metadata about
16 a typedef through the TypedefInfo class. This class provides the
17 same functionality, using an interface as close as possible to
18 TypedefInfo but the typedef metadata comes from the Clang C++
19 compiler, not CINT.
20 */
21 
22 #include "TClingTypedefInfo.h"
23 
24 #include "TDictionary.h"
25 #include "TError.h"
26 #include "TMetaUtils.h"
27 #include "Rtypes.h" // for gDebug
28 #include "ThreadLocalStorage.h"
29 
30 #include "cling/Interpreter/LookupHelper.h"
31 #include "cling/Utils/AST.h"
32 #include "clang/AST/Attr.h"
33 
34 using namespace clang;
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Lookup named typedef and initialize the iterator to point to it.
38 /// Yields a non-iterable TClingTypedefInfo (fIter is invalid).
39 
40 TClingTypedefInfo::TClingTypedefInfo(cling::Interpreter *interp,
41  const char *name)
42  : fInterp(interp), fFirstTime(true), fDescend(false), fDecl(0), fTitle("")
43 {
44  Init(name);
45 }
46 
47 TClingTypedefInfo::TClingTypedefInfo(cling::Interpreter *interp,
48  const clang::TypedefNameDecl *TdefD)
49  : fInterp(interp), fFirstTime(true), fDescend(false), fDecl(TdefD),
50  fTitle("")
51 {
52  // Initialize with a clang::TypedefDecl.
53  // fIter is invalid; cannot call Next().
54 }
55 
56 ////////////////////////////////////////////////////////////////////////////////
57 /// Get the current typedef declaration.
58 
59 const clang::Decl *TClingTypedefInfo::GetDecl() const
60 {
61  return fDecl;
62 }
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// Lookup named typedef and reset the iterator to point to it.
66 
67 void TClingTypedefInfo::Init(const char *name)
68 {
69  fDecl = 0;
70 
71  // Reset the iterator to invalid.
72  fFirstTime = true;
73  fDescend = false;
74  fIter = clang::DeclContext::decl_iterator();
75  fIterStack.clear();
76 
77  // Some trivial early exit, covering many cases in a cheap way.
78  if (!name || !*name) return;
79  const char lastChar = name[strlen(name) - 1];
80  if (lastChar == '*' || lastChar == '&' || !strncmp(name, "const ", 6))
81  return;
82 
83  // Ask the cling interpreter to lookup the name for us.
84  const cling::LookupHelper& lh = fInterp->getLookupHelper();
85  clang::QualType QT = lh.findType(name,
86  gDebug > 5 ? cling::LookupHelper::WithDiagnostics
87  : cling::LookupHelper::NoDiagnostics);
88  if (QT.isNull()) {
89  std::string buf = TClassEdit::InsertStd(name);
90  if (buf != name) {
91  QT = lh.findType(buf,
92  gDebug > 5 ? cling::LookupHelper::WithDiagnostics
93  : cling::LookupHelper::NoDiagnostics);
94  }
95  if (QT.isNull()) {
96  return;
97  }
98  }
99  const clang::TypedefType *td = QT->getAs<clang::TypedefType>();
100  // if (fDecl && !llvm::isa<clang::TypedefDecl>(fDecl)) {
101  if (!td) {
102  // If what the lookup found is not a typedef, ignore it.
103  return;
104  }
105  fDecl = td->getDecl();
106 }
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// Return true if the current iterator position is valid.
110 
112 {
113  return fDecl;
114 }
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 /// Increment the iterator, return true if new position is valid.
118 
120 {
121  if (!*fIter) {
122  // Iterator is already invalid.
123  if (fFirstTime && fDecl) {
124  std::string buf;
125  clang::PrintingPolicy Policy(fDecl->getASTContext().getPrintingPolicy());
126  llvm::raw_string_ostream stream(buf);
127  llvm::dyn_cast<clang::NamedDecl>(fDecl)
128  ->getNameForDiagnostic(stream, Policy, /*Qualified=*/false);
129  stream.flush();
130  Error("TClingTypedefInfo::InternalNext","Next called but iteration not prepared for %s!",buf.c_str());
131  }
132  return 0;
133  }
134  // Deserialization might happen during the iteration.
135  cling::Interpreter::PushTransactionRAII pushedT(fInterp);
136  while (true) {
137  // Advance to next usable decl, or return if
138  // there is no next usable decl.
139  if (fFirstTime) {
140  // The cint semantics are strange.
141  fFirstTime = false;
142  }
143  else {
144  // Advance the iterator one decl, descending into
145  // the current decl context if necessary.
146  if (!fDescend) {
147  // Do not need to scan the decl context of the
148  // current decl, move on to the next decl.
149  ++fIter;
150  }
151  else {
152  // Descend into the decl context of the current decl.
153  fDescend = false;
154  fIterStack.push_back(fIter);
155  clang::DeclContext *dc = llvm::cast<clang::DeclContext>(*fIter);
156  fIter = dc->decls_begin();
157  }
158  // Fix it if we went past the end.
159  while (!*fIter && fIterStack.size()) {
160  fIter = fIterStack.back();
161  fIterStack.pop_back();
162  ++fIter;
163  }
164  // Check for final termination.
165  if (!*fIter) {
166  // We have reached the end of the translation unit, all done.
167  fDecl = 0;
168  return 0;
169  }
170  }
171  // Return if this decl is a typedef.
172  if (llvm::isa<clang::TypedefNameDecl>(*fIter)) {
173  fDecl = *fIter;
174  return 1;
175  }
176  // Descend into namespaces and classes.
177  clang::Decl::Kind dk = fIter->getKind();
178  if ((dk == clang::Decl::Namespace) || (dk == clang::Decl::CXXRecord) ||
179  (dk == clang::Decl::ClassTemplateSpecialization)) {
180  fDescend = true;
181  }
182  }
183 }
184 
185 ////////////////////////////////////////////////////////////////////////////////
186 /// Increment the iterator.
187 
189 {
190  return InternalNext();
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 /// Return a bit mask of metadata about the current typedef.
195 
197 {
198  if (!IsValid()) {
199  return 0L;
200  }
201  long property = 0L;
202  property |= kIsTypedef;
203  const clang::TypedefNameDecl *td = llvm::dyn_cast<clang::TypedefNameDecl>(fDecl);
204  clang::QualType qt = td->getUnderlyingType().getCanonicalType();
205  if (qt.isConstQualified()) {
206  property |= kIsConstant;
207  }
208  while (1) {
209  if (qt->isArrayType()) {
210  qt = llvm::cast<clang::ArrayType>(qt)->getElementType();
211  continue;
212  }
213  else if (qt->isReferenceType()) {
214  property |= kIsReference;
215  qt = llvm::cast<clang::ReferenceType>(qt)->getPointeeType();
216  continue;
217  }
218  else if (qt->isPointerType()) {
219  property |= kIsPointer;
220  if (qt.isConstQualified()) {
221  property |= kIsConstPointer;
222  }
223  qt = llvm::cast<clang::PointerType>(qt)->getPointeeType();
224  continue;
225  }
226  else if (qt->isMemberPointerType()) {
227  qt = llvm::cast<clang::MemberPointerType>(qt)->getPointeeType();
228  continue;
229  }
230  break;
231  }
232  if (qt->isBuiltinType()) {
233  property |= kIsFundamental;
234  }
235  if (qt.isConstQualified()) {
236  property |= kIsConstant;
237  }
238  return property;
239 }
240 
241 ////////////////////////////////////////////////////////////////////////////////
242 /// Return the size in bytes of the underlying type of the current typedef.
243 
245 {
246  if (!IsValid()) {
247  return 1;
248  }
249  clang::ASTContext &context = fDecl->getASTContext();
250  const clang::TypedefNameDecl *td = llvm::dyn_cast<clang::TypedefNameDecl>(fDecl);
251  clang::QualType qt = td->getUnderlyingType();
252  if (qt->isDependentType()) {
253  // The underlying type is dependent on a template parameter,
254  // we have no idea what it is yet.
255  return 0;
256  }
257  if (const clang::RecordType *rt = qt->getAs<clang::RecordType>()) {
258  if (!rt->getDecl()->getDefinition()) {
259  // This is a typedef to a forward-declared type.
260  return 0;
261  }
262  }
263 
264  // Deserialization might happen during the size calculation.
265  cling::Interpreter::PushTransactionRAII pushedT(fInterp);
266 
267  // Note: This is an int64_t.
268  clang::CharUnits::QuantityType quantity =
269  context.getTypeSizeInChars(qt).getQuantity();
270  // Truncate cast to fit the CINT interface.
271  return static_cast<int>(quantity);
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Get the name of the underlying type of the current typedef.
276 
278 {
279  if (!IsValid()) {
280  return "(unknown)";
281  }
282  // Note: This must be static because we return a pointer to the internals.
283  TTHREAD_TLS_DECL( std::string, truename);
284  truename.clear();
285  const clang::TypedefNameDecl *td = llvm::dyn_cast<clang::TypedefNameDecl>(fDecl);
286  clang::QualType underlyingType = td->getUnderlyingType();
287  if (underlyingType->isBooleanType()) {
288  return "bool";
289  }
290  const clang::ASTContext &ctxt = fInterp->getCI()->getASTContext();
291  ROOT::TMetaUtils::GetNormalizedName(truename, ctxt.getTypedefType(td), *fInterp, normCtxt);
292 
293  return truename.c_str();
294 }
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 /// Get the name of the current typedef.
298 
299 const char *TClingTypedefInfo::Name() const
300 {
301  if (!IsValid()) {
302  return "(unknown)";
303  }
304  // Note: This must be static because we return a pointer to the internals.
305  TTHREAD_TLS_DECL( std::string, fullname);
306  fullname.clear();
307  const clang::TypedefNameDecl *td = llvm::dyn_cast<clang::TypedefNameDecl>(fDecl);
308  const clang::ASTContext &ctxt = fDecl->getASTContext();
309  ROOT::TMetaUtils::GetFullyQualifiedTypeName(fullname,ctxt.getTypedefType(td),*fInterp);
310  return fullname.c_str();
311 }
312 
313 ////////////////////////////////////////////////////////////////////////////////
314 
316 {
317  if (!IsValid()) {
318  return 0;
319  }
320  //NOTE: We can't use it as a cache due to the "thoughtful" self iterator
321  //if (fTitle.size())
322  // return fTitle.c_str();
323 
324  // Try to get the comment either from the annotation or the header file if present
325 
326  // Iterate over the redeclarations, we can have multiple definitions in the
327  // redecl chain (came from merging of pcms).
328  if (const TypedefNameDecl *TND = llvm::dyn_cast<TypedefNameDecl>(GetDecl())) {
329  if ( (TND = ROOT::TMetaUtils::GetAnnotatedRedeclarable(TND)) ) {
330  if (AnnotateAttr *A = TND->getAttr<AnnotateAttr>()) {
331  fTitle = A->getAnnotation().str();
332  return fTitle.c_str();
333  }
334  }
335  }
336  else if (!GetDecl()->isFromASTFile()) {
337  // Try to get the comment from the header file if present
338  // but not for decls from AST file, where rootcling would have
339  // created an annotation
341  }
342  return fTitle.c_str();
343 }
344 
int InternalNext()
Increment the iterator, return true if new position is valid.
RooArgList L(const RooAbsArg &v1)
void Init(const char *name)
Lookup named typedef and reset the iterator to point to it.
const clang::Decl * fDecl
std::vector< clang::DeclContext::decl_iterator > fIterStack
clang::DeclContext::decl_iterator fIter
std::string InsertStd(const char *tname)
const char * TrueName(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
Get the name of the underlying type of the current typedef.
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
static double A[]
int Next()
Increment the iterator.
long Property() const
Return a bit mask of metadata about the current typedef.
TClingTypedefInfo(cling::Interpreter *interp)
void Error(const char *location, const char *msgfmt,...)
void GetNormalizedName(std::string &norm_name, const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
Return the type name normalized for ROOT, keeping only the ROOT opaque typedef (Double32_t, etc.) and adding default template argument for all types except the STL collections where we remove the default template argument if any.
const T * GetAnnotatedRedeclarable(const T *Redecl)
Definition: TMetaUtils.h:628
const clang::Decl * GetDecl() const
Get the current typedef declaration.
const char * Name() const
Get the name of the current typedef.
int Size() const
Return the size in bytes of the underlying type of the current typedef.
Definition: TCling.h:48
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...
bool IsValid() const
Return true if the current iterator position is valid.
cling::Interpreter * fInterp
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
char name[80]
Definition: TGX11.cxx:109