Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TClingDataMemberInfo.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 TClingDataMemberInfo
13
14Emulation of the CINT DataMemberInfo class.
15
16The CINT C++ interpreter provides an interface to metadata about
17the data members of a class through the DataMemberInfo class. This
18class provides the same functionality, using an interface as close
19as possible to DataMemberInfo but the data member metadata comes
20from the Clang C++ compiler, not CINT.
21*/
22
24
25#include "TDictionary.h"
26#include "TClingClassInfo.h"
27#include "TClingTypeInfo.h"
28#include "TClingUtils.h"
29#include "TClassEdit.h"
30#include "TError.h"
31#include "TInterpreter.h"
32#include "TVirtualMutex.h"
33
34#include "cling/Interpreter/Interpreter.h"
35
36#include "clang/AST/Attr.h"
37#include "clang/AST/ASTContext.h"
38#include "clang/AST/Decl.h"
39#include "clang/AST/GlobalDecl.h"
40#include "clang/AST/Expr.h"
41#include "clang/AST/ExprCXX.h"
42#include "clang/AST/PrettyPrinter.h"
43#include "clang/AST/RecordLayout.h"
44#include "clang/AST/Type.h"
45
46#include "llvm/Support/Casting.h"
47#include "llvm/Support/raw_ostream.h"
48#include "llvm/ADT/APSInt.h"
49#include "llvm/ADT/APFloat.h"
50
51using namespace clang;
52
53namespace {
54 static bool IsRelevantKind(clang::Decl::Kind DK)
55 {
56 return DK == clang::Decl::Field || DK == clang::Decl::EnumConstant || DK == clang::Decl::Var;
57 }
58}
59
60bool TClingDataMemberIter::ShouldSkip(const clang::Decl *D) const
61{
63 return true;
64
65 if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) {
66 // Skip unnamed declarations, e.g. in
67 // struct S {
68 // struct { int i; }
69 // };
70 // the inner struct corresponds to an unnamed member variable,
71 // where only `S::i` should be exposed.
72 if (!ND->getIdentifier())
73 return true;
74 } else {
75 // TClingDataMemberIter only cares about NamedDecls.
76 return true;
77 }
78
79 return !IsRelevantKind(D->getKind());
80}
81
82bool TClingDataMemberIter::ShouldSkip(const clang::UsingShadowDecl *USD) const
83{
85 return true;
86
87 if (auto *VD = llvm::dyn_cast<clang::ValueDecl>(USD->getTargetDecl())) {
88 return !IsRelevantKind(VD->getKind());
89 }
90
91 // TODO: handle multi-level UsingShadowDecls.
92 return true;
93}
94
98: TClingDeclInfo(nullptr), fInterp(interp)
99{
100
102
103 if (ci) {
104 fClassInfo = *ci;
105 } else {
106 fClassInfo = TClingClassInfo(interp);
107 }
108
109 if (!ci || !ci->IsValid()) {
110 return;
111 }
112
113 auto *DC = llvm::dyn_cast<clang::DeclContext>(ci->GetDecl());
114
115 fIter = TClingDataMemberIter(interp, DC, selection);
116 fIter.Init();
117}
118
120 const clang::ValueDecl *ValD,
121 TClingClassInfo *ci)
122: TClingDeclInfo(ValD), fInterp(interp)
123{
124
125 if (ci) {
126 fClassInfo = *ci;
127 } else {
128 fClassInfo = TClingClassInfo(interp);
129 }
130
131 using namespace llvm;
132 const auto DC = ValD->getDeclContext();
133 (void)DC;
134 assert((ci || isa<TranslationUnitDecl>(DC) ||
135 ((DC->isTransparentContext() || DC->isInlineNamespace()) && isa<TranslationUnitDecl>(DC->getParent()) ) ||
136 isa<EnumConstantDecl>(ValD)) && "Not TU?");
137 assert(IsRelevantKind(ValD->getKind()) &&
138 "The decl should be either VarDecl or FieldDecl or EnumConstDecl");
139
140}
141
143{
144 // Three cases:
145 // 1) 00: none to be checked
146 // 2) 01: type to be checked
147 // 3) 10: none to be checked
148 // 4) 11: both to be checked
149 unsigned int code = fIoType.empty() + (int(fIoName.empty()) << 1);
150
151 if (code == 0) return;
152
153 const Decl* decl = GetTargetValueDecl();
154
155 if (code == 3 || code == 2) ROOT::TMetaUtils::ExtractAttrPropertyFromName(*decl,"ioname",fIoName);
156 if (code == 3 || code == 1) ROOT::TMetaUtils::ExtractAttrPropertyFromName(*decl,"iotype",fIoType);
157
158}
159
161{
162 if (!IsValid()) {
163 return TDictionary::DeclId_t();
164 }
165 if (auto *VD = GetAsValueDecl())
166 return (const clang::Decl*)(VD->getCanonicalDecl());
167 return (const clang::Decl*)(GetAsUsingShadowDecl()->getCanonicalDecl());
168}
169
170const clang::ValueDecl *TClingDataMemberInfo::GetAsValueDecl() const
171{
172 return dyn_cast<ValueDecl>(GetDecl());
173}
174
175const clang::UsingShadowDecl *TClingDataMemberInfo::GetAsUsingShadowDecl() const
176{
177 return dyn_cast<UsingShadowDecl>(GetDecl());
178}
179
180const clang::ValueDecl *TClingDataMemberInfo::GetTargetValueDecl() const
181{
182 const Decl *D = GetDecl();
183 do {
184 if (auto VD = dyn_cast<ValueDecl>(D))
185 return VD;
186 } while ((D = dyn_cast<UsingShadowDecl>(D)->getTargetDecl()));
187 return nullptr;
188}
189
190const clang::Type *TClingDataMemberInfo::GetClassAsType() const {
191 return fClassInfo.GetType();
192}
193
195{
196 if (!IsValid()) {
197 return -1;
198 }
199 const clang::ValueDecl *VD = GetTargetValueDecl();
200 // Sanity check the current data member.
201 clang::Decl::Kind DK = VD->getKind();
202 if (
203 (DK != clang::Decl::Field) &&
204 (DK != clang::Decl::Var) &&
205 (DK != clang::Decl::EnumConstant)
206 ) {
207 // Error, was not a data member, variable, or enumerator.
208 return -1;
209 }
210 if (DK == clang::Decl::EnumConstant) {
211 // We know that an enumerator value does not have array type.
212 return 0;
213 }
214 // To get this information we must count the number
215 // of array type nodes in the canonical type chain.
216 clang::QualType QT = VD->getType().getCanonicalType();
217 int cnt = 0;
218 while (1) {
219 if (QT->isArrayType()) {
220 ++cnt;
221 QT = llvm::cast<clang::ArrayType>(QT)->getElementType();
222 continue;
223 }
224 else if (QT->isReferenceType()) {
225 QT = llvm::cast<clang::ReferenceType>(QT)->getPointeeType();
226 continue;
227 }
228 else if (QT->isPointerType()) {
229 QT = llvm::cast<clang::PointerType>(QT)->getPointeeType();
230 continue;
231 }
232 else if (QT->isMemberPointerType()) {
233 QT = llvm::cast<clang::MemberPointerType>(QT)->getPointeeType();
234 continue;
235 }
236 break;
237 }
238 return cnt;
239}
240
242{
243 if (!IsValid()) {
244 return -1;
245 }
246 const clang::ValueDecl *VD = GetTargetValueDecl();
247 // Sanity check the current data member.
248 clang::Decl::Kind DK = GetDecl()->getKind();
249 if (
250 (DK != clang::Decl::Field) &&
251 (DK != clang::Decl::Var) &&
252 (DK != clang::Decl::EnumConstant)
253 ) {
254 // Error, was not a data member, variable, or enumerator.
255 return -1;
256 }
257 if (DK == clang::Decl::EnumConstant) {
258 // We know that an enumerator value does not have array type.
259 return 0;
260 }
261 // To get this information we must count the number
262 // of array type nodes in the canonical type chain.
263 clang::QualType QT = VD->getType().getCanonicalType();
264 int paran = ArrayDim();
265 if ((dim < 0) || (dim >= paran)) {
266 // Passed dimension is out of bounds.
267 return -1;
268 }
269 int cnt = dim;
270 int max = 0;
271 while (1) {
272 if (QT->isArrayType()) {
273 if (cnt == 0) {
274 if (const clang::ConstantArrayType *CAT =
275 llvm::dyn_cast<clang::ConstantArrayType>(QT)
276 ) {
277 max = static_cast<int>(CAT->getSize().getZExtValue());
278 }
279 else if (llvm::dyn_cast<clang::IncompleteArrayType>(QT)) {
280 max = INT_MAX;
281 }
282 else {
283 max = -1;
284 }
285 break;
286 }
287 --cnt;
288 QT = llvm::cast<clang::ArrayType>(QT)->getElementType();
289 continue;
290 }
291 else if (QT->isReferenceType()) {
292 QT = llvm::cast<clang::ReferenceType>(QT)->getPointeeType();
293 continue;
294 }
295 else if (QT->isPointerType()) {
296 QT = llvm::cast<clang::PointerType>(QT)->getPointeeType();
297 continue;
298 }
299 else if (QT->isMemberPointerType()) {
300 QT = llvm::cast<clang::MemberPointerType>(QT)->getPointeeType();
301 continue;
302 }
303 break;
304 }
305 return max;
306}
307
309{
310 assert(!fDecl && "This is a single decl, not an iterator!");
311
312 ClearNames();
313
314 if (!fFirstTime && !fIter.IsValid()) {
315 // Iterator is already invalid.
316 return 0;
317 }
318 // Advance to the next decl.
319 if (fFirstTime) {
320 // The cint semantics are weird.
321 fFirstTime = false;
322 } else {
323 fIter.Next();
324 }
325 return fIter.IsValid();
326}
327
329{
330 using namespace clang;
331
332 if (!IsValid()) {
333 return -1L;
334 }
335
336 const ValueDecl *D = GetTargetValueDecl();
337 ASTContext& C = D->getASTContext();
338 if (const FieldDecl *FldD = dyn_cast<FieldDecl>(D)) {
339 // The current member is a non-static data member.
340 const clang::RecordDecl *RD = FldD->getParent();
341 const clang::ASTRecordLayout &Layout = C.getASTRecordLayout(RD);
342 uint64_t bits = Layout.getFieldOffset(FldD->getFieldIndex());
343 int64_t offset = C.toCharUnitsFromBits(bits).getQuantity();
344 return static_cast<long>(offset);
345 }
346 else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
347 // Could trigger deserialization of decls, in particular in case
348 // of constexpr, like:
349 // static constexpr Long64_t something = std::numeric_limits<Long64_t>::max();
350 cling::Interpreter::PushTransactionRAII RAII(fInterp);
351
352 if (long addr = reinterpret_cast<long>(fInterp->getAddressOfGlobal(GlobalDecl(VD))))
353 return addr;
354 auto evalStmt = VD->ensureEvaluatedStmt();
355 if (evalStmt && evalStmt->Value) {
356 if (const APValue* val = VD->evaluateValue()) {
357 if (VD->getType()->isIntegralType(C)) {
358 return reinterpret_cast<long>(val->getInt().getRawData());
359 } else {
360 // The VD stores the init value; its lifetime should the lifetime of
361 // this offset.
362 switch (val->getKind()) {
363 case APValue::Int: {
364 if (val->getInt().isSigned())
365 fConstInitVal.fLong = (long)val->getInt().getSExtValue();
366 else
367 fConstInitVal.fLong = (long)val->getInt().getZExtValue();
368 return (long) &fConstInitVal.fLong;
369 }
370 case APValue::Float:
371 if (&val->getFloat().getSemantics()
372 == (const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle()) {
373 fConstInitVal.fFloat = val->getFloat().convertToFloat();
374 return (long)&fConstInitVal.fFloat;
375 } else if (&val->getFloat().getSemantics()
376 == (const llvm::fltSemantics*) &llvm::APFloat::IEEEdouble()) {
377 fConstInitVal.fDouble = val->getFloat().convertToDouble();
378 return (long)&fConstInitVal.fDouble;
379 }
380 // else fall-through
381 default:
382 ;// fall-through
383 };
384 // fall-through
385 } // not integral type
386 } // have an APValue
387 } // have an initializing value
388 }
389 // FIXME: We have to explicitly check for not enum constant because the
390 // implementation of getAddressOfGlobal relies on mangling the name and in
391 // clang there is misbehaviour in MangleContext::shouldMangleDeclName.
392 // enum constants are essentially numbers and don't get addresses. However
393 // ROOT expects the address to the enum constant initializer to be returned.
394 else if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
395 // The raw data is stored as a long long, so we need to find the 'long'
396 // part.
397#ifdef R__BYTESWAP
398 // In this case at the beginning.
399 return reinterpret_cast<long>(ECD->getInitVal().getRawData());
400#else
401 // In this case in the second part.
402 return reinterpret_cast<long>(((char*)ECD->getInitVal().getRawData())+sizeof(long) );
403#endif
404 return -1L;
405}
406
408{
409 if (!IsValid()) {
410 return 0L;
411 }
412 long property = 0L;
413
414 // If the declaration is public in a private nested struct, make the declaration
415 // private nonetheless, as for outside access (e.g. ROOT I/O) it's private:
416 // NOTE: this uses `GetDecl()`, to capture the access of the UsingShadowDecl,
417 // which is defined in the derived class and might differ from the access of the decl
418 // in the base class.
419 // TODO: move this somewhere such that TClingMethodInfo can use this, too.
420 const Decl *thisDecl = GetDecl();
421 clang::AccessSpecifier strictestAccess = thisDecl->getAccess();
422 const DeclContext *nonTransparentDC = thisDecl->getDeclContext();
423
424 auto getParentAccessAndNonTransparentDC = [&]() {
425 const Decl *declOrParent = thisDecl;
426 for (const auto *Parent = declOrParent->getDeclContext(); !llvm::isa<TranslationUnitDecl>(Parent);
427 Parent = declOrParent->getDeclContext()) {
428 if (!Parent->isTransparentContext()) {
429 if (const auto *RD = llvm::dyn_cast<clang::RecordDecl>(Parent)) {
430 if (!RD->isAnonymousStructOrUnion()) {
431 nonTransparentDC = RD;
432 break;
433 }
434 } else {
435 nonTransparentDC = Parent;
436 break;
437 }
438 }
439
440 declOrParent = llvm::dyn_cast<clang::Decl>(Parent);
441 if (strictestAccess < declOrParent->getAccess()) {
442 strictestAccess = declOrParent->getAccess();
443 }
444 }
445 };
446
447 getParentAccessAndNonTransparentDC();
448
449 switch (strictestAccess) {
450 case clang::AS_public:
451 property |= kIsPublic;
452 break;
453 case clang::AS_protected:
454 property |= kIsProtected;
455 break;
456 case clang::AS_private:
457 property |= kIsPrivate;
458 break;
459 case clang::AS_none: //?
460 property |= kIsPublic;
461 break;
462 default:
463 // IMPOSSIBLE
464 break;
465 }
466 if (llvm::isa<clang::UsingShadowDecl>(thisDecl))
467 property |= kIsUsing;
468
469 const clang::ValueDecl *vd = GetTargetValueDecl();
470 if (const clang::VarDecl *vard = llvm::dyn_cast<clang::VarDecl>(vd)) {
471 if (vard->isConstexpr())
472 property |= kIsConstexpr;
473 if (vard->getStorageClass() == clang::SC_Static) {
474 property |= kIsStatic;
475 } else if (nonTransparentDC->isNamespace()) {
476 // Data members of a namespace are global variable which were
477 // considered to be 'static' in the CINT (and thus ROOT) scheme.
478 property |= kIsStatic;
479 }
480 } else if (llvm::isa<clang::EnumConstantDecl>(vd)) {
481 // Enumeration constant are considered to be 'static' data member in
482 // the CINT (and thus ROOT) scheme.
483 property |= kIsStatic;
484 }
485 clang::QualType qt = vd->getType();
486 if (llvm::isa<clang::TypedefType>(qt)) {
487 property |= kIsTypedef;
488 }
489 qt = qt.getCanonicalType();
490 property = TClingDeclInfo::Property(property, qt);
491 const clang::TagType *tt = qt->getAs<clang::TagType>();
492 if (tt) {
493 // tt->getDecl() might deserialize.
494 cling::Interpreter::PushTransactionRAII RAII(fInterp);
495 const clang::TagDecl *td = tt->getDecl();
496 if (td->isClass()) {
497 property |= kIsClass;
498 }
499 else if (td->isStruct()) {
500 property |= kIsStruct;
501 }
502 else if (td->isUnion()) {
503 property |= kIsUnion;
504 }
505 else if (td->isEnum()) {
506 property |= kIsEnum;
507 }
508 }
509
510 if (const auto *RD = llvm::dyn_cast<RecordDecl>(thisDecl->getDeclContext())) {
511 if (RD->isUnion())
512 property |= kIsUnionMember;
513 }
514 // We can't be a namespace, can we?
515 // if (dc->isNamespace() && !dc->isTranslationUnit()) {
516 // property |= kIsNamespace;
517 // }
518 return property;
519}
520
522{
523 if (!IsValid()) {
524 return 0L;
525 }
526 const clang::ValueDecl *vd = GetTargetValueDecl();
527 clang::QualType qt = vd->getType();
528 return TClingTypeInfo(fInterp, qt).Property();
529}
530
532{
533 if (!IsValid()) {
534 return -1;
535 }
536
537 const clang::ValueDecl *vd = GetTargetValueDecl();
538 // Sanity check the current data member.
539 clang::Decl::Kind dk = vd->getKind();
540 if ((dk != clang::Decl::Field) && (dk != clang::Decl::Var) &&
541 (dk != clang::Decl::EnumConstant)) {
542 // Error, was not a data member, variable, or enumerator.
543 return -1;
544 }
545 clang::QualType qt = vd->getType();
546 if (qt->isIncompleteType()) {
547 // We cannot determine the size of forward-declared types.
548 return -1;
549 }
550 clang::ASTContext &context = GetDecl()->getASTContext();
551 // Truncate cast to fit to cint interface.
552 return static_cast<int>(context.getTypeSizeInChars(qt).getQuantity());
553}
554
556{
557 if (!IsValid()) {
558 return 0;
559 }
560
562 if (!fIoType.empty()) return fIoType.c_str();
563
564 // Note: This must be static because we return a pointer inside it!
565 static std::string buf;
566 buf.clear();
567 const clang::ValueDecl *vd = GetTargetValueDecl();
568 clang::QualType vdType = vd->getType();
569 // In CINT's version, the type name returns did *not* include any array
570 // information, ROOT's existing code depends on it.
571 while (vdType->isArrayType()) {
572 vdType = GetDecl()->getASTContext().getQualifiedType(vdType->getBaseElementTypeUnsafe(),vdType.getQualifiers());
573 }
574
575 // if (we_need_to_do_the_subst_because_the_class_is_a_template_instance_of_double32_t)
577
579
580 return buf.c_str();
581}
582
584{
585 if (!IsValid()) {
586 return 0;
587 }
588
590 if (!fIoType.empty()) return fIoType.c_str();
591
592 // Note: This must be static because we return a pointer inside it!
593 static std::string buf;
594 buf.clear();
595 const clang::ValueDecl *vd = GetTargetValueDecl();
596 // if (we_need_to_do_the_subst_because_the_class_is_a_template_instance_of_double32_t)
597 clang::QualType vdType = ROOT::TMetaUtils::ReSubstTemplateArg(vd->getType(), GetClassAsType());
598
599 ROOT::TMetaUtils::GetNormalizedName(buf, vdType, *fInterp, normCtxt);
600
601 // In CINT's version, the type name returns did *not* include any array
602 // information, ROOT's existing code depends on it.
603 // This might become part of the implementation of GetNormalizedName.
604 while (buf.length() && buf[buf.length()-1] == ']') {
605 size_t last = buf.rfind('['); // if this is not the bracket we are looking, the type is malformed.
606 if (last != std::string::npos) {
607 buf.erase(last);
608 }
609 }
610 return buf.c_str();
611}
612
613const char *TClingDataMemberInfo::Name() const
614{
615 if (!IsValid()) {
616 return 0;
617 }
618
620 if (!fIoName.empty()) return fIoName.c_str();
621
622 return TClingDeclInfo::Name();
623}
624
626{
627 if (!IsValid()) {
628 return 0;
629 }
630
631 //NOTE: We can't use it as a cache due to the "thoughtful" self iterator
632 //if (fTitle.size())
633 // return fTitle.c_str();
634
635 bool titleFound=false;
636 // Try to get the comment either from the annotation or the header file if present
637 std::string attribute_s;
638 const Decl* decl = GetTargetValueDecl();
639 for (Decl::attr_iterator attrIt = decl->attr_begin();
640 attrIt!=decl->attr_end() && !titleFound ;++attrIt){
641 if (0 == ROOT::TMetaUtils::extractAttrString(*attrIt, attribute_s) &&
642 attribute_s.find(ROOT::TMetaUtils::propNames::separator) == std::string::npos){
643 fTitle = attribute_s;
644 titleFound=true;
645 }
646 }
647
648 if (!titleFound && !decl->isFromASTFile()) {
649 // Try to get the comment from the header file if present
650 // but not for decls from AST file, where rootcling would have
651 // created an annotation
653 }
654
655 return fTitle.c_str();
656}
657
658// ValidArrayIndex return a static string (so use it or copy it immediately, do not
659// call GrabIndex twice in the same expression) containing the size of the
660// array data member.
662{
663 if (!IsValid()) {
664 return llvm::StringRef();
665 }
666 const clang::DeclaratorDecl *FD = llvm::dyn_cast<clang::DeclaratorDecl>(GetTargetValueDecl());
668 else return llvm::StringRef();
669}
670
long
@ kIsPublic
Definition TDictionary.h:75
@ kIsUnionMember
Definition TDictionary.h:74
@ kIsConstexpr
Definition TDictionary.h:93
@ kIsClass
Definition TDictionary.h:65
@ kIsEnum
Definition TDictionary.h:68
@ kIsPrivate
Definition TDictionary.h:77
@ kIsUsing
Definition TDictionary.h:97
@ kIsStatic
Definition TDictionary.h:80
@ kIsStruct
Definition TDictionary.h:66
@ kIsProtected
Definition TDictionary.h:76
@ kIsUnion
Definition TDictionary.h:67
@ kIsTypedef
Definition TDictionary.h:69
R__EXTERN TVirtualMutex * gInterpreterMutex
typedef void((*Func_t)())
#define R__LOCKGUARD(mutex)
Emulation of the CINT ClassInfo class.
const clang::Type * GetType() const
const char * TypeName() const
const clang::Type * GetClassAsType() const
const clang::Decl * GetDecl() const override
const char * TypeTrueName(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
const clang::UsingShadowDecl * GetAsUsingShadowDecl() const
TClingDataMemberInfo(cling::Interpreter *interp)
union TClingDataMemberInfo::@29 fConstInitVal
cling::Interpreter * fInterp
const clang::ValueDecl * GetTargetValueDecl() const
Get the ValueDecl, or if this represents a UsingShadowDecl, the underlying target ValueDecl.
const clang::ValueDecl * GetAsValueDecl() const
llvm::StringRef ValidArrayIndex() const
const char * Name() const override
TClingDataMemberIter fIter
Iterate over VarDecl, FieldDecl, EnumConstantDecl, IndirectFieldDecl, and UsingShadowDecls thereof,...
TDictionary::EMemberSelection fSelection
bool ShouldSkip(const clang::Decl *FD) const final
const clang::Decl * fDecl
virtual const char * Name() const
virtual bool IsValid() const
long Property(long property, clang::QualType &qt) const
virtual const clang::Decl * GetDecl() const
bool Next()
Advance to next non-skipped; return false if no next decl exists.
virtual bool IsValid() const
Emulation of the CINT TypeInfo class.
long Property() const
static bool WantsRegularMembers(EMemberSelection sel)
EMemberSelection
Kinds of members to include in lists.
static bool WantsUsingDecls(EMemberSelection sel)
const void * DeclId_t
static const std::string separator("@@@")
llvm::StringRef DataMemberInfo__ValidArrayIndex(const clang::DeclaratorDecl &m, int *errnum=0, llvm::StringRef *errstr=0)
ValidArrayIndex return a static string (so use it or copy it immediatly, do not call GrabIndex twice ...
int extractAttrString(clang::Attr *attribute, std::string &attrString)
Extract attr string.
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,...
clang::QualType ReSubstTemplateArg(clang::QualType input, const clang::Type *instance)
Check if 'input' or any of its template parameter was substituted when instantiating the class templa...
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
bool ExtractAttrPropertyFromName(const clang::Decl &decl, const std::string &propName, std::string &propValue)
This routine counts on the "propName<separator>propValue" format.
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.
auto * tt
Definition textangle.C:16