Logo ROOT  
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
13Emulation of the CINT TypedefInfo class.
14
15The CINT C++ interpreter provides an interface to metadata about
16a typedef through the TypedefInfo class. This class provides the
17same functionality, using an interface as close as possible to
18TypedefInfo but the typedef metadata comes from the Clang C++
19compiler, 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
34using 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
40TClingTypedefInfo::TClingTypedefInfo(cling::Interpreter *interp,
41 const char *name)
42 : TClingDeclInfo(nullptr), fInterp(interp), fFirstTime(true), fDescend(false), fTitle("")
43{
44 Init(name);
45}
46
47TClingTypedefInfo::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
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
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
174{
175 return InternalNext();
176}
177
178////////////////////////////////////////////////////////////////////////////////
179/// Return a bit mask of metadata about the current typedef.
180
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 return TClingDeclInfo::Property(property, qt);
191}
192
193////////////////////////////////////////////////////////////////////////////////
194/// Return the size in bytes of the underlying type of the current typedef.
195
197{
198 if (!IsValid()) {
199 return 1;
200 }
201 clang::ASTContext &context = fDecl->getASTContext();
202 const clang::TypedefNameDecl *td = llvm::dyn_cast<clang::TypedefNameDecl>(fDecl);
203 clang::QualType qt = td->getUnderlyingType();
204 if (qt->isDependentType()) {
205 // The underlying type is dependent on a template parameter,
206 // we have no idea what it is yet.
207 return 0;
208 }
209 if (const clang::RecordType *rt = qt->getAs<clang::RecordType>()) {
210 if (!rt->getDecl()->getDefinition()) {
211 // This is a typedef to a forward-declared type.
212 return 0;
213 }
214 }
215
216 // Deserialization might happen during the size calculation.
217 cling::Interpreter::PushTransactionRAII pushedT(fInterp);
218
219 // Note: This is an int64_t.
220 clang::CharUnits::QuantityType quantity =
221 context.getTypeSizeInChars(qt).getQuantity();
222 // Truncate cast to fit the CINT interface.
223 return static_cast<int>(quantity);
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Get the name of the underlying type of the current typedef.
228
230{
231 if (!IsValid()) {
232 return "(unknown)";
233 }
234 // Note: This must be static because we return a pointer to the internals.
235 TTHREAD_TLS_DECL( std::string, truename);
236 truename.clear();
237 const clang::TypedefNameDecl *td = llvm::dyn_cast<clang::TypedefNameDecl>(fDecl);
238 clang::QualType underlyingType = td->getUnderlyingType();
239 if (underlyingType->isBooleanType()) {
240 return "bool";
241 }
242 const clang::ASTContext &ctxt = fInterp->getCI()->getASTContext();
243 ROOT::TMetaUtils::GetNormalizedName(truename, ctxt.getTypedefType(td), *fInterp, normCtxt);
244
245 return truename.c_str();
246}
247
248////////////////////////////////////////////////////////////////////////////////
249/// Get the name of the current typedef.
250
251const char *TClingTypedefInfo::Name() const
252{
253 if (!IsValid()) {
254 return "(unknown)";
255 }
256 if (!fNameCache.empty())
257 return fNameCache.c_str();
258
259 const clang::TypedefNameDecl *td = llvm::cast<clang::TypedefNameDecl>(fDecl);
260 const clang::ASTContext &ctxt = td->getASTContext();
262 return fNameCache.c_str();
263}
264
265////////////////////////////////////////////////////////////////////////////////
266
268{
269 if (!IsValid()) {
270 return 0;
271 }
272 //NOTE: We can't use it as a cache due to the "thoughtful" self iterator
273 //if (fTitle.size())
274 // return fTitle.c_str();
275
276 // Try to get the comment either from the annotation or the header file if present
277
278 // Iterate over the redeclarations, we can have multiple definitions in the
279 // redecl chain (came from merging of pcms).
280 if (const TypedefNameDecl *TND = llvm::dyn_cast<TypedefNameDecl>(GetDecl())) {
282 if (AnnotateAttr *A = TND->getAttr<AnnotateAttr>()) {
283 fTitle = A->getAnnotation().str();
284 return fTitle.c_str();
285 }
286 }
287 }
288 else if (!GetDecl()->isFromASTFile()) {
289 // Try to get the comment from the header file if present
290 // but not for decls from AST file, where rootcling would have
291 // created an annotation
293 }
294 return fTitle.c_str();
295}
296
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
@ kIsTypedef
Definition: TDictionary.h:69
void Error(const char *location, const char *msgfmt,...)
char name[80]
Definition: TGX11.cxx:109
const clang::Decl * fDecl
virtual bool IsValid() const
long Property(long property, clang::QualType &qt) const
std::string fNameCache
virtual const clang::Decl * GetDecl() const
const char * TrueName(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
Get the name of the underlying type of the current typedef.
long Property() const
Return a bit mask of metadata about the current typedef.
clang::DeclContext::decl_iterator fIter
TClingTypedefInfo(cling::Interpreter *interp)
const char * Name() const override
Get the name of the current typedef.
void Init(const char *name)
Lookup named typedef and reset the iterator to point to it.
int InternalNext()
Increment the iterator, return true if new position is valid.
int Next()
Increment the iterator.
int Size() const
Return the size in bytes of the underlying type of the current typedef.
std::vector< clang::DeclContext::decl_iterator > fIterStack
cling::Interpreter * fInterp
static double A[]
const T * GetAnnotatedRedeclarable(const T *Redecl)
Definition: TClingUtils.h:638
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,...
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
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.
std::string InsertStd(const char *tname)
static constexpr double L