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"
49struct LinkdefReader::Options {
50 Options() : fNoStreamer(0), fNoInputOper(0), fUseByteCount(0), fVersionNumber(-1) {}
56 int fRequestStreamerInfo;
103 fLine(1), fCount(0), fSelectionRules(nullptr), fIOConstructorTypesPtr(&IOConstructorTypes), fInterp(interp)
128 const std::string& identifier,
130 bool request_only_tclass,
131 LinkdefReader::Options *options )
135 ROOT::TMetaUtils::Info(
"LinkdefReader::AddRule",
"Ruletype is %s with the identifier %s\n", ruletype.c_str(), identifier.c_str());
143 if (identifier ==
"globals" || identifier ==
"global") {
180 }
else if (identifier ==
"functions" || identifier ==
"function") {
192 }
else if (identifier ==
"classes" || identifier ==
"namespaces" ||
193 identifier ==
"class" || identifier ==
"namespace") {
202 csr.SetAttributeValue(
"pattern",
"*");
212 csr.SetAttributeValue(
"pattern",
"*");
221 }
else if (identifier ==
"typedefs" || identifier ==
"typedef") {
237 std::string localIdentifier(identifier);
238 if (localIdentifier.length() && localIdentifier[0] ==
'"' && localIdentifier[localIdentifier.length() - 1] ==
'"') {
239 localIdentifier = localIdentifier.substr(1, localIdentifier.length() - 2);
264 csr.SetAttributeValue(
"pattern",
"*");
267 csr.SetAttributeValue(
"file_name", localIdentifier);
276 csr.SetRequestStreamerInfo(
true);
285 std::string localIdentifier(identifier);
286 bool name_or_proto =
false;
293 if (localIdentifier.at(localIdentifier.length() - 1) ==
'*') fsr.
SetAttributeValue(
"pattern", localIdentifier);
296 int pos = localIdentifier.find(
"(*)");
322 std::string localIdentifier(identifier);
357 std::string localIdentifier(identifier);
360 if (request_only_tclass) {
363 int len = localIdentifier.length();
365 const std::string protStr(
"+protected");
366 const std::string privStr(
"+private");
368 if (localIdentifier.compare(0, protStr.length(), protStr) == 0) {
370 localIdentifier.erase(0, protStr.length() + 1);
371 len = localIdentifier.length();
372 }
else if (localIdentifier.compare(0, privStr.length(), privStr) == 0) {
374 localIdentifier.erase(0, privStr.length() + 1);
375 len = localIdentifier.length();
382 while (!ending && where < len) {
383 char last = localIdentifier.at(len - where);
411 std::cerr <<
"Warning: " << localIdentifier <<
" option + mutual exclusive with -, + prevails\n";
415 localIdentifier.erase(len - (where - 2));
417 localIdentifier.erase(len - (where - 1));
424 if (localIdentifier ==
"*") {
437 if (localIdentifier ==
"*") {
499 int pos = rule_token.find(
"*");
500 if (pos > -1)
return true;
516 int pos1, pos1_1, pos2, pos2_1;
518 pos1 =
proto.find_first_of(
"(");
519 pos1_1 =
proto.find_last_of(
"(");
521 if (pos1 != pos1_1) {
522 std::cout <<
"Error at line " <<
fLine <<
" - too many ( in function prototype!" << std::endl;
526 pos2 =
proto.find_first_of(
")");
527 pos2_1 =
proto.find_last_of(
")");
529 if (pos2 != pos2_1) {
530 std::cout <<
"Error at line " <<
fLine <<
" - too many ) in function prototype!" << std::endl;
536 std::cout <<
"Error at line " <<
fLine <<
" - missing ) in function prototype" << std::endl;
540 std::cout <<
"Error at line " <<
fLine <<
" - wrong order of ( and ) in function prototype" << std::endl;
547 pos3 =
proto.find(
" ", pos3);
549 proto.erase(pos3, 1);
556 std::cout <<
"Error at line " <<
fLine <<
" - missing ( in function prototype" << std::endl;
572 int pos1 = -1, pos2 = -1;
573 int open_br = 0, close_br = 0;
577 pos =
pattern.find(
" ", pos + 1);
578 pos1 =
pattern.find(
"<", pos1 + 1);
579 pos2 =
pattern.find(
">", pos2 + 1);
581 if ((pos < 0) && (pos1 < 0) && (pos2 < 0))
break;
583 if (pos1 > -1) ++open_br;
584 if (pos2 > -1) ++close_br;
586 if (pos < 0)
continue;
592 if (pos > 0) before =
pattern.at(pos - 1);
593 if (pos < (
int)(
pattern.length() - 1)) after =
pattern.at(pos + 1);
617 std::cout <<
"Error at line " <<
fLine - 1 <<
" - extra space" << std::endl;
623 if (open_br != close_br) {
624 std::cout <<
"Error at line " <<
fLine <<
" - number of < doesn't match number of >" << std::endl;
631class LinkdefReaderPragmaHandler :
public clang::PragmaHandler {
634 clang::SourceManager &fSourceManager;
636 LinkdefReaderPragmaHandler(
const char *which,
LinkdefReader &owner, clang::SourceManager &sm) :
638 clang::PragmaHandler(which), fOwner(owner), fSourceManager(sm) {
641 void Error(
const char *message,
const clang::Token &tok,
bool source =
true) {
643 std::cerr << message <<
" at ";
644 tok.getLocation().dump(fSourceManager);
647 std::cerr << fSourceManager.getCharacterData(tok.getLocation());
652 bool ProcessOptions(LinkdefReader::Options &options,
653 clang::Preprocessor &PP,
670 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
671 Error(
"Error: the 'options' keyword must be followed by an '='", tok);
676 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
677 if (!tok.getIdentifierInfo()) {
678 Error(
"Error: Malformed version option.", tok);
679 }
else if (tok.getIdentifierInfo()->getName() ==
"nomap") {
682 }
else if (tok.getIdentifierInfo()->getName() ==
"nostreamer") options.fNoStreamer = 1;
683 else if (tok.getIdentifierInfo()->getName() ==
"noinputoper") options.fNoInputOper = 1;
684 else if (tok.getIdentifierInfo()->getName() ==
"evolution") options.fRequestStreamerInfo = 1;
685 else if (tok.getIdentifierInfo()->getName() ==
"stub") {
688 }
else if (tok.getIdentifierInfo()->getName() ==
"version") {
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 version.", start);
696 clang::Token number = tok;
697 if (tok.isNot(clang::tok::eod)) PP.Lex(tok);
698 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
699 Error(
"Error: missing right parenthesis after version.", start);
702 if (!number.isLiteral()) {
703 std::cerr <<
"Error: Malformed version option, the value is not a non-negative number!";
706 std::string verStr(number.getLiteralData(), number.getLength());
707 bool noDigit =
false;
708 for (std::string::size_type i = 0; i < verStr.size(); ++i)
709 if (!isdigit(verStr[i])) noDigit =
true;
712 std::cerr <<
"Error: Malformed version option! \"" << verStr <<
"\" is not a non-negative number!";
715 options.fVersionNumber = atoi(verStr.c_str());
717 Error(
"Warning: ignoring unknown #pragma link option=", tok);
720 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
731class PragmaExtraInclude :
public LinkdefReaderPragmaHandler {
733 PragmaExtraInclude(
LinkdefReader &owner, clang::SourceManager &sm) :
735 LinkdefReaderPragmaHandler(
"extra_include", owner, sm) {
738 void HandlePragma(clang::Preprocessor &PP,
739 clang::PragmaIntroducerKind Introducer,
745 if (Introducer != clang::PIK_HashPragma)
return;
746 if (!tok.getIdentifierInfo())
return;
747 if (tok.getIdentifierInfo()->getName() !=
"extra_include")
return;
753 if (tok.is(clang::tok::eod)) {
754 Error(
"Warning - lonely pragma statement: ", tok);
757 const char *start = fSourceManager.getCharacterData(tok.getLocation());
760 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
764 if (tok.isNot(clang::tok::semi)) {
765 Error(
"Error: missing ; at end of rule", tok,
false);
768 if (end.is(clang::tok::unknown)) {
769 Error(
"Error: Unknown token!", tok);
771 llvm::StringRef include(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
780class PragmaIoReadInclude :
public LinkdefReaderPragmaHandler {
782 PragmaIoReadInclude(
LinkdefReader &owner, clang::SourceManager &sm) :
784 LinkdefReaderPragmaHandler(
"read", owner, sm) {
787 void HandlePragma(clang::Preprocessor &PP,
788 clang::PragmaIntroducerKind Introducer,
794 if (Introducer != clang::PIK_HashPragma)
return;
795 if (!tok.getIdentifierInfo())
return;
796 if (tok.getIdentifierInfo()->getName() !=
"read")
return;
802 if (tok.is(clang::tok::eod)) {
803 Error(
"Warning - lonely pragma statement: ", tok);
806 const char *start = fSourceManager.getCharacterData(tok.getLocation());
809 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
818 if (end.is(clang::tok::unknown)) {
819 Error(
"Error: unknown token", tok);
821 llvm::StringRef rule_text(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
823 std::string error_string;
825 if (!error_string.empty())
826 std::cerr << error_string;
836class PragmaLinkCollector :
public LinkdefReaderPragmaHandler {
841 PragmaLinkCollector(
LinkdefReader &owner, clang::SourceManager &sm) :
843 LinkdefReaderPragmaHandler(
"link", owner, sm) {
846 void HandlePragma(clang::Preprocessor &PP,
847 clang::PragmaIntroducerKind Introducer,
853 if (Introducer != clang::PIK_HashPragma)
return;
854 if (!tok.getIdentifierInfo())
return;
855 if (tok.getIdentifierInfo()->getName() !=
"link")
return;
861 if (tok.is(clang::tok::eod)) {
862 Error(
"Warning - lonely pragma statement: ", tok);
866 if (tok.isAnyIdentifier()) {
867 if ((tok.getIdentifierInfo()->getName() ==
"off")) {
869 }
else if ((tok.getIdentifierInfo()->getName() ==
"C")) {
872 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
873 Error(
"Error ++ expected after '#pragma link C' at ", tok);
877 Error(
"Error #pragma link should be followed by off or C", tok);
881 Error(
"Error bad #pragma format. ", tok);
886 if (tok.is(clang::tok::eod)) {
887 Error(
"Error no arguments after #pragma link C++/off: ", tok);
890 auto identifier = tok.getIdentifierInfo();
891 if (identifier ==
nullptr) {
892 if (linkOn)
Error(
"Error #pragma link C++ should be followed by identifier", tok);
893 else Error(
"Error #pragma link off should be followed by identifier", tok);
897 llvm::StringRef
type = identifier->getName();
899 std::unique_ptr<LinkdefReader::Options> options;
900 if (
type ==
"options" ||
type ==
"option") {
901 options.reset(
new LinkdefReader::Options());
902 if (!ProcessOptions(*options, PP, tok)) {
905 if (tok.getIdentifierInfo())
type = tok.getIdentifierInfo()->getName();
908 PP.LexUnexpandedToken(tok);
909 const char *start = fSourceManager.getCharacterData(tok.getLocation());
912 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
916 PP.LexUnexpandedToken(tok);
919 if (tok.isNot(clang::tok::semi)) {
920 Error(
"Error: missing ; at end of rule", tok,
false);
924 if (end.is(clang::tok::unknown)) {
925 if (!fOwner.
AddRule(
type.data(),
"", linkOn,
false, options.get())) {
929 llvm::StringRef identifier(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
931 if (!fOwner.
AddRule(
type, identifier, linkOn,
false, options.get())) {
944class PragmaCreateCollector :
public LinkdefReaderPragmaHandler {
946 PragmaCreateCollector(
LinkdefReader &owner, clang::SourceManager &sm) :
948 LinkdefReaderPragmaHandler(
"create", owner, sm) {
951 void HandlePragma(clang::Preprocessor &PP,
952 clang::PragmaIntroducerKind Introducer,
958 if (Introducer != clang::PIK_HashPragma)
return;
959 if (!tok.getIdentifierInfo())
return;
960 if (tok.getIdentifierInfo()->getName() !=
"create")
return;
966 if (tok.is(clang::tok::eod)) {
967 Error(
"Warning - lonely pragma statement: ", tok);
970 if ((tok.getIdentifierInfo()->getName() !=
"TClass")) {
971 Error(
"Error: currently only supporting TClass after '#pragma create':", tok);
976 const char *start = fSourceManager.getCharacterData(tok.getLocation());
977 clang::Token end = tok;
978 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
983 if (tok.isNot(clang::tok::semi)) {
984 Error(
"Error: missing ; at end of rule", tok,
false);
988 llvm::StringRef identifier(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
990 if (!fOwner.
AddRule(
"class", identifier,
true,
true)) {
1009 std::vector<const char *> parserArgsC;
1010 for (
size_t i = 0,
n = parserArgs.size(); i <
n; ++i) {
1011 parserArgsC.push_back(parserArgs[i].c_str());
1015 std::unique_ptr<llvm::MemoryBuffer> memBuf = llvm::MemoryBuffer::getMemBuffer(code,
"CLING #pragma extraction");
1016 clang::CompilerInstance *pragmaCI = cling::CIFactory::createCI(std::move(memBuf), parserArgsC.size(),
1017 &parserArgsC[0], llvmdir,
nullptr ,
1020 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1021 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1022 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1024 PragmaLinkCollector pragmaLinkCollector(*
this, pragmaCI->getASTContext().getSourceManager());
1026 PragmaExtraInclude pragmaExtraInclude(*
this, pragmaCI->getASTContext().getSourceManager());
1027 PragmaIoReadInclude pragmaIoReadInclude(*
this, pragmaCI->getASTContext().getSourceManager());
1029 PP.AddPragmaHandler(&pragmaLinkCollector);
1030 PP.AddPragmaHandler(&pragmaCreateCollector);
1031 PP.AddPragmaHandler(&pragmaExtraInclude);
1032 PP.AddPragmaHandler(&pragmaIoReadInclude);
1035 PP.EnterMainSourceFile();
1039 }
while (tok.isNot(clang::tok::eof));
1042 return 0 == DClient.getNumErrors();
void Error(const char *location, const char *msgfmt,...)
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 SetRequestedVersionNumber(int version)
void SetRequestPrivate(bool val)
void SetRequestNoStreamer(bool noStreamer)
void SetRequestOnlyTClass(bool val)
void SetRequestStreamerInfo(bool needStreamerInfo)
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)
bool AddRule(const std::string &ruletype, const std::string &identifier, bool linkOn, bool requestOnlyTClass, Options *option=0)
friend class PragmaExtraInclude
static std::map< std::string, EPragmaNames > fgMapPragmaNames
static void PopulatePragmaMap()
static void PopulateCppMap()
ROOT::TMetaUtils::RConstructorTypes * fIOConstructorTypesPtr
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.
static constexpr double sr