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