Logo ROOT   6.18/05
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 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
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
262const 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
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
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
R__EXTERN Int_t gDebug
Definition: Rtypes.h:91
@ kIsPointer
Definition: TDictionary.h:77
@ kIsConstant
Definition: TDictionary.h:86
@ kIsReference
Definition: TDictionary.h:81
@ kIsConstPointer
Definition: TDictionary.h:88
@ kIsFundamental
Definition: TDictionary.h:70
@ 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
std::string fNameCache
virtual const clang::Decl * GetDecl() const
const char * Name() override
Get the name of the current typedef.
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)
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[]
std::string InsertStd(const char *tname)
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.
Definition: TClassEdit.cxx:821
static constexpr double L