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
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,
80 unsigned int verbose /* = 0 */) :
81 fVerboseLevel(verbose),
82 fSourceManager(nullptr),
83 fInterpreter(interpret),
84 fRecordDeclCallback(nullptr),
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 = nullptr;
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 llvm::toString(num, /*radix*/10, /*signed*/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 == nullptr)
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, nullptr, 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() &&
546 std::string normName;
548 recordDecl->getASTContext().getTypeDeclType(recordDecl),
550 fNormCtxt);
551 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());
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) : nullptr;
672
673 const ClassSelectionRule *selectedFromRecDecl = fSelectionRules.IsDeclSelected(recordDecl, false /* exclude typedef rules*/);
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 // Don't generate a dictionary for the class underlying a typedef found
692 // for a file name match (eg. "defined_in")
693 if (!selectedFromRecDecl && selectedFromTypedef->HasAttributeFileName())
694 return true;
695 }
696
697 if (selected->IsFromTypedef()) {
698 if (typedefNameDecl && !IsElementPresent(fSelectedTypedefs, typedefNameDecl))
699 fSelectedTypedefs.push_back(typedefNameDecl);
700 return true;
701 }
702
703 if (typedefNameDecl)
704 ROOT::TMetaUtils::Info("RScanner::TreatRecordDeclOrTypedefNameDecl",
705 "Typedef is selected %s.\n", typedefNameDecl->getNameAsString().c_str());
706
707 // For the case kNo, we could (but don't) remove the node from the pcm
708 // For the case kDontCare, the rule is just a place holder and we are actually trying to exclude some of its children
709 // (this is used only in the selection xml case).
710
711 // Reject the selection of std::pair on the ground that it is trivial
712 // and can easily be recreated from the AST information.
713 if (recordDecl->getName() == "pair") {
714 const clang::NamespaceDecl *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(recordDecl->getDeclContext());
715 if (!nsDecl){
716 ROOT::TMetaUtils::Error("RScanner::TreatRecordDeclOrTypedefNameDecl",
717 "Cannot convert context of RecordDecl called pair into a namespace.\n");
718 return true;
719 }
720 const clang::NamespaceDecl *nsCanonical = nsDecl->getCanonicalDecl();
721 if (nsCanonical && nsCanonical == fInterpreter.getCI()->getSema().getStdNamespace()) {
722 if (selected->HasAttributeFileName() || selected->HasAttributeFilePattern()) {
723 return true;
724 }
725 }
726 }
727
728 // Insert in the selected classes if not already there
729 // We need this check since the same class can be selected through its name or typedef
730 bool rcrdDeclNotAlreadySelected = fselectedRecordDecls.insert((RecordDecl*)recordDecl->getCanonicalDecl()).second;
731 if (!fFirstPass && !rcrdDeclNotAlreadySelected) {
732 // Diagnose conflicting selection rules:
733 auto declSelRuleMapIt = fDeclSelRuleMap.find(recordDecl->getCanonicalDecl());
734 if (declSelRuleMapIt != fDeclSelRuleMap.end() &&
735 declSelRuleMapIt->second != selected) {
736 std::string normName;
738 recordDecl->getASTContext().getTypeDeclType(recordDecl),
740 fNormCtxt);
741
742 auto previouslyMatchingRule = (const ClassSelectionRule*)declSelRuleMapIt->second;
743 int previouslineno = previouslyMatchingRule->GetLineNumber();
744
745 std::string cleanFileName = llvm::sys::path::filename(selected->GetSelFileName()).str();
746 auto lineno = selected->GetLineNumber();
747 auto rulesAreCompatible = SelectionRulesUtils::areEqual<ClassSelectionRule>(selected, previouslyMatchingRule, true /*moduloNameOrPattern*/);
748 if (!rulesAreCompatible){
749 std::stringstream message;
750 if (lineno > 1) message << "Selection file " << cleanFileName << ", lines "
751 << lineno << " and " << previouslineno << ". ";
752 message << "Attempt to select a class "<< normName << " with two rules which have incompatible attributes. "
753 << "The attributes such as transiency might not be correctly propagated to the typesystem of ROOT.\n";
754 selected->Print(message);
755 message << "Conflicting rule already matched:\n";
756 previouslyMatchingRule->Print(message);
757 ROOT::TMetaUtils::Warning(nullptr,"%s\n", message.str().c_str());
758 }
759 }
760 }
761
762 fDeclSelRuleMap[recordDecl->getCanonicalDecl()] = selected;
763
764 if (!rcrdDeclNotAlreadySelected || fFirstPass)
765 return true;
766
767 // Before adding the decl to the selected ones, check its access.
768 // We do not yet support I/O of private or protected classes.
769 // See ROOT-7450.
770 // Additionally, private declarations lead to uncompilable code, so just ignore (ROOT-9112).
771 if (recordDecl->getAccess() == AS_private || recordDecl->getAccess() == AS_protected) {
772 // Don't warn about types selected by "everything in that file".
773 auto isFileSelection = selected->HasAttributeFileName() &&
774 selected->HasAttributePattern() &&
775 "*" == selected->GetAttributePattern();
776 if (!isFileSelection) {
777 std::string normName;
779 recordDecl->getASTContext().getTypeDeclType(recordDecl),
781 fNormCtxt);
782 auto msg = "Class or struct %s was selected but its dictionary cannot be generated: "
783 "this is a private or protected class and this is not supported. No direct "
784 "I/O operation of %s instances will be possible.\n";
785 ROOT::TMetaUtils::Warning(nullptr,msg,normName.c_str(),normName.c_str());
786 }
787 return true;
788 }
789
790 // Replace on the fly the type if the type for IO is different for example
791 // in presence of unique_ptr<T> or collections thereof.
792 // The following lines are very delicate: we need to preserve the special
793 // ROOT opaque typedefs.
794 auto req_type = selected->GetRequestedType();
795 clang::QualType thisType(req_type, 0);
796 std::string attr_name = selected->GetAttributeName().c_str();
797
798 auto sc = AddAnnotatedRecordDecl(selected, req_type, recordDecl, attr_name, typedefNameDecl);
799 if (sc != 0) {
800 return false;
801 }
802
803 if (auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
804 fDelayedAnnotatedRecordDecls.emplace_back(DelayedAnnotatedRecordDeclInfo{selected, CTSD, typedefNameDecl});
805 }
806
807 return true;
808}
809
811{
812 for (auto &&info: fDelayedAnnotatedRecordDecls) {
813 const clang::Type *thisType = info.fSelected->GetRequestedType();
814 if (!thisType)
815 thisType = info.fDecl->getTypeForDecl();
816 const clang::CXXRecordDecl *recordDecl = info.fDecl;
817 auto nameTypeForIO = ROOT::TMetaUtils::GetNameTypeForIO(clang::QualType(thisType, 0), fInterpreter, fNormCtxt);
818 auto typeForIO = nameTypeForIO.second;
819 // It could be that we have in hands a type which is not a class, e.g.
820 // in presence of unique_ptr<T> we got a T with T=double.
821 if (typeForIO.getTypePtr() == thisType)
822 continue;
823 if (auto recordDeclForIO = typeForIO->getAsCXXRecordDecl()) {
824 const auto canRecordDeclForIO = recordDeclForIO->getCanonicalDecl();
825 if (!fselectedRecordDecls.insert(canRecordDeclForIO).second)
826 continue;
827 recordDecl = canRecordDeclForIO;
828 fDeclSelRuleMap[recordDecl] = info.fSelected;
829 thisType = typeForIO.getTypePtr();
830 }
831
832 AddAnnotatedRecordDecl(info.fSelected, thisType, recordDecl,
833 nameTypeForIO.first, info.fTypedefNameDecl, 1000);
834 }
835}
836
837////////////////////////////////////////////////////////////////////////////////
838/// Visitor for every TypedefNameDecl, i.e. aliases and typedefs
839/// We check three conditions before trying to match the name:
840/// 1) If we are creating a big PCM
841/// 2) If the underlying decl is a RecordDecl
842/// 3) If the typedef is eventually contained in the std namespace
843
844bool RScanner::VisitTypedefNameDecl(clang::TypedefNameDecl* D)
845{
847 return true;
848
849 if (!shouldVisitDecl(D))
850 return true;
851
852 const clang::DeclContext *ctx = D->getDeclContext();
853
854 bool isInStd=false;
855 if (ctx) {
856 const clang::NamedDecl *parent = llvm::dyn_cast<clang::NamedDecl> (ctx);
857 isInStd = parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::");
858 }
859
860 if (ROOT::TMetaUtils::GetUnderlyingRecordDecl(D->getUnderlyingType()) &&
861 !isInStd){
863 }
864
865 return true;
866}
867
868////////////////////////////////////////////////////////////////////////////////
869
870bool RScanner::VisitEnumDecl(clang::EnumDecl* D)
871{
873 return true;
874
875 if (!shouldVisitDecl(D))
876 return true;
877
879 !IsElementPresent(fSelectedEnums, D)){ // Removal of duplicates.
880 fSelectedEnums.push_back(D);
881 }
882
883 return true;
884}
885
886////////////////////////////////////////////////////////////////////////////////
887
888bool RScanner::VisitVarDecl(clang::VarDecl* D)
889{
890 if (!D->hasGlobalStorage() ||
892 return true;
893
894 if (!shouldVisitDecl(D))
895 return true;
896
898 fSelectedVariables.push_back(D);
899 }
900
901 return true;
902}
903
904////////////////////////////////////////////////////////////////////////////////
905/// Nothing to be done here
906
907bool RScanner::VisitFieldDecl(clang::FieldDecl* D)
908{
909 return true;
910
911// bool ret = true;
912//
913// if(fSelectionRules.IsDeclSelected(D)){
914//
915// // if (fVerboseLevel > 0) {
916// // std::string qual_name;
917// // GetDeclQualName(D,qual_name);
918// // std::cout<<"\tSelected field -> " << qual_name << "\n";
919// // }
920// }
921// else {
922// }
923//
924// return ret;
925}
926
927////////////////////////////////////////////////////////////////////////////////
928
929bool RScanner::VisitFunctionDecl(clang::FunctionDecl* D)
930{
932 return true;
933
934 if (!shouldVisitDecl(D))
935 return true;
936
937 if(clang::FunctionDecl::TemplatedKind::TK_FunctionTemplate == D->getTemplatedKind())
938 return true;
939
941 fSelectedFunctions.push_back(D);
942 }
943
944 return true;
945}
946
947////////////////////////////////////////////////////////////////////////////////
948
950{
951 bool ret = true;
952
953 if (!DC)
954 return true;
955
956 clang::Decl* D = dyn_cast<clang::Decl>(DC);
957 // skip implicit decls
958 if (D && D->isImplicit()){
959 return true;
960 }
961
963 const clang::NamespaceDecl *parent = llvm::dyn_cast<clang::NamespaceDecl> (DC);
964 if (parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::"))
965 return true;
966 }
967
968 for (DeclContext::decl_iterator Child = DC->decls_begin(), ChildEnd = DC->decls_end();
969 ret && (Child != ChildEnd); ++Child) {
970 ret=TraverseDecl(*Child);
971 }
972
973 return ret;
974
975}
976
977////////////////////////////////////////////////////////////////////////////////
978
979bool RScanner::GetDeclName(clang::Decl* D, std::string& name) const
980{
981 clang::NamedDecl* N = dyn_cast<clang::NamedDecl> (D);
982
983 if (N) {
984 name = N->getNameAsString();
985 return true;
986 }
987 else {
988 name = "UNNAMED";
989 return false;
990 }
991}
992
993////////////////////////////////////////////////////////////////////////////////
994
995bool RScanner::GetDeclQualName(const clang::Decl* D, std::string& qual_name)
996{
997 auto N = dyn_cast<const clang::NamedDecl> (D);
998
999 if (N) {
1000 llvm::raw_string_ostream stream(qual_name);
1001 N->getNameForDiagnostic(stream,D->getASTContext().getPrintingPolicy(),true); // qual_name = N->getQualifiedNameAsString();
1002 return true;
1003 }
1004 else {
1005 return false;
1006 }
1007}
1008
1009////////////////////////////////////////////////////////////////////////////////
1010
1011bool RScanner::GetFunctionPrototype(clang::Decl* D, std::string& prototype) const {
1012 if (!D) {
1013 return false;
1014 }
1015
1016 clang::FunctionDecl* F = dyn_cast<clang::FunctionDecl> (D);
1017
1018 if (F) {
1019
1020 prototype = "";
1021 for (clang::FunctionDecl::param_iterator I = F->param_begin(), E = F->param_end(); I != E; ++I) {
1022 clang::ParmVarDecl* P = *I;
1023
1024 if (prototype != "")
1025 prototype += ",";
1026
1027 //std::string type = P->getType().getAsString();
1028 std::string type = P->getType().getAsString();
1029 if (type.at(type.length()-1) == '*') {
1030 type.at(type.length()-2) = '*';
1031 type.erase(type.length()-1);
1032 }
1033 prototype += type;
1034 }
1035
1036 prototype = "(" + prototype + ")";
1037 return true;
1038 }
1039 else {
1040 ShowWarning("can't convert Decl to FunctionDecl","");
1041 return false;
1042 }
1043}
1044
1045////////////////////////////////////////////////////////////////////////////////
1046
1047void RScanner::Scan(const clang::ASTContext &C)
1048{
1049 fSourceManager = &C.getSourceManager();
1050
1051// if (fVerboseLevel >= 3) fSelectionRules.PrintSelectionRules();
1052
1054 std::cout<<"File name detected"<<std::endl;
1055 }
1056
1058 TraverseDecl(C.getTranslationUnitDecl());
1059
1060 fFirstPass=false;
1061 fselectedRecordDecls.clear();
1062 fSelectedEnums.clear();
1063 fSelectedTypedefs.clear();
1064 fSelectedVariables.clear();
1065 fSelectedFunctions.clear();
1066 TraverseDecl(C.getTranslationUnitDecl());
1067
1068 // The RecursiveASTVisitor uses range-based for; we must not modify the AST
1069 // during iteration / visitation. Instead, buffer the lookups that could
1070 // potentially create new template specializations, and handle them here:
1072}
1073
1074
1075////////////////////////////////////////////////////////////////////////////////
1076/// Set the callback to the RecordDecl and return the previous one.
1077
1079{
1081 fRecordDeclCallback = callback;
1082 return old;
1083}
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
#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
bool HasAttributeFileName() const
bool HasAttributePattern() 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 RequestNoInputOperator() const
void Print(std::ostream &out) const final
std::string GetLocation(clang::Decl *D) const
Definition Scanner.cxx:234
void Scan(const clang::ASTContext &C)
Definition Scanner.cxx:1047
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: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:308
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:319
void AddDelayedAnnotatedRecordDecls()
Definition Scanner.cxx:810
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:907
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:193
std::string FuncParameters(clang::FunctionDecl *D) const
Definition Scanner.cxx:431
bool fTypeTable[fgTypeLast+1]
Definition Scanner.h:192
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:129
bool GetFunctionPrototype(clang::Decl *D, std::string &prototype) const
Definition Scanner.cxx:1011
std::set< clang::RecordDecl * > fselectedRecordDecls
Definition Scanner.h:198
std::string ConvTemplateName(clang::TemplateName &N) const
Definition Scanner.cxx:416
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:326
bool VisitVarDecl(clang::VarDecl *D)
Definition Scanner.cxx:888
TypedefColl_t fSelectedTypedefs
Definition Scanner.h:130
bool fFirstPass
Definition Scanner.h:200
std::string GetSrcLocation(clang::SourceLocation L) const
Definition Scanner.cxx:224
void(* DeclCallback)(const clang::RecordDecl *)
Definition Scanner.h:77
void UnsupportedType(clang::QualType qual_type) const
Definition Scanner.cxx:368
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:1078
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:194
static const char * fgClangFuncKey
Definition Scanner.h:123
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:133
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:140
bool VisitEnumDecl(clang::EnumDecl *D)
Definition Scanner.cxx:870
static std::map< clang::Decl *, std::string > fgAnonymousClassMap
Definition Scanner.h:175
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:995
std::string ExprToStr(clang::Expr *expr) const
Definition Scanner.cxx:401
static const int fgTypeLast
Definition Scanner.h:188
SelectionRules & fSelectionRules
Definition Scanner.h:197
virtual ~RScanner()
Definition Scanner.cxx:104
static const char * fgClangDeclKey
Definition Scanner.h:122
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:189
VariableColl_t fSelectedVariables
Definition Scanner.h:132
bool VisitFunctionDecl(clang::FunctionDecl *D)
Definition Scanner.cxx:929
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:979
bool TraverseDeclContextHelper(clang::DeclContext *DC)
Definition Scanner.cxx:949
ClassColl_t fSelectedClasses
Definition Scanner.h:128
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:844
The class representing the collection of selection rules.
bool GetHasFileNameRule() const
const ClassSelectionRule * IsDeclSelected(const clang::RecordDecl *D, bool includeTypedefRule) const
#define F(x, y, z)
#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,...)
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
bool areEqual< ClassSelectionRule >(const ClassSelectionRule *r1, const ClassSelectionRule *r2, bool moduloNameOrPattern)