Logo ROOT   6.08/07
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.
int Size() const
Return the size in bytes of the underlying type of the current typedef.
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
const char * Name() const
Get the name of the current typedef.
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[]
long Property() const
Return a bit mask of metadata about the current typedef.
int Next()
Increment the iterator.
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
bool IsValid() const
Return true if the current iterator position is valid.
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...
cling::Interpreter * fInterp
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
const clang::Decl * GetDecl() const
Get the current typedef declaration.
char name[80]
Definition: TGX11.cxx:109