Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Scanner.cxx
Go to the documentation of this file.
1// @(#)root/utils/src:$Id$
2// Author: Philippe Canal November 2011 ; originated from Zdenek Culik 16/04/2010 and Velislava Spasova.
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/rootcint. *
10 *************************************************************************/
11
12#include "Scanner.h"
13#include "clang/AST/ASTConsumer.h"
14#include "clang/Basic/SourceLocation.h"
15#include "clang/Basic/SourceManager.h"
16#include "llvm/ADT/SmallSet.h"
17#include "clang/Sema/Sema.h"
18#include "clang/Frontend/CompilerInstance.h"
19
20#include "cling/Interpreter/Interpreter.h"
21#include "llvm/Support/Path.h"
22
23#include "TClassEdit.h"
24
25#include <iostream>
26#include <sstream> // class ostringstream
27#include "llvm/ADT/StringExtras.h"
28
29#include "SelectionRules.h"
30
31namespace {
32
33 class RPredicateIsSameNamespace
34 {
35 private:
36 clang::NamespaceDecl *fTarget;
37 public:
38 RPredicateIsSameNamespace(clang::NamespaceDecl *target) : fTarget(target) {}
39
41 {
42 return (fTarget == element);
43 }
44 };
45
46template<class T>
47inline static bool IsElementPresent(const std::vector<T> &v, const T &el){
48 return std::find(v.begin(),v.end(),el) != v.end();
49}
50
51template<class T>
52inline static bool IsElementPresent(const std::vector<const T*> &v, T *el){
53 return std::find(v.begin(),v.end(),el) != v.end();
54}
55
56}
57
58using namespace ROOT;
59using namespace clang;
60
61const char* RScanner::fgClangDeclKey = "ClangDecl"; // property key used for connection with Clang objects
62const char* RScanner::fgClangFuncKey = "ClangFunc"; // property key for demangled names
63
67
68std::map <clang::Decl*, std::string> RScanner::fgAnonymousClassMap;
69std::map <clang::Decl*, std::string> RScanner::fgAnonymousEnumMap;
70
71////////////////////////////////////////////////////////////////////////////////
72/// Regular constructor setting up the scanner to search for entities
73/// matching the 'rules'.
74
76 EScanType stype,
77 const cling::Interpreter &interpret,
79 unsigned int verbose /* = 0 */) :
80 fVerboseLevel(verbose),
81 fSourceManager(nullptr),
82 fInterpreter(interpret),
83 fRecordDeclCallback(nullptr),
84 fNormCtxt(normCtxt),
85 fSelectionRules(rules),
86 fScanType(stype),
87 fFirstPass(true)
88{
89 // Build the cache for all selection rules
91
92 for (int i = 0; i <= fgDeclLast; i ++)
93 fDeclTable [i] = false;
94
95 for (int i = 0; i <= fgTypeLast; i ++)
96 fTypeTable [i] = false;
97
98 fLastDecl = nullptr;
99}
100
101////////////////////////////////////////////////////////////////////////////////
102
106
107////////////////////////////////////////////////////////////////////////////////
108/// Whether we can actually visit this declaration, i.e. if it is reachable
109/// via name lookup.
110///
111/// RScanner shouldn't touch decls for which this method returns false as we
112/// call Sema methods on those declarations. Those will fail in strange way as
113/// they assume those decls are already visible.
114///
115/// The main problem this is supposed to prevent is when we use C++ modules and
116/// have hidden declarations in our AST. Usually they can't be found as they are
117/// hidden from name lookup until their module is actually imported, but as the
118/// RecursiveASTVisitor is not supposed to be restricted by lookup limitations,
119/// it still reaches those hidden declarations.
120bool RScanner::shouldVisitDecl(clang::NamedDecl *D)
121{
122 if (auto M = D->getOwningModule()) {
123 return fInterpreter.getSema().isModuleVisible(M);
124 }
125 return true;
126}
127
128////////////////////////////////////////////////////////////////////////////////
129
130inline void* ToDeclProp(clang::Decl* item)
131{
132 /* conversion and type check used by AddProperty */
133 return item;
134}
135
136////////////////////////////////////////////////////////////////////////////////
137
138inline size_t APIntToSize(const llvm::APInt& num)
139{
140 return *num.getRawData();
141}
142
143////////////////////////////////////////////////////////////////////////////////
144
145inline long APIntToLong(const llvm::APInt& num)
146{
147 return *num.getRawData();
148}
149
150////////////////////////////////////////////////////////////////////////////////
151
152inline std::string APIntToStr(const llvm::APInt& num)
153{
154 return llvm::toString(num, /*radix*/10, /*signed*/true);
155}
156
157////////////////////////////////////////////////////////////////////////////////
158
159inline std::string IntToStr(int num)
160{
161 std::string txt = "";
162 txt += num;
163 return txt;
164}
165
166////////////////////////////////////////////////////////////////////////////////
167
168inline std::string IntToStd(int num)
169{
170 std::ostringstream stream;
171 stream << num;
172 return stream.str();
173}
174
175////////////////////////////////////////////////////////////////////////////////
176
177inline std::string Message(const std::string &msg, const std::string &location)
178{
179 std::string loc = location;
180
181 if (loc == "")
182 return msg;
183 else
184 return loc + " " + msg;
185}
186
187////////////////////////////////////////////////////////////////////////////////
188
189void RScanner::ShowInfo(const std::string &msg, const std::string &location) const
190{
191 const std::string message = Message(msg, location);
192 std::cout << message << std::endl;
193}
194
195////////////////////////////////////////////////////////////////////////////////
196
197void RScanner::ShowWarning(const std::string &msg, const std::string &location) const
198{
199 const std::string message = Message(msg, location);
200 std::cout << message << std::endl;
201}
202
203////////////////////////////////////////////////////////////////////////////////
204
205void RScanner::ShowError(const std::string &msg, const std::string &location) const
206{
207 const std::string message = Message(msg, location);
208 std::cout << message << std::endl;
209}
210
211////////////////////////////////////////////////////////////////////////////////
212
213void RScanner::ShowTemplateInfo(const std::string &msg, const std::string &location) const
214{
215 std::string loc = location;
216 if (loc == "")
219}
220
221////////////////////////////////////////////////////////////////////////////////
222
223std::string RScanner::GetSrcLocation(clang::SourceLocation L) const
224{
225 std::string location = "";
226 llvm::raw_string_ostream stream(location);
227 L.print(stream, *fSourceManager);
228 return stream.str();
229}
230
231////////////////////////////////////////////////////////////////////////////////
232
233std::string RScanner::GetLocation(clang::Decl* D) const
234{
235 if (D == nullptr)
236 {
237 return "";
238 }
239 else
240 {
241 std::string location = "";
242 llvm::raw_string_ostream stream(location);
243 D->getLocation().print(stream, *fSourceManager);
244 return stream.str();
245 }
246}
247
248////////////////////////////////////////////////////////////////////////////////
249
250std::string RScanner::GetName(clang::Decl* D) const
251{
252 std::string name = "";
253 // std::string kind = D->getDeclKindName();
254
255 if (clang::NamedDecl* ND = dyn_cast <clang::NamedDecl> (D)) {
256 name = ND->getQualifiedNameAsString();
257 }
258
259 return name;
260}
261
262////////////////////////////////////////////////////////////////////////////////
263
264inline std::string AddSpace(const std::string &txt)
265{
266 if (txt == "")
267 return "";
268 else
269 return txt + " ";
270}
271
272////////////////////////////////////////////////////////////////////////////////
273
274void RScanner::DeclInfo(clang::Decl* D) const
275{
276 std::string location = GetLocation(D);
277 std::string kind = D->getDeclKindName();
278 std::string name = GetName(D);
279 ShowInfo("Scan: " + kind + " declaration " + name, location);
280}
281
282////////////////////////////////////////////////////////////////////////////////
283/// unknown - this kind of declaration was not known to programmer
284
285void RScanner::UnknownDecl(clang::Decl* D, const std::string &txt) const
286{
287 std::string location = GetLocation(D);
288 std::string kind = D->getDeclKindName();
289 std::string name = GetName(D);
290 ShowWarning("Unknown " + AddSpace(txt) + kind + " declaration " + name, location);
291}
292
293////////////////////////////////////////////////////////////////////////////////
294/// unexpected - this kind of declaration is unexpected (in concrete place)
295
296void RScanner::UnexpectedDecl(clang::Decl* D, const std::string &txt) const
297{
298 std::string location = GetLocation(D);
299 std::string kind = D->getDeclKindName();
300 std::string name = GetName(D);
301 ShowWarning("Unexpected " + kind + " declaration " + name, location);
302}
303
304////////////////////////////////////////////////////////////////////////////////
305/// unsupported - this kind of declaration is probably not used (in current version of C++)
306
307void RScanner::UnsupportedDecl(clang::Decl* D, const std::string &txt) const
308{
309 std::string location = GetLocation(D);
310 std::string kind = D->getDeclKindName();
311 std::string name = GetName(D);
312 ShowWarning("Unsupported " + AddSpace(txt) + kind + " declaration " + name, location);
313}
314
315////////////////////////////////////////////////////////////////////////////////
316/// unimportant - this kind of declaration is not stored into reflex
317
318void RScanner::UnimportantDecl(clang::Decl* D, const std::string &txt) const
319{
320}
321
322////////////////////////////////////////////////////////////////////////////////
323/// information about item, that should be implemented
324
325void RScanner::UnimplementedDecl(clang::Decl* D, const std::string &txt)
326{
327 clang::Decl::Kind k = D->getKind();
328
329 bool show = true;
330 if (k <= fgDeclLast) {
331 if (fDeclTable [k])
332 show = false; // already displayed
333 else
334 fDeclTable [k] = true;
335 }
336
337 if (show)
338 {
339 std::string location = GetLocation(D);
340 std::string kind = D->getDeclKindName();
341 std::string name = GetName(D);
342 std::string msg = "Unimplemented ";
343 if (txt == "") {
344 msg += "declaration";
345 } else {
346 msg += txt;
347 }
348 msg += ": ";
349 msg += kind;
350 msg += " ";
351 msg += name;
352 ShowWarning(msg,location);
353 }
354}
355
356////////////////////////////////////////////////////////////////////////////////
357
358void RScanner::UnknownType(clang::QualType qual_type) const
359{
360 std::string location = GetLocation(fLastDecl);
361 std::string kind = qual_type.getTypePtr()->getTypeClassName();
362 ShowWarning("Unknown " + kind + " type " + qual_type.getAsString(), location);
363}
364
365////////////////////////////////////////////////////////////////////////////////
366
367void RScanner::UnsupportedType(clang::QualType qual_type) const
368{
369 std::string location = GetLocation(fLastDecl);
370 std::string kind = qual_type.getTypePtr()->getTypeClassName();
371 ShowWarning("Unsupported " + kind + " type " + qual_type.getAsString(), location);
372}
373
374////////////////////////////////////////////////////////////////////////////////
375
376std::string RScanner::GetEnumName(clang::EnumDecl* D) const
377{
378 std::string enum_name = D->getQualifiedNameAsString();
379
380 if (! D->getDeclName ()) {
381 if (fgAnonymousEnumMap.find (D) != fgAnonymousEnumMap.end())
382 {
383 // already encountered anonymous enumeration type
385 }
386 else
387 {
389 enum_name = "_ANONYMOUS_ENUM_" + IntToStd(fgAnonymousEnumCounter) + "_"; // !?
391 // ShowInfo ("anonymous enum " + enum_name, GetLocation (D));
392 }
393 }
394
395 return enum_name;
396}
397
398////////////////////////////////////////////////////////////////////////////////
399
400std::string RScanner::ExprToStr(clang::Expr* expr) const
401{
402 clang::LangOptions lang_opts;
403 clang::PrintingPolicy print_opts(lang_opts); // !?
404
405 std::string text = "";
406 llvm::raw_string_ostream stream(text);
407
408 expr->printPretty(stream, nullptr, print_opts);
409
410 return stream.str();
411}
412
413////////////////////////////////////////////////////////////////////////////////
414
415std::string RScanner::ConvTemplateName(clang::TemplateName& N) const
416{
417 clang::LangOptions lang_opts;
418 clang::PrintingPolicy print_opts(lang_opts); // !?
419
420 std::string text = "";
421 llvm::raw_string_ostream stream(text);
422
423 N.print(stream, print_opts);
424
425 return stream.str();
426}
427
428////////////////////////////////////////////////////////////////////////////////
429
430std::string RScanner::FuncParameters(clang::FunctionDecl* D) const
431{
432 std::string result = "";
433
434 for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
435 clang::ParmVarDecl* P = *I;
436
437 if (result != "")
438 result += ";"; // semicolon, not comma, important
439
440 std::string type = P->getType().getAsString();
441 std::string name = P->getNameAsString();
442
443 result += type + " " + name;
444
445 // NO if (P->hasDefaultArg ()) // check hasUnparsedDefaultArg () and hasUninstantiatedDefaultArg ()
446 if (P->getInit()) {
447 std::string init_value = ExprToStr(P->getDefaultArg());
448 result += "=" + init_value;
449 }
450 }
451
452 return result;
453}
454
455////////////////////////////////////////////////////////////////////////////////
456
457std::string RScanner::FuncParameterList(clang::FunctionDecl* D) const
458{
459 std::string result = "";
460
461 for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
462 clang::ParmVarDecl* P = *I;
463
464 if (result != "")
465 result += ",";
466
467 std::string type = P->getType().getAsString();
468 result += type;
469 }
470
471 return "(" + result + ")";
472}
473
474////////////////////////////////////////////////////////////////////////////////
475/// This method visits a namespace node
476
477bool RScanner::VisitNamespaceDecl(clang::NamespaceDecl* N)
478{
479 // We don't need to visit this while creating the big PCM
481 return true;
482
483 if (!shouldVisitDecl(N))
484 return true;
485
486 // in case it is implicit we don't create a builder
487 // [Note: Can N be nullptr?, is so 'ShouldVisitDecl' should test or we should test sooner]
488 if((N && N->isImplicit()) || !N){
489 return true;
490 }
491
492 bool ret = true;
493
495 if (selected) {
496
497 clang::DeclContext* primary_ctxt = N->getPrimaryContext();
498 clang::NamespaceDecl* primary = llvm::dyn_cast<clang::NamespaceDecl>(primary_ctxt);
499
500 RPredicateIsSameNamespace pred(primary);
502 // The namespace is not already registered.
503
504 if (fVerboseLevel > 0) {
505 std::string qual_name;
507 // std::cout<<"\tSelected namespace -> " << qual_name << " ptr " << (void*)N << " decl ctxt " << (void*)N->getPrimaryContext() << " classname " <<primary->getNameAsString() << "\n";
508 std::cout<<"\tSelected namespace -> " << qual_name << "\n";
509 }
510 fSelectedNamespaces.push_back(AnnotatedNamespaceDecl(primary,selected->GetIndex(),selected->RequestOnlyTClass()));
511 }
512 ret = true;
513 }
514
515 return ret;
516}
517
518////////////////////////////////////////////////////////////////////////////////
519
520bool RScanner::VisitRecordDecl(clang::RecordDecl* D)
521{
522 if (!shouldVisitDecl(D))
523 return true;
524
525 // This method visits a class node
527
528
529}
530
531////////////////////////////////////////////////////////////////////////////////
532
534 const clang::Type* req_type,
535 const clang::RecordDecl* recordDecl,
536 const std::string& attr_name,
537 const clang::TypedefNameDecl* typedefNameDecl,
538 unsigned int indexOffset)
539{
540
541 bool has_attr_name = selected->HasAttributeName();
542
543 if (recordDecl->isUnion() &&
545 std::string normName;
547 recordDecl->getASTContext().getTypeDeclType(recordDecl),
549 fNormCtxt);
550 ROOT::TMetaUtils::Error(nullptr,"Union %s has been selected for I/O. This is not supported. Interactive usage of unions is supported, as all C++ entities, without the need of dictionaries.\n",normName.c_str());
551 return 1;
552 }
553
554 // clang-format off
555 if (has_attr_name) {
556 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
557 req_type,
559 attr_name.c_str(),
560 selected->RequestStreamerInfo(),
561 selected->RequestNoStreamer(),
562 selected->RequestNoInputOperator(),
563 selected->RequestOnlyTClass(),
564 selected->RequestedVersionNumber(),
565 selected->RequestedRNTupleSerializationMode(),
567 fNormCtxt);
568 } else {
569 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
571 selected->RequestStreamerInfo(),
572 selected->RequestNoStreamer(),
573 selected->RequestNoInputOperator(),
574 selected->RequestOnlyTClass(),
575 selected->RequestedVersionNumber(),
576 selected->RequestedRNTupleSerializationMode(),
578 fNormCtxt);
579 }
580 // clang-format on
581
582 if (fVerboseLevel > 0) {
583 std::string qual_name;
585 std::string normName;
587 recordDecl->getASTContext().getTypeDeclType(recordDecl),
589 fNormCtxt);
590 std::string typedef_qual_name;
591 std::string typedefMsg;
592 if (typedefNameDecl){
594 typedefMsg = "(through typedef/alias " + typedef_qual_name + ") ";
595 }
596
597 std::cout << "Selected class "
598 << typedefMsg
599 << "-> "
600 << qual_name
601 << " for ROOT: "
602 << normName
603 << "\n";
604 }
605 return 0;
606}
607
608////////////////////////////////////////////////////////////////////////////////
609
611{
612 // For every class is created a new class buider irrespectful of weather the
613 // class is internal for another class declaration or not.
614 // RecordDecls and TypedefDecls (or RecordDecls!) are treated.
615 // We follow two different codepaths if the typeDecl is a RecordDecl or
616 // a TypedefDecl. If typeDecl is a TypedefDecl, recordDecl becomes the
617 // underlying RecordDecl.
618 // This is done to leverage the selections rule matching in SelectionRules
619 // which works basically with names.
620 // At the end of the method, if the typedef name is matched, an AnnotatedRecordDecl
621 // with the underlying RecordDecl is fed to the machinery.
622
623 const clang::RecordDecl* recordDecl = clang::dyn_cast<clang::RecordDecl>(typeDecl);
624 const clang::TypedefNameDecl* typedefNameDecl = clang::dyn_cast<clang::TypedefNameDecl>(typeDecl);
625
626 // If typeDecl is not a RecordDecl, try to fetch the RecordDecl behind the TypedefDecl
627 if (!recordDecl && typedefNameDecl) {
629 }
630
631 // If at this point recordDecl is still NULL, we have a problem
632 if (!recordDecl) {
633 ROOT::TMetaUtils::Warning("RScanner::TreatRecordDeclOrTypeNameDecl",
634 "Could not cast typeDecl either to RecordDecl or could not get RecordDecl underneath typedef.\n");
635 return true;
636 }
637
638 // Do not select unnamed records.
639 if (!recordDecl->getIdentifier())
640 return true;
641
642 // Do not select dependent types.
643 if (recordDecl->isDependentType())
644 return true;
645
647 return true;
648
649
650 // At this point, recordDecl must be a RecordDecl pointer.
651
653 // Pass on any declaration. This is usually used to record dependency.
654 // Since rootcint see C++ compliant header files, we can assume that
655 // if a forward declaration or declaration has been inserted, the
656 // classes for which we are creating a dictionary will be using
657 // them either directly or indirectly. Any false positive can be
658 // resolved by removing the spurrious dependency in the (user) header
659 // files.
661 }
662
663 // in case it is implicit or a forward declaration, we are not interested.
664 if(recordDecl->isImplicit() || !recordDecl->isCompleteDefinition()) {
665 return true;
666 }
667
668 // Never select the class templates themselves.
669 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl);
670 if (cxxdecl && cxxdecl->getDescribedClassTemplate ()) {
671 return true;
672 }
673
675
676 const ClassSelectionRule *selectedFromRecDecl = fSelectionRules.IsDeclSelected(recordDecl, false /* exclude typedef rules*/);
677
679
680 if (! selected) return true; // early exit. Nothing more to be done.
681
682 // Selected through typedef but excluded with concrete classname
683 bool excludedFromRecDecl = false;
686
687 if (selected->GetSelected() != BaseSelectionRule::kYes || excludedFromRecDecl)
688 return true;
689
690 // Save the typedef
694 // Don't generate a dictionary for the class underlying a typedef found
695 // for a file name match (eg. "defined_in")
696 if (!selectedFromRecDecl && selectedFromTypedef->HasAttributeFileName())
697 return true;
698 }
699
700 if (selected->IsFromTypedef()) {
703 return true;
704 }
705
706 if (typedefNameDecl)
707 ROOT::TMetaUtils::Info("RScanner::TreatRecordDeclOrTypedefNameDecl",
708 "Typedef is selected %s.\n", typedefNameDecl->getNameAsString().c_str());
709
710 // For the case kNo, we could (but don't) remove the node from the pcm
711 // For the case kDontCare, the rule is just a place holder and we are actually trying to exclude some of its children
712 // (this is used only in the selection xml case).
713
714 // Reject the selection of std::pair on the ground that it is trivial
715 // and can easily be recreated from the AST information.
716 if (recordDecl->getName() == "pair") {
717 const clang::NamespaceDecl *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(recordDecl->getDeclContext());
718 if (!nsDecl){
719 ROOT::TMetaUtils::Error("RScanner::TreatRecordDeclOrTypedefNameDecl",
720 "Cannot convert context of RecordDecl called pair into a namespace.\n");
721 return true;
722 }
723 const clang::NamespaceDecl *nsCanonical = nsDecl->getCanonicalDecl();
724 if (nsCanonical && nsCanonical == fInterpreter.getCI()->getSema().getStdNamespace()) {
725 if (selected->HasAttributeFileName() || selected->HasAttributeFilePattern()) {
726 return true;
727 }
728 }
729 }
730
731 // Insert in the selected classes if not already there
732 // We need this check since the same class can be selected through its name or typedef
733 bool rcrdDeclNotAlreadySelected = fselectedRecordDecls.insert((RecordDecl*)recordDecl->getCanonicalDecl()).second;
735 // Diagnose conflicting selection rules:
736 auto declSelRuleMapIt = fDeclSelRuleMap.find(recordDecl->getCanonicalDecl());
737 if (declSelRuleMapIt != fDeclSelRuleMap.end() &&
738 declSelRuleMapIt->second != selected) {
739 std::string normName;
741 recordDecl->getASTContext().getTypeDeclType(recordDecl),
743 fNormCtxt);
744
746 int previouslineno = previouslyMatchingRule->GetLineNumber();
747
748 std::string cleanFileName = llvm::sys::path::filename(selected->GetSelFileName()).str();
749 auto lineno = selected->GetLineNumber();
751 if (!rulesAreCompatible){
752 std::stringstream message;
753 if (lineno > 1) message << "Selection file " << cleanFileName << ", lines "
754 << lineno << " and " << previouslineno << ". ";
755 message << "Attempt to select a class "<< normName << " with two rules which have incompatible attributes. "
756 << "The attributes such as transiency might not be correctly propagated to the typesystem of ROOT.\n";
757 selected->Print(message);
758 message << "Conflicting rule already matched:\n";
759 previouslyMatchingRule->Print(message);
760 ROOT::TMetaUtils::Warning(nullptr,"%s\n", message.str().c_str());
761 }
762 }
763 }
764
765 fDeclSelRuleMap[recordDecl->getCanonicalDecl()] = selected;
766
768 return true;
769
770 // Before adding the decl to the selected ones, check its access.
771 // We do not yet support I/O of private or protected classes.
772 // See ROOT-7450.
773 // Additionally, private declarations lead to uncompilable code, so just ignore (ROOT-9112).
774 if (recordDecl->getAccess() == AS_private || recordDecl->getAccess() == AS_protected) {
775 // Don't warn about types selected by "everything in that file".
776 auto isFileSelection = selected->HasAttributeFileName() &&
777 selected->HasAttributePattern() &&
778 "*" == selected->GetAttributePattern();
779 if (!isFileSelection) {
780 std::string normName;
782 recordDecl->getASTContext().getTypeDeclType(recordDecl),
784 fNormCtxt);
785 auto msg = "Class or struct %s was selected but its dictionary cannot be generated: "
786 "this is a private or protected class and this is not supported. No direct "
787 "I/O operation of %s instances will be possible.\n";
788 ROOT::TMetaUtils::Warning(nullptr,msg,normName.c_str(),normName.c_str());
789 }
790 return true;
791 }
792
793 // Replace on the fly the type if the type for IO is different for example
794 // in presence of unique_ptr<T> or collections thereof.
795 // The following lines are very delicate: we need to preserve the special
796 // ROOT opaque typedefs.
797 auto req_type = selected->GetRequestedType();
798 clang::QualType thisType(req_type, 0);
799 std::string attr_name = selected->GetAttributeName().c_str();
800
802 if (sc != 0) {
803 return false;
804 }
805
806 if (auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
808 }
809
810 return true;
811}
812
814{
815 for (auto &&info: fDelayedAnnotatedRecordDecls) {
816 const clang::Type *thisType = info.fSelected->GetRequestedType();
817 if (!thisType)
818 thisType = info.fDecl->getTypeForDecl();
819 const clang::CXXRecordDecl *recordDecl = info.fDecl;
821 auto typeForIO = nameTypeForIO.second;
822 // It could be that we have in hands a type which is not a class, e.g.
823 // in presence of unique_ptr<T> we got a T with T=double.
824 if (typeForIO.getTypePtr() == thisType)
825 continue;
826 if (auto recordDeclForIO = typeForIO->getAsCXXRecordDecl()) {
827 const auto canRecordDeclForIO = recordDeclForIO->getCanonicalDecl();
828 if (!fselectedRecordDecls.insert(canRecordDeclForIO).second)
829 continue;
831 fDeclSelRuleMap[recordDecl] = info.fSelected;
832 thisType = typeForIO.getTypePtr();
833 }
834
836 nameTypeForIO.first, info.fTypedefNameDecl, 1000);
837 }
838}
839
840////////////////////////////////////////////////////////////////////////////////
841/// Visitor for every TypedefNameDecl, i.e. aliases and typedefs
842/// We check three conditions before trying to match the name:
843/// 1) If we are creating a big PCM
844/// 2) If the underlying decl is a RecordDecl
845/// 3) If the typedef is eventually contained in the std namespace
846
847bool RScanner::VisitTypedefNameDecl(clang::TypedefNameDecl* D)
848{
850 return true;
851
852 if (!shouldVisitDecl(D))
853 return true;
854
855 const clang::DeclContext *ctx = D->getDeclContext();
856
857 bool isInStd=false;
858 if (ctx) {
859 const clang::NamedDecl *parent = llvm::dyn_cast<clang::NamedDecl> (ctx);
860 isInStd = parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::");
861 }
862
863 if (ROOT::TMetaUtils::GetUnderlyingRecordDecl(D->getUnderlyingType()) &&
864 !isInStd){
866 }
867
868 return true;
869}
870
871////////////////////////////////////////////////////////////////////////////////
872
873bool RScanner::VisitEnumDecl(clang::EnumDecl* D)
874{
876 return true;
877
878 if (!shouldVisitDecl(D))
879 return true;
880
882 !IsElementPresent(fSelectedEnums, D)){ // Removal of duplicates.
883 fSelectedEnums.push_back(D);
884 }
885
886 return true;
887}
888
889////////////////////////////////////////////////////////////////////////////////
890
891bool RScanner::VisitVarDecl(clang::VarDecl* D)
892{
893 if (!D->hasGlobalStorage() ||
895 return true;
896
897 if (!shouldVisitDecl(D))
898 return true;
899
901 fSelectedVariables.push_back(D);
902 }
903
904 return true;
905}
906
907////////////////////////////////////////////////////////////////////////////////
908/// Nothing to be done here
909
910bool RScanner::VisitFieldDecl(clang::FieldDecl* D)
911{
912 return true;
913
914// bool ret = true;
915//
916// if(fSelectionRules.IsDeclSelected(D)){
917//
918// // if (fVerboseLevel > 0) {
919// // std::string qual_name;
920// // GetDeclQualName(D,qual_name);
921// // std::cout<<"\tSelected field -> " << qual_name << "\n";
922// // }
923// }
924// else {
925// }
926//
927// return ret;
928}
929
930////////////////////////////////////////////////////////////////////////////////
931
932bool RScanner::VisitFunctionDecl(clang::FunctionDecl* D)
933{
935 return true;
936
937 if (!shouldVisitDecl(D))
938 return true;
939
940 if(clang::FunctionDecl::TemplatedKind::TK_FunctionTemplate == D->getTemplatedKind())
941 return true;
942
944 fSelectedFunctions.push_back(D);
945 }
946
947 return true;
948}
949
950////////////////////////////////////////////////////////////////////////////////
951
953{
954 bool ret = true;
955
956 if (!DC)
957 return true;
958
959 clang::Decl* D = dyn_cast<clang::Decl>(DC);
960 // skip implicit decls
961 if (D && D->isImplicit()){
962 return true;
963 }
964
966 const clang::NamespaceDecl *parent = llvm::dyn_cast<clang::NamespaceDecl> (DC);
967 if (parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::"))
968 return true;
969 }
970
971 for (DeclContext::decl_iterator Child = DC->decls_begin(), ChildEnd = DC->decls_end();
972 ret && (Child != ChildEnd); ++Child) {
974 }
975
976 return ret;
977
978}
979
980////////////////////////////////////////////////////////////////////////////////
981
982bool RScanner::GetDeclName(clang::Decl* D, std::string& name) const
983{
984 clang::NamedDecl* N = dyn_cast<clang::NamedDecl> (D);
985
986 if (N) {
987 name = N->getNameAsString();
988 return true;
989 }
990 else {
991 name = "UNNAMED";
992 return false;
993 }
994}
995
996////////////////////////////////////////////////////////////////////////////////
997
998bool RScanner::GetDeclQualName(const clang::Decl* D, std::string& qual_name)
999{
1001
1002 if (N) {
1003 llvm::raw_string_ostream stream(qual_name);
1004 N->getNameForDiagnostic(stream,D->getASTContext().getPrintingPolicy(),true); // qual_name = N->getQualifiedNameAsString();
1005 return true;
1006 }
1007 else {
1008 return false;
1009 }
1010}
1011
1012////////////////////////////////////////////////////////////////////////////////
1013
1014bool RScanner::GetFunctionPrototype(clang::Decl* D, std::string& prototype) const {
1015 if (!D) {
1016 return false;
1017 }
1018
1019 clang::FunctionDecl* F = dyn_cast<clang::FunctionDecl> (D);
1020
1021 if (F) {
1022
1023 prototype = "";
1024 for (clang::FunctionDecl::param_iterator I = F->param_begin(), E = F->param_end(); I != E; ++I) {
1025 clang::ParmVarDecl* P = *I;
1026
1027 if (prototype != "")
1028 prototype += ",";
1029
1030 //std::string type = P->getType().getAsString();
1031 std::string type = P->getType().getAsString();
1032 if (type.at(type.length()-1) == '*') {
1033 type.at(type.length()-2) = '*';
1034 type.erase(type.length()-1);
1035 }
1036 prototype += type;
1037 }
1038
1039 prototype = "(" + prototype + ")";
1040 return true;
1041 }
1042 else {
1043 ShowWarning("can't convert Decl to FunctionDecl","");
1044 return false;
1045 }
1046}
1047
1048////////////////////////////////////////////////////////////////////////////////
1049
1050void RScanner::Scan(const clang::ASTContext &C)
1051{
1052 fSourceManager = &C.getSourceManager();
1053
1054// if (fVerboseLevel >= 3) fSelectionRules.PrintSelectionRules();
1055
1057 std::cout<<"File name detected"<<std::endl;
1058 }
1059
1060 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter *>(&fInterpreter));
1061
1063 TraverseDecl(C.getTranslationUnitDecl());
1064
1065 fFirstPass=false;
1066 fselectedRecordDecls.clear();
1067 fSelectedEnums.clear();
1068 fSelectedTypedefs.clear();
1069 fSelectedVariables.clear();
1070 fSelectedFunctions.clear();
1071 TraverseDecl(C.getTranslationUnitDecl());
1072
1073 // The RecursiveASTVisitor uses range-based for; we must not modify the AST
1074 // during iteration / visitation. Instead, buffer the lookups that could
1075 // potentially create new template specializations, and handle them here:
1077}
1078
1079
1080////////////////////////////////////////////////////////////////////////////////
1081/// Set the callback to the RecordDecl and return the previous one.
1082
std::string IntToStr(int num)
Definition Scanner.cxx:159
long APIntToLong(const llvm::APInt &num)
Definition Scanner.cxx:145
std::string AddSpace(const std::string &txt)
Definition Scanner.cxx:264
size_t APIntToSize(const llvm::APInt &num)
Definition Scanner.cxx:138
void * ToDeclProp(clang::Decl *item)
Definition Scanner.cxx:130
std::string APIntToStr(const llvm::APInt &num)
Definition Scanner.cxx:152
std::string IntToStd(int num)
Definition Scanner.cxx:168
std::string Message(const std::string &msg, const std::string &location)
Definition Scanner.cxx:177
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h req_type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char text
char name[80]
Definition TGX11.cxx:110
TRObject operator()(const T1 &t1) const
const_iterator end() const
std::string GetLocation(clang::Decl *D) const
Definition Scanner.cxx:233
void Scan(const clang::ASTContext &C)
Definition Scanner.cxx:1050
void UnknownDecl(clang::Decl *D, const std::string &txt="") const
unknown - this kind of declaration was not known to programmer
Definition Scanner.cxx:285
RScanner(SelectionRules &rules, EScanType stype, const cling::Interpreter &interpret, ROOT::TMetaUtils::TNormalizedCtxt &normCtxt, unsigned int verbose=0)
Regular constructor setting up the scanner to search for entities matching the 'rules'.
Definition Scanner.cxx:75
ROOT::TMetaUtils::TNormalizedCtxt & fNormCtxt
Definition Scanner.h:196
DeclCallback fRecordDeclCallback
Definition Scanner.h:191
void UnsupportedDecl(clang::Decl *D, const std::string &txt="") const
unsupported - this kind of declaration is probably not used (in current version of C++)
Definition Scanner.cxx:307
static std::map< clang::Decl *, std::string > fgAnonymousEnumMap
Definition Scanner.h:176
void UnimportantDecl(clang::Decl *D, const std::string &txt="") const
unimportant - this kind of declaration is not stored into reflex
Definition Scanner.cxx:318
void AddDelayedAnnotatedRecordDecls()
Definition Scanner.cxx:813
const clang::SourceManager * fSourceManager
Definition Scanner.h:185
static const int fgDeclLast
Definition Scanner.h:187
FunctionColl_t fSelectedFunctions
Definition Scanner.h:131
EScanType fScanType
Definition Scanner.h:199
bool VisitFieldDecl(clang::FieldDecl *D)
Nothing to be done here.
Definition Scanner.cxx:910
void ShowInfo(const std::string &msg, const std::string &location="") const
Definition Scanner.cxx:189
bool TreatRecordDeclOrTypedefNameDecl(clang::TypeDecl *typeDecl)
Definition Scanner.cxx:610
static int fgAnonymousClassCounter
Definition Scanner.h:193
std::string FuncParameters(clang::FunctionDecl *D) const
Definition Scanner.cxx:430
bool fTypeTable[fgTypeLast+1]
Definition Scanner.h:192
void ShowTemplateInfo(const std::string &msg, const std::string &location="") const
Definition Scanner.cxx:213
std::string GetEnumName(clang::EnumDecl *D) const
Definition Scanner.cxx:376
NamespaceColl_t fSelectedNamespaces
Definition Scanner.h:129
bool GetFunctionPrototype(clang::Decl *D, std::string &prototype) const
Definition Scanner.cxx:1014
std::set< clang::RecordDecl * > fselectedRecordDecls
Definition Scanner.h:198
std::string ConvTemplateName(clang::TemplateName &N) const
Definition Scanner.cxx:415
static int fgBadClassCounter
Definition Scanner.h:195
void UnimplementedDecl(clang::Decl *D, const std::string &txt="")
information about item, that should be implemented
Definition Scanner.cxx:325
bool VisitVarDecl(clang::VarDecl *D)
Definition Scanner.cxx:891
TypedefColl_t fSelectedTypedefs
Definition Scanner.h:130
bool fFirstPass
Definition Scanner.h:200
std::string GetSrcLocation(clang::SourceLocation L) const
Definition Scanner.cxx:223
void(* DeclCallback)(const clang::RecordDecl *)
Definition Scanner.h:77
void UnsupportedType(clang::QualType qual_type) const
Definition Scanner.cxx:367
const cling::Interpreter & fInterpreter
Definition Scanner.h:186
DeclCallback SetRecordDeclCallback(DeclCallback callback)
Set the callback to the RecordDecl and return the previous one.
Definition Scanner.cxx:1083
bool VisitNamespaceDecl(clang::NamespaceDecl *D)
This method visits a namespace node.
Definition Scanner.cxx:477
void ShowWarning(const std::string &msg, const std::string &location="") const
Definition Scanner.cxx:197
std::string GetName(clang::Decl *D) const
Definition Scanner.cxx:250
static int fgAnonymousEnumCounter
Definition Scanner.h:194
static const char * fgClangFuncKey
Definition Scanner.h:123
void ShowError(const std::string &msg, const std::string &location="") const
Definition Scanner.cxx:205
void UnexpectedDecl(clang::Decl *D, const std::string &txt="") const
unexpected - this kind of declaration is unexpected (in concrete place)
Definition Scanner.cxx:296
EnumColl_t fSelectedEnums
Definition Scanner.h:133
int AddAnnotatedRecordDecl(const ClassSelectionRule *, const clang::Type *, const clang::RecordDecl *, const std::string &, const clang::TypedefNameDecl *, unsigned int indexOffset=0)
Definition Scanner.cxx:533
std::vector< DelayedAnnotatedRecordDeclInfo > fDelayedAnnotatedRecordDecls
Definition Scanner.h:140
bool VisitEnumDecl(clang::EnumDecl *D)
Definition Scanner.cxx:873
static std::map< clang::Decl *, std::string > fgAnonymousClassMap
Definition Scanner.h:175
std::string FuncParameterList(clang::FunctionDecl *D) const
Definition Scanner.cxx:457
static bool GetDeclQualName(const clang::Decl *D, std::string &qual_name)
Definition Scanner.cxx:998
std::string ExprToStr(clang::Expr *expr) const
Definition Scanner.cxx:400
static const int fgTypeLast
Definition Scanner.h:188
SelectionRules & fSelectionRules
Definition Scanner.h:197
virtual ~RScanner()
Definition Scanner.cxx:103
static const char * fgClangDeclKey
Definition Scanner.h:122
bool VisitRecordDecl(clang::RecordDecl *D)
Definition Scanner.cxx:520
void UnknownType(clang::QualType qual_type) const
Definition Scanner.cxx:358
bool fDeclTable[fgDeclLast+1]
Definition Scanner.h:189
VariableColl_t fSelectedVariables
Definition Scanner.h:132
bool VisitFunctionDecl(clang::FunctionDecl *D)
Definition Scanner.cxx:932
DeclsSelRulesMap_t fDeclSelRuleMap
Definition Scanner.h:201
unsigned int fVerboseLevel
Definition Scanner.h:167
clang::Decl * fLastDecl
Definition Scanner.h:190
bool GetDeclName(clang::Decl *D, std::string &name) const
Definition Scanner.cxx:982
bool TraverseDeclContextHelper(clang::DeclContext *DC)
Definition Scanner.cxx:952
ClassColl_t fSelectedClasses
Definition Scanner.h:128
void DeclInfo(clang::Decl *D) const
Definition Scanner.cxx:274
bool shouldVisitDecl(clang::NamedDecl *D)
Whether we can actually visit this declaration, i.e.
Definition Scanner.cxx:120
bool VisitTypedefNameDecl(clang::TypedefNameDecl *D)
Visitor for every TypedefNameDecl, i.e.
Definition Scanner.cxx:847
The class representing the collection of selection rules.
bool GetHasFileNameRule() const
const ClassSelectionRule * IsDeclSelected(const clang::RecordDecl *D, bool includeTypedefRule) const
#define I(x, y, z)
clang::RecordDecl * GetUnderlyingRecordDecl(clang::QualType type)
void Error(const char *location, const char *fmt,...)
void Info(const char *location, const char *fmt,...)
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 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,...
bool IsStdClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace.
std::pair< std::string, clang::QualType > GetNameTypeForIO(const clang::QualType &templateInstanceType, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt, TClassEdit::EModType mode=TClassEdit::kNone)
void Warning(const char *location, const char *fmt,...)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
bool areEqual< ClassSelectionRule >(const ClassSelectionRule *r1, const ClassSelectionRule *r2, bool moduloNameOrPattern)