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