35#include "llvm/Support/raw_ostream.h"
37#include "clang/AST/ASTContext.h"
39#include "clang/Frontend/CompilerInstance.h"
41#include "clang/Lex/Preprocessor.h"
42#include "clang/Lex/Pragma.h"
44#include "cling/Interpreter/CIFactory.h"
45#include "cling/Interpreter/Interpreter.h"
131 const std::string& identifier,
133 bool request_only_tclass,
138 ROOT::TMetaUtils::Info(
"LinkdefReader::AddRule",
"Ruletype is %s with the identifier %s\n", ruletype.c_str(), identifier.c_str());
146 if (identifier ==
"globals" || identifier ==
"global") {
183 }
else if (identifier ==
"functions" || identifier ==
"function") {
195 }
else if (identifier ==
"classes" || identifier ==
"namespaces" ||
196 identifier ==
"class" || identifier ==
"namespace") {
205 csr.SetAttributeValue(
"pattern",
"*");
215 csr.SetAttributeValue(
"pattern",
"*");
224 }
else if (identifier ==
"typedefs" || identifier ==
"typedef") {
240 std::string localIdentifier(identifier);
241 if (localIdentifier.length() && localIdentifier[0] ==
'"' && localIdentifier[localIdentifier.length() - 1] ==
'"') {
242 localIdentifier = localIdentifier.substr(1, localIdentifier.length() - 2);
267 csr.SetAttributeValue(
"pattern",
"*");
270 csr.SetAttributeValue(
"file_name", localIdentifier);
279 csr.SetRequestStreamerInfo(
true);
288 std::string localIdentifier(identifier);
289 bool name_or_proto =
false;
296 if (localIdentifier.at(localIdentifier.length() - 1) ==
'*') fsr.
SetAttributeValue(
"pattern", localIdentifier);
299 int pos = localIdentifier.find(
"(*)");
325 std::string localIdentifier(identifier);
360 std::string localIdentifier(identifier);
363 if (request_only_tclass) {
366 int len = localIdentifier.length();
368 const std::string protStr(
"+protected");
369 const std::string privStr(
"+private");
371 if (localIdentifier.compare(0, protStr.length(), protStr) == 0) {
373 localIdentifier.erase(0, protStr.length() + 1);
374 len = localIdentifier.length();
375 }
else if (localIdentifier.compare(0, privStr.length(), privStr) == 0) {
377 localIdentifier.erase(0, privStr.length() + 1);
378 len = localIdentifier.length();
385 while (!ending && where < len) {
386 char last = localIdentifier.at(len - where);
417 std::cerr <<
"Warning: " << localIdentifier <<
" option + mutual exclusive with -, + prevails\n";
421 localIdentifier.erase(len - (where - 2));
423 localIdentifier.erase(len - (where - 1));
430 if (localIdentifier ==
"*") {
443 if (localIdentifier ==
"*") {
505 int pos = rule_token.find(
"*");
506 if (pos > -1)
return true;
522 int pos1, pos1_1, pos2, pos2_1;
524 pos1 =
proto.find_first_of(
"(");
525 pos1_1 =
proto.find_last_of(
"(");
527 if (pos1 != pos1_1) {
528 std::cout <<
"Error at line " <<
fLine <<
" - too many ( in function prototype!" << std::endl;
532 pos2 =
proto.find_first_of(
")");
533 pos2_1 =
proto.find_last_of(
")");
535 if (pos2 != pos2_1) {
536 std::cout <<
"Error at line " <<
fLine <<
" - too many ) in function prototype!" << std::endl;
542 std::cout <<
"Error at line " <<
fLine <<
" - missing ) in function prototype" << std::endl;
546 std::cout <<
"Error at line " <<
fLine <<
" - wrong order of ( and ) in function prototype" << std::endl;
553 pos3 =
proto.find(
" ", pos3);
555 proto.erase(pos3, 1);
562 std::cout <<
"Error at line " <<
fLine <<
" - missing ( in function prototype" << std::endl;
578 int pos1 = -1, pos2 = -1;
579 int open_br = 0, close_br = 0;
581 pos = pattern.find(
" ", pos + 1);
582 pos1 = pattern.find(
"<", pos1 + 1);
583 pos2 = pattern.find(
">", pos2 + 1);
585 if ((pos < 0) && (pos1 < 0) && (pos2 < 0))
break;
587 if (pos1 > -1) ++open_br;
588 if (pos2 > -1) ++close_br;
590 if (pos < 0)
continue;
596 if (pos > 0) before = pattern.at(pos - 1);
597 if (pos < (
int)(pattern.length() - 1)) after = pattern.at(pos + 1);
621 std::cout <<
"Error at line " <<
fLine - 1 <<
" - extra space" << std::endl;
624 pattern.erase(pos, 1);
627 if (open_br != close_br) {
628 std::cout <<
"Error at line " <<
fLine <<
" - number of < doesn't match number of >" << std::endl;
631 pattern =
"operator*(*" + pattern +
"*)";
644 void Error(
const char *message,
const clang::Token &tok,
645 const clang::Preprocessor& PP,
bool source =
true) {
647 std::cerr << message <<
" at ";
648 const clang::SourceManager &SM = PP.getSourceManager();
649 tok.getLocation().dump(SM);
652 std::cerr << SM.getCharacterData(tok.getLocation());
658 clang::Preprocessor &PP,
677 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
678 Error(
"Error: the 'options' keyword must be followed by an '='", tok, PP);
683 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
684 if (!tok.getIdentifierInfo()) {
685 Error(
"Error: Malformed version option.", tok, PP);
686 }
else if (tok.getIdentifierInfo()->getName() ==
"nomap") {
689 }
else if (tok.getIdentifierInfo()->getName() ==
"nostreamer") options.
fNoStreamer = 1;
690 else if (tok.getIdentifierInfo()->getName() ==
"noinputoper") options.
fNoInputOper = 1;
692 else if (tok.getIdentifierInfo()->getName() ==
"rntupleStreamerMode") {
693 clang::Token
start = tok;
695 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
696 Error(
"Error: missing left parenthesis after rntupleStreamerMode.",
start, PP);
700 clang::Token boolval = tok;
701 if (tok.isNot(clang::tok::eod))
703 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
704 Error(
"Error: missing right parenthesis after rntupleStreamerMode.",
start, PP);
707 if (!boolval.getIdentifierInfo()) {
708 Error(
"Error: Malformed rntupleStreamerMode option (either 'true' or 'false').", boolval, PP);
711 if (boolval.getIdentifierInfo()->getName() ==
"false") {
713 Error(
"Error: Can only specify a single rntuple option "
714 "(either rntupleStreamerMode(true) or rntupleStreamerMode(false))",
719 }
else if (boolval.getIdentifierInfo()->getName() ==
"true") {
721 Error(
"Error: Can only specify a single rntuple option "
722 "(either rntupleStreamerMode(true) or rntupleStreamerMode(false))",
726 Error(
"Error: rntupleStreamerMode(true) and rntupleSoARecord are mutually exclusive", boolval, PP);
731 Error(
"Error: Malformed rntupleStreamerMode option (either 'true' or 'false').", boolval, PP);
733 }
else if (tok.getIdentifierInfo()->getName() ==
"rntupleSoARecord") {
734 clang::Token
start = tok;
736 if (tok.isNot(clang::tok::l_paren)) {
737 Error(
"Error: missing left parenthesis after rntupleSoARecord.",
start, PP);
741 clang::Token strval = tok;
742 if (tok.isNot(clang::tok::eod))
744 if (tok.isNot(clang::tok::r_paren)) {
745 Error(
"Error: missing right parenthesis after rntupleSoARecord.",
start, PP);
748 if (!strval.getIdentifierInfo() || strval.getIdentifierInfo()->getName().empty()) {
749 Error(
"Error: Malformed rntupleSoARecord option.", strval, PP);
752 Error(
"Error: rntupleStreamerMode(true) and rntupleSoARecord are mutually exclusive", strval, PP);
755 }
else if (tok.getIdentifierInfo()->getName() ==
"stub") {
758 }
else if (tok.getIdentifierInfo()->getName() ==
"version") {
759 clang::Token
start = tok;
761 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
762 Error(
"Error: missing left parenthesis after version.",
start, PP);
766 clang::Token number = tok;
767 if (tok.isNot(clang::tok::eod)) PP.Lex(tok);
768 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
769 Error(
"Error: missing right parenthesis after version.",
start, PP);
772 if (!number.isLiteral()) {
773 std::cerr <<
"Error: Malformed version option, the value is not a non-negative number!";
776 std::string verStr(number.getLiteralData(), number.getLength());
777 bool noDigit =
false;
778 for (std::string::size_type i = 0; i < verStr.size(); ++i)
779 if (!isdigit(verStr[i])) noDigit =
true;
782 std::cerr <<
"Error: Malformed version option! \"" << verStr <<
"\" is not a non-negative number!";
787 Error(
"Warning: ignoring unknown #pragma link option=", tok, PP);
790 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
809 clang::PragmaIntroducer Introducer,
810 clang::Token &tok)
override {
815 if (Introducer.Kind != clang::PIK_HashPragma)
return;
816 if (!tok.getIdentifierInfo())
return;
817 if (tok.getIdentifierInfo()->getName() !=
"extra_include")
return;
823 if (tok.is(clang::tok::eod)) {
824 Error(
"Warning - lonely pragma statement: ", tok, PP);
827 const clang::SourceManager &SM = PP.getSourceManager();
828 const char *
start = SM.getCharacterData(tok.getLocation());
831 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
835 if (tok.isNot(clang::tok::semi)) {
836 Error(
"Error: missing ; at end of rule", tok, PP,
false);
839 if (end.is(clang::tok::unknown)) {
840 Error(
"Error: Unknown token!", tok, PP);
842 llvm::StringRef include(
start, SM.getCharacterData(end.getLocation()) -
start + end.getLength());
844 if (!
fOwner.AddInclude(include.str())) {
859 clang::PragmaIntroducer Introducer,
860 clang::Token &tok)
override {
865 if (Introducer.Kind != clang::PIK_HashPragma)
return;
866 if (!tok.getIdentifierInfo())
return;
867 if (tok.getIdentifierInfo()->getName() !=
"read")
return;
873 if (tok.is(clang::tok::eod)) {
874 Error(
"Warning - lonely pragma statement: ", tok, PP);
877 const clang::SourceManager& SM = PP.getSourceManager();
878 const char *
start = SM.getCharacterData(tok.getLocation());
881 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
890 if (end.is(clang::tok::unknown)) {
891 Error(
"Error: unknown token", tok, PP);
893 llvm::StringRef rule_text(
start, SM.getCharacterData(end.getLocation()) -
start + end.getLength());
895 std::string error_string;
897 if (!error_string.empty())
898 std::cerr << error_string;
919 clang::PragmaIntroducer Introducer,
920 clang::Token &tok)
override {
925 if (Introducer.Kind != clang::PIK_HashPragma)
return;
926 if (!tok.getIdentifierInfo())
return;
927 if (tok.getIdentifierInfo()->getName() !=
"link")
return;
933 if (tok.is(clang::tok::eod)) {
934 Error(
"Warning - lonely pragma statement: ", tok, PP);
938 if (tok.isAnyIdentifier()) {
939 if ((tok.getIdentifierInfo()->getName() ==
"off")) {
941 }
else if ((tok.getIdentifierInfo()->getName() ==
"C")) {
944 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
945 Error(
"Error ++ expected after '#pragma link C' at ", tok, PP);
949 Error(
"Error #pragma link should be followed by off or C", tok, PP);
953 Error(
"Error bad #pragma format. ", tok, PP);
958 if (tok.is(clang::tok::eod)) {
959 Error(
"Error no arguments after #pragma link C++/off: ", tok, PP);
962 auto identifier = tok.getIdentifierInfo();
963 if (identifier ==
nullptr) {
964 if (linkOn)
Error(
"Error #pragma link C++ should be followed by identifier", tok, PP);
965 else Error(
"Error #pragma link off should be followed by identifier", tok, PP);
969 llvm::StringRef type = identifier->getName();
971 std::unique_ptr<LinkdefReader::Options> options;
972 if (type ==
"options" || type ==
"option") {
977 if (tok.getIdentifierInfo()) type = tok.getIdentifierInfo()->getName();
980 PP.LexUnexpandedToken(tok);
981 const clang::SourceManager &SM = PP.getSourceManager();
982 const char *
start = SM.getCharacterData(tok.getLocation());
985 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
989 PP.LexUnexpandedToken(tok);
992 if (tok.isNot(clang::tok::semi)) {
993 Error(
"Error: missing ; at end of rule", tok, PP,
false);
997 if (end.is(clang::tok::unknown)) {
998 if (!
fOwner.AddRule(type.data(),
"", linkOn,
false, options.get())) {
999 Error(type.data(), tok, PP,
false);
1002 llvm::StringRef identifier(
start, SM.getCharacterData(end.getLocation()) -
start + end.getLength());
1004 if (!
fOwner.AddRule(type.str(), identifier.str(), linkOn,
false, options.get())) {
1005 Error(type.data(), tok, PP,
false);
1025 clang::PragmaIntroducer Introducer,
1026 clang::Token &tok)
override {
1031 if (Introducer.Kind != clang::PIK_HashPragma)
return;
1032 if (!tok.getIdentifierInfo())
return;
1033 if (tok.getIdentifierInfo()->getName() !=
"create")
return;
1039 if (tok.is(clang::tok::eod)) {
1040 Error(
"Warning - lonely pragma statement: ", tok, PP);
1043 if ((tok.getIdentifierInfo()->getName() !=
"TClass")) {
1044 Error(
"Error: currently only supporting TClass after '#pragma create':", tok, PP);
1049 const clang::SourceManager &SM = PP.getSourceManager();
1050 const char *
start = SM.getCharacterData(tok.getLocation());
1051 clang::Token end = tok;
1052 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
1057 if (tok.isNot(clang::tok::semi)) {
1058 Error(
"Error: missing ; at end of rule", tok, PP,
false);
1062 llvm::StringRef identifier(
start, SM.getCharacterData(end.getLocation()) -
start + end.getLength());
1064 if (!
fOwner.AddRule(
"class", identifier.str(),
true,
true)) {
1083 std::vector<const char *> parserArgsC;
1084 for (
size_t i = 0,
n = parserArgs.size(); i <
n; ++i) {
1085 parserArgsC.push_back(parserArgs[i].c_str());
1089 std::unique_ptr<llvm::MemoryBuffer> memBuf = llvm::MemoryBuffer::getMemBuffer(code,
"CLING #pragma extraction");
1090 clang::CompilerInstance *pragmaCI =
1091 cling::CIFactory::createCI(std::move(memBuf), parserArgsC.size(), &parserArgsC[0], llvmdir,
1092 std::nullopt , {} ,
true );
1094 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1095 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1096 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1104 PP.AddPragmaHandler(&pragmaLinkCollector);
1105 PP.AddPragmaHandler(&pragmaCreateCollector);
1106 PP.AddPragmaHandler(&pragmaExtraInclude);
1107 PP.AddPragmaHandler(&pragmaIoReadInclude);
1110 PP.EnterMainSourceFile();
1114 }
while (tok.isNot(clang::tok::annot_repl_input_end));
1117 return 0 == DClient.getNumErrors();
VariableSelectionRule EnumSelectionRule
VariableSelectionRule FunctionSelectionRule
void SetAttributeValue(const std::string &attributeName, const std::string &attributeValue)
void SetSelected(ESelect sel)
void SetRequestedRNTupleSerializationMode(int serializationMode)
bool RequestNoStreamer() const
void SetRequestNoInputOperator(bool excl)
bool RequestStreamerInfo() const
void SetRequestProtected(bool val)
void SetRequestedRNTupleSoARecord(const std::string &recordName)
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
friend class PragmaLinkCollector
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)
friend class PragmaCreateCollector
bool Parse(SelectionRules &sr, llvm::StringRef code, const std::vector< std::string > &parserArgs, const char *llvmdir)
friend class PragmaExtraInclude
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 ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.
std::string fRNTupleSoARecord
int fRNTupleSerializationMode