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