34#include "llvm/Support/raw_ostream.h"
36#include "clang/AST/ASTContext.h"
38#include "clang/Frontend/CompilerInstance.h"
40#include "clang/Lex/Preprocessor.h"
41#include "clang/Lex/Pragma.h"
43#include "cling/Interpreter/CIFactory.h"
44#include "cling/Interpreter/Interpreter.h"
104 fLine(1), fCount(0), fSelectionRules(nullptr), fIOConstructorTypesPtr(&IOConstructorTypes), fInterp(interp)
129 const std::string& identifier,
131 bool request_only_tclass,
136 ROOT::TMetaUtils::Info(
"LinkdefReader::AddRule",
"Ruletype is %s with the identifier %s\n", ruletype.c_str(), identifier.c_str());
144 if (identifier ==
"globals" || identifier ==
"global") {
181 }
else if (identifier ==
"functions" || identifier ==
"function") {
193 }
else if (identifier ==
"classes" || identifier ==
"namespaces" ||
194 identifier ==
"class" || identifier ==
"namespace") {
203 csr.SetAttributeValue(
"pattern",
"*");
213 csr.SetAttributeValue(
"pattern",
"*");
222 }
else if (identifier ==
"typedefs" || identifier ==
"typedef") {
238 std::string localIdentifier(identifier);
239 if (localIdentifier.length() && localIdentifier[0] ==
'"' && localIdentifier[localIdentifier.length() - 1] ==
'"') {
240 localIdentifier = localIdentifier.substr(1, localIdentifier.length() - 2);
265 csr.SetAttributeValue(
"pattern",
"*");
268 csr.SetAttributeValue(
"file_name", localIdentifier);
277 csr.SetRequestStreamerInfo(
true);
286 std::string localIdentifier(identifier);
287 bool name_or_proto =
false;
294 if (localIdentifier.at(localIdentifier.length() - 1) ==
'*') fsr.
SetAttributeValue(
"pattern", localIdentifier);
297 int pos = localIdentifier.find(
"(*)");
323 std::string localIdentifier(identifier);
358 std::string localIdentifier(identifier);
361 if (request_only_tclass) {
364 int len = localIdentifier.length();
366 const std::string protStr(
"+protected");
367 const std::string privStr(
"+private");
369 if (localIdentifier.compare(0, protStr.length(), protStr) == 0) {
371 localIdentifier.erase(0, protStr.length() + 1);
372 len = localIdentifier.length();
373 }
else if (localIdentifier.compare(0, privStr.length(), privStr) == 0) {
375 localIdentifier.erase(0, privStr.length() + 1);
376 len = localIdentifier.length();
383 while (!ending && where <
len) {
384 char last = localIdentifier.at(
len - where);
414 std::cerr <<
"Warning: " << localIdentifier <<
" option + mutual exclusive with -, + prevails\n";
418 localIdentifier.erase(
len - (where - 2));
420 localIdentifier.erase(
len - (where - 1));
427 if (localIdentifier ==
"*") {
440 if (localIdentifier ==
"*") {
502 int pos = rule_token.find(
"*");
503 if (pos > -1)
return true;
519 int pos1, pos1_1, pos2, pos2_1;
521 pos1 =
proto.find_first_of(
"(");
522 pos1_1 =
proto.find_last_of(
"(");
524 if (pos1 != pos1_1) {
525 std::cout <<
"Error at line " <<
fLine <<
" - too many ( in function prototype!" << std::endl;
529 pos2 =
proto.find_first_of(
")");
530 pos2_1 =
proto.find_last_of(
")");
532 if (pos2 != pos2_1) {
533 std::cout <<
"Error at line " <<
fLine <<
" - too many ) in function prototype!" << std::endl;
539 std::cout <<
"Error at line " <<
fLine <<
" - missing ) in function prototype" << std::endl;
543 std::cout <<
"Error at line " <<
fLine <<
" - wrong order of ( and ) in function prototype" << std::endl;
550 pos3 =
proto.find(
" ", pos3);
552 proto.erase(pos3, 1);
559 std::cout <<
"Error at line " <<
fLine <<
" - missing ( in function prototype" << std::endl;
575 int pos1 = -1, pos2 = -1;
576 int open_br = 0, close_br = 0;
578 pos = pattern.find(
" ", pos + 1);
579 pos1 = pattern.find(
"<", pos1 + 1);
580 pos2 = pattern.find(
">", pos2 + 1);
582 if ((pos < 0) && (pos1 < 0) && (pos2 < 0))
break;
584 if (pos1 > -1) ++open_br;
585 if (pos2 > -1) ++close_br;
587 if (pos < 0)
continue;
593 if (pos > 0) before = pattern.at(pos - 1);
594 if (pos < (
int)(pattern.length() - 1)) after = pattern.at(pos + 1);
618 std::cout <<
"Error at line " <<
fLine - 1 <<
" - extra space" << std::endl;
621 pattern.erase(pos, 1);
624 if (open_br != close_br) {
625 std::cout <<
"Error at line " <<
fLine <<
" - number of < doesn't match number of >" << std::endl;
628 pattern =
"operator*(*" + pattern +
"*)";
641 void Error(
const char *message,
const clang::Token &tok,
642 const clang::Preprocessor& PP,
bool source =
true) {
644 std::cerr << message <<
" at ";
645 const clang::SourceManager &SM = PP.getSourceManager();
646 tok.getLocation().dump(SM);
649 std::cerr << SM.getCharacterData(tok.getLocation());
655 clang::Preprocessor &PP,
673 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
674 Error(
"Error: the 'options' keyword must be followed by an '='", tok, PP);
679 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
680 if (!tok.getIdentifierInfo()) {
681 Error(
"Error: Malformed version option.", tok, PP);
682 }
else if (tok.getIdentifierInfo()->getName() ==
"nomap") {
685 }
else if (tok.getIdentifierInfo()->getName() ==
"nostreamer") options.
fNoStreamer = 1;
686 else if (tok.getIdentifierInfo()->getName() ==
"noinputoper") options.
fNoInputOper = 1;
688 else if (tok.getIdentifierInfo()->getName() ==
"rntupleSplit") {
689 clang::Token start = tok;
691 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
692 Error(
"Error: missing left parenthesis after rntupleSplit.", start, PP);
696 clang::Token boolval = tok;
697 if (tok.isNot(clang::tok::eod))
699 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
700 Error(
"Error: missing right parenthesis after rntupleSplit.", start, PP);
703 if (!boolval.getIdentifierInfo()) {
704 Error(
"Error: Malformed rntupleSplit option (either 'true' or 'false').", boolval, PP);
707 if (boolval.getIdentifierInfo()->getName() ==
"true") {
709 Error(
"Error: Can only specify a single rntuple option "
710 "(either rntupleSplit(true) or rntupleSplit(false))",
715 }
else if (boolval.getIdentifierInfo()->getName() ==
"false") {
717 Error(
"Error: Can only specify a single rntuple option "
718 "(either rntupleSplit(true) or rntupleSplit(false))",
724 Error(
"Error: Malformed rntupleSplit option (either 'true' or 'false').", boolval, PP);
726 }
else if (tok.getIdentifierInfo()->getName() ==
"stub") {
729 }
else if (tok.getIdentifierInfo()->getName() ==
"version") {
730 clang::Token start = tok;
732 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
733 Error(
"Error: missing left parenthesis after version.", start, PP);
737 clang::Token number = tok;
738 if (tok.isNot(clang::tok::eod)) PP.Lex(tok);
739 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
740 Error(
"Error: missing right parenthesis after version.", start, PP);
743 if (!number.isLiteral()) {
744 std::cerr <<
"Error: Malformed version option, the value is not a non-negative number!";
747 std::string verStr(number.getLiteralData(), number.getLength());
748 bool noDigit =
false;
749 for (std::string::size_type i = 0; i < verStr.size(); ++i)
750 if (!isdigit(verStr[i])) noDigit =
true;
753 std::cerr <<
"Error: Malformed version option! \"" << verStr <<
"\" is not a non-negative number!";
754 Error(
"", start, PP);
758 Error(
"Warning: ignoring unknown #pragma link option=", tok, PP);
761 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
780 clang::PragmaIntroducer Introducer,
781 clang::Token &tok)
override {
786 if (Introducer.Kind != clang::PIK_HashPragma)
return;
787 if (!tok.getIdentifierInfo())
return;
788 if (tok.getIdentifierInfo()->getName() !=
"extra_include")
return;
794 if (tok.is(clang::tok::eod)) {
795 Error(
"Warning - lonely pragma statement: ", tok, PP);
798 const clang::SourceManager &SM = PP.getSourceManager();
799 const char *start = SM.getCharacterData(tok.getLocation());
802 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
806 if (tok.isNot(clang::tok::semi)) {
807 Error(
"Error: missing ; at end of rule", tok, PP,
false);
810 if (end.is(clang::tok::unknown)) {
811 Error(
"Error: Unknown token!", tok, PP);
813 llvm::StringRef include(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
830 clang::PragmaIntroducer Introducer,
831 clang::Token &tok)
override {
836 if (Introducer.Kind != clang::PIK_HashPragma)
return;
837 if (!tok.getIdentifierInfo())
return;
838 if (tok.getIdentifierInfo()->getName() !=
"read")
return;
844 if (tok.is(clang::tok::eod)) {
845 Error(
"Warning - lonely pragma statement: ", tok, PP);
848 const clang::SourceManager& SM = PP.getSourceManager();
849 const char *start = SM.getCharacterData(tok.getLocation());
852 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
861 if (end.is(clang::tok::unknown)) {
862 Error(
"Error: unknown token", tok, PP);
864 llvm::StringRef rule_text(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
866 std::string error_string;
868 if (!error_string.empty())
869 std::cerr << error_string;
890 clang::PragmaIntroducer Introducer,
891 clang::Token &tok)
override {
896 if (Introducer.Kind != clang::PIK_HashPragma)
return;
897 if (!tok.getIdentifierInfo())
return;
898 if (tok.getIdentifierInfo()->getName() !=
"link")
return;
904 if (tok.is(clang::tok::eod)) {
905 Error(
"Warning - lonely pragma statement: ", tok, PP);
909 if (tok.isAnyIdentifier()) {
910 if ((tok.getIdentifierInfo()->getName() ==
"off")) {
912 }
else if ((tok.getIdentifierInfo()->getName() ==
"C")) {
915 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
916 Error(
"Error ++ expected after '#pragma link C' at ", tok, PP);
920 Error(
"Error #pragma link should be followed by off or C", tok, PP);
924 Error(
"Error bad #pragma format. ", tok, PP);
929 if (tok.is(clang::tok::eod)) {
930 Error(
"Error no arguments after #pragma link C++/off: ", tok, PP);
933 auto identifier = tok.getIdentifierInfo();
934 if (identifier ==
nullptr) {
935 if (linkOn)
Error(
"Error #pragma link C++ should be followed by identifier", tok, PP);
936 else Error(
"Error #pragma link off should be followed by identifier", tok, PP);
940 llvm::StringRef
type = identifier->getName();
942 std::unique_ptr<LinkdefReader::Options> options;
943 if (
type ==
"options" ||
type ==
"option") {
948 if (tok.getIdentifierInfo())
type = tok.getIdentifierInfo()->getName();
951 PP.LexUnexpandedToken(tok);
952 const clang::SourceManager &SM = PP.getSourceManager();
953 const char *start = SM.getCharacterData(tok.getLocation());
956 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
960 PP.LexUnexpandedToken(tok);
963 if (tok.isNot(clang::tok::semi)) {
964 Error(
"Error: missing ; at end of rule", tok, PP,
false);
968 if (end.is(clang::tok::unknown)) {
973 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
975 if (!
fOwner.
AddRule(
type.str(), identifier.str(), linkOn,
false, options.get())) {
996 clang::PragmaIntroducer Introducer,
997 clang::Token &tok)
override {
1002 if (Introducer.Kind != clang::PIK_HashPragma)
return;
1003 if (!tok.getIdentifierInfo())
return;
1004 if (tok.getIdentifierInfo()->getName() !=
"create")
return;
1010 if (tok.is(clang::tok::eod)) {
1011 Error(
"Warning - lonely pragma statement: ", tok, PP);
1014 if ((tok.getIdentifierInfo()->getName() !=
"TClass")) {
1015 Error(
"Error: currently only supporting TClass after '#pragma create':", tok, PP);
1020 const clang::SourceManager &SM = PP.getSourceManager();
1021 const char *start = SM.getCharacterData(tok.getLocation());
1022 clang::Token end = tok;
1023 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
1028 if (tok.isNot(clang::tok::semi)) {
1029 Error(
"Error: missing ; at end of rule", tok, PP,
false);
1033 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
1035 if (!
fOwner.
AddRule(
"class", identifier.str(),
true,
true)) {
1054 std::vector<const char *> parserArgsC;
1055 for (
size_t i = 0,
n = parserArgs.size(); i <
n; ++i) {
1056 parserArgsC.push_back(parserArgs[i].c_str());
1060 std::unique_ptr<llvm::MemoryBuffer> memBuf = llvm::MemoryBuffer::getMemBuffer(code,
"CLING #pragma extraction");
1061 clang::CompilerInstance *pragmaCI = cling::CIFactory::createCI(std::move(memBuf), parserArgsC.size(),
1062 &parserArgsC[0], llvmdir,
nullptr ,
1065 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1066 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1067 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1075 PP.AddPragmaHandler(&pragmaLinkCollector);
1076 PP.AddPragmaHandler(&pragmaCreateCollector);
1077 PP.AddPragmaHandler(&pragmaExtraInclude);
1078 PP.AddPragmaHandler(&pragmaIoReadInclude);
1081 PP.EnterMainSourceFile();
1085 }
while (tok.isNot(clang::tok::eof));
1088 return 0 == DClient.getNumErrors();
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 UChar_t len
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
void SetAttributeValue(const std::string &attributeName, const std::string &attributeValue)
void SetSelected(ESelect sel)
bool RequestNoStreamer() const
void SetRequestNoInputOperator(bool excl)
bool RequestStreamerInfo() const
void SetRequestProtected(bool val)
void SetRequestedRNTupleSplitMode(int splitMode)
void SetRequestedVersionNumber(int version)
void SetRequestPrivate(bool val)
void SetRequestNoStreamer(bool noStreamer)
void SetRequestOnlyTClass(bool val)
void SetRequestStreamerInfo(bool needStreamerInfo)
bool ProcessOptions(LinkdefReader::Options &options, clang::Preprocessor &PP, clang::Token &tok)
LinkdefReaderPragmaHandler(const char *which, LinkdefReader &owner)
void Error(const char *message, const clang::Token &tok, const clang::Preprocessor &PP, bool source=true)
bool ProcessOperators(std::string &pattern)
bool LoadIncludes(std::string &extraInclude)
SelectionRules * fSelectionRules
LinkdefReader(cling::Interpreter &interp, ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes)
bool ProcessFunctionPrototype(std::string &proto, bool &name)
static std::map< std::string, ECppNames > fgMapCppNames
cling::Interpreter & fInterp
bool IsPatternRule(const std::string &rule_token)
bool AddInclude(const std::string &include)
bool Parse(SelectionRules &sr, llvm::StringRef code, const std::vector< std::string > &parserArgs, const char *llvmdir)
static std::map< std::string, EPragmaNames > fgMapPragmaNames
static void PopulatePragmaMap()
static void PopulateCppMap()
bool AddRule(const std::string &ruletype, const std::string &identifier, bool linkOn, bool requestOnlyTClass, Options *option=nullptr)
ROOT::TMetaUtils::RConstructorTypes * fIOConstructorTypesPtr
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
PragmaCreateCollector(LinkdefReader &owner)
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
PragmaIoReadInclude(LinkdefReader &owner)
PragmaLinkCollector(LinkdefReader &owner)
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
The class representing the collection of selection rules.
void AddVariableSelectionRule(const VariableSelectionRule &varSel)
void AddClassSelectionRule(const ClassSelectionRule &classSel)
bool GetHasFileNameRule() const
void AddEnumSelectionRule(const EnumSelectionRule &enumSel)
void AddFunctionSelectionRule(const FunctionSelectionRule &funcSel)
void SetHasFileNameRule(bool file_rule)
void ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.