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