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" << " sizeof(" << csymbol << ") );" << "\n";
1991 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
1992 finalString << " instance.SetNew(&new_" << mappedname.c_str() << ");" << "\n";
1993 if (args.size()==0 && NeedDestructor(decl, interp))
1994 finalString << " instance.SetNewArray(&newArray_" << mappedname.c_str() << ");" << "\n";
1995 }
1996 if (NeedDestructor(decl, interp)) {
1997 finalString << " instance.SetDelete(&delete_" << mappedname.c_str() << ");" << "\n" << " instance.SetDeleteArray(&deleteArray_" << mappedname.c_str() << ");" << "\n" << " instance.SetDestructor(&destruct_" << mappedname.c_str() << ");" << "\n";
1998 }
2000 finalString << " instance.SetDirectoryAutoAdd(&directoryAutoAdd_" << mappedname.c_str() << ");" << "\n";
2001 }
2003 // We have a custom member function streamer or an older (not StreamerInfo based) automatic streamer.
2004 finalString << " instance.SetStreamerFunc(&streamer_" << mappedname.c_str() << ");" << "\n";
2005 }
2007 // We have a custom member function streamer or an older (not StreamerInfo based) automatic streamer.
2008 finalString << " instance.SetConvStreamerFunc(&conv_streamer_" << mappedname.c_str() << ");" << "\n";
2009 }
2011 finalString << " instance.SetMerge(&merge_" << mappedname.c_str() << ");" << "\n";
2012 }
2014 finalString << " instance.SetResetAfterMerge(&reset_" << mappedname.c_str() << ");" << "\n";
2015 }
2016 if (bset) {
2017 finalString << " instance.AdoptCollectionProxyInfo(TCollectionProxyInfo::Generate(TCollectionProxyInfo::" << "Pushback" << "<Internal::TStdBitsetHelper< " << classname.c_str() << " > >()));" << "\n";
2018
2019 needCollectionProxy = true;
2020 } else if (stl != 0 &&
2021 ((stl > 0 && stl<ROOT::kSTLend) || (stl < 0 && stl>-ROOT::kSTLend)) && // is an stl container
2022 (stl != ROOT::kSTLbitset && stl !=-ROOT::kSTLbitset) ){ // is no bitset
2023 int idx = classname.find("<");
2024 int stlType = (idx!=(int)std::string::npos) ? TClassEdit::STLKind(classname.substr(0,idx)) : 0;
2025 const char* methodTCP = nullptr;
2026 switch(stlType) {
2027 case ROOT::kSTLvector:
2028 case ROOT::kSTLlist:
2029 case ROOT::kSTLdeque:
2030 case ROOT::kROOTRVec:
2031 methodTCP="Pushback";
2032 break;
2034 methodTCP="Pushfront";
2035 break;
2036 case ROOT::kSTLmap:
2037 case ROOT::kSTLmultimap:
2040 methodTCP="MapInsert";
2041 break;
2042 case ROOT::kSTLset:
2043 case ROOT::kSTLmultiset:
2046 methodTCP="Insert";
2047 break;
2048 }
2049 // FIXME Workaround: for the moment we do not generate coll proxies with unique ptrs since
2050 // they imply copies and therefore do not compile.
2051 auto classNameForIO = TClassEdit::GetNameForIO(classname);
2052 finalString << " instance.AdoptCollectionProxyInfo(TCollectionProxyInfo::Generate(TCollectionProxyInfo::" << methodTCP << "< " << classNameForIO.c_str() << " >()));" << "\n";
2053
2054 needCollectionProxy = true;
2055 }
2056
2057 //---------------------------------------------------------------------------
2058 // Register Alternate spelling of the class name.
2059 /////////////////////////////////////////////////////////////////////////////
2060
2061 if (cl.GetRequestedName()[0] && classname != cl.GetRequestedName()) {
2062 finalString << "\n" << " instance.AdoptAlternate(::ROOT::AddClassAlternate(\""
2063 << classname << "\",\"" << cl.GetRequestedName() << "\"));\n";
2064 }
2065
2066 if (!cl.GetDemangledTypeInfo().empty()
2067 && cl.GetDemangledTypeInfo() != classname
2068 && cl.GetDemangledTypeInfo() != cl.GetRequestedName()) {
2069 finalString << "\n" << " instance.AdoptAlternate(::ROOT::AddClassAlternate(\""
2070 << classname << "\",\"" << cl.GetDemangledTypeInfo() << "\"));\n";
2071
2072 }
2073
2074 //---------------------------------------------------------------------------
2075 // Register underlying SoA record for RNTuple SoA layouts
2076 /////////////////////////////////////////////////////////////////////////////
2077
2078 if (!cl.RequestedRNTupleSoARecord().empty()) {
2079 finalString << " instance.SetRNTupleSoARecord(\"" << cl.RequestedRNTupleSoARecord() << "\");" << "\n";
2080 }
2081
2082 //---------------------------------------------------------------------------
2083 // Pass the schema evolution rules to TGenericClassInfo
2084 /////////////////////////////////////////////////////////////////////////////
2085
2086 if( (rulesIt1 != ROOT::gReadRules.end() && rulesIt1->second.size()>0) || (rulesIt2 != ROOT::gReadRawRules.end() && rulesIt2->second.size()>0) ) {
2087 finalString << "\n" << " ::ROOT::Internal::TSchemaHelper* rule;" << "\n";
2088 }
2089
2090 if( rulesIt1 != ROOT::gReadRules.end() ) {
2091 finalString << "\n" << " // the io read rules" << "\n" << " std::vector<::ROOT::Internal::TSchemaHelper> readrules(" << rulesIt1->second.size() << ");" << "\n";
2092 ROOT::WriteSchemaList(rulesIt1->second.fRules, "readrules", finalString);
2093 finalString << " instance.SetReadRules( readrules );" << "\n";
2094 rulesIt1->second.fGenerated = true;
2095 }
2096
2097 if( rulesIt2 != ROOT::gReadRawRules.end() ) {
2098 finalString << "\n" << " // the io read raw rules" << "\n" << " std::vector<::ROOT::Internal::TSchemaHelper> readrawrules(" << rulesIt2->second.size() << ");" << "\n";
2099 ROOT::WriteSchemaList(rulesIt2->second.fRules, "readrawrules", finalString);
2100 finalString << " instance.SetReadRawRules( readrawrules );" << "\n";
2101 rulesIt2->second.fGenerated = true;
2102 }
2103
2104 finalString << " return &instance;" << "\n" << " }" << "\n";
2105
2107 // The GenerateInitInstance for STL are not unique and should not be externally accessible
2108 finalString << " TGenericClassInfo *GenerateInitInstance(const " << csymbol << "*)" << "\n" << " {\n return GenerateInitInstanceLocal(static_cast<" << csymbol << "*>(nullptr));\n }" << "\n";
2109 }
2110
2111 finalString << " // Static variable to force the class initialization" << "\n";
2112 // must be one long line otherwise UseDummy does not work
2113
2114
2115 finalString << " static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstanceLocal(static_cast<const " << csymbol << "*>(nullptr)); R__UseDummy(_R__UNIQUE_DICT_(Init));" << "\n";
2116
2117 if (!ClassInfo__HasMethod(decl,"Dictionary",interp) || IsTemplate(*decl)) {
2118 finalString << "\n" << " // Dictionary for non-ClassDef classes" << "\n"
2119 << " static TClass *" << mappedname << "_Dictionary() {\n"
2120 << " TClass* theClass ="
2121 << "::ROOT::GenerateInitInstanceLocal(static_cast<const " << csymbol << "*>(nullptr))->GetClass();\n"
2122 << " " << mappedname << "_TClassManip(theClass);\n";
2123 finalString << " return theClass;\n";
2124 finalString << " }\n\n";
2125
2126 // Now manipulate tclass in order to percolate the properties expressed as
2127 // annotations of the decls.
2128 std::string manipString;
2129 std::string attribute_s;
2130 std::string attrName, attrValue;
2131 // Class properties
2132 bool attrMapExtracted = false;
2133 if (decl->hasAttrs()){
2134 // Loop on the attributes
2135 for (clang::Decl::attr_iterator attrIt = decl->attr_begin();
2136 attrIt!=decl->attr_end();++attrIt){
2138 continue;
2139 }
2141 continue;
2142 }
2143 if (attrName == "name" ||
2144 attrName == "pattern" ||
2145 attrName == "rootmap") continue;
2146 // A general property
2147 // 1) We need to create the property map (in the gen code)
2148 // 2) we need to take out the map (in the gen code)
2149 // 3) We need to bookkep the fact that the map is created and out (in this source)
2150 // 4) We fill the map (in the gen code)
2151 if (!attrMapExtracted){
2152 manipString+=" theClass->CreateAttributeMap();\n";
2153 manipString+=" TDictAttributeMap* attrMap( theClass->GetAttributeMap() );\n";
2154 attrMapExtracted=true;
2155 }
2156 manipString+=" attrMap->AddProperty(\""+attrName +"\",\""+attrValue+"\");\n";
2157 }
2158 } // end of class has properties
2159
2160 // Member properties
2161 // Loop on declarations inside the class, including data members
2162 for(clang::CXXRecordDecl::decl_iterator internalDeclIt = decl->decls_begin();
2163 internalDeclIt != decl->decls_end(); ++internalDeclIt){
2164 if (!(!(*internalDeclIt)->isImplicit()
2165 && (clang::isa<clang::FieldDecl>(*internalDeclIt) ||
2166 clang::isa<clang::VarDecl>(*internalDeclIt)))) continue; // Check if it's a var or a field
2167
2168 // Now let's check the attributes of the var/field
2169 if (!internalDeclIt->hasAttrs()) continue;
2170
2171 attrMapExtracted = false;
2172 bool memberPtrCreated = false;
2173
2174 for (clang::Decl::attr_iterator attrIt = internalDeclIt->attr_begin();
2175 attrIt!=internalDeclIt->attr_end();++attrIt){
2176
2177 // Get the attribute as string
2179 continue;
2180 }
2181
2182 // Check the name of the decl
2183 clang::NamedDecl* namedInternalDecl = clang::dyn_cast<clang::NamedDecl> (*internalDeclIt);
2184 if (!namedInternalDecl) {
2185 TMetaUtils::Error(nullptr, "Cannot convert field declaration to clang::NamedDecl");
2186 continue;
2187 }
2188 const std::string memberName(namedInternalDecl->getName());
2189 const std::string cppMemberName = "theMember_"+memberName;
2190
2191 // Prepare a string to get the data member, it can be used later.
2192 const std::string dataMemberCreation= " TDataMember* "+cppMemberName+" = theClass->GetDataMember(\""+memberName+"\");\n";
2193
2194 // Let's now attack regular properties
2195
2197 continue;
2198 }
2199
2200 // Skip these
2201 if (attrName == propNames::comment ||
2202 attrName == propNames::iotype ||
2203 attrName == propNames::ioname ) continue;
2204
2205 if (!memberPtrCreated){
2207 memberPtrCreated=true;
2208 }
2209
2210 if (!attrMapExtracted){
2211 manipString+=" "+cppMemberName+"->CreateAttributeMap();\n";
2212 manipString+=" TDictAttributeMap* memberAttrMap_"+memberName+"( theMember_"+memberName+"->GetAttributeMap() );\n";
2213 attrMapExtracted=true;
2214 }
2215
2216 manipString+=" memberAttrMap_"+memberName+"->AddProperty(\""+attrName +"\",\""+attrValue+"\");\n";
2217
2218
2219 } // End loop on attributes
2220 } // End loop on internal declarations
2221
2222
2223 finalString << " static void " << mappedname << "_TClassManip(TClass* " << (manipString.empty() ? "":"theClass") << "){\n"
2224 << manipString
2225 << " }\n\n";
2226 } // End of !ClassInfo__HasMethod(decl,"Dictionary") || IsTemplate(*decl))
2227
2228 finalString << "} // end of namespace ROOT" << "\n" << "\n";
2229}
2230
2232 std::vector<std::string> &standaloneTargets,
2233 const cling::Interpreter &interp)
2234{
2236 if (!rulesIt1.second.fGenerated) {
2237 const clang::Type *typeptr = nullptr;
2238 const clang::CXXRecordDecl *target =
2239 ROOT::TMetaUtils::ScopeSearch(rulesIt1.first.c_str(), interp, true /*diag*/, &typeptr);
2240
2241 if (!target && !rulesIt1.second.fTargetDecl) {
2242 auto &&nRules = rulesIt1.second.size();
2243 std::string rule{nRules > 1 ? "rules" : "rule"};
2244 std::string verb{nRules > 1 ? "were" : "was"};
2245 ROOT::TMetaUtils::Warning(nullptr, "%d %s for target class %s %s not used!\n", nRules, rule.c_str(),
2246 rulesIt1.first.c_str(), verb.c_str());
2247 continue;
2248 }
2249
2252
2253 std::string name;
2255
2256 std::string mappedname;
2258
2259 finalString << "namespace ROOT {" << "\n";
2260 // Also TClingUtils.cxx:1823
2261 int i = 0;
2262 finalString << "\n // Schema evolution read functions\n";
2263 std::list<ROOT::SchemaRuleMap_t>::iterator rIt = rulesIt1.second.fRules.begin();
2264 while (rIt != rulesIt1.second.fRules.end()) {
2265
2266 //--------------------------------------------------------------------
2267 // Check if the rules refer to valid data members
2268 ///////////////////////////////////////////////////////////////////////
2269
2270 std::string error_string;
2272 ROOT::TMetaUtils::Warning(nullptr, "%s", error_string.c_str());
2273 rIt = rulesIt1.second.fRules.erase(rIt);
2274 continue;
2275 }
2276
2277 //---------------------------------------------------------------------
2278 // Write the conversion function if necessary
2279 ///////////////////////////////////////////////////////////////////////
2280
2281 if (rIt->find("code") != rIt->end()) {
2282 if (rawrules)
2284 else
2286 }
2287 ++rIt;
2288 }
2289 finalString << "} // namespace ROOT" << "\n";
2290
2291 standaloneTargets.push_back(rulesIt1.first);
2292 rulesIt1.second.fGenerated = true;
2293 }
2294 }
2295}
2296
2298 const std::vector<std::string> &standaloneTargets)
2299{
2300 std::string functionname("RecordReadRules_");
2302
2303 finalString << "namespace ROOT {" << "\n";
2304 finalString << " // Registration Schema evolution read functions\n";
2305 finalString << " int " << functionname << "() {" << "\n";
2306 if (!standaloneTargets.empty())
2307 finalString << "\n"
2308 << " ::ROOT::Internal::TSchemaHelper* rule;" << "\n";
2309 for (const auto &target : standaloneTargets) {
2310 std::string name;
2312
2313 ROOT::SchemaRuleClassMap_t::iterator rulesIt1 = ROOT::gReadRules.find(target.c_str());
2314 finalString << " {\n";
2315 if (rulesIt1 != ROOT::gReadRules.end()) {
2316 finalString << " // the io read rules for " << target << "\n";
2317 finalString << " std::vector<::ROOT::Internal::TSchemaHelper> readrules(" << rulesIt1->second.size()
2318 << ");" << "\n";
2319 ROOT::WriteSchemaList(rulesIt1->second.fRules, "readrules", finalString);
2320 finalString << " TClass::RegisterReadRules(TSchemaRule::kReadRule, \"" << name
2321 << "\", std::move(readrules));\n";
2322 rulesIt1->second.fGenerated = true;
2323 }
2324 ROOT::SchemaRuleClassMap_t::iterator rulesIt2 = ROOT::gReadRawRules.find(target.c_str());
2325 if (rulesIt2 != ROOT::gReadRawRules.end()) {
2326 finalString << "\n // the io read raw rules for " << target << "\n";
2327 finalString << " std::vector<::ROOT::Internal::TSchemaHelper> readrawrules(" << rulesIt2->second.size()
2328 << ");" << "\n";
2329 ROOT::WriteSchemaList(rulesIt2->second.fRules, "readrawrules", finalString);
2330 finalString << " TClass::RegisterReadRules(TSchemaRule::kReadRawRule, \"" << name
2331 << "\", std::move(readrawrules));\n";
2332 rulesIt2->second.fGenerated = true;
2333 }
2334 finalString << " }\n";
2335 }
2336 finalString << " return 0;\n";
2337 finalString << " }\n";
2338 finalString << " static int _R__UNIQUE_DICT_(ReadRules_" << dictName << ") = " << functionname << "();";
2339 finalString << "R__UseDummy(_R__UNIQUE_DICT_(ReadRules_" << dictName << "));" << "\n";
2340 finalString << "} // namespace ROOT" << "\n";
2341}
2342
2343////////////////////////////////////////////////////////////////////////////////
2344/// Return true if one of the class' enclosing scope is a namespace and
2345/// set fullname to the fully qualified name,
2346/// clsname to the name within a namespace
2347/// and nsname to the namespace fully qualified name.
2348
2350 std::string &clsname,
2351 std::string &nsname,
2352 const clang::CXXRecordDecl *cl)
2353{
2354 fullname.clear();
2355 nsname.clear();
2356
2358 clsname = fullname;
2359
2360 // Inline namespace are stripped from the normalized name, we need to
2361 // strip it from the prefix we want to remove.
2362 auto ctxt = cl->getEnclosingNamespaceContext();
2363 while(ctxt && ctxt!=cl && ctxt->isInlineNamespace()) {
2364 ctxt = ctxt->getParent();
2365 }
2366 if (ctxt) {
2367 const clang::NamedDecl *namedCtxt = llvm::dyn_cast<clang::NamedDecl>(ctxt);
2368 if (namedCtxt && namedCtxt!=cl) {
2369 const clang::NamespaceDecl *nsdecl = llvm::dyn_cast<clang::NamespaceDecl>(namedCtxt);
2370 if (nsdecl && !nsdecl->isAnonymousNamespace()) {
2372 clsname.erase (0, nsname.size() + 2);
2373 return true;
2374 }
2375 }
2376 }
2377 return false;
2378}
2379
2380////////////////////////////////////////////////////////////////////////////////
2381
2382const clang::DeclContext *GetEnclosingSpace(const clang::RecordDecl &cl)
2383{
2384 const clang::DeclContext *ctxt = cl.getDeclContext();
2385 while(ctxt && !ctxt->isNamespace()) {
2386 ctxt = ctxt->getParent();
2387 }
2388 return ctxt;
2389}
2390
2391////////////////////////////////////////////////////////////////////////////////
2392/// Write all the necessary opening part of the namespace and
2393/// return the number of closing brackets needed
2394/// For example for Space1::Space2
2395/// we write: namespace Space1 { namespace Space2 {
2396/// and return 2.
2397
2398int ROOT::TMetaUtils::WriteNamespaceHeader(std::ostream &out, const clang::DeclContext *ctxt)
2399{
2400 int closing_brackets = 0;
2401
2402 //fprintf(stderr,"DEBUG: in WriteNamespaceHeader for %s with %s\n",
2403 // cl.Fullname(),namespace_obj.Fullname());
2404 if (ctxt && ctxt->isNamespace()) {
2405 closing_brackets = WriteNamespaceHeader(out,ctxt->getParent());
2406 const clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(ctxt);
2407 if (ns) {
2408 for (int indent = 0; indent < closing_brackets; ++indent)
2409 out << " ";
2410 if (ns->isInline())
2411 out << "inline ";
2412 out << "namespace " << ns->getNameAsString() << " {" << std::endl;
2414 }
2415 }
2416
2417 return closing_brackets;
2418}
2419
2420////////////////////////////////////////////////////////////////////////////////
2421
2422int ROOT::TMetaUtils::WriteNamespaceHeader(std::ostream &out, const clang::RecordDecl *cl)
2423{
2424 return WriteNamespaceHeader(out, GetEnclosingSpace(*cl));
2425}
2426
2427////////////////////////////////////////////////////////////////////////////////
2428
2429bool ROOT::TMetaUtils::NeedTemplateKeyword(const clang::CXXRecordDecl *cl)
2430{
2431 clang::TemplateSpecializationKind kind = cl->getTemplateSpecializationKind();
2432 if (kind == clang::TSK_Undeclared ) {
2433 // Note a template;
2434 return false;
2435 } else if (kind == clang::TSK_ExplicitSpecialization) {
2436 // This is a specialized templated class
2437 return false;
2438 } else {
2439 // This is an automatically or explicitly instantiated templated class.
2440 return true;
2441 }
2442}
2443
2444////////////////////////////////////////////////////////////////////////////////
2445/// return true if we can find a custom operator new with placement
2446
2447bool ROOT::TMetaUtils::HasCustomOperatorNewPlacement(const char *which, const clang::RecordDecl &cl, const cling::Interpreter &interp)
2448{
2449 const char *name = which;
2450 const char *proto = "size_t";
2451 const char *protoPlacement = "size_t,void*";
2452
2453 // First search in the enclosing namespaces
2454 const clang::FunctionDecl *operatornew
2455 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl.getDeclContext()),
2456 name, proto, interp,
2457 cling::LookupHelper::NoDiagnostics);
2458 const clang::FunctionDecl *operatornewPlacement
2459 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl.getDeclContext()),
2461 cling::LookupHelper::NoDiagnostics);
2462
2463 const clang::DeclContext *ctxtnew = nullptr;
2464 const clang::DeclContext *ctxtnewPlacement = nullptr;
2465
2466 if (operatornew) {
2467 ctxtnew = operatornew->getParent();
2468 }
2471 }
2472
2473 // Then in the class and base classes
2475 false /*diags*/);
2478 false /*diags*/);
2479
2480 if (operatornew) {
2481 ctxtnew = operatornew->getParent();
2482 }
2485 }
2486
2487 if (!ctxtnewPlacement) {
2488 return false;
2489 }
2490 if (!ctxtnew) {
2491 // Only a new with placement, no hiding
2492 return true;
2493 }
2494 // Both are non zero
2495 if (ctxtnew == ctxtnewPlacement) {
2496 // Same declaration ctxt, no hiding
2497 return true;
2498 }
2499 const clang::CXXRecordDecl* clnew = llvm::dyn_cast<clang::CXXRecordDecl>(ctxtnew);
2500 const clang::CXXRecordDecl* clnewPlacement = llvm::dyn_cast<clang::CXXRecordDecl>(ctxtnewPlacement);
2501 if (!clnew && !clnewPlacement) {
2502 // They are both in different namespaces, I am not sure of the rules.
2503 // we probably ought to find which one is closest ... for now bail
2504 // (because rootcling was also bailing on that).
2505 return true;
2506 }
2507 if (clnew && !clnewPlacement) {
2508 // operator new is class method hiding the outer scope operator new with placement.
2509 return false;
2510 }
2511 if (!clnew && clnewPlacement) {
2512 // operator new is a not class method and can not hide new with placement which is a method
2513 return true;
2514 }
2515 // Both are class methods
2516 if (clnew->isDerivedFrom(clnewPlacement)) {
2517 // operator new is in a more derived part of the hierarchy, it is hiding operator new with placement.
2518 return false;
2519 }
2520 // operator new with placement is in a more derived part of the hierarchy, it can't be hidden by operator new.
2521 return true;
2522}
2523
2524////////////////////////////////////////////////////////////////////////////////
2525/// return true if we can find a custom operator new with placement
2526
2527bool ROOT::TMetaUtils::HasCustomOperatorNewPlacement(const clang::RecordDecl &cl, const cling::Interpreter &interp)
2528{
2529 return HasCustomOperatorNewPlacement("operator new",cl, interp);
2530}
2531
2532////////////////////////////////////////////////////////////////////////////////
2533/// return true if we can find a custom operator new with placement
2534
2535bool ROOT::TMetaUtils::HasCustomOperatorNewArrayPlacement(const clang::RecordDecl &cl, const cling::Interpreter &interp)
2536{
2537 return HasCustomOperatorNewPlacement("operator new[]",cl, interp);
2538}
2539
2540////////////////////////////////////////////////////////////////////////////////
2541/// std::string NormalizedName;
2542/// GetNormalizedName(NormalizedName, decl->getASTContext().getTypeDeclType(decl), interp, normCtxt);
2543
2545 const AnnotatedRecordDecl &cl,
2546 const clang::CXXRecordDecl *decl,
2547 const cling::Interpreter &interp,
2550{
2551 std::string classname = TClassEdit::GetLong64_Name(cl.GetNormalizedName());
2552
2553 std::string mappedname;
2554 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
2555
2556 // Write the functions that are need for the TGenericClassInfo.
2557 // This includes
2558 // IsA
2559 // operator new
2560 // operator new[]
2561 // operator delete
2562 // operator delete[]
2563
2564 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
2565
2566 if ( ! TClassEdit::IsStdClass( classname.c_str() ) ) {
2567
2568 // Prefix the full class name with '::' except for the STL
2569 // containers and std::string. This is to request the
2570 // real class instead of the class in the namespace ROOT::Shadow
2571 classname.insert(0,"::");
2572 }
2573
2574 finalString << "namespace ROOT {" << "\n";
2575
2576 std::string args;
2577 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
2578 // write the constructor wrapper only for concrete classes
2579 finalString << " // Wrappers around operator new" << "\n";
2580 finalString << " static void *new_" << mappedname.c_str() << "(void *p) {" << "\n" << " return p ? ";
2582 finalString << "new(p) ";
2583 finalString << classname.c_str();
2584 finalString << args;
2585 finalString << " : ";
2586 } else {
2587 finalString << "::new(static_cast<::ROOT::Internal::TOperatorNewHelper*>(p)) ";
2588 finalString << classname.c_str();
2589 finalString << args;
2590 finalString << " : ";
2591 }
2592 finalString << "new " << classname.c_str() << args << ";" << "\n";
2593 finalString << " }" << "\n";
2594
2595 if (args.size()==0 && NeedDestructor(decl, interp)) {
2596 // Can not can newArray if the destructor is not public.
2597 finalString << " static void *newArray_";
2598 finalString << mappedname.c_str();
2599 finalString << "(Long_t nElements, void *p) {";
2600 finalString << "\n";
2601 finalString << " return p ? ";
2603 finalString << "new(p) ";
2604 finalString << classname.c_str();
2605 finalString << "[nElements] : ";
2606 } else {
2607 finalString << "::new(static_cast<::ROOT::Internal::TOperatorNewHelper*>(p)) ";
2608 finalString << classname.c_str();
2609 finalString << "[nElements] : ";
2610 }
2611 finalString << "new ";
2612 finalString << classname.c_str();
2613 finalString << "[nElements];";
2614 finalString << "\n";
2615 finalString << " }";
2616 finalString << "\n";
2617 }
2618 }
2619
2620 if (NeedDestructor(decl, interp)) {
2621 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";
2622 }
2623
2625 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";
2626 }
2627
2629 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";
2630 }
2631
2633 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";
2634 }
2635
2636 if (HasNewMerge(decl, interp)) {
2637 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";
2638 } else if (HasOldMerge(decl, interp)) {
2639 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";
2640 }
2641
2643 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";
2644 }
2645 finalString << "} // end of namespace ROOT for class " << classname.c_str() << "\n" << "\n";
2646}
2647
2648////////////////////////////////////////////////////////////////////////////////
2649/// Write interface function for STL members
2650
2652 const cling::Interpreter &interp,
2654{
2655 std::string a;
2656 std::string clName;
2657 TMetaUtils::GetCppName(clName, ROOT::TMetaUtils::GetFileName(*cl.GetRecordDecl(), interp).c_str());
2659 if (version == 0) return;
2660 if (version < 0 && !(cl.RequestStreamerInfo()) ) return;
2661
2662
2663 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
2664 if (!clxx) return;
2665
2666 // We also need to look at the base classes.
2667 for(clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
2668 iter != end;
2669 ++iter)
2670 {
2671 int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
2672 if (k!=0) {
2673 Internal::RStl::Instance().GenerateTClassFor( iter->getType(), interp, normCtxt);
2674 }
2675 }
2676
2677 // Loop over the non static data member.
2678 for(clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
2679 field_iter != end;
2680 ++field_iter)
2681 {
2682 std::string mTypename;
2684
2685 //member is a string
2686 {
2688 if (!strcmp(shortTypeName, "string")) {
2689 continue;
2690 }
2691 }
2692
2694
2696 if (k!=0) {
2697 // fprintf(stderr,"Add %s which is also",m.Type()->Name());
2698 // fprintf(stderr," %s\n",R__TrueName(**field_iter) );
2699 clang::QualType utype(ROOT::TMetaUtils::GetUnderlyingType(field_iter->getType()),0);
2700 Internal::RStl::Instance().GenerateTClassFor(utype, interp, normCtxt);
2701 }
2702 }
2703}
2704
2705////////////////////////////////////////////////////////////////////////////////
2706/// TrueName strips the typedefs and array dimensions.
2707
2708std::string ROOT::TMetaUtils::TrueName(const clang::FieldDecl &m)
2709{
2710 const clang::Type *rawtype = m.getType()->getCanonicalTypeInternal().getTypePtr();
2711 if (rawtype->isArrayType()) {
2712 rawtype = rawtype->getBaseElementTypeUnsafe ();
2713 }
2714
2715 std::string result;
2716 ROOT::TMetaUtils::GetQualifiedName(result, clang::QualType(rawtype,0), m);
2717 return result;
2718}
2719
2720////////////////////////////////////////////////////////////////////////////////
2721/// Return the version number of the class or -1
2722/// if the function Class_Version does not exist.
2723
2724int ROOT::TMetaUtils::GetClassVersion(const clang::RecordDecl *cl, const cling::Interpreter& interp)
2725{
2726 const clang::CXXRecordDecl* CRD = llvm::dyn_cast<clang::CXXRecordDecl>(cl);
2727 if (!CRD) {
2728 // Must be an enum or namespace.
2729 // FIXME: Make it work for a namespace!
2730 return -1;
2731 }
2732 const clang::FunctionDecl* funcCV = ROOT::TMetaUtils::ClassInfo__HasMethod(CRD,"Class_Version",interp);
2733
2734 // if we have no Class_Info() return -1.
2735 if (!funcCV) return -1;
2736
2737 // if we have many Class_Info() (?!) return 1.
2738 if (funcCV == (clang::FunctionDecl*)-1) return 1;
2739
2741}
2742
2743////////////////////////////////////////////////////////////////////////////////
2744/// If the function contains 'just': return SomeValue;
2745/// this routine will extract this value and return it.
2746/// The first element is set to true we have the body of the function and it
2747/// is indeed a trivial function with just a return of a value.
2748/// The second element contains the value (or -1 is case of failure)
2749
2750std::pair<bool, int>
2751ROOT::TMetaUtils::GetTrivialIntegralReturnValue(const clang::FunctionDecl *funcCV, const cling::Interpreter &interp)
2752{
2753 using res_t = std::pair<bool, int>;
2754
2755 const clang::CompoundStmt* FuncBody
2756 = llvm::dyn_cast_or_null<clang::CompoundStmt>(funcCV->getBody());
2757 if (!FuncBody)
2758 return res_t{false, -1};
2759 if (FuncBody->size() != 1) {
2760 // This is a non-ClassDef(), complex function - it might depend on state
2761 // and thus we'll need the runtime and cannot determine the result
2762 // statically.
2763 return res_t{false, -1};
2764 }
2765 const clang::ReturnStmt* RetStmt
2766 = llvm::dyn_cast<clang::ReturnStmt>(FuncBody->body_back());
2767 if (!RetStmt)
2768 return res_t{false, -1};
2769 const clang::Expr* RetExpr = RetStmt->getRetValue();
2770 // ClassDef controls the content of Class_Version() but not the return
2771 // expression which is CPP expanded from what the user provided as second
2772 // ClassDef argument. It's usually just be an integer literal but it could
2773 // also be an enum or a variable template for all we know.
2774 // Go through ICE to be more general.
2775 if (auto RetRes = RetExpr->getIntegerConstantExpr(funcCV->getASTContext())) {
2776 if (RetRes->isSigned())
2777 return res_t{true, (Version_t)RetRes->getSExtValue()};
2778 return res_t{true, (Version_t)RetRes->getZExtValue()};
2779 }
2780 return res_t{false, -1};
2781}
2782
2783////////////////////////////////////////////////////////////////////////////////
2784/// Is this an STL container.
2785
2787{
2788 return TMetaUtils::IsSTLCont(*annotated.GetRecordDecl());
2789}
2790
2791////////////////////////////////////////////////////////////////////////////////
2792/// Is this an STL container?
2793
2795{
2796 clang::QualType type = m.getType();
2798
2799 if (decl) return TMetaUtils::IsSTLCont(*decl);
2800 else return ROOT::kNotSTL;
2801}
2802
2803////////////////////////////////////////////////////////////////////////////////
2804/// Is this an STL container?
2805
2806int ROOT::TMetaUtils::IsSTLContainer(const clang::CXXBaseSpecifier &base)
2807{
2808 clang::QualType type = base.getType();
2810
2811 if (decl) return TMetaUtils::IsSTLCont(*decl);
2812 else return ROOT::kNotSTL;
2813}
2814
2815////////////////////////////////////////////////////////////////////////////////
2816/// Calls the given lambda on every header in the given module.
2817/// includeDirectlyUsedModules designates if the foreach should also loop over
2818/// the headers in all modules that are directly used via a `use` declaration
2819/// in the modulemap.
2821 const std::function<void(const clang::Module::Header &)> &closure,
2823{
2824 // Iterates over all headers in a module and calls the closure on each.
2825
2826 // Make a list of modules and submodules that we can check for headers.
2827 // We use a SetVector to prevent an infinite loop in unlikely case the
2828 // modules somehow are messed up and don't form a tree...
2829 llvm::SetVector<const clang::Module *> modules;
2830 modules.insert(&module);
2831 for (size_t i = 0; i < modules.size(); ++i) {
2832 const clang::Module *M = modules[i];
2833 for (const clang::Module *subModule : M->submodules())
2834 modules.insert(subModule);
2835 }
2836
2837 for (const clang::Module *m : modules) {
2839 for (clang::Module *used : m->DirectUses) {
2841 }
2842 }
2843
2844 // We want to check for all headers except the list of excluded headers here.
2845 for (auto HK : {clang::Module::HK_Normal, clang::Module::HK_Textual, clang::Module::HK_Private,
2846 clang::Module::HK_PrivateTextual}) {
2847 const auto &headerList = m->getHeaders(HK);
2848 for (const clang::Module::Header &moduleHeader : headerList) {
2850 }
2851 }
2852 }
2853}
2854
2855////////////////////////////////////////////////////////////////////////////////
2856/// Return the absolute type of typeDesc.
2857/// E.g.: typeDesc = "class TNamed**", returns "TNamed".
2858/// we remove * and const keywords. (we do not want to remove & ).
2859/// You need to use the result immediately before it is being overwritten.
2860
2862{
2863 static char t[4096];
2864 static const char* constwd = "const ";
2865 static const char* constwdend = "const";
2866
2867 const char *s;
2868 char *p=t;
2869 int lev=0;
2870 for (s=typeDesc;*s;s++) {
2871 if (*s=='<') lev++;
2872 if (*s=='>') lev--;
2873 if (lev==0 && *s=='*') continue;
2874 if (lev==0 && (strncmp(constwd,s,strlen(constwd))==0
2875 ||strcmp(constwdend,s)==0 ) ) {
2876 s+=strlen(constwd)-1; // -1 because the loop adds 1
2877 continue;
2878 }
2879 if (lev==0 && *s==' ' && *(s+1)!='*') { p = t; continue;}
2880 if (p - t > (long)sizeof(t)) {
2881 printf("ERROR (rootcling): type name too long for StortTypeName: %s\n",
2882 typeDesc);
2883 p[0] = 0;
2884 return t;
2885 }
2886 *p++ = *s;
2887 }
2888 p[0]=0;
2889
2890 return t;
2891}
2892
2893bool ROOT::TMetaUtils::IsStreamableObject(const clang::FieldDecl &m,
2894 const cling::Interpreter& interp)
2895{
2896 auto comment = ROOT::TMetaUtils::GetComment( m );
2897
2898 // Transient
2899 if (!comment.empty() && comment[0] == '!')
2900 return false;
2901
2902 clang::QualType type = m.getType();
2903
2904 if (type->isReferenceType()) {
2905 // Reference can not be streamed.
2906 return false;
2907 }
2908
2909 std::string mTypeName = type.getAsString(m.getASTContext().getPrintingPolicy());
2910 if (!strcmp(mTypeName.c_str(), "string") || !strcmp(mTypeName.c_str(), "string*")) {
2911 return true;
2912 }
2913 if (!strcmp(mTypeName.c_str(), "std::string") || !strcmp(mTypeName.c_str(), "std::string*")) {
2914 return true;
2915 }
2916
2918 return true;
2919 }
2920
2921 const clang::Type *rawtype = type.getTypePtr()->getBaseElementTypeUnsafe ();
2922
2923 if (rawtype->isPointerType()) {
2924 //Get to the 'raw' type.
2925 clang::QualType pointee;
2926 while ( (pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull() && pointee.getTypePtr() != rawtype)
2927 {
2928 rawtype = pointee.getTypePtr();
2929 }
2930 }
2931
2932 if (rawtype->isFundamentalType() || rawtype->isEnumeralType()) {
2933 // not an ojbect.
2934 return false;
2935 }
2936
2937 const clang::CXXRecordDecl *cxxdecl = rawtype->getAsCXXRecordDecl();
2939 if (!(ROOT::TMetaUtils::ClassInfo__HasMethod(cxxdecl,"Class_Version", interp))) return true;
2941 if (version > 0) return true;
2942 }
2943 return false;
2944}
2945
2946////////////////////////////////////////////////////////////////////////////////
2947/// Return the absolute type of typeDesc.
2948/// E.g.: typeDesc = "class TNamed**", returns "TNamed".
2949/// we remove * and const keywords. (we do not want to remove & ).
2950/// You need to use the result immediately before it is being overwritten.
2951
2952std::string ROOT::TMetaUtils::ShortTypeName(const clang::FieldDecl &m)
2953{
2954 const clang::Type *rawtype = m.getType().getTypePtr();
2955
2956 //Get to the 'raw' type.
2957 clang::QualType pointee;
2958 while ( rawtype->isPointerType() && ((pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull()) && pointee.getTypePtr() != rawtype)
2959 {
2960 rawtype = pointee.getTypePtr();
2961 }
2962
2963 std::string result;
2964 ROOT::TMetaUtils::GetQualifiedName(result, clang::QualType(rawtype,0), m);
2965 return result;
2966}
2967
2968////////////////////////////////////////////////////////////////////////////////
2969
2970clang::RecordDecl *ROOT::TMetaUtils::GetUnderlyingRecordDecl(clang::QualType type)
2971{
2972 const clang::Type *rawtype = ROOT::TMetaUtils::GetUnderlyingType(type);
2973
2974 if (rawtype->isFundamentalType() || rawtype->isEnumeralType()) {
2975 // not an object.
2976 return nullptr;
2977 }
2978 return rawtype->getAsCXXRecordDecl();
2979}
2980
2981////////////////////////////////////////////////////////////////////////////////
2982/// Generate the code of the class
2983/// If the requestor is genreflex, request the new streamer format
2984
2986 const AnnotatedRecordDecl &cl,
2987 const cling::Interpreter &interp,
2989 std::ostream& dictStream,
2991 bool isGenreflex=false)
2992{
2993 const clang::CXXRecordDecl* decl = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
2994
2995 if (!decl || !decl->isCompleteDefinition()) {
2996 return;
2997 }
2998
2999 std::string fullname;
3001 if (TClassEdit::IsSTLCont(fullname) ) {
3002 Internal::RStl::Instance().GenerateTClassFor(cl.GetNormalizedName(), llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl()), interp, normCtxt);
3003 return;
3004 }
3005
3007 // The !genreflex is there to prevent genreflex to select collections which are data members
3008 // This is to maintain the behaviour of ROOT5 and ROOT6 up to 6.07 included.
3009 if (cl.RootFlag() && !isGenreflex) ROOT::TMetaUtils::WritePointersSTL(cl, interp, normCtxt); // In particular this detect if the class has a version number.
3010 if (!(cl.RequestNoStreamer())) {
3011 (*WriteStreamerFunc)(cl, interp, normCtxt, dictStream, isGenreflex || cl.RequestStreamerInfo());
3012 } else
3013 ROOT::TMetaUtils::Info(nullptr, "Class %s: Do not generate Streamer() [*** custom streamer ***]\n",fullname.c_str());
3014 } else {
3015 ROOT::TMetaUtils::Info(nullptr, "Class %s: Streamer() not declared\n", fullname.c_str());
3016
3017 // See comment above about the !isGenreflex
3019 }
3021}
3022
3023////////////////////////////////////////////////////////////////////////////////
3024/// Add any unspecified template parameters to the class template instance,
3025/// mentioned anywhere in the type.
3026///
3027/// Note: this does not strip any typedef but could be merged with cling::utils::Transform::GetPartiallyDesugaredType
3028/// if we can safely replace TClassEdit::IsStd with a test on the declaring scope
3029/// and if we can resolve the fact that the added parameter do not take into account possible use/dependences on Double32_t
3030/// and if we decide that adding the default is the right long term solution or not.
3031/// Whether it is or not depend on the I/O on whether the default template argument might change or not
3032/// and whether they (should) affect the on disk layout (for STL containers, we do know they do not).
3033
3035 const cling::Interpreter &interpreter,
3037{
3038 const clang::ASTContext& Ctx = interpreter.getCI()->getASTContext();
3039
3040 clang::QualType originalType = instanceType;
3041
3042 // In case of name* we need to strip the pointer first, add the default and attach
3043 // the pointer once again.
3044 if (llvm::isa<clang::PointerType>(instanceType.getTypePtr())) {
3045 // Get the qualifiers.
3046 clang::Qualifiers quals = instanceType.getQualifiers();
3047 clang::QualType newPointee = AddDefaultParameters(instanceType->getPointeeType(), interpreter, normCtxt);
3048 if (newPointee != instanceType->getPointeeType()) {
3049 instanceType = Ctx.getPointerType(newPointee);
3050 // Add back the qualifiers.
3051 instanceType = Ctx.getQualifiedType(instanceType, quals);
3052 }
3053 return instanceType;
3054 }
3055
3056 // In case of Int_t& we need to strip the pointer first, desugar and attach
3057 // the pointer once again.
3058 if (llvm::isa<clang::ReferenceType>(instanceType.getTypePtr())) {
3059 // Get the qualifiers.
3060 bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(instanceType.getTypePtr());
3061 clang::Qualifiers quals = instanceType.getQualifiers();
3062 clang::QualType newPointee = AddDefaultParameters(instanceType->getPointeeType(), interpreter, normCtxt);
3063
3064 if (newPointee != instanceType->getPointeeType()) {
3065 // Add the r- or l- value reference type back to the desugared one
3066 if (isLValueRefTy)
3067 instanceType = Ctx.getLValueReferenceType(newPointee);
3068 else
3069 instanceType = Ctx.getRValueReferenceType(newPointee);
3070 // Add back the qualifiers.
3071 instanceType = Ctx.getQualifiedType(instanceType, quals);
3072 }
3073 return instanceType;
3074 }
3075
3076 // Treat the Scope.
3077 bool prefix_changed = false;
3078 clang::NestedNameSpecifier *prefix = nullptr;
3079 clang::Qualifiers prefix_qualifiers = instanceType.getLocalQualifiers();
3080 const clang::ElaboratedType* etype
3081 = llvm::dyn_cast<clang::ElaboratedType>(instanceType.getTypePtr());
3082 if (etype) {
3083 // We have to also handle the prefix.
3084 prefix = AddDefaultParametersNNS(Ctx, etype->getQualifier(), interpreter, normCtxt);
3085 prefix_changed = prefix != etype->getQualifier();
3086 instanceType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3087 }
3088
3089 // In case of template specializations iterate over the arguments and
3090 // add unspecified default parameter.
3091
3092 const clang::TemplateSpecializationType* TST
3093 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instanceType.getTypePtr());
3094
3095 const clang::ClassTemplateSpecializationDecl* TSTdecl
3096 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(instanceType.getTypePtr()->getAsCXXRecordDecl());
3097
3098 // Don't add the default paramater onto std classes.
3099 // We really need this for __shared_ptr which add a enum constant value which
3100 // is spelled in its 'numeral' form and thus the resulting type name is
3101 // incorrect. We also can used this for any of the STL collections where we
3102 // know we don't want the default argument. For the other members of the
3103 // std namespace this is dubious (because TMetaUtils::GetNormalizedName would
3104 // not drop those defaults). [I.e. the real test ought to be is std and
3105 // name is __shared_ptr or vector or list or set or etc.]
3107
3108 bool mightHaveChanged = false;
3109 if (TST && TSTdecl) {
3110
3111 clang::Sema& S = interpreter.getCI()->getSema();
3112 clang::TemplateDecl *Template = TSTdecl->getSpecializedTemplate()->getMostRecentDecl();
3113 clang::TemplateParameterList *Params = Template->getTemplateParameters();
3114 clang::TemplateParameterList::iterator Param = Params->begin(); // , ParamEnd = Params->end();
3115 //llvm::SmallVectorImpl<TemplateArgument> Converted; // Need to contains the other arguments.
3116 // Converted seems to be the same as our 'desArgs'
3117
3118 unsigned int dropDefault = normCtxt.GetConfig().DropDefaultArg(*Template);
3119
3120 llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
3121 llvm::SmallVector<clang::TemplateArgument, 4> canonArgs;
3122 llvm::ArrayRef<clang::TemplateArgument> template_arguments = TST->template_arguments();
3123 unsigned int Idecl = 0, Edecl = TSTdecl->getTemplateArgs().size();
3124 // If we have more arguments than the TSTdecl, it is a variadic template
3125 // and we want all template arguments.
3126 if (template_arguments.size() > Edecl) {
3127 Edecl = template_arguments.size();
3128 }
3129 unsigned int maxAddArg = Edecl - dropDefault;
3130 for (const clang::TemplateArgument *I = template_arguments.begin(), *E = template_arguments.end(); Idecl != Edecl;
3131 I != E ? ++I : nullptr, ++Idecl, ++Param) {
3132
3133 if (I != E) {
3134
3135 if (I->getKind() == clang::TemplateArgument::Template) {
3136 clang::TemplateName templateName = I->getAsTemplate();
3137 clang::TemplateDecl* templateDecl = templateName.getAsTemplateDecl();
3138 if (templateDecl) {
3139 clang::DeclContext* declCtxt = templateDecl->getDeclContext();
3140
3141 if (declCtxt && !templateName.getAsQualifiedTemplateName()){
3142 clang::NamespaceDecl* ns = clang::dyn_cast<clang::NamespaceDecl>(declCtxt);
3143 clang::NestedNameSpecifier* nns;
3144 if (ns) {
3145 nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx, ns);
3146 } else if (clang::TagDecl* TD = llvm::dyn_cast<clang::TagDecl>(declCtxt)) {
3147 nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx,TD, false /*FullyQualified*/);
3148 } else {
3149 // TU scope
3150 desArgs.push_back(*I);
3151 continue;
3152 }
3153 clang::TemplateName UnderlyingTN(templateDecl);
3154 if (clang::UsingShadowDecl *USD = templateName.getAsUsingShadowDecl())
3155 UnderlyingTN = clang::TemplateName(USD);
3156 clang::TemplateName templateNameWithNSS ( Ctx.getQualifiedTemplateName(nns, false, UnderlyingTN) );
3157 desArgs.push_back(clang::TemplateArgument(templateNameWithNSS));
3158 mightHaveChanged = true;
3159 continue;
3160 }
3161 }
3162 }
3163
3164 if (I->getKind() != clang::TemplateArgument::Type) {
3165 desArgs.push_back(*I);
3166 continue;
3167 }
3168
3169 clang::QualType SubTy = I->getAsType();
3170
3171 // Check if the type needs more desugaring and recurse.
3172 // (Originally this was limited to elaborated and templated type,
3173 // but we also need to do it for pointer and reference type
3174 // and who knows what, so do it always)
3175 clang::QualType newSubTy = AddDefaultParameters(SubTy,
3177 normCtxt);
3178 if (SubTy != newSubTy) {
3179 mightHaveChanged = true;
3180 desArgs.push_back(clang::TemplateArgument(newSubTy));
3181 } else {
3182 desArgs.push_back(*I);
3183 }
3184 // Converted.push_back(TemplateArgument(ArgTypeForTemplate));
3185 } else if (!isStdDropDefault && Idecl < maxAddArg) {
3186
3187 mightHaveChanged = true;
3188
3189 const clang::TemplateArgument& templateArg
3190 = TSTdecl->getTemplateArgs().get(Idecl);
3191 if (templateArg.getKind() != clang::TemplateArgument::Type) {
3192 desArgs.push_back(templateArg);
3193 continue;
3194 }
3195 clang::QualType SubTy = templateArg.getAsType();
3196
3197 clang::SourceLocation TemplateLoc = Template->getSourceRange ().getBegin(); //NOTE: not sure that this is the 'right' location.
3198 clang::SourceLocation RAngleLoc = TSTdecl->getSourceRange().getBegin(); // NOTE: most likely wrong, I think this is expecting the location of right angle
3199
3200 clang::TemplateTypeParmDecl *TTP = llvm::dyn_cast<clang::TemplateTypeParmDecl>(*Param);
3201 {
3202 // We may induce template instantiation
3203 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
3204 bool HasDefaultArgs;
3205 clang::TemplateArgumentLoc ArgType = S.SubstDefaultTemplateArgumentIfAvailable(
3206 Template,
3208 RAngleLoc,
3209 TTP,
3210 desArgs,
3211 canonArgs,
3213 // The substition can fail, in which case there would have been compilation
3214 // error printed on the screen.
3215 if (ArgType.getArgument().isNull()
3216 || ArgType.getArgument().getKind() != clang::TemplateArgument::Type) {
3217 ROOT::TMetaUtils::Error("ROOT::TMetaUtils::AddDefaultParameters",
3218 "Template parameter substitution failed for %s around %s\n",
3219 instanceType.getAsString().c_str(), SubTy.getAsString().c_str());
3220 break;
3221 }
3222 clang::QualType BetterSubTy = ArgType.getArgument().getAsType();
3223 SubTy = cling::utils::Transform::GetPartiallyDesugaredType(Ctx,BetterSubTy,normCtxt.GetConfig(),/*fullyQualified=*/ true);
3224 }
3226 desArgs.push_back(clang::TemplateArgument(SubTy));
3227 } else {
3228 // We are past the end of the list of specified arguements and we
3229 // do not want to add the default, no need to continue.
3230 break;
3231 }
3232 }
3233
3234 // If we added default parameter, allocate new type in the AST.
3235 if (mightHaveChanged) {
3236 instanceType = Ctx.getTemplateSpecializationType(TST->getTemplateName(),
3237 desArgs,
3238 TST->getCanonicalTypeInternal());
3239 }
3240 }
3241
3243 if (prefix) {
3244 instanceType = Ctx.getElaboratedType(clang::ElaboratedTypeKeyword::None, prefix, instanceType);
3245 instanceType = Ctx.getQualifiedType(instanceType,prefix_qualifiers);
3246 }
3247 return instanceType;
3248}
3249
3250////////////////////////////////////////////////////////////////////////////////
3251/// ValidArrayIndex return a static string (so use it or copy it immediatly, do not
3252/// call GrabIndex twice in the same expression) containing the size of the
3253/// array data member.
3254/// In case of error, or if the size is not specified, GrabIndex returns 0.
3255/// If errnum is not null, *errnum updated with the error number:
3256/// Cint::G__DataMemberInfo::G__VALID : valid array index
3257/// Cint::G__DataMemberInfo::G__NOT_INT : array index is not an int
3258/// Cint::G__DataMemberInfo::G__NOT_DEF : index not defined before array
3259/// (this IS an error for streaming to disk)
3260/// Cint::G__DataMemberInfo::G__IS_PRIVATE: index exist in a parent class but is private
3261/// Cint::G__DataMemberInfo::G__UNKNOWN : index is not known
3262/// If errstr is not null, *errstr is updated with the address of a static
3263/// string containing the part of the index with is invalid.
3264
3265llvm::StringRef ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(const cling::Interpreter &interp, const clang::DeclaratorDecl &m, int *errnum, llvm::StringRef *errstr)
3266{
3267 llvm::StringRef title;
3268
3269 // Try to get the comment either from the annotation or the header file if present
3270 if (clang::AnnotateAttr *A = m.getAttr<clang::AnnotateAttr>())
3271 title = A->getAnnotation();
3272 else
3273 // Try to get the comment from the header file if present
3275
3276 // Let's see if the user provided us with some information
3277 // with the format: //[dimension] this is the dim of the array
3278 // dimension can be an arithmetical expression containing, literal integer,
3279 // the operator *,+ and - and data member of integral type. In addition the
3280 // data members used for the size of the array need to be defined prior to
3281 // the array.
3282
3283 if (errnum) *errnum = VALID;
3284
3285 if (title.size() == 0 || (title[0] != '[')) return llvm::StringRef();
3286 size_t rightbracket = title.find(']');
3287 if (rightbracket == llvm::StringRef::npos) return llvm::StringRef();
3288
3289 std::string working;
3290 llvm::StringRef indexvar(title.data()+1,rightbracket-1);
3291
3292 // now we should have indexvar=dimension
3293 // Let's see if this is legal.
3294 // which means a combination of data member and digit separated by '*','+','-'
3295 // First we remove white spaces.
3296 unsigned int i;
3297 size_t indexvarlen = indexvar.size();
3298 for ( i=0; i<indexvarlen; i++) {
3299 if (!isspace(indexvar[i])) {
3300 working += indexvar[i];
3301 }
3302 }
3303
3304 // Now we go through all indentifiers
3305 const char *tokenlist = "*+-";
3306 char *current = const_cast<char*>(working.c_str());
3307 current = strtok(current,tokenlist); // this method does not need to be reentrant
3308
3309 while (current) {
3310 // Check the token
3311 if (isdigit(current[0])) {
3312 for(i=0;i<strlen(current);i++) {
3313 if (!isdigit(current[i])) {
3314 // Error we only access integer.
3315 //NOTE: *** Need to print an error;
3316 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not an interger\n",
3317 // member.MemberOf()->Name(), member.Name(), current);
3318 if (errstr) *errstr = current;
3319 if (errnum) *errnum = NOT_INT;
3320 return llvm::StringRef();
3321 }
3322 }
3323 } else { // current token is not a digit
3324 // first let's see if it is a data member:
3325 const clang::CXXRecordDecl *parent_clxx = llvm::dyn_cast<clang::CXXRecordDecl>(m.getDeclContext());
3326 const clang::FieldDecl *index1 = nullptr;
3327 if (parent_clxx)
3329 if ( index1 ) {
3330 if ( IsFieldDeclInt(index1) ) {
3331 // Let's see if it has already been written down in the
3332 // Streamer.
3333 // Let's see if we already wrote it down in the
3334 // streamer.
3335 for(clang::RecordDecl::field_iterator field_iter = parent_clxx->field_begin(), end = parent_clxx->field_end();
3336 field_iter != end;
3337 ++field_iter)
3338 {
3339 if ( field_iter->getNameAsString() == m.getNameAsString() ) {
3340 // we reached the current data member before
3341 // reaching the index so we have not written it yet!
3342 //NOTE: *** Need to print an error;
3343 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) has not been defined before the array \n",
3344 // member.MemberOf()->Name(), member.Name(), current);
3345 if (errstr) *errstr = current;
3346 if (errnum) *errnum = NOT_DEF;
3347 return llvm::StringRef();
3348 }
3349 if ( field_iter->getNameAsString() == index1->getNameAsString() ) {
3350 break;
3351 }
3352 } // end of while (m_local.Next())
3353 } else {
3354 //NOTE: *** Need to print an error;
3355 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3356 // member.MemberOf()->Name(), member.Name(), current);
3357 if (errstr) *errstr = current;
3358 if (errnum) *errnum = NOT_INT;
3359 return llvm::StringRef();
3360 }
3361 } else {
3362 // There is no variable by this name in this class, let see
3363 // the base classes!:
3364 int found = 0;
3365 if (parent_clxx) {
3366 clang::Sema& SemaR = const_cast<cling::Interpreter&>(interp).getSema();
3368 }
3369 if ( index1 ) {
3370 if ( IsFieldDeclInt(index1) ) {
3371 found = 1;
3372 } else {
3373 // We found a data member but it is the wrong type
3374 //NOTE: *** Need to print an error;
3375 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3376 // member.MemberOf()->Name(), member.Name(), current);
3377 if (errnum) *errnum = NOT_INT;
3378 if (errstr) *errstr = current;
3379 //NOTE: *** Need to print an error;
3380 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3381 // member.MemberOf()->Name(), member.Name(), current);
3382 if (errnum) *errnum = NOT_INT;
3383 if (errstr) *errstr = current;
3384 return llvm::StringRef();
3385 }
3386 if ( found && (index1->getAccess() == clang::AS_private) ) {
3387 //NOTE: *** Need to print an error;
3388 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is a private member of %s \n",
3389 if (errstr) *errstr = current;
3390 if (errnum) *errnum = IS_PRIVATE;
3391 return llvm::StringRef();
3392 }
3393 }
3394 if (!found) {
3395 //NOTE: *** Need to print an error;
3396 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not known \n",
3397 // member.MemberOf()->Name(), member.Name(), indexvar);
3398 if (errstr) *errstr = indexvar;
3399 if (errnum) *errnum = UNKNOWN;
3400 return llvm::StringRef();
3401 } // end of if not found
3402 } // end of if is a data member of the class
3403 } // end of if isdigit
3404
3405 current = strtok(nullptr, tokenlist);
3406 } // end of while loop on tokens
3407
3408 return indexvar;
3409
3410}
3411
3412////////////////////////////////////////////////////////////////////////////////
3413/// Return (in the argument 'output') a valid name of the C++ symbol/type (pass as 'input')
3414/// that can be used in C++ as a variable name.
3415
3416void ROOT::TMetaUtils::GetCppName(std::string &out, const char *in)
3417{
3418 unsigned int i = 0;
3419 char c;
3420 out.clear();
3421 while((c = in[i++])) {
3422 const char *repl = nullptr;
3423 switch(c) {
3424 case '+': repl = "pL"; break;
3425 case '-': repl = "mI"; break;
3426 case '*': repl = "mU"; break;
3427 case '/': repl = "dI"; break;
3428 case '&': repl = "aN"; break;
3429 case '%': repl = "pE"; break;
3430 case '|': repl = "oR"; break;
3431 case '^': repl = "hA"; break;
3432 case '>': repl = "gR"; break;
3433 case '<': repl = "lE"; break;
3434 case '=': repl = "eQ"; break;
3435 case '~': repl = "wA"; break;
3436 case '.': repl = "dO"; break;
3437 case '(': repl = "oP"; break;
3438 case ')': repl = "cP"; break;
3439 case '[': repl = "oB"; break;
3440 case ']': repl = "cB"; break;
3441 case '{': repl = "lB"; break;
3442 case '}': repl = "rB"; break;
3443 case ';': repl = "sC"; break;
3444 case '#': repl = "hS"; break;
3445 case '?': repl = "qM"; break;
3446 case '`': repl = "bT"; break;
3447 case '!': repl = "nO"; break;
3448 case ',': repl = "cO"; break;
3449 case '$': repl = "dA"; break;
3450 case ' ': repl = "sP"; break;
3451 case ':': repl = "cL"; break;
3452 case '"': repl = "dQ"; break;
3453 case '@': repl = "aT"; break;
3454 case '\'': repl = "sQ"; break;
3455 case '\\': repl = "fI"; break;
3456 }
3457 if (repl)
3458 out.append(repl);
3459 else
3460 out.push_back(c);
3461 }
3462
3463 // If out is empty, or if it starts with a number, it's not a valid C++ variable. Prepend a "_"
3464 if (out.empty() || isdigit(out[0]))
3465 out.insert(out.begin(), '_');
3466}
3467
3468static clang::SourceLocation
3470 clang::SourceLocation sourceLoc) {
3471 // Follow macro expansion until we hit a source file.
3472 if (!sourceLoc.isFileID()) {
3473 return sourceManager.getExpansionRange(sourceLoc).getEnd();
3474 }
3475 return sourceLoc;
3476}
3477
3478////////////////////////////////////////////////////////////////////////////////
3479/// Return the header file to be included to declare the Decl.
3480
3481std::string ROOT::TMetaUtils::GetFileName(const clang::Decl& decl,
3482 const cling::Interpreter& interp)
3483{
3484 // It looks like the template specialization decl actually contains _less_ information
3485 // on the location of the code than the decl (in case where there is forward declaration,
3486 // that is what the specialization points to).
3487 //
3488 // const clang::CXXRecordDecl* clxx = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
3489 // if (clxx) {
3490 // switch(clxx->getTemplateSpecializationKind()) {
3491 // case clang::TSK_Undeclared:
3492 // // We want the default behavior
3493 // break;
3494 // case clang::TSK_ExplicitInstantiationDeclaration:
3495 // case clang::TSK_ExplicitInstantiationDefinition:
3496 // case clang::TSK_ImplicitInstantiation: {
3497 // // We want the location of the template declaration:
3498 // const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
3499 // if (tmplt_specialization) {
3500 // // return GetFileName(const_cast< clang::ClassTemplateSpecializationDecl *>(tmplt_specialization)->getSpecializedTemplate());
3501 // }
3502 // break;
3503 // }
3504 // case clang::TSK_ExplicitSpecialization:
3505 // // We want the default behavior
3506 // break;
3507 // default:
3508 // break;
3509 // }
3510 // }
3511
3512 using namespace clang;
3513 SourceLocation headerLoc = decl.getLocation();
3514
3515 static const char invalidFilename[] = "";
3516 if (!headerLoc.isValid()) return invalidFilename;
3517
3518 HeaderSearch& HdrSearch = interp.getCI()->getPreprocessor().getHeaderSearchInfo();
3519
3520 SourceManager& sourceManager = decl.getASTContext().getSourceManager();
3525 sourceManager.getIncludeLoc(headerFID));
3526
3527 OptionalFileEntryRef headerFE = sourceManager.getFileEntryRefForID(headerFID);
3528 while (includeLoc.isValid() && sourceManager.isInSystemHeader(includeLoc)) {
3530 // use HeaderSearch on the basename, to make sure it takes a header from
3531 // the include path (e.g. not from /usr/include/bits/)
3532 assert(headerFE && "Couldn't find FileEntry from FID!");
3533 auto FEhdr
3534 = HdrSearch.LookupFile(llvm::sys::path::filename(headerFE->getName()),
3536 true /*isAngled*/, nullptr/*FromDir*/, foundDir,
3537 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>>(),
3538 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3539 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3540 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/,
3541 false /*SkipCache*/,
3542 false /*BuildSystemModule*/,
3543 false /*OpenFile*/, true /*CacheFailures*/);
3544 if (FEhdr) break;
3545 headerFID = sourceManager.getFileID(includeLoc);
3546 headerFE = sourceManager.getFileEntryRefForID(headerFID);
3547 // If we have a system header in a module we can't just trace back the
3548 // original include with the preprocessor. But it should be enough if
3549 // we trace it back to the top-level system header that includes this
3550 // declaration.
3551 if (interp.getCI()->getLangOpts().Modules && !headerFE) {
3552 assert(decl.isFirstDecl() && "Couldn't trace back include from a decl"
3553 " that is not from an AST file");
3554 assert(StringRef(includeLoc.printToString(sourceManager)).starts_with("<module-includes>"));
3555 break;
3556 }
3558 sourceManager.getIncludeLoc(headerFID));
3559 }
3560
3561 if (!headerFE) return invalidFilename;
3562
3563 llvm::SmallString<256> headerFileName(headerFE->getName());
3564 // Remove double ../ from the path so that the search below finds a valid
3565 // longest match and does not result in growing paths.
3566 llvm::sys::path::remove_dots(headerFileName, /*remove_dot_dot=*/true);
3567
3568 // Now headerFID references the last valid system header or the original
3569 // user file.
3570 // Find out how to include it by matching file name to include paths.
3571 // We assume that the file "/A/B/C/D.h" can at some level be included as
3572 // "C/D.h". Be we cannot know whether that happens to be a different file
3573 // with the same name. Thus we first find the longest stem that can be
3574 // reached, say B/C/D.h. Then we find the shortest one, say C/D.h, that
3575 // points to the same file as the long version. If such a short version
3576 // exists it will be returned. If it doesn't the long version is returned.
3577 bool isAbsolute = llvm::sys::path::is_absolute(headerFileName);
3578 clang::OptionalFileEntryRef FELong;
3579 // Find the longest available match.
3580 for (llvm::sys::path::const_iterator
3581 IDir = llvm::sys::path::begin(headerFileName),
3582 EDir = llvm::sys::path::end(headerFileName);
3583 !FELong && IDir != EDir; ++IDir) {
3584 if (isAbsolute) {
3585 // skip "/" part
3586 isAbsolute = false;
3587 continue;
3588 }
3589 size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3590 llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3591 assert(trailingPart.data() + trailingPart.size()
3592 == headerFileName.data() + headerFileName.size()
3593 && "Mismatched partitioning of file name!");
3596 true /*isAngled*/, nullptr/*FromDir*/, FoundDir,
3597 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>>(),
3598 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3599 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3600 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/);
3601 }
3602
3603 if (!FELong) {
3604 // We did not find any file part in any search path.
3605 return invalidFilename;
3606 }
3607
3608 // Iterates through path *parts* "C"; we need trailing parts "C/D.h"
3609 for (llvm::sys::path::reverse_iterator
3610 IDir = llvm::sys::path::rbegin(headerFileName),
3611 EDir = llvm::sys::path::rend(headerFileName);
3612 IDir != EDir; ++IDir) {
3613 size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3614 llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3615 assert(trailingPart.data() + trailingPart.size()
3616 == headerFileName.data() + headerFileName.size()
3617 && "Mismatched partitioning of file name!");
3619 // Can we find it, and is it the same file as the long version?
3620 // (or are we back to the previously found spelling, which is fine, too)
3621 if (HdrSearch.LookupFile(trailingPart, SourceLocation(),
3622 true /*isAngled*/, nullptr/*FromDir*/, FoundDir,
3623 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>>(),
3624 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3625 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3626 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/) == FELong) {
3627 return trailingPart.str();
3628 }
3629 }
3630
3631 return invalidFilename;
3632}
3633
3634////////////////////////////////////////////////////////////////////////////////
3635
3637 const clang::QualType &qtype,
3638 const clang::ASTContext &astContext)
3639{
3640 std::string fqname = cling::utils::TypeName::GetFullyQualifiedName(qtype, astContext);
3644}
3645
3646////////////////////////////////////////////////////////////////////////////////
3647
3649 const clang::QualType &qtype,
3650 const cling::Interpreter &interpreter)
3651{
3652 // We need this because GetFullyQualifiedTypeName is triggering deserialization
3653 // This calling the same name function GetFullyQualifiedTypeName, but this should stay here because
3654 // callee doesn't have an interpreter pointer
3655 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
3656
3658 qtype,
3659 interpreter.getCI()->getASTContext());
3660}
3661
3662////////////////////////////////////////////////////////////////////////////////
3663/// Get the template specialisation decl and template decl behind the qualtype
3664/// Returns true if successfully found, false otherwise
3665
3666bool ROOT::TMetaUtils::QualType2Template(const clang::QualType& qt,
3667 clang::ClassTemplateDecl*& ctd,
3668 clang::ClassTemplateSpecializationDecl*& ctsd)
3669{
3670 using namespace clang;
3671 const Type* theType = qt.getTypePtr();
3672 if (!theType){
3673 ctd=nullptr;
3674 ctsd=nullptr;
3675 return false;
3676 }
3677
3678 if (theType->isPointerType()) {
3679 return QualType2Template(theType->getPointeeType(), ctd, ctsd);
3680 }
3681
3682 if (const RecordType* rType = llvm::dyn_cast<RecordType>(theType)) {
3683 ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(rType->getDecl());
3684 if (ctsd) {
3685 ctd = ctsd->getSpecializedTemplate();
3686 return true;
3687 }
3688 }
3689
3690 if (const SubstTemplateTypeParmType* sttpType = llvm::dyn_cast<SubstTemplateTypeParmType>(theType)){
3691 return QualType2Template(sttpType->getReplacementType(), ctd, ctsd);
3692 }
3693
3694
3695 ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(qt->getAsCXXRecordDecl());
3696 if(ctsd){
3697 ctd = ctsd->getSpecializedTemplate();
3698 return true;
3699 }
3700
3701 ctd=nullptr;
3702 ctsd=nullptr;
3703 return false;
3704}
3705
3706////////////////////////////////////////////////////////////////////////////////
3707/// Extract from a qualtype the class template if this makes sense.
3708/// Retuns the ClassTemplateDecl or nullptr otherwise.
3709
3710clang::ClassTemplateDecl* ROOT::TMetaUtils::QualType2ClassTemplateDecl(const clang::QualType& qt)
3711{
3712 using namespace clang;
3716 return ctd;
3717}
3718
3719////////////////////////////////////////////////////////////////////////////////
3720/// These manipulations are necessary because a template specialisation type
3721/// does not inherit from a record type (there is an asymmetry between
3722/// the decls and the types in the clang interface).
3723/// We may need therefore to step into the "Decl dimension" to then get back
3724/// to the "type dimension".
3725
3726clang::TemplateName ROOT::TMetaUtils::ExtractTemplateNameFromQualType(const clang::QualType& qt)
3727{
3728 using namespace clang;
3730
3731 const Type* theType = qt.getTypePtr();
3732
3733 if (const TemplateSpecializationType* tst = llvm::dyn_cast_or_null<const TemplateSpecializationType>(theType)) {
3734 theTemplateName = tst->getTemplateName();
3735 } // We step into the decl dimension
3738 }
3739
3740 return theTemplateName;
3741}
3742
3743////////////////////////////////////////////////////////////////////////////////
3744
3745static bool areEqualTypes(const clang::TemplateArgument& tArg,
3746 llvm::SmallVectorImpl<clang::TemplateArgument>& preceedingTArgs,
3747 const clang::NamedDecl& tPar,
3748 const cling::Interpreter& interp,
3750{
3751 using namespace ROOT::TMetaUtils;
3752 using namespace clang;
3753
3754 // Check if this is a type for security
3755 TemplateTypeParmDecl* ttpdPtr = const_cast<TemplateTypeParmDecl*>(llvm::dyn_cast<TemplateTypeParmDecl>(&tPar));
3756 if (!ttpdPtr) return false;
3757 if (!ttpdPtr->hasDefaultArgument()) return false; // we should not be here in this case, but we protect us.
3758
3759 // Try the fast solution
3760 QualType tParQualType = ttpdPtr->getDefaultArgument().getArgument().getAsType();
3761 const QualType tArgQualType = tArg.getAsType();
3762
3763 // Now the equality tests for non template specialisations.
3764
3765 // The easy cases:
3766 // template <class T=double> class A; or
3767 // template <class T=A<float>> class B;
3768 if (tParQualType.getTypePtr() == tArgQualType.getTypePtr()) return true;
3769
3770 // Here the difficulty comes. We have to check if the argument is equal to its
3771 // default. We can do that bootstrapping an argument which has the default value
3772 // based on the preceeding arguments.
3773 // Basically we ask sema to give us the value of the argument given the template
3774 // of behind the parameter and the all the arguments.
3775 // So:
3776
3777 // Take the template out of the parameter
3778
3779 const clang::ElaboratedType* etype
3780 = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3781 while (etype) {
3782 tParQualType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3783 etype = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3784 }
3785
3787 llvm::dyn_cast<TemplateSpecializationType>(tParQualType.getTypePtr());
3788
3789 if(!tst) // nothing more to be tried. They are different indeed.
3790 return false;
3791
3793 = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(tArgQualType->getAsCXXRecordDecl());
3794
3795 if(!TSTdecl) // nothing more to be tried. They are different indeed.
3796 return false;
3797
3798 TemplateDecl *Template = tst->getTemplateName().getAsTemplateDecl();
3799
3800 // Take the template location
3801 SourceLocation TemplateLoc = Template->getSourceRange ().getBegin();
3802
3803 // Get the position of the "<" (LA) of the specializaion
3804 SourceLocation LAngleLoc = TSTdecl->getSourceRange().getBegin();
3805
3806
3807 // Enclose in a scope for the RAII
3808 bool isEqual=false;
3810 {
3811 clang::Sema& S = interp.getCI()->getSema();
3812 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interp));
3813 llvm::SmallVector<clang::TemplateArgument, 4> canonArgs;
3814 bool HasDefaultArgs;
3815 TemplateArgumentLoc defTArgLoc = S.SubstDefaultTemplateArgumentIfAvailable(Template,
3817 LAngleLoc,
3818 ttpdPtr,
3820 canonArgs,
3822 // The substition can fail, in which case there would have been compilation
3823 // error printed on the screen.
3824 newArg = defTArgLoc.getArgument();
3825 if (newArg.isNull() ||
3826 newArg.getKind() != clang::TemplateArgument::Type) {
3827 ROOT::TMetaUtils::Error("areEqualTypes",
3828 "Template parameter substitution failed!");
3829 }
3830
3832 = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(newArg.getAsType()->getAsCXXRecordDecl());
3833// std::cout << "nSTdecl is " << nTSTdecl << std::endl;
3834
3835 isEqual = (nTSTdecl && nTSTdecl->getMostRecentDecl() == TSTdecl->getMostRecentDecl()) ||
3836 (tParQualType.getTypePtr() == newArg.getAsType().getTypePtr());
3837 }
3838
3839
3840 return isEqual;
3841}
3842
3843
3844////////////////////////////////////////////////////////////////////////////////
3845/// std::cout << "Are equal values?\n";
3846
3847static bool areEqualValues(const clang::TemplateArgument& tArg,
3848 const clang::NamedDecl& tPar)
3849{
3850 using namespace clang;
3851 const NonTypeTemplateParmDecl* nttpdPtr = llvm::dyn_cast<NonTypeTemplateParmDecl>(&tPar);
3852 if (!nttpdPtr) return false;
3854
3855 if (!nttpd.hasDefaultArgument())
3856 return false;
3857
3858 // 64 bits wide and signed (non unsigned, that is why "false")
3859 llvm::APSInt defaultValueAPSInt(64, false);
3860 if (Expr* defArgExpr = nttpd.getDefaultArgument().getArgument().getAsExpr()) {
3861 const ASTContext& astCtxt = nttpdPtr->getASTContext();
3862 if (auto Value = defArgExpr->getIntegerConstantExpr(astCtxt))
3864 }
3865
3866 const int value = tArg.getAsIntegral().getLimitedValue();
3867
3868 // std::cout << (value == defaultValueAPSInt ? "yes!":"no") << std::endl;
3869 return value == defaultValueAPSInt;
3870}
3871
3872////////////////////////////////////////////////////////////////////////////////
3873/// Check if this NamedDecl is a template parameter with a default argument.
3874/// This is a single interface to treat both integral and type parameters.
3875/// Returns true if this is the case, false otherwise
3876
3877static bool isTypeWithDefault(const clang::NamedDecl* nDecl)
3878{
3879 using namespace clang;
3880 if (!nDecl) return false;
3881 if (const TemplateTypeParmDecl* ttpd = llvm::dyn_cast<TemplateTypeParmDecl>(nDecl))
3882 return ttpd->hasDefaultArgument();
3883 if (const NonTypeTemplateParmDecl* nttpd = llvm::dyn_cast<NonTypeTemplateParmDecl>(nDecl))
3884 return nttpd->hasDefaultArgument();
3885 return false;
3886
3887}
3888
3889static void KeepNParams(clang::QualType& normalizedType,
3890 const clang::QualType& vanillaType,
3891 const cling::Interpreter& interp,
3893
3894// Returns true if normTArg might have changed.
3895static bool RecurseKeepNParams(clang::TemplateArgument &normTArg,
3896 const clang::TemplateArgument &tArg,
3897 const cling::Interpreter& interp,
3899 const clang::ASTContext& astCtxt)
3900{
3901 using namespace ROOT::TMetaUtils;
3902 using namespace clang;
3903
3904 // Once we know there is no more default parameter, we can run through to the end
3905 // and/or recurse in the template parameter packs.
3906
3907 // If this is a type,
3908 // we need first of all to recurse: this argument may need to be manipulated
3909 if (tArg.getKind() == clang::TemplateArgument::Type) {
3910 QualType thisNormQualType = normTArg.getAsType();
3911 QualType thisArgQualType = tArg.getAsType();
3914 interp,
3915 normCtxt);
3918 } else if (normTArg.getKind() == clang::TemplateArgument::Pack) {
3919 assert( tArg.getKind() == clang::TemplateArgument::Pack );
3920
3922 bool mightHaveChanged = true;
3923 for (auto I = normTArg.pack_begin(), E = normTArg.pack_end(),
3924 FI = tArg.pack_begin(), FE = tArg.pack_end();
3925 I != E && FI != FE; ++I, ++FI)
3926 {
3929 desArgs.push_back(pack_arg);
3930 }
3931 if (mightHaveChanged) {
3932 ASTContext &mutableCtx( const_cast<ASTContext&>(astCtxt) );
3933 normTArg = TemplateArgument::CreatePackCopy(mutableCtx, desArgs);
3934 }
3935 return mightHaveChanged;
3936 }
3937 return false;
3938}
3939
3940
3941////////////////////////////////////////////////////////////////////////////////
3942/// This function allows to manipulate the number of arguments in the type
3943/// of a template specialisation.
3944
3945static void KeepNParams(clang::QualType& normalizedType,
3946 const clang::QualType& vanillaType,
3947 const cling::Interpreter& interp,
3949{
3950 using namespace ROOT::TMetaUtils;
3951 using namespace clang;
3952
3953 // If this type has no template specialisation behind, we don't need to do
3954 // anything
3957 if (! QualType2Template(vanillaType, ctd, ctsd)) return ;
3958
3959 // Even if this is a template, if we don't keep any argument, return
3960 const int nArgsToKeep = normCtxt.GetNargsToKeep(ctd);
3961
3962 // Important in case of early return: we must restore the original qualtype
3964
3965 const ASTContext& astCtxt = ctsd->getASTContext();
3966
3967
3968 // In case of name* we need to strip the pointer first, add the default and attach
3969 // the pointer once again.
3970 if (llvm::isa<clang::PointerType>(normalizedType.getTypePtr())) {
3971 // Get the qualifiers.
3972 clang::Qualifiers quals = normalizedType.getQualifiers();
3973 auto valNormalizedType = normalizedType->getPointeeType();
3975 normalizedType = astCtxt.getPointerType(valNormalizedType);
3976 // Add back the qualifiers.
3977 normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
3978 return;
3979 }
3980
3981 // In case of Int_t& we need to strip the pointer first, desugar and attach
3982 // the pointer once again.
3983 if (llvm::isa<clang::ReferenceType>(normalizedType.getTypePtr())) {
3984 // Get the qualifiers.
3985 bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(normalizedType.getTypePtr());
3986 clang::Qualifiers quals = normalizedType.getQualifiers();
3987 auto valNormType = normalizedType->getPointeeType();
3989
3990 // Add the r- or l- value reference type back to the desugared one
3991 if (isLValueRefTy)
3992 normalizedType = astCtxt.getLValueReferenceType(valNormType);
3993 else
3994 normalizedType = astCtxt.getRValueReferenceType(valNormType);
3995 // Add back the qualifiers.
3996 normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
3997 return;
3998 }
3999
4000 // Treat the Scope (factorise the code out to reuse it in AddDefaultParameters)
4001 bool prefix_changed = false;
4002 clang::NestedNameSpecifier* prefix = nullptr;
4003 clang::Qualifiers prefix_qualifiers = normalizedType.getLocalQualifiers();
4004 const clang::ElaboratedType* etype
4005 = llvm::dyn_cast<clang::ElaboratedType>(normalizedType.getTypePtr());
4006 if (etype) {
4007 // We have to also handle the prefix.
4008 // TODO: we ought to be running KeepNParams
4009 prefix = AddDefaultParametersNNS(astCtxt, etype->getQualifier(), interp, normCtxt);
4010 prefix_changed = prefix != etype->getQualifier();
4011 normalizedType = clang::QualType(etype->getNamedType().getTypePtr(),0);
4012 }
4013
4014 // The canonical decl does not necessarily have the template default arguments.
4015 // Need to walk through the redecl chain to find it (we know there will be no
4016 // inconsistencies, at least)
4017 const clang::ClassTemplateDecl* ctdWithDefaultArgs = ctd;
4018 for (const RedeclarableTemplateDecl* rd: ctdWithDefaultArgs->redecls()) {
4019 clang::TemplateParameterList* tpl = rd->getTemplateParameters();
4020 if (tpl->getMinRequiredArguments () < tpl->size()) {
4021 ctdWithDefaultArgs = llvm::dyn_cast<clang::ClassTemplateDecl>(rd);
4022 break;
4023 }
4024 }
4025
4026 if (!ctdWithDefaultArgs) {
4027 Error("KeepNParams", "Not found template default arguments\n");
4029 return;
4030 }
4031
4032 TemplateParameterList* tParsPtr = ctdWithDefaultArgs->getTemplateParameters();
4034 const TemplateArgumentList& tArgs = ctsd->getTemplateArgs();
4035
4036 // We extract the template name from the type
4037 TemplateName theTemplateName = ExtractTemplateNameFromQualType(normalizedType);
4038 if (theTemplateName.isNull()) {
4040 return;
4041 }
4042
4044 llvm::dyn_cast<TemplateSpecializationType>(normalizedType.getTypePtr());
4045 if (!normalizedTst) {
4047 return;
4048 }
4049
4050 const clang::ClassTemplateSpecializationDecl* TSTdecl
4051 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(normalizedType.getTypePtr()->getAsCXXRecordDecl());
4052 bool isStdDropDefault = TSTdecl && IsStdDropDefaultClass(*TSTdecl);
4053
4054 // Loop over the template parameters and arguments recursively.
4055 // We go down the two lanes: the one of template parameters (decls) and the
4056 // one of template arguments (QualTypes) in parallel. The former are a
4057 // property of the template, independent of its instantiations.
4058 // The latter are a property of the instance itself.
4059 llvm::SmallVector<TemplateArgument, 4> argsToKeep;
4060
4061 const int nArgs = tArgs.size();
4062 const auto &normArgs = normalizedTst->template_arguments();
4063 const int nNormArgs = normArgs.size();
4064
4065 bool mightHaveChanged = false;
4066 int latestNonDefaultArg = -1;
4067
4068 // becomes true when a parameter has a value equal to its default
4069 for (int formal = 0, inst = 0; formal != nArgs; ++formal, ++inst) {
4070 const NamedDecl* tParPtr = tPars.getParam(formal);
4071 if (!tParPtr) {
4072 Error("KeepNParams", "The parameter number %s is null.\n", formal);
4073 continue;
4074 }
4075
4076 // Stop if the normalized TemplateSpecializationType has less arguments than
4077 // the one index is pointing at.
4078 // We piggy back on the AddDefaultParameters routine basically.
4079 if (formal == nNormArgs || inst == nNormArgs) break;
4080
4081 const TemplateArgument& tArg = tArgs.get(formal);
4083
4084 bool shouldKeepArg = nArgsToKeep < 0 || inst < nArgsToKeep;
4085 if (isStdDropDefault) shouldKeepArg = false;
4086
4087 // Nothing to do here: either this parameter has no default, or we have to keep it.
4088 // FIXME: Temporary measure to get Atlas started with this.
4089 // We put a hard cut on the number of template arguments to keep, w/o checking if
4090 // they are non default. This makes this feature UNUSABLE for cases like std::vector,
4091 // where 2 different entities would have the same name if an allocator different from
4092 // the default one is by chance used.
4094 if ( tParPtr->isTemplateParameterPack() ) {
4095 // This is the last template parameter in the template declaration
4096 // but it is signaling that there can be an arbitrary number of arguments
4097 // in the template instance. So to avoid inadvertenly dropping those
4098 // arguments we just process all remaining argument and exit the main loop.
4099 for( ; inst != nNormArgs; ++inst) {
4102 argsToKeep.push_back(normTArg);
4103 }
4104 // Done.
4106 break;
4107 }
4109 argsToKeep.push_back(normTArg);
4111 continue;
4112 } else {
4113 if (!isStdDropDefault) {
4114 // Here we should not break but rather check if the value is the default one.
4115 mightHaveChanged = true;
4116 break;
4117 }
4118 // For std, we want to check the default args values.
4119 }
4120
4121 // Now, we keep it only if it not is equal to its default, expressed in the arg
4122 // Some gymnastic is needed to decide how to check for equality according to the
4123 // flavour of Type: templateType or Integer
4124 bool equal=false;
4125 auto argKind = tArg.getKind();
4126 if (argKind == clang::TemplateArgument::Type){
4127 // we need all the info
4129 } else if (argKind == clang::TemplateArgument::Integral){
4130 equal = areEqualValues(tArg, *tParPtr);
4131 }
4132
4133 argsToKeep.push_back(normTArg);
4134 if (!equal) {
4137 } else {
4138 mightHaveChanged = true;
4139 }
4140
4141
4142 } // of loop over parameters and arguments
4143
4144 if (latestNonDefaultArg >= 0)
4145 argsToKeep.resize(latestNonDefaultArg + 1);
4146
4149 return;
4150 }
4151
4152 // now, let's remanipulate our Qualtype
4153 if (mightHaveChanged) {
4154 Qualifiers qualifiers = normalizedType.getLocalQualifiers();
4155 normalizedType = astCtxt.getTemplateSpecializationType(theTemplateName,
4156 argsToKeep,
4157 normalizedType.getTypePtr()->getCanonicalTypeInternal());
4158 normalizedType = astCtxt.getQualifiedType(normalizedType, qualifiers);
4159 }
4160
4161 // Here we have (prefix_changed==true || mightHaveChanged), in both case
4162 // we need to reconstruct the type.
4163 if (prefix) {
4164 normalizedType = astCtxt.getElaboratedType(clang::ElaboratedTypeKeyword::None, prefix, normalizedType);
4166 }
4167}
4168
4169////////////////////////////////////////////////////////////////////////////////
4170/// Return the type normalized for ROOT,
4171/// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4172/// adding default template argument for all types except those explicitly
4173/// requested to be drop by the user.
4174/// Default template for STL collections are not yet removed by this routine.
4175
4176clang::QualType ROOT::TMetaUtils::GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4177{
4178 clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4179
4180 // Modules can trigger deserialization.
4181 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
4182 clang::QualType normalizedType = cling::utils::Transform::GetPartiallyDesugaredType(ctxt, type, normCtxt.GetConfig(), true /* fully qualify */);
4183
4184 // Readd missing default template parameters
4186
4187 // Get the number of arguments to keep in case they are not default.
4189
4190 return normalizedType;
4191}
4192
4193////////////////////////////////////////////////////////////////////////////////
4194/// Return the type name normalized for ROOT,
4195/// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4196/// adding default template argument for all types except the STL collections
4197/// where we remove the default template argument if any.
4198///
4199/// This routine might actually belong in the interpreter because
4200/// cache the clang::Type might be intepreter specific.
4201
4202void ROOT::TMetaUtils::GetNormalizedName(std::string &norm_name, const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4203{
4204 if (type.isNull()) {
4205 norm_name = "";
4206 return;
4207 }
4208
4210
4211 clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4212 clang::PrintingPolicy policy(ctxt.getPrintingPolicy());
4213 policy.SuppressTagKeyword = true; // Never get the class or struct keyword
4214 policy.SuppressScope = true; // Force the scope to be coming from a clang::ElaboratedType.
4215 policy.AnonymousTagLocations = false; // Do not extract file name + line number for anonymous types.
4216 // The scope suppression is required for getting rid of the anonymous part of the name of a class defined in an anonymous namespace.
4217 // This gives us more control vs not using the clang::ElaboratedType and relying on the Policy.SuppressUnwrittenScope which would
4218 // strip both the anonymous and the inline namespace names (and we probably do not want the later to be suppressed).
4219
4220 std::string normalizedNameStep1;
4221
4222 // getAsStringInternal can trigger deserialization
4223 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
4224 normalizedType.getAsStringInternal(normalizedNameStep1,policy);
4225
4226 // Remove the _Atomic type specifyier if present before normalising
4229
4230 // Still remove the std:: and default template argument for STL container and
4231 // normalize the location and amount of white spaces.
4234
4238
4239 // The result of this routine is by definition a fully qualified name. There is an implicit starting '::' at the beginning of the name.
4240 // Depending on how the user typed their code, in particular typedef declarations, we may end up with an explicit '::' being
4241 // part of the result string. For consistency, we must remove it.
4242 if (norm_name.length()>2 && norm_name[0]==':' && norm_name[1]==':') {
4243 norm_name.erase(0,2);
4244 }
4245
4246}
4247
4248////////////////////////////////////////////////////////////////////////////////
4249
4251 const clang::TypeDecl* typeDecl,
4252 const cling::Interpreter &interpreter)
4253{
4255 const clang::Sema &sema = interpreter.getSema();
4256 clang::ASTContext& astCtxt = sema.getASTContext();
4257 clang::QualType qualType = astCtxt.getTypeDeclType(typeDecl);
4258
4260 qualType,
4262 tNormCtxt);
4263}
4264
4265////////////////////////////////////////////////////////////////////////////////
4266std::pair<std::string,clang::QualType>
4268 const cling::Interpreter &interpreter,
4271{
4272 std::string thisTypeName;
4273 GetNormalizedName(thisTypeName, thisType, interpreter, normCtxt );
4274 bool hasChanged;
4276 if (!hasChanged) return std::make_pair(thisTypeName,thisType);
4277
4279 ROOT::TMetaUtils::Info("ROOT::TMetaUtils::GetTypeForIO",
4280 "Name changed from %s to %s\n", thisTypeName.c_str(), thisTypeNameForIO.c_str());
4281 }
4282
4283 auto& lookupHelper = interpreter.getLookupHelper();
4284
4285 const clang::Type* typePtrForIO;
4287 cling::LookupHelper::DiagSetting::NoDiagnostics,
4288 &typePtrForIO);
4289
4290 // This should never happen
4291 if (!typePtrForIO) {
4292 ROOT::TMetaUtils::Fatal("ROOT::TMetaUtils::GetTypeForIO",
4293 "Type not found: %s.",thisTypeNameForIO.c_str());
4294 }
4295
4296 clang::QualType typeForIO(typePtrForIO,0);
4297
4298 // Check if this is a class. Indeed it could well be a POD
4299 if (!typeForIO->isRecordType()) {
4300 return std::make_pair(thisTypeNameForIO,typeForIO);
4301 }
4302
4303 auto thisDeclForIO = typeForIO->getAsCXXRecordDecl();
4304 if (!thisDeclForIO) {
4305 ROOT::TMetaUtils::Error("ROOT::TMetaUtils::GetTypeForIO",
4306 "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());
4307 return std::make_pair(thisTypeName,thisType);
4308 }
4309
4310 return std::make_pair(thisTypeNameForIO,typeForIO);
4311}
4312
4313////////////////////////////////////////////////////////////////////////////////
4314
4315clang::QualType ROOT::TMetaUtils::GetTypeForIO(const clang::QualType& thisType,
4316 const cling::Interpreter &interpreter,
4319{
4321}
4322
4323////////////////////////////////////////////////////////////////////////////////
4324/// Return the dictionary file name for a module
4325
4327{
4328 std::string dictFileName(moduleName);
4329 dictFileName += "_rdict.pcm";
4330 return dictFileName;
4331}
4332
4333int dumpDeclForAssert(const clang::Decl& D, const char* commentStart) {
4334 llvm::errs() << llvm::StringRef(commentStart, 80) << '\n';
4335 D.dump();
4336 return 0;
4337}
4338
4339////////////////////////////////////////////////////////////////////////////////
4340/// Returns the comment (// striped away), annotating declaration in a meaningful
4341/// for ROOT IO way.
4342/// Takes optional out parameter clang::SourceLocation returning the source
4343/// location of the comment.
4344///
4345/// CXXMethodDecls, FieldDecls and TagDecls are annotated.
4346/// CXXMethodDecls declarations and FieldDecls are annotated as follows:
4347/// Eg. void f(); // comment1
4348/// int member; // comment2
4349/// Inline definitions of CXXMethodDecls after the closing } \n. Eg:
4350/// void f()
4351/// {...} // comment3
4352/// TagDecls are annotated in the end of the ClassDef macro. Eg.
4353/// class MyClass {
4354/// ...
4355/// ClassDef(MyClass, 1) // comment4
4356///
4357
4358llvm::StringRef ROOT::TMetaUtils::GetComment(const clang::Decl &decl, clang::SourceLocation *loc)
4359{
4360 clang::SourceManager& sourceManager = decl.getASTContext().getSourceManager();
4361 clang::SourceLocation sourceLocation = decl.getEndLoc();
4362
4363 // If the location is a macro get the expansion location.
4364 sourceLocation = sourceManager.getExpansionRange(sourceLocation).getEnd();
4365 // FIXME: We should optimize this routine instead making it do the wrong thing
4366 // returning an empty comment if the decl came from the AST.
4367 // In order to do that we need to: check if the decl has an attribute and
4368 // return the attribute content (including walking the redecl chain) and if
4369 // this is not the case we should try finding it in the header file.
4370 // This will allow us to move the implementation of TCling*Info::Title() in
4371 // TClingDeclInfo.
4372 if (!decl.hasOwningModule() && sourceManager.isLoadedSourceLocation(sourceLocation)) {
4373 // Do not touch disk for nodes coming from the PCH.
4374 return "";
4375 }
4376
4377 bool invalid;
4378 const char *commentStart = sourceManager.getCharacterData(sourceLocation, &invalid);
4379 if (invalid)
4380 return "";
4381
4382 bool skipToSemi = true;
4383 if (const clang::FunctionDecl* FD = clang::dyn_cast<clang::FunctionDecl>(&decl)) {
4384 if (FD->isImplicit()) {
4385 // Compiler generated function.
4386 return "";
4387 }
4388 if (FD->isExplicitlyDefaulted() || FD->isDeletedAsWritten()) {
4389 // ctorOrFunc() = xyz; with commentStart pointing somewhere into
4390 // ctorOrFunc.
4391 // We have to skipToSemi
4392 } else if (FD->doesThisDeclarationHaveABody()) {
4393 // commentStart is at body's '}'
4394 // But we might end up e.g. at the ')' of a CPP macro
4395 assert((decl.getEndLoc() != sourceLocation || *commentStart == '}'
4397 && "Expected macro or end of body at '}'");
4398 if (*commentStart) ++commentStart;
4399
4400 // We might still have a ';'; skip the spaces and check.
4401 while (*commentStart && isspace(*commentStart)
4402 && *commentStart != '\n' && *commentStart != '\r') {
4403 ++commentStart;
4404 }
4405 if (*commentStart == ';') ++commentStart;
4406
4407 skipToSemi = false;
4408 }
4409 } else if (const clang::EnumConstantDecl* ECD
4410 = clang::dyn_cast<clang::EnumConstantDecl>(&decl)) {
4411 // either "konstant = 12, //COMMENT" or "lastkonstant // COMMENT"
4412 if (ECD->getNextDeclInContext())
4413 while (*commentStart && *commentStart != ',' && *commentStart != '\r' && *commentStart != '\n')
4414 ++commentStart;
4415 // else commentStart already points to the end.
4416
4417 skipToSemi = false;
4418 }
4419
4420 if (skipToSemi) {
4421 while (*commentStart && *commentStart != ';' && *commentStart != '\r' && *commentStart != '\n')
4422 ++commentStart;
4423 if (*commentStart == ';') ++commentStart;
4424 }
4425
4426 // Now skip the spaces until beginning of comments or EOL.
4427 while ( *commentStart && isspace(*commentStart)
4428 && *commentStart != '\n' && *commentStart != '\r') {
4429 ++commentStart;
4430 }
4431
4432 if (commentStart[0] != '/' ||
4433 (commentStart[1] != '/' && commentStart[1] != '*')) {
4434 // not a comment
4435 return "";
4436 }
4437
4438 // Treat by default c++ comments (+2) but also Doxygen comments (+4)
4439 // Int_t fPx; ///< Some doxygen comment for persistent data.
4440 // Int_t fPy; //!< Some doxygen comment for persistent data.
4441 // Int_t fPz; /*!< Some doxygen comment for persistent data. */
4442 // Int_t fPa; /**< Some doxygen comment for persistent data. */
4443 unsigned int skipChars = 2;
4444 if (commentStart[0] == '/' &&
4445 commentStart[1] == '/' &&
4446 (commentStart[2] == '/' || commentStart[2] == '!') &&
4447 commentStart[3] == '<') {
4448 skipChars = 4;
4449 } else if (commentStart[0] == '/' &&
4450 commentStart[1] == '*' &&
4451 (commentStart[2] == '*' || commentStart[2] == '!') &&
4452 commentStart[3] == '<') {
4453 skipChars = 4;
4454 }
4455
4457
4458 // Now skip the spaces after comment start until EOL.
4459 while ( *commentStart && isspace(*commentStart)
4460 && *commentStart != '\n' && *commentStart != '\r') {
4461 ++commentStart;
4462 }
4463 const char* commentEnd = commentStart;
4464 // Even for /* comments we only take the first line into account.
4465 while (*commentEnd && *commentEnd != '\n' && *commentEnd != '\r') {
4466 ++commentEnd;
4467 }
4468
4469 // "Skip" (don't include) trailing space.
4470 // *commentEnd points behind comment end thus check commentEnd[-1]
4471 while (commentEnd > commentStart && isspace(commentEnd[-1])) {
4472 --commentEnd;
4473 }
4474
4475 if (loc) {
4476 // Find the true beginning of a comment.
4477 unsigned offset = commentStart - sourceManager.getCharacterData(sourceLocation);
4478 *loc = sourceLocation.getLocWithOffset(offset - 1);
4479 }
4480
4481 return llvm::StringRef(commentStart, commentEnd - commentStart);
4482}
4483
4484////////////////////////////////////////////////////////////////////////////////
4485/// Return true if class has any of class declarations like ClassDef, ClassDefNV, ClassDefOverride
4486
4487bool ROOT::TMetaUtils::HasClassDefMacro(const clang::Decl *decl, const cling::Interpreter &interpreter)
4488{
4489 if (!decl) return false;
4490
4491 auto& sema = interpreter.getCI()->getSema();
4492 auto maybeMacroLoc = decl->getLocation();
4493
4494 if (!maybeMacroLoc.isMacroID()) return false;
4495
4496 static const std::vector<std::string> signatures =
4497 { "ClassDef", "ClassDefOverride", "ClassDefNV", "ClassDefInline", "ClassDefInlineOverride", "ClassDefInlineNV" };
4498
4499 for (auto &name : signatures)
4500 if (sema.findMacroSpelling(maybeMacroLoc, name))
4501 return true;
4502
4503 return false;
4504}
4505
4506////////////////////////////////////////////////////////////////////////////////
4507/// Return the class comment after the ClassDef:
4508/// class MyClass {
4509/// ...
4510/// ClassDef(MyClass, 1) // class comment
4511///
4512
4513llvm::StringRef ROOT::TMetaUtils::GetClassComment(const clang::CXXRecordDecl &decl,
4514 clang::SourceLocation *loc,
4515 const cling::Interpreter &interpreter)
4516{
4517 using namespace clang;
4518
4519 const Decl* DeclFileLineDecl
4520 = interpreter.getLookupHelper().findFunctionProto(&decl, "DeclFileLine", "",
4521 cling::LookupHelper::NoDiagnostics);
4522
4523 // For now we allow only a special macro (ClassDef) to have meaningful comments
4526 llvm::StringRef comment = ROOT::TMetaUtils::GetComment(*DeclFileLineDecl, &commentSLoc);
4527 if (comment.size()) {
4528 if (loc) {
4529 *loc = commentSLoc;
4530 }
4531 return comment;
4532 }
4533 }
4534 return llvm::StringRef();
4535}
4536
4537////////////////////////////////////////////////////////////////////////////////
4538/// Return the base/underlying type of a chain of array or pointers type.
4539/// Does not yet support the array and pointer part being intermixed.
4540
4541const clang::Type *ROOT::TMetaUtils::GetUnderlyingType(clang::QualType type)
4542{
4543 const clang::Type *rawtype = type.getTypePtr();
4544
4545 // NOTE: We probably meant isa<clang::ElaboratedType>
4546 if (rawtype->isElaboratedTypeSpecifier() ) {
4547 rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4548 }
4549 if (rawtype->isArrayType()) {
4550 rawtype = type.getTypePtr()->getBaseElementTypeUnsafe ();
4551 }
4552 if (rawtype->isPointerType() || rawtype->isReferenceType() ) {
4553 //Get to the 'raw' type.
4554 clang::QualType pointee;
4555 while ( (pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull() && pointee.getTypePtr() != rawtype)
4556 {
4557 rawtype = pointee.getTypePtr();
4558
4559 if (rawtype->isElaboratedTypeSpecifier() ) {
4560 rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4561 }
4562 if (rawtype->isArrayType()) {
4563 rawtype = rawtype->getBaseElementTypeUnsafe ();
4564 }
4565 }
4566 }
4567 if (rawtype->isArrayType()) {
4568 rawtype = rawtype->getBaseElementTypeUnsafe ();
4569 }
4570 return rawtype;
4571}
4572
4573////////////////////////////////////////////////////////////////////////////////
4574/// Return true if the DeclContext is representing an entity reacheable from the
4575/// global namespace
4576
4577bool ROOT::TMetaUtils::IsCtxtReacheable(const clang::DeclContext &ctxt)
4578{
4579 if (ctxt.isNamespace() || ctxt.isTranslationUnit())
4580 return true;
4581 else if(const auto parentdecl = llvm::dyn_cast<clang::CXXRecordDecl>(&ctxt))
4583 else
4584 // For example "extern C" context.
4585 return true;
4586}
4587
4588////////////////////////////////////////////////////////////////////////////////
4589/// Return true if the decl is representing an entity reacheable from the
4590/// global namespace
4591
4593{
4594 const clang::DeclContext *ctxt = decl.getDeclContext();
4595 switch (decl.getAccess()) {
4596 case clang::AS_public:
4597 return !ctxt || IsCtxtReacheable(*ctxt);
4598 case clang::AS_protected:
4599 return false;
4600 case clang::AS_private:
4601 return false;
4602 case clang::AS_none:
4603 return !ctxt || IsCtxtReacheable(*ctxt);
4604 default:
4605 // IMPOSSIBLE
4606 assert(false && "Unexpected value for the access property value in Clang");
4607 return false;
4608 }
4609}
4610
4611////////////////////////////////////////////////////////////////////////////////
4612/// Return true, if the decl is part of the std namespace.
4613
4614bool ROOT::TMetaUtils::IsStdClass(const clang::RecordDecl &cl)
4615{
4616 return cling::utils::Analyze::IsStdClass(cl);
4617}
4618
4619////////////////////////////////////////////////////////////////////////////////
4620/// Return true, if the decl is part of the std namespace and we want
4621/// its default parameter dropped.
4622
4623bool ROOT::TMetaUtils::IsStdDropDefaultClass(const clang::RecordDecl &cl)
4624{
4625 // Might need to reduce it to shared_ptr and STL collection.s
4626 if (cling::utils::Analyze::IsStdClass(cl)) {
4627 static const char *names[] =
4628 { "shared_ptr", "__shared_ptr",
4629 "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset"};
4630 llvm::StringRef clname(cl.getName());
4631 for(auto &&name : names) {
4632 if (clname == name) return true;
4633 }
4634 }
4635 return false;
4636}
4637
4638////////////////////////////////////////////////////////////////////////////////
4639/// This is a recursive function
4640
4641bool ROOT::TMetaUtils::MatchWithDeclOrAnyOfPrevious(const clang::CXXRecordDecl &cl,
4642 const clang::CXXRecordDecl &currentCl)
4643{
4644 // We found it: let's return true
4645 if (&cl == &currentCl) return true;
4646
4647 const clang::CXXRecordDecl* previous = currentCl.getPreviousDecl();
4648
4649 // There is no previous decl, so we cannot possibly find it
4650 if (nullptr == previous){
4651 return false;
4652 }
4653
4654 // We try to find it in the previous
4656
4657}
4658
4659//______________________________________________________________________________
4660
4661bool ROOT::TMetaUtils::IsOfType(const clang::CXXRecordDecl &cl, const std::string& typ, const cling::LookupHelper& lh)
4662{
4663 // Return true if the decl is of type.
4664 // A proper hashtable for caching results would be the ideal solution
4665 // 1) Only one lookup per type
4666 // 2) No string comparison
4667 // We may use a map which becomes an unordered map if c++11 is enabled?
4668
4669 const clang::CXXRecordDecl *thisDecl =
4670 llvm::dyn_cast_or_null<clang::CXXRecordDecl>(lh.findScope(typ, cling::LookupHelper::WithDiagnostics));
4671
4672 // this would be probably an assert given that this state is not reachable unless a mistake is somewhere
4673 if (! thisDecl){
4674 Error("IsOfType","Record decl of type %s not found in the AST.", typ.c_str());
4675 return false;
4676 }
4677
4678 // Now loop on all previous decls to seek a match
4679 const clang::CXXRecordDecl *mostRecentDecl = thisDecl->getMostRecentDecl();
4681
4682 return matchFound;
4683}
4684
4685////////////////////////////////////////////////////////////////////////////////
4686/// type : type name: vector<list<classA,allocator>,allocator>
4687/// result: 0 : not stl container
4688/// abs(result): code of container 1=vector,2=list,3=deque,4=map
4689/// 5=multimap,6=set,7=multiset
4690
4692{
4693 // This routine could be enhanced to also support:
4694 //
4695 // testAlloc: if true, we test allocator, if it is not default result is negative
4696 // result: 0 : not stl container
4697 // abs(result): code of container 1=vector,2=list,3=deque,4=map
4698 // 5=multimap,6=set,7=multiset
4699 // positive val: we have a vector or list with default allocator to any depth
4700 // like vector<list<vector<int>>>
4701 // negative val: STL container other than vector or list, or non default allocator
4702 // For example: vector<deque<int>> has answer -1
4703
4704 if (!IsStdClass(cl)) {
4705 auto *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(cl.getDeclContext());
4706 if (cl.getName() != "RVec" || nsDecl == nullptr || nsDecl->getName() != "VecOps")
4707 return ROOT::kNotSTL;
4708
4709 auto *parentNsDecl = llvm::dyn_cast<clang::NamespaceDecl>(cl.getDeclContext()->getParent());
4710 if (parentNsDecl == nullptr || parentNsDecl->getName() != "ROOT")
4711 return ROOT::kNotSTL;
4712 }
4713
4714 return STLKind(cl.getName());
4715}
4716
4717static bool hasSomeTypedefSomewhere(const clang::Type* T) {
4718 using namespace clang;
4719 struct SearchTypedef: public TypeVisitor<SearchTypedef, bool> {
4720 bool VisitTypedefType(const TypedefType* TD) {
4721 return true;
4722 }
4723 bool VisitArrayType(const ArrayType* AT) {
4724 return Visit(AT->getElementType().getTypePtr());
4725 }
4726 bool VisitDecltypeType(const DecltypeType* DT) {
4727 return Visit(DT->getUnderlyingType().getTypePtr());
4728 }
4729 bool VisitPointerType(const PointerType* PT) {
4730 return Visit(PT->getPointeeType().getTypePtr());
4731 }
4732 bool VisitReferenceType(const ReferenceType* RT) {
4733 return Visit(RT->getPointeeType().getTypePtr());
4734 }
4736 return Visit(STST->getReplacementType().getTypePtr());
4737 }
4739 for (const TemplateArgument &TA : TST->template_arguments()) {
4740 if (TA.getKind() == TemplateArgument::Type && Visit(TA.getAsType().getTypePtr()))
4741 return true;
4742 }
4743 return false;
4744 }
4746 return false; // shrug...
4747 }
4748 bool VisitTypeOfType(const TypeOfType* TOT) {
4749 return TOT->getUnmodifiedType().getTypePtr();
4750 }
4752 NestedNameSpecifier* NNS = ET->getQualifier();
4753 while (NNS) {
4754 if (NNS->getKind() == NestedNameSpecifier::TypeSpec) {
4755 if (Visit(NNS->getAsType()))
4756 return true;
4757 }
4758 NNS = NNS->getPrefix();
4759 }
4760 return Visit(ET->getNamedType().getTypePtr());
4761 }
4762 };
4763
4765 return ST.Visit(T);
4766}
4767
4768////////////////////////////////////////////////////////////////////////////////
4769/// Check if 'input' or any of its template parameter was substituted when
4770/// instantiating the class template instance and replace it with the
4771/// partially sugared types we have from 'instance'.
4772
4773clang::QualType ROOT::TMetaUtils::ReSubstTemplateArg(clang::QualType input, const clang::Type *instance)
4774{
4775 if (!instance) return input;
4776 // if there is no typedef in instance then there is nothing guiding any
4777 // template parameter typedef replacement.
4779 return input;
4780
4781 using namespace llvm;
4782 using namespace clang;
4783 const clang::ASTContext &Ctxt = instance->getAsCXXRecordDecl()->getASTContext();
4784
4785 // Treat scope (clang::ElaboratedType) if any.
4786 const clang::ElaboratedType* etype
4787 = llvm::dyn_cast<clang::ElaboratedType>(input.getTypePtr());
4788 if (etype) {
4789 // We have to also handle the prefix.
4790
4791 clang::Qualifiers scope_qualifiers = input.getLocalQualifiers();
4792 assert(instance->getAsCXXRecordDecl() != nullptr && "ReSubstTemplateArg only makes sense with a type representing a class.");
4793
4794 clang::NestedNameSpecifier *scope = ReSubstTemplateArgNNS(Ctxt,etype->getQualifier(),instance);
4795 clang::QualType subTy = ReSubstTemplateArg(clang::QualType(etype->getNamedType().getTypePtr(),0),instance);
4796
4797 if (scope)
4798 subTy = Ctxt.getElaboratedType(clang::ElaboratedTypeKeyword::None, scope, subTy);
4799 subTy = Ctxt.getQualifiedType(subTy,scope_qualifiers);
4800 return subTy;
4801 }
4802
4803 QualType QT = input;
4804
4805 // In case of Int_t* we need to strip the pointer first, ReSubst and attach
4806 // the pointer once again.
4807 if (isa<clang::PointerType>(QT.getTypePtr())) {
4808 // Get the qualifiers.
4809 Qualifiers quals = QT.getQualifiers();
4810 QualType nQT;
4811 nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4812 if (nQT == QT->getPointeeType()) return QT;
4813
4814 QT = Ctxt.getPointerType(nQT);
4815 // Add back the qualifiers.
4816 QT = Ctxt.getQualifiedType(QT, quals);
4817 return QT;
4818 }
4819
4820 // In case of Int_t& we need to strip the pointer first, ReSubst and attach
4821 // the reference once again.
4822 if (isa<ReferenceType>(QT.getTypePtr())) {
4823 // Get the qualifiers.
4824 bool isLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
4825 Qualifiers quals = QT.getQualifiers();
4826 QualType nQT;
4827 nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4828 if (nQT == QT->getPointeeType()) return QT;
4829
4830 // Add the r- or l-value reference type back to the desugared one.
4831 if (isLValueRefTy)
4832 QT = Ctxt.getLValueReferenceType(nQT);
4833 else
4834 QT = Ctxt.getRValueReferenceType(nQT);
4835 // Add back the qualifiers.
4836 QT = Ctxt.getQualifiedType(QT, quals);
4837 return QT;
4838 }
4839
4840 // In case of Int_t[2] we need to strip the array first, ReSubst and attach
4841 // the array once again.
4842 if (isa<clang::ArrayType>(QT.getTypePtr())) {
4843 // Get the qualifiers.
4844 Qualifiers quals = QT.getQualifiers();
4845
4846 if (const auto arr = dyn_cast<ConstantArrayType>(QT.getTypePtr())) {
4847 QualType newQT= ReSubstTemplateArg(arr->getElementType(),instance);
4848
4849 if (newQT == arr->getElementType()) return QT;
4850 QT = Ctxt.getConstantArrayType(newQT,
4851 arr->getSize(),
4852 arr->getSizeExpr(),
4853 arr->getSizeModifier(),
4854 arr->getIndexTypeCVRQualifiers());
4855
4856 } else if (const auto arr = dyn_cast<DependentSizedArrayType>(QT.getTypePtr())) {
4857 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4858
4859 if (newQT == QT) return QT;
4860 QT = Ctxt.getDependentSizedArrayType (newQT,
4861 arr->getSizeExpr(),
4862 arr->getSizeModifier(),
4863 arr->getIndexTypeCVRQualifiers(),
4864 arr->getBracketsRange());
4865
4866 } else if (const auto arr = dyn_cast<IncompleteArrayType>(QT.getTypePtr())) {
4867 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4868
4869 if (newQT == arr->getElementType()) return QT;
4870 QT = Ctxt.getIncompleteArrayType (newQT,
4871 arr->getSizeModifier(),
4872 arr->getIndexTypeCVRQualifiers());
4873
4874 } else if (const auto arr = dyn_cast<VariableArrayType>(QT.getTypePtr())) {
4875 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4876
4877 if (newQT == arr->getElementType()) return QT;
4878 QT = Ctxt.getVariableArrayType (newQT,
4879 arr->getSizeExpr(),
4880 arr->getSizeModifier(),
4881 arr->getIndexTypeCVRQualifiers(),
4882 arr->getBracketsRange());
4883 }
4884
4885 // Add back the qualifiers.
4886 QT = Ctxt.getQualifiedType(QT, quals);
4887 return QT;
4888 }
4889
4890 // If the instance is also an elaborated type, we need to skip
4891 etype = llvm::dyn_cast<clang::ElaboratedType>(instance);
4892 if (etype) {
4893 instance = etype->getNamedType().getTypePtr();
4894 if (!instance) return input;
4895 }
4896
4897 const clang::TemplateSpecializationType* TST
4898 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instance);
4899
4900 if (!TST) return input;
4901
4902 const clang::ClassTemplateSpecializationDecl* TSTdecl
4903 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(instance->getAsCXXRecordDecl());
4904
4905 if (!TSTdecl) return input;
4906
4907 const clang::SubstTemplateTypeParmType *substType
4908 = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(input.getTypePtr());
4909
4910 if (substType) {
4911 // Make sure it got replaced from this template
4912 const clang::ClassTemplateDecl *replacedCtxt = nullptr;
4913
4914 const clang::DeclContext *replacedDeclCtxt = substType->getReplacedParameter()->getDeclContext();
4915 const clang::CXXRecordDecl *decl = llvm::dyn_cast<clang::CXXRecordDecl>(replacedDeclCtxt);
4916 unsigned int index = substType->getReplacedParameter()->getIndex();
4917 if (decl) {
4918
4919 if (decl->getKind() == clang::Decl::ClassTemplatePartialSpecialization) {
4920 const clang::ClassTemplatePartialSpecializationDecl *spec = llvm::dyn_cast<clang::ClassTemplatePartialSpecializationDecl>(decl);
4921
4922 unsigned int depth = substType->getReplacedParameter()->getDepth();
4923
4924 const TemplateArgument *instanceArgs = spec->getTemplateArgs().data();
4925 unsigned int instanceNArgs = spec->getTemplateArgs().size();
4926
4927 // Search for the 'right' replacement.
4928
4929 for(unsigned int A = 0; A < instanceNArgs; ++A) {
4930 if (instanceArgs[A].getKind() == clang::TemplateArgument::Type) {
4931 clang::QualType argQualType = instanceArgs[A].getAsType();
4932
4933 const clang::TemplateTypeParmType *replacementType;
4934
4935 replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(argQualType);
4936
4937 if (!replacementType) {
4938 const clang::SubstTemplateTypeParmType *argType
4939 = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(argQualType);
4940 if (argType) {
4941 clang::QualType replacementQT = argType->getReplacementType();
4942 replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(replacementQT);
4943 }
4944 }
4945 if (replacementType &&
4946 depth == replacementType->getDepth() &&
4947 index == replacementType->getIndex() )
4948 {
4949 index = A;
4950 break;
4951 }
4952 }
4953 }
4954 replacedCtxt = spec->getSpecializedTemplate();
4955 } else {
4956 replacedCtxt = decl->getDescribedClassTemplate();
4957 }
4958 } else if (auto const declguide = llvm::dyn_cast<clang::CXXDeductionGuideDecl>(replacedDeclCtxt)) {
4959 replacedCtxt = llvm::dyn_cast<clang::ClassTemplateDecl>(declguide->getDeducedTemplate());
4960 } else if (auto const ctdecl = llvm::dyn_cast<clang::ClassTemplateDecl>(replacedDeclCtxt)) {
4962 } else {
4963 std::string astDump;
4964 llvm::raw_string_ostream ostream(astDump);
4965 instance->dump(ostream, Ctxt);
4966 ostream.flush();
4967 ROOT::TMetaUtils::Warning("ReSubstTemplateArg","Unexpected type of declaration context for template parameter: %s.\n\tThe responsible class is:\n\t%s\n",
4968 replacedDeclCtxt->getDeclKindName(), astDump.c_str());
4969 replacedCtxt = nullptr;
4970 }
4971
4972 if (replacedCtxt && replacedCtxt->getCanonicalDecl() == TSTdecl->getSpecializedTemplate()->getCanonicalDecl())
4973 {
4974 const auto &TAs = TST->template_arguments();
4975 if (index >= TAs.size()) {
4976 // The argument replaced was a default template argument that is
4977 // being listed as part of the instance ...
4978 // so we probably don't really know how to spell it ... we would need to recreate it
4979 // (See AddDefaultParameters).
4980 return input;
4981 } else if (TAs[index].getKind() == clang::TemplateArgument::Type) {
4982 return TAs[index].getAsType();
4983 } else {
4984 // The argument is (likely) a value or expression and there is nothing for us
4985 // to change
4986 return input;
4987 }
4988 }
4989 }
4990 // Maybe a class template instance, recurse and rebuild
4991 const clang::TemplateSpecializationType* inputTST
4992 = llvm::dyn_cast<const clang::TemplateSpecializationType>(input.getTypePtr());
4993 const clang::ASTContext& astCtxt = TSTdecl->getASTContext();
4994
4995 if (inputTST) {
4996 bool mightHaveChanged = false;
4997 llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
4998 for (const clang::TemplateArgument &TA : inputTST->template_arguments()) {
4999 if (TA.getKind() != clang::TemplateArgument::Type) {
5000 desArgs.push_back(TA);
5001 continue;
5002 }
5003
5004 clang::QualType SubTy = TA.getAsType();
5005 // Check if the type needs more desugaring and recurse.
5006 if (llvm::isa<clang::ElaboratedType>(SubTy)
5007 || llvm::isa<clang::SubstTemplateTypeParmType>(SubTy)
5008 || llvm::isa<clang::TemplateSpecializationType>(SubTy)) {
5009 clang::QualType newSubTy = ReSubstTemplateArg(SubTy,instance);
5011 if (!newSubTy.isNull()) {
5012 desArgs.push_back(clang::TemplateArgument(newSubTy));
5013 }
5014 } else
5015 desArgs.push_back(TA);
5016 }
5017
5018 // If desugaring happened allocate new type in the AST.
5019 if (mightHaveChanged) {
5020 clang::Qualifiers qualifiers = input.getLocalQualifiers();
5021 input = astCtxt.getTemplateSpecializationType(inputTST->getTemplateName(),
5022 desArgs,
5023 inputTST->getCanonicalTypeInternal());
5024 input = astCtxt.getQualifiedType(input, qualifiers);
5025 }
5026 }
5027
5028 return input;
5029}
5030
5031////////////////////////////////////////////////////////////////////////////////
5032/// Remove the last n template arguments from the name
5033
5035{
5036 if ( nArgsToRemove == 0 || name == "")
5037 return 0;
5038
5039 // We proceed from the right to the left, counting commas which are not
5040 // enclosed by < >.
5041 const unsigned int length = name.length();
5042 unsigned int cur=0; // let's start beyond the first > from the right
5043 unsigned int nArgsRemoved=0;
5044 unsigned int nBraces=0;
5045 char c='@';
5047 c = name[cur];
5048 if (c == '<') nBraces++;
5049 if (c == '>') nBraces--;
5050 if (c == ',' && nBraces==1 /*So we are not in a sub-template*/) nArgsRemoved++;
5051 cur++;
5052 }
5053 cur--;
5054 name = name.substr(0,cur)+">";
5055 return 0;
5056
5057}
5058
5059////////////////////////////////////////////////////////////////////////////////
5060/// Converts STL container name to number. vector -> 1, etc..
5061
5063{
5064 static const char *stls[] = //container names
5065 {"any","vector","list", "deque","map","multimap","set","multiset","bitset",
5066 "forward_list","unordered_set","unordered_multiset","unordered_map","unordered_multimap", "RVec", nullptr};
5067 static const ROOT::ESTLType values[] =
5078 };
5079 // kind of stl container
5080 for (int k = 1; stls[k]; k++) {
5081 if (type == stls[k])
5082 return values[k];
5083 }
5084 return ROOT::kNotSTL;
5085}
5086
5087////////////////////////////////////////////////////////////////////////////////
5088
5089const clang::TypedefNameDecl *ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TypedefNameDecl *TND)
5090{
5091 if (!TND)
5092 return nullptr;
5093
5094 TND = TND->getMostRecentDecl();
5095 while (TND && !(TND->hasAttrs()))
5096 TND = TND->getPreviousDecl();
5097
5098 return TND;
5099}
5100
5101////////////////////////////////////////////////////////////////////////////////
5102
5103const clang::TagDecl *ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TagDecl *TD)
5104{
5105 if (!TD)
5106 return nullptr;
5107
5108 TD = TD->getMostRecentDecl();
5109 while (TD && !(TD->hasAttrs() && TD->isThisDeclarationADefinition()))
5110 TD = TD->getPreviousDecl();
5111
5112 return TD;
5113}
5114
5115////////////////////////////////////////////////////////////////////////////////
5116/// Extract the immediately outer namespace and then launch the recursion
5117
5119 std::list<std::pair<std::string,bool> >& enclosingNamespaces)
5120{
5121 const clang::DeclContext* enclosingNamespaceDeclCtxt = decl.getDeclContext();
5122 if (!enclosingNamespaceDeclCtxt) return;
5123
5124 const clang::NamespaceDecl* enclosingNamespace =
5125 clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
5126 if (!enclosingNamespace) return;
5127
5128 enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
5129 enclosingNamespace->isInline()));
5130
5132
5133}
5134
5135////////////////////////////////////////////////////////////////////////////////
5136/// Extract enclosing namespaces recursively
5137
5139 std::list<std::pair<std::string,bool> >& enclosingNamespaces)
5140{
5141 const clang::DeclContext* enclosingNamespaceDeclCtxt = ctxt.getParent ();
5142
5143 // If no parent is found, nothing more to be done
5145 return;
5146 }
5147
5148 // Check if the parent is a namespace (it could be a class for example)
5149 // if not, nothing to be done here
5150 const clang::NamespaceDecl* enclosingNamespace = clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
5151 if (!enclosingNamespace) return;
5152
5153 // Add to the list of parent namespaces
5154 enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
5155 enclosingNamespace->isInline()));
5156
5157 // here the recursion
5159}
5160
5161////////////////////////////////////////////////////////////////////////////////
5162/// Extract the names and types of containing scopes.
5163/// Stop if a class is met and return its pointer.
5164
5165const clang::RecordDecl *ROOT::TMetaUtils::ExtractEnclosingScopes(const clang::Decl& decl,
5166 std::list<std::pair<std::string,unsigned int> >& enclosingSc)
5167{
5168 const clang::DeclContext* enclosingDeclCtxt = decl.getDeclContext();
5169 if (!enclosingDeclCtxt) return nullptr;
5170
5171 unsigned int scopeType;
5172
5173 if (auto enclosingNamespacePtr =
5174 clang::dyn_cast<clang::NamespaceDecl>(enclosingDeclCtxt)){
5175 scopeType= enclosingNamespacePtr->isInline() ? 1 : 0; // inline or simple namespace
5176 enclosingSc.push_back(std::make_pair(enclosingNamespacePtr->getNameAsString(),scopeType));
5178 }
5179
5180 if (auto enclosingClassPtr =
5181 clang::dyn_cast<clang::RecordDecl>(enclosingDeclCtxt)){
5182 return enclosingClassPtr;
5183 }
5184
5185 return nullptr;
5186}
5187
5188////////////////////////////////////////////////////////////////////////////////
5189/// Reimplementation of TSystem::ExpandPathName() that cannot be
5190/// used from TMetaUtils.
5191
5192static void replaceEnvVars(const char* varname, std::string& txt)
5193{
5194 std::string::size_type beginVar = 0;
5195 std::string::size_type endVar = 0;
5196 while ((beginVar = txt.find('$', beginVar)) != std::string::npos
5197 && beginVar + 1 < txt.length()) {
5198 std::string::size_type beginVarName = beginVar + 1;
5199 std::string::size_type endVarName = std::string::npos;
5200 if (txt[beginVarName] == '(') {
5201 // "$(VARNAME)" style.
5202 endVarName = txt.find(')', beginVarName);
5203 ++beginVarName;
5204 if (endVarName == std::string::npos) {
5205 ROOT::TMetaUtils::Error(nullptr, "Missing ')' for '$(' in $%s at %s\n",
5206 varname, txt.c_str() + beginVar);
5207 return;
5208 }
5209 endVar = endVarName + 1;
5210 } else {
5211 // "$VARNAME/..." style.
5212 beginVarName = beginVar + 1;
5214 while (isalnum(txt[endVarName]) || txt[endVarName] == '_')
5215 ++endVarName;
5217 }
5218
5219 const char* val = std::getenv(txt.substr(beginVarName,
5220 endVarName - beginVarName).c_str());
5221 if (!val) val = "";
5222
5223 txt.replace(beginVar, endVar - beginVar, val);
5224 int lenval = strlen(val);
5225 int delta = lenval - (endVar - beginVar); // these many extra chars,
5226 endVar += delta; // advance the end marker accordingly.
5227
5228 // Look for the next one
5229 beginVar = endVar + 1;
5230 }
5231}
5232
5233////////////////////////////////////////////////////////////////////////////////
5234/// Organise the parameters for cling in order to guarantee relocatability
5235/// It treats the gcc toolchain and the root include path
5236/// FIXME: enables relocatability for experiments' framework headers until PCMs
5237/// are available.
5238
5240{
5241 const char* envInclPath = std::getenv("ROOT_INCLUDE_PATH");
5242
5243 if (!envInclPath)
5244 return;
5245
5246#ifdef _WIN32
5247 constexpr char kPathSep = ';';
5248#else
5249 constexpr char kPathSep = ':';
5250#endif
5251
5252 std::istringstream envInclPathsStream(envInclPath);
5253 std::string inclPath;
5254 while (std::getline(envInclPathsStream, inclPath, kPathSep)) {
5255 // Can't use TSystem in here; re-implement TSystem::ExpandPathName().
5256 replaceEnvVars("ROOT_INCLUDE_PATH", inclPath);
5257 if (!inclPath.empty()) {
5258 clingArgs.push_back("-I");
5259 clingArgs.push_back(inclPath);
5260 }
5261 }
5262}
5263
5264////////////////////////////////////////////////////////////////////////////////
5265
5266void ROOT::TMetaUtils::ReplaceAll(std::string& str, const std::string& from, const std::string& to,bool recurse)
5267{
5268 if(from.empty())
5269 return;
5270 size_t start_pos = 0;
5271 bool changed=true;
5272 while (changed){
5273 changed=false;
5274 start_pos = 0;
5275 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
5276 str.replace(start_pos, from.length(), to);
5277 start_pos += to.length();
5278 if (recurse) changed = true;
5279 }
5280 }
5281}
5282
5283////////////////////////////////////////////////////////////////////////////////
5284/// Return the separator suitable for this platform.
5289
5290////////////////////////////////////////////////////////////////////////////////
5291
5292bool ROOT::TMetaUtils::EndsWith(const std::string &theString, const std::string &theSubstring)
5293{
5294 if (theString.size() < theSubstring.size()) return false;
5295 const unsigned int theSubstringSize = theSubstring.size();
5296 return 0 == theString.compare(theString.size() - theSubstringSize,
5298 theSubstring);
5299}
5300
5301////////////////////////////////////////////////////////////////////////////////
5302
5303bool ROOT::TMetaUtils::BeginsWith(const std::string &theString, const std::string &theSubstring)
5304{
5305 if (theString.size() < theSubstring.size()) return false;
5306 const unsigned int theSubstringSize = theSubstring.size();
5307 return 0 == theString.compare(0,
5309 theSubstring);
5310}
5311
5312
5313
5314////////////////////////////////////////////////////////////////////////////////
5315
5317{
5318 // Note, should change this into take llvm::StringRef.
5319
5320 if ((strstr(filename, "LinkDef") || strstr(filename, "Linkdef") ||
5321 strstr(filename, "linkdef")) && strstr(filename, ".h")) {
5322 return true;
5323 }
5324 size_t len = strlen(filename);
5325 size_t linkdeflen = 9; /* strlen("linkdef.h") */
5326 if (len >= 9) {
5327 if (0 == strncasecmp(filename + (len - linkdeflen), "linkdef", linkdeflen - 2)
5328 && 0 == strcmp(filename + (len - 2), ".h")
5329 ) {
5330 return true;
5331 } else {
5332 return false;
5333 }
5334 } else {
5335 return false;
5336 }
5337}
5338
5339////////////////////////////////////////////////////////////////////////////////
5340
5342{
5343 return llvm::sys::path::extension(filename) == ".h" ||
5344 llvm::sys::path::extension(filename) == ".hh" ||
5345 llvm::sys::path::extension(filename) == ".hpp" ||
5346 llvm::sys::path::extension(filename) == ".H" ||
5347 llvm::sys::path::extension(filename) == ".h++" ||
5348 llvm::sys::path::extension(filename) == "hxx" ||
5349 llvm::sys::path::extension(filename) == "Hxx" ||
5350 llvm::sys::path::extension(filename) == "HXX";
5351}
5352
5353////////////////////////////////////////////////////////////////////////////////
5354
5355const std::string ROOT::TMetaUtils::AST2SourceTools::Decls2FwdDecls(const std::vector<const clang::Decl *> &decls,
5356 cling::Interpreter::IgnoreFilesFunc_t ignoreFiles,
5357 const cling::Interpreter &interp,
5358 std::string *logs)
5359{
5360 clang::Sema &sema = interp.getSema();
5361 cling::Transaction theTransaction(sema);
5362 std::set<clang::Decl *> addedDecls;
5363 for (auto decl : decls) {
5364 // again waiting for cling
5365 clang::Decl *ncDecl = const_cast<clang::Decl *>(decl);
5366 theTransaction.append(ncDecl);
5367 }
5368 std::string newFwdDecl;
5369 llvm::raw_string_ostream llvmOstr(newFwdDecl);
5370
5371 std::string locallogs;
5372 llvm::raw_string_ostream llvmLogStr(locallogs);
5373 interp.forwardDeclare(theTransaction, sema.getPreprocessor(), sema.getASTContext(), llvmOstr, true,
5374 logs ? &llvmLogStr : nullptr, ignoreFiles);
5375 llvmOstr.flush();
5376 llvmLogStr.flush();
5377 if (logs)
5378 logs->swap(locallogs);
5379 return newFwdDecl;
5380}
5381
5382////////////////////////////////////////////////////////////////////////////////
5383/// Take the namespaces which enclose the decl and put them around the
5384/// definition string.
5385/// For example, if the definition string is "myClass" which is enclosed by
5386/// the namespaces ns1 and ns2, one would get:
5387/// namespace ns2{ namespace ns1 { class myClass; } }
5388
5390 std::string& defString)
5391{
5393 return rcd ? 1:0;
5394}
5395
5396////////////////////////////////////////////////////////////////////////////////
5397/// Take the scopes which enclose the decl and put them around the
5398/// definition string.
5399/// If a class is encountered, bail out.
5400
5401const clang::RecordDecl* ROOT::TMetaUtils::AST2SourceTools::EncloseInScopes(const clang::Decl& decl,
5402 std::string& defString)
5403{
5404 std::list<std::pair<std::string,unsigned int> > enclosingNamespaces;
5406
5407 if (rcdPtr) return rcdPtr;
5408
5409 // Check if we have enclosing namespaces
5410 static const std::string scopeType [] = {"namespace ", "inline namespace ", "class "};
5411
5412 std::string scopeName;
5413 std::string scopeContent;
5414 unsigned int scopeIndex;
5415 for (auto const & encScope : enclosingNamespaces){
5416 scopeIndex = encScope.second;
5417 scopeName = encScope.first;
5418 scopeContent = " { " + defString + " }";
5420 scopeName +
5422 }
5423 return nullptr;
5424}
5425
5426////////////////////////////////////////////////////////////////////////////////
5427/// Loop over the template parameters and build a string for template arguments
5428/// using the fully qualified name
5429/// There are different cases:
5430/// Case 1: a simple template parameter
5431/// E.g. `template<typename T> class A;`
5432/// Case 2: a non-type: either an integer or an enum
5433/// E.g. `template<int I, Foo > class A;` where `Foo` is `enum Foo {red, blue};`
5434/// 2 sub cases here:
5435/// SubCase 2.a: the parameter is an enum: bail out, cannot be treated.
5436/// SubCase 2.b: use the fully qualified name
5437/// Case 3: a TemplateTemplate argument
5438/// E.g. `template <template <typename> class T> class container { };`
5439
5441 const clang::TemplateParameterList& tmplParamList,
5442 const cling::Interpreter& interpreter)
5443{
5444 templateArgs="<";
5445 for (auto prmIt = tmplParamList.begin();
5446 prmIt != tmplParamList.end(); prmIt++){
5447
5448 if (prmIt != tmplParamList.begin())
5449 templateArgs += ", ";
5450
5451 auto nDecl = *prmIt;
5452 std::string typeName;
5453
5454 // Case 1
5455 if (llvm::isa<clang::TemplateTypeParmDecl>(nDecl)){
5456 typeName = "typename ";
5457 if (nDecl->isParameterPack())
5458 typeName += "... ";
5459 typeName += (*prmIt)->getNameAsString();
5460 }
5461 // Case 2
5462 else if (auto nttpd = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(nDecl)){
5463 auto theType = nttpd->getType();
5464 // If this is an enum, use int as it is impossible to fwd declare and
5465 // this makes sense since it is not a type...
5466 if (theType.getAsString().find("enum") != std::string::npos){
5467 std::string astDump;
5468 llvm::raw_string_ostream ostream(astDump);
5469 nttpd->dump(ostream);
5470 ostream.flush();
5471 ROOT::TMetaUtils::Warning(nullptr,"Forward declarations of templates with enums as template parameters. The responsible class is: %s\n", astDump.c_str());
5472 return 1;
5473 } else {
5475 theType,
5476 interpreter);
5477 }
5478 }
5479 // Case 3: TemplateTemplate argument
5480 else if (auto ttpd = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(nDecl)){
5482 if (retCode!=0){
5483 std::string astDump;
5484 llvm::raw_string_ostream ostream(astDump);
5485 ttpd->dump(ostream);
5486 ostream.flush();
5487 ROOT::TMetaUtils::Error(nullptr,"Cannot reconstruct template template parameter forward declaration for %s\n", astDump.c_str());
5488 return 1;
5489 }
5490 }
5491
5492 templateArgs += typeName;
5493 }
5494
5495 templateArgs+=">";
5496 return 0;
5497}
5498
5499////////////////////////////////////////////////////////////////////////////////
5500/// Convert a tmplt decl to its fwd decl
5501
5503 const cling::Interpreter& interpreter,
5504 std::string& defString)
5505{
5506 std::string templatePrefixString;
5507 auto tmplParamList= templDecl.getTemplateParameters();
5508 if (!tmplParamList){ // Should never happen
5509 Error(nullptr,
5510 "Cannot extract template parameter list for %s",
5511 templDecl.getNameAsString().c_str());
5512 return 1;
5513 }
5514
5516 if (retCode!=0){
5517 Warning(nullptr,
5518 "Problems with arguments for forward declaration of class %s\n",
5519 templDecl.getNameAsString().c_str());
5520 return retCode;
5521 }
5522 templatePrefixString = "template " + templatePrefixString + " ";
5523
5524 defString = templatePrefixString + "class ";
5525 if (templDecl.isParameterPack())
5526 defString += "... ";
5527 defString += templDecl.getNameAsString();
5528 if (llvm::isa<clang::TemplateTemplateParmDecl>(&templDecl)) {
5529 // When fwd declaring the template template arg of
5530 // namespace N { template <template <class T> class C> class X; }
5531 // we don't need to put it into any namespace, and we want no trailing
5532 // ';'
5533 return 0;
5534 }
5535 defString += ';';
5537}
5538
5539////////////////////////////////////////////////////////////////////////////////
5540
5541static int TreatSingleTemplateArg(const clang::TemplateArgument& arg,
5542 std::string& argFwdDecl,
5543 const cling::Interpreter& interpreter,
5544 bool acceptStl=false)
5545{
5546 using namespace ROOT::TMetaUtils::AST2SourceTools;
5547
5548 // We do nothing in presence of ints, bools, templates.
5549 // We should probably in presence of templates though...
5550 if (clang::TemplateArgument::Type != arg.getKind()) return 0;
5551
5552 auto argQualType = arg.getAsType();
5553
5554 // Recursively remove all *
5555 while (llvm::isa<clang::PointerType>(argQualType.getTypePtr())) argQualType = argQualType->getPointeeType();
5556
5557 auto argTypePtr = argQualType.getTypePtr();
5558
5559 // Bail out on enums
5560 if (llvm::isa<clang::EnumType>(argTypePtr)){
5561 return 1;
5562 }
5563
5564 // If this is a built-in, just return: fwd decl not necessary.
5565 if (llvm::isa<clang::BuiltinType>(argTypePtr)){
5566 return 0;
5567 }
5568
5569 // Treat typedefs which are arguments
5570 if (auto tdTypePtr = llvm::dyn_cast<clang::TypedefType>(argTypePtr)) {
5571 FwdDeclFromTypeDefNameDecl(*tdTypePtr->getDecl(), interpreter, argFwdDecl);
5572 return 0;
5573 }
5574
5575 if (auto argRecTypePtr = llvm::dyn_cast<clang::RecordType>(argTypePtr)){
5576 // Now we cannot but have a RecordType
5577 if (auto argRecDeclPtr = argRecTypePtr->getDecl()){
5578 FwdDeclFromRcdDecl(*argRecDeclPtr,interpreter,argFwdDecl,acceptStl);
5579 }
5580 return 0;
5581 }
5582
5583 return 1;
5584}
5585
5586////////////////////////////////////////////////////////////////////////////////
5587/// Convert a tmplt decl to its fwd decl
5588
5590 const cling::Interpreter& interpreter,
5591 std::string& defString,
5592 const std::string &normalizedName)
5593{
5594 // If this is an explicit specialization, inject it into cling, too, such that it can have
5595 // externalLexicalStorage, see TCling.cxx's ExtVisibleStorageAdder::VisitClassTemplateSpecializationDecl.
5596 if (auto tmplSpecDeclPtr = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)) {
5597 if (const auto *specDef = tmplSpecDeclPtr->getDefinition()) {
5598 if (specDef->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization)
5599 return 0;
5600 // normalizedName contains scope, no need to enclose in namespace!
5602 std::cout << " Forward declaring template spec " << normalizedName << ":\n";
5603 for (auto arg : tmplSpecDeclPtr->getTemplateArgs().asArray()) {
5604 std::string argFwdDecl;
5605 int retCode = TreatSingleTemplateArg(arg, argFwdDecl, interpreter, /*acceptStl=*/false);
5607 std::cout << " o Template argument ";
5608 if (retCode == 0) {
5609 std::cout << "successfully treated. Arg fwd decl: " << argFwdDecl << std::endl;
5610 } else {
5611 std::cout << "could not be treated. Abort fwd declaration generation.\n";
5612 }
5613 }
5614
5615 if (retCode != 0) { // A sign we must bail out
5616 return retCode;
5617 }
5618 defString += argFwdDecl + '\n';
5619 }
5620 defString += "template <> class " + normalizedName + ';';
5621 return 0;
5622 }
5623 }
5624
5625 return 0;
5626}
5627
5628////////////////////////////////////////////////////////////////////////////////
5629/// Convert a rcd decl to its fwd decl
5630/// If this is a template specialisation, treat in the proper way.
5631/// If it is contained in a class, just fwd declare the class.
5632
5634 const cling::Interpreter& interpreter,
5635 std::string& defString,
5636 bool acceptStl)
5637{
5638 // Do not fwd declare the templates in the stl.
5640 return 0;
5641
5642 // Do not fwd declare unnamed decls.
5643 if (!recordDecl.getIdentifier())
5644 return 0;
5645
5646 // We may need to fwd declare the arguments of the template
5647 std::string argsFwdDecl;
5648
5649 if (auto tmplSpecDeclPtr = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)){
5650 std::string argFwdDecl;
5652 std::cout << "Class " << recordDecl.getNameAsString()
5653 << " is a template specialisation. Treating its arguments.\n";
5654 for(auto arg : tmplSpecDeclPtr->getTemplateArgs().asArray()){
5657 std::cout << " o Template argument ";
5658 if (retCode==0){
5659 std::cout << "successfully treated. Arg fwd decl: " << argFwdDecl << std::endl;
5660 } else {
5661 std::cout << "could not be treated. Abort fwd declaration generation.\n";
5662 }
5663 }
5664
5665 if (retCode!=0){ // A sign we must bail out
5666 return retCode;
5667 }
5669 }
5670
5671 if (acceptStl){
5673 return 0;
5674 }
5675
5676 int retCode=0;
5677 if (auto tmplDeclPtr = tmplSpecDeclPtr->getSpecializedTemplate()){
5679 }
5680 defString = argsFwdDecl + "\n" + defString;
5681 return retCode;
5682
5683 }
5684
5685 defString = "class " + recordDecl.getNameAsString() + ";";
5686 const clang::RecordDecl* rcd = EncloseInScopes(recordDecl, defString);
5687
5688 if (rcd){
5690 }
5691 // Add a \n here to avoid long lines which contain duplications, for example (from MathCore):
5692 // namespace ROOT { namespace Math { class IBaseFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5693 // namespace ROOT { namespace Math { class IGradientFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5694 defString = argsFwdDecl + "\n" + defString;
5695
5696 return 0;
5697}
5698
5699////////////////////////////////////////////////////////////////////////////////
5700/// Extract "forward declaration" of a typedef.
5701/// If the typedef is contained in a class, just fwd declare the class.
5702/// If not, fwd declare the typedef and all the dependent typedefs and types if necessary.
5703
5705 const cling::Interpreter& interpreter,
5706 std::string& fwdDeclString,
5707 std::unordered_set<std::string>* fwdDeclSetPtr)
5708{
5709 std::string buffer = tdnDecl.getNameAsString();
5710 std::string underlyingName;
5711 auto underlyingType = tdnDecl.getUnderlyingType().getCanonicalType();
5712 if (const clang::TagType* TT
5713 = llvm::dyn_cast<clang::TagType>(underlyingType.getTypePtr())) {
5714 if (clang::NamedDecl* ND = TT->getDecl()) {
5715 if (!ND->getIdentifier()) {
5716 // No fwd decl for unnamed underlying entities.
5717 return 0;
5718 }
5719 }
5720 }
5721
5722 TNormalizedCtxt nCtxt(interpreter.getLookupHelper());
5726 nCtxt);
5727
5728 // Heuristic: avoid entities like myclass<myType1, myType2::xyz>
5729 if (underlyingName.find(">::") != std::string::npos)
5730 return 0;
5731
5732 buffer="typedef "+underlyingName+" "+buffer+";";
5733 const clang::RecordDecl* rcd=EncloseInScopes(tdnDecl,buffer);
5734 if (rcd) {
5735 // We do not need the whole series of scopes, just the class.
5736 // It is enough to trigger an uncomplete type autoload/parse callback
5737 // for example: MyClass::blabla::otherNs::myTypedef
5739 }
5740
5741 // Start Recursion if the underlying type is a TypedefNameDecl
5742 // Note: the simple cast w/o the getSingleStepDesugaredType call
5743 // does not work in case the typedef is in a namespace.
5744 auto& ctxt = tdnDecl.getASTContext();
5745 auto immediatelyUnderlyingType = underlyingType.getSingleStepDesugaredType(ctxt);
5746
5747 if (auto underlyingTdnTypePtr = llvm::dyn_cast<clang::TypedefType>(immediatelyUnderlyingType.getTypePtr())){
5748 std::string tdnFwdDecl;
5752 tdnFwdDecl,
5754 if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(tdnFwdDecl).second)
5756 } else if (auto CXXRcdDeclPtr = immediatelyUnderlyingType->getAsCXXRecordDecl()){
5757 std::string classFwdDecl;
5759 std::cout << "Typedef " << tdnDecl.getNameAsString() << " hides a class: "
5760 << CXXRcdDeclPtr->getNameAsString() << std::endl;
5764 true /* acceptStl*/);
5765 if (retCode!=0){ // bail out
5766 return 0;
5767 }
5768
5769 if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(classFwdDecl).second)
5771 }
5772
5773 fwdDeclString+=buffer;
5774
5775 return 0;
5776}
5777
5778////////////////////////////////////////////////////////////////////////////////
5779/// Get the default value as string.
5780/// Limited at the moment to:
5781/// - Integers
5782/// - Booleans
5783
5784int ROOT::TMetaUtils::AST2SourceTools::GetDefArg(const clang::ParmVarDecl& par,
5785 std::string& valAsString,
5786 const clang::PrintingPolicy& ppolicy)
5787{
5788 auto defArgExprPtr = par.getDefaultArg();
5789 auto& ctxt = par.getASTContext();
5790 if(!defArgExprPtr->isEvaluatable(ctxt)){
5791 return -1;
5792 }
5793
5794 auto defArgType = par.getType();
5795
5796 // The value is a boolean
5797 if (defArgType->isBooleanType()){
5798 bool result;
5799 defArgExprPtr->EvaluateAsBooleanCondition (result,ctxt);
5800 valAsString=std::to_string(result);
5801 return 0;
5802 }
5803
5804 // The value is an integer
5805 if (defArgType->isIntegerType()){
5806 clang::Expr::EvalResult evalResult;
5807 defArgExprPtr->EvaluateAsInt(evalResult, ctxt);
5808 llvm::APSInt result = evalResult.Val.getInt();
5809 auto uintVal = *result.getRawData();
5810 if (result.isNegative()){
5811 long long int intVal=uintVal*-1;
5812 valAsString=std::to_string(intVal);
5813 } else {
5814 valAsString=std::to_string(uintVal);
5815 }
5816
5817 return 0;
5818 }
5819
5820 // The value is something else. We go for the generalised printer
5821 llvm::raw_string_ostream rso(valAsString);
5822 defArgExprPtr->printPretty(rso,nullptr,ppolicy);
5823 valAsString = rso.str();
5824 // We can be in presence of a string. Let's escape the characters properly.
5825 ROOT::TMetaUtils::ReplaceAll(valAsString,"\\\"","__TEMP__VAL__");
5827 ROOT::TMetaUtils::ReplaceAll(valAsString,"__TEMP__VAL__","\\\"");
5828
5829 return 0;
5830}
5831
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:157
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