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