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