Logo ROOT   6.18/05
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 if((N && N->isImplicit()) || !N){
489 return true;
490 }
491
492 bool ret = true;
493
495 if (selected) {
496
497 clang::DeclContext* primary_ctxt = N->getPrimaryContext();
498 clang::NamespaceDecl* primary = llvm::dyn_cast<clang::NamespaceDecl>(primary_ctxt);
499
500 RPredicateIsSameNamespace pred(primary);
501 if ( find_if(fSelectedNamespaces.begin(),fSelectedNamespaces.end(),pred) == fSelectedNamespaces.end() ) {
502 // The namespace is not already registered.
503
504 if (fVerboseLevel > 0) {
505 std::string qual_name;
506 GetDeclQualName(N,qual_name);
507 // std::cout<<"\tSelected namespace -> " << qual_name << " ptr " << (void*)N << " decl ctxt " << (void*)N->getPrimaryContext() << " classname " <<primary->getNameAsString() << "\n";
508 std::cout<<"\tSelected namespace -> " << qual_name << "\n";
509 }
510 fSelectedNamespaces.push_back(AnnotatedNamespaceDecl(primary,selected->GetIndex(),selected->RequestOnlyTClass()));
511 }
512 ret = true;
513 }
514
515 return ret;
516}
517
518////////////////////////////////////////////////////////////////////////////////
519
520bool RScanner::VisitRecordDecl(clang::RecordDecl* D)
521{
522 if (!shouldVisitDecl(D))
523 return true;
524
525 // This method visits a class node
527
528
529}
530
531////////////////////////////////////////////////////////////////////////////////
532
534 const clang::Type* req_type,
535 const clang::RecordDecl* recordDecl,
536 const std::string& attr_name,
537 const clang::TypedefNameDecl* typedefNameDecl,
538 unsigned int indexOffset)
539{
540
541 bool has_attr_name = selected->HasAttributeName();
542
543 if (recordDecl->isUnion() &&
544 0 != ROOT::TMetaUtils::GetClassVersion(recordDecl,fInterpreter)) {
545 std::string normName;
547 recordDecl->getASTContext().getTypeDeclType(recordDecl),
549 fNormCtxt);
550 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());
551 return 1;
552 }
553
554 if (has_attr_name) {
555 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
556 req_type,
557 recordDecl,
558 attr_name.c_str(),
559 selected->RequestStreamerInfo(),
560 selected->RequestNoStreamer(),
561 selected->RequestNoInputOperator(),
562 selected->RequestOnlyTClass(),
563 selected->RequestedVersionNumber(),
565 fNormCtxt);
566 } else {
567 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
568 recordDecl,
569 selected->RequestStreamerInfo(),
570 selected->RequestNoStreamer(),
571 selected->RequestNoInputOperator(),
572 selected->RequestOnlyTClass(),
573 selected->RequestedVersionNumber(),
575 fNormCtxt);
576 }
577
578 if (fVerboseLevel > 0) {
579 std::string qual_name;
580 GetDeclQualName(recordDecl,qual_name);
581 std::string normName;
583 recordDecl->getASTContext().getTypeDeclType(recordDecl),
585 fNormCtxt);
586 std::string typedef_qual_name;
587 std::string typedefMsg;
588 if (typedefNameDecl){
589 GetDeclQualName(typedefNameDecl,typedef_qual_name);
590 typedefMsg = "(through typedef/alias " + typedef_qual_name + ") ";
591 }
592
593 std::cout << "Selected class "
594 << typedefMsg
595 << "-> "
596 << qual_name
597 << " for ROOT: "
598 << normName
599 << "\n";
600 }
601 return 0;
602}
603
604////////////////////////////////////////////////////////////////////////////////
605
606bool RScanner::TreatRecordDeclOrTypedefNameDecl(clang::TypeDecl* typeDecl)
607{
608 // For every class is created a new class buider irrespectful of weather the
609 // class is internal for another class declaration or not.
610 // RecordDecls and TypedefDecls (or RecordDecls!) are treated.
611 // We follow two different codepaths if the typeDecl is a RecordDecl or
612 // a TypedefDecl. If typeDecl is a TypedefDecl, recordDecl becomes the
613 // underlying RecordDecl.
614 // This is done to leverage the selections rule matching in SelectionRules
615 // which works basically with names.
616 // At the end of the method, if the typedef name is matched, an AnnotatedRecordDecl
617 // with the underlying RecordDecl is fed to the machinery.
618
619 const clang::RecordDecl* recordDecl = clang::dyn_cast<clang::RecordDecl>(typeDecl);
620 const clang::TypedefNameDecl* typedefNameDecl = clang::dyn_cast<clang::TypedefNameDecl>(typeDecl);
621
622 // If typeDecl is not a RecordDecl, try to fetch the RecordDecl behind the TypedefDecl
623 if (!recordDecl && typedefNameDecl) {
624 recordDecl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(typedefNameDecl->getUnderlyingType());
625 }
626
627 // If at this point recordDecl is still NULL, we have a problem
628 if (!recordDecl) {
629 ROOT::TMetaUtils::Warning("RScanner::TreatRecordDeclOrTypeNameDecl",
630 "Could not cast typeDecl either to RecordDecl or could not get RecordDecl underneath typedef.\n");
631 return true;
632 }
633
634 // Do not select unnamed records.
635 if (!recordDecl->getIdentifier())
636 return true;
637
638 // Do not select dependent types.
639 if (recordDecl->isDependentType())
640 return true;
641
643 return true;
644
645
646 // At this point, recordDecl must be a RecordDecl pointer.
647
648 if (recordDecl && fRecordDeclCallback) {
649 // Pass on any declaration. This is usually used to record dependency.
650 // Since rootcint see C++ compliant header files, we can assume that
651 // if a forward declaration or declaration has been inserted, the
652 // classes for which we are creating a dictionary will be using
653 // them either directly or indirectly. Any false positive can be
654 // resolved by removing the spurrious dependency in the (user) header
655 // files.
656 fRecordDeclCallback(recordDecl);
657 }
658
659 // in case it is implicit or a forward declaration, we are not interested.
660 if(recordDecl && (recordDecl->isImplicit() || !recordDecl->isCompleteDefinition()) ) {
661 return true;
662 }
663
664 // Never select the class templates themselves.
665 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl);
666 if (cxxdecl && cxxdecl->getDescribedClassTemplate ()) {
667 return true;
668 }
669
670 const ClassSelectionRule *selectedFromTypedef = typedefNameDecl ? fSelectionRules.IsDeclSelected(typedefNameDecl) : 0;
671
672 const ClassSelectionRule *selectedFromRecDecl = fSelectionRules.IsDeclSelected(recordDecl);
673
674 const ClassSelectionRule *selected = typedefNameDecl ? selectedFromTypedef : selectedFromRecDecl;
675
676 if (! selected) return true; // early exit. Nothing more to be done.
677
678 // Selected through typedef but excluded with concrete classname
679 bool excludedFromRecDecl = false;
680 if ( selectedFromRecDecl )
681 excludedFromRecDecl = selectedFromRecDecl->GetSelected() == BaseSelectionRule::kNo;
682
683 if (selected->GetSelected() == BaseSelectionRule::kYes && !excludedFromRecDecl) {
684 // The record decl will results to be selected
685
686 // Save the typedef
687 if (selectedFromTypedef){
688 if (!IsElementPresent(fSelectedTypedefs, typedefNameDecl))
689 fSelectedTypedefs.push_back(typedefNameDecl);
690 // Early exit here if we are not in presence of XML
691 if (!fSelectionRules.IsSelectionXMLFile()) return true;
692 }
693
694 if (fSelectionRules.IsSelectionXMLFile() && selected->IsFromTypedef()) {
695 if (!IsElementPresent(fSelectedTypedefs, typedefNameDecl))
696 fSelectedTypedefs.push_back(typedefNameDecl);
697 return true;
698 }
699
700 if (typedefNameDecl)
701 ROOT::TMetaUtils::Info("RScanner::TreatRecordDeclOrTypedefNameDecl",
702 "Typedef is selected %s.\n", typedefNameDecl->getNameAsString().c_str());
703
704 // For the case kNo, we could (but don't) remove the node from the pcm
705 // For the case kDontCare, the rule is just a place holder and we are actually trying to exclude some of its children
706 // (this is used only in the selection xml case).
707
708 // Reject the selection of std::pair on the ground that it is trivial
709 // and can easily be recreated from the AST information.
710 if (recordDecl && recordDecl->getName() == "pair") {
711 const clang::NamespaceDecl *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(recordDecl->getDeclContext());
712 if (!nsDecl){
713 ROOT::TMetaUtils::Error("RScanner::TreatRecordDeclOrTypedefNameDecl",
714 "Cannot convert context of RecordDecl called pair into a namespace.\n");
715 return true;
716 }
717 const clang::NamespaceDecl *nsCanonical = nsDecl->getCanonicalDecl();
718 if (nsCanonical && nsCanonical == fInterpreter.getCI()->getSema().getStdNamespace()) {
719 if (selected->HasAttributeFileName() || selected->HasAttributeFilePattern()) {
720 return true;
721 }
722 }
723 }
724
725 // Insert in the selected classes if not already there
726 // We need this check since the same class can be selected through its name or typedef
727 bool rcrdDeclNotAlreadySelected = fselectedRecordDecls.insert((RecordDecl*)recordDecl->getCanonicalDecl()).second;
728
729 auto declSelRuleMapIt = fDeclSelRuleMap.find(recordDecl->getCanonicalDecl());
730 if (!fFirstPass &&
731 !rcrdDeclNotAlreadySelected &&
732 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 fDeclSelRuleMap[recordDecl->getCanonicalDecl()]=selected;
760
761 if(rcrdDeclNotAlreadySelected &&
762 !fFirstPass){
763
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 // We exclude filename selections as they can come from aclic
769 auto isFileSelection = selected->HasAttributeFileName() &&
770 selected->HasAttributePattern() &&
771 "*" == selected->GetAttributePattern();
772 auto canDeclAccess = recordDecl->getCanonicalDecl()->getAccess();
773 if (!isFileSelection && (AS_protected == canDeclAccess || AS_private == canDeclAccess)){
774 std::string normName;
776 recordDecl->getASTContext().getTypeDeclType(recordDecl),
778 fNormCtxt);
779 auto msg = "Class or struct %s was selected but its dictionary cannot be generated: "
780 "this is a private or protected class and this is not supported. No direct "
781 "I/O operation of %s instances will be possible.\n";
782 ROOT::TMetaUtils::Warning(0,msg,normName.c_str(),normName.c_str());
783 return true;
784 }
785
786 // Replace on the fly the type if the type for IO is different for example
787 // in presence of unique_ptr<T> or collections thereof.
788 // The following lines are very delicate: we need to preserve the special
789 // ROOT opaque typedefs.
790 auto req_type = selected->GetRequestedType();
791 clang::QualType thisType(req_type, 0);
792 std::string attr_name = selected->GetAttributeName().c_str();
793
794 auto sc = AddAnnotatedRecordDecl(selected, req_type, recordDecl, attr_name, typedefNameDecl);
795 if (sc != 0) {
796 return false;
797 }
798
799 if (auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
800 fDelayedAnnotatedRecordDecls.emplace_back(DelayedAnnotatedRecordDeclInfo{selected, CTSD, typedefNameDecl});
801 }
802 }
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}
SVector< double, 2 > v
Definition: Dict.h:5
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:606
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:533
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:520
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
Namespace for new ROOT classes and functions.
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:821
static constexpr double L
constexpr Double_t E()
Base of natural log:
Definition: TMath.h:97