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