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