Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TClingUtils.cxx
Go to the documentation of this file.
1// @(#)root/metautils:$Id$
2// Author: Paul Russo, 2009-10-06
3
4/*************************************************************************
5 * Copyright (C) 1995-2011, 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//______________________________________________________________________________
13// //
14// ROOT::TMetaUtils provides utility wrappers around //
15// cling, the LLVM-based interpreter. It's an internal set of tools //
16// used by TCling and rootcling. //
17// //
18//______________________________________________________________________________
19#include <algorithm>
20#include <iostream>
21#include <sstream>
22#include <cstdlib>
23#include <cstdio>
24#include <unordered_set>
25#include <cctype>
26
27#include "RConfigure.h"
29#include <ROOT/RConfig.hxx>
31#include "Rtypes.h"
32#include "strlcpy.h"
33
34#include "RStl.h"
35
36#include "clang/AST/ASTContext.h"
37#include "clang/AST/Attr.h"
38#include "clang/AST/CXXInheritance.h"
39#include "clang/AST/Decl.h"
40#include "clang/AST/DeclTemplate.h"
41#include "clang/AST/Mangle.h"
42#include "clang/AST/Type.h"
43#include "clang/AST/TypeVisitor.h"
44#include "clang/Frontend/CompilerInstance.h"
45#include "clang/Lex/HeaderSearch.h"
46#include "clang/Lex/ModuleMap.h"
47#include "clang/Lex/Preprocessor.h"
48#include "clang/Lex/PreprocessorOptions.h"
49
50#include "clang/Sema/Lookup.h"
51#include "clang/Sema/Sema.h"
52#include "clang/Sema/SemaDiagnostic.h"
53
54#include "cling/Interpreter/LookupHelper.h"
55#include "cling/Interpreter/Transaction.h"
56#include "cling/Interpreter/Interpreter.h"
57#include "cling/Utils/AST.h"
58#include "cling/Interpreter/InterpreterAccessRAII.h"
59
60#include "llvm/Support/Path.h"
61#include "llvm/Support/FileSystem.h"
62
63#include "TClingUtils.h"
64
65#ifdef _WIN32
66#define strncasecmp _strnicmp
67#include <io.h>
68#else
69#include <unistd.h>
70#endif // _WIN32
71
72namespace ROOT {
73namespace TMetaUtils {
74
75std::string GetRealPath(const std::string &path)
76{
77 llvm::SmallString<256> result_path;
78 llvm::sys::fs::real_path(path, result_path, /*expandTilde*/true);
79 return result_path.str().str();
80}
81
82
83////////////////////////////////////////////////////////////////////////////////
84
86 using DeclsCont_t = TNormalizedCtxt::Config_t::SkipCollection;
90private:
94public:
95 TNormalizedCtxtImpl(const cling::LookupHelper &lh);
96
97 const Config_t &GetConfig() const { return fConfig; }
99 void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl* templ, unsigned int i);
100 int GetNargsToKeep(const clang::ClassTemplateDecl* templ) const;
102 void keepTypedef(const cling::LookupHelper &lh, const char* name,
103 bool replace = false);
104};
105}
106}
107
108namespace {
109
110////////////////////////////////////////////////////////////////////////////////
111/// Add default parameter to the scope if needed.
112
113static clang::NestedNameSpecifier *AddDefaultParametersNNS(const clang::ASTContext& Ctx,
114 clang::NestedNameSpecifier* scope,
115 const cling::Interpreter &interpreter,
117 if (!scope) return nullptr;
118
119 const clang::Type* scope_type = scope->getAsType();
120 if (scope_type) {
121 // this is not a namespace, so we might need to desugar
122 clang::NestedNameSpecifier* outer_scope = scope->getPrefix();
123 if (outer_scope) {
125 }
126
127 clang::QualType addDefault =
129 // NOTE: Should check whether the type has changed or not.
130 if (addDefault.getTypePtr() != scope_type)
131 return clang::NestedNameSpecifier::Create(Ctx,outer_scope,
132 false /* template keyword wanted */,
133 addDefault.getTypePtr());
134 }
135 return scope;
136}
137
138////////////////////////////////////////////////////////////////////////////////
139
140static bool CheckDefinition(const clang::CXXRecordDecl *cl, const clang::CXXRecordDecl *context)
141{
142 if (!cl->hasDefinition()) {
143 if (context) {
144 ROOT::TMetaUtils::Error("CheckDefinition",
145 "Missing definition for class %s, please #include its header in the header of %s\n",
146 cl->getName().str().c_str(), context->getName().str().c_str());
147 } else {
148 ROOT::TMetaUtils::Error("CheckDefinition",
149 "Missing definition for class %s\n",
150 cl->getName().str().c_str());
151 }
152 return false;
153 }
154 return true;
155}
156
157////////////////////////////////////////////////////////////////////////////////
158/// Check if 'scope' or any of its template parameter was substituted when
159/// instantiating the class template instance and replace it with the
160/// partially sugared types we have from 'instance'.
161
162static clang::NestedNameSpecifier *ReSubstTemplateArgNNS(const clang::ASTContext &Ctxt,
163 clang::NestedNameSpecifier *scope,
164 const clang::Type *instance)
165{
166 if (!scope) return nullptr;
167
168 const clang::Type* scope_type = scope->getAsType();
169 if (scope_type) {
170 clang::NestedNameSpecifier* outer_scope = scope->getPrefix();
171 if (outer_scope) {
173 }
174 clang::QualType substScope =
176 // NOTE: Should check whether the type has changed or not.
177 scope = clang::NestedNameSpecifier::Create(Ctxt,outer_scope,
178 false /* template keyword wanted */,
179 substScope.getTypePtr());
180 }
181 return scope;
182}
183
184////////////////////////////////////////////////////////////////////////////////
185
186static bool IsTypeInt(const clang::Type *type)
187{
188 const clang::BuiltinType * builtin = llvm::dyn_cast<clang::BuiltinType>(type->getCanonicalTypeInternal().getTypePtr());
189 if (builtin) {
190 return builtin->isInteger(); // builtin->getKind() == clang::BuiltinType::Int;
191 } else {
192 return false;
193 }
194}
195
196////////////////////////////////////////////////////////////////////////////////
197
198static bool IsFieldDeclInt(const clang::FieldDecl *field)
199{
200 return IsTypeInt(field->getType().getTypePtr());
201}
202
203////////////////////////////////////////////////////////////////////////////////
204/// Return a data member name 'what' in the class described by 'cl' if any.
205
206static const clang::FieldDecl *GetDataMemberFromAll(const clang::CXXRecordDecl &cl, llvm::StringRef what)
207{
208 clang::ASTContext &C = cl.getASTContext();
209 clang::DeclarationName DName = &C.Idents.get(what);
210 auto R = cl.lookup(DName);
211 for (const clang::NamedDecl *D : R)
213 return FD;
214 return nullptr;
215}
216
217////////////////////////////////////////////////////////////////////////////////
218/// Return a data member name 'what' in any of the base classes of the class described by 'cl' if any.
219
220static const clang::FieldDecl *GetDataMemberFromAllParents(clang::Sema &SemaR, const clang::CXXRecordDecl &cl, const char *what)
221{
222 clang::DeclarationName DName = &SemaR.Context.Idents.get(what);
223 clang::LookupResult R(SemaR, DName, clang::SourceLocation(),
224 clang::Sema::LookupOrdinaryName,
225 RedeclarationKind::ForExternalRedeclaration);
226 SemaR.LookupInSuper(R, &const_cast<clang::CXXRecordDecl&>(cl));
227 if (R.empty())
228 return nullptr;
229 return llvm::dyn_cast<const clang::FieldDecl>(R.getFoundDecl());
230}
231
232static
233cling::LookupHelper::DiagSetting ToLHDS(bool wantDiags) {
234 return wantDiags
235 ? cling::LookupHelper::WithDiagnostics
236 : cling::LookupHelper::NoDiagnostics;
237}
238
239} // end of anonymous namespace
240
241
242namespace ROOT {
243namespace TMetaUtils {
244
245////////////////////////////////////////////////////////////////////////////////
246/// Add to the internal map the pointer of a template as key and the number of
247/// template arguments to keep as value.
248
249void TNormalizedCtxtImpl::AddTemplAndNargsToKeep(const clang::ClassTemplateDecl* templ,
250 unsigned int i){
251 if (!templ){
252 Error("TNormalizedCtxt::AddTemplAndNargsToKeep",
253 "Tring to specify a number of template arguments to keep for a null pointer. Exiting without assigning any value.\n");
254 return;
255 }
256
257 const clang::ClassTemplateDecl* canTempl = templ->getCanonicalDecl();
258
259 if(fTemplatePtrArgsToKeepMap.count(canTempl)==1 &&
261 const std::string templateName (canTempl->getNameAsString());
262 const std::string i_str (std::to_string(i));
263 const std::string previousArgsToKeep(std::to_string(fTemplatePtrArgsToKeepMap[canTempl]));
264 Error("TNormalizedCtxt::AddTemplAndNargsToKeep",
265 "Tring to specify for template %s %s arguments to keep, while before this number was %s\n",
266 canTempl->getNameAsString().c_str(),
267 i_str.c_str(),
268 previousArgsToKeep.c_str());
269 }
270
272}
273////////////////////////////////////////////////////////////////////////////////
274/// Get from the map the number of arguments to keep.
275/// It uses the canonical decl of the template as key.
276/// If not present, returns -1.
277
278int TNormalizedCtxtImpl::GetNargsToKeep(const clang::ClassTemplateDecl* templ) const{
279 const clang::ClassTemplateDecl* constTempl = templ->getCanonicalDecl();
281 int nArgsToKeep = (thePairPtr != fTemplatePtrArgsToKeepMap.end() ) ? thePairPtr->second : -1;
282 return nArgsToKeep;
283}
284
285
286////////////////////////////////////////////////////////////////////////////////
287
288TNormalizedCtxt::TNormalizedCtxt(const cling::LookupHelper &lh):
290{}
291
295
305void TNormalizedCtxt::AddTemplAndNargsToKeep(const clang::ClassTemplateDecl* templ, unsigned int i)
306{
308}
309int TNormalizedCtxt::GetNargsToKeep(const clang::ClassTemplateDecl* templ) const
310{
311 return fImpl->GetNargsToKeep(templ);
312}
316void TNormalizedCtxt::keepTypedef(const cling::LookupHelper &lh, const char* name,
317 bool replace /*= false*/)
318{
319 return fImpl->keepTypedef(lh, name, replace);
320}
321
322std::string AnnotatedRecordDecl::BuildDemangledTypeInfo(const clang::RecordDecl *rDecl,
323 const std::string &normalizedName)
324{
325 // Types with strong typedefs must not be findable through demangled type names, or else
326 // the demangled name will resolve to both sinblings double / Double32_t.
327 if (normalizedName.find("Double32_t") != std::string::npos
328 || normalizedName.find("Float16_t") != std::string::npos)
329 return {};
330 std::unique_ptr<clang::MangleContext> mangleCtx(rDecl->getASTContext().createMangleContext());
331 std::string mangledName;
332 {
333 llvm::raw_string_ostream sstr(mangledName);
334 if (const clang::TypeDecl* TD = llvm::dyn_cast<clang::TypeDecl>(rDecl)) {
335 mangleCtx->mangleCXXRTTI(clang::QualType(TD->getTypeForDecl(), 0), sstr);
336 }
337 }
338 if (!mangledName.empty()) {
339 int errDemangle = 0;
340#ifdef WIN32
341 if (mangledName[0] == '\01')
342 mangledName.erase(0, 1);
345 static const char typeinfoNameFor[] = " `RTTI Type Descriptor'";
347 std::string demangledName = demangledTIName;
349#else
352 static const char typeinfoNameFor[] = "typeinfo for ";
355#endif
357 return demangledName;
358 } else {
359#ifdef WIN32
360 ROOT::TMetaUtils::Error("AnnotatedRecordDecl::BuildDemangledTypeInfo",
361 "Demangled typeinfo name '%s' does not contain `RTTI Type Descriptor'\n",
363#else
364 ROOT::TMetaUtils::Error("AnnotatedRecordDecl::BuildDemangledTypeInfo",
365 "Demangled typeinfo name '%s' does not start with 'typeinfo for'\n",
367#endif
368 } // if demangled type_info starts with "typeinfo for "
369 } // if demangling worked
371 } // if mangling worked
372 return {};
373}
374
375
376////////////////////////////////////////////////////////////////////////////////
377/// There is no requested type name.
378/// Still let's normalized the actual name.
379
380// clang-format off
406
407////////////////////////////////////////////////////////////////////////////////
408/// Normalize the requested type name.
409
410// clang-format off
412 const clang::Type *requestedType,
413 const clang::RecordDecl *decl,
414 const char *requestName,
415 unsigned int nTemplateArgsToSkip,
416 bool rStreamerInfo,
417 bool rNoStreamer,
422 const std::string &rRequestedRNTupleSoARecord,
423 const cling::Interpreter &interpreter,
425 : fRuleIndex(index),
426 fDecl(decl),
427 fRequestedName(""),
428 fRequestStreamerInfo(rStreamerInfo),
429 fRequestNoStreamer(rNoStreamer),
430 fRequestNoInputOperator(rRequestNoInputOperator),
431 fRequestOnlyTClass(rRequestOnlyTClass),
432 fRequestedVersionNumber(rRequestVersionNumber),
433 fRequestedRNTupleSerializationMode(rRequestedRNTupleSerializationMode),
434 fRequestedRNTupleSoARecord(rRequestedRNTupleSoARecord)
435// clang-format on
436{
437 // For comparison purposes.
439 splitname1.ShortType(fRequestedName, 0);
440
443 ROOT::TMetaUtils::Warning("AnnotatedRecordDecl",
444 "Could not remove the requested template arguments.\n");
445 }
447}
448
449////////////////////////////////////////////////////////////////////////////////
450/// Normalize the requested type name.
451
452// clang-format off
454 const clang::Type *requestedType,
455 const clang::RecordDecl *decl,
456 const char *requestName,
457 bool rStreamerInfo,
458 bool rNoStreamer,
463 const std::string &rRequestedRNTupleSoARecord,
464 const cling::Interpreter &interpreter,
466 : fRuleIndex(index),
467 fDecl(decl),
468 fRequestedName(""),
469 fRequestStreamerInfo(rStreamerInfo),
470 fRequestNoStreamer(rNoStreamer),
471 fRequestNoInputOperator(rRequestNoInputOperator),
472 fRequestOnlyTClass(rRequestOnlyTClass),
473 fRequestedVersionNumber(rRequestVersionNumber),
474 fRequestedRNTupleSerializationMode(rRequestedRNTupleSerializationMode),
475 fRequestedRNTupleSoARecord(rRequestedRNTupleSoARecord)
476// clang-format on
477{
478 // For comparison purposes.
480 splitname1.ShortType(fRequestedName, 0);
481
484}
485
486////////////////////////////////////////////////////////////////////////////////
487/// Normalize the requested name.
488
489// clang-format off
491 const clang::RecordDecl *decl,
492 const char *requestName,
493 bool rStreamerInfo,
494 bool rNoStreamer,
499 const std::string &rRequestedRNTupleSoARecord,
500 const cling::Interpreter &interpreter,
502 : fRuleIndex(index),
503 fDecl(decl),
504 fRequestedName(""),
505 fRequestStreamerInfo(rStreamerInfo),
506 fRequestNoStreamer(rNoStreamer),
507 fRequestNoInputOperator(rRequestNoInputOperator),
508 fRequestOnlyTClass(rRequestOnlyTClass),
509 fRequestedVersionNumber(rRequestVersionNumber),
510 fRequestedRNTupleSerializationMode(rRequestedRNTupleSerializationMode),
511 fRequestedRNTupleSoARecord(rRequestedRNTupleSoARecord)
512// clang-format on
513{
514 // const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (decl);
515 // if (tmplt_specialization) {
516 // tmplt_specialization->getTemplateArgs ().data()->print(decl->getASTContext().getPrintingPolicy(),llvm::outs());
517 // llvm::outs() << "\n";
518 // }
519 // const char *current = requestName;
520 // Strips spaces and std::
521 if (requestName && requestName[0]) {
524
526 } else {
527 TMetaUtils::GetNormalizedName( fNormalizedName, decl->getASTContext().getTypeDeclType(decl),interpreter,normCtxt);
528 }
530}
531
532////////////////////////////////////////////////////////////////////////////////
533
535 ExistingTypeCheck_t existingTypeCheck, CheckInClassTable_t CheckInClassTable,
536 AutoParse_t autoParse, bool *shuttingDownPtr, const int *pgDebug /*= 0*/)
537 : fInterpreter(&interpreter),
538 fNormalizedCtxt(&normCtxt),
539 fExistingTypeCheck(existingTypeCheck),
540 fCheckInClassTable(CheckInClassTable),
541 fAutoParse(autoParse),
542 fInterpreterIsShuttingDownPtr(shuttingDownPtr),
543 fPDebug(pgDebug)
544{
545}
546
547////////////////////////////////////////////////////////////////////////////////
548/// Helper routine to ry hard to avoid looking up in the Cling database as
549/// this could enduce an unwanted autoparsing.
550
552 std::string &result)
553{
554 if (tname.empty()) return false;
555
557 else return false;
558}
559
560bool TClingLookupHelper::CheckInClassTable(const std::string &tname, std::string &result)
561{
562 if (tname.empty())
563 return false;
564
567 else
568 return false;
569}
570
571////////////////////////////////////////////////////////////////////////////////
572
574{
575 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
576 clang::QualType t = lh.findType(nameLong, ToLHDS(WantDiags()));
577 if (!t.isNull()) {
578 clang::QualType dest = cling::utils::Transform::GetPartiallyDesugaredType(fInterpreter->getCI()->getASTContext(), t, fNormalizedCtxt->GetConfig(), true /* fully qualify */);
579 if (!dest.isNull() && (dest != t)) {
580 // getAsStringInternal() appends.
581 nameLong.clear();
582 dest.getAsStringInternal(nameLong, fInterpreter->getCI()->getASTContext().getPrintingPolicy());
583 }
584 }
585}
586
587////////////////////////////////////////////////////////////////////////////////
588
590 const std::string &nameLong)
591{
592 // We are going to use and possibly update the interpreter information.
593 cling::InterpreterAccessRAII LockAccess(*fInterpreter);
594
595 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
596 clang::QualType t = lh.findType(nondef.c_str(), ToLHDS(WantDiags()));
597 if (!t.isNull()) {
598 clang::QualType dest = cling::utils::Transform::GetPartiallyDesugaredType(fInterpreter->getCI()->getASTContext(), t, fNormalizedCtxt->GetConfig(), true /* fully qualify */);
599 if (!dest.isNull() && (dest != t) &&
600 nameLong == t.getAsString(fInterpreter->getCI()->getASTContext().getPrintingPolicy()))
601 return true;
602 }
603 return false;
604}
605
606////////////////////////////////////////////////////////////////////////////////
607
608bool TClingLookupHelper::IsDeclaredScope(const std::string &base, bool &isInlined)
609{
610 // We are going to use and possibly update the interpreter information.
611 cling::InterpreterAccessRAII LockAccess(*fInterpreter);
612
613 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
614 const clang::Decl *scope = lh.findScope(base.c_str(), ToLHDS(WantDiags()), nullptr);
615
616 if (!scope) {
617 // the nesting namespace is not declared
618 isInlined = false;
619 return false;
620 }
621 const clang::NamespaceDecl *nsdecl = llvm::dyn_cast<clang::NamespaceDecl>(scope);
622 isInlined = nsdecl && nsdecl->isInline();
623 return true;
624}
625
626////////////////////////////////////////////////////////////////////////////////
627/// We assume that we have a simple type:
628/// [const] typename[*&][const]
629
631 std::string &result,
632 bool dropstd /* = true */)
633{
634 if (tname.empty()) return false;
635
636 // Try hard to avoid looking up in the Cling database as this could enduce
637 // an unwanted autoparsing.
638 // Note: this is always done by the callers and thus is redundant.
639 // Maybe replace with
642 return ! result.empty();
643 }
644
645 if (fAutoParse) fAutoParse(tname.c_str());
646
647 // We are going to use and possibly update the interpreter information.
648 cling::InterpreterAccessRAII LockAccess(*fInterpreter);
649
650 // Since we already check via other means (TClassTable which is populated by
651 // the dictonary loading, and the gROOT list of classes and enums, which are
652 // populated via TProtoClass/Enum), we should be able to disable the autoloading
653 // ... which requires access to libCore or libCling ...
654 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
655 clang::QualType t = lh.findType(tname.c_str(), ToLHDS(WantDiags()));
656 // Technically we ought to try:
657 // if (t.isNull()) t = lh.findType(TClassEdit::InsertStd(tname), ToLHDS(WantDiags()));
658 // at least until the 'normalized name' contains the std:: prefix.
659
660 if (!t.isNull()) {
662 if (!dest.isNull() && dest != t) {
663 // Since our input is not a template instance name, rather than going through the full
664 // TMetaUtils::GetNormalizedName, we just do the 'strip leading std' and fix
665 // white space.
666 clang::PrintingPolicy policy(fInterpreter->getCI()->getASTContext().getPrintingPolicy());
667 policy.SuppressTagKeyword = true; // Never get the class or struct keyword
668 // The scope suppression is required for getting rid of the anonymous part of the name of a class defined in an
669 // anonymous namespace. In LLVM22 (and before), SuppressUnwrittenScope suppresses anonymous namespaces. Inline
670 // namespace suppression is separately controlled by SuppressInlineNamespace, which we probably don't want to
671 // be suppressed.
672 policy.SuppressUnwrittenScope = true; // Strip anonymous namespace names
673
674 // getAsStringInternal() appends.
675 result.clear();
676 dest.getAsStringInternal(result, policy);
677 // Strip the std::
678 unsigned long offset = 0;
679 if (strncmp(result.c_str(), "const ", 6) == 0) {
680 offset = 6;
681 }
682 if (dropstd && strncmp(result.c_str()+offset, "std::", 5) == 0) {
683 result.erase(offset,5);
684 }
685 for(unsigned int i = 1; i<result.length(); ++i) {
686 if (result[i]=='s') {
687 if (result[i-1]=='<' || result[i-1]==',' || result[i-1]==' ') {
688 if (dropstd && result.compare(i,5,"std::",5) == 0) {
689 result.erase(i,5);
690 }
691 }
692 }
693 if (result[i]==' ') {
694 if (result[i-1] == ',') {
695 result.erase(i,1);
696 --i;
697 } else if ( (i+1) < result.length() &&
698 (result[i+1]=='*' || result[i+1]=='&' || result[i+1]=='[') ) {
699 result.erase(i,1);
700 --i;
701 }
702 }
703 }
704
705// std::string alt;
706// TMetaUtils::GetNormalizedName(alt, dest, *fInterpreter, *fNormalizedCtxt);
707// if (alt != result) fprintf(stderr,"norm: %s vs result=%s\n",alt.c_str(),result.c_str());
708
709 return true;
710 }
711 }
712 return false;
713}
714
715////////////////////////////////////////////////////////////////////////////////
716// TClassEdit will call this routine as soon as any of its static variable (used
717// for caching) is destroyed.
723
724 } // end namespace ROOT
725} // end namespace TMetaUtils
726
727
728////////////////////////////////////////////////////////////////////////////////
729/// Insert the type with name into the collection of typedefs to keep.
730/// if replace, replace occurrences of the canonical type by name.
731
733 const char* name,
734 bool replace /*=false*/) {
735 clang::QualType toSkip = lh.findType(name, cling::LookupHelper::WithDiagnostics);
736 if (const clang::Type* T = toSkip.getTypePtr()) {
737 const clang::TypedefType *tt = llvm::dyn_cast<clang::TypedefType>(T);
738 if (!tt) return;
739 clang::Decl* D = tt->getDecl();
740 fConfig.m_toSkip.insert(D);
741 if (replace) {
742 clang::QualType canon = toSkip->getCanonicalTypeInternal();
743 fConfig.m_toReplace.insert(std::make_pair(canon.getTypePtr(),T));
744 } else {
745 fTypeWithAlternative.insert(T);
746 }
747 }
748}
749
750////////////////////////////////////////////////////////////////////////////////
751/// Initialize the list of typedef to keep (i.e. make them opaque for normalization)
752/// and the list of typedef whose semantic is different from their underlying type
753/// (Double32_t and Float16_t).
754/// This might be specific to an interpreter.
755
757{
758 keepTypedef(lh, "Double32_t");
759 keepTypedef(lh, "Float16_t");
760 keepTypedef(lh, "Long64_t", true);
761 keepTypedef(lh, "ULong64_t", true);
762
763 clang::QualType toSkip = lh.findType("string", cling::LookupHelper::WithDiagnostics);
764 if (!toSkip.isNull()) {
765 if (const clang::TypedefType* TT
766 = llvm::dyn_cast_or_null<clang::TypedefType>(toSkip.getTypePtr()))
767 fConfig.m_toSkip.insert(TT->getDecl());
768 }
769 toSkip = lh.findType("std::string", cling::LookupHelper::WithDiagnostics);
770 if (!toSkip.isNull()) {
771 if (const clang::TypedefType* TT
772 = llvm::dyn_cast_or_null<clang::TypedefType>(toSkip.getTypePtr()))
773 fConfig.m_toSkip.insert(TT->getDecl());
774
775 clang::QualType canon = toSkip->getCanonicalTypeInternal();
776 fConfig.m_toReplace.insert(std::make_pair(canon.getTypePtr(),toSkip.getTypePtr()));
777 }
778}
779
782
783////////////////////////////////////////////////////////////////////////////////
784
785inline bool IsTemplate(const clang::Decl &cl)
786{
787 return (cl.getKind() == clang::Decl::ClassTemplatePartialSpecialization
788 || cl.getKind() == clang::Decl::ClassTemplateSpecialization);
789}
790
791
792////////////////////////////////////////////////////////////////////////////////
793
794const clang::FunctionDecl* ROOT::TMetaUtils::ClassInfo__HasMethod(const clang::DeclContext *cl, const char* name,
795 const cling::Interpreter& interp)
796{
797 clang::Sema* S = &interp.getSema();
798 const clang::NamedDecl* ND = cling::utils::Lookup::Named(S, name, cl);
799 if (ND == (clang::NamedDecl*)-1)
800 return (clang::FunctionDecl*)-1;
801 return llvm::dyn_cast_or_null<clang::FunctionDecl>(ND);
802}
803
804////////////////////////////////////////////////////////////////////////////////
805/// Return the scope corresponding to 'name' or std::'name'
806
807const clang::CXXRecordDecl *
808ROOT::TMetaUtils::ScopeSearch(const char *name, const cling::Interpreter &interp,
809 bool /*diagnose*/, const clang::Type** resultType)
810{
811 const cling::LookupHelper& lh = interp.getLookupHelper();
812 // We have many bogus diagnostics if we allow diagnostics here. Suppress.
813 // FIXME: silence them in the callers.
814 const clang::CXXRecordDecl *result
815 = llvm::dyn_cast_or_null<clang::CXXRecordDecl>
816 (lh.findScope(name, cling::LookupHelper::NoDiagnostics, resultType));
817 if (!result) {
818 std::string std_name("std::");
819 std_name += name;
820 // We have many bogus diagnostics if we allow diagnostics here. Suppress.
821 // FIXME: silence them in the callers.
822 result = llvm::dyn_cast_or_null<clang::CXXRecordDecl>
823 (lh.findScope(std_name, cling::LookupHelper::NoDiagnostics, resultType));
824 }
825 return result;
826}
827
828
829////////////////////////////////////////////////////////////////////////////////
830
831bool ROOT::TMetaUtils::RequireCompleteType(const cling::Interpreter &interp, const clang::CXXRecordDecl *cl)
832{
833 clang::QualType qType(cl->getTypeForDecl(),0);
834 return RequireCompleteType(interp,cl->getLocation(),qType);
835}
836
837////////////////////////////////////////////////////////////////////////////////
838
839bool ROOT::TMetaUtils::RequireCompleteType(const cling::Interpreter &interp, clang::SourceLocation Loc, clang::QualType Type)
840{
841 clang::Sema& S = interp.getCI()->getSema();
842 // Here we might not have an active transaction to handle
843 // the caused instantiation decl.
844 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interp));
845 return S.RequireCompleteType(Loc, Type, clang::diag::err_incomplete_type);
846}
847
848////////////////////////////////////////////////////////////////////////////////
849
850bool ROOT::TMetaUtils::IsBase(const clang::CXXRecordDecl *cl, const clang::CXXRecordDecl *base,
851 const clang::CXXRecordDecl *context, const cling::Interpreter &interp)
852{
853 if (!cl || !base) {
854 return false;
855 }
856
857 if (!cl->getDefinition() || !cl->isCompleteDefinition()) {
859 }
860
861 if (!CheckDefinition(cl, context) || !CheckDefinition(base, context)) {
862 return false;
863 }
864
865 if (!base->hasDefinition()) {
866 ROOT::TMetaUtils::Error("IsBase", "Missing definition for class %s\n", base->getName().str().c_str());
867 return false;
868 }
869 return cl->isDerivedFrom(base);
870}
871
872////////////////////////////////////////////////////////////////////////////////
873
874bool ROOT::TMetaUtils::IsBase(const clang::FieldDecl &m, const char* basename, const cling::Interpreter &interp)
875{
876 const clang::CXXRecordDecl* CRD = llvm::dyn_cast<clang::CXXRecordDecl>(ROOT::TMetaUtils::GetUnderlyingRecordDecl(m.getType()));
877 if (!CRD) {
878 return false;
879 }
880
881 const clang::NamedDecl *base
882 = ScopeSearch(basename, interp, true /*diagnose*/, nullptr);
883
884 if (base) {
885 return IsBase(CRD, llvm::dyn_cast<clang::CXXRecordDecl>( base ),
886 llvm::dyn_cast<clang::CXXRecordDecl>(m.getDeclContext()),interp);
887 }
888 return false;
889}
890
891////////////////////////////////////////////////////////////////////////////////
892
894 const clang::NamedDecl &forcontext,
895 const clang::QualType &qti,
896 const char *R__t,int rwmode,
897 const cling::Interpreter &interp,
898 const char *tcl)
899{
900 static const clang::CXXRecordDecl *TObject_decl
901 = ROOT::TMetaUtils::ScopeSearch("TObject", interp, true /*diag*/, nullptr);
902 enum {
903 kBIT_ISTOBJECT = 0x10000000,
904 kBIT_HASSTREAMER = 0x20000000,
905 kBIT_ISSTRING = 0x40000000,
906
907 kBIT_ISPOINTER = 0x00001000,
908 kBIT_ISFUNDAMENTAL = 0x00000020,
909 kBIT_ISENUM = 0x00000008
910 };
911
912 const clang::Type &ti( * qti.getTypePtr() );
913 std::string tiName;
915
916 std::string objType(ROOT::TMetaUtils::ShortTypeName(tiName.c_str()));
917
918 const clang::Type *rawtype = ROOT::TMetaUtils::GetUnderlyingType(clang::QualType(&ti,0));
919 std::string rawname;
921
922 clang::CXXRecordDecl *cxxtype = rawtype->getAsCXXRecordDecl() ;
924 int isTObj = cxxtype && (IsBase(cxxtype,TObject_decl,nullptr,interp) || rawname == "TObject");
925
926 long kase = 0;
927
928 if (ti.isPointerType()) kase |= kBIT_ISPOINTER;
929 if (rawtype->isFundamentalType()) kase |= kBIT_ISFUNDAMENTAL;
930 if (rawtype->isEnumeralType()) kase |= kBIT_ISENUM;
931
932
933 if (isTObj) kase |= kBIT_ISTOBJECT;
935 if (tiName == "string") kase |= kBIT_ISSTRING;
936 if (tiName == "string*") kase |= kBIT_ISSTRING;
937
938
939 if (!tcl)
940 tcl = " internal error in rootcling ";
941 // if (strcmp(objType,"string")==0) RStl::Instance().GenerateTClassFor( "string", interp, normCtxt );
942
943 if (rwmode == 0) { //Read mode
944
945 if (R__t) finalString << " " << tiName << " " << R__t << ";" << std::endl;
946 switch (kase) {
947
949 if (!R__t) return 0;
950 finalString << " R__b >> " << R__t << ";" << std::endl;
951 break;
952
954 if (!R__t) return 1;
955 finalString << " " << R__t << " = (" << tiName << ")R__b.ReadObjectAny(" << tcl << ");" << std::endl;
956 break;
957
958 case kBIT_ISENUM:
959 if (!R__t) return 0;
960 // fprintf(fp, " R__b >> (Int_t&)%s;\n",R__t);
961 // On some platforms enums and not 'Int_t' and casting to a reference to Int_t
962 // induces the silent creation of a temporary which is 'filled' __instead of__
963 // the desired enum. So we need to take it one step at a time.
964 finalString << " Int_t readtemp;" << std::endl
965 << " R__b >> readtemp;" << std::endl
966 << " " << R__t << " = static_cast<" << tiName << ">(readtemp);" << std::endl;
967 break;
968
969 case kBIT_HASSTREAMER:
971 if (!R__t) return 0;
972 finalString << " " << R__t << ".Streamer(R__b);" << std::endl;
973 break;
974
976 if (!R__t) return 1;
977 //fprintf(fp, " fprintf(stderr,\"info is %%p %%d\\n\",R__b.GetInfo(),R__b.GetInfo()?R__b.GetInfo()->GetOldVersion():-1);\n");
978 finalString << " if (R__b.GetInfo() && R__b.GetInfo()->GetOldVersion()<=3) {" << std::endl;
979 if (cxxtype && cxxtype->isAbstract()) {
980 finalString << " R__ASSERT(0);// " << objType << " is abstract. We assume that older file could not be produced using this streaming method." << std::endl;
981 } else {
982 finalString << " " << R__t << " = new " << objType << ";" << std::endl
983 << " " << R__t << "->Streamer(R__b);" << std::endl;
984 }
985 finalString << " } else {" << std::endl
986 << " " << R__t << " = (" << tiName << ")R__b.ReadObjectAny(" << tcl << ");" << std::endl
987 << " }" << std::endl;
988 break;
989
990 case kBIT_ISSTRING:
991 if (!R__t) return 0;
992 finalString << " {TString R__str;" << std::endl
993 << " R__str.Streamer(R__b);" << std::endl
994 << " " << R__t << " = R__str.Data();}" << std::endl;
995 break;
996
997 case kBIT_ISSTRING|kBIT_ISPOINTER:
998 if (!R__t) return 0;
999 finalString << " {TString R__str;" << std::endl
1000 << " R__str.Streamer(R__b);" << std::endl
1001 << " " << R__t << " = new string(R__str.Data());}" << std::endl;
1002 break;
1003
1004 case kBIT_ISPOINTER:
1005 if (!R__t) return 1;
1006 finalString << " " << R__t << " = (" << tiName << ")R__b.ReadObjectAny(" << tcl << ");" << std::endl;
1007 break;
1008
1009 default:
1010 if (!R__t) return 1;
1011 finalString << " R__b.StreamObject(&" << R__t << "," << tcl << ");" << std::endl;
1012 break;
1013 }
1014
1015 } else { //Write case
1016
1017 switch (kase) {
1018
1019 case kBIT_ISFUNDAMENTAL:
1021 if (!R__t) return 0;
1022 finalString << " R__b << " << R__t << ";" << std::endl;
1023 break;
1024
1025 case kBIT_ISENUM:
1026 if (!R__t) return 0;
1027 finalString << " { void *ptr_enum = (void*)&" << R__t << ";\n";
1028 finalString << " R__b >> *reinterpret_cast<Int_t*>(ptr_enum); }" << std::endl;
1029 break;
1030
1031 case kBIT_HASSTREAMER:
1033 if (!R__t) return 0;
1034 finalString << " ((" << objType << "&)" << R__t << ").Streamer(R__b);" << std::endl;
1035 break;
1036
1038 if (!R__t) return 1;
1039 finalString << " R__b.WriteObjectAny(" << R__t << "," << tcl << ");" << std::endl;
1040 break;
1041
1042 case kBIT_ISSTRING:
1043 if (!R__t) return 0;
1044 finalString << " {TString R__str(" << R__t << ".c_str());" << std::endl
1045 << " R__str.Streamer(R__b);};" << std::endl;
1046 break;
1047
1048 case kBIT_ISSTRING|kBIT_ISPOINTER:
1049 if (!R__t) return 0;
1050 finalString << " {TString R__str(" << R__t << "->c_str());" << std::endl
1051 << " R__str.Streamer(R__b);}" << std::endl;
1052 break;
1053
1054 case kBIT_ISPOINTER:
1055 if (!R__t) return 1;
1056 finalString << " R__b.WriteObjectAny(" << R__t << "," << tcl <<");" << std::endl;
1057 break;
1058
1059 default:
1060 if (!R__t) return 1;
1061 finalString << " R__b.StreamObject((" << objType << "*)&" << R__t << "," << tcl << ");" << std::endl;
1062 break;
1063 }
1064 }
1065 return 0;
1066}
1067
1068////////////////////////////////////////////////////////////////////////////////
1069/// Checks if default constructor exists and accessible
1070
1071bool ROOT::TMetaUtils::CheckDefaultConstructor(const clang::CXXRecordDecl* cl, const cling::Interpreter& interpreter)
1072{
1073 clang::CXXRecordDecl* ncCl = const_cast<clang::CXXRecordDecl*>(cl);
1074
1075 // We may induce template instantiation
1076 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
1077
1078 if (auto* Ctor = interpreter.getCI()->getSema().LookupDefaultConstructor(ncCl)) {
1079 if (Ctor->getAccess() == clang::AS_public && !Ctor->isDeleted()) {
1080 return true;
1081 }
1082 }
1083
1084 return false;
1085}
1086
1087
1088////////////////////////////////////////////////////////////////////////////////
1089/// Checks IO constructor - must be public and with specified argument
1090
1092 const char *typeOfArg,
1093 const clang::CXXRecordDecl *expectedArgType,
1094 const cling::Interpreter& interpreter)
1095{
1096 if (typeOfArg && !expectedArgType) {
1097 const cling::LookupHelper& lh = interpreter.getLookupHelper();
1098 // We can not use findScope since the type we are given are usually,
1099 // only forward declared (and findScope explicitly reject them).
1100 clang::QualType instanceType = lh.findType(typeOfArg, cling::LookupHelper::WithDiagnostics);
1101 if (!instanceType.isNull())
1102 expectedArgType = instanceType->getAsCXXRecordDecl();
1103 }
1104
1105 if (!expectedArgType)
1106 return EIOCtorCategory::kAbsent;
1107
1108 // FIXME: We should not iterate here. That costs memory!
1109 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
1110 for (auto iter = cl->ctor_begin(), end = cl->ctor_end(); iter != end; ++iter)
1111 {
1112 if ((iter->getAccess() != clang::AS_public) || (iter->getNumParams() != 1))
1113 continue;
1114
1115 // We can reach this constructor.
1116 clang::QualType argType((*iter->param_begin())->getType());
1117 argType = argType.getDesugaredType(cl->getASTContext());
1118 // Deal with pointers and references: ROOT-7723
1119 auto ioCtorCategory = EIOCtorCategory::kAbsent;
1120 if (argType->isPointerType()) {
1121 ioCtorCategory = EIOCtorCategory::kIOPtrType;
1122 argType = argType->getPointeeType();
1123 } else if (argType->isReferenceType()) {
1124 ioCtorCategory = EIOCtorCategory::kIORefType;
1125 argType = argType.getNonReferenceType();
1126 } else
1127 continue;
1128
1129 argType = argType.getDesugaredType(cl->getASTContext());
1130 const clang::CXXRecordDecl *argDecl = argType->getAsCXXRecordDecl();
1131 if (argDecl) {
1132 if (argDecl->getCanonicalDecl() == expectedArgType->getCanonicalDecl()) {
1133 return ioCtorCategory;
1134 }
1135 } else {
1136 std::string realArg = argType.getAsString();
1137 std::string clarg("class ");
1138 clarg += typeOfArg;
1139 if (realArg == clarg)
1140 return ioCtorCategory;
1141 }
1142 } // for each constructor
1143
1144 return EIOCtorCategory::kAbsent;
1145}
1146
1147
1148////////////////////////////////////////////////////////////////////////////////
1149/// Check if class has constructor of provided type - either default or with single argument
1150
1153 const cling::Interpreter& interpreter)
1154{
1155 const char *arg = ioctortype.GetName();
1156
1157 if (!ioctortype.GetType() && (!arg || !arg[0])) {
1158 // We are looking for a constructor with zero non-default arguments.
1159
1160 return CheckDefaultConstructor(cl, interpreter) ? EIOCtorCategory::kDefault : EIOCtorCategory::kAbsent;
1161 }
1162
1163 return CheckIOConstructor(cl, arg, ioctortype.GetType(), interpreter);
1164}
1165
1166
1167////////////////////////////////////////////////////////////////////////////////
1168
1169const clang::CXXMethodDecl *GetMethodWithProto(const clang::Decl* cinfo,
1170 const char *method, const char *proto,
1171 const cling::Interpreter &interp,
1172 bool diagnose)
1173{
1174 const clang::FunctionDecl* funcD
1175 = interp.getLookupHelper().findFunctionProto(cinfo, method, proto,
1176 diagnose ? cling::LookupHelper::WithDiagnostics
1177 : cling::LookupHelper::NoDiagnostics);
1178 if (funcD)
1179 return llvm::dyn_cast<const clang::CXXMethodDecl>(funcD);
1180
1181 return nullptr;
1182}
1183
1184
1185////////////////////////////////////////////////////////////////////////////////
1186
1187namespace ROOT {
1188 namespace TMetaUtils {
1189 RConstructorType::RConstructorType(const char *type_of_arg, const cling::Interpreter &interp) : fArgTypeName(type_of_arg),fArgType(nullptr)
1190 {
1191 const cling::LookupHelper& lh = interp.getLookupHelper();
1192 // We can not use findScope since the type we are given are usually,
1193 // only forward declared (and findScope explicitly reject them).
1194 clang::QualType instanceType = lh.findType(type_of_arg, cling::LookupHelper::WithDiagnostics);
1195 if (!instanceType.isNull())
1196 fArgType = instanceType->getAsCXXRecordDecl();
1197 }
1198 const char *RConstructorType::GetName() const { return fArgTypeName.c_str(); }
1199 const clang::CXXRecordDecl *RConstructorType::GetType() const { return fArgType; }
1200 }
1201}
1202
1203////////////////////////////////////////////////////////////////////////////////
1204/// return true if we can find an constructor calleable without any arguments
1205/// or with one the IOCtor special types.
1206
1207bool ROOT::TMetaUtils::HasIOConstructor(const clang::CXXRecordDecl *cl,
1208 std::string& arg,
1210 const cling::Interpreter &interp)
1211{
1212 if (cl->isAbstract()) return false;
1213
1214 for (auto & ctorType : ctorTypes) {
1215
1217
1218 if (EIOCtorCategory::kAbsent == ioCtorCat)
1219 continue;
1220
1221 std::string proto( ctorType.GetName() );
1222 bool defaultCtor = proto.empty();
1223 if (defaultCtor) {
1224 arg.clear();
1225 } else {
1226 // I/O constructors can take pointers or references to ctorTypes
1227 proto += " *";
1228 if (EIOCtorCategory::kIOPtrType == ioCtorCat) {
1229 arg = "( ("; //(MyType*)nullptr
1230 } else if (EIOCtorCategory::kIORefType == ioCtorCat) {
1231 arg = "( *("; //*(MyType*)nullptr
1232 }
1233 arg += proto;
1234 arg += ")nullptr )";
1235 }
1236 // Check for private operator new
1237 const clang::CXXMethodDecl *method
1238 = GetMethodWithProto(cl, "operator new", "size_t", interp,
1239 cling::LookupHelper::NoDiagnostics);
1240 if (method && method->getAccess() != clang::AS_public) {
1241 // The non-public op new is not going to improve for other c'tors.
1242 return false;
1243 }
1244
1245 // This one looks good!
1246 return true;
1247 }
1248 return false;
1249}
1250
1251////////////////////////////////////////////////////////////////////////////////
1252
1253bool ROOT::TMetaUtils::NeedDestructor(const clang::CXXRecordDecl *cl,
1254 const cling::Interpreter& interp)
1255{
1256 if (!cl) return false;
1257
1258 if (cl->hasUserDeclaredDestructor()) {
1259
1260 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interp));
1261 clang::CXXDestructorDecl *dest = cl->getDestructor();
1262 if (dest) {
1263 return (dest->getAccess() == clang::AS_public);
1264 } else {
1265 return true; // no destructor, so let's assume it means default?
1266 }
1267 }
1268 return true;
1269}
1270
1271////////////////////////////////////////////////////////////////////////////////
1272/// Return true, if the function (defined by the name and prototype) exists and is public
1273
1274bool ROOT::TMetaUtils::CheckPublicFuncWithProto(const clang::CXXRecordDecl *cl,
1275 const char *methodname,
1276 const char *proto,
1277 const cling::Interpreter &interp,
1278 bool diagnose)
1279{
1280 const clang::CXXMethodDecl *method
1282 diagnose ? cling::LookupHelper::WithDiagnostics
1283 : cling::LookupHelper::NoDiagnostics);
1284 return (method && method->getAccess() == clang::AS_public);
1285}
1286
1287////////////////////////////////////////////////////////////////////////////////
1288/// Return true if the class has a method DirectoryAutoAdd(TDirectory *)
1289
1290bool ROOT::TMetaUtils::HasDirectoryAutoAdd(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1291{
1292 // Detect if the class has a DirectoryAutoAdd
1293
1294 // Detect if the class or one of its parent has a DirectoryAutoAdd
1295 const char *proto = "TDirectory*";
1296 const char *name = "DirectoryAutoAdd";
1297
1298 return CheckPublicFuncWithProto(cl,name,proto,interp, false /*diags*/);
1299}
1300
1301
1302////////////////////////////////////////////////////////////////////////////////
1303/// Return true if the class has a method Merge(TCollection*,TFileMergeInfo*)
1304
1305bool ROOT::TMetaUtils::HasNewMerge(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1306{
1307 // Detect if the class has a 'new' Merge function.
1308
1309 // Detect if the class or one of its parent has a DirectoryAutoAdd
1310 const char *proto = "TCollection*,TFileMergeInfo*";
1311 const char *name = "Merge";
1312
1313 return CheckPublicFuncWithProto(cl,name,proto,interp, false /*diags*/);
1314}
1315
1316////////////////////////////////////////////////////////////////////////////////
1317/// Return true if the class has a method Merge(TCollection*)
1318
1319bool ROOT::TMetaUtils::HasOldMerge(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1320{
1321 // Detect if the class has an old fashion Merge function.
1322
1323 // Detect if the class or one of its parent has a DirectoryAutoAdd
1324 const char *proto = "TCollection*";
1325 const char *name = "Merge";
1326
1327 return CheckPublicFuncWithProto(cl,name,proto, interp, false /*diags*/);
1328}
1329
1330
1331////////////////////////////////////////////////////////////////////////////////
1332/// Return true if the class has a method ResetAfterMerge(TFileMergeInfo *)
1333
1334bool ROOT::TMetaUtils::HasResetAfterMerge(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1335{
1336 // Detect if the class has a 'new' Merge function.
1337 // bool hasMethod = cl.HasMethod("DirectoryAutoAdd");
1338
1339 // Detect if the class or one of its parent has a DirectoryAutoAdd
1340 const char *proto = "TFileMergeInfo*";
1341 const char *name = "ResetAfterMerge";
1342
1343 return CheckPublicFuncWithProto(cl,name,proto, interp, false /*diags*/);
1344}
1345
1346
1347////////////////////////////////////////////////////////////////////////////////
1348/// Return true if the class has a custom member function streamer.
1349
1351 const clang::CXXRecordDecl* clxx,
1352 const cling::Interpreter &interp,
1354{
1355 static const char *proto = "TBuffer&";
1356
1357 const clang::CXXMethodDecl *method
1358 = GetMethodWithProto(clxx,"Streamer",proto, interp,
1359 cling::LookupHelper::NoDiagnostics);
1360 const clang::DeclContext *clxx_as_context = llvm::dyn_cast<clang::DeclContext>(clxx);
1361
1362 return (method && method->getDeclContext() == clxx_as_context
1363 && ( cl.RequestNoStreamer() || !cl.RequestStreamerInfo()));
1364}
1365
1366////////////////////////////////////////////////////////////////////////////////
1367/// Return true if the class has a custom member function streamer.
1368
1370 const clang::CXXRecordDecl* clxx,
1371 const cling::Interpreter &interp,
1373{
1374 static const char *proto = "TBuffer&,TClass*";
1375
1376 const clang::CXXMethodDecl *method
1377 = GetMethodWithProto(clxx,"Streamer",proto, interp,
1378 cling::LookupHelper::NoDiagnostics);
1379 const clang::DeclContext *clxx_as_context = llvm::dyn_cast<clang::DeclContext>(clxx);
1380
1381 return (method && method->getDeclContext() == clxx_as_context
1382 && ( cl.RequestNoStreamer() || !cl.RequestStreamerInfo()));
1383}
1384
1385
1386////////////////////////////////////////////////////////////////////////////////
1387/// Main implementation relying on GetFullyQualifiedTypeName
1388/// All other GetQualifiedName functions leverage this one except the
1389/// one for namespaces.
1390
1391void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
1392{
1394}
1395
1396//----
1397std::string ROOT::TMetaUtils::GetQualifiedName(const clang::QualType &type, const clang::NamedDecl &forcontext)
1398{
1399 std::string result;
1401 type,
1402 forcontext);
1403 return result;
1404}
1405
1406
1407////////////////////////////////////////////////////////////////////////////////
1408
1409void ROOT::TMetaUtils::GetQualifiedName(std::string& qual_type, const clang::Type &type, const clang::NamedDecl &forcontext)
1410{
1411 clang::QualType qualType(&type,0);
1413 qualType,
1414 forcontext);
1415}
1416
1417//---
1418std::string ROOT::TMetaUtils::GetQualifiedName(const clang::Type &type, const clang::NamedDecl &forcontext)
1419{
1420 std::string result;
1422 type,
1423 forcontext);
1424 return result;
1425}
1426
1427// //______________________________________________________________________________
1428// void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::NamespaceDecl &cl)
1429// {
1430// GetQualifiedName(qual_name,cl);
1431// }
1432//
1433// //----
1434// std::string ROOT::TMetaUtils::GetQualifiedName(const clang::NamespaceDecl &cl){
1435// return GetQualifiedName(cl);
1436// }
1437
1438////////////////////////////////////////////////////////////////////////////////
1439/// This implementation does not rely on GetFullyQualifiedTypeName
1440
1441void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::NamedDecl &cl)
1442{
1443 llvm::raw_string_ostream stream(qual_name);
1444 clang::PrintingPolicy policy( cl.getASTContext().getPrintingPolicy() );
1445 policy.SuppressTagKeyword = true; // Never get the class or struct keyword
1446 policy.SuppressUnwrittenScope = true; // Don't write the inline or anonymous namespace names.
1447
1448 cl.getNameForDiagnostic(stream,policy,true);
1449 stream.flush(); // flush to string.
1450
1451 if ( qual_name == "(anonymous " || qual_name == "(unnamed" ) {
1452 size_t pos = qual_name.find(':');
1453 qual_name.erase(0,pos+2);
1454 }
1455}
1456
1457//----
1458std::string ROOT::TMetaUtils::GetQualifiedName(const clang::NamedDecl &cl){
1459 std::string result;
1461 return result;
1462}
1463
1464
1465////////////////////////////////////////////////////////////////////////////////
1466
1467void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::RecordDecl &recordDecl)
1468{
1469 const clang::Type* declType ( recordDecl.getTypeForDecl() );
1470 clang::QualType qualType(declType,0);
1472 qualType,
1473 recordDecl);
1474}
1475
1476//----
1477std::string ROOT::TMetaUtils::GetQualifiedName(const clang::RecordDecl &recordDecl)
1478{
1479 std::string result;
1481 return result;
1482}
1483
1484////////////////////////////////////////////////////////////////////////////////
1485
1490
1491//----
1498
1499////////////////////////////////////////////////////////////////////////////////
1500/// Create the data member name-type map for given class
1501
1502static void CreateNameTypeMap(const clang::CXXRecordDecl &cl, ROOT::MembersTypeMap_t& nameType)
1503{
1504 std::stringstream dims;
1505 std::string typenameStr;
1506
1507 const clang::ASTContext& astContext = cl.getASTContext();
1508
1509 // Loop over the non static data member.
1510 for(clang::RecordDecl::field_iterator field_iter = cl.field_begin(), end = cl.field_end();
1511 field_iter != end;
1512 ++field_iter){
1513 // The CINT based code was filtering away static variables (they are not part of
1514 // the list starting with field_begin in clang), and const enums (which should
1515 // also not be part of this list).
1516 // It was also filtering out the 'G__virtualinfo' artificial member.
1517
1518 typenameStr.clear();
1519 dims.str("");
1520 dims.clear();
1521
1522 clang::QualType fieldType(field_iter->getType());
1523 if (fieldType->isConstantArrayType()) {
1524 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(fieldType.getTypePtr());
1525 while (arrayType) {
1526 dims << "[" << arrayType->getSize().getLimitedValue() << "]";
1527 fieldType = arrayType->getElementType();
1528 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1529 }
1530 }
1531
1533 nameType[field_iter->getName().str()] = ROOT::Internal::TSchemaType(typenameStr.c_str(),dims.str().c_str());
1534 }
1535
1536 // And now the base classes
1537 // We also need to look at the base classes.
1538 for(clang::CXXRecordDecl::base_class_const_iterator iter = cl.bases_begin(), end = cl.bases_end();
1539 iter != end;
1540 ++iter){
1541 std::string basename( iter->getType()->getAsCXXRecordDecl()->getNameAsString() ); // Intentionally using only the unqualified name.
1543 }
1544}
1545
1546////////////////////////////////////////////////////////////////////////////////
1547
1548const clang::FunctionDecl *ROOT::TMetaUtils::GetFuncWithProto(const clang::Decl* cinfo,
1549 const char *method,
1550 const char *proto,
1551 const cling::Interpreter &interp,
1552 bool diagnose)
1553{
1554 return interp.getLookupHelper().findFunctionProto(cinfo, method, proto,
1555 diagnose ? cling::LookupHelper::WithDiagnostics
1556 : cling::LookupHelper::NoDiagnostics);
1557}
1558
1559////////////////////////////////////////////////////////////////////////////////
1560/// It looks like the template specialization decl actually contains _less_ information
1561/// on the location of the code than the decl (in case where there is forward declaration,
1562/// that is what the specialization points to.
1563///
1564/// const clang::CXXRecordDecl* clxx = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
1565/// if (clxx) {
1566/// switch(clxx->getTemplateSpecializationKind()) {
1567/// case clang::TSK_Undeclared:
1568/// // We want the default behavior
1569/// break;
1570/// case clang::TSK_ExplicitInstantiationDeclaration:
1571/// case clang::TSK_ExplicitInstantiationDefinition:
1572/// case clang::TSK_ImplicitInstantiation: {
1573/// // We want the location of the template declaration:
1574/// const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
1575/// if (tmplt_specialization) {
1576/// return GetLineNumber(const_cast< clang::ClassTemplateSpecializationDecl *>(tmplt_specialization)->getSpecializedTemplate());
1577/// }
1578/// break;
1579/// }
1580/// case clang::TSK_ExplicitSpecialization:
1581/// // We want the default behavior
1582/// break;
1583/// default:
1584/// break;
1585/// }
1586/// }
1587
1589{
1590 clang::SourceLocation sourceLocation = decl->getLocation();
1591 clang::SourceManager& sourceManager = decl->getASTContext().getSourceManager();
1592
1593 if (!sourceLocation.isValid() ) {
1594 return -1;
1595 }
1596
1597 if (!sourceLocation.isFileID()) {
1598 sourceLocation = sourceManager.getExpansionRange(sourceLocation).getEnd();
1599 }
1600
1601 if (sourceLocation.isValid() && sourceLocation.isFileID()) {
1602 return sourceManager.getLineNumber(sourceManager.getFileID(sourceLocation),sourceManager.getFileOffset(sourceLocation));
1603 }
1604 else {
1605 return -1;
1606 }
1607}
1608
1609////////////////////////////////////////////////////////////////////////////////
1610/// Return true if the type is a Double32_t or Float16_t or
1611/// is a instance template that depends on Double32_t or Float16_t.
1612
1614{
1615 while (llvm::isa<clang::PointerType>(instanceType.getTypePtr())
1616 || llvm::isa<clang::ReferenceType>(instanceType.getTypePtr()))
1617 {
1618 instanceType = instanceType->getPointeeType();
1619 }
1620
1621 const clang::ElaboratedType* etype
1622 = llvm::dyn_cast<clang::ElaboratedType>(instanceType.getTypePtr());
1623 if (etype) {
1624 instanceType = clang::QualType(etype->getNamedType().getTypePtr(),0);
1625 }
1626
1627 // There is no typedef to worried about, except for the opaque ones.
1628
1629 // Technically we should probably used our own list with just
1630 // Double32_t and Float16_t
1631 if (normCtxt.GetTypeWithAlternative().count(instanceType.getTypePtr())) {
1632 return true;
1633 }
1634
1635
1636 bool result = false;
1637 const clang::CXXRecordDecl* clxx = instanceType->getAsCXXRecordDecl();
1638 if (clxx && clxx->getTemplateSpecializationKind() != clang::TSK_Undeclared) {
1639 // do the template thing.
1640 const clang::TemplateSpecializationType* TST
1641 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instanceType.getTypePtr());
1642 if (!TST) {
1643 // std::string type_name;
1644 // type_name = GetQualifiedName( instanceType, *clxx );
1645 // fprintf(stderr,"ERROR: Could not findS TST for %s\n",type_name.c_str());
1646 return false;
1647 }
1648 for (const clang::TemplateArgument &TA : TST->template_arguments()) {
1649 if (TA.getKind() == clang::TemplateArgument::Type) {
1651 }
1652 }
1653 }
1654 return result;
1655}
1656
1657////////////////////////////////////////////////////////////////////////////////
1658/// Return true if any of the argument is or contains a double32.
1659
1661 const cling::Interpreter &interp,
1663{
1664 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1665 if (!clxx || clxx->getTemplateSpecializationKind() == clang::TSK_Undeclared) return false;
1666
1667 clang::QualType instanceType = interp.getLookupHelper().findType(cl.GetNormalizedName(),
1668 cling::LookupHelper::WithDiagnostics);
1669 if (instanceType.isNull()) {
1670 //Error(0,"Could not find the clang::Type for %s\n",cl.GetNormalizedName());
1671 return false;
1672 }
1673
1675}
1676
1677////////////////////////////////////////////////////////////////////////////////
1678/// Extract attr string
1679
1681{
1682 clang::AnnotateAttr* annAttr = clang::dyn_cast<clang::AnnotateAttr>(attribute);
1683 if (!annAttr) {
1684 //TMetaUtils::Error(0,"Could not cast Attribute to AnnotatedAttribute\n");
1685 return 1;
1686 }
1687 attrString = annAttr->getAnnotation().str();
1688 return 0;
1689}
1690
1691////////////////////////////////////////////////////////////////////////////////
1692
1694{
1695 // if separator found, extract name and value
1696 size_t substrFound (attributeStr.find(propNames::separator));
1697 if (substrFound==std::string::npos) {
1698 //TMetaUtils::Error(0,"Could not find property name-value separator (%s)\n",ROOT::TMetaUtils::PropertyNameValSeparator.c_str());
1699 return 1;
1700 }
1701 size_t EndPart1 = attributeStr.find_first_of(propNames::separator) ;
1702 attrName = attributeStr.substr(0, EndPart1);
1703 const int separatorLength(propNames::separator.size());
1705 return 0;
1706}
1707
1708////////////////////////////////////////////////////////////////////////////////
1709
1710int ROOT::TMetaUtils::extractPropertyNameVal(clang::Attr* attribute, std::string& attrName, std::string& attrValue)
1711{
1712 std::string attrString;
1714 if (0!=ret) return ret;
1716}
1717
1718////////////////////////////////////////////////////////////////////////////////
1719/// This routine counts on the "propName<separator>propValue" format
1720
1722 const std::string& propName,
1723 std::string& propValue)
1724{
1725 for (clang::Decl::attr_iterator attrIt = decl.attr_begin();
1726 attrIt!=decl.attr_end();++attrIt){
1727 clang::AnnotateAttr* annAttr = clang::dyn_cast<clang::AnnotateAttr>(*attrIt);
1728 if (!annAttr) continue;
1729
1730 llvm::StringRef attribute = annAttr->getAnnotation();
1731 std::pair<llvm::StringRef,llvm::StringRef> split = attribute.split(propNames::separator.c_str());
1732 if (split.first != propName.c_str()) continue;
1733 else {
1734 propValue = split.second.str();
1735 return true;
1736 }
1737 }
1738 return false;
1739}
1740
1741////////////////////////////////////////////////////////////////////////////////
1742/// This routine counts on the "propName<separator>propValue" format
1743
1745 const std::string& propName,
1746 int& propValue)
1747{
1748 for (clang::Decl::attr_iterator attrIt = decl.attr_begin();
1749 attrIt!=decl.attr_end();++attrIt){
1750 clang::AnnotateAttr* annAttr = clang::dyn_cast<clang::AnnotateAttr>(*attrIt);
1751 if (!annAttr) continue;
1752
1753 llvm::StringRef attribute = annAttr->getAnnotation();
1754 std::pair<llvm::StringRef,llvm::StringRef> split = attribute.split(propNames::separator.c_str());
1755 if (split.first != propName.c_str()) continue;
1756 else {
1757 return split.second.getAsInteger(10,propValue);
1758 }
1759 }
1760 return false;
1761}
1762
1763////////////////////////////////////////////////////////////////////////////////
1764/// FIXME: a function of 450+ lines!
1765
1767 const AnnotatedRecordDecl &cl,
1768 const clang::CXXRecordDecl *decl,
1769 const cling::Interpreter &interp,
1772 bool& needCollectionProxy)
1773{
1774 std::string classname = TClassEdit::GetLong64_Name(cl.GetNormalizedName());
1775
1776 std::string mappedname;
1777 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
1778 std::string csymbol = classname;
1779 std::string args;
1780
1781 if ( ! TClassEdit::IsStdClass( classname.c_str() ) ) {
1782
1783 // Prefix the full class name with '::' except for the STL
1784 // containers and std::string. This is to request the
1785 // real class instead of the class in the namespace ROOT::Shadow
1786 csymbol.insert(0,"::");
1787 }
1788
1789 int stl = TClassEdit::IsSTLCont(classname);
1790 bool bset = TClassEdit::IsSTLBitset(classname.c_str());
1791
1792 bool isStd = TMetaUtils::IsStdClass(*decl);
1793 const cling::LookupHelper& lh = interp.getLookupHelper();
1794 bool isString = TMetaUtils::IsOfType(*decl,"std::string",lh);
1795
1796 bool isStdNotString = isStd && !isString;
1797
1798 finalString << "namespace ROOT {" << "\n";
1799
1800 if (!ClassInfo__HasMethod(decl,"Dictionary",interp) || IsTemplate(*decl))
1801 {
1802 finalString << " static TClass *" << mappedname.c_str() << "_Dictionary();\n"
1803 << " static void " << mappedname.c_str() << "_TClassManip(TClass*);\n";
1804
1805
1806 }
1807
1808 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
1809 finalString << " static void *new_" << mappedname.c_str() << "(void *p = nullptr);" << "\n";
1810
1811 if (args.size()==0 && NeedDestructor(decl, interp))
1812 {
1813 finalString << " static void *newArray_";
1814 finalString << mappedname.c_str();
1815 finalString << "(Long_t size, void *p);";
1816 finalString << "\n";
1817 }
1818 }
1819
1820 if (NeedDestructor(decl, interp)) {
1821 finalString << " static void delete_" << mappedname.c_str() << "(void *p);" << "\n" << " static void deleteArray_" << mappedname.c_str() << "(void *p);" << "\n" << " static void destruct_" << mappedname.c_str() << "(void *p);" << "\n";
1822 }
1824 finalString << " static void directoryAutoAdd_" << mappedname.c_str() << "(void *obj, TDirectory *dir);" << "\n";
1825 }
1827 finalString << " static void streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj);" << "\n";
1828 }
1830 finalString << " static void conv_streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj, const TClass*);" << "\n";
1831 }
1833 finalString << " static Long64_t merge_" << mappedname.c_str() << "(void *obj, TCollection *coll,TFileMergeInfo *info);" << "\n";
1834 }
1836 finalString << " static void reset_" << mappedname.c_str() << "(void *obj, TFileMergeInfo *info);" << "\n";
1837 }
1838
1839 //--------------------------------------------------------------------------
1840 // Check if we have any schema evolution rules for this class
1841 /////////////////////////////////////////////////////////////////////////////
1842
1843 ROOT::SchemaRuleClassMap_t::iterator rulesIt1 = ROOT::gReadRules.find( classname.c_str() );
1844 ROOT::SchemaRuleClassMap_t::iterator rulesIt2 = ROOT::gReadRawRules.find( classname.c_str() );
1845
1847 CreateNameTypeMap( *decl, nameTypeMap ); // here types for schema evo are written
1848
1849 //--------------------------------------------------------------------------
1850 // Process the read rules
1851 /////////////////////////////////////////////////////////////////////////////
1852
1853 if( rulesIt1 != ROOT::gReadRules.end() ) {
1854 int i = 0;
1855 finalString << "\n // Schema evolution read functions\n";
1856 std::list<ROOT::SchemaRuleMap_t>::iterator rIt = rulesIt1->second.fRules.begin();
1857 while (rIt != rulesIt1->second.fRules.end()) {
1858
1859 //--------------------------------------------------------------------
1860 // Check if the rules refer to valid data members
1861 ///////////////////////////////////////////////////////////////////////
1862
1863 std::string error_string;
1865 Warning(nullptr, "%s", error_string.c_str());
1866 rIt = rulesIt1->second.fRules.erase(rIt);
1867 continue;
1868 }
1869
1870 //---------------------------------------------------------------------
1871 // Write the conversion function if necessary
1872 ///////////////////////////////////////////////////////////////////////
1873
1874 if( rIt->find( "code" ) != rIt->end() ) {
1876 }
1877 ++rIt;
1878 }
1879 }
1880
1881
1882
1883
1884 //--------------------------------------------------------------------------
1885 // Process the read raw rules
1886 /////////////////////////////////////////////////////////////////////////////
1887
1888 if( rulesIt2 != ROOT::gReadRawRules.end() ) {
1889 int i = 0;
1890 finalString << "\n // Schema evolution read raw functions\n";
1891 std::list<ROOT::SchemaRuleMap_t>::iterator rIt = rulesIt2->second.fRules.begin();
1892 while (rIt != rulesIt2->second.fRules.end()) {
1893
1894 //--------------------------------------------------------------------
1895 // Check if the rules refer to valid data members
1896 ///////////////////////////////////////////////////////////////////////
1897
1898 std::string error_string;
1900 Warning(nullptr, "%s", error_string.c_str());
1901 rIt = rulesIt2->second.fRules.erase(rIt);
1902 continue;
1903 }
1904
1905 //---------------------------------------------------------------------
1906 // Write the conversion function
1907 ///////////////////////////////////////////////////////////////////////
1908
1909 if( rIt->find( "code" ) == rIt->end() )
1910 continue;
1911
1913 ++rIt;
1914 }
1915 }
1916
1917 finalString << "\n" << " // Function generating the singleton type initializer" << "\n";
1918
1919 finalString << " static TGenericClassInfo *GenerateInitInstanceLocal(const " << csymbol << "*)" << "\n" << " {" << "\n";
1920
1921 finalString << " " << csymbol << " *ptr = nullptr;" << "\n";
1922
1923 //fprintf(fp, " static ::ROOT::ClassInfo< %s > \n",classname.c_str());
1924 if (ClassInfo__HasMethod(decl,"IsA",interp) ) {
1925 finalString << " static ::TVirtualIsAProxy* isa_proxy = new ::TInstrumentedIsAProxy< " << csymbol << " >(nullptr);" << "\n";
1926 }
1927 else {
1928 finalString << " static ::TVirtualIsAProxy* isa_proxy = new ::TIsAProxy(typeid(" << csymbol << "));" << "\n";
1929 }
1930 finalString << " static ::ROOT::TGenericClassInfo " << "\n" << " instance(\"" << classname.c_str() << "\", ";
1931
1932 if (ClassInfo__HasMethod(decl,"Class_Version",interp)) {
1933 finalString << csymbol << "::Class_Version(), ";
1934 } else if (bset) {
1935 finalString << "2, "; // bitset 'version number'
1936 } else if (stl) {
1937 finalString << "-2, "; // "::TStreamerInfo::Class_Version(), ";
1938 } else if( cl.HasClassVersion() ) {
1939 finalString << cl.RequestedVersionNumber() << ", ";
1940 } else { // if (cl_input.RequestStreamerInfo()) {
1941
1942 // Need to find out if the operator>> is actually defined for this class.
1943 static const char *versionFunc = "GetClassVersion";
1944 // int ncha = strlen(classname.c_str())+strlen(versionFunc)+5;
1945 // char *funcname= new char[ncha];
1946 // snprintf(funcname,ncha,"%s<%s >",versionFunc,classname.c_str());
1947 std::string proto = classname + "*";
1948 const clang::Decl* ctxt = llvm::dyn_cast<clang::Decl>((*cl).getDeclContext());
1949 const clang::FunctionDecl *methodinfo
1951 interp, cling::LookupHelper::NoDiagnostics);
1952 // delete [] funcname;
1953
1954 if (methodinfo &&
1955 ROOT::TMetaUtils::GetFileName(*methodinfo, interp).find("Rtypes.h") == llvm::StringRef::npos) {
1956
1957 // GetClassVersion was defined in the header file.
1958 //fprintf(fp, "GetClassVersion((%s *)0x0), ",classname.c_str());
1959 finalString << "GetClassVersion< ";
1960 finalString << classname.c_str();
1961 finalString << " >(), ";
1962 }
1963 //static char temporary[1024];
1964 //sprintf(temporary,"GetClassVersion<%s>( (%s *) 0x0 )",classname.c_str(),classname.c_str());
1965 //fprintf(stderr,"DEBUG: %s has value %d\n",classname.c_str(),(int)G__int(G__calc(temporary)));
1966 }
1967
1968 std::string filename = ROOT::TMetaUtils::GetFileName(*cl, interp);
1969 if (filename.length() > 0) {
1970 for (unsigned int i=0; i<filename.length(); i++) {
1971 if (filename[i]=='\\') filename[i]='/';
1972 }
1973 }
1974 finalString << "\"" << filename << "\", " << ROOT::TMetaUtils::GetLineNumber(cl)
1975 << "," << "\n" << " typeid(" << csymbol
1976 << "), ::ROOT::Internal::DefineBehavior(ptr, ptr)," << "\n" << " ";
1977
1978 if (ClassInfo__HasMethod(decl,"Dictionary",interp) && !IsTemplate(*decl)) {
1979 finalString << "&" << csymbol << "::Dictionary, ";
1980 } else {
1981 finalString << "&" << mappedname << "_Dictionary, ";
1982 }
1983
1984 enum {
1985 TClassTable__kHasCustomStreamerMember = 0x10 // See TClassTable.h
1986 };
1987
1988 Int_t rootflag = cl.RootFlag();
1991 }
1992 finalString << "isa_proxy, " << rootflag << "," << "\n"
1993 << " sizeof(" << csymbol << "), alignof(" << csymbol << ") );" << "\n";
1994 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
1995 finalString << " instance.SetNew(&new_" << mappedname.c_str() << ");" << "\n";
1996 if (args.size()==0 && NeedDestructor(decl, interp))
1997 finalString << " instance.SetNewArray(&newArray_" << mappedname.c_str() << ");" << "\n";
1998 }
1999 if (NeedDestructor(decl, interp)) {
2000 finalString << " instance.SetDelete(&delete_" << mappedname.c_str() << ");" << "\n" << " instance.SetDeleteArray(&deleteArray_" << mappedname.c_str() << ");" << "\n" << " instance.SetDestructor(&destruct_" << mappedname.c_str() << ");" << "\n";
2001 }
2003 finalString << " instance.SetDirectoryAutoAdd(&directoryAutoAdd_" << mappedname.c_str() << ");" << "\n";
2004 }
2006 // We have a custom member function streamer or an older (not StreamerInfo based) automatic streamer.
2007 finalString << " instance.SetStreamerFunc(&streamer_" << mappedname.c_str() << ");" << "\n";
2008 }
2010 // We have a custom member function streamer or an older (not StreamerInfo based) automatic streamer.
2011 finalString << " instance.SetConvStreamerFunc(&conv_streamer_" << mappedname.c_str() << ");" << "\n";
2012 }
2014 finalString << " instance.SetMerge(&merge_" << mappedname.c_str() << ");" << "\n";
2015 }
2017 finalString << " instance.SetResetAfterMerge(&reset_" << mappedname.c_str() << ");" << "\n";
2018 }
2019 if (bset) {
2020 finalString << " instance.AdoptCollectionProxyInfo(TCollectionProxyInfo::Generate(TCollectionProxyInfo::" << "Pushback" << "<Internal::TStdBitsetHelper< " << classname.c_str() << " > >()));" << "\n";
2021
2022 needCollectionProxy = true;
2023 } else if (stl != 0 &&
2024 ((stl > 0 && stl<ROOT::kSTLend) || (stl < 0 && stl>-ROOT::kSTLend)) && // is an stl container
2025 (stl != ROOT::kSTLbitset && stl !=-ROOT::kSTLbitset) ){ // is no bitset
2026 int idx = classname.find("<");
2027 int stlType = (idx!=(int)std::string::npos) ? TClassEdit::STLKind(classname.substr(0,idx)) : 0;
2028 const char* methodTCP = nullptr;
2029 switch(stlType) {
2030 case ROOT::kSTLvector:
2031 case ROOT::kSTLlist:
2032 case ROOT::kSTLdeque:
2033 case ROOT::kROOTRVec:
2034 methodTCP="Pushback";
2035 break;
2037 methodTCP="Pushfront";
2038 break;
2039 case ROOT::kSTLmap:
2040 case ROOT::kSTLmultimap:
2043 methodTCP="MapInsert";
2044 break;
2045 case ROOT::kSTLset:
2046 case ROOT::kSTLmultiset:
2049 methodTCP="Insert";
2050 break;
2051 }
2052 // FIXME Workaround: for the moment we do not generate coll proxies with unique ptrs since
2053 // they imply copies and therefore do not compile.
2054 auto classNameForIO = TClassEdit::GetNameForIO(classname);
2055
2056 finalString << " static_assert(alignof(" << csymbol << "::value_type) <= 4096,\n";
2057 finalString << " \"Class with alignment strictly greater than 4096 are currently not supported in "
2058 "CollectionProxy. \"\n";
2059 finalString << " \"Please report this case to the developers\");\n";
2060 finalString << " instance.AdoptCollectionProxyInfo(TCollectionProxyInfo::Generate(TCollectionProxyInfo::" << methodTCP << "< " << classNameForIO.c_str() << " >()));" << "\n";
2061
2062 needCollectionProxy = true;
2063 }
2064
2065 //---------------------------------------------------------------------------
2066 // Register Alternate spelling of the class name.
2067 /////////////////////////////////////////////////////////////////////////////
2068
2069 if (cl.GetRequestedName()[0] && classname != cl.GetRequestedName()) {
2070 finalString << "\n" << " instance.AdoptAlternate(::ROOT::AddClassAlternate(\""
2071 << classname << "\",\"" << cl.GetRequestedName() << "\"));\n";
2072 }
2073
2074 if (!cl.GetDemangledTypeInfo().empty()
2075 && cl.GetDemangledTypeInfo() != classname
2076 && cl.GetDemangledTypeInfo() != cl.GetRequestedName()) {
2077 finalString << "\n" << " instance.AdoptAlternate(::ROOT::AddClassAlternate(\""
2078 << classname << "\",\"" << cl.GetDemangledTypeInfo() << "\"));\n";
2079
2080 }
2081
2082 //---------------------------------------------------------------------------
2083 // Register underlying SoA record for RNTuple SoA layouts
2084 /////////////////////////////////////////////////////////////////////////////
2085
2086 if (!cl.RequestedRNTupleSoARecord().empty()) {
2087 finalString << " instance.SetRNTupleSoARecord(\"" << cl.RequestedRNTupleSoARecord() << "\");" << "\n";
2088 }
2089
2090 //---------------------------------------------------------------------------
2091 // Pass the schema evolution rules to TGenericClassInfo
2092 /////////////////////////////////////////////////////////////////////////////
2093
2094 if( (rulesIt1 != ROOT::gReadRules.end() && rulesIt1->second.size()>0) || (rulesIt2 != ROOT::gReadRawRules.end() && rulesIt2->second.size()>0) ) {
2095 finalString << "\n" << " ::ROOT::Internal::TSchemaHelper* rule;" << "\n";
2096 }
2097
2098 if( rulesIt1 != ROOT::gReadRules.end() ) {
2099 finalString << "\n" << " // the io read rules" << "\n" << " std::vector<::ROOT::Internal::TSchemaHelper> readrules(" << rulesIt1->second.size() << ");" << "\n";
2100 ROOT::WriteSchemaList(rulesIt1->second.fRules, "readrules", finalString);
2101 finalString << " instance.SetReadRules( readrules );" << "\n";
2102 rulesIt1->second.fGenerated = true;
2103 }
2104
2105 if( rulesIt2 != ROOT::gReadRawRules.end() ) {
2106 finalString << "\n" << " // the io read raw rules" << "\n" << " std::vector<::ROOT::Internal::TSchemaHelper> readrawrules(" << rulesIt2->second.size() << ");" << "\n";
2107 ROOT::WriteSchemaList(rulesIt2->second.fRules, "readrawrules", finalString);
2108 finalString << " instance.SetReadRawRules( readrawrules );" << "\n";
2109 rulesIt2->second.fGenerated = true;
2110 }
2111
2112 finalString << " return &instance;" << "\n" << " }" << "\n";
2113
2115 // The GenerateInitInstance for STL are not unique and should not be externally accessible
2116 finalString << " TGenericClassInfo *GenerateInitInstance(const " << csymbol << "*)" << "\n" << " {\n return GenerateInitInstanceLocal(static_cast<" << csymbol << "*>(nullptr));\n }" << "\n";
2117 }
2118
2119 finalString << " // Static variable to force the class initialization" << "\n";
2120 // must be one long line otherwise UseDummy does not work
2121
2122
2123 finalString << " static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstanceLocal(static_cast<const " << csymbol << "*>(nullptr)); R__UseDummy(_R__UNIQUE_DICT_(Init));" << "\n";
2124
2125 if (!ClassInfo__HasMethod(decl,"Dictionary",interp) || IsTemplate(*decl)) {
2126 finalString << "\n" << " // Dictionary for non-ClassDef classes" << "\n"
2127 << " static TClass *" << mappedname << "_Dictionary() {\n"
2128 << " TClass* theClass ="
2129 << "::ROOT::GenerateInitInstanceLocal(static_cast<const " << csymbol << "*>(nullptr))->GetClass();\n"
2130 << " " << mappedname << "_TClassManip(theClass);\n";
2131 finalString << " return theClass;\n";
2132 finalString << " }\n\n";
2133
2134 // Now manipulate tclass in order to percolate the properties expressed as
2135 // annotations of the decls.
2136 std::string manipString;
2137 std::string attribute_s;
2138 std::string attrName, attrValue;
2139 // Class properties
2140 bool attrMapExtracted = false;
2141 if (decl->hasAttrs()){
2142 // Loop on the attributes
2143 for (clang::Decl::attr_iterator attrIt = decl->attr_begin();
2144 attrIt!=decl->attr_end();++attrIt){
2146 continue;
2147 }
2149 continue;
2150 }
2151 if (attrName == "name" ||
2152 attrName == "pattern" ||
2153 attrName == "rootmap") continue;
2154 // A general property
2155 // 1) We need to create the property map (in the gen code)
2156 // 2) we need to take out the map (in the gen code)
2157 // 3) We need to bookkep the fact that the map is created and out (in this source)
2158 // 4) We fill the map (in the gen code)
2159 if (!attrMapExtracted){
2160 manipString+=" theClass->CreateAttributeMap();\n";
2161 manipString+=" TDictAttributeMap* attrMap( theClass->GetAttributeMap() );\n";
2162 attrMapExtracted=true;
2163 }
2164 manipString+=" attrMap->AddProperty(\""+attrName +"\",\""+attrValue+"\");\n";
2165 }
2166 } // end of class has properties
2167
2168 // Member properties
2169 // Loop on declarations inside the class, including data members
2170 for(clang::CXXRecordDecl::decl_iterator internalDeclIt = decl->decls_begin();
2171 internalDeclIt != decl->decls_end(); ++internalDeclIt){
2172 if (!(!(*internalDeclIt)->isImplicit()
2173 && (clang::isa<clang::FieldDecl>(*internalDeclIt) ||
2174 clang::isa<clang::VarDecl>(*internalDeclIt)))) continue; // Check if it's a var or a field
2175
2176 // Now let's check the attributes of the var/field
2177 if (!internalDeclIt->hasAttrs()) continue;
2178
2179 attrMapExtracted = false;
2180 bool memberPtrCreated = false;
2181
2182 for (clang::Decl::attr_iterator attrIt = internalDeclIt->attr_begin();
2183 attrIt!=internalDeclIt->attr_end();++attrIt){
2184
2185 // Get the attribute as string
2187 continue;
2188 }
2189
2190 // Check the name of the decl
2191 clang::NamedDecl* namedInternalDecl = clang::dyn_cast<clang::NamedDecl> (*internalDeclIt);
2192 if (!namedInternalDecl) {
2193 TMetaUtils::Error(nullptr, "Cannot convert field declaration to clang::NamedDecl");
2194 continue;
2195 }
2196 const std::string memberName(namedInternalDecl->getName());
2197 const std::string cppMemberName = "theMember_"+memberName;
2198
2199 // Prepare a string to get the data member, it can be used later.
2200 const std::string dataMemberCreation= " TDataMember* "+cppMemberName+" = theClass->GetDataMember(\""+memberName+"\");\n";
2201
2202 // Let's now attack regular properties
2203
2205 continue;
2206 }
2207
2208 // Skip these
2209 if (attrName == propNames::comment ||
2210 attrName == propNames::iotype ||
2211 attrName == propNames::ioname ) continue;
2212
2213 if (!memberPtrCreated){
2215 memberPtrCreated=true;
2216 }
2217
2218 if (!attrMapExtracted){
2219 manipString+=" "+cppMemberName+"->CreateAttributeMap();\n";
2220 manipString+=" TDictAttributeMap* memberAttrMap_"+memberName+"( theMember_"+memberName+"->GetAttributeMap() );\n";
2221 attrMapExtracted=true;
2222 }
2223
2224 manipString+=" memberAttrMap_"+memberName+"->AddProperty(\""+attrName +"\",\""+attrValue+"\");\n";
2225
2226
2227 } // End loop on attributes
2228 } // End loop on internal declarations
2229
2230
2231 finalString << " static void " << mappedname << "_TClassManip(TClass* " << (manipString.empty() ? "":"theClass") << "){\n"
2232 << manipString
2233 << " }\n\n";
2234 } // End of !ClassInfo__HasMethod(decl,"Dictionary") || IsTemplate(*decl))
2235
2236 finalString << "} // end of namespace ROOT" << "\n" << "\n";
2237}
2238
2240 std::vector<std::string> &standaloneTargets,
2241 const cling::Interpreter &interp)
2242{
2244 if (!rulesIt1.second.fGenerated) {
2245 const clang::Type *typeptr = nullptr;
2246 const clang::CXXRecordDecl *target =
2247 ROOT::TMetaUtils::ScopeSearch(rulesIt1.first.c_str(), interp, true /*diag*/, &typeptr);
2248
2249 if (!target && !rulesIt1.second.fTargetDecl) {
2250 auto &&nRules = rulesIt1.second.size();
2251 std::string rule{nRules > 1 ? "rules" : "rule"};
2252 std::string verb{nRules > 1 ? "were" : "was"};
2253 ROOT::TMetaUtils::Warning(nullptr, "%d %s for target class %s %s not used!\n", nRules, rule.c_str(),
2254 rulesIt1.first.c_str(), verb.c_str());
2255 continue;
2256 }
2257
2260
2261 std::string name;
2263
2264 std::string mappedname;
2266
2267 finalString << "namespace ROOT {" << "\n";
2268 // Also TClingUtils.cxx:1823
2269 int i = 0;
2270 finalString << "\n // Schema evolution read functions\n";
2271 std::list<ROOT::SchemaRuleMap_t>::iterator rIt = rulesIt1.second.fRules.begin();
2272 while (rIt != rulesIt1.second.fRules.end()) {
2273
2274 //--------------------------------------------------------------------
2275 // Check if the rules refer to valid data members
2276 ///////////////////////////////////////////////////////////////////////
2277
2278 std::string error_string;
2280 ROOT::TMetaUtils::Warning(nullptr, "%s", error_string.c_str());
2281 rIt = rulesIt1.second.fRules.erase(rIt);
2282 continue;
2283 }
2284
2285 //---------------------------------------------------------------------
2286 // Write the conversion function if necessary
2287 ///////////////////////////////////////////////////////////////////////
2288
2289 if (rIt->find("code") != rIt->end()) {
2290 if (rawrules)
2292 else
2294 }
2295 ++rIt;
2296 }
2297 finalString << "} // namespace ROOT" << "\n";
2298
2299 standaloneTargets.push_back(rulesIt1.first);
2300 rulesIt1.second.fGenerated = true;
2301 }
2302 }
2303}
2304
2306 const std::vector<std::string> &standaloneTargets)
2307{
2308 std::string functionname("RecordReadRules_");
2310
2311 finalString << "namespace ROOT {" << "\n";
2312 finalString << " // Registration Schema evolution read functions\n";
2313 finalString << " int " << functionname << "() {" << "\n";
2314 if (!standaloneTargets.empty())
2315 finalString << "\n"
2316 << " ::ROOT::Internal::TSchemaHelper* rule;" << "\n";
2317 for (const auto &target : standaloneTargets) {
2318 std::string name;
2320
2321 ROOT::SchemaRuleClassMap_t::iterator rulesIt1 = ROOT::gReadRules.find(target.c_str());
2322 finalString << " {\n";
2323 if (rulesIt1 != ROOT::gReadRules.end()) {
2324 finalString << " // the io read rules for " << target << "\n";
2325 finalString << " std::vector<::ROOT::Internal::TSchemaHelper> readrules(" << rulesIt1->second.size()
2326 << ");" << "\n";
2327 ROOT::WriteSchemaList(rulesIt1->second.fRules, "readrules", finalString);
2328 finalString << " TClass::RegisterReadRules(TSchemaRule::kReadRule, \"" << name
2329 << "\", std::move(readrules));\n";
2330 rulesIt1->second.fGenerated = true;
2331 }
2332 ROOT::SchemaRuleClassMap_t::iterator rulesIt2 = ROOT::gReadRawRules.find(target.c_str());
2333 if (rulesIt2 != ROOT::gReadRawRules.end()) {
2334 finalString << "\n // the io read raw rules for " << target << "\n";
2335 finalString << " std::vector<::ROOT::Internal::TSchemaHelper> readrawrules(" << rulesIt2->second.size()
2336 << ");" << "\n";
2337 ROOT::WriteSchemaList(rulesIt2->second.fRules, "readrawrules", finalString);
2338 finalString << " TClass::RegisterReadRules(TSchemaRule::kReadRawRule, \"" << name
2339 << "\", std::move(readrawrules));\n";
2340 rulesIt2->second.fGenerated = true;
2341 }
2342 finalString << " }\n";
2343 }
2344 finalString << " return 0;\n";
2345 finalString << " }\n";
2346 finalString << " static int _R__UNIQUE_DICT_(ReadRules_" << dictName << ") = " << functionname << "();";
2347 finalString << "R__UseDummy(_R__UNIQUE_DICT_(ReadRules_" << dictName << "));" << "\n";
2348 finalString << "} // namespace ROOT" << "\n";
2349}
2350
2351////////////////////////////////////////////////////////////////////////////////
2352/// Return true if one of the class' enclosing scope is a namespace and
2353/// set fullname to the fully qualified name,
2354/// clsname to the name within a namespace
2355/// and nsname to the namespace fully qualified name.
2356
2358 std::string &clsname,
2359 std::string &nsname,
2360 const clang::CXXRecordDecl *cl)
2361{
2362 fullname.clear();
2363 nsname.clear();
2364
2366 clsname = fullname;
2367
2368 // Inline namespace are stripped from the normalized name, we need to
2369 // strip it from the prefix we want to remove.
2370 auto ctxt = cl->getEnclosingNamespaceContext();
2371 while(ctxt && ctxt!=cl && ctxt->isInlineNamespace()) {
2372 ctxt = ctxt->getParent();
2373 }
2374 if (ctxt) {
2375 const clang::NamedDecl *namedCtxt = llvm::dyn_cast<clang::NamedDecl>(ctxt);
2376 if (namedCtxt && namedCtxt!=cl) {
2377 const clang::NamespaceDecl *nsdecl = llvm::dyn_cast<clang::NamespaceDecl>(namedCtxt);
2378 if (nsdecl && !nsdecl->isAnonymousNamespace()) {
2380 clsname.erase (0, nsname.size() + 2);
2381 return true;
2382 }
2383 }
2384 }
2385 return false;
2386}
2387
2388////////////////////////////////////////////////////////////////////////////////
2389
2390const clang::DeclContext *GetEnclosingSpace(const clang::RecordDecl &cl)
2391{
2392 const clang::DeclContext *ctxt = cl.getDeclContext();
2393 while(ctxt && !ctxt->isNamespace()) {
2394 ctxt = ctxt->getParent();
2395 }
2396 return ctxt;
2397}
2398
2399////////////////////////////////////////////////////////////////////////////////
2400/// Write all the necessary opening part of the namespace and
2401/// return the number of closing brackets needed
2402/// For example for Space1::Space2
2403/// we write: namespace Space1 { namespace Space2 {
2404/// and return 2.
2405
2406int ROOT::TMetaUtils::WriteNamespaceHeader(std::ostream &out, const clang::DeclContext *ctxt)
2407{
2408 int closing_brackets = 0;
2409
2410 //fprintf(stderr,"DEBUG: in WriteNamespaceHeader for %s with %s\n",
2411 // cl.Fullname(),namespace_obj.Fullname());
2412 if (ctxt && ctxt->isNamespace()) {
2413 closing_brackets = WriteNamespaceHeader(out,ctxt->getParent());
2414 const clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(ctxt);
2415 if (ns) {
2416 for (int indent = 0; indent < closing_brackets; ++indent)
2417 out << " ";
2418 if (ns->isInline())
2419 out << "inline ";
2420 out << "namespace " << ns->getNameAsString() << " {" << std::endl;
2422 }
2423 }
2424
2425 return closing_brackets;
2426}
2427
2428////////////////////////////////////////////////////////////////////////////////
2429
2430int ROOT::TMetaUtils::WriteNamespaceHeader(std::ostream &out, const clang::RecordDecl *cl)
2431{
2432 return WriteNamespaceHeader(out, GetEnclosingSpace(*cl));
2433}
2434
2435////////////////////////////////////////////////////////////////////////////////
2436
2437bool ROOT::TMetaUtils::NeedTemplateKeyword(const clang::CXXRecordDecl *cl)
2438{
2439 clang::TemplateSpecializationKind kind = cl->getTemplateSpecializationKind();
2440 if (kind == clang::TSK_Undeclared ) {
2441 // Note a template;
2442 return false;
2443 } else if (kind == clang::TSK_ExplicitSpecialization) {
2444 // This is a specialized templated class
2445 return false;
2446 } else {
2447 // This is an automatically or explicitly instantiated templated class.
2448 return true;
2449 }
2450}
2451
2452////////////////////////////////////////////////////////////////////////////////
2453/// return true if we can find a custom operator new with placement
2454
2455bool ROOT::TMetaUtils::HasCustomOperatorNewPlacement(const char *which, const clang::RecordDecl &cl, const cling::Interpreter &interp)
2456{
2457 const char *name = which;
2458 const char *proto = "size_t";
2459 const char *protoPlacement = "size_t,void*";
2460
2461 // First search in the enclosing namespaces
2462 const clang::FunctionDecl *operatornew
2463 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl.getDeclContext()),
2464 name, proto, interp,
2465 cling::LookupHelper::NoDiagnostics);
2466 const clang::FunctionDecl *operatornewPlacement
2467 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl.getDeclContext()),
2469 cling::LookupHelper::NoDiagnostics);
2470
2471 const clang::DeclContext *ctxtnew = nullptr;
2472 const clang::DeclContext *ctxtnewPlacement = nullptr;
2473
2474 if (operatornew) {
2475 ctxtnew = operatornew->getParent();
2476 }
2479 }
2480
2481 // Then in the class and base classes
2483 false /*diags*/);
2486 false /*diags*/);
2487
2488 if (operatornew) {
2489 ctxtnew = operatornew->getParent();
2490 }
2493 }
2494
2495 if (!ctxtnewPlacement) {
2496 return false;
2497 }
2498 if (!ctxtnew) {
2499 // Only a new with placement, no hiding
2500 return true;
2501 }
2502 // Both are non zero
2503 if (ctxtnew == ctxtnewPlacement) {
2504 // Same declaration ctxt, no hiding
2505 return true;
2506 }
2507 const clang::CXXRecordDecl* clnew = llvm::dyn_cast<clang::CXXRecordDecl>(ctxtnew);
2508 const clang::CXXRecordDecl* clnewPlacement = llvm::dyn_cast<clang::CXXRecordDecl>(ctxtnewPlacement);
2509 if (!clnew && !clnewPlacement) {
2510 // They are both in different namespaces, I am not sure of the rules.
2511 // we probably ought to find which one is closest ... for now bail
2512 // (because rootcling was also bailing on that).
2513 return true;
2514 }
2515 if (clnew && !clnewPlacement) {
2516 // operator new is class method hiding the outer scope operator new with placement.
2517 return false;
2518 }
2519 if (!clnew && clnewPlacement) {
2520 // operator new is a not class method and can not hide new with placement which is a method
2521 return true;
2522 }
2523 // Both are class methods
2524 if (clnew->isDerivedFrom(clnewPlacement)) {
2525 // operator new is in a more derived part of the hierarchy, it is hiding operator new with placement.
2526 return false;
2527 }
2528 // operator new with placement is in a more derived part of the hierarchy, it can't be hidden by operator new.
2529 return true;
2530}
2531
2532////////////////////////////////////////////////////////////////////////////////
2533/// return true if we can find a custom operator new with placement
2534
2535bool ROOT::TMetaUtils::HasCustomOperatorNewPlacement(const clang::RecordDecl &cl, const cling::Interpreter &interp)
2536{
2537 return HasCustomOperatorNewPlacement("operator new",cl, interp);
2538}
2539
2540////////////////////////////////////////////////////////////////////////////////
2541/// return true if we can find a custom operator new with placement
2542
2543bool ROOT::TMetaUtils::HasCustomOperatorNewArrayPlacement(const clang::RecordDecl &cl, const cling::Interpreter &interp)
2544{
2545 return HasCustomOperatorNewPlacement("operator new[]",cl, interp);
2546}
2547
2548////////////////////////////////////////////////////////////////////////////////
2549/// std::string NormalizedName;
2550/// GetNormalizedName(NormalizedName, decl->getASTContext().getTypeDeclType(decl), interp, normCtxt);
2551
2553 const AnnotatedRecordDecl &cl,
2554 const clang::CXXRecordDecl *decl,
2555 const cling::Interpreter &interp,
2558{
2559 std::string classname = TClassEdit::GetLong64_Name(cl.GetNormalizedName());
2560
2561 std::string mappedname;
2562 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
2563
2564 // Write the functions that are need for the TGenericClassInfo.
2565 // This includes
2566 // IsA
2567 // operator new
2568 // operator new[]
2569 // operator delete
2570 // operator delete[]
2571
2572 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
2573
2574 if ( ! TClassEdit::IsStdClass( classname.c_str() ) ) {
2575
2576 // Prefix the full class name with '::' except for the STL
2577 // containers and std::string. This is to request the
2578 // real class instead of the class in the namespace ROOT::Shadow
2579 classname.insert(0,"::");
2580 }
2581
2582 finalString << "namespace ROOT {" << "\n";
2583
2584 std::string args;
2585 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
2586 // write the constructor wrapper only for concrete classes
2587 finalString << " // Wrappers around operator new" << "\n";
2588 finalString << " static void *new_" << mappedname.c_str() << "(void *p) {" << "\n" << " return p ? ";
2590 finalString << "new(p) ";
2591 finalString << classname.c_str();
2592 finalString << args;
2593 finalString << " : ";
2594 } else {
2595 finalString << "::new(static_cast<::ROOT::Internal::TOperatorNewHelper*>(p)) ";
2596 finalString << classname.c_str();
2597 finalString << args;
2598 finalString << " : ";
2599 }
2600 finalString << "new " << classname.c_str() << args << ";" << "\n";
2601 finalString << " }" << "\n";
2602
2603 if (args.size()==0 && NeedDestructor(decl, interp)) {
2604 // Can not can newArray if the destructor is not public.
2605 finalString << " static void *newArray_";
2606 finalString << mappedname.c_str();
2607 finalString << "(Long_t nElements, void *p) {";
2608 finalString << "\n";
2609 finalString << " return p ? ";
2611 finalString << "new(p) ";
2612 finalString << classname.c_str();
2613 finalString << "[nElements] : ";
2614 } else {
2615 finalString << "::new(static_cast<::ROOT::Internal::TOperatorNewHelper*>(p)) ";
2616 finalString << classname.c_str();
2617 finalString << "[nElements] : ";
2618 }
2619 finalString << "new ";
2620 finalString << classname.c_str();
2621 finalString << "[nElements];";
2622 finalString << "\n";
2623 finalString << " }";
2624 finalString << "\n";
2625 }
2626 }
2627
2628 if (NeedDestructor(decl, interp)) {
2629 finalString << " // Wrapper around operator delete" << "\n" << " static void delete_" << mappedname.c_str() << "(void *p) {" << "\n" << " delete (static_cast<" << classname.c_str() << "*>(p));" << "\n" << " }" << "\n" << " static void deleteArray_" << mappedname.c_str() << "(void *p) {" << "\n" << " delete [] (static_cast<" << classname.c_str() << "*>(p));" << "\n" << " }" << "\n" << " static void destruct_" << mappedname.c_str() << "(void *p) {" << "\n" << " typedef " << classname.c_str() << " current_t;" << "\n" << " (static_cast<current_t*>(p))->~current_t();" << "\n" << " }" << "\n";
2630 }
2631
2633 finalString << " // Wrapper around the directory auto add." << "\n" << " static void directoryAutoAdd_" << mappedname.c_str() << "(void *p, TDirectory *dir) {" << "\n" << " ((" << classname.c_str() << "*)p)->DirectoryAutoAdd(dir);" << "\n" << " }" << "\n";
2634 }
2635
2637 finalString << " // Wrapper around a custom streamer member function." << "\n" << " static void streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj) {" << "\n" << " ((" << classname.c_str() << "*)obj)->" << classname.c_str() << "::Streamer(buf);" << "\n" << " }" << "\n";
2638 }
2639
2641 finalString << " // Wrapper around a custom streamer member function." << "\n" << " static void conv_streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj, const TClass *onfile_class) {" << "\n" << " ((" << classname.c_str() << "*)obj)->" << classname.c_str() << "::Streamer(buf,onfile_class);" << "\n" << " }" << "\n";
2642 }
2643
2644 if (HasNewMerge(decl, interp)) {
2645 finalString << " // Wrapper around the merge function." << "\n" << " static Long64_t merge_" << mappedname.c_str() << "(void *obj,TCollection *coll,TFileMergeInfo *info) {" << "\n" << " return ((" << classname.c_str() << "*)obj)->Merge(coll,info);" << "\n" << " }" << "\n";
2646 } else if (HasOldMerge(decl, interp)) {
2647 finalString << " // Wrapper around the merge function." << "\n" << " static Long64_t merge_" << mappedname.c_str() << "(void *obj,TCollection *coll,TFileMergeInfo *) {" << "\n" << " return ((" << classname.c_str() << "*)obj)->Merge(coll);" << "\n" << " }" << "\n";
2648 }
2649
2651 finalString << " // Wrapper around the Reset function." << "\n" << " static void reset_" << mappedname.c_str() << "(void *obj,TFileMergeInfo *info) {" << "\n" << " ((" << classname.c_str() << "*)obj)->ResetAfterMerge(info);" << "\n" << " }" << "\n";
2652 }
2653 finalString << "} // end of namespace ROOT for class " << classname.c_str() << "\n" << "\n";
2654}
2655
2656////////////////////////////////////////////////////////////////////////////////
2657/// Write interface function for STL members
2658
2660 const cling::Interpreter &interp,
2662{
2663 std::string a;
2664 std::string clName;
2665 TMetaUtils::GetCppName(clName, ROOT::TMetaUtils::GetFileName(*cl.GetRecordDecl(), interp).c_str());
2667 if (version == 0) return;
2668 if (version < 0 && !(cl.RequestStreamerInfo()) ) return;
2669
2670
2671 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
2672 if (!clxx) return;
2673
2674 // We also need to look at the base classes.
2675 for(clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
2676 iter != end;
2677 ++iter)
2678 {
2679 int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
2680 if (k!=0) {
2681 Internal::RStl::Instance().GenerateTClassFor( iter->getType(), interp, normCtxt);
2682 }
2683 }
2684
2685 // Loop over the non static data member.
2686 for(clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
2687 field_iter != end;
2688 ++field_iter)
2689 {
2690 std::string mTypename;
2692
2693 //member is a string
2694 {
2696 if (!strcmp(shortTypeName, "string")) {
2697 continue;
2698 }
2699 }
2700
2702
2704 if (k!=0) {
2705 // fprintf(stderr,"Add %s which is also",m.Type()->Name());
2706 // fprintf(stderr," %s\n",R__TrueName(**field_iter) );
2707 clang::QualType utype(ROOT::TMetaUtils::GetUnderlyingType(field_iter->getType()),0);
2708 Internal::RStl::Instance().GenerateTClassFor(utype, interp, normCtxt);
2709 }
2710 }
2711}
2712
2713////////////////////////////////////////////////////////////////////////////////
2714/// TrueName strips the typedefs and array dimensions.
2715
2716std::string ROOT::TMetaUtils::TrueName(const clang::FieldDecl &m)
2717{
2718 const clang::Type *rawtype = m.getType()->getCanonicalTypeInternal().getTypePtr();
2719 if (rawtype->isArrayType()) {
2720 rawtype = rawtype->getBaseElementTypeUnsafe ();
2721 }
2722
2723 std::string result;
2724 ROOT::TMetaUtils::GetQualifiedName(result, clang::QualType(rawtype,0), m);
2725 return result;
2726}
2727
2728////////////////////////////////////////////////////////////////////////////////
2729/// Return the version number of the class or -1
2730/// if the function Class_Version does not exist.
2731
2732int ROOT::TMetaUtils::GetClassVersion(const clang::RecordDecl *cl, const cling::Interpreter& interp)
2733{
2734 const clang::CXXRecordDecl* CRD = llvm::dyn_cast<clang::CXXRecordDecl>(cl);
2735 if (!CRD) {
2736 // Must be an enum or namespace.
2737 // FIXME: Make it work for a namespace!
2738 return -1;
2739 }
2740 const clang::FunctionDecl* funcCV = ROOT::TMetaUtils::ClassInfo__HasMethod(CRD,"Class_Version",interp);
2741
2742 // if we have no Class_Info() return -1.
2743 if (!funcCV) return -1;
2744
2745 // if we have many Class_Info() (?!) return 1.
2746 if (funcCV == (clang::FunctionDecl*)-1) return 1;
2747
2749}
2750
2751////////////////////////////////////////////////////////////////////////////////
2752/// If the function contains 'just': return SomeValue;
2753/// this routine will extract this value and return it.
2754/// The first element is set to true we have the body of the function and it
2755/// is indeed a trivial function with just a return of a value.
2756/// The second element contains the value (or -1 is case of failure)
2757
2758std::pair<bool, int>
2759ROOT::TMetaUtils::GetTrivialIntegralReturnValue(const clang::FunctionDecl *funcCV, const cling::Interpreter &interp)
2760{
2761 using res_t = std::pair<bool, int>;
2762
2763 const clang::CompoundStmt* FuncBody
2764 = llvm::dyn_cast_or_null<clang::CompoundStmt>(funcCV->getBody());
2765 if (!FuncBody)
2766 return res_t{false, -1};
2767 if (FuncBody->size() != 1) {
2768 // This is a non-ClassDef(), complex function - it might depend on state
2769 // and thus we'll need the runtime and cannot determine the result
2770 // statically.
2771 return res_t{false, -1};
2772 }
2773 const clang::ReturnStmt* RetStmt
2774 = llvm::dyn_cast<clang::ReturnStmt>(FuncBody->body_back());
2775 if (!RetStmt)
2776 return res_t{false, -1};
2777 const clang::Expr* RetExpr = RetStmt->getRetValue();
2778 // ClassDef controls the content of Class_Version() but not the return
2779 // expression which is CPP expanded from what the user provided as second
2780 // ClassDef argument. It's usually just be an integer literal but it could
2781 // also be an enum or a variable template for all we know.
2782 // Go through ICE to be more general.
2783 if (auto RetRes = RetExpr->getIntegerConstantExpr(funcCV->getASTContext())) {
2784 if (RetRes->isSigned())
2785 return res_t{true, (Version_t)RetRes->getSExtValue()};
2786 return res_t{true, (Version_t)RetRes->getZExtValue()};
2787 }
2788 return res_t{false, -1};
2789}
2790
2791////////////////////////////////////////////////////////////////////////////////
2792/// Is this an STL container.
2793
2795{
2796 return TMetaUtils::IsSTLCont(*annotated.GetRecordDecl());
2797}
2798
2799////////////////////////////////////////////////////////////////////////////////
2800/// Is this an STL container?
2801
2803{
2804 clang::QualType type = m.getType();
2806
2807 if (decl) return TMetaUtils::IsSTLCont(*decl);
2808 else return ROOT::kNotSTL;
2809}
2810
2811////////////////////////////////////////////////////////////////////////////////
2812/// Is this an STL container?
2813
2814int ROOT::TMetaUtils::IsSTLContainer(const clang::CXXBaseSpecifier &base)
2815{
2816 clang::QualType type = base.getType();
2818
2819 if (decl) return TMetaUtils::IsSTLCont(*decl);
2820 else return ROOT::kNotSTL;
2821}
2822
2823////////////////////////////////////////////////////////////////////////////////
2824/// Calls the given lambda on every header in the given module.
2825/// includeDirectlyUsedModules designates if the foreach should also loop over
2826/// the headers in all modules that are directly used via a `use` declaration
2827/// in the modulemap.
2829 const std::function<void(const clang::Module::Header &)> &closure,
2831{
2832 // Iterates over all headers in a module and calls the closure on each.
2833
2834 // Make a list of modules and submodules that we can check for headers.
2835 // We use a SetVector to prevent an infinite loop in unlikely case the
2836 // modules somehow are messed up and don't form a tree...
2837 llvm::SetVector<const clang::Module *> modules;
2838 modules.insert(&module);
2839 for (size_t i = 0; i < modules.size(); ++i) {
2840 const clang::Module *M = modules[i];
2841 for (const clang::Module *subModule : M->submodules())
2842 modules.insert(subModule);
2843 }
2844
2845 for (const clang::Module *m : modules) {
2847 for (clang::Module *used : m->DirectUses) {
2849 }
2850 }
2851
2852 // We want to check for all headers except the list of excluded headers here.
2853 for (auto HK : {clang::Module::HK_Normal, clang::Module::HK_Textual, clang::Module::HK_Private,
2854 clang::Module::HK_PrivateTextual}) {
2855 const auto &headerList = m->getHeaders(HK);
2856 for (const clang::Module::Header &moduleHeader : headerList) {
2858 }
2859 }
2860 }
2861}
2862
2863////////////////////////////////////////////////////////////////////////////////
2864/// Return the absolute type of typeDesc.
2865/// E.g.: typeDesc = "class TNamed**", returns "TNamed".
2866/// we remove * and const keywords. (we do not want to remove & ).
2867/// You need to use the result immediately before it is being overwritten.
2868
2870{
2871 static char t[4096];
2872 static const char* constwd = "const ";
2873 static const char* constwdend = "const";
2874
2875 const char *s;
2876 char *p=t;
2877 int lev=0;
2878 for (s=typeDesc;*s;s++) {
2879 if (*s=='<') lev++;
2880 if (*s=='>') lev--;
2881 if (lev==0 && *s=='*') continue;
2882 if (lev==0 && (strncmp(constwd,s,strlen(constwd))==0
2883 ||strcmp(constwdend,s)==0 ) ) {
2884 s+=strlen(constwd)-1; // -1 because the loop adds 1
2885 continue;
2886 }
2887 if (lev==0 && *s==' ' && *(s+1)!='*') { p = t; continue;}
2888 if (p - t > (long)sizeof(t)) {
2889 printf("ERROR (rootcling): type name too long for StortTypeName: %s\n",
2890 typeDesc);
2891 p[0] = 0;
2892 return t;
2893 }
2894 *p++ = *s;
2895 }
2896 p[0]=0;
2897
2898 return t;
2899}
2900
2901bool ROOT::TMetaUtils::IsStreamableObject(const clang::FieldDecl &m,
2902 const cling::Interpreter& interp)
2903{
2904 auto comment = ROOT::TMetaUtils::GetComment( m );
2905
2906 // Transient
2907 if (!comment.empty() && comment[0] == '!')
2908 return false;
2909
2910 clang::QualType type = m.getType();
2911
2912 if (type->isReferenceType()) {
2913 // Reference can not be streamed.
2914 return false;
2915 }
2916
2917 std::string mTypeName = type.getAsString(m.getASTContext().getPrintingPolicy());
2918 if (!strcmp(mTypeName.c_str(), "string") || !strcmp(mTypeName.c_str(), "string*")) {
2919 return true;
2920 }
2921 if (!strcmp(mTypeName.c_str(), "std::string") || !strcmp(mTypeName.c_str(), "std::string*")) {
2922 return true;
2923 }
2924
2926 return true;
2927 }
2928
2929 const clang::Type *rawtype = type.getTypePtr()->getBaseElementTypeUnsafe ();
2930
2931 if (rawtype->isPointerType()) {
2932 //Get to the 'raw' type.
2933 clang::QualType pointee;
2934 while ( (pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull() && pointee.getTypePtr() != rawtype)
2935 {
2936 rawtype = pointee.getTypePtr();
2937 }
2938 }
2939
2940 if (rawtype->isFundamentalType() || rawtype->isEnumeralType()) {
2941 // not an ojbect.
2942 return false;
2943 }
2944
2945 const clang::CXXRecordDecl *cxxdecl = rawtype->getAsCXXRecordDecl();
2947 if (!(ROOT::TMetaUtils::ClassInfo__HasMethod(cxxdecl,"Class_Version", interp))) return true;
2949 if (version > 0) return true;
2950 }
2951 return false;
2952}
2953
2954////////////////////////////////////////////////////////////////////////////////
2955/// Return the absolute type of typeDesc.
2956/// E.g.: typeDesc = "class TNamed**", returns "TNamed".
2957/// we remove * and const keywords. (we do not want to remove & ).
2958/// You need to use the result immediately before it is being overwritten.
2959
2960std::string ROOT::TMetaUtils::ShortTypeName(const clang::FieldDecl &m)
2961{
2962 const clang::Type *rawtype = m.getType().getTypePtr();
2963
2964 //Get to the 'raw' type.
2965 clang::QualType pointee;
2966 while ( rawtype->isPointerType() && ((pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull()) && pointee.getTypePtr() != rawtype)
2967 {
2968 rawtype = pointee.getTypePtr();
2969 }
2970
2971 std::string result;
2972 ROOT::TMetaUtils::GetQualifiedName(result, clang::QualType(rawtype,0), m);
2973 return result;
2974}
2975
2976////////////////////////////////////////////////////////////////////////////////
2977
2978clang::RecordDecl *ROOT::TMetaUtils::GetUnderlyingRecordDecl(clang::QualType type)
2979{
2980 const clang::Type *rawtype = ROOT::TMetaUtils::GetUnderlyingType(type);
2981
2982 if (rawtype->isFundamentalType() || rawtype->isEnumeralType()) {
2983 // not an object.
2984 return nullptr;
2985 }
2986 return rawtype->getAsCXXRecordDecl();
2987}
2988
2989////////////////////////////////////////////////////////////////////////////////
2990/// Generate the code of the class
2991/// If the requestor is genreflex, request the new streamer format
2992
2994 const AnnotatedRecordDecl &cl,
2995 const cling::Interpreter &interp,
2997 std::ostream& dictStream,
2999 bool isGenreflex=false)
3000{
3001 const clang::CXXRecordDecl* decl = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
3002
3003 if (!decl || !decl->isCompleteDefinition()) {
3004 return;
3005 }
3006
3007 std::string fullname;
3009 if (TClassEdit::IsSTLCont(fullname) ) {
3010 Internal::RStl::Instance().GenerateTClassFor(cl.GetNormalizedName(), llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl()), interp, normCtxt);
3011 return;
3012 }
3013
3015 // The !genreflex is there to prevent genreflex to select collections which are data members
3016 // This is to maintain the behaviour of ROOT5 and ROOT6 up to 6.07 included.
3017 if (cl.RootFlag() && !isGenreflex) ROOT::TMetaUtils::WritePointersSTL(cl, interp, normCtxt); // In particular this detect if the class has a version number.
3018 if (!(cl.RequestNoStreamer())) {
3019 (*WriteStreamerFunc)(cl, interp, normCtxt, dictStream, isGenreflex || cl.RequestStreamerInfo());
3020 } else
3021 ROOT::TMetaUtils::Info(nullptr, "Class %s: Do not generate Streamer() [*** custom streamer ***]\n",fullname.c_str());
3022 } else {
3023 ROOT::TMetaUtils::Info(nullptr, "Class %s: Streamer() not declared\n", fullname.c_str());
3024
3025 // See comment above about the !isGenreflex
3027 }
3029}
3030
3031////////////////////////////////////////////////////////////////////////////////
3032/// Add any unspecified template parameters to the class template instance,
3033/// mentioned anywhere in the type.
3034///
3035/// Note: this does not strip any typedef but could be merged with cling::utils::Transform::GetPartiallyDesugaredType
3036/// if we can safely replace TClassEdit::IsStd with a test on the declaring scope
3037/// and if we can resolve the fact that the added parameter do not take into account possible use/dependences on Double32_t
3038/// and if we decide that adding the default is the right long term solution or not.
3039/// Whether it is or not depend on the I/O on whether the default template argument might change or not
3040/// and whether they (should) affect the on disk layout (for STL containers, we do know they do not).
3041
3043 const cling::Interpreter &interpreter,
3045{
3046 const clang::ASTContext& Ctx = interpreter.getCI()->getASTContext();
3047
3048 clang::QualType originalType = instanceType;
3049
3050 // In case of name* we need to strip the pointer first, add the default and attach
3051 // the pointer once again.
3052 if (llvm::isa<clang::PointerType>(instanceType.getTypePtr())) {
3053 // Get the qualifiers.
3054 clang::Qualifiers quals = instanceType.getQualifiers();
3055 clang::QualType newPointee = AddDefaultParameters(instanceType->getPointeeType(), interpreter, normCtxt);
3056 if (newPointee != instanceType->getPointeeType()) {
3057 instanceType = Ctx.getPointerType(newPointee);
3058 // Add back the qualifiers.
3059 instanceType = Ctx.getQualifiedType(instanceType, quals);
3060 }
3061 return instanceType;
3062 }
3063
3064 // In case of Int_t& we need to strip the pointer first, desugar and attach
3065 // the pointer once again.
3066 if (llvm::isa<clang::ReferenceType>(instanceType.getTypePtr())) {
3067 // Get the qualifiers.
3068 bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(instanceType.getTypePtr());
3069 clang::Qualifiers quals = instanceType.getQualifiers();
3070 clang::QualType newPointee = AddDefaultParameters(instanceType->getPointeeType(), interpreter, normCtxt);
3071
3072 if (newPointee != instanceType->getPointeeType()) {
3073 // Add the r- or l- value reference type back to the desugared one
3074 if (isLValueRefTy)
3075 instanceType = Ctx.getLValueReferenceType(newPointee);
3076 else
3077 instanceType = Ctx.getRValueReferenceType(newPointee);
3078 // Add back the qualifiers.
3079 instanceType = Ctx.getQualifiedType(instanceType, quals);
3080 }
3081 return instanceType;
3082 }
3083
3084 // Treat the Scope.
3085 bool prefix_changed = false;
3086 clang::NestedNameSpecifier *prefix = nullptr;
3087 clang::Qualifiers prefix_qualifiers = instanceType.getLocalQualifiers();
3088 const clang::ElaboratedType* etype
3089 = llvm::dyn_cast<clang::ElaboratedType>(instanceType.getTypePtr());
3090 if (etype) {
3091 // We have to also handle the prefix.
3092 prefix = AddDefaultParametersNNS(Ctx, etype->getQualifier(), interpreter, normCtxt);
3093 prefix_changed = prefix != etype->getQualifier();
3094 instanceType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3095 }
3096
3097 // In case of template specializations iterate over the arguments and
3098 // add unspecified default parameter.
3099
3100 const clang::TemplateSpecializationType* TST
3101 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instanceType.getTypePtr());
3102
3103 const clang::ClassTemplateSpecializationDecl* TSTdecl
3104 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(instanceType.getTypePtr()->getAsCXXRecordDecl());
3105
3106 // Don't add the default paramater onto std classes.
3107 // We really need this for __shared_ptr which add a enum constant value which
3108 // is spelled in its 'numeral' form and thus the resulting type name is
3109 // incorrect. We also can used this for any of the STL collections where we
3110 // know we don't want the default argument. For the other members of the
3111 // std namespace this is dubious (because TMetaUtils::GetNormalizedName would
3112 // not drop those defaults). [I.e. the real test ought to be is std and
3113 // name is __shared_ptr or vector or list or set or etc.]
3115
3116 bool mightHaveChanged = false;
3117 if (TST && TSTdecl) {
3118
3119 clang::Sema& S = interpreter.getCI()->getSema();
3120 clang::TemplateDecl *Template = TSTdecl->getSpecializedTemplate()->getMostRecentDecl();
3121 clang::TemplateParameterList *Params = Template->getTemplateParameters();
3122 clang::TemplateParameterList::iterator Param = Params->begin(); // , ParamEnd = Params->end();
3123 //llvm::SmallVectorImpl<TemplateArgument> Converted; // Need to contains the other arguments.
3124 // Converted seems to be the same as our 'desArgs'
3125
3126 unsigned int dropDefault = normCtxt.GetConfig().DropDefaultArg(*Template);
3127
3128 llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
3129 llvm::SmallVector<clang::TemplateArgument, 4> canonArgs;
3130 llvm::ArrayRef<clang::TemplateArgument> template_arguments = TST->template_arguments();
3131 unsigned int Idecl = 0, Edecl = TSTdecl->getTemplateArgs().size();
3132 // If we have more arguments than the TSTdecl, it is a variadic template
3133 // and we want all template arguments.
3134 if (template_arguments.size() > Edecl) {
3135 Edecl = template_arguments.size();
3136 }
3137 unsigned int maxAddArg = Edecl - dropDefault;
3138 for (const clang::TemplateArgument *I = template_arguments.begin(), *E = template_arguments.end(); Idecl != Edecl;
3139 I != E ? ++I : nullptr, ++Idecl, ++Param) {
3140
3141 if (I != E) {
3142
3143 if (I->getKind() == clang::TemplateArgument::Template) {
3144 clang::TemplateName templateName = I->getAsTemplate();
3145 clang::TemplateDecl* templateDecl = templateName.getAsTemplateDecl();
3146 if (templateDecl) {
3147 clang::DeclContext* declCtxt = templateDecl->getDeclContext();
3148
3149 if (declCtxt && !templateName.getAsQualifiedTemplateName()){
3150 clang::NamespaceDecl* ns = clang::dyn_cast<clang::NamespaceDecl>(declCtxt);
3151 clang::NestedNameSpecifier* nns;
3152 if (ns) {
3153 nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx, ns);
3154 } else if (clang::TagDecl* TD = llvm::dyn_cast<clang::TagDecl>(declCtxt)) {
3155 nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx,TD, false /*FullyQualified*/);
3156 } else {
3157 // TU scope
3158 desArgs.push_back(*I);
3159 continue;
3160 }
3161 clang::TemplateName UnderlyingTN(templateDecl);
3162 if (clang::UsingShadowDecl *USD = templateName.getAsUsingShadowDecl())
3163 UnderlyingTN = clang::TemplateName(USD);
3164 clang::TemplateName templateNameWithNSS ( Ctx.getQualifiedTemplateName(nns, false, UnderlyingTN) );
3165 desArgs.push_back(clang::TemplateArgument(templateNameWithNSS));
3166 mightHaveChanged = true;
3167 continue;
3168 }
3169 }
3170 }
3171
3172 if (I->getKind() != clang::TemplateArgument::Type) {
3173 desArgs.push_back(*I);
3174 continue;
3175 }
3176
3177 clang::QualType SubTy = I->getAsType();
3178
3179 // Check if the type needs more desugaring and recurse.
3180 // (Originally this was limited to elaborated and templated type,
3181 // but we also need to do it for pointer and reference type
3182 // and who knows what, so do it always)
3183 clang::QualType newSubTy = AddDefaultParameters(SubTy,
3185 normCtxt);
3186 if (SubTy != newSubTy) {
3187 mightHaveChanged = true;
3188 desArgs.push_back(clang::TemplateArgument(newSubTy));
3189 } else {
3190 desArgs.push_back(*I);
3191 }
3192 // Converted.push_back(TemplateArgument(ArgTypeForTemplate));
3193 } else if (!isStdDropDefault && Idecl < maxAddArg) {
3194
3195 mightHaveChanged = true;
3196
3197 const clang::TemplateArgument& templateArg
3198 = TSTdecl->getTemplateArgs().get(Idecl);
3199 if (templateArg.getKind() != clang::TemplateArgument::Type) {
3200 desArgs.push_back(templateArg);
3201 continue;
3202 }
3203 clang::QualType SubTy = templateArg.getAsType();
3204
3205 clang::SourceLocation TemplateLoc = Template->getSourceRange ().getBegin(); //NOTE: not sure that this is the 'right' location.
3206 clang::SourceLocation RAngleLoc = TSTdecl->getSourceRange().getBegin(); // NOTE: most likely wrong, I think this is expecting the location of right angle
3207
3208 clang::TemplateTypeParmDecl *TTP = llvm::dyn_cast<clang::TemplateTypeParmDecl>(*Param);
3209 {
3210 // We may induce template instantiation
3211 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
3212 bool HasDefaultArgs;
3213 clang::TemplateArgumentLoc ArgType = S.SubstDefaultTemplateArgumentIfAvailable(
3214 Template,
3216 RAngleLoc,
3217 TTP,
3218 desArgs,
3219 canonArgs,
3221 // The substition can fail, in which case there would have been compilation
3222 // error printed on the screen.
3223 if (ArgType.getArgument().isNull()
3224 || ArgType.getArgument().getKind() != clang::TemplateArgument::Type) {
3225 ROOT::TMetaUtils::Error("ROOT::TMetaUtils::AddDefaultParameters",
3226 "Template parameter substitution failed for %s around %s\n",
3227 instanceType.getAsString().c_str(), SubTy.getAsString().c_str());
3228 break;
3229 }
3230 clang::QualType BetterSubTy = ArgType.getArgument().getAsType();
3231 SubTy = cling::utils::Transform::GetPartiallyDesugaredType(Ctx,BetterSubTy,normCtxt.GetConfig(),/*fullyQualified=*/ true);
3232 }
3234 desArgs.push_back(clang::TemplateArgument(SubTy));
3235 } else {
3236 // We are past the end of the list of specified arguements and we
3237 // do not want to add the default, no need to continue.
3238 break;
3239 }
3240 }
3241
3242 // If we added default parameter, allocate new type in the AST.
3243 if (mightHaveChanged) {
3244 instanceType = Ctx.getTemplateSpecializationType(TST->getTemplateName(),
3245 desArgs,
3246 TST->getCanonicalTypeInternal());
3247 }
3248 }
3249
3251 if (prefix) {
3252 instanceType = Ctx.getElaboratedType(clang::ElaboratedTypeKeyword::None, prefix, instanceType);
3253 instanceType = Ctx.getQualifiedType(instanceType,prefix_qualifiers);
3254 }
3255 return instanceType;
3256}
3257
3258////////////////////////////////////////////////////////////////////////////////
3259/// ValidArrayIndex return a static string (so use it or copy it immediatly, do not
3260/// call GrabIndex twice in the same expression) containing the size of the
3261/// array data member.
3262/// In case of error, or if the size is not specified, GrabIndex returns 0.
3263/// If errnum is not null, *errnum updated with the error number:
3264/// Cint::G__DataMemberInfo::G__VALID : valid array index
3265/// Cint::G__DataMemberInfo::G__NOT_INT : array index is not an int
3266/// Cint::G__DataMemberInfo::G__NOT_DEF : index not defined before array
3267/// (this IS an error for streaming to disk)
3268/// Cint::G__DataMemberInfo::G__IS_PRIVATE: index exist in a parent class but is private
3269/// Cint::G__DataMemberInfo::G__UNKNOWN : index is not known
3270/// If errstr is not null, *errstr is updated with the address of a static
3271/// string containing the part of the index with is invalid.
3272
3273llvm::StringRef ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(const cling::Interpreter &interp, const clang::DeclaratorDecl &m, int *errnum, llvm::StringRef *errstr)
3274{
3275 llvm::StringRef title;
3276
3277 // Try to get the comment either from the annotation or the header file if present
3278 if (clang::AnnotateAttr *A = m.getAttr<clang::AnnotateAttr>())
3279 title = A->getAnnotation();
3280 else
3281 // Try to get the comment from the header file if present
3283
3284 // Let's see if the user provided us with some information
3285 // with the format: //[dimension] this is the dim of the array
3286 // dimension can be an arithmetical expression containing, literal integer,
3287 // the operator *,+ and - and data member of integral type. In addition the
3288 // data members used for the size of the array need to be defined prior to
3289 // the array.
3290
3291 if (errnum) *errnum = VALID;
3292
3293 if (title.size() == 0 || (title[0] != '[')) return llvm::StringRef();
3294 size_t rightbracket = title.find(']');
3295 if (rightbracket == llvm::StringRef::npos) return llvm::StringRef();
3296
3297 std::string working;
3298 llvm::StringRef indexvar(title.data()+1,rightbracket-1);
3299
3300 // now we should have indexvar=dimension
3301 // Let's see if this is legal.
3302 // which means a combination of data member and digit separated by '*','+','-'
3303 // First we remove white spaces.
3304 unsigned int i;
3305 size_t indexvarlen = indexvar.size();
3306 for ( i=0; i<indexvarlen; i++) {
3307 if (!isspace(indexvar[i])) {
3308 working += indexvar[i];
3309 }
3310 }
3311
3312 // Now we go through all indentifiers
3313 const char *tokenlist = "*+-";
3314 char *current = const_cast<char*>(working.c_str());
3315 current = strtok(current,tokenlist); // this method does not need to be reentrant
3316
3317 while (current) {
3318 // Check the token
3319 if (isdigit(current[0])) {
3320 for(i=0;i<strlen(current);i++) {
3321 if (!isdigit(current[i])) {
3322 // Error we only access integer.
3323 //NOTE: *** Need to print an error;
3324 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not an interger\n",
3325 // member.MemberOf()->Name(), member.Name(), current);
3326 if (errstr) *errstr = current;
3327 if (errnum) *errnum = NOT_INT;
3328 return llvm::StringRef();
3329 }
3330 }
3331 } else { // current token is not a digit
3332 // first let's see if it is a data member:
3333 const clang::CXXRecordDecl *parent_clxx = llvm::dyn_cast<clang::CXXRecordDecl>(m.getDeclContext());
3334 const clang::FieldDecl *index1 = nullptr;
3335 if (parent_clxx)
3337 if ( index1 ) {
3338 if ( IsFieldDeclInt(index1) ) {
3339 // Let's see if it has already been written down in the
3340 // Streamer.
3341 // Let's see if we already wrote it down in the
3342 // streamer.
3343 for(clang::RecordDecl::field_iterator field_iter = parent_clxx->field_begin(), end = parent_clxx->field_end();
3344 field_iter != end;
3345 ++field_iter)
3346 {
3347 if ( field_iter->getNameAsString() == m.getNameAsString() ) {
3348 // we reached the current data member before
3349 // reaching the index so we have not written it yet!
3350 //NOTE: *** Need to print an error;
3351 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) has not been defined before the array \n",
3352 // member.MemberOf()->Name(), member.Name(), current);
3353 if (errstr) *errstr = current;
3354 if (errnum) *errnum = NOT_DEF;
3355 return llvm::StringRef();
3356 }
3357 if ( field_iter->getNameAsString() == index1->getNameAsString() ) {
3358 break;
3359 }
3360 } // end of while (m_local.Next())
3361 } else {
3362 //NOTE: *** Need to print an error;
3363 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3364 // member.MemberOf()->Name(), member.Name(), current);
3365 if (errstr) *errstr = current;
3366 if (errnum) *errnum = NOT_INT;
3367 return llvm::StringRef();
3368 }
3369 } else {
3370 // There is no variable by this name in this class, let see
3371 // the base classes!:
3372 int found = 0;
3373 if (parent_clxx) {
3374 clang::Sema& SemaR = const_cast<cling::Interpreter&>(interp).getSema();
3376 }
3377 if ( index1 ) {
3378 if ( IsFieldDeclInt(index1) ) {
3379 found = 1;
3380 } else {
3381 // We found a data member but it is the wrong type
3382 //NOTE: *** Need to print an error;
3383 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3384 // member.MemberOf()->Name(), member.Name(), current);
3385 if (errnum) *errnum = NOT_INT;
3386 if (errstr) *errstr = current;
3387 //NOTE: *** Need to print an error;
3388 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3389 // member.MemberOf()->Name(), member.Name(), current);
3390 if (errnum) *errnum = NOT_INT;
3391 if (errstr) *errstr = current;
3392 return llvm::StringRef();
3393 }
3394 if ( found && (index1->getAccess() == clang::AS_private) ) {
3395 //NOTE: *** Need to print an error;
3396 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is a private member of %s \n",
3397 if (errstr) *errstr = current;
3398 if (errnum) *errnum = IS_PRIVATE;
3399 return llvm::StringRef();
3400 }
3401 }
3402 if (!found) {
3403 //NOTE: *** Need to print an error;
3404 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not known \n",
3405 // member.MemberOf()->Name(), member.Name(), indexvar);
3406 if (errstr) *errstr = indexvar;
3407 if (errnum) *errnum = UNKNOWN;
3408 return llvm::StringRef();
3409 } // end of if not found
3410 } // end of if is a data member of the class
3411 } // end of if isdigit
3412
3413 current = strtok(nullptr, tokenlist);
3414 } // end of while loop on tokens
3415
3416 return indexvar;
3417
3418}
3419
3420////////////////////////////////////////////////////////////////////////////////
3421/// Return (in the argument 'output') a valid name of the C++ symbol/type (pass as 'input')
3422/// that can be used in C++ as a variable name.
3423
3424void ROOT::TMetaUtils::GetCppName(std::string &out, const char *in)
3425{
3426 unsigned int i = 0;
3427 char c;
3428 out.clear();
3429 while((c = in[i++])) {
3430 const char *repl = nullptr;
3431 switch(c) {
3432 case '+': repl = "pL"; break;
3433 case '-': repl = "mI"; break;
3434 case '*': repl = "mU"; break;
3435 case '/': repl = "dI"; break;
3436 case '&': repl = "aN"; break;
3437 case '%': repl = "pE"; break;
3438 case '|': repl = "oR"; break;
3439 case '^': repl = "hA"; break;
3440 case '>': repl = "gR"; break;
3441 case '<': repl = "lE"; break;
3442 case '=': repl = "eQ"; break;
3443 case '~': repl = "wA"; break;
3444 case '.': repl = "dO"; break;
3445 case '(': repl = "oP"; break;
3446 case ')': repl = "cP"; break;
3447 case '[': repl = "oB"; break;
3448 case ']': repl = "cB"; break;
3449 case '{': repl = "lB"; break;
3450 case '}': repl = "rB"; break;
3451 case ';': repl = "sC"; break;
3452 case '#': repl = "hS"; break;
3453 case '?': repl = "qM"; break;
3454 case '`': repl = "bT"; break;
3455 case '!': repl = "nO"; break;
3456 case ',': repl = "cO"; break;
3457 case '$': repl = "dA"; break;
3458 case ' ': repl = "sP"; break;
3459 case ':': repl = "cL"; break;
3460 case '"': repl = "dQ"; break;
3461 case '@': repl = "aT"; break;
3462 case '\'': repl = "sQ"; break;
3463 case '\\': repl = "fI"; break;
3464 }
3465 if (repl)
3466 out.append(repl);
3467 else
3468 out.push_back(c);
3469 }
3470
3471 // If out is empty, or if it starts with a number, it's not a valid C++ variable. Prepend a "_"
3472 if (out.empty() || isdigit(out[0]))
3473 out.insert(out.begin(), '_');
3474}
3475
3476static clang::SourceLocation
3478 clang::SourceLocation sourceLoc) {
3479 // Follow macro expansion until we hit a source file.
3480 if (!sourceLoc.isFileID()) {
3481 return sourceManager.getExpansionRange(sourceLoc).getEnd();
3482 }
3483 return sourceLoc;
3484}
3485
3486////////////////////////////////////////////////////////////////////////////////
3487/// Return the header file to be included to declare the Decl.
3488
3489std::string ROOT::TMetaUtils::GetFileName(const clang::Decl& decl,
3490 const cling::Interpreter& interp)
3491{
3492 // It looks like the template specialization decl actually contains _less_ information
3493 // on the location of the code than the decl (in case where there is forward declaration,
3494 // that is what the specialization points to).
3495 //
3496 // const clang::CXXRecordDecl* clxx = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
3497 // if (clxx) {
3498 // switch(clxx->getTemplateSpecializationKind()) {
3499 // case clang::TSK_Undeclared:
3500 // // We want the default behavior
3501 // break;
3502 // case clang::TSK_ExplicitInstantiationDeclaration:
3503 // case clang::TSK_ExplicitInstantiationDefinition:
3504 // case clang::TSK_ImplicitInstantiation: {
3505 // // We want the location of the template declaration:
3506 // const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
3507 // if (tmplt_specialization) {
3508 // // return GetFileName(const_cast< clang::ClassTemplateSpecializationDecl *>(tmplt_specialization)->getSpecializedTemplate());
3509 // }
3510 // break;
3511 // }
3512 // case clang::TSK_ExplicitSpecialization:
3513 // // We want the default behavior
3514 // break;
3515 // default:
3516 // break;
3517 // }
3518 // }
3519
3520 using namespace clang;
3521 SourceLocation headerLoc = decl.getLocation();
3522
3523 static const char invalidFilename[] = "";
3524 if (!headerLoc.isValid()) return invalidFilename;
3525
3526 HeaderSearch& HdrSearch = interp.getCI()->getPreprocessor().getHeaderSearchInfo();
3527
3528 SourceManager& sourceManager = decl.getASTContext().getSourceManager();
3533 sourceManager.getIncludeLoc(headerFID));
3534
3535 OptionalFileEntryRef headerFE = sourceManager.getFileEntryRefForID(headerFID);
3536 while (includeLoc.isValid() && sourceManager.isInSystemHeader(includeLoc)) {
3538 // use HeaderSearch on the basename, to make sure it takes a header from
3539 // the include path (e.g. not from /usr/include/bits/)
3540 assert(headerFE && "Couldn't find FileEntry from FID!");
3541 auto FEhdr
3542 = HdrSearch.LookupFile(llvm::sys::path::filename(headerFE->getName()),
3544 true /*isAngled*/, nullptr/*FromDir*/, foundDir,
3545 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>>(),
3546 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3547 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3548 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/,
3549 false /*SkipCache*/,
3550 false /*BuildSystemModule*/,
3551 false /*OpenFile*/, true /*CacheFailures*/);
3552 if (FEhdr) break;
3553 headerFID = sourceManager.getFileID(includeLoc);
3554 headerFE = sourceManager.getFileEntryRefForID(headerFID);
3555 // If we have a system header in a module we can't just trace back the
3556 // original include with the preprocessor. But it should be enough if
3557 // we trace it back to the top-level system header that includes this
3558 // declaration.
3559 if (interp.getCI()->getLangOpts().Modules && !headerFE) {
3560 assert(decl.isFirstDecl() && "Couldn't trace back include from a decl"
3561 " that is not from an AST file");
3562 assert(StringRef(includeLoc.printToString(sourceManager)).starts_with("<module-includes>"));
3563 break;
3564 }
3566 sourceManager.getIncludeLoc(headerFID));
3567 }
3568
3569 if (!headerFE) return invalidFilename;
3570
3571 llvm::SmallString<256> headerFileName(headerFE->getName());
3572 // Remove double ../ from the path so that the search below finds a valid
3573 // longest match and does not result in growing paths.
3574 llvm::sys::path::remove_dots(headerFileName, /*remove_dot_dot=*/true);
3575
3576 // Now headerFID references the last valid system header or the original
3577 // user file.
3578 // Find out how to include it by matching file name to include paths.
3579 // We assume that the file "/A/B/C/D.h" can at some level be included as
3580 // "C/D.h". Be we cannot know whether that happens to be a different file
3581 // with the same name. Thus we first find the longest stem that can be
3582 // reached, say B/C/D.h. Then we find the shortest one, say C/D.h, that
3583 // points to the same file as the long version. If such a short version
3584 // exists it will be returned. If it doesn't the long version is returned.
3585 bool isAbsolute = llvm::sys::path::is_absolute(headerFileName);
3586 clang::OptionalFileEntryRef FELong;
3587 // Find the longest available match.
3588 for (llvm::sys::path::const_iterator
3589 IDir = llvm::sys::path::begin(headerFileName),
3590 EDir = llvm::sys::path::end(headerFileName);
3591 !FELong && IDir != EDir; ++IDir) {
3592 if (isAbsolute) {
3593 // skip "/" part
3594 isAbsolute = false;
3595 continue;
3596 }
3597 size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3598 llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3599 assert(trailingPart.data() + trailingPart.size()
3600 == headerFileName.data() + headerFileName.size()
3601 && "Mismatched partitioning of file name!");
3604 true /*isAngled*/, nullptr/*FromDir*/, FoundDir,
3605 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>>(),
3606 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3607 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3608 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/);
3609 }
3610
3611 if (!FELong) {
3612 // We did not find any file part in any search path.
3613 return invalidFilename;
3614 }
3615
3616 // Iterates through path *parts* "C"; we need trailing parts "C/D.h"
3617 for (llvm::sys::path::reverse_iterator
3618 IDir = llvm::sys::path::rbegin(headerFileName),
3619 EDir = llvm::sys::path::rend(headerFileName);
3620 IDir != EDir; ++IDir) {
3621 size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3622 llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3623 assert(trailingPart.data() + trailingPart.size()
3624 == headerFileName.data() + headerFileName.size()
3625 && "Mismatched partitioning of file name!");
3627 // Can we find it, and is it the same file as the long version?
3628 // (or are we back to the previously found spelling, which is fine, too)
3629 if (HdrSearch.LookupFile(trailingPart, SourceLocation(),
3630 true /*isAngled*/, nullptr/*FromDir*/, FoundDir,
3631 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>>(),
3632 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3633 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3634 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/) == FELong) {
3635 return trailingPart.str();
3636 }
3637 }
3638
3639 return invalidFilename;
3640}
3641
3642////////////////////////////////////////////////////////////////////////////////
3643
3645 const clang::QualType &qtype,
3646 const clang::ASTContext &astContext)
3647{
3648 std::string fqname = cling::utils::TypeName::GetFullyQualifiedName(qtype, astContext);
3652}
3653
3654////////////////////////////////////////////////////////////////////////////////
3655
3657 const clang::QualType &qtype,
3658 const cling::Interpreter &interpreter)
3659{
3660 // We need this because GetFullyQualifiedTypeName is triggering deserialization
3661 // This calling the same name function GetFullyQualifiedTypeName, but this should stay here because
3662 // callee doesn't have an interpreter pointer
3663 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
3664
3666 qtype,
3667 interpreter.getCI()->getASTContext());
3668}
3669
3670////////////////////////////////////////////////////////////////////////////////
3671/// Get the template specialisation decl and template decl behind the qualtype
3672/// Returns true if successfully found, false otherwise
3673
3674bool ROOT::TMetaUtils::QualType2Template(const clang::QualType& qt,
3675 clang::ClassTemplateDecl*& ctd,
3676 clang::ClassTemplateSpecializationDecl*& ctsd)
3677{
3678 using namespace clang;
3679 const Type* theType = qt.getTypePtr();
3680 if (!theType){
3681 ctd=nullptr;
3682 ctsd=nullptr;
3683 return false;
3684 }
3685
3686 if (theType->isPointerType()) {
3687 return QualType2Template(theType->getPointeeType(), ctd, ctsd);
3688 }
3689
3690 if (const RecordType* rType = llvm::dyn_cast<RecordType>(theType)) {
3691 ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(rType->getDecl());
3692 if (ctsd) {
3693 ctd = ctsd->getSpecializedTemplate();
3694 return true;
3695 }
3696 }
3697
3698 if (const SubstTemplateTypeParmType* sttpType = llvm::dyn_cast<SubstTemplateTypeParmType>(theType)){
3699 return QualType2Template(sttpType->getReplacementType(), ctd, ctsd);
3700 }
3701
3702
3703 ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(qt->getAsCXXRecordDecl());
3704 if(ctsd){
3705 ctd = ctsd->getSpecializedTemplate();
3706 return true;
3707 }
3708
3709 ctd=nullptr;
3710 ctsd=nullptr;
3711 return false;
3712}
3713
3714////////////////////////////////////////////////////////////////////////////////
3715/// Extract from a qualtype the class template if this makes sense.
3716/// Retuns the ClassTemplateDecl or nullptr otherwise.
3717
3718clang::ClassTemplateDecl* ROOT::TMetaUtils::QualType2ClassTemplateDecl(const clang::QualType& qt)
3719{
3720 using namespace clang;
3724 return ctd;
3725}
3726
3727////////////////////////////////////////////////////////////////////////////////
3728/// These manipulations are necessary because a template specialisation type
3729/// does not inherit from a record type (there is an asymmetry between
3730/// the decls and the types in the clang interface).
3731/// We may need therefore to step into the "Decl dimension" to then get back
3732/// to the "type dimension".
3733
3734clang::TemplateName ROOT::TMetaUtils::ExtractTemplateNameFromQualType(const clang::QualType& qt)
3735{
3736 using namespace clang;
3738
3739 const Type* theType = qt.getTypePtr();
3740
3741 if (const TemplateSpecializationType* tst = llvm::dyn_cast_or_null<const TemplateSpecializationType>(theType)) {
3742 theTemplateName = tst->getTemplateName();
3743 } // We step into the decl dimension
3746 }
3747
3748 return theTemplateName;
3749}
3750
3751////////////////////////////////////////////////////////////////////////////////
3752
3753static bool areEqualTypes(const clang::TemplateArgument& tArg,
3754 llvm::SmallVectorImpl<clang::TemplateArgument>& preceedingTArgs,
3755 const clang::NamedDecl& tPar,
3756 const cling::Interpreter& interp,
3758{
3759 using namespace ROOT::TMetaUtils;
3760 using namespace clang;
3761
3762 // Check if this is a type for security
3763 TemplateTypeParmDecl* ttpdPtr = const_cast<TemplateTypeParmDecl*>(llvm::dyn_cast<TemplateTypeParmDecl>(&tPar));
3764 if (!ttpdPtr) return false;
3765 if (!ttpdPtr->hasDefaultArgument()) return false; // we should not be here in this case, but we protect us.
3766
3767 // Try the fast solution
3768 QualType tParQualType = ttpdPtr->getDefaultArgument().getArgument().getAsType();
3769 const QualType tArgQualType = tArg.getAsType();
3770
3771 // Now the equality tests for non template specialisations.
3772
3773 // The easy cases:
3774 // template <class T=double> class A; or
3775 // template <class T=A<float>> class B;
3776 if (tParQualType.getTypePtr() == tArgQualType.getTypePtr()) return true;
3777
3778 // Here the difficulty comes. We have to check if the argument is equal to its
3779 // default. We can do that bootstrapping an argument which has the default value
3780 // based on the preceeding arguments.
3781 // Basically we ask sema to give us the value of the argument given the template
3782 // of behind the parameter and the all the arguments.
3783 // So:
3784
3785 // Take the template out of the parameter
3786
3787 const clang::ElaboratedType* etype
3788 = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3789 while (etype) {
3790 tParQualType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3791 etype = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3792 }
3793
3795 llvm::dyn_cast<TemplateSpecializationType>(tParQualType.getTypePtr());
3796
3797 if(!tst) // nothing more to be tried. They are different indeed.
3798 return false;
3799
3801 = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(tArgQualType->getAsCXXRecordDecl());
3802
3803 if(!TSTdecl) // nothing more to be tried. They are different indeed.
3804 return false;
3805
3806 TemplateDecl *Template = tst->getTemplateName().getAsTemplateDecl();
3807
3808 // Take the template location
3809 SourceLocation TemplateLoc = Template->getSourceRange ().getBegin();
3810
3811 // Get the position of the "<" (LA) of the specializaion
3812 SourceLocation LAngleLoc = TSTdecl->getSourceRange().getBegin();
3813
3814
3815 // Enclose in a scope for the RAII
3816 bool isEqual=false;
3818 {
3819 clang::Sema& S = interp.getCI()->getSema();
3820 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interp));
3821 llvm::SmallVector<clang::TemplateArgument, 4> canonArgs;
3822 bool HasDefaultArgs;
3823 TemplateArgumentLoc defTArgLoc = S.SubstDefaultTemplateArgumentIfAvailable(Template,
3825 LAngleLoc,
3826 ttpdPtr,
3828 canonArgs,
3830 // The substition can fail, in which case there would have been compilation
3831 // error printed on the screen.
3832 newArg = defTArgLoc.getArgument();
3833 if (newArg.isNull() ||
3834 newArg.getKind() != clang::TemplateArgument::Type) {
3835 ROOT::TMetaUtils::Error("areEqualTypes",
3836 "Template parameter substitution failed!");
3837 }
3838
3840 = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(newArg.getAsType()->getAsCXXRecordDecl());
3841// std::cout << "nSTdecl is " << nTSTdecl << std::endl;
3842
3843 isEqual = (nTSTdecl && nTSTdecl->getMostRecentDecl() == TSTdecl->getMostRecentDecl()) ||
3844 (tParQualType.getTypePtr() == newArg.getAsType().getTypePtr());
3845 }
3846
3847
3848 return isEqual;
3849}
3850
3851
3852////////////////////////////////////////////////////////////////////////////////
3853/// std::cout << "Are equal values?\n";
3854
3855static bool areEqualValues(const clang::TemplateArgument& tArg,
3856 const clang::NamedDecl& tPar)
3857{
3858 using namespace clang;
3859 const NonTypeTemplateParmDecl* nttpdPtr = llvm::dyn_cast<NonTypeTemplateParmDecl>(&tPar);
3860 if (!nttpdPtr) return false;
3862
3863 if (!nttpd.hasDefaultArgument())
3864 return false;
3865
3866 // 64 bits wide and signed (non unsigned, that is why "false")
3867 llvm::APSInt defaultValueAPSInt(64, false);
3868 if (Expr* defArgExpr = nttpd.getDefaultArgument().getArgument().getAsExpr()) {
3869 const ASTContext& astCtxt = nttpdPtr->getASTContext();
3870 if (auto Value = defArgExpr->getIntegerConstantExpr(astCtxt))
3872 }
3873
3874 const int value = tArg.getAsIntegral().getLimitedValue();
3875
3876 // std::cout << (value == defaultValueAPSInt ? "yes!":"no") << std::endl;
3877 return value == defaultValueAPSInt;
3878}
3879
3880////////////////////////////////////////////////////////////////////////////////
3881/// Check if this NamedDecl is a template parameter with a default argument.
3882/// This is a single interface to treat both integral and type parameters.
3883/// Returns true if this is the case, false otherwise
3884
3885static bool isTypeWithDefault(const clang::NamedDecl* nDecl)
3886{
3887 using namespace clang;
3888 if (!nDecl) return false;
3889 if (const TemplateTypeParmDecl* ttpd = llvm::dyn_cast<TemplateTypeParmDecl>(nDecl))
3890 return ttpd->hasDefaultArgument();
3891 if (const NonTypeTemplateParmDecl* nttpd = llvm::dyn_cast<NonTypeTemplateParmDecl>(nDecl))
3892 return nttpd->hasDefaultArgument();
3893 return false;
3894
3895}
3896
3897static void KeepNParams(clang::QualType& normalizedType,
3898 const clang::QualType& vanillaType,
3899 const cling::Interpreter& interp,
3901
3902// Returns true if normTArg might have changed.
3903static bool RecurseKeepNParams(clang::TemplateArgument &normTArg,
3904 const clang::TemplateArgument &tArg,
3905 const cling::Interpreter& interp,
3907 const clang::ASTContext& astCtxt)
3908{
3909 using namespace ROOT::TMetaUtils;
3910 using namespace clang;
3911
3912 // Once we know there is no more default parameter, we can run through to the end
3913 // and/or recurse in the template parameter packs.
3914
3915 // If this is a type,
3916 // we need first of all to recurse: this argument may need to be manipulated
3917 if (tArg.getKind() == clang::TemplateArgument::Type) {
3918 QualType thisNormQualType = normTArg.getAsType();
3919 QualType thisArgQualType = tArg.getAsType();
3922 interp,
3923 normCtxt);
3926 } else if (normTArg.getKind() == clang::TemplateArgument::Pack) {
3927 assert( tArg.getKind() == clang::TemplateArgument::Pack );
3928
3930 bool mightHaveChanged = true;
3931 for (auto I = normTArg.pack_begin(), E = normTArg.pack_end(),
3932 FI = tArg.pack_begin(), FE = tArg.pack_end();
3933 I != E && FI != FE; ++I, ++FI)
3934 {
3937 desArgs.push_back(pack_arg);
3938 }
3939 if (mightHaveChanged) {
3940 ASTContext &mutableCtx( const_cast<ASTContext&>(astCtxt) );
3941 normTArg = TemplateArgument::CreatePackCopy(mutableCtx, desArgs);
3942 }
3943 return mightHaveChanged;
3944 }
3945 return false;
3946}
3947
3948
3949////////////////////////////////////////////////////////////////////////////////
3950/// This function allows to manipulate the number of arguments in the type
3951/// of a template specialisation.
3952
3953static void KeepNParams(clang::QualType& normalizedType,
3954 const clang::QualType& vanillaType,
3955 const cling::Interpreter& interp,
3957{
3958 using namespace ROOT::TMetaUtils;
3959 using namespace clang;
3960
3961 // If this type has no template specialisation behind, we don't need to do
3962 // anything
3965 if (! QualType2Template(vanillaType, ctd, ctsd)) return ;
3966
3967 // Even if this is a template, if we don't keep any argument, return
3968 const int nArgsToKeep = normCtxt.GetNargsToKeep(ctd);
3969
3970 // Important in case of early return: we must restore the original qualtype
3972
3973 const ASTContext& astCtxt = ctsd->getASTContext();
3974
3975
3976 // In case of name* we need to strip the pointer first, add the default and attach
3977 // the pointer once again.
3978 if (llvm::isa<clang::PointerType>(normalizedType.getTypePtr())) {
3979 // Get the qualifiers.
3980 clang::Qualifiers quals = normalizedType.getQualifiers();
3981 auto valNormalizedType = normalizedType->getPointeeType();
3983 normalizedType = astCtxt.getPointerType(valNormalizedType);
3984 // Add back the qualifiers.
3985 normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
3986 return;
3987 }
3988
3989 // In case of Int_t& we need to strip the pointer first, desugar and attach
3990 // the pointer once again.
3991 if (llvm::isa<clang::ReferenceType>(normalizedType.getTypePtr())) {
3992 // Get the qualifiers.
3993 bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(normalizedType.getTypePtr());
3994 clang::Qualifiers quals = normalizedType.getQualifiers();
3995 auto valNormType = normalizedType->getPointeeType();
3997
3998 // Add the r- or l- value reference type back to the desugared one
3999 if (isLValueRefTy)
4000 normalizedType = astCtxt.getLValueReferenceType(valNormType);
4001 else
4002 normalizedType = astCtxt.getRValueReferenceType(valNormType);
4003 // Add back the qualifiers.
4004 normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
4005 return;
4006 }
4007
4008 // Treat the Scope (factorise the code out to reuse it in AddDefaultParameters)
4009 bool prefix_changed = false;
4010 clang::NestedNameSpecifier* prefix = nullptr;
4011 clang::Qualifiers prefix_qualifiers = normalizedType.getLocalQualifiers();
4012 const clang::ElaboratedType* etype
4013 = llvm::dyn_cast<clang::ElaboratedType>(normalizedType.getTypePtr());
4014 if (etype) {
4015 // We have to also handle the prefix.
4016 // TODO: we ought to be running KeepNParams
4017 prefix = AddDefaultParametersNNS(astCtxt, etype->getQualifier(), interp, normCtxt);
4018 prefix_changed = prefix != etype->getQualifier();
4019 normalizedType = clang::QualType(etype->getNamedType().getTypePtr(),0);
4020 }
4021
4022 // The canonical decl does not necessarily have the template default arguments.
4023 // Need to walk through the redecl chain to find it (we know there will be no
4024 // inconsistencies, at least)
4025 const clang::ClassTemplateDecl* ctdWithDefaultArgs = ctd;
4026 for (const RedeclarableTemplateDecl* rd: ctdWithDefaultArgs->redecls()) {
4027 clang::TemplateParameterList* tpl = rd->getTemplateParameters();
4028 if (tpl->getMinRequiredArguments () < tpl->size()) {
4029 ctdWithDefaultArgs = llvm::dyn_cast<clang::ClassTemplateDecl>(rd);
4030 break;
4031 }
4032 }
4033
4034 if (!ctdWithDefaultArgs) {
4035 Error("KeepNParams", "Not found template default arguments\n");
4037 return;
4038 }
4039
4040 TemplateParameterList* tParsPtr = ctdWithDefaultArgs->getTemplateParameters();
4042 const TemplateArgumentList& tArgs = ctsd->getTemplateArgs();
4043
4044 // We extract the template name from the type
4045 TemplateName theTemplateName = ExtractTemplateNameFromQualType(normalizedType);
4046 if (theTemplateName.isNull()) {
4048 return;
4049 }
4050
4052 llvm::dyn_cast<TemplateSpecializationType>(normalizedType.getTypePtr());
4053 if (!normalizedTst) {
4055 return;
4056 }
4057
4058 const clang::ClassTemplateSpecializationDecl* TSTdecl
4059 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(normalizedType.getTypePtr()->getAsCXXRecordDecl());
4060 bool isStdDropDefault = TSTdecl && IsStdDropDefaultClass(*TSTdecl);
4061
4062 // Loop over the template parameters and arguments recursively.
4063 // We go down the two lanes: the one of template parameters (decls) and the
4064 // one of template arguments (QualTypes) in parallel. The former are a
4065 // property of the template, independent of its instantiations.
4066 // The latter are a property of the instance itself.
4067 llvm::SmallVector<TemplateArgument, 4> argsToKeep;
4068
4069 const int nArgs = tArgs.size();
4070 const auto &normArgs = normalizedTst->template_arguments();
4071 const int nNormArgs = normArgs.size();
4072
4073 bool mightHaveChanged = false;
4074 int latestNonDefaultArg = -1;
4075
4076 // becomes true when a parameter has a value equal to its default
4077 for (int formal = 0, inst = 0; formal != nArgs; ++formal, ++inst) {
4078 const NamedDecl* tParPtr = tPars.getParam(formal);
4079 if (!tParPtr) {
4080 Error("KeepNParams", "The parameter number %s is null.\n", formal);
4081 continue;
4082 }
4083
4084 // Stop if the normalized TemplateSpecializationType has less arguments than
4085 // the one index is pointing at.
4086 // We piggy back on the AddDefaultParameters routine basically.
4087 if (formal == nNormArgs || inst == nNormArgs) break;
4088
4089 const TemplateArgument& tArg = tArgs.get(formal);
4091
4092 bool shouldKeepArg = nArgsToKeep < 0 || inst < nArgsToKeep;
4093 if (isStdDropDefault) shouldKeepArg = false;
4094
4095 // Nothing to do here: either this parameter has no default, or we have to keep it.
4096 // FIXME: Temporary measure to get Atlas started with this.
4097 // We put a hard cut on the number of template arguments to keep, w/o checking if
4098 // they are non default. This makes this feature UNUSABLE for cases like std::vector,
4099 // where 2 different entities would have the same name if an allocator different from
4100 // the default one is by chance used.
4102 if ( tParPtr->isTemplateParameterPack() ) {
4103 // This is the last template parameter in the template declaration
4104 // but it is signaling that there can be an arbitrary number of arguments
4105 // in the template instance. So to avoid inadvertenly dropping those
4106 // arguments we just process all remaining argument and exit the main loop.
4107 for( ; inst != nNormArgs; ++inst) {
4110 argsToKeep.push_back(normTArg);
4111 }
4112 // Done.
4114 break;
4115 }
4117 argsToKeep.push_back(normTArg);
4119 continue;
4120 } else {
4121 if (!isStdDropDefault) {
4122 // Here we should not break but rather check if the value is the default one.
4123 mightHaveChanged = true;
4124 break;
4125 }
4126 // For std, we want to check the default args values.
4127 }
4128
4129 // Now, we keep it only if it not is equal to its default, expressed in the arg
4130 // Some gymnastic is needed to decide how to check for equality according to the
4131 // flavour of Type: templateType or Integer
4132 bool equal=false;
4133 auto argKind = tArg.getKind();
4134 if (argKind == clang::TemplateArgument::Type){
4135 // we need all the info
4137 } else if (argKind == clang::TemplateArgument::Integral){
4138 equal = areEqualValues(tArg, *tParPtr);
4139 }
4140
4141 argsToKeep.push_back(normTArg);
4142 if (!equal) {
4145 } else {
4146 mightHaveChanged = true;
4147 }
4148
4149
4150 } // of loop over parameters and arguments
4151
4152 if (latestNonDefaultArg >= 0)
4153 argsToKeep.resize(latestNonDefaultArg + 1);
4154
4157 return;
4158 }
4159
4160 // now, let's remanipulate our Qualtype
4161 if (mightHaveChanged) {
4162 Qualifiers qualifiers = normalizedType.getLocalQualifiers();
4163 normalizedType = astCtxt.getTemplateSpecializationType(theTemplateName,
4164 argsToKeep,
4165 normalizedType.getTypePtr()->getCanonicalTypeInternal());
4166 normalizedType = astCtxt.getQualifiedType(normalizedType, qualifiers);
4167 }
4168
4169 // Here we have (prefix_changed==true || mightHaveChanged), in both case
4170 // we need to reconstruct the type.
4171 if (prefix) {
4172 normalizedType = astCtxt.getElaboratedType(clang::ElaboratedTypeKeyword::None, prefix, normalizedType);
4174 }
4175}
4176
4177////////////////////////////////////////////////////////////////////////////////
4178/// Return the type normalized for ROOT,
4179/// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4180/// adding default template argument for all types except those explicitly
4181/// requested to be drop by the user.
4182/// Default template for STL collections are not yet removed by this routine.
4183
4184clang::QualType ROOT::TMetaUtils::GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4185{
4186 clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4187
4188 // Modules can trigger deserialization.
4189 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
4190 clang::QualType normalizedType = cling::utils::Transform::GetPartiallyDesugaredType(ctxt, type, normCtxt.GetConfig(), true /* fully qualify */);
4191
4192 // Readd missing default template parameters
4194
4195 // Get the number of arguments to keep in case they are not default.
4197
4198 return normalizedType;
4199}
4200
4201////////////////////////////////////////////////////////////////////////////////
4202/// Return the type name normalized for ROOT,
4203/// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4204/// adding default template argument for all types except the STL collections
4205/// where we remove the default template argument if any.
4206///
4207/// This routine might actually belong in the interpreter because
4208/// cache the clang::Type might be intepreter specific.
4209
4210void ROOT::TMetaUtils::GetNormalizedName(std::string &norm_name, const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4211{
4212 if (type.isNull()) {
4213 norm_name = "";
4214 return;
4215 }
4216
4218
4219 clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4220 clang::PrintingPolicy policy(ctxt.getPrintingPolicy());
4221 policy.SuppressTagKeyword = true; // Never get the class or struct keyword
4222 policy.AnonymousTagLocations = false; // Do not extract file name + line number for anonymous types.
4223 // The scope suppression is required for getting rid of the anonymous part of the name of a class defined in an
4224 // anonymous namespace. In LLVM22 (and before), SuppressUnwrittenScope suppresses anonymous namespaces. Inline
4225 // namespace suppression is separately controlled by SuppressInlineNamespace, which we probably don't want to be
4226 // suppressed.
4227 policy.SuppressUnwrittenScope = true; // Strip anonymous namespace names
4228
4229 std::string normalizedNameStep1;
4230
4231 // getAsStringInternal can trigger deserialization
4232 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
4233 normalizedType.getAsStringInternal(normalizedNameStep1,policy);
4234
4235 // Remove the _Atomic type specifyier if present before normalising
4238
4239 // Still remove the std:: and default template argument for STL container and
4240 // normalize the location and amount of white spaces.
4243
4247
4248 // The result of this routine is by definition a fully qualified name. There is an implicit starting '::' at the beginning of the name.
4249 // Depending on how the user typed their code, in particular typedef declarations, we may end up with an explicit '::' being
4250 // part of the result string. For consistency, we must remove it.
4251 if (norm_name.length()>2 && norm_name[0]==':' && norm_name[1]==':') {
4252 norm_name.erase(0,2);
4253 }
4254
4255}
4256
4257////////////////////////////////////////////////////////////////////////////////
4258
4260 const clang::TypeDecl* typeDecl,
4261 const cling::Interpreter &interpreter)
4262{
4264 const clang::Sema &sema = interpreter.getSema();
4265 clang::ASTContext& astCtxt = sema.getASTContext();
4266 clang::QualType qualType = astCtxt.getTypeDeclType(typeDecl);
4267
4269 qualType,
4271 tNormCtxt);
4272}
4273
4274////////////////////////////////////////////////////////////////////////////////
4275std::pair<std::string,clang::QualType>
4277 const cling::Interpreter &interpreter,
4280{
4281 std::string thisTypeName;
4282 GetNormalizedName(thisTypeName, thisType, interpreter, normCtxt );
4283 bool hasChanged;
4285 if (!hasChanged) return std::make_pair(thisTypeName,thisType);
4286
4288 ROOT::TMetaUtils::Info("ROOT::TMetaUtils::GetTypeForIO",
4289 "Name changed from %s to %s\n", thisTypeName.c_str(), thisTypeNameForIO.c_str());
4290 }
4291
4292 auto& lookupHelper = interpreter.getLookupHelper();
4293
4294 const clang::Type* typePtrForIO;
4296 cling::LookupHelper::DiagSetting::NoDiagnostics,
4297 &typePtrForIO);
4298
4299 // This should never happen
4300 if (!typePtrForIO) {
4301 ROOT::TMetaUtils::Fatal("ROOT::TMetaUtils::GetTypeForIO",
4302 "Type not found: %s.",thisTypeNameForIO.c_str());
4303 }
4304
4305 clang::QualType typeForIO(typePtrForIO,0);
4306
4307 // Check if this is a class. Indeed it could well be a POD
4308 if (!typeForIO->isRecordType()) {
4309 return std::make_pair(thisTypeNameForIO,typeForIO);
4310 }
4311
4312 auto thisDeclForIO = typeForIO->getAsCXXRecordDecl();
4313 if (!thisDeclForIO) {
4314 ROOT::TMetaUtils::Error("ROOT::TMetaUtils::GetTypeForIO",
4315 "The type for IO corresponding to %s is %s and it could not be found in the AST as class.\n", thisTypeName.c_str(), thisTypeNameForIO.c_str());
4316 return std::make_pair(thisTypeName,thisType);
4317 }
4318
4319 return std::make_pair(thisTypeNameForIO,typeForIO);
4320}
4321
4322////////////////////////////////////////////////////////////////////////////////
4323
4324clang::QualType ROOT::TMetaUtils::GetTypeForIO(const clang::QualType& thisType,
4325 const cling::Interpreter &interpreter,
4328{
4330}
4331
4332////////////////////////////////////////////////////////////////////////////////
4333/// Return the dictionary file name for a module
4334
4336{
4337 std::string dictFileName(moduleName);
4338 dictFileName += "_rdict.pcm";
4339 return dictFileName;
4340}
4341
4342int dumpDeclForAssert(const clang::Decl& D, const char* commentStart) {
4343 llvm::errs() << llvm::StringRef(commentStart, 80) << '\n';
4344 D.dump();
4345 return 0;
4346}
4347
4348////////////////////////////////////////////////////////////////////////////////
4349/// Returns the comment (// striped away), annotating declaration in a meaningful
4350/// for ROOT IO way.
4351/// Takes optional out parameter clang::SourceLocation returning the source
4352/// location of the comment.
4353///
4354/// CXXMethodDecls, FieldDecls and TagDecls are annotated.
4355/// CXXMethodDecls declarations and FieldDecls are annotated as follows:
4356/// Eg. void f(); // comment1
4357/// int member; // comment2
4358/// Inline definitions of CXXMethodDecls after the closing } \n. Eg:
4359/// void f()
4360/// {...} // comment3
4361/// TagDecls are annotated in the end of the ClassDef macro. Eg.
4362/// class MyClass {
4363/// ...
4364/// ClassDef(MyClass, 1) // comment4
4365///
4366
4367llvm::StringRef ROOT::TMetaUtils::GetComment(const clang::Decl &decl, clang::SourceLocation *loc)
4368{
4369 clang::SourceManager& sourceManager = decl.getASTContext().getSourceManager();
4370 clang::SourceLocation sourceLocation = decl.getEndLoc();
4371
4372 // If the location is a macro get the expansion location.
4373 sourceLocation = sourceManager.getExpansionRange(sourceLocation).getEnd();
4374 // FIXME: We should optimize this routine instead making it do the wrong thing
4375 // returning an empty comment if the decl came from the AST.
4376 // In order to do that we need to: check if the decl has an attribute and
4377 // return the attribute content (including walking the redecl chain) and if
4378 // this is not the case we should try finding it in the header file.
4379 // This will allow us to move the implementation of TCling*Info::Title() in
4380 // TClingDeclInfo.
4381 if (!decl.hasOwningModule() && sourceManager.isLoadedSourceLocation(sourceLocation)) {
4382 // Do not touch disk for nodes coming from the PCH.
4383 return "";
4384 }
4385
4386 bool invalid;
4387 const char *commentStart = sourceManager.getCharacterData(sourceLocation, &invalid);
4388 if (invalid)
4389 return "";
4390
4391 bool skipToSemi = true;
4392 if (const clang::FunctionDecl* FD = clang::dyn_cast<clang::FunctionDecl>(&decl)) {
4393 if (FD->isImplicit()) {
4394 // Compiler generated function.
4395 return "";
4396 }
4397 if (FD->isExplicitlyDefaulted() || FD->isDeletedAsWritten()) {
4398 // ctorOrFunc() = xyz; with commentStart pointing somewhere into
4399 // ctorOrFunc.
4400 // We have to skipToSemi
4401 } else if (FD->doesThisDeclarationHaveABody()) {
4402 // commentStart is at body's '}'
4403 // But we might end up e.g. at the ')' of a CPP macro
4404 assert((decl.getEndLoc() != sourceLocation || *commentStart == '}'
4406 && "Expected macro or end of body at '}'");
4407 if (*commentStart) ++commentStart;
4408
4409 // We might still have a ';'; skip the spaces and check.
4410 while (*commentStart && isspace(*commentStart)
4411 && *commentStart != '\n' && *commentStart != '\r') {
4412 ++commentStart;
4413 }
4414 if (*commentStart == ';') ++commentStart;
4415
4416 skipToSemi = false;
4417 }
4418 } else if (const clang::EnumConstantDecl* ECD
4419 = clang::dyn_cast<clang::EnumConstantDecl>(&decl)) {
4420 // either "konstant = 12, //COMMENT" or "lastkonstant // COMMENT"
4421 if (ECD->getNextDeclInContext())
4422 while (*commentStart && *commentStart != ',' && *commentStart != '\r' && *commentStart != '\n')
4423 ++commentStart;
4424 // else commentStart already points to the end.
4425
4426 skipToSemi = false;
4427 }
4428
4429 if (skipToSemi) {
4430 while (*commentStart && *commentStart != ';' && *commentStart != '\r' && *commentStart != '\n')
4431 ++commentStart;
4432 if (*commentStart == ';') ++commentStart;
4433 }
4434
4435 // Now skip the spaces until beginning of comments or EOL.
4436 while ( *commentStart && isspace(*commentStart)
4437 && *commentStart != '\n' && *commentStart != '\r') {
4438 ++commentStart;
4439 }
4440
4441 if (commentStart[0] != '/' ||
4442 (commentStart[1] != '/' && commentStart[1] != '*')) {
4443 // not a comment
4444 return "";
4445 }
4446
4447 // Treat by default c++ comments (+2) but also Doxygen comments (+4)
4448 // Int_t fPx; ///< Some doxygen comment for persistent data.
4449 // Int_t fPy; //!< Some doxygen comment for persistent data.
4450 // Int_t fPz; /*!< Some doxygen comment for persistent data. */
4451 // Int_t fPa; /**< Some doxygen comment for persistent data. */
4452 unsigned int skipChars = 2;
4453 if (commentStart[0] == '/' &&
4454 commentStart[1] == '/' &&
4455 (commentStart[2] == '/' || commentStart[2] == '!') &&
4456 commentStart[3] == '<') {
4457 skipChars = 4;
4458 } else if (commentStart[0] == '/' &&
4459 commentStart[1] == '*' &&
4460 (commentStart[2] == '*' || commentStart[2] == '!') &&
4461 commentStart[3] == '<') {
4462 skipChars = 4;
4463 }
4464
4466
4467 // Now skip the spaces after comment start until EOL.
4468 while ( *commentStart && isspace(*commentStart)
4469 && *commentStart != '\n' && *commentStart != '\r') {
4470 ++commentStart;
4471 }
4472 const char* commentEnd = commentStart;
4473 // Even for /* comments we only take the first line into account.
4474 while (*commentEnd && *commentEnd != '\n' && *commentEnd != '\r') {
4475 ++commentEnd;
4476 }
4477
4478 // "Skip" (don't include) trailing space.
4479 // *commentEnd points behind comment end thus check commentEnd[-1]
4480 while (commentEnd > commentStart && isspace(commentEnd[-1])) {
4481 --commentEnd;
4482 }
4483
4484 if (loc) {
4485 // Find the true beginning of a comment.
4486 unsigned offset = commentStart - sourceManager.getCharacterData(sourceLocation);
4487 *loc = sourceLocation.getLocWithOffset(offset - 1);
4488 }
4489
4490 return llvm::StringRef(commentStart, commentEnd - commentStart);
4491}
4492
4493////////////////////////////////////////////////////////////////////////////////
4494/// Return true if class has any of class declarations like ClassDef, ClassDefNV, ClassDefOverride
4495
4496bool ROOT::TMetaUtils::HasClassDefMacro(const clang::Decl *decl, const cling::Interpreter &interpreter)
4497{
4498 if (!decl) return false;
4499
4500 auto& sema = interpreter.getCI()->getSema();
4501 auto maybeMacroLoc = decl->getLocation();
4502
4503 if (!maybeMacroLoc.isMacroID()) return false;
4504
4505 static const std::vector<std::string> signatures =
4506 { "ClassDef", "ClassDefOverride", "ClassDefNV", "ClassDefInline", "ClassDefInlineOverride", "ClassDefInlineNV" };
4507
4508 for (auto &name : signatures)
4509 if (sema.findMacroSpelling(maybeMacroLoc, name))
4510 return true;
4511
4512 return false;
4513}
4514
4515////////////////////////////////////////////////////////////////////////////////
4516/// Return the class comment after the ClassDef:
4517/// class MyClass {
4518/// ...
4519/// ClassDef(MyClass, 1) // class comment
4520///
4521
4522llvm::StringRef ROOT::TMetaUtils::GetClassComment(const clang::CXXRecordDecl &decl,
4523 clang::SourceLocation *loc,
4524 const cling::Interpreter &interpreter)
4525{
4526 using namespace clang;
4527
4528 const Decl* DeclFileLineDecl
4529 = interpreter.getLookupHelper().findFunctionProto(&decl, "DeclFileLine", "",
4530 cling::LookupHelper::NoDiagnostics);
4531
4532 // For now we allow only a special macro (ClassDef) to have meaningful comments
4535 llvm::StringRef comment = ROOT::TMetaUtils::GetComment(*DeclFileLineDecl, &commentSLoc);
4536 if (comment.size()) {
4537 if (loc) {
4538 *loc = commentSLoc;
4539 }
4540 return comment;
4541 }
4542 }
4543 return llvm::StringRef();
4544}
4545
4546////////////////////////////////////////////////////////////////////////////////
4547/// Return the base/underlying type of a chain of array or pointers type.
4548/// Does not yet support the array and pointer part being intermixed.
4549
4550const clang::Type *ROOT::TMetaUtils::GetUnderlyingType(clang::QualType type)
4551{
4552 const clang::Type *rawtype = type.getTypePtr();
4553
4554 // NOTE: We probably meant isa<clang::ElaboratedType>
4555 if (rawtype->isElaboratedTypeSpecifier() ) {
4556 rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4557 }
4558 if (rawtype->isArrayType()) {
4559 rawtype = type.getTypePtr()->getBaseElementTypeUnsafe ();
4560 }
4561 if (rawtype->isPointerType() || rawtype->isReferenceType() ) {
4562 //Get to the 'raw' type.
4563 clang::QualType pointee;
4564 while ( (pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull() && pointee.getTypePtr() != rawtype)
4565 {
4566 rawtype = pointee.getTypePtr();
4567
4568 if (rawtype->isElaboratedTypeSpecifier() ) {
4569 rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4570 }
4571 if (rawtype->isArrayType()) {
4572 rawtype = rawtype->getBaseElementTypeUnsafe ();
4573 }
4574 }
4575 }
4576 if (rawtype->isArrayType()) {
4577 rawtype = rawtype->getBaseElementTypeUnsafe ();
4578 }
4579 return rawtype;
4580}
4581
4582////////////////////////////////////////////////////////////////////////////////
4583/// Return true if the DeclContext is representing an entity reacheable from the
4584/// global namespace
4585
4586bool ROOT::TMetaUtils::IsCtxtReacheable(const clang::DeclContext &ctxt)
4587{
4588 if (ctxt.isNamespace() || ctxt.isTranslationUnit())
4589 return true;
4590 else if(const auto parentdecl = llvm::dyn_cast<clang::CXXRecordDecl>(&ctxt))
4592 else
4593 // For example "extern C" context.
4594 return true;
4595}
4596
4597////////////////////////////////////////////////////////////////////////////////
4598/// Return true if the decl is representing an entity reacheable from the
4599/// global namespace
4600
4602{
4603 const clang::DeclContext *ctxt = decl.getDeclContext();
4604 switch (decl.getAccess()) {
4605 case clang::AS_public:
4606 return !ctxt || IsCtxtReacheable(*ctxt);
4607 case clang::AS_protected:
4608 return false;
4609 case clang::AS_private:
4610 return false;
4611 case clang::AS_none:
4612 return !ctxt || IsCtxtReacheable(*ctxt);
4613 default:
4614 // IMPOSSIBLE
4615 assert(false && "Unexpected value for the access property value in Clang");
4616 return false;
4617 }
4618}
4619
4620////////////////////////////////////////////////////////////////////////////////
4621/// Return true, if the decl is part of the std namespace.
4622
4623bool ROOT::TMetaUtils::IsStdClass(const clang::RecordDecl &cl)
4624{
4625 return cling::utils::Analyze::IsStdClass(cl);
4626}
4627
4628////////////////////////////////////////////////////////////////////////////////
4629/// Return true, if the decl is part of the std namespace and we want
4630/// its default parameter dropped.
4631
4632bool ROOT::TMetaUtils::IsStdDropDefaultClass(const clang::RecordDecl &cl)
4633{
4634 // Might need to reduce it to shared_ptr and STL collection.s
4635 if (cling::utils::Analyze::IsStdClass(cl)) {
4636 static const char *names[] =
4637 { "shared_ptr", "__shared_ptr",
4638 "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset"};
4639 llvm::StringRef clname(cl.getName());
4640 for(auto &&name : names) {
4641 if (clname == name) return true;
4642 }
4643 }
4644 return false;
4645}
4646
4647////////////////////////////////////////////////////////////////////////////////
4648/// This is a recursive function
4649
4650bool ROOT::TMetaUtils::MatchWithDeclOrAnyOfPrevious(const clang::CXXRecordDecl &cl,
4651 const clang::CXXRecordDecl &currentCl)
4652{
4653 // We found it: let's return true
4654 if (&cl == &currentCl) return true;
4655
4656 const clang::CXXRecordDecl* previous = currentCl.getPreviousDecl();
4657
4658 // There is no previous decl, so we cannot possibly find it
4659 if (nullptr == previous){
4660 return false;
4661 }
4662
4663 // We try to find it in the previous
4665
4666}
4667
4668//______________________________________________________________________________
4669
4670bool ROOT::TMetaUtils::IsOfType(const clang::CXXRecordDecl &cl, const std::string& typ, const cling::LookupHelper& lh)
4671{
4672 // Return true if the decl is of type.
4673 // A proper hashtable for caching results would be the ideal solution
4674 // 1) Only one lookup per type
4675 // 2) No string comparison
4676 // We may use a map which becomes an unordered map if c++11 is enabled?
4677
4678 const clang::CXXRecordDecl *thisDecl =
4679 llvm::dyn_cast_or_null<clang::CXXRecordDecl>(lh.findScope(typ, cling::LookupHelper::WithDiagnostics));
4680
4681 // this would be probably an assert given that this state is not reachable unless a mistake is somewhere
4682 if (! thisDecl){
4683 Error("IsOfType","Record decl of type %s not found in the AST.", typ.c_str());
4684 return false;
4685 }
4686
4687 // Now loop on all previous decls to seek a match
4688 const clang::CXXRecordDecl *mostRecentDecl = thisDecl->getMostRecentDecl();
4690
4691 return matchFound;
4692}
4693
4694////////////////////////////////////////////////////////////////////////////////
4695/// type : type name: vector<list<classA,allocator>,allocator>
4696/// result: 0 : not stl container
4697/// abs(result): code of container 1=vector,2=list,3=deque,4=map
4698/// 5=multimap,6=set,7=multiset
4699
4701{
4702 // This routine could be enhanced to also support:
4703 //
4704 // testAlloc: if true, we test allocator, if it is not default result is negative
4705 // result: 0 : not stl container
4706 // abs(result): code of container 1=vector,2=list,3=deque,4=map
4707 // 5=multimap,6=set,7=multiset
4708 // positive val: we have a vector or list with default allocator to any depth
4709 // like vector<list<vector<int>>>
4710 // negative val: STL container other than vector or list, or non default allocator
4711 // For example: vector<deque<int>> has answer -1
4712
4713 if (!IsStdClass(cl)) {
4714 auto *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(cl.getDeclContext());
4715 if (cl.getName() != "RVec" || nsDecl == nullptr || nsDecl->getName() != "VecOps")
4716 return ROOT::kNotSTL;
4717
4718 auto *parentNsDecl = llvm::dyn_cast<clang::NamespaceDecl>(cl.getDeclContext()->getParent());
4719 if (parentNsDecl == nullptr || parentNsDecl->getName() != "ROOT")
4720 return ROOT::kNotSTL;
4721 }
4722
4723 return STLKind(cl.getName());
4724}
4725
4726static bool hasSomeTypedefSomewhere(const clang::Type* T) {
4727 using namespace clang;
4728 struct SearchTypedef: public TypeVisitor<SearchTypedef, bool> {
4729 bool VisitTypedefType(const TypedefType* TD) {
4730 return true;
4731 }
4732 bool VisitArrayType(const ArrayType* AT) {
4733 return Visit(AT->getElementType().getTypePtr());
4734 }
4735 bool VisitDecltypeType(const DecltypeType* DT) {
4736 return Visit(DT->getUnderlyingType().getTypePtr());
4737 }
4738 bool VisitPointerType(const PointerType* PT) {
4739 return Visit(PT->getPointeeType().getTypePtr());
4740 }
4741 bool VisitReferenceType(const ReferenceType* RT) {
4742 return Visit(RT->getPointeeType().getTypePtr());
4743 }
4745 return Visit(STST->getReplacementType().getTypePtr());
4746 }
4748 for (const TemplateArgument &TA : TST->template_arguments()) {
4749 if (TA.getKind() == TemplateArgument::Type && Visit(TA.getAsType().getTypePtr()))
4750 return true;
4751 }
4752 return false;
4753 }
4755 return false; // shrug...
4756 }
4757 bool VisitTypeOfType(const TypeOfType* TOT) {
4758 return TOT->getUnmodifiedType().getTypePtr();
4759 }
4761 NestedNameSpecifier* NNS = ET->getQualifier();
4762 while (NNS) {
4763 if (NNS->getKind() == NestedNameSpecifier::TypeSpec) {
4764 if (Visit(NNS->getAsType()))
4765 return true;
4766 }
4767 NNS = NNS->getPrefix();
4768 }
4769 return Visit(ET->getNamedType().getTypePtr());
4770 }
4771 };
4772
4774 return ST.Visit(T);
4775}
4776
4777////////////////////////////////////////////////////////////////////////////////
4778/// Check if 'input' or any of its template parameter was substituted when
4779/// instantiating the class template instance and replace it with the
4780/// partially sugared types we have from 'instance'.
4781
4782clang::QualType ROOT::TMetaUtils::ReSubstTemplateArg(clang::QualType input, const clang::Type *instance)
4783{
4784 if (!instance) return input;
4785 // if there is no typedef in instance then there is nothing guiding any
4786 // template parameter typedef replacement.
4788 return input;
4789
4790 using namespace llvm;
4791 using namespace clang;
4792 const clang::ASTContext &Ctxt = instance->getAsCXXRecordDecl()->getASTContext();
4793
4794 // Treat scope (clang::ElaboratedType) if any.
4795 const clang::ElaboratedType* etype
4796 = llvm::dyn_cast<clang::ElaboratedType>(input.getTypePtr());
4797 if (etype) {
4798 // We have to also handle the prefix.
4799
4800 clang::Qualifiers scope_qualifiers = input.getLocalQualifiers();
4801 assert(instance->getAsCXXRecordDecl() != nullptr && "ReSubstTemplateArg only makes sense with a type representing a class.");
4802
4803 clang::NestedNameSpecifier *scope = ReSubstTemplateArgNNS(Ctxt,etype->getQualifier(),instance);
4804 clang::QualType subTy = ReSubstTemplateArg(clang::QualType(etype->getNamedType().getTypePtr(),0),instance);
4805
4806 if (scope)
4807 subTy = Ctxt.getElaboratedType(clang::ElaboratedTypeKeyword::None, scope, subTy);
4808 subTy = Ctxt.getQualifiedType(subTy,scope_qualifiers);
4809 return subTy;
4810 }
4811
4812 QualType QT = input;
4813
4814 // In case of Int_t* we need to strip the pointer first, ReSubst and attach
4815 // the pointer once again.
4816 if (isa<clang::PointerType>(QT.getTypePtr())) {
4817 // Get the qualifiers.
4818 Qualifiers quals = QT.getQualifiers();
4819 QualType nQT;
4820 nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4821 if (nQT == QT->getPointeeType()) return QT;
4822
4823 QT = Ctxt.getPointerType(nQT);
4824 // Add back the qualifiers.
4825 QT = Ctxt.getQualifiedType(QT, quals);
4826 return QT;
4827 }
4828
4829 // In case of Int_t& we need to strip the pointer first, ReSubst and attach
4830 // the reference once again.
4831 if (isa<ReferenceType>(QT.getTypePtr())) {
4832 // Get the qualifiers.
4833 bool isLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
4834 Qualifiers quals = QT.getQualifiers();
4835 QualType nQT;
4836 nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4837 if (nQT == QT->getPointeeType()) return QT;
4838
4839 // Add the r- or l-value reference type back to the desugared one.
4840 if (isLValueRefTy)
4841 QT = Ctxt.getLValueReferenceType(nQT);
4842 else
4843 QT = Ctxt.getRValueReferenceType(nQT);
4844 // Add back the qualifiers.
4845 QT = Ctxt.getQualifiedType(QT, quals);
4846 return QT;
4847 }
4848
4849 // In case of Int_t[2] we need to strip the array first, ReSubst and attach
4850 // the array once again.
4851 if (isa<clang::ArrayType>(QT.getTypePtr())) {
4852 // Get the qualifiers.
4853 Qualifiers quals = QT.getQualifiers();
4854
4855 if (const auto arr = dyn_cast<ConstantArrayType>(QT.getTypePtr())) {
4856 QualType newQT= ReSubstTemplateArg(arr->getElementType(),instance);
4857
4858 if (newQT == arr->getElementType()) return QT;
4859 QT = Ctxt.getConstantArrayType(newQT,
4860 arr->getSize(),
4861 arr->getSizeExpr(),
4862 arr->getSizeModifier(),
4863 arr->getIndexTypeCVRQualifiers());
4864
4865 } else if (const auto arr = dyn_cast<DependentSizedArrayType>(QT.getTypePtr())) {
4866 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4867
4868 if (newQT == QT) return QT;
4869 QT = Ctxt.getDependentSizedArrayType (newQT,
4870 arr->getSizeExpr(),
4871 arr->getSizeModifier(),
4872 arr->getIndexTypeCVRQualifiers(),
4873 arr->getBracketsRange());
4874
4875 } else if (const auto arr = dyn_cast<IncompleteArrayType>(QT.getTypePtr())) {
4876 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4877
4878 if (newQT == arr->getElementType()) return QT;
4879 QT = Ctxt.getIncompleteArrayType (newQT,
4880 arr->getSizeModifier(),
4881 arr->getIndexTypeCVRQualifiers());
4882
4883 } else if (const auto arr = dyn_cast<VariableArrayType>(QT.getTypePtr())) {
4884 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4885
4886 if (newQT == arr->getElementType()) return QT;
4887 QT = Ctxt.getVariableArrayType (newQT,
4888 arr->getSizeExpr(),
4889 arr->getSizeModifier(),
4890 arr->getIndexTypeCVRQualifiers(),
4891 arr->getBracketsRange());
4892 }
4893
4894 // Add back the qualifiers.
4895 QT = Ctxt.getQualifiedType(QT, quals);
4896 return QT;
4897 }
4898
4899 // If the instance is also an elaborated type, we need to skip
4900 etype = llvm::dyn_cast<clang::ElaboratedType>(instance);
4901 if (etype) {
4902 instance = etype->getNamedType().getTypePtr();
4903 if (!instance) return input;
4904 }
4905
4906 const clang::TemplateSpecializationType* TST
4907 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instance);
4908
4909 if (!TST) return input;
4910
4911 const clang::ClassTemplateSpecializationDecl* TSTdecl
4912 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(instance->getAsCXXRecordDecl());
4913
4914 if (!TSTdecl) return input;
4915
4916 const clang::SubstTemplateTypeParmType *substType
4917 = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(input.getTypePtr());
4918
4919 if (substType) {
4920 // Make sure it got replaced from this template
4921 const clang::ClassTemplateDecl *replacedCtxt = nullptr;
4922
4923 const clang::DeclContext *replacedDeclCtxt = substType->getReplacedParameter()->getDeclContext();
4924 const clang::CXXRecordDecl *decl = llvm::dyn_cast<clang::CXXRecordDecl>(replacedDeclCtxt);
4925 unsigned int index = substType->getReplacedParameter()->getIndex();
4926 if (decl) {
4927
4928 if (decl->getKind() == clang::Decl::ClassTemplatePartialSpecialization) {
4929 const clang::ClassTemplatePartialSpecializationDecl *spec = llvm::dyn_cast<clang::ClassTemplatePartialSpecializationDecl>(decl);
4930
4931 unsigned int depth = substType->getReplacedParameter()->getDepth();
4932
4933 const TemplateArgument *instanceArgs = spec->getTemplateArgs().data();
4934 unsigned int instanceNArgs = spec->getTemplateArgs().size();
4935
4936 // Search for the 'right' replacement.
4937
4938 for(unsigned int A = 0; A < instanceNArgs; ++A) {
4939 if (instanceArgs[A].getKind() == clang::TemplateArgument::Type) {
4940 clang::QualType argQualType = instanceArgs[A].getAsType();
4941
4942 const clang::TemplateTypeParmType *replacementType;
4943
4944 replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(argQualType);
4945
4946 if (!replacementType) {
4947 const clang::SubstTemplateTypeParmType *argType
4948 = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(argQualType);
4949 if (argType) {
4950 clang::QualType replacementQT = argType->getReplacementType();
4951 replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(replacementQT);
4952 }
4953 }
4954 if (replacementType &&
4955 depth == replacementType->getDepth() &&
4956 index == replacementType->getIndex() )
4957 {
4958 index = A;
4959 break;
4960 }
4961 }
4962 }
4963 replacedCtxt = spec->getSpecializedTemplate();
4964 } else {
4965 replacedCtxt = decl->getDescribedClassTemplate();
4966 }
4967 } else if (auto const declguide = llvm::dyn_cast<clang::CXXDeductionGuideDecl>(replacedDeclCtxt)) {
4968 replacedCtxt = llvm::dyn_cast<clang::ClassTemplateDecl>(declguide->getDeducedTemplate());
4969 } else if (auto const ctdecl = llvm::dyn_cast<clang::ClassTemplateDecl>(replacedDeclCtxt)) {
4971 } else {
4972 std::string astDump;
4973 llvm::raw_string_ostream ostream(astDump);
4974 instance->dump(ostream, Ctxt);
4975 ostream.flush();
4976 ROOT::TMetaUtils::Warning("ReSubstTemplateArg","Unexpected type of declaration context for template parameter: %s.\n\tThe responsible class is:\n\t%s\n",
4977 replacedDeclCtxt->getDeclKindName(), astDump.c_str());
4978 replacedCtxt = nullptr;
4979 }
4980
4981 if (replacedCtxt && replacedCtxt->getCanonicalDecl() == TSTdecl->getSpecializedTemplate()->getCanonicalDecl())
4982 {
4983 const auto &TAs = TST->template_arguments();
4984 if (index >= TAs.size()) {
4985 // The argument replaced was a default template argument that is
4986 // being listed as part of the instance ...
4987 // so we probably don't really know how to spell it ... we would need to recreate it
4988 // (See AddDefaultParameters).
4989 return input;
4990 } else if (TAs[index].getKind() == clang::TemplateArgument::Type) {
4991 return TAs[index].getAsType();
4992 } else {
4993 // The argument is (likely) a value or expression and there is nothing for us
4994 // to change
4995 return input;
4996 }
4997 }
4998 }
4999 // Maybe a class template instance, recurse and rebuild
5000 const clang::TemplateSpecializationType* inputTST
5001 = llvm::dyn_cast<const clang::TemplateSpecializationType>(input.getTypePtr());
5002 const clang::ASTContext& astCtxt = TSTdecl->getASTContext();
5003
5004 if (inputTST) {
5005 bool mightHaveChanged = false;
5006 llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
5007 for (const clang::TemplateArgument &TA : inputTST->template_arguments()) {
5008 if (TA.getKind() != clang::TemplateArgument::Type) {
5009 desArgs.push_back(TA);
5010 continue;
5011 }
5012
5013 clang::QualType SubTy = TA.getAsType();
5014 // Check if the type needs more desugaring and recurse.
5015 if (llvm::isa<clang::ElaboratedType>(SubTy)
5016 || llvm::isa<clang::SubstTemplateTypeParmType>(SubTy)
5017 || llvm::isa<clang::TemplateSpecializationType>(SubTy)) {
5018 clang::QualType newSubTy = ReSubstTemplateArg(SubTy,instance);
5020 if (!newSubTy.isNull()) {
5021 desArgs.push_back(clang::TemplateArgument(newSubTy));
5022 }
5023 } else
5024 desArgs.push_back(TA);
5025 }
5026
5027 // If desugaring happened allocate new type in the AST.
5028 if (mightHaveChanged) {
5029 clang::Qualifiers qualifiers = input.getLocalQualifiers();
5030 input = astCtxt.getTemplateSpecializationType(inputTST->getTemplateName(),
5031 desArgs,
5032 inputTST->getCanonicalTypeInternal());
5033 input = astCtxt.getQualifiedType(input, qualifiers);
5034 }
5035 }
5036
5037 return input;
5038}
5039
5040////////////////////////////////////////////////////////////////////////////////
5041/// Remove the last n template arguments from the name
5042
5044{
5045 if ( nArgsToRemove == 0 || name == "")
5046 return 0;
5047
5048 // We proceed from the right to the left, counting commas which are not
5049 // enclosed by < >.
5050 const unsigned int length = name.length();
5051 unsigned int cur=0; // let's start beyond the first > from the right
5052 unsigned int nArgsRemoved=0;
5053 unsigned int nBraces=0;
5054 char c='@';
5056 c = name[cur];
5057 if (c == '<') nBraces++;
5058 if (c == '>') nBraces--;
5059 if (c == ',' && nBraces==1 /*So we are not in a sub-template*/) nArgsRemoved++;
5060 cur++;
5061 }
5062 cur--;
5063 name = name.substr(0,cur)+">";
5064 return 0;
5065
5066}
5067
5068////////////////////////////////////////////////////////////////////////////////
5069/// Converts STL container name to number. vector -> 1, etc..
5070
5072{
5073 static const char *stls[] = //container names
5074 {"any","vector","list", "deque","map","multimap","set","multiset","bitset",
5075 "forward_list","unordered_set","unordered_multiset","unordered_map","unordered_multimap", "RVec", nullptr};
5076 static const ROOT::ESTLType values[] =
5087 };
5088 // kind of stl container
5089 for (int k = 1; stls[k]; k++) {
5090 if (type == stls[k])
5091 return values[k];
5092 }
5093 return ROOT::kNotSTL;
5094}
5095
5096////////////////////////////////////////////////////////////////////////////////
5097
5098const clang::TypedefNameDecl *ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TypedefNameDecl *TND)
5099{
5100 if (!TND)
5101 return nullptr;
5102
5103 TND = TND->getMostRecentDecl();
5104 while (TND && !(TND->hasAttrs()))
5105 TND = TND->getPreviousDecl();
5106
5107 return TND;
5108}
5109
5110////////////////////////////////////////////////////////////////////////////////
5111
5112const clang::TagDecl *ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TagDecl *TD)
5113{
5114 if (!TD)
5115 return nullptr;
5116
5117 TD = TD->getMostRecentDecl();
5118 while (TD && !(TD->hasAttrs() && TD->isThisDeclarationADefinition()))
5119 TD = TD->getPreviousDecl();
5120
5121 return TD;
5122}
5123
5124////////////////////////////////////////////////////////////////////////////////
5125/// Extract the immediately outer namespace and then launch the recursion
5126
5128 std::list<std::pair<std::string,bool> >& enclosingNamespaces)
5129{
5130 const clang::DeclContext* enclosingNamespaceDeclCtxt = decl.getDeclContext();
5131 if (!enclosingNamespaceDeclCtxt) return;
5132
5133 const clang::NamespaceDecl* enclosingNamespace =
5134 clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
5135 if (!enclosingNamespace) return;
5136
5137 enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
5138 enclosingNamespace->isInline()));
5139
5141
5142}
5143
5144////////////////////////////////////////////////////////////////////////////////
5145/// Extract enclosing namespaces recursively
5146
5148 std::list<std::pair<std::string,bool> >& enclosingNamespaces)
5149{
5150 const clang::DeclContext* enclosingNamespaceDeclCtxt = ctxt.getParent ();
5151
5152 // If no parent is found, nothing more to be done
5154 return;
5155 }
5156
5157 // Check if the parent is a namespace (it could be a class for example)
5158 // if not, nothing to be done here
5159 const clang::NamespaceDecl* enclosingNamespace = clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
5160 if (!enclosingNamespace) return;
5161
5162 // Add to the list of parent namespaces
5163 enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
5164 enclosingNamespace->isInline()));
5165
5166 // here the recursion
5168}
5169
5170////////////////////////////////////////////////////////////////////////////////
5171/// Extract the names and types of containing scopes.
5172/// Stop if a class is met and return its pointer.
5173
5174const clang::RecordDecl *ROOT::TMetaUtils::ExtractEnclosingScopes(const clang::Decl& decl,
5175 std::list<std::pair<std::string,unsigned int> >& enclosingSc)
5176{
5177 const clang::DeclContext* enclosingDeclCtxt = decl.getDeclContext();
5178 if (!enclosingDeclCtxt) return nullptr;
5179
5180 unsigned int scopeType;
5181
5182 if (auto enclosingNamespacePtr =
5183 clang::dyn_cast<clang::NamespaceDecl>(enclosingDeclCtxt)){
5184 scopeType= enclosingNamespacePtr->isInline() ? 1 : 0; // inline or simple namespace
5185 enclosingSc.push_back(std::make_pair(enclosingNamespacePtr->getNameAsString(),scopeType));
5187 }
5188
5189 if (auto enclosingClassPtr =
5190 clang::dyn_cast<clang::RecordDecl>(enclosingDeclCtxt)){
5191 return enclosingClassPtr;
5192 }
5193
5194 return nullptr;
5195}
5196
5197////////////////////////////////////////////////////////////////////////////////
5198/// Reimplementation of TSystem::ExpandPathName() that cannot be
5199/// used from TMetaUtils.
5200
5201static void replaceEnvVars(const char* varname, std::string& txt)
5202{
5203 std::string::size_type beginVar = 0;
5204 std::string::size_type endVar = 0;
5205 while ((beginVar = txt.find('$', beginVar)) != std::string::npos
5206 && beginVar + 1 < txt.length()) {
5207 std::string::size_type beginVarName = beginVar + 1;
5208 std::string::size_type endVarName = std::string::npos;
5209 if (txt[beginVarName] == '(') {
5210 // "$(VARNAME)" style.
5211 endVarName = txt.find(')', beginVarName);
5212 ++beginVarName;
5213 if (endVarName == std::string::npos) {
5214 ROOT::TMetaUtils::Error(nullptr, "Missing ')' for '$(' in $%s at %s\n",
5215 varname, txt.c_str() + beginVar);
5216 return;
5217 }
5218 endVar = endVarName + 1;
5219 } else {
5220 // "$VARNAME/..." style.
5221 beginVarName = beginVar + 1;
5223 while (isalnum(txt[endVarName]) || txt[endVarName] == '_')
5224 ++endVarName;
5226 }
5227
5228 const char* val = std::getenv(txt.substr(beginVarName,
5229 endVarName - beginVarName).c_str());
5230 if (!val) val = "";
5231
5232 txt.replace(beginVar, endVar - beginVar, val);
5233 int lenval = strlen(val);
5234 int delta = lenval - (endVar - beginVar); // these many extra chars,
5235 endVar += delta; // advance the end marker accordingly.
5236
5237 // Look for the next one
5238 beginVar = endVar + 1;
5239 }
5240}
5241
5242////////////////////////////////////////////////////////////////////////////////
5243/// Organise the parameters for cling in order to guarantee relocatability
5244/// It treats the gcc toolchain and the root include path
5245/// FIXME: enables relocatability for experiments' framework headers until PCMs
5246/// are available.
5247
5249{
5250 const char* envInclPath = std::getenv("ROOT_INCLUDE_PATH");
5251
5252 if (!envInclPath)
5253 return;
5254
5255#ifdef _WIN32
5256 constexpr char kPathSep = ';';
5257#else
5258 constexpr char kPathSep = ':';
5259#endif
5260
5261 std::istringstream envInclPathsStream(envInclPath);
5262 std::string inclPath;
5263 while (std::getline(envInclPathsStream, inclPath, kPathSep)) {
5264 // Can't use TSystem in here; re-implement TSystem::ExpandPathName().
5265 replaceEnvVars("ROOT_INCLUDE_PATH", inclPath);
5266 if (!inclPath.empty()) {
5267 clingArgs.push_back("-I");
5268 clingArgs.push_back(inclPath);
5269 }
5270 }
5271}
5272
5273////////////////////////////////////////////////////////////////////////////////
5274
5275void ROOT::TMetaUtils::ReplaceAll(std::string& str, const std::string& from, const std::string& to,bool recurse)
5276{
5277 if(from.empty())
5278 return;
5279 size_t start_pos = 0;
5280 bool changed=true;
5281 while (changed){
5282 changed=false;
5283 start_pos = 0;
5284 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
5285 str.replace(start_pos, from.length(), to);
5286 start_pos += to.length();
5287 if (recurse) changed = true;
5288 }
5289 }
5290}
5291
5292////////////////////////////////////////////////////////////////////////////////
5293/// Return the separator suitable for this platform.
5298
5299////////////////////////////////////////////////////////////////////////////////
5300
5301bool ROOT::TMetaUtils::EndsWith(const std::string &theString, const std::string &theSubstring)
5302{
5303 if (theString.size() < theSubstring.size()) return false;
5304 const unsigned int theSubstringSize = theSubstring.size();
5305 return 0 == theString.compare(theString.size() - theSubstringSize,
5307 theSubstring);
5308}
5309
5310////////////////////////////////////////////////////////////////////////////////
5311
5312bool ROOT::TMetaUtils::BeginsWith(const std::string &theString, const std::string &theSubstring)
5313{
5314 if (theString.size() < theSubstring.size()) return false;
5315 const unsigned int theSubstringSize = theSubstring.size();
5316 return 0 == theString.compare(0,
5318 theSubstring);
5319}
5320
5321
5322
5323////////////////////////////////////////////////////////////////////////////////
5324
5326{
5327 // Note, should change this into take llvm::StringRef.
5328
5329 if ((strstr(filename, "LinkDef") || strstr(filename, "Linkdef") ||
5330 strstr(filename, "linkdef")) && strstr(filename, ".h")) {
5331 return true;
5332 }
5333 size_t len = strlen(filename);
5334 size_t linkdeflen = 9; /* strlen("linkdef.h") */
5335 if (len >= 9) {
5336 if (0 == strncasecmp(filename + (len - linkdeflen), "linkdef", linkdeflen - 2)
5337 && 0 == strcmp(filename + (len - 2), ".h")
5338 ) {
5339 return true;
5340 } else {
5341 return false;
5342 }
5343 } else {
5344 return false;
5345 }
5346}
5347
5348////////////////////////////////////////////////////////////////////////////////
5349
5351{
5352 return llvm::sys::path::extension(filename) == ".h" ||
5353 llvm::sys::path::extension(filename) == ".hh" ||
5354 llvm::sys::path::extension(filename) == ".hpp" ||
5355 llvm::sys::path::extension(filename) == ".H" ||
5356 llvm::sys::path::extension(filename) == ".h++" ||
5357 llvm::sys::path::extension(filename) == "hxx" ||
5358 llvm::sys::path::extension(filename) == "Hxx" ||
5359 llvm::sys::path::extension(filename) == "HXX";
5360}
5361
5362////////////////////////////////////////////////////////////////////////////////
5363
5364const std::string ROOT::TMetaUtils::AST2SourceTools::Decls2FwdDecls(const std::vector<const clang::Decl *> &decls,
5365 cling::Interpreter::IgnoreFilesFunc_t ignoreFiles,
5366 const cling::Interpreter &interp,
5367 std::string *logs)
5368{
5369 clang::Sema &sema = interp.getSema();
5370 cling::Transaction theTransaction(sema);
5371 std::set<clang::Decl *> addedDecls;
5372 for (auto decl : decls) {
5373 // again waiting for cling
5374 clang::Decl *ncDecl = const_cast<clang::Decl *>(decl);
5375 theTransaction.append(ncDecl);
5376 }
5377 std::string newFwdDecl;
5378 llvm::raw_string_ostream llvmOstr(newFwdDecl);
5379
5380 std::string locallogs;
5381 llvm::raw_string_ostream llvmLogStr(locallogs);
5382 interp.forwardDeclare(theTransaction, sema.getPreprocessor(), sema.getASTContext(), llvmOstr, true,
5383 logs ? &llvmLogStr : nullptr, ignoreFiles);
5384 llvmOstr.flush();
5385 llvmLogStr.flush();
5386 if (logs)
5387 logs->swap(locallogs);
5388 return newFwdDecl;
5389}
5390
5391////////////////////////////////////////////////////////////////////////////////
5392/// Take the namespaces which enclose the decl and put them around the
5393/// definition string.
5394/// For example, if the definition string is "myClass" which is enclosed by
5395/// the namespaces ns1 and ns2, one would get:
5396/// namespace ns2{ namespace ns1 { class myClass; } }
5397
5399 std::string& defString)
5400{
5402 return rcd ? 1:0;
5403}
5404
5405////////////////////////////////////////////////////////////////////////////////
5406/// Take the scopes which enclose the decl and put them around the
5407/// definition string.
5408/// If a class is encountered, bail out.
5409
5410const clang::RecordDecl* ROOT::TMetaUtils::AST2SourceTools::EncloseInScopes(const clang::Decl& decl,
5411 std::string& defString)
5412{
5413 std::list<std::pair<std::string,unsigned int> > enclosingNamespaces;
5415
5416 if (rcdPtr) return rcdPtr;
5417
5418 // Check if we have enclosing namespaces
5419 static const std::string scopeType [] = {"namespace ", "inline namespace ", "class "};
5420
5421 std::string scopeName;
5422 std::string scopeContent;
5423 unsigned int scopeIndex;
5424 for (auto const & encScope : enclosingNamespaces){
5425 scopeIndex = encScope.second;
5426 scopeName = encScope.first;
5427 scopeContent = " { " + defString + " }";
5429 scopeName +
5431 }
5432 return nullptr;
5433}
5434
5435////////////////////////////////////////////////////////////////////////////////
5436/// Loop over the template parameters and build a string for template arguments
5437/// using the fully qualified name
5438/// There are different cases:
5439/// Case 1: a simple template parameter
5440/// E.g. `template<typename T> class A;`
5441/// Case 2: a non-type: either an integer or an enum
5442/// E.g. `template<int I, Foo > class A;` where `Foo` is `enum Foo {red, blue};`
5443/// 2 sub cases here:
5444/// SubCase 2.a: the parameter is an enum: bail out, cannot be treated.
5445/// SubCase 2.b: use the fully qualified name
5446/// Case 3: a TemplateTemplate argument
5447/// E.g. `template <template <typename> class T> class container { };`
5448
5450 const clang::TemplateParameterList& tmplParamList,
5451 const cling::Interpreter& interpreter)
5452{
5453 templateArgs="<";
5454 for (auto prmIt = tmplParamList.begin();
5455 prmIt != tmplParamList.end(); prmIt++){
5456
5457 if (prmIt != tmplParamList.begin())
5458 templateArgs += ", ";
5459
5460 auto nDecl = *prmIt;
5461 std::string typeName;
5462
5463 // Case 1
5464 if (llvm::isa<clang::TemplateTypeParmDecl>(nDecl)){
5465 typeName = "typename ";
5466 if (nDecl->isParameterPack())
5467 typeName += "... ";
5468 typeName += (*prmIt)->getNameAsString();
5469 }
5470 // Case 2
5471 else if (auto nttpd = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(nDecl)){
5472 auto theType = nttpd->getType();
5473 // If this is an enum, use int as it is impossible to fwd declare and
5474 // this makes sense since it is not a type...
5475 if (theType.getAsString().find("enum") != std::string::npos){
5476 std::string astDump;
5477 llvm::raw_string_ostream ostream(astDump);
5478 nttpd->dump(ostream);
5479 ostream.flush();
5480 ROOT::TMetaUtils::Warning(nullptr,"Forward declarations of templates with enums as template parameters. The responsible class is: %s\n", astDump.c_str());
5481 return 1;
5482 } else {
5484 theType,
5485 interpreter);
5486 }
5487 }
5488 // Case 3: TemplateTemplate argument
5489 else if (auto ttpd = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(nDecl)){
5491 if (retCode!=0){
5492 std::string astDump;
5493 llvm::raw_string_ostream ostream(astDump);
5494 ttpd->dump(ostream);
5495 ostream.flush();
5496 ROOT::TMetaUtils::Error(nullptr,"Cannot reconstruct template template parameter forward declaration for %s\n", astDump.c_str());
5497 return 1;
5498 }
5499 }
5500
5501 templateArgs += typeName;
5502 }
5503
5504 templateArgs+=">";
5505 return 0;
5506}
5507
5508////////////////////////////////////////////////////////////////////////////////
5509/// Convert a tmplt decl to its fwd decl
5510
5512 const cling::Interpreter& interpreter,
5513 std::string& defString)
5514{
5515 std::string templatePrefixString;
5516 auto tmplParamList= templDecl.getTemplateParameters();
5517 if (!tmplParamList){ // Should never happen
5518 Error(nullptr,
5519 "Cannot extract template parameter list for %s",
5520 templDecl.getNameAsString().c_str());
5521 return 1;
5522 }
5523
5525 if (retCode!=0){
5526 Warning(nullptr,
5527 "Problems with arguments for forward declaration of class %s\n",
5528 templDecl.getNameAsString().c_str());
5529 return retCode;
5530 }
5531 templatePrefixString = "template " + templatePrefixString + " ";
5532
5533 defString = templatePrefixString + "class ";
5534 if (templDecl.isParameterPack())
5535 defString += "... ";
5536 defString += templDecl.getNameAsString();
5537 if (llvm::isa<clang::TemplateTemplateParmDecl>(&templDecl)) {
5538 // When fwd declaring the template template arg of
5539 // namespace N { template <template <class T> class C> class X; }
5540 // we don't need to put it into any namespace, and we want no trailing
5541 // ';'
5542 return 0;
5543 }
5544 defString += ';';
5546}
5547
5548////////////////////////////////////////////////////////////////////////////////
5549
5550static int TreatSingleTemplateArg(const clang::TemplateArgument& arg,
5551 std::string& argFwdDecl,
5552 const cling::Interpreter& interpreter,
5553 bool acceptStl=false)
5554{
5555 using namespace ROOT::TMetaUtils::AST2SourceTools;
5556
5557 // We do nothing in presence of ints, bools, templates.
5558 // We should probably in presence of templates though...
5559 if (clang::TemplateArgument::Type != arg.getKind()) return 0;
5560
5561 auto argQualType = arg.getAsType();
5562
5563 // Recursively remove all *
5564 while (llvm::isa<clang::PointerType>(argQualType.getTypePtr())) argQualType = argQualType->getPointeeType();
5565
5566 auto argTypePtr = argQualType.getTypePtr();
5567
5568 // Bail out on enums
5569 if (llvm::isa<clang::EnumType>(argTypePtr)){
5570 return 1;
5571 }
5572
5573 // If this is a built-in, just return: fwd decl not necessary.
5574 if (llvm::isa<clang::BuiltinType>(argTypePtr)){
5575 return 0;
5576 }
5577
5578 // Treat typedefs which are arguments
5579 if (auto tdTypePtr = llvm::dyn_cast<clang::TypedefType>(argTypePtr)) {
5580 FwdDeclFromTypeDefNameDecl(*tdTypePtr->getDecl(), interpreter, argFwdDecl);
5581 return 0;
5582 }
5583
5584 if (auto argRecTypePtr = llvm::dyn_cast<clang::RecordType>(argTypePtr)){
5585 // Now we cannot but have a RecordType
5586 if (auto argRecDeclPtr = argRecTypePtr->getDecl()){
5587 FwdDeclFromRcdDecl(*argRecDeclPtr,interpreter,argFwdDecl,acceptStl);
5588 }
5589 return 0;
5590 }
5591
5592 return 1;
5593}
5594
5595////////////////////////////////////////////////////////////////////////////////
5596/// Convert a tmplt decl to its fwd decl
5597
5599 const cling::Interpreter& interpreter,
5600 std::string& defString,
5601 const std::string &normalizedName)
5602{
5603 // If this is an explicit specialization, inject it into cling, too, such that it can have
5604 // externalLexicalStorage, see TCling.cxx's ExtVisibleStorageAdder::VisitClassTemplateSpecializationDecl.
5605 if (auto tmplSpecDeclPtr = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)) {
5606 if (const auto *specDef = tmplSpecDeclPtr->getDefinition()) {
5607 if (specDef->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization)
5608 return 0;
5609 // normalizedName contains scope, no need to enclose in namespace!
5611 std::cout << " Forward declaring template spec " << normalizedName << ":\n";
5612 for (auto arg : tmplSpecDeclPtr->getTemplateArgs().asArray()) {
5613 std::string argFwdDecl;
5614 int retCode = TreatSingleTemplateArg(arg, argFwdDecl, interpreter, /*acceptStl=*/false);
5616 std::cout << " o Template argument ";
5617 if (retCode == 0) {
5618 std::cout << "successfully treated. Arg fwd decl: " << argFwdDecl << std::endl;
5619 } else {
5620 std::cout << "could not be treated. Abort fwd declaration generation.\n";
5621 }
5622 }
5623
5624 if (retCode != 0) { // A sign we must bail out
5625 return retCode;
5626 }
5627 defString += argFwdDecl + '\n';
5628 }
5629 defString += "template <> class " + normalizedName + ';';
5630 return 0;
5631 }
5632 }
5633
5634 return 0;
5635}
5636
5637////////////////////////////////////////////////////////////////////////////////
5638/// Convert a rcd decl to its fwd decl
5639/// If this is a template specialisation, treat in the proper way.
5640/// If it is contained in a class, just fwd declare the class.
5641
5643 const cling::Interpreter& interpreter,
5644 std::string& defString,
5645 bool acceptStl)
5646{
5647 // Do not fwd declare the templates in the stl.
5649 return 0;
5650
5651 // Do not fwd declare unnamed decls.
5652 if (!recordDecl.getIdentifier())
5653 return 0;
5654
5655 // We may need to fwd declare the arguments of the template
5656 std::string argsFwdDecl;
5657
5658 if (auto tmplSpecDeclPtr = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)){
5659 std::string argFwdDecl;
5661 std::cout << "Class " << recordDecl.getNameAsString()
5662 << " is a template specialisation. Treating its arguments.\n";
5663 for(auto arg : tmplSpecDeclPtr->getTemplateArgs().asArray()){
5666 std::cout << " o Template argument ";
5667 if (retCode==0){
5668 std::cout << "successfully treated. Arg fwd decl: " << argFwdDecl << std::endl;
5669 } else {
5670 std::cout << "could not be treated. Abort fwd declaration generation.\n";
5671 }
5672 }
5673
5674 if (retCode!=0){ // A sign we must bail out
5675 return retCode;
5676 }
5678 }
5679
5680 if (acceptStl){
5682 return 0;
5683 }
5684
5685 int retCode=0;
5686 if (auto tmplDeclPtr = tmplSpecDeclPtr->getSpecializedTemplate()){
5688 }
5689 defString = argsFwdDecl + "\n" + defString;
5690 return retCode;
5691
5692 }
5693
5694 defString = "class " + recordDecl.getNameAsString() + ";";
5695 const clang::RecordDecl* rcd = EncloseInScopes(recordDecl, defString);
5696
5697 if (rcd){
5699 }
5700 // Add a \n here to avoid long lines which contain duplications, for example (from MathCore):
5701 // namespace ROOT { namespace Math { class IBaseFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5702 // namespace ROOT { namespace Math { class IGradientFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5703 defString = argsFwdDecl + "\n" + defString;
5704
5705 return 0;
5706}
5707
5708////////////////////////////////////////////////////////////////////////////////
5709/// Extract "forward declaration" of a typedef.
5710/// If the typedef is contained in a class, just fwd declare the class.
5711/// If not, fwd declare the typedef and all the dependent typedefs and types if necessary.
5712
5714 const cling::Interpreter& interpreter,
5715 std::string& fwdDeclString,
5716 std::unordered_set<std::string>* fwdDeclSetPtr)
5717{
5718 std::string buffer = tdnDecl.getNameAsString();
5719 std::string underlyingName;
5720 auto underlyingType = tdnDecl.getUnderlyingType().getCanonicalType();
5721 if (const clang::TagType* TT
5722 = llvm::dyn_cast<clang::TagType>(underlyingType.getTypePtr())) {
5723 if (clang::NamedDecl* ND = TT->getDecl()) {
5724 if (!ND->getIdentifier()) {
5725 // No fwd decl for unnamed underlying entities.
5726 return 0;
5727 }
5728 }
5729 }
5730
5731 TNormalizedCtxt nCtxt(interpreter.getLookupHelper());
5735 nCtxt);
5736
5737 // Heuristic: avoid entities like myclass<myType1, myType2::xyz>
5738 if (underlyingName.find(">::") != std::string::npos)
5739 return 0;
5740
5741 buffer="typedef "+underlyingName+" "+buffer+";";
5742 const clang::RecordDecl* rcd=EncloseInScopes(tdnDecl,buffer);
5743 if (rcd) {
5744 // We do not need the whole series of scopes, just the class.
5745 // It is enough to trigger an uncomplete type autoload/parse callback
5746 // for example: MyClass::blabla::otherNs::myTypedef
5748 }
5749
5750 // Start Recursion if the underlying type is a TypedefNameDecl
5751 // Note: the simple cast w/o the getSingleStepDesugaredType call
5752 // does not work in case the typedef is in a namespace.
5753 auto& ctxt = tdnDecl.getASTContext();
5754 auto immediatelyUnderlyingType = underlyingType.getSingleStepDesugaredType(ctxt);
5755
5756 if (auto underlyingTdnTypePtr = llvm::dyn_cast<clang::TypedefType>(immediatelyUnderlyingType.getTypePtr())){
5757 std::string tdnFwdDecl;
5761 tdnFwdDecl,
5763 if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(tdnFwdDecl).second)
5765 } else if (auto CXXRcdDeclPtr = immediatelyUnderlyingType->getAsCXXRecordDecl()){
5766 std::string classFwdDecl;
5768 std::cout << "Typedef " << tdnDecl.getNameAsString() << " hides a class: "
5769 << CXXRcdDeclPtr->getNameAsString() << std::endl;
5773 true /* acceptStl*/);
5774 if (retCode!=0){ // bail out
5775 return 0;
5776 }
5777
5778 if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(classFwdDecl).second)
5780 }
5781
5782 fwdDeclString+=buffer;
5783
5784 return 0;
5785}
5786
5787////////////////////////////////////////////////////////////////////////////////
5788/// Get the default value as string.
5789/// Limited at the moment to:
5790/// - Integers
5791/// - Booleans
5792
5793int ROOT::TMetaUtils::AST2SourceTools::GetDefArg(const clang::ParmVarDecl& par,
5794 std::string& valAsString,
5795 const clang::PrintingPolicy& ppolicy)
5796{
5797 auto defArgExprPtr = par.getDefaultArg();
5798 auto& ctxt = par.getASTContext();
5799 if(!defArgExprPtr->isEvaluatable(ctxt)){
5800 return -1;
5801 }
5802
5803 auto defArgType = par.getType();
5804
5805 // The value is a boolean
5806 if (defArgType->isBooleanType()){
5807 bool result;
5808 defArgExprPtr->EvaluateAsBooleanCondition (result,ctxt);
5809 valAsString=std::to_string(result);
5810 return 0;
5811 }
5812
5813 // The value is an integer
5814 if (defArgType->isIntegerType()){
5815 clang::Expr::EvalResult evalResult;
5816 defArgExprPtr->EvaluateAsInt(evalResult, ctxt);
5817 llvm::APSInt result = evalResult.Val.getInt();
5818 auto uintVal = *result.getRawData();
5819 if (result.isNegative()){
5820 long long int intVal=uintVal*-1;
5821 valAsString=std::to_string(intVal);
5822 } else {
5823 valAsString=std::to_string(uintVal);
5824 }
5825
5826 return 0;
5827 }
5828
5829 // The value is something else. We go for the generalised printer
5830 llvm::raw_string_ostream rso(valAsString);
5831 defArgExprPtr->printPretty(rso,nullptr,ppolicy);
5832 valAsString = rso.str();
5833 // We can be in presence of a string. Let's escape the characters properly.
5834 ROOT::TMetaUtils::ReplaceAll(valAsString,"\\\"","__TEMP__VAL__");
5836 ROOT::TMetaUtils::ReplaceAll(valAsString,"__TEMP__VAL__","\\\"");
5837
5838 return 0;
5839}
5840
The file contains utilities which are foundational and could be used across the core component of ROO...
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define R(a, b, c, d, e, f, g, h, i)
Definition RSha256.hxx:110
static Roo_reg_AGKInteg1D instance
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
short Version_t
Class version identifier (short)
Definition RtypesCore.h:80
static void indent(ostringstream &buf, int indent_level)
static bool RecurseKeepNParams(clang::TemplateArgument &normTArg, const clang::TemplateArgument &tArg, const cling::Interpreter &interp, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt, const clang::ASTContext &astCtxt)
static clang::SourceLocation getFinalSpellingLoc(clang::SourceManager &sourceManager, clang::SourceLocation sourceLoc)
const clang::DeclContext * GetEnclosingSpace(const clang::RecordDecl &cl)
bool IsTemplate(const clang::Decl &cl)
static void KeepNParams(clang::QualType &normalizedType, const clang::QualType &vanillaType, const cling::Interpreter &interp, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
This function allows to manipulate the number of arguments in the type of a template specialisation.
static void CreateNameTypeMap(const clang::CXXRecordDecl &cl, ROOT::MembersTypeMap_t &nameType)
Create the data member name-type map for given class.
const clang::CXXMethodDecl * GetMethodWithProto(const clang::Decl *cinfo, const char *method, const char *proto, const cling::Interpreter &interp, bool diagnose)
int dumpDeclForAssert(const clang::Decl &D, const char *commentStart)
static void replaceEnvVars(const char *varname, std::string &txt)
Reimplementation of TSystem::ExpandPathName() that cannot be used from TMetaUtils.
static bool areEqualValues(const clang::TemplateArgument &tArg, const clang::NamedDecl &tPar)
std::cout << "Are equal values?\n";
static bool isTypeWithDefault(const clang::NamedDecl *nDecl)
Check if this NamedDecl is a template parameter with a default argument.
static int TreatSingleTemplateArg(const clang::TemplateArgument &arg, std::string &argFwdDecl, const cling::Interpreter &interpreter, bool acceptStl=false)
static bool areEqualTypes(const clang::TemplateArgument &tArg, llvm::SmallVectorImpl< clang::TemplateArgument > &preceedingTArgs, const clang::NamedDecl &tPar, const cling::Interpreter &interp, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
static bool hasSomeTypedefSomewhere(const clang::Type *T)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
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 filename
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 target
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 result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
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 length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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 UChar_t len
Option_t Option_t TPoint TPoint const char mode
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 type
char name[80]
Definition TGX11.cxx:148
const char * proto
Definition civetweb.c:18822
#define free
Definition civetweb.c:1578
const_iterator begin() const
const_iterator end() const
const clang::RecordDecl * GetRecordDecl() const
AnnotatedRecordDecl(long index, const clang::RecordDecl *decl, bool rStreamerInfo, bool rNoStreamer, bool rRequestNoInputOperator, bool rRequestOnlyTClass, int rRequestedVersionNumber, int rRequestedRNTupleSerializationMode, const std::string &rRequestedRNTupleSoARecord, const cling::Interpreter &interpret, const TNormalizedCtxt &normCtxt)
There is no requested type name.
const clang::RecordDecl * fDecl
const std::string & RequestedRNTupleSoARecord() const
const char * GetRequestedName() const
static std::string BuildDemangledTypeInfo(const clang::RecordDecl *rDecl, const std::string &normalizedName)
const std::string & GetDemangledTypeInfo() const
const char * GetNormalizedName() const
const clang::CXXRecordDecl * fArgType
const clang::CXXRecordDecl * GetType() const
RConstructorType(const char *type_of_arg, const cling::Interpreter &)
bool IsDeclaredScope(const std::string &base, bool &isInlined) override
bool IsAlreadyPartiallyDesugaredName(const std::string &nondef, const std::string &nameLong) override
TClingLookupHelper(cling::Interpreter &interpreter, TNormalizedCtxt &normCtxt, ExistingTypeCheck_t existingTypeCheck, CheckInClassTable_t CheckInClassTable, AutoParse_t autoParse, bool *shuttingDownPtr, const int *pgDebug=nullptr)
ExistingTypeCheck_t fExistingTypeCheck
CheckInClassTable_t fCheckInClassTable
bool GetPartiallyDesugaredNameWithScopeHandling(const std::string &tname, std::string &result, bool dropstd=true) override
We assume that we have a simple type: [const] typename[*&][const].
bool CheckInClassTable(const std::string &tname, std::string &result) override
void GetPartiallyDesugaredName(std::string &nameLong) override
bool ExistingTypeCheck(const std::string &tname, std::string &result) override
Helper routine to ry hard to avoid looking up in the Cling database as this could enduce an unwanted ...
const Config_t & GetConfig() const
TNormalizedCtxt::Config_t::SkipCollection DeclsCont_t
TNormalizedCtxt::TemplPtrIntMap_t TemplPtrIntMap_t
int GetNargsToKeep(const clang::ClassTemplateDecl *templ) const
Get from the map the number of arguments to keep.
TNormalizedCtxt::Config_t Config_t
TNormalizedCtxtImpl(const cling::LookupHelper &lh)
Initialize the list of typedef to keep (i.e.
TNormalizedCtxt::TypesCont_t TypesCont_t
void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl *templ, unsigned int i)
Add to the internal map the pointer of a template as key and the number of template arguments to keep...
void keepTypedef(const cling::LookupHelper &lh, const char *name, bool replace=false)
Insert the type with name into the collection of typedefs to keep.
const TypesCont_t & GetTypeWithAlternative() const
const TemplPtrIntMap_t GetTemplNargsToKeepMap() const
static TemplPtrIntMap_t fTemplatePtrArgsToKeepMap
void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl *templ, unsigned int i)
void keepTypedef(const cling::LookupHelper &lh, const char *name, bool replace=false)
cling::utils::Transform::Config Config_t
std::map< const clang::ClassTemplateDecl *, int > TemplPtrIntMap_t
TNormalizedCtxt(const cling::LookupHelper &lh)
TNormalizedCtxtImpl * fImpl
const TypesCont_t & GetTypeWithAlternative() const
std::set< const clang::Type * > TypesCont_t
int GetNargsToKeep(const clang::ClassTemplateDecl *templ) const
const Config_t & GetConfig() const
const TemplPtrIntMap_t GetTemplNargsToKeepMap() const
A RAII helper to remove and readd enclosing _Atomic() It expects no spaces at the beginning or end of...
Definition TClassEdit.h:160
#define I(x, y, z)
const std::string & GetPathSeparator()
int EncloseInNamespaces(const clang::Decl &decl, std::string &defString)
Take the namespaces which enclose the decl and put them around the definition string.
int FwdDeclFromTypeDefNameDecl(const clang::TypedefNameDecl &tdnDecl, const cling::Interpreter &interpreter, std::string &fwdDeclString, std::unordered_set< std::string > *fwdDeclSet=nullptr)
Extract "forward declaration" of a typedef.
int PrepareArgsForFwdDecl(std::string &templateArgs, const clang::TemplateParameterList &tmplParamList, const cling::Interpreter &interpreter)
Loop over the template parameters and build a string for template arguments using the fully qualified...
int FwdDeclFromTmplDecl(const clang::TemplateDecl &tmplDecl, const cling::Interpreter &interpreter, std::string &defString)
Convert a tmplt decl to its fwd decl.
const clang::RecordDecl * EncloseInScopes(const clang::Decl &decl, std::string &defString)
Take the scopes which enclose the decl and put them around the definition string.
int FwdDeclFromRcdDecl(const clang::RecordDecl &recordDecl, const cling::Interpreter &interpreter, std::string &defString, bool acceptStl=false)
Convert a rcd decl to its fwd decl If this is a template specialisation, treat in the proper way.
int GetDefArg(const clang::ParmVarDecl &par, std::string &valAsString, const clang::PrintingPolicy &pp)
Get the default value as string.
int FwdDeclIfTmplSpec(const clang::RecordDecl &recordDecl, const cling::Interpreter &interpreter, std::string &defString, const std::string &normalizedName)
Convert a tmplt decl to its fwd decl.
const std::string Decls2FwdDecls(const std::vector< const clang::Decl * > &decls, bool(*ignoreFiles)(const clang::PresumedLoc &), const cling::Interpreter &interp, std::string *logs)
bool HasClassDefMacro(const clang::Decl *decl, const cling::Interpreter &interpreter)
Return true if class has any of class declarations like ClassDef, ClassDefNV, ClassDefOverride.
llvm::StringRef GetClassComment(const clang::CXXRecordDecl &decl, clang::SourceLocation *loc, const cling::Interpreter &interpreter)
Return the class comment after the ClassDef: class MyClass { ... ClassDef(MyClass,...
const T * GetAnnotatedRedeclarable(const T *Redecl)
int extractPropertyNameValFromString(const std::string attributeStr, std::string &attrName, std::string &attrValue)
bool hasOpaqueTypedef(clang::QualType instanceType, const TNormalizedCtxt &normCtxt)
Return true if the type is a Double32_t or Float16_t or is a instance template that depends on Double...
EIOCtorCategory CheckConstructor(const clang::CXXRecordDecl *, const RConstructorType &, const cling::Interpreter &interp)
Check if class has constructor of provided type - either default or with single argument.
clang::RecordDecl * GetUnderlyingRecordDecl(clang::QualType type)
bool BeginsWith(const std::string &theString, const std::string &theSubstring)
bool IsDeclReacheable(const clang::Decl &decl)
Return true if the decl is representing an entity reacheable from the global namespace.
const clang::FunctionDecl * ClassInfo__HasMethod(const clang::DeclContext *cl, char const *, const cling::Interpreter &interp)
bool GetNameWithinNamespace(std::string &, std::string &, std::string &, clang::CXXRecordDecl const *)
Return true if one of the class' enclosing scope is a namespace and set fullname to the fully qualifi...
const clang::RecordDecl * ExtractEnclosingScopes(const clang::Decl &decl, std::list< std::pair< std::string, unsigned int > > &enclosingSc)
Extract the names and types of containing scopes.
bool HasCustomOperatorNewArrayPlacement(clang::RecordDecl const &, const cling::Interpreter &interp)
return true if we can find a custom operator new with placement
void Error(const char *location, const char *fmt,...)
void WriteClassInit(std::ostream &finalString, const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *decl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt, const RConstructorTypes &ctorTypes, bool &needCollectionProxy)
FIXME: a function of 450+ lines!
void Info(const char *location, const char *fmt,...)
int WriteNamespaceHeader(std::ostream &, const clang::RecordDecl *)
int GetClassVersion(const clang::RecordDecl *cl, const cling::Interpreter &interp)
Return the version number of the class or -1 if the function Class_Version does not exist.
clang::QualType GetTypeForIO(const clang::QualType &templateInstanceType, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt, TClassEdit::EModType mode=TClassEdit::kNone)
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,...
void WritePointersSTL(const AnnotatedRecordDecl &cl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt)
Write interface function for STL members.
bool HasNewMerge(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method Merge(TCollection*,TFileMergeInfo*)
bool CheckPublicFuncWithProto(clang::CXXRecordDecl const *, char const *, char const *, const cling::Interpreter &, bool diagnose)
Return true, if the function (defined by the name and prototype) exists and is public.
std::string GetFileName(const clang::Decl &decl, const cling::Interpreter &interp)
Return the header file to be included to declare the Decl.
void WriteStandaloneReadRules(std::ostream &finalString, bool rawrules, std::vector< std::string > &standaloneTargets, const cling::Interpreter &interp)
clang::ClassTemplateDecl * QualType2ClassTemplateDecl(const clang::QualType &qt)
Extract from a qualtype the class template if this makes sense.
int IsSTLContainer(const AnnotatedRecordDecl &annotated)
Is this an STL container.
void Fatal(const char *location, const char *fmt,...)
std::list< RConstructorType > RConstructorTypes
int extractPropertyNameVal(clang::Attr *attribute, std::string &attrName, std::string &attrValue)
std::string GetModuleFileName(const char *moduleName)
Return the dictionary file name for a module.
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...
bool NeedDestructor(clang::CXXRecordDecl const *, const cling::Interpreter &)
bool EndsWith(const std::string &theString, const std::string &theSubstring)
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
bool NeedTemplateKeyword(clang::CXXRecordDecl const *)
bool HasCustomConvStreamerMemberFunction(const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *clxx, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt)
Return true if the class has a custom member function streamer.
bool HasDirectoryAutoAdd(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method DirectoryAutoAdd(TDirectory *)
const clang::FunctionDecl * GetFuncWithProto(const clang::Decl *cinfo, const char *method, const char *proto, const cling::Interpreter &gInterp, bool diagnose)
int ElementStreamer(std::ostream &finalString, const clang::NamedDecl &forcontext, const clang::QualType &qti, const char *t, int rwmode, const cling::Interpreter &interp, const char *tcl=nullptr)
bool MatchWithDeclOrAnyOfPrevious(const clang::CXXRecordDecl &cl, const clang::CXXRecordDecl &currentCl)
This is a recursive function.
clang::QualType GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
Return the type normalized for ROOT, keeping only the ROOT opaque typedef (Double32_t,...
const char * ShortTypeName(const char *typeDesc)
Return the absolute type of typeDesc.
void GetCppName(std::string &output, const char *input)
Return (in the argument 'output') a valid name of the C++ symbol/type (pass as 'input') that can be u...
bool HasCustomOperatorNewPlacement(char const *, clang::RecordDecl const &, const cling::Interpreter &)
return true if we can find a custom operator new with placement
bool IsStdClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace.
bool HasResetAfterMerge(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method ResetAfterMerge(TFileMergeInfo *)
ROOT::ESTLType STLKind(const llvm::StringRef type)
Converts STL container name to number. vector -> 1, etc..
void WriteClassCode(CallWriteStreamer_t WriteStreamerFunc, const AnnotatedRecordDecl &cl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt, std::ostream &finalString, const RConstructorTypes &ctorTypes, bool isGenreflex)
Generate the code of the class If the requestor is genreflex, request the new streamer format.
bool HasOldMerge(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method Merge(TCollection*)
clang::TemplateName ExtractTemplateNameFromQualType(const clang::QualType &qt)
These manipulations are necessary because a template specialisation type does not inherit from a reco...
int RemoveTemplateArgsFromName(std::string &name, unsigned int)
Remove the last n template arguments from the name.
long GetLineNumber(clang::Decl const *)
It looks like the template specialization decl actually contains less information on the location of ...
void WriteAuxFunctions(std::ostream &finalString, const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *decl, const cling::Interpreter &interp, const RConstructorTypes &ctorTypes, const TNormalizedCtxt &normCtxt)
std::string NormalizedName; GetNormalizedName(NormalizedName, decl->getASTContext()....
void foreachHeaderInModule(const clang::Module &module, const std::function< void(const clang::Module::Header &)> &closure, bool includeDirectlyUsedModules=true)
Calls the given lambda on every header in the given module.
bool IsBase(const clang::CXXRecordDecl *cl, const clang::CXXRecordDecl *base, const clang::CXXRecordDecl *context, const cling::Interpreter &interp)
void ExtractCtxtEnclosingNameSpaces(const clang::DeclContext &, std::list< std::pair< std::string, bool > > &)
Extract enclosing namespaces recursively.
std::pair< bool, int > GetTrivialIntegralReturnValue(const clang::FunctionDecl *funcCV, const cling::Interpreter &interp)
If the function contains 'just': return SomeValue; this routine will extract this value and return it...
bool HasCustomStreamerMemberFunction(const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *clxx, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt)
Return true if the class has a custom member function streamer.
std::string GetRealPath(const std::string &path)
clang::QualType AddDefaultParameters(clang::QualType instanceType, const cling::Interpreter &interpret, const TNormalizedCtxt &normCtxt)
Add any unspecified template parameters to the class template instance, mentioned anywhere in the typ...
std::pair< std::string, clang::QualType > GetNameTypeForIO(const clang::QualType &templateInstanceType, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt, TClassEdit::EModType mode=TClassEdit::kNone)
void GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
Main implementation relying on GetFullyQualifiedTypeName All other GetQualifiedName functions leverag...
bool ExtractAttrIntPropertyFromName(const clang::Decl &decl, const std::string &propName, int &propValue)
This routine counts on the "propName<separator>propValue" format.
bool IsLinkdefFile(const char *filename)
void WriteRulesRegistration(std::ostream &finalString, const std::string &dictName, const std::vector< std::string > &standaloneTargets)
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.
void SetPathsForRelocatability(std::vector< std::string > &clingArgs)
Organise the parameters for cling in order to guarantee relocatability It treats the gcc toolchain an...
bool IsStreamableObject(const clang::FieldDecl &m, const cling::Interpreter &interp)
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
bool QualType2Template(const clang::QualType &qt, clang::ClassTemplateDecl *&ctd, clang::ClassTemplateSpecializationDecl *&ctsd)
Get the template specialisation decl and template decl behind the qualtype Returns true if successful...
std::string TrueName(const clang::FieldDecl &m)
TrueName strips the typedefs and array dimensions.
const clang::Type * GetUnderlyingType(clang::QualType type)
Return the base/underlying type of a chain of array or pointers type.
ROOT::ESTLType IsSTLCont(const clang::RecordDecl &cl)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container abs(result):...
bool IsStdDropDefaultClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace and we want its default parameter dropped.
bool RequireCompleteType(const cling::Interpreter &interp, const clang::CXXRecordDecl *cl)
bool IsHeaderName(const std::string &filename)
void Warning(const char *location, const char *fmt,...)
bool IsCtxtReacheable(const clang::DeclContext &ctxt)
Return true if the DeclContext is representing an entity reacheable from the global namespace.
bool IsOfType(const clang::CXXRecordDecl &cl, const std::string &type, const cling::LookupHelper &lh)
const std::string & GetPathSeparator()
Return the separator suitable for this platform.
bool CheckDefaultConstructor(const clang::CXXRecordDecl *, const cling::Interpreter &interp)
Checks if default constructor exists and accessible.
EIOCtorCategory CheckIOConstructor(const clang::CXXRecordDecl *, const char *, const clang::CXXRecordDecl *, const cling::Interpreter &interp)
Checks IO constructor - must be public and with specified argument.
bool ExtractAttrPropertyFromName(const clang::Decl &decl, const std::string &propName, std::string &propValue)
This routine counts on the "propName<separator>propValue" format.
const clang::CXXRecordDecl * ScopeSearch(const char *name, const cling::Interpreter &gInterp, bool diagnose, const clang::Type **resultType)
Return the scope corresponding to 'name' or std::'name'.
int & GetErrorIgnoreLevel()
void ExtractEnclosingNameSpaces(const clang::Decl &, std::list< std::pair< std::string, bool > > &)
Extract the immediately outer namespace and then launch the recursion.
bool HasIOConstructor(clang::CXXRecordDecl const *, std::string &, const RConstructorTypes &, const cling::Interpreter &)
return true if we can find an constructor calleable without any arguments or with one the IOCtor spec...
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 ...
void WriteSchemaList(std::list< SchemaRuleMap_t > &rules, const std::string &listName, std::ostream &output)
Write schema rules.
std::map< std::string, ROOT::Internal::TSchemaType > MembersTypeMap_t
ESTLType
Definition ESTLType.h:28
@ kSTLbitset
Definition ESTLType.h:37
@ kSTLmap
Definition ESTLType.h:33
@ kSTLunorderedmultiset
Definition ESTLType.h:43
@ kROOTRVec
Definition ESTLType.h:46
@ kSTLend
Definition ESTLType.h:47
@ kSTLset
Definition ESTLType.h:35
@ kSTLmultiset
Definition ESTLType.h:36
@ kSTLdeque
Definition ESTLType.h:32
@ kSTLvector
Definition ESTLType.h:30
@ kSTLunorderedmultimap
Definition ESTLType.h:45
@ kSTLunorderedset
Definition ESTLType.h:42
@ kSTLlist
Definition ESTLType.h:31
@ kSTLforwardlist
Definition ESTLType.h:41
@ kSTLunorderedmap
Definition ESTLType.h:44
@ kNotSTL
Definition ESTLType.h:29
@ kSTLmultimap
Definition ESTLType.h:34
void WriteReadRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for Read rule, the function name is being written to rule["funcname"].
R__EXTERN SchemaRuleClassMap_t gReadRules
bool HasValidDataMembers(SchemaRuleMap_t &rule, MembersTypeMap_t &members, std::string &error_string)
Check if given rule contains references to valid data members.
void WriteReadRawRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for ReadRaw rule, the function name is being written to rule["funcname"...
R__EXTERN SchemaRuleClassMap_t gReadRawRules
ROOT::ESTLType STLKind(std::string_view type)
Converts STL container name to number.
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
std::string GetLong64_Name(const char *original)
Replace 'long long' and 'unsigned long long' by 'Long64_t' and 'ULong64_t'.
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
char * DemangleName(const char *mangled_name, int &errorCode)
Definition TClassEdit.h:255
std::string GetNameForIO(const std::string &templateInstanceName, TClassEdit::EModType mode=TClassEdit::kNone, bool *hasChanged=nullptr)
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.
@ kKeepOuterConst
Definition TClassEdit.h:88
@ kDropStlDefault
Definition TClassEdit.h:83
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>
constexpr Double_t C()
Velocity of light in .
Definition TMath.h:117
static const char * what
Definition stlLoader.cc:5
TMarker m
Definition textangle.C:8
auto * tt
Definition textangle.C:16