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