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