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 "clang/Interpreter/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 {
109 }
110
111 if (!ci || !ci->IsValid()) {
112 return;
113 }
114
115 auto *DC = llvm::dyn_cast<clang::DeclContext>(ci->GetDecl());
116
118 fIter.Init();
119}
120
122 const clang::ValueDecl *ValD,
124: TClingDeclInfo(ValD), fInterp(interp)
125{
126
127 if (ci) {
128 fClassInfo = *ci;
129 } else {
131 }
132
133 using namespace llvm;
134 const auto DC = ValD->getDeclContext();
135 (void)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{
175}
176
177const clang::UsingShadowDecl *TClingDataMemberInfo::GetAsUsingShadowDecl() const
178{
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
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()) {
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;
459 strictestAccess = declOrParent->getAccess();
460 }
461 }
462 };
463
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();
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();
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
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){
655 attribute_s.find(ROOT::TMetaUtils::propNames::separator) == std::string::npos){
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
Definition RtypesCore.h:75
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
@ 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
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 offset
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
R__EXTERN TVirtualMutex * gInterpreterMutex
#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
union TClingDataMemberInfo::@28 fConstInitVal
const clang::UsingShadowDecl * GetAsUsingShadowDecl() const
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
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("@@@")
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