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
61extern cling::Interpreter *gInterp;
62
63const char* RScanner::fgClangDeclKey = "ClangDecl"; // property key used for connection with Clang objects
64const char* RScanner::fgClangFuncKey = "ClangFunc"; // property key for demangled names
65
69
70std::map <clang::Decl*, std::string> RScanner::fgAnonymousClassMap;
71std::map <clang::Decl*, std::string> RScanner::fgAnonymousEnumMap;
72
73////////////////////////////////////////////////////////////////////////////////
74/// Regular constructor setting up the scanner to search for entities
75/// matching the 'rules'.
76
78 EScanType stype,
79 const cling::Interpreter &interpret,
81 unsigned int verbose /* = 0 */) :
82 fVerboseLevel(verbose),
83 fSourceManager(nullptr),
84 fInterpreter(interpret),
85 fRecordDeclCallback(nullptr),
86 fNormCtxt(normCtxt),
87 fSelectionRules(rules),
88 fScanType(stype),
89 fFirstPass(true)
90{
91 // Build the cache for all selection rules
93
94 for (int i = 0; i <= fgDeclLast; i ++)
95 fDeclTable [i] = false;
96
97 for (int i = 0; i <= fgTypeLast; i ++)
98 fTypeTable [i] = false;
99
100 fLastDecl = nullptr;
101}
102
103////////////////////////////////////////////////////////////////////////////////
104
106{
107}
108
109////////////////////////////////////////////////////////////////////////////////
110/// Whether we can actually visit this declaration, i.e. if it is reachable
111/// via name lookup.
112///
113/// RScanner shouldn't touch decls for which this method returns false as we
114/// call Sema methods on those declarations. Those will fail in strange way as
115/// they assume those decls are already visible.
116///
117/// The main problem this is supposed to prevent is when we use C++ modules and
118/// have hidden declarations in our AST. Usually they can't be found as they are
119/// hidden from name lookup until their module is actually imported, but as the
120/// RecursiveASTVisitor is not supposed to be restricted by lookup limitations,
121/// it still reaches those hidden declarations.
122bool RScanner::shouldVisitDecl(clang::NamedDecl *D)
123{
124 if (auto M = D->getOwningModule()) {
125 return fInterpreter.getSema().isModuleVisible(M);
126 }
127 return true;
128}
129
130////////////////////////////////////////////////////////////////////////////////
131
132inline void* ToDeclProp(clang::Decl* item)
133{
134 /* conversion and type check used by AddProperty */
135 return item;
136}
137
138////////////////////////////////////////////////////////////////////////////////
139
140inline size_t APIntToSize(const llvm::APInt& num)
141{
142 return *num.getRawData();
143}
144
145////////////////////////////////////////////////////////////////////////////////
146
147inline long APIntToLong(const llvm::APInt& num)
148{
149 return *num.getRawData();
150}
151
152////////////////////////////////////////////////////////////////////////////////
153
154inline std::string APIntToStr(const llvm::APInt& num)
155{
156 return llvm::toString(num, /*radix*/10, /*signed*/true);
157}
158
159////////////////////////////////////////////////////////////////////////////////
160
161inline std::string IntToStr(int num)
162{
163 std::string txt = "";
164 txt += num;
165 return txt;
166}
167
168////////////////////////////////////////////////////////////////////////////////
169
170inline std::string IntToStd(int num)
171{
172 std::ostringstream stream;
173 stream << num;
174 return stream.str();
175}
176
177////////////////////////////////////////////////////////////////////////////////
178
179inline std::string Message(const std::string &msg, const std::string &location)
180{
181 std::string loc = location;
182
183 if (loc == "")
184 return msg;
185 else
186 return loc + " " + msg;
187}
188
189////////////////////////////////////////////////////////////////////////////////
190
191void RScanner::ShowInfo(const std::string &msg, const std::string &location) const
192{
193 const std::string message = Message(msg, location);
194 std::cout << message << std::endl;
195}
196
197////////////////////////////////////////////////////////////////////////////////
198
199void RScanner::ShowWarning(const std::string &msg, const std::string &location) const
200{
201 const std::string message = Message(msg, location);
202 std::cout << message << std::endl;
203}
204
205////////////////////////////////////////////////////////////////////////////////
206
207void RScanner::ShowError(const std::string &msg, const std::string &location) const
208{
209 const std::string message = Message(msg, location);
210 std::cout << message << std::endl;
211}
212
213////////////////////////////////////////////////////////////////////////////////
214
215void RScanner::ShowTemplateInfo(const std::string &msg, const std::string &location) const
216{
217 std::string loc = location;
218 if (loc == "")
219 loc = GetLocation (fLastDecl);
220 ShowWarning(msg, loc);
221}
222
223////////////////////////////////////////////////////////////////////////////////
224
225std::string RScanner::GetSrcLocation(clang::SourceLocation L) const
226{
227 std::string location = "";
228 llvm::raw_string_ostream stream(location);
229 L.print(stream, *fSourceManager);
230 return stream.str();
231}
232
233////////////////////////////////////////////////////////////////////////////////
234
235std::string RScanner::GetLocation(clang::Decl* D) const
236{
237 if (D == nullptr)
238 {
239 return "";
240 }
241 else
242 {
243 std::string location = "";
244 llvm::raw_string_ostream stream(location);
245 D->getLocation().print(stream, *fSourceManager);
246 return stream.str();
247 }
248}
249
250////////////////////////////////////////////////////////////////////////////////
251
252std::string RScanner::GetName(clang::Decl* D) const
253{
254 std::string name = "";
255 // std::string kind = D->getDeclKindName();
256
257 if (clang::NamedDecl* ND = dyn_cast <clang::NamedDecl> (D)) {
258 name = ND->getQualifiedNameAsString();
259 }
260
261 return name;
262}
263
264////////////////////////////////////////////////////////////////////////////////
265
266inline std::string AddSpace(const std::string &txt)
267{
268 if (txt == "")
269 return "";
270 else
271 return txt + " ";
272}
273
274////////////////////////////////////////////////////////////////////////////////
275
276void RScanner::DeclInfo(clang::Decl* D) const
277{
278 std::string location = GetLocation(D);
279 std::string kind = D->getDeclKindName();
280 std::string name = GetName(D);
281 ShowInfo("Scan: " + kind + " declaration " + name, location);
282}
283
284////////////////////////////////////////////////////////////////////////////////
285/// unknown - this kind of declaration was not known to programmer
286
287void RScanner::UnknownDecl(clang::Decl* D, const std::string &txt) const
288{
289 std::string location = GetLocation(D);
290 std::string kind = D->getDeclKindName();
291 std::string name = GetName(D);
292 ShowWarning("Unknown " + AddSpace(txt) + kind + " declaration " + name, location);
293}
294
295////////////////////////////////////////////////////////////////////////////////
296/// unexpected - this kind of declaration is unexpected (in concrete place)
297
298void RScanner::UnexpectedDecl(clang::Decl* D, const std::string &txt) const
299{
300 std::string location = GetLocation(D);
301 std::string kind = D->getDeclKindName();
302 std::string name = GetName(D);
303 ShowWarning("Unexpected " + kind + " declaration " + name, location);
304}
305
306////////////////////////////////////////////////////////////////////////////////
307/// unsupported - this kind of declaration is probably not used (in current version of C++)
308
309void RScanner::UnsupportedDecl(clang::Decl* D, const std::string &txt) const
310{
311 std::string location = GetLocation(D);
312 std::string kind = D->getDeclKindName();
313 std::string name = GetName(D);
314 ShowWarning("Unsupported " + AddSpace(txt) + kind + " declaration " + name, location);
315}
316
317////////////////////////////////////////////////////////////////////////////////
318/// unimportant - this kind of declaration is not stored into reflex
319
320void RScanner::UnimportantDecl(clang::Decl* D, const std::string &txt) const
321{
322}
323
324////////////////////////////////////////////////////////////////////////////////
325/// information about item, that should be implemented
326
327void RScanner::UnimplementedDecl(clang::Decl* D, const std::string &txt)
328{
329 clang::Decl::Kind k = D->getKind();
330
331 bool show = true;
332 if (k <= fgDeclLast) {
333 if (fDeclTable [k])
334 show = false; // already displayed
335 else
336 fDeclTable [k] = true;
337 }
338
339 if (show)
340 {
341 std::string location = GetLocation(D);
342 std::string kind = D->getDeclKindName();
343 std::string name = GetName(D);
344 std::string msg = "Unimplemented ";
345 if (txt == "") {
346 msg += "declaration";
347 } else {
348 msg += txt;
349 }
350 msg += ": ";
351 msg += kind;
352 msg += " ";
353 msg += name;
354 ShowWarning(msg,location);
355 }
356}
357
358////////////////////////////////////////////////////////////////////////////////
359
360void RScanner::UnknownType(clang::QualType qual_type) const
361{
362 std::string location = GetLocation(fLastDecl);
363 std::string kind = qual_type.getTypePtr()->getTypeClassName();
364 ShowWarning("Unknown " + kind + " type " + qual_type.getAsString(), location);
365}
366
367////////////////////////////////////////////////////////////////////////////////
368
369void RScanner::UnsupportedType(clang::QualType qual_type) const
370{
371 std::string location = GetLocation(fLastDecl);
372 std::string kind = qual_type.getTypePtr()->getTypeClassName();
373 ShowWarning("Unsupported " + kind + " type " + qual_type.getAsString(), location);
374}
375
376////////////////////////////////////////////////////////////////////////////////
377
378std::string RScanner::GetEnumName(clang::EnumDecl* D) const
379{
380 std::string enum_name = D->getQualifiedNameAsString();
381
382 if (! D->getDeclName ()) {
383 if (fgAnonymousEnumMap.find (D) != fgAnonymousEnumMap.end())
384 {
385 // already encountered anonymous enumeration type
386 enum_name = fgAnonymousEnumMap [D];
387 }
388 else
389 {
391 enum_name = "_ANONYMOUS_ENUM_" + IntToStd(fgAnonymousEnumCounter) + "_"; // !?
392 fgAnonymousEnumMap [D] = enum_name;
393 // ShowInfo ("anonymous enum " + enum_name, GetLocation (D));
394 }
395 }
396
397 return enum_name;
398}
399
400////////////////////////////////////////////////////////////////////////////////
401
402std::string RScanner::ExprToStr(clang::Expr* expr) const
403{
404 clang::LangOptions lang_opts;
405 clang::PrintingPolicy print_opts(lang_opts); // !?
406
407 std::string text = "";
408 llvm::raw_string_ostream stream(text);
409
410 expr->printPretty(stream, nullptr, print_opts);
411
412 return stream.str();
413}
414
415////////////////////////////////////////////////////////////////////////////////
416
417std::string RScanner::ConvTemplateName(clang::TemplateName& N) const
418{
419 clang::LangOptions lang_opts;
420 clang::PrintingPolicy print_opts(lang_opts); // !?
421
422 std::string text = "";
423 llvm::raw_string_ostream stream(text);
424
425 N.print(stream, print_opts);
426
427 return stream.str();
428}
429
430////////////////////////////////////////////////////////////////////////////////
431
432std::string RScanner::FuncParameters(clang::FunctionDecl* D) const
433{
434 std::string result = "";
435
436 for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
437 clang::ParmVarDecl* P = *I;
438
439 if (result != "")
440 result += ";"; // semicolon, not comma, important
441
442 std::string type = P->getType().getAsString();
443 std::string name = P->getNameAsString();
444
445 result += type + " " + name;
446
447 // NO if (P->hasDefaultArg ()) // check hasUnparsedDefaultArg () and hasUninstantiatedDefaultArg ()
448 if (P->getInit()) {
449 std::string init_value = ExprToStr(P->getDefaultArg());
450 result += "=" + init_value;
451 }
452 }
453
454 return result;
455}
456
457////////////////////////////////////////////////////////////////////////////////
458
459std::string RScanner::FuncParameterList(clang::FunctionDecl* D) const
460{
461 std::string result = "";
462
463 for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
464 clang::ParmVarDecl* P = *I;
465
466 if (result != "")
467 result += ",";
468
469 std::string type = P->getType().getAsString();
470 result += type;
471 }
472
473 return "(" + result + ")";
474}
475
476////////////////////////////////////////////////////////////////////////////////
477/// This method visits a namespace node
478
479bool RScanner::VisitNamespaceDecl(clang::NamespaceDecl* N)
480{
481 // We don't need to visit this while creating the big PCM
483 return true;
484
485 if (!shouldVisitDecl(N))
486 return true;
487
488 // in case it is implicit we don't create a builder
489 // [Note: Can N be nullptr?, is so 'ShouldVisitDecl' should test or we should test sooner]
490 if((N && N->isImplicit()) || !N){
491 return true;
492 }
493
494 bool ret = true;
495
497 if (selected) {
498
499 clang::DeclContext* primary_ctxt = N->getPrimaryContext();
500 clang::NamespaceDecl* primary = llvm::dyn_cast<clang::NamespaceDecl>(primary_ctxt);
501
502 RPredicateIsSameNamespace pred(primary);
503 if ( find_if(fSelectedNamespaces.begin(),fSelectedNamespaces.end(),pred) == fSelectedNamespaces.end() ) {
504 // The namespace is not already registered.
505
506 if (fVerboseLevel > 0) {
507 std::string qual_name;
508 GetDeclQualName(N,qual_name);
509 // std::cout<<"\tSelected namespace -> " << qual_name << " ptr " << (void*)N << " decl ctxt " << (void*)N->getPrimaryContext() << " classname " <<primary->getNameAsString() << "\n";
510 std::cout<<"\tSelected namespace -> " << qual_name << "\n";
511 }
512 fSelectedNamespaces.push_back(AnnotatedNamespaceDecl(primary,selected->GetIndex(),selected->RequestOnlyTClass()));
513 }
514 ret = true;
515 }
516
517 return ret;
518}
519
520////////////////////////////////////////////////////////////////////////////////
521
522bool RScanner::VisitRecordDecl(clang::RecordDecl* D)
523{
524 if (!shouldVisitDecl(D))
525 return true;
526
527 // This method visits a class node
529
530
531}
532
533////////////////////////////////////////////////////////////////////////////////
534
536 const clang::Type* req_type,
537 const clang::RecordDecl* recordDecl,
538 const std::string& attr_name,
539 const clang::TypedefNameDecl* typedefNameDecl,
540 unsigned int indexOffset)
541{
542
543 bool has_attr_name = selected->HasAttributeName();
544
545 if (recordDecl->isUnion() &&
547 std::string normName;
549 recordDecl->getASTContext().getTypeDeclType(recordDecl),
551 fNormCtxt);
552 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());
553 return 1;
554 }
555
556 // clang-format off
557 if (has_attr_name) {
558 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
559 req_type,
560 recordDecl,
561 attr_name.c_str(),
562 selected->RequestStreamerInfo(),
563 selected->RequestNoStreamer(),
564 selected->RequestNoInputOperator(),
565 selected->RequestOnlyTClass(),
566 selected->RequestedVersionNumber(),
569 fNormCtxt);
570 } else {
571 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
572 recordDecl,
573 selected->RequestStreamerInfo(),
574 selected->RequestNoStreamer(),
575 selected->RequestNoInputOperator(),
576 selected->RequestOnlyTClass(),
577 selected->RequestedVersionNumber(),
580 fNormCtxt);
581 }
582 // clang-format on
583
584 if (fVerboseLevel > 0) {
585 std::string qual_name;
586 GetDeclQualName(recordDecl,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){
595 GetDeclQualName(typedefNameDecl,typedef_qual_name);
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
612bool RScanner::TreatRecordDeclOrTypedefNameDecl(clang::TypeDecl* typeDecl)
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) {
630 recordDecl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(typedefNameDecl->getUnderlyingType());
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.
662 fRecordDeclCallback(recordDecl);
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
676 const ClassSelectionRule *selectedFromTypedef = typedefNameDecl ? fSelectionRules.IsDeclSelected(typedefNameDecl) : nullptr;
677
678 const ClassSelectionRule *selectedFromRecDecl = fSelectionRules.IsDeclSelected(recordDecl, false /* exclude typedef rules*/);
679
680 const ClassSelectionRule *selected = typedefNameDecl ? selectedFromTypedef : selectedFromRecDecl;
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;
686 if ( selectedFromRecDecl )
687 excludedFromRecDecl = selectedFromRecDecl->GetSelected() == BaseSelectionRule::kNo;
688
689 if (selected->GetSelected() != BaseSelectionRule::kYes || excludedFromRecDecl)
690 return true;
691
692 // Save the typedef
693 if (selectedFromTypedef) {
694 if (!IsElementPresent(fSelectedTypedefs, typedefNameDecl))
695 fSelectedTypedefs.push_back(typedefNameDecl);
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()) {
703 if (typedefNameDecl && !IsElementPresent(fSelectedTypedefs, typedefNameDecl))
704 fSelectedTypedefs.push_back(typedefNameDecl);
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;
736 if (!fFirstPass && !rcrdDeclNotAlreadySelected) {
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
747 auto previouslyMatchingRule = (const ClassSelectionRule*)declSelRuleMapIt->second;
748 int previouslineno = previouslyMatchingRule->GetLineNumber();
749
750 std::string cleanFileName = llvm::sys::path::filename(selected->GetSelFileName()).str();
751 auto lineno = selected->GetLineNumber();
752 auto rulesAreCompatible = SelectionRulesUtils::areEqual<ClassSelectionRule>(selected, previouslyMatchingRule, true /*moduloNameOrPattern*/);
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
769 if (!rcrdDeclNotAlreadySelected || fFirstPass)
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
803 auto sc = AddAnnotatedRecordDecl(selected, req_type, recordDecl, attr_name, typedefNameDecl);
804 if (sc != 0) {
805 return false;
806 }
807
808 if (auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
809 fDelayedAnnotatedRecordDecls.emplace_back(DelayedAnnotatedRecordDeclInfo{selected, CTSD, typedefNameDecl});
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;
822 auto nameTypeForIO = ROOT::TMetaUtils::GetNameTypeForIO(clang::QualType(thisType, 0), fInterpreter, fNormCtxt);
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;
832 recordDecl = canRecordDeclForIO;
833 fDeclSelRuleMap[recordDecl] = info.fSelected;
834 thisType = typeForIO.getTypePtr();
835 }
836
837 AddAnnotatedRecordDecl(info.fSelected, thisType, recordDecl,
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) {
975 ret=TraverseDecl(*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{
1002 auto N = dyn_cast<const clang::NamedDecl> (D);
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
1063 TraverseDecl(C.getTranslationUnitDecl());
1064
1065 fFirstPass=false;
1066 fselectedRecordDecls.clear();
1067 fSelectedEnums.clear();
1068 fSelectedTypedefs.clear();
1069 fSelectedVariables.clear();
1070 fSelectedFunctions.clear();
1071 TraverseDecl(C.getTranslationUnitDecl());
1072
1073 // The RecursiveASTVisitor uses range-based for; we must not modify the AST
1074 // during iteration / visitation. Instead, buffer the lookups that could
1075 // potentially create new template specializations, and handle them here:
1077}
1078
1079
1080////////////////////////////////////////////////////////////////////////////////
1081/// Set the callback to the RecordDecl and return the previous one.
1082
1084{
1086 fRecordDeclCallback = callback;
1087 return old;
1088}
std::string IntToStr(int num)
Definition Scanner.cxx:161
long APIntToLong(const llvm::APInt &num)
Definition Scanner.cxx:147
cling::Interpreter * gInterp
std::string AddSpace(const std::string &txt)
Definition Scanner.cxx:266
size_t APIntToSize(const llvm::APInt &num)
Definition Scanner.cxx:140
void * ToDeclProp(clang::Decl *item)
Definition Scanner.cxx:132
std::string APIntToStr(const llvm::APInt &num)
Definition Scanner.cxx:154
std::string IntToStd(int num)
Definition Scanner.cxx:170
std::string Message(const std::string &msg, const std::string &location)
Definition Scanner.cxx:179
#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
int RequestedRNTupleSerializationMode() const
bool RequestNoInputOperator() const
void Print(std::ostream &out) const final
std::string GetLocation(clang::Decl *D) const
Definition Scanner.cxx:235
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:287
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:77
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:309
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:320
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:191
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:432
bool fTypeTable[fgTypeLast+1]
Definition Scanner.h:192
void ShowTemplateInfo(const std::string &msg, const std::string &location="") const
Definition Scanner.cxx:215
std::string GetEnumName(clang::EnumDecl *D) const
Definition Scanner.cxx:378
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:417
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:327
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:225
void(* DeclCallback)(const clang::RecordDecl *)
Definition Scanner.h:77
void UnsupportedType(clang::QualType qual_type) const
Definition Scanner.cxx:369
const cling::Interpreter & fInterpreter
Definition Scanner.h:186
DeclCallback SetRecordDeclCallback(DeclCallback callback)
Set the callback to the RecordDecl and return the previous one.
Definition Scanner.cxx:1083
bool VisitNamespaceDecl(clang::NamespaceDecl *D)
This method visits a namespace node.
Definition Scanner.cxx:479
void ShowWarning(const std::string &msg, const std::string &location="") const
Definition Scanner.cxx:199
std::string GetName(clang::Decl *D) const
Definition Scanner.cxx:252
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:207
void UnexpectedDecl(clang::Decl *D, const std::string &txt="") const
unexpected - this kind of declaration is unexpected (in concrete place)
Definition Scanner.cxx:298
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:535
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:459
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:402
static const int fgTypeLast
Definition Scanner.h:188
SelectionRules & fSelectionRules
Definition Scanner.h:197
virtual ~RScanner()
Definition Scanner.cxx:105
static const char * fgClangDeclKey
Definition Scanner.h:122
bool VisitRecordDecl(clang::RecordDecl *D)
Definition Scanner.cxx:522
void UnknownType(clang::QualType qual_type) const
Definition Scanner.cxx:360
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:276
bool shouldVisitDecl(clang::NamedDecl *D)
Whether we can actually visit this declaration, i.e.
Definition Scanner.cxx:122
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 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,...)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
bool areEqual< ClassSelectionRule >(const ClassSelectionRule *r1, const ClassSelectionRule *r2, bool moduloNameOrPattern)