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();
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 if (!td)
204 return 0; // should never happens
205 clang::QualType qt = td->getUnderlyingType();
206 if (qt->isDependentType()) {
207 // The underlying type is dependent on a template parameter,
208 // we have no idea what it is yet.
209 return 0;
210 }
211 if (const clang::RecordType *rt = qt->getAs<clang::RecordType>()) {
212 if (!rt->getDecl()->getDefinition()) {
213 // This is a typedef to a forward-declared type.
214 return 0;
215 }
216 }
217
218 // Deserialization might happen during the size calculation.
219 cling::Interpreter::PushTransactionRAII pushedT(fInterp);
220
221 // Note: This is an int64_t.
222 clang::CharUnits::QuantityType quantity =
223 context.getTypeSizeInChars(qt).getQuantity();
224 // Truncate cast to fit the CINT interface.
225 return static_cast<int>(quantity);
226}
227
228////////////////////////////////////////////////////////////////////////////////
229/// Get the name of the underlying type of the current typedef.
230
232{
233 if (!IsValid()) {
234 return "(unknown)";
235 }
236 // Note: This must be static because we return a pointer to the internals.
237 TTHREAD_TLS_DECL( std::string, truename);
238 truename.clear();
239 const clang::TypedefNameDecl *td = llvm::dyn_cast<clang::TypedefNameDecl>(fDecl);
240 if (!td)
241 return "(badcast)";
242 clang::QualType underlyingType = td->getUnderlyingType();
243 if (underlyingType->isBooleanType()) {
244 return "bool";
245 }
246 const clang::ASTContext &ctxt = fInterp->getCI()->getASTContext();
247 ROOT::TMetaUtils::GetNormalizedName(truename, ctxt.getTypedefType(td), *fInterp, normCtxt);
248
249 return truename.c_str(); // NOLINT
250}
251
252////////////////////////////////////////////////////////////////////////////////
253/// Get the name of the current typedef.
254
255const char *TClingTypedefInfo::Name() const
256{
257 if (!IsValid()) {
258 return "(unknown)";
259 }
260 if (!fNameCache.empty())
261 return fNameCache.c_str();
262
263 const clang::TypedefNameDecl *td = llvm::cast<clang::TypedefNameDecl>(fDecl);
264 const clang::ASTContext &ctxt = td->getASTContext();
266 return fNameCache.c_str();
267}
268
269////////////////////////////////////////////////////////////////////////////////
270
272{
273 if (!IsValid()) {
274 return 0;
275 }
276 //NOTE: We can't use it as a cache due to the "thoughtful" self iterator
277 //if (fTitle.size())
278 // return fTitle.c_str();
279
280 // Try to get the comment either from the annotation or the header file if present
281
282 // Iterate over the redeclarations, we can have multiple definitions in the
283 // redecl chain (came from merging of pcms).
284 if (const TypedefNameDecl *TND = llvm::dyn_cast<TypedefNameDecl>(GetDecl())) {
286 if (AnnotateAttr *A = TND->getAttr<AnnotateAttr>()) {
287 fTitle = A->getAnnotation().str();
288 return fTitle.c_str();
289 }
290 }
291 }
292 else if (!GetDecl()->isFromASTFile()) {
293 // Try to get the comment from the header file if present
294 // but not for decls from AST file, where rootcling would have
295 // created an annotation
297 }
298 return fTitle.c_str();
299}
300
@ kIsTypedef
Definition: TDictionary.h:69
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t property
char name[80]
Definition: TGX11.cxx:110
Int_t gDebug
Definition: TROOT.cxx:585
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:644
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