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