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(),
566 selected->RequestedRNTupleSoARecord(),
568 fNormCtxt);
569 } else {
570 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
572 selected->RequestStreamerInfo(),
573 selected->RequestNoStreamer(),
574 selected->RequestNoInputOperator(),
575 selected->RequestOnlyTClass(),
576 selected->RequestedVersionNumber(),
577 selected->RequestedRNTupleSerializationMode(),
578 selected->RequestedRNTupleSoARecord(),
580 fNormCtxt);
581 }
582 // clang-format on
583
584 if (fVerboseLevel > 0) {
585 std::string qual_name;
587 std::string normName;
589 recordDecl->getASTContext().getTypeDeclType(recordDecl),
591 fNormCtxt);
592 std::string typedef_qual_name;
593 std::string typedefMsg;
594 if (typedefNameDecl){
596 typedefMsg = "(through typedef/alias " + typedef_qual_name + ") ";
597 }
598
599 std::cout << "Selected class "
600 << typedefMsg
601 << "-> "
602 << qual_name
603 << " for ROOT: "
604 << normName
605 << "\n";
606 }
607 return 0;
608}
609
610////////////////////////////////////////////////////////////////////////////////
611
613{
614 // For every class is created a new class buider irrespectful of weather the
615 // class is internal for another class declaration or not.
616 // RecordDecls and TypedefDecls (or RecordDecls!) are treated.
617 // We follow two different codepaths if the typeDecl is a RecordDecl or
618 // a TypedefDecl. If typeDecl is a TypedefDecl, recordDecl becomes the
619 // underlying RecordDecl.
620 // This is done to leverage the selections rule matching in SelectionRules
621 // which works basically with names.
622 // At the end of the method, if the typedef name is matched, an AnnotatedRecordDecl
623 // with the underlying RecordDecl is fed to the machinery.
624
625 const clang::RecordDecl* recordDecl = clang::dyn_cast<clang::RecordDecl>(typeDecl);
626 const clang::TypedefNameDecl* typedefNameDecl = clang::dyn_cast<clang::TypedefNameDecl>(typeDecl);
627
628 // If typeDecl is not a RecordDecl, try to fetch the RecordDecl behind the TypedefDecl
629 if (!recordDecl && typedefNameDecl) {
631 }
632
633 // If at this point recordDecl is still NULL, we have a problem
634 if (!recordDecl) {
635 ROOT::TMetaUtils::Warning("RScanner::TreatRecordDeclOrTypeNameDecl",
636 "Could not cast typeDecl either to RecordDecl or could not get RecordDecl underneath typedef.\n");
637 return true;
638 }
639
640 // Do not select unnamed records.
641 if (!recordDecl->getIdentifier())
642 return true;
643
644 // Do not select dependent types.
645 if (recordDecl->isDependentType())
646 return true;
647
649 return true;
650
651
652 // At this point, recordDecl must be a RecordDecl pointer.
653
655 // Pass on any declaration. This is usually used to record dependency.
656 // Since rootcint see C++ compliant header files, we can assume that
657 // if a forward declaration or declaration has been inserted, the
658 // classes for which we are creating a dictionary will be using
659 // them either directly or indirectly. Any false positive can be
660 // resolved by removing the spurrious dependency in the (user) header
661 // files.
663 }
664
665 // in case it is implicit or a forward declaration, we are not interested.
666 if(recordDecl->isImplicit() || !recordDecl->isCompleteDefinition()) {
667 return true;
668 }
669
670 // Never select the class templates themselves.
671 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl);
672 if (cxxdecl && cxxdecl->getDescribedClassTemplate ()) {
673 return true;
674 }
675
677
678 const ClassSelectionRule *selectedFromRecDecl = fSelectionRules.IsDeclSelected(recordDecl, false /* exclude typedef rules*/);
679
681
682 if (! selected) return true; // early exit. Nothing more to be done.
683
684 // Selected through typedef but excluded with concrete classname
685 bool excludedFromRecDecl = false;
688
689 if (selected->GetSelected() != BaseSelectionRule::kYes || excludedFromRecDecl)
690 return true;
691
692 // Save the typedef
696 // Don't generate a dictionary for the class underlying a typedef found
697 // for a file name match (eg. "defined_in")
698 if (!selectedFromRecDecl && selectedFromTypedef->HasAttributeFileName())
699 return true;
700 }
701
702 if (selected->IsFromTypedef()) {
705 return true;
706 }
707
708 if (typedefNameDecl)
709 ROOT::TMetaUtils::Info("RScanner::TreatRecordDeclOrTypedefNameDecl",
710 "Typedef is selected %s.\n", typedefNameDecl->getNameAsString().c_str());
711
712 // For the case kNo, we could (but don't) remove the node from the pcm
713 // For the case kDontCare, the rule is just a place holder and we are actually trying to exclude some of its children
714 // (this is used only in the selection xml case).
715
716 // Reject the selection of std::pair on the ground that it is trivial
717 // and can easily be recreated from the AST information.
718 if (recordDecl->getName() == "pair") {
719 const clang::NamespaceDecl *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(recordDecl->getDeclContext());
720 if (!nsDecl){
721 ROOT::TMetaUtils::Error("RScanner::TreatRecordDeclOrTypedefNameDecl",
722 "Cannot convert context of RecordDecl called pair into a namespace.\n");
723 return true;
724 }
725 const clang::NamespaceDecl *nsCanonical = nsDecl->getCanonicalDecl();
726 if (nsCanonical && nsCanonical == fInterpreter.getCI()->getSema().getStdNamespace()) {
727 if (selected->HasAttributeFileName() || selected->HasAttributeFilePattern()) {
728 return true;
729 }
730 }
731 }
732
733 // Insert in the selected classes if not already there
734 // We need this check since the same class can be selected through its name or typedef
735 bool rcrdDeclNotAlreadySelected = fselectedRecordDecls.insert((RecordDecl*)recordDecl->getCanonicalDecl()).second;
737 // Diagnose conflicting selection rules:
738 auto declSelRuleMapIt = fDeclSelRuleMap.find(recordDecl->getCanonicalDecl());
739 if (declSelRuleMapIt != fDeclSelRuleMap.end() &&
740 declSelRuleMapIt->second != selected) {
741 std::string normName;
743 recordDecl->getASTContext().getTypeDeclType(recordDecl),
745 fNormCtxt);
746
748 int previouslineno = previouslyMatchingRule->GetLineNumber();
749
750 std::string cleanFileName = llvm::sys::path::filename(selected->GetSelFileName()).str();
751 auto lineno = selected->GetLineNumber();
753 if (!rulesAreCompatible){
754 std::stringstream message;
755 if (lineno > 1) message << "Selection file " << cleanFileName << ", lines "
756 << lineno << " and " << previouslineno << ". ";
757 message << "Attempt to select a class "<< normName << " with two rules which have incompatible attributes. "
758 << "The attributes such as transiency might not be correctly propagated to the typesystem of ROOT.\n";
759 selected->Print(message);
760 message << "Conflicting rule already matched:\n";
761 previouslyMatchingRule->Print(message);
762 ROOT::TMetaUtils::Warning(nullptr,"%s\n", message.str().c_str());
763 }
764 }
765 }
766
767 fDeclSelRuleMap[recordDecl->getCanonicalDecl()] = selected;
768
770 return true;
771
772 // Before adding the decl to the selected ones, check its access.
773 // We do not yet support I/O of private or protected classes.
774 // See ROOT-7450.
775 // Additionally, private declarations lead to uncompilable code, so just ignore (ROOT-9112).
776 if (recordDecl->getAccess() == AS_private || recordDecl->getAccess() == AS_protected) {
777 // Don't warn about types selected by "everything in that file".
778 auto isFileSelection = selected->HasAttributeFileName() &&
779 selected->HasAttributePattern() &&
780 "*" == selected->GetAttributePattern();
781 if (!isFileSelection) {
782 std::string normName;
784 recordDecl->getASTContext().getTypeDeclType(recordDecl),
786 fNormCtxt);
787 auto msg = "Class or struct %s was selected but its dictionary cannot be generated: "
788 "this is a private or protected class and this is not supported. No direct "
789 "I/O operation of %s instances will be possible.\n";
790 ROOT::TMetaUtils::Warning(nullptr,msg,normName.c_str(),normName.c_str());
791 }
792 return true;
793 }
794
795 // Replace on the fly the type if the type for IO is different for example
796 // in presence of unique_ptr<T> or collections thereof.
797 // The following lines are very delicate: we need to preserve the special
798 // ROOT opaque typedefs.
799 auto req_type = selected->GetRequestedType();
800 clang::QualType thisType(req_type, 0);
801 std::string attr_name = selected->GetAttributeName().c_str();
802
804 if (sc != 0) {
805 return false;
806 }
807
808 if (auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
810 }
811
812 return true;
813}
814
816{
817 for (auto &&info: fDelayedAnnotatedRecordDecls) {
818 const clang::Type *thisType = info.fSelected->GetRequestedType();
819 if (!thisType)
820 thisType = info.fDecl->getTypeForDecl();
821 const clang::CXXRecordDecl *recordDecl = info.fDecl;
823 auto typeForIO = nameTypeForIO.second;
824 // It could be that we have in hands a type which is not a class, e.g.
825 // in presence of unique_ptr<T> we got a T with T=double.
826 if (typeForIO.getTypePtr() == thisType)
827 continue;
828 if (auto recordDeclForIO = typeForIO->getAsCXXRecordDecl()) {
829 const auto canRecordDeclForIO = recordDeclForIO->getCanonicalDecl();
830 if (!fselectedRecordDecls.insert(canRecordDeclForIO).second)
831 continue;
833 fDeclSelRuleMap[recordDecl] = info.fSelected;
834 thisType = typeForIO.getTypePtr();
835 }
836
838 nameTypeForIO.first, info.fTypedefNameDecl, 1000);
839 }
840}
841
842////////////////////////////////////////////////////////////////////////////////
843/// Visitor for every TypedefNameDecl, i.e. aliases and typedefs
844/// We check three conditions before trying to match the name:
845/// 1) If we are creating a big PCM
846/// 2) If the underlying decl is a RecordDecl
847/// 3) If the typedef is eventually contained in the std namespace
848
849bool RScanner::VisitTypedefNameDecl(clang::TypedefNameDecl* D)
850{
852 return true;
853
854 if (!shouldVisitDecl(D))
855 return true;
856
857 const clang::DeclContext *ctx = D->getDeclContext();
858
859 bool isInStd=false;
860 if (ctx) {
861 const clang::NamedDecl *parent = llvm::dyn_cast<clang::NamedDecl> (ctx);
862 isInStd = parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::");
863 }
864
865 if (ROOT::TMetaUtils::GetUnderlyingRecordDecl(D->getUnderlyingType()) &&
866 !isInStd){
868 }
869
870 return true;
871}
872
873////////////////////////////////////////////////////////////////////////////////
874
875bool RScanner::VisitEnumDecl(clang::EnumDecl* D)
876{
878 return true;
879
880 if (!shouldVisitDecl(D))
881 return true;
882
884 !IsElementPresent(fSelectedEnums, D)){ // Removal of duplicates.
885 fSelectedEnums.push_back(D);
886 }
887
888 return true;
889}
890
891////////////////////////////////////////////////////////////////////////////////
892
893bool RScanner::VisitVarDecl(clang::VarDecl* D)
894{
895 if (!D->hasGlobalStorage() ||
897 return true;
898
899 if (!shouldVisitDecl(D))
900 return true;
901
903 fSelectedVariables.push_back(D);
904 }
905
906 return true;
907}
908
909////////////////////////////////////////////////////////////////////////////////
910/// Nothing to be done here
911
912bool RScanner::VisitFieldDecl(clang::FieldDecl* D)
913{
914 return true;
915
916// bool ret = true;
917//
918// if(fSelectionRules.IsDeclSelected(D)){
919//
920// // if (fVerboseLevel > 0) {
921// // std::string qual_name;
922// // GetDeclQualName(D,qual_name);
923// // std::cout<<"\tSelected field -> " << qual_name << "\n";
924// // }
925// }
926// else {
927// }
928//
929// return ret;
930}
931
932////////////////////////////////////////////////////////////////////////////////
933
934bool RScanner::VisitFunctionDecl(clang::FunctionDecl* D)
935{
937 return true;
938
939 if (!shouldVisitDecl(D))
940 return true;
941
942 if(clang::FunctionDecl::TemplatedKind::TK_FunctionTemplate == D->getTemplatedKind())
943 return true;
944
946 fSelectedFunctions.push_back(D);
947 }
948
949 return true;
950}
951
952////////////////////////////////////////////////////////////////////////////////
953
955{
956 bool ret = true;
957
958 if (!DC)
959 return true;
960
961 clang::Decl* D = dyn_cast<clang::Decl>(DC);
962 // skip implicit decls
963 if (D && D->isImplicit()){
964 return true;
965 }
966
968 const clang::NamespaceDecl *parent = llvm::dyn_cast<clang::NamespaceDecl> (DC);
969 if (parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::"))
970 return true;
971 }
972
973 for (DeclContext::decl_iterator Child = DC->decls_begin(), ChildEnd = DC->decls_end();
974 ret && (Child != ChildEnd); ++Child) {
976 }
977
978 return ret;
979
980}
981
982////////////////////////////////////////////////////////////////////////////////
983
984bool RScanner::GetDeclName(clang::Decl* D, std::string& name) const
985{
986 clang::NamedDecl* N = dyn_cast<clang::NamedDecl> (D);
987
988 if (N) {
989 name = N->getNameAsString();
990 return true;
991 }
992 else {
993 name = "UNNAMED";
994 return false;
995 }
996}
997
998////////////////////////////////////////////////////////////////////////////////
999
1000bool RScanner::GetDeclQualName(const clang::Decl* D, std::string& qual_name)
1001{
1003
1004 if (N) {
1005 llvm::raw_string_ostream stream(qual_name);
1006 N->getNameForDiagnostic(stream,D->getASTContext().getPrintingPolicy(),true); // qual_name = N->getQualifiedNameAsString();
1007 return true;
1008 }
1009 else {
1010 return false;
1011 }
1012}
1013
1014////////////////////////////////////////////////////////////////////////////////
1015
1016bool RScanner::GetFunctionPrototype(clang::Decl* D, std::string& prototype) const {
1017 if (!D) {
1018 return false;
1019 }
1020
1021 clang::FunctionDecl* F = dyn_cast<clang::FunctionDecl> (D);
1022
1023 if (F) {
1024
1025 prototype = "";
1026 for (clang::FunctionDecl::param_iterator I = F->param_begin(), E = F->param_end(); I != E; ++I) {
1027 clang::ParmVarDecl* P = *I;
1028
1029 if (prototype != "")
1030 prototype += ",";
1031
1032 //std::string type = P->getType().getAsString();
1033 std::string type = P->getType().getAsString();
1034 if (type.at(type.length()-1) == '*') {
1035 type.at(type.length()-2) = '*';
1036 type.erase(type.length()-1);
1037 }
1038 prototype += type;
1039 }
1040
1041 prototype = "(" + prototype + ")";
1042 return true;
1043 }
1044 else {
1045 ShowWarning("can't convert Decl to FunctionDecl","");
1046 return false;
1047 }
1048}
1049
1050////////////////////////////////////////////////////////////////////////////////
1051
1052void RScanner::Scan(const clang::ASTContext &C)
1053{
1054 fSourceManager = &C.getSourceManager();
1055
1056// if (fVerboseLevel >= 3) fSelectionRules.PrintSelectionRules();
1057
1059 std::cout<<"File name detected"<<std::endl;
1060 }
1061
1062 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter *>(&fInterpreter));
1063
1065 TraverseDecl(C.getTranslationUnitDecl());
1066
1067 fFirstPass=false;
1068 fselectedRecordDecls.clear();
1069 fSelectedEnums.clear();
1070 fSelectedTypedefs.clear();
1071 fSelectedVariables.clear();
1072 fSelectedFunctions.clear();
1073 TraverseDecl(C.getTranslationUnitDecl());
1074
1075 // The RecursiveASTVisitor uses range-based for; we must not modify the AST
1076 // during iteration / visitation. Instead, buffer the lookups that could
1077 // potentially create new template specializations, and handle them here:
1079}
1080
1081
1082////////////////////////////////////////////////////////////////////////////////
1083/// Set the callback to the RecordDecl and return the previous one.
1084
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:157
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:1052
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:815
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:912
void ShowInfo(const std::string &msg, const std::string &location="") const
Definition Scanner.cxx:189
bool TreatRecordDeclOrTypedefNameDecl(clang::TypeDecl *typeDecl)
Definition Scanner.cxx:612
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:1016
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:893
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:1085
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:875
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:1000
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:934
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:984
bool TraverseDeclContextHelper(clang::DeclContext *DC)
Definition Scanner.cxx:954
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:849
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,...)
bool areEqual< ClassSelectionRule >(const ClassSelectionRule *r1, const ClassSelectionRule *r2, bool moduloNameOrPattern)