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