27 #include "TClingUtils.h"
31 #include "clang/AST/Attr.h"
32 #include "clang/AST/ASTContext.h"
33 #include "clang/AST/Decl.h"
34 #include "clang/AST/GlobalDecl.h"
35 #include "clang/AST/Expr.h"
36 #include "clang/AST/ExprCXX.h"
37 #include "clang/AST/PrettyPrinter.h"
38 #include "clang/AST/RecordLayout.h"
39 #include "clang/AST/Type.h"
41 #include "llvm/Support/Casting.h"
42 #include "llvm/Support/raw_ostream.h"
43 #include "llvm/ADT/APSInt.h"
44 #include "llvm/ADT/APFloat.h"
46 using namespace clang;
48 TClingDataMemberInfo::TClingDataMemberInfo(cling::Interpreter *interp,
50 : TClingDeclInfo(nullptr), fInterp(interp), fClassInfo(0), fFirstTime(true), fTitle(
""), fContextIdx(0U), fIoType(
""), fIoName(
"")
54 fClassInfo =
new TClingClassInfo(interp);
56 fClassInfo =
new TClingClassInfo(*ci);
58 if (fClassInfo->IsValid()) {
59 Decl *D =
const_cast<Decl*
>(fClassInfo->GetDecl());
61 clang::DeclContext *dc = llvm::cast<clang::DeclContext>(D);
62 dc->collectAllContexts(fContexts);
65 cling::Interpreter::PushTransactionRAII RAII(interp);
66 fIter = llvm::cast<clang::DeclContext>(D)->decls_begin();
67 const TagDecl *TD = ROOT::TMetaUtils::GetAnnotatedRedeclarable(llvm::dyn_cast<TagDecl>(D));
69 fIter = TD->decls_begin();
78 TClingDataMemberInfo::TClingDataMemberInfo(cling::Interpreter *interp,
79 const clang::ValueDecl *ValD,
81 : TClingDeclInfo(ValD), fInterp(interp), fClassInfo(ci ? new TClingClassInfo(*ci) : new TClingClassInfo(interp, ValD)), fFirstTime(true),
82 fTitle(
""), fContextIdx(0U), fIoType(
""), fIoName(
""){
85 const auto DC = ValD->getDeclContext();
87 assert((ci || isa<TranslationUnitDecl>(DC) ||
88 ((DC->isTransparentContext() || DC->isInlineNamespace()) && isa<TranslationUnitDecl>(DC->getParent()) ) ||
89 isa<EnumConstantDecl>(ValD)) &&
"Not TU?");
90 assert((isa<VarDecl>(ValD) ||
91 isa<FieldDecl>(ValD) ||
92 isa<EnumConstantDecl>(ValD) ||
93 isa<IndirectFieldDecl>(ValD)) &&
94 "The decl should be either VarDecl or FieldDecl or EnumConstDecl");
98 void TClingDataMemberInfo::CheckForIoTypeAndName()
const
105 unsigned int code = fIoType.empty() + (int(fIoName.empty()) << 1);
107 if (code == 0)
return;
109 const Decl* decl = GetDecl();
111 if (code == 3 || code == 2) ROOT::TMetaUtils::ExtractAttrPropertyFromName(*decl,
"ioname",fIoName);
112 if (code == 3 || code == 1) ROOT::TMetaUtils::ExtractAttrPropertyFromName(*decl,
"iotype",fIoType);
116 TDictionary::DeclId_t TClingDataMemberInfo::GetDeclId()
const
119 return TDictionary::DeclId_t();
121 return (
const clang::Decl*)(GetDecl()->getCanonicalDecl());
124 int TClingDataMemberInfo::ArrayDim()
const
130 clang::Decl::Kind DK = GetDecl()->getKind();
132 (DK != clang::Decl::Field) &&
133 (DK != clang::Decl::Var) &&
134 (DK != clang::Decl::EnumConstant)
139 if (DK == clang::Decl::EnumConstant) {
145 const clang::ValueDecl *VD = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
146 clang::QualType QT = VD->getType().getCanonicalType();
149 if (QT->isArrayType()) {
151 QT = llvm::cast<clang::ArrayType>(QT)->getElementType();
154 else if (QT->isReferenceType()) {
155 QT = llvm::cast<clang::ReferenceType>(QT)->getPointeeType();
158 else if (QT->isPointerType()) {
159 QT = llvm::cast<clang::PointerType>(QT)->getPointeeType();
162 else if (QT->isMemberPointerType()) {
163 QT = llvm::cast<clang::MemberPointerType>(QT)->getPointeeType();
171 int TClingDataMemberInfo::MaxIndex(
int dim)
const
177 clang::Decl::Kind DK = GetDecl()->getKind();
179 (DK != clang::Decl::Field) &&
180 (DK != clang::Decl::Var) &&
181 (DK != clang::Decl::EnumConstant)
186 if (DK == clang::Decl::EnumConstant) {
192 const clang::ValueDecl *VD = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
193 clang::QualType QT = VD->getType().getCanonicalType();
194 int paran = ArrayDim();
195 if ((dim < 0) || (dim >= paran)) {
202 if (QT->isArrayType()) {
204 if (
const clang::ConstantArrayType *CAT =
205 llvm::dyn_cast<clang::ConstantArrayType>(QT)
207 max =
static_cast<int>(CAT->getSize().getZExtValue());
209 else if (llvm::dyn_cast<clang::IncompleteArrayType>(QT)) {
218 QT = llvm::cast<clang::ArrayType>(QT)->getElementType();
221 else if (QT->isReferenceType()) {
222 QT = llvm::cast<clang::ReferenceType>(QT)->getPointeeType();
225 else if (QT->isPointerType()) {
226 QT = llvm::cast<clang::PointerType>(QT)->getPointeeType();
229 else if (QT->isMemberPointerType()) {
230 QT = llvm::cast<clang::MemberPointerType>(QT)->getPointeeType();
238 int TClingDataMemberInfo::InternalNext()
241 &&
"This is a single decl, not an iterator!");
244 bool increment =
true;
246 while (fFirstTime || *fIter) {
251 else if (increment) {
259 if (fIterStack.size()) {
261 fIter = fIterStack.back();
262 fIterStack.pop_back();
268 if (fContextIdx >= fContexts.size()) {
272 clang::DeclContext *dc = fContexts[fContextIdx];
274 cling::Interpreter::PushTransactionRAII RAII(fInterp);
275 fIter = dc->decls_begin();
284 clang::Decl::Kind DK = fIter->getKind();
285 if (DK == clang::Decl::Enum) {
288 fIterStack.push_back(fIter);
289 cling::Interpreter::PushTransactionRAII RAII(fInterp);
290 fIter = llvm::dyn_cast<clang::DeclContext>(*fIter)->decls_begin();
294 if ((DK == clang::Decl::Field) || (DK == clang::Decl::EnumConstant) ||
295 (DK == clang::Decl::Var)) {
301 if (
auto NS = dyn_cast<NamespaceDecl>(*fIter)) {
302 if (NS->getDeclContext()->isTranslationUnit() && NS->isInlineNamespace())
303 fContexts.push_back(NS);
309 long TClingDataMemberInfo::Offset()
311 using namespace clang;
317 const Decl *D = GetDecl();
318 ASTContext& C = D->getASTContext();
319 if (
const FieldDecl *FldD = dyn_cast<FieldDecl>(D)) {
321 const clang::RecordDecl *RD = FldD->getParent();
322 const clang::ASTRecordLayout &Layout = C.getASTRecordLayout(RD);
323 uint64_t bits = Layout.getFieldOffset(FldD->getFieldIndex());
324 int64_t offset = C.toCharUnitsFromBits(bits).getQuantity();
325 return static_cast<long>(offset);
327 else if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
331 cling::Interpreter::PushTransactionRAII RAII(fInterp);
333 if (
long addr = reinterpret_cast<long>(fInterp->getAddressOfGlobal(GlobalDecl(VD))))
335 auto evalStmt = VD->ensureEvaluatedStmt();
336 if (evalStmt && evalStmt->Value) {
337 if (
const APValue* val = VD->evaluateValue()) {
338 if (VD->getType()->isIntegralType(C)) {
339 return reinterpret_cast<long>(val->getInt().getRawData());
343 switch (val->getKind()) {
345 if (val->getInt().isSigned())
346 fConstInitVal.fLong = (
long)val->getInt().getSExtValue();
348 fConstInitVal.fLong = (long)val->getInt().getZExtValue();
349 return (
long) &fConstInitVal.fLong;
352 if (&val->getFloat().getSemantics()
353 == (
const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle()) {
354 fConstInitVal.fFloat = val->getFloat().convertToFloat();
355 return (
long)&fConstInitVal.fFloat;
356 }
else if (&val->getFloat().getSemantics()
357 == (
const llvm::fltSemantics*) &llvm::APFloat::IEEEdouble()) {
358 fConstInitVal.fDouble = val->getFloat().convertToDouble();
359 return (
long)&fConstInitVal.fDouble;
375 else if (
const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
380 return reinterpret_cast<long>(ECD->getInitVal().getRawData());
383 return reinterpret_cast<long>(((
char*)ECD->getInitVal().getRawData())+
sizeof(
long) );
388 long TClingDataMemberInfo::Property()
const
394 const clang::Decl *declaccess = GetDecl();
395 if (declaccess->getDeclContext()->isTransparentContext()) {
396 declaccess = llvm::dyn_cast<clang::Decl>(declaccess->getDeclContext());
397 if (!declaccess) declaccess = GetDecl();
399 switch (declaccess->getAccess()) {
400 case clang::AS_public:
401 property |= kIsPublic;
403 case clang::AS_protected:
404 property |= kIsProtected;
406 case clang::AS_private:
407 property |= kIsPrivate;
410 if (declaccess->getDeclContext()->isNamespace()) {
411 property |= kIsPublic;
420 if (
const clang::VarDecl *vard = llvm::dyn_cast<clang::VarDecl>(GetDecl())) {
421 if (vard->isConstexpr())
422 property |= kIsConstexpr;
423 if (vard->getStorageClass() == clang::SC_Static) {
424 property |= kIsStatic;
425 }
else if (declaccess->getDeclContext()->isNamespace()) {
428 property |= kIsStatic;
431 if (llvm::isa<clang::EnumConstantDecl>(GetDecl())) {
434 property |= kIsStatic;
436 const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
437 clang::QualType qt = vd->getType();
438 if (llvm::isa<clang::TypedefType>(qt)) {
439 property |= kIsTypedef;
441 qt = qt.getCanonicalType();
442 if (qt.isConstQualified()) {
443 property |= kIsConstant;
446 if (qt->isArrayType()) {
447 property |= kIsArray;
448 qt = llvm::cast<clang::ArrayType>(qt)->getElementType();
451 else if (qt->isReferenceType()) {
452 property |= kIsReference;
453 qt = llvm::cast<clang::ReferenceType>(qt)->getPointeeType();
456 else if (qt->isPointerType()) {
457 property |= kIsPointer;
458 if (qt.isConstQualified()) {
459 property |= kIsConstPointer;
461 qt = llvm::cast<clang::PointerType>(qt)->getPointeeType();
464 else if (qt->isMemberPointerType()) {
465 qt = llvm::cast<clang::MemberPointerType>(qt)->getPointeeType();
470 if (qt->isBuiltinType()) {
471 property |= kIsFundamental;
473 if (qt.isConstQualified()) {
474 property |= kIsConstant;
476 const clang::TagType *tt = qt->getAs<clang::TagType>();
478 const clang::TagDecl *td = tt->getDecl();
480 property |= kIsClass;
482 else if (td->isStruct()) {
483 property |= kIsStruct;
485 else if (td->isUnion()) {
486 property |= kIsUnion;
488 else if (td->isEnum()) {
499 long TClingDataMemberInfo::TypeProperty()
const
504 const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
505 clang::QualType qt = vd->getType();
506 return TClingTypeInfo(fInterp, qt).Property();
509 int TClingDataMemberInfo::TypeSize()
const
516 clang::Decl::Kind dk = GetDecl()->getKind();
517 if ((dk != clang::Decl::Field) && (dk != clang::Decl::Var) &&
518 (dk != clang::Decl::EnumConstant)) {
522 const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
523 clang::QualType qt = vd->getType();
524 if (qt->isIncompleteType()) {
528 clang::ASTContext &context = GetDecl()->getASTContext();
530 return static_cast<int>(context.getTypeSizeInChars(qt).getQuantity());
533 const char *TClingDataMemberInfo::TypeName()
const
539 CheckForIoTypeAndName();
540 if (!fIoType.empty())
return fIoType.c_str();
543 static std::string buf;
545 if (
const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl())) {
546 clang::QualType vdType = vd->getType();
549 while (vdType->isArrayType()) {
550 vdType = GetDecl()->getASTContext().getQualifiedType(vdType->getBaseElementTypeUnsafe(),vdType.getQualifiers());
554 vdType = ROOT::TMetaUtils::ReSubstTemplateArg(vdType, fClassInfo->GetType() );
556 ROOT::TMetaUtils::GetFullyQualifiedTypeName(buf, vdType, *fInterp);
563 const char *TClingDataMemberInfo::TypeTrueName(
const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
const
569 CheckForIoTypeAndName();
570 if (!fIoType.empty())
return fIoType.c_str();
573 static std::string buf;
575 if (
const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl())) {
577 clang::QualType vdType = ROOT::TMetaUtils::ReSubstTemplateArg(vd->getType(), fClassInfo->GetType());
579 ROOT::TMetaUtils::GetNormalizedName(buf, vdType, *fInterp, normCtxt);
584 while (buf.length() && buf[buf.length()-1] ==
']') {
585 size_t last = buf.rfind(
'[');
586 if (last != std::string::npos) {
595 const char *TClingDataMemberInfo::Name()
601 CheckForIoTypeAndName();
602 if (!fIoName.empty())
return fIoName.c_str();
604 return TClingDeclInfo::Name();
607 const char *TClingDataMemberInfo::Title()
617 bool titleFound=
false;
619 std::string attribute_s;
620 const Decl* decl = GetDecl();
621 for (Decl::attr_iterator attrIt = decl->attr_begin();
622 attrIt!=decl->attr_end() && !titleFound ;++attrIt){
623 if (0 == ROOT::TMetaUtils::extractAttrString(*attrIt, attribute_s) &&
624 attribute_s.find(ROOT::TMetaUtils::propNames::separator) == std::string::npos){
625 fTitle = attribute_s;
630 if (!titleFound && !GetDecl()->isFromASTFile()) {
634 fTitle = ROOT::TMetaUtils::GetComment(*GetDecl()).str();
637 return fTitle.c_str();
643 llvm::StringRef TClingDataMemberInfo::ValidArrayIndex()
const
646 return llvm::StringRef();
648 const clang::DeclaratorDecl *FD = llvm::dyn_cast<clang::DeclaratorDecl>(GetDecl());
649 if (FD)
return ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(*FD);
650 else return llvm::StringRef();