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"
20 #include "cling/Interpreter/Interpreter.h"
21 #include "llvm/Support/Path.h"
32 class RPredicateIsSameNamespace
35 clang::NamespaceDecl *fTarget;
37 RPredicateIsSameNamespace(clang::NamespaceDecl *target) : fTarget(target) {}
39 bool operator()(
const RScanner::AnnotatedNamespaceDecl& element)
41 return (fTarget == element);
46 inline static bool IsElementPresent(
const std::vector<T> &v,
const T &el){
47 return std::find(v.begin(),v.end(),el) != v.end();
51 inline static bool IsElementPresent(
const std::vector<const T*> &v, T *el){
52 return std::find(v.begin(),v.end(),el) != v.end();
58 using namespace clang;
60 extern cling::Interpreter *gInterp;
62 const char* RScanner::fgClangDeclKey =
"ClangDecl";
63 const char* RScanner::fgClangFuncKey =
"ClangFunc";
65 int RScanner::fgAnonymousClassCounter = 0;
66 int RScanner::fgBadClassCounter = 0;
67 int RScanner::fgAnonymousEnumCounter = 0;
69 std::map <clang::Decl*, std::string> RScanner::fgAnonymousClassMap;
70 std::map <clang::Decl*, std::string> RScanner::fgAnonymousEnumMap;
76 RScanner::RScanner (SelectionRules &rules,
78 const cling::Interpreter &interpret,
79 ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
80 unsigned int verbose ) :
81 fVerboseLevel(verbose),
83 fInterpreter(interpret),
84 fRecordDeclCallback(0),
86 fSelectionRules(rules),
91 fSelectionRules.FillCache();
93 for (
int i = 0; i <= fgDeclLast; i ++)
94 fDeclTable [i] =
false;
96 for (
int i = 0; i <= fgTypeLast; i ++)
97 fTypeTable [i] =
false;
104 RScanner::~RScanner ()
121 bool RScanner::shouldVisitDecl(clang::NamedDecl *D)
123 if (
auto M = D->getOwningModule()) {
124 return fInterpreter.getSema().isModuleVisible(M);
131 inline void* ToDeclProp(clang::Decl* item)
139 inline size_t APIntToSize(
const llvm::APInt& num)
141 return *num.getRawData();
146 inline long APIntToLong(
const llvm::APInt& num)
148 return *num.getRawData();
153 inline std::string APIntToStr(
const llvm::APInt& num)
155 return num.toString(10,
true);
160 inline std::string IntToStr(
int num)
162 std::string txt =
"";
169 inline std::string IntToStd(
int num)
171 std::ostringstream stream;
178 inline std::string Message(
const std::string &msg,
const std::string &location)
180 std::string loc = location;
185 return loc +
" " + msg;
190 void RScanner::ShowInfo(
const std::string &msg,
const std::string &location)
const
192 const std::string message = Message(msg, location);
193 std::cout << message << std::endl;
198 void RScanner::ShowWarning(
const std::string &msg,
const std::string &location)
const
200 const std::string message = Message(msg, location);
201 std::cout << message << std::endl;
206 void RScanner::ShowError(
const std::string &msg,
const std::string &location)
const
208 const std::string message = Message(msg, location);
209 std::cout << message << std::endl;
214 void RScanner::ShowTemplateInfo(
const std::string &msg,
const std::string &location)
const
216 std::string loc = location;
218 loc = GetLocation (fLastDecl);
219 ShowWarning(msg, loc);
224 std::string RScanner::GetSrcLocation(clang::SourceLocation L)
const
226 std::string location =
"";
227 llvm::raw_string_ostream stream(location);
228 L.print(stream, *fSourceManager);
234 std::string RScanner::GetLocation(clang::Decl* D)
const
242 std::string location =
"";
243 llvm::raw_string_ostream stream(location);
244 D->getLocation().print(stream, *fSourceManager);
251 std::string RScanner::GetName(clang::Decl* D)
const
253 std::string name =
"";
256 if (clang::NamedDecl* ND = dyn_cast <clang::NamedDecl> (D)) {
257 name = ND->getQualifiedNameAsString();
265 inline std::string AddSpace(
const std::string &txt)
275 void RScanner::DeclInfo(clang::Decl* D)
const
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);
286 void RScanner::UnknownDecl(clang::Decl* D,
const std::string &txt)
const
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);
297 void RScanner::UnexpectedDecl(clang::Decl* D,
const std::string &txt)
const
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);
308 void RScanner::UnsupportedDecl(clang::Decl* D,
const std::string &txt)
const
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);
319 void RScanner::UnimportantDecl(clang::Decl* D,
const std::string &txt)
const
326 void RScanner::UnimplementedDecl(clang::Decl* D,
const std::string &txt)
328 clang::Decl::Kind k = D->getKind();
331 if (k <= fgDeclLast) {
335 fDeclTable [k] =
true;
340 std::string location = GetLocation(D);
341 std::string kind = D->getDeclKindName();
342 std::string name = GetName(D);
343 std::string msg =
"Unimplemented ";
345 msg +=
"declaration";
353 ShowWarning(msg,location);
359 void RScanner::UnknownType(clang::QualType qual_type)
const
361 std::string location = GetLocation(fLastDecl);
362 std::string kind = qual_type.getTypePtr()->getTypeClassName();
363 ShowWarning(
"Unknown " + kind +
" type " + qual_type.getAsString(), location);
368 void RScanner::UnsupportedType(clang::QualType qual_type)
const
370 std::string location = GetLocation(fLastDecl);
371 std::string kind = qual_type.getTypePtr()->getTypeClassName();
372 ShowWarning(
"Unsupported " + kind +
" type " + qual_type.getAsString(), location);
377 std::string RScanner::GetEnumName(clang::EnumDecl* D)
const
379 std::string enum_name = D->getQualifiedNameAsString();
381 if (! D->getDeclName ()) {
382 if (fgAnonymousEnumMap.find (D) != fgAnonymousEnumMap.end())
385 enum_name = fgAnonymousEnumMap [D];
389 fgAnonymousEnumCounter ++;
390 enum_name =
"_ANONYMOUS_ENUM_" + IntToStd(fgAnonymousEnumCounter) +
"_";
391 fgAnonymousEnumMap [D] = enum_name;
401 std::string RScanner::ExprToStr(clang::Expr* expr)
const
403 clang::LangOptions lang_opts;
404 clang::PrintingPolicy print_opts(lang_opts);
406 std::string text =
"";
407 llvm::raw_string_ostream stream(text);
409 expr->printPretty(stream, NULL, print_opts);
416 std::string RScanner::ConvTemplateName(clang::TemplateName& N)
const
418 clang::LangOptions lang_opts;
419 clang::PrintingPolicy print_opts(lang_opts);
421 std::string text =
"";
422 llvm::raw_string_ostream stream(text);
424 N.print(stream, print_opts);
431 std::string RScanner::FuncParameters(clang::FunctionDecl* D)
const
433 std::string result =
"";
435 for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
436 clang::ParmVarDecl* P = *I;
441 std::string type = P->getType().getAsString();
442 std::string name = P->getNameAsString();
444 result += type +
" " + name;
448 std::string init_value = ExprToStr(P->getDefaultArg());
449 result +=
"=" + init_value;
458 std::string RScanner::FuncParameterList(clang::FunctionDecl* D)
const
460 std::string result =
"";
462 for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
463 clang::ParmVarDecl* P = *I;
468 std::string type = P->getType().getAsString();
472 return "(" + result +
")";
478 bool RScanner::VisitNamespaceDecl(clang::NamespaceDecl* N)
481 if (fScanType == EScanType::kOnePCM)
484 if (!shouldVisitDecl(N))
489 if((N && N->isImplicit()) || !N){
495 const ClassSelectionRule *selected = fSelectionRules.IsDeclSelected(N);
498 clang::DeclContext* primary_ctxt = N->getPrimaryContext();
499 clang::NamespaceDecl* primary = llvm::dyn_cast<clang::NamespaceDecl>(primary_ctxt);
501 RPredicateIsSameNamespace pred(primary);
502 if ( find_if(fSelectedNamespaces.begin(),fSelectedNamespaces.end(),pred) == fSelectedNamespaces.end() ) {
505 if (fVerboseLevel > 0) {
506 std::string qual_name;
507 GetDeclQualName(N,qual_name);
509 std::cout<<
"\tSelected namespace -> " << qual_name <<
"\n";
511 fSelectedNamespaces.push_back(AnnotatedNamespaceDecl(primary,selected->GetIndex(),selected->RequestOnlyTClass()));
521 bool RScanner::VisitRecordDecl(clang::RecordDecl* D)
523 if (!shouldVisitDecl(D))
527 return TreatRecordDeclOrTypedefNameDecl(D);
534 int RScanner::AddAnnotatedRecordDecl(
const ClassSelectionRule* selected,
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)
542 bool has_attr_name = selected->HasAttributeName();
544 if (recordDecl->isUnion() &&
545 0 != ROOT::TMetaUtils::GetClassVersion(recordDecl,fInterpreter)) {
546 std::string normName;
547 TMetaUtils::GetNormalizedName(normName,
548 recordDecl->getASTContext().getTypeDeclType(recordDecl),
551 ROOT::TMetaUtils::Error(0,
"Union %s has been selected for I/O. This is not supported. Interactive usage of unions is supported, as all C++ entities, without the need of dictionaries.\n",normName.c_str());
556 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
560 selected->RequestStreamerInfo(),
561 selected->RequestNoStreamer(),
562 selected->RequestNoInputOperator(),
563 selected->RequestOnlyTClass(),
564 selected->RequestedVersionNumber(),
568 fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
570 selected->RequestStreamerInfo(),
571 selected->RequestNoStreamer(),
572 selected->RequestNoInputOperator(),
573 selected->RequestOnlyTClass(),
574 selected->RequestedVersionNumber(),
579 if (fVerboseLevel > 0) {
580 std::string qual_name;
581 GetDeclQualName(recordDecl,qual_name);
582 std::string normName;
583 TMetaUtils::GetNormalizedName(normName,
584 recordDecl->getASTContext().getTypeDeclType(recordDecl),
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 +
") ";
594 std::cout <<
"Selected class "
607 bool RScanner::TreatRecordDeclOrTypedefNameDecl(clang::TypeDecl* typeDecl)
620 const clang::RecordDecl* recordDecl = clang::dyn_cast<clang::RecordDecl>(typeDecl);
621 const clang::TypedefNameDecl* typedefNameDecl = clang::dyn_cast<clang::TypedefNameDecl>(typeDecl);
624 if (!recordDecl && typedefNameDecl) {
625 recordDecl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(typedefNameDecl->getUnderlyingType());
630 ROOT::TMetaUtils::Warning(
"RScanner::TreatRecordDeclOrTypeNameDecl",
631 "Could not cast typeDecl either to RecordDecl or could not get RecordDecl underneath typedef.\n");
636 if (!recordDecl->getIdentifier())
640 if (recordDecl->isDependentType())
643 if (fScanType == EScanType::kOnePCM && ROOT::TMetaUtils::IsStdClass(*recordDecl))
649 if (fRecordDeclCallback) {
657 fRecordDeclCallback(recordDecl);
661 if(recordDecl->isImplicit() || !recordDecl->isCompleteDefinition()) {
666 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl);
667 if (cxxdecl && cxxdecl->getDescribedClassTemplate ()) {
671 const ClassSelectionRule *selectedFromTypedef = typedefNameDecl ? fSelectionRules.IsDeclSelected(typedefNameDecl) : 0;
673 const ClassSelectionRule *selectedFromRecDecl = fSelectionRules.IsDeclSelected(recordDecl);
675 const ClassSelectionRule *selected = typedefNameDecl ? selectedFromTypedef : selectedFromRecDecl;
677 if (! selected)
return true;
680 bool excludedFromRecDecl =
false;
681 if ( selectedFromRecDecl )
682 excludedFromRecDecl = selectedFromRecDecl->GetSelected() == BaseSelectionRule::kNo;
684 if (selected->GetSelected() != BaseSelectionRule::kYes || excludedFromRecDecl)
688 if (selectedFromTypedef){
689 if (!IsElementPresent(fSelectedTypedefs, typedefNameDecl))
690 fSelectedTypedefs.push_back(typedefNameDecl);
692 if (!fSelectionRules.IsSelectionXMLFile())
return true;
695 if (fSelectionRules.IsSelectionXMLFile() && selected->IsFromTypedef()) {
696 if (!IsElementPresent(fSelectedTypedefs, typedefNameDecl))
697 fSelectedTypedefs.push_back(typedefNameDecl);
702 ROOT::TMetaUtils::Info(
"RScanner::TreatRecordDeclOrTypedefNameDecl",
703 "Typedef is selected %s.\n", typedefNameDecl->getNameAsString().c_str());
711 if (recordDecl->getName() ==
"pair") {
712 const clang::NamespaceDecl *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(recordDecl->getDeclContext());
714 ROOT::TMetaUtils::Error(
"RScanner::TreatRecordDeclOrTypedefNameDecl",
715 "Cannot convert context of RecordDecl called pair into a namespace.\n");
718 const clang::NamespaceDecl *nsCanonical = nsDecl->getCanonicalDecl();
719 if (nsCanonical && nsCanonical == fInterpreter.getCI()->getSema().getStdNamespace()) {
720 if (selected->HasAttributeFileName() || selected->HasAttributeFilePattern()) {
728 bool rcrdDeclNotAlreadySelected = fselectedRecordDecls.insert((RecordDecl*)recordDecl->getCanonicalDecl()).second;
729 if (!fFirstPass && !rcrdDeclNotAlreadySelected) {
731 auto declSelRuleMapIt = fDeclSelRuleMap.find(recordDecl->getCanonicalDecl());
732 if (declSelRuleMapIt != fDeclSelRuleMap.end() &&
733 declSelRuleMapIt->second != selected) {
734 std::string normName;
735 TMetaUtils::GetNormalizedName(normName,
736 recordDecl->getASTContext().getTypeDeclType(recordDecl),
740 auto previouslyMatchingRule = (
const ClassSelectionRule*)declSelRuleMapIt->second;
741 int previouslineno = previouslyMatchingRule->GetLineNumber();
743 std::string cleanFileName = llvm::sys::path::filename(selected->GetSelFileName());
744 auto lineno = selected->GetLineNumber();
745 auto rulesAreCompatible = SelectionRulesUtils::areEqual<ClassSelectionRule>(selected, previouslyMatchingRule,
true );
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());
760 fDeclSelRuleMap[recordDecl->getCanonicalDecl()] = selected;
762 if (!rcrdDeclNotAlreadySelected || fFirstPass)
769 if (recordDecl->getAccess() == AS_private || recordDecl->getAccess() == AS_protected) {
771 auto isFileSelection = selected->HasAttributeFileName() &&
772 selected->HasAttributePattern() &&
773 "*" == selected->GetAttributePattern();
774 if (!isFileSelection) {
775 std::string normName;
776 TMetaUtils::GetNormalizedName(normName,
777 recordDecl->getASTContext().getTypeDeclType(recordDecl),
780 auto msg =
"Class or struct %s was selected but its dictionary cannot be generated: "
781 "this is a private or protected class and this is not supported. No direct "
782 "I/O operation of %s instances will be possible.\n";
783 ROOT::TMetaUtils::Warning(0,msg,normName.c_str(),normName.c_str());
792 auto req_type = selected->GetRequestedType();
793 clang::QualType thisType(req_type, 0);
794 std::string attr_name = selected->GetAttributeName().c_str();
796 auto sc = AddAnnotatedRecordDecl(selected, req_type, recordDecl, attr_name, typedefNameDecl);
801 if (
auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
802 fDelayedAnnotatedRecordDecls.emplace_back(DelayedAnnotatedRecordDeclInfo{selected, CTSD, typedefNameDecl});
808 void RScanner::AddDelayedAnnotatedRecordDecls()
810 for (
auto &&info: fDelayedAnnotatedRecordDecls) {
811 const clang::Type *thisType = info.fSelected->GetRequestedType();
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;
819 if (typeForIO.getTypePtr() == thisType)
821 if (
auto recordDeclForIO = typeForIO->getAsCXXRecordDecl()) {
822 const auto canRecordDeclForIO = recordDeclForIO->getCanonicalDecl();
823 if (!fselectedRecordDecls.insert(canRecordDeclForIO).second)
825 recordDecl = canRecordDeclForIO;
826 fDeclSelRuleMap[recordDecl] = info.fSelected;
827 thisType = typeForIO.getTypePtr();
830 AddAnnotatedRecordDecl(info.fSelected, thisType, recordDecl,
831 nameTypeForIO.first, info.fTypedefNameDecl, 1000);
842 bool RScanner::VisitTypedefNameDecl(clang::TypedefNameDecl* D)
844 if (fScanType == EScanType::kOnePCM)
847 if (!shouldVisitDecl(D))
850 const clang::DeclContext *ctx = D->getDeclContext();
854 const clang::NamedDecl *parent = llvm::dyn_cast<clang::NamedDecl> (ctx);
855 isInStd = parent && 0 == parent->getQualifiedNameAsString().compare(0,5,
"std::");
858 if (ROOT::TMetaUtils::GetUnderlyingRecordDecl(D->getUnderlyingType()) &&
860 TreatRecordDeclOrTypedefNameDecl(D);
868 bool RScanner::VisitEnumDecl(clang::EnumDecl* D)
870 if (fScanType == EScanType::kOnePCM)
873 if (!shouldVisitDecl(D))
876 if(fSelectionRules.IsDeclSelected(D) &&
877 !IsElementPresent(fSelectedEnums, D)){
878 fSelectedEnums.push_back(D);
886 bool RScanner::VisitVarDecl(clang::VarDecl* D)
888 if (!D->hasGlobalStorage() ||
889 fScanType == EScanType::kOnePCM)
892 if (!shouldVisitDecl(D))
895 if(fSelectionRules.IsDeclSelected(D)){
896 fSelectedVariables.push_back(D);
905 bool RScanner::VisitFieldDecl(clang::FieldDecl* D)
927 bool RScanner::VisitFunctionDecl(clang::FunctionDecl* D)
929 if (fScanType == EScanType::kOnePCM)
932 if (!shouldVisitDecl(D))
935 if(clang::FunctionDecl::TemplatedKind::TK_FunctionTemplate == D->getTemplatedKind())
938 if(fSelectionRules.IsDeclSelected(D)){
939 fSelectedFunctions.push_back(D);
947 bool RScanner::TraverseDeclContextHelper(DeclContext *DC)
954 clang::Decl* D = dyn_cast<clang::Decl>(DC);
956 if (D && D->isImplicit()){
960 if (fScanType == EScanType::kOnePCM){
961 const clang::NamespaceDecl *parent = llvm::dyn_cast<clang::NamespaceDecl> (DC);
962 if (parent && 0 == parent->getQualifiedNameAsString().compare(0,5,
"std::"))
966 for (DeclContext::decl_iterator Child = DC->decls_begin(), ChildEnd = DC->decls_end();
967 ret && (Child != ChildEnd); ++Child) {
968 ret=TraverseDecl(*Child);
977 bool RScanner::GetDeclName(clang::Decl* D, std::string& name)
const
979 clang::NamedDecl* N = dyn_cast<clang::NamedDecl> (D);
982 name = N->getNameAsString();
993 bool RScanner::GetDeclQualName(
const clang::Decl* D, std::string& qual_name)
995 auto N = dyn_cast<
const clang::NamedDecl> (D);
998 llvm::raw_string_ostream stream(qual_name);
999 N->getNameForDiagnostic(stream,D->getASTContext().getPrintingPolicy(),
true);
1009 bool RScanner::GetFunctionPrototype(clang::Decl* D, std::string& prototype)
const {
1014 clang::FunctionDecl* F = dyn_cast<clang::FunctionDecl> (D);
1019 for (clang::FunctionDecl::param_iterator I = F->param_begin(), E = F->param_end(); I != E; ++I) {
1020 clang::ParmVarDecl* P = *I;
1022 if (prototype !=
"")
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);
1034 prototype =
"(" + prototype +
")";
1038 ShowWarning(
"can't convert Decl to FunctionDecl",
"");
1045 void RScanner::Scan(
const clang::ASTContext &C)
1047 fSourceManager = &C.getSourceManager();
1051 if (fVerboseLevel > 0 && fSelectionRules.GetHasFileNameRule()) {
1052 std::cout<<
"File name detected"<<std::endl;
1055 if (fScanType == EScanType::kTwoPasses)
1056 TraverseDecl(C.getTranslationUnitDecl());
1059 fselectedRecordDecls.clear();
1060 fSelectedEnums.clear();
1061 fSelectedTypedefs.clear();
1062 fSelectedVariables.clear();
1063 fSelectedFunctions.clear();
1064 TraverseDecl(C.getTranslationUnitDecl());
1069 AddDelayedAnnotatedRecordDecls();
1076 RScanner::DeclCallback RScanner::SetRecordDeclCallback(RScanner::DeclCallback callback)
1078 DeclCallback old = fRecordDeclCallback;
1079 fRecordDeclCallback = callback;