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"
103 fLine(1), fCount(0), fSelectionRules(nullptr), fIOConstructorTypesPtr(&IOConstructorTypes), fInterp(interp)
128 const std::string& identifier,
130 bool request_only_tclass,
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;
575 pos = pattern.find(
" ", pos + 1);
576 pos1 = pattern.find(
"<", pos1 + 1);
577 pos2 = pattern.find(
">", pos2 + 1);
579 if ((pos < 0) && (pos1 < 0) && (pos2 < 0))
break;
581 if (pos1 > -1) ++open_br;
582 if (pos2 > -1) ++close_br;
584 if (pos < 0)
continue;
590 if (pos > 0) before = pattern.at(pos - 1);
591 if (pos < (
int)(pattern.length() - 1)) after = pattern.at(pos + 1);
615 std::cout <<
"Error at line " <<
fLine - 1 <<
" - extra space" << std::endl;
618 pattern.erase(pos, 1);
621 if (open_br != close_br) {
622 std::cout <<
"Error at line " <<
fLine <<
" - number of < doesn't match number of >" << std::endl;
625 pattern =
"operator*(*" + pattern +
"*)";
639 void Error(
const char *message,
const clang::Token &tok,
bool source =
true) {
641 std::cerr << message <<
" at ";
651 clang::Preprocessor &PP,
668 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
669 Error(
"Error: the 'options' keyword must be followed by an '='", tok);
674 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
675 if (!tok.getIdentifierInfo()) {
676 Error(
"Error: Malformed version option.", tok);
677 }
else if (tok.getIdentifierInfo()->getName() ==
"nomap") {
680 }
else if (tok.getIdentifierInfo()->getName() ==
"nostreamer") options.
fNoStreamer = 1;
681 else if (tok.getIdentifierInfo()->getName() ==
"noinputoper") options.
fNoInputOper = 1;
683 else if (tok.getIdentifierInfo()->getName() ==
"stub") {
686 }
else if (tok.getIdentifierInfo()->getName() ==
"version") {
687 clang::Token start = tok;
689 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
690 Error(
"Error: missing left parenthesis after version.", start);
694 clang::Token number = tok;
695 if (tok.isNot(clang::tok::eod)) PP.Lex(tok);
696 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
697 Error(
"Error: missing right parenthesis after version.", start);
700 if (!number.isLiteral()) {
701 std::cerr <<
"Error: Malformed version option, the value is not a non-negative number!";
704 std::string verStr(number.getLiteralData(), number.getLength());
705 bool noDigit =
false;
706 for (std::string::size_type i = 0; i < verStr.size(); ++i)
707 if (!isdigit(verStr[i])) noDigit =
true;
710 std::cerr <<
"Error: Malformed version option! \"" << verStr <<
"\" is not a non-negative number!";
715 Error(
"Warning: ignoring unknown #pragma link option=", tok);
718 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
737 clang::PragmaIntroducer Introducer,
738 clang::Token &tok)
override {
743 if (Introducer.Kind != clang::PIK_HashPragma)
return;
744 if (!tok.getIdentifierInfo())
return;
745 if (tok.getIdentifierInfo()->getName() !=
"extra_include")
return;
751 if (tok.is(clang::tok::eod)) {
752 Error(
"Warning - lonely pragma statement: ", tok);
755 const char *start =
fSourceManager.getCharacterData(tok.getLocation());
758 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
762 if (tok.isNot(clang::tok::semi)) {
763 Error(
"Error: missing ; at end of rule", tok,
false);
766 if (end.is(clang::tok::unknown)) {
767 Error(
"Error: Unknown token!", tok);
769 llvm::StringRef include(start,
fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
786 clang::PragmaIntroducer Introducer,
787 clang::Token &tok)
override {
792 if (Introducer.Kind != clang::PIK_HashPragma)
return;
793 if (!tok.getIdentifierInfo())
return;
794 if (tok.getIdentifierInfo()->getName() !=
"read")
return;
800 if (tok.is(clang::tok::eod)) {
801 Error(
"Warning - lonely pragma statement: ", tok);
804 const char *start =
fSourceManager.getCharacterData(tok.getLocation());
807 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
816 if (end.is(clang::tok::unknown)) {
817 Error(
"Error: unknown token", tok);
819 llvm::StringRef rule_text(start,
fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
821 std::string error_string;
823 if (!error_string.empty())
824 std::cerr << error_string;
845 clang::PragmaIntroducer Introducer,
846 clang::Token &tok)
override {
851 if (Introducer.Kind != clang::PIK_HashPragma)
return;
852 if (!tok.getIdentifierInfo())
return;
853 if (tok.getIdentifierInfo()->getName() !=
"link")
return;
859 if (tok.is(clang::tok::eod)) {
860 Error(
"Warning - lonely pragma statement: ", tok);
864 if (tok.isAnyIdentifier()) {
865 if ((tok.getIdentifierInfo()->getName() ==
"off")) {
867 }
else if ((tok.getIdentifierInfo()->getName() ==
"C")) {
870 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
871 Error(
"Error ++ expected after '#pragma link C' at ", tok);
875 Error(
"Error #pragma link should be followed by off or C", tok);
879 Error(
"Error bad #pragma format. ", tok);
884 if (tok.is(clang::tok::eod)) {
885 Error(
"Error no arguments after #pragma link C++/off: ", tok);
888 auto identifier = tok.getIdentifierInfo();
889 if (identifier ==
nullptr) {
890 if (linkOn)
Error(
"Error #pragma link C++ should be followed by identifier", tok);
891 else Error(
"Error #pragma link off should be followed by identifier", tok);
895 llvm::StringRef
type = identifier->getName();
897 std::unique_ptr<LinkdefReader::Options> options;
898 if (
type ==
"options" ||
type ==
"option") {
903 if (tok.getIdentifierInfo())
type = tok.getIdentifierInfo()->getName();
906 PP.LexUnexpandedToken(tok);
907 const char *start =
fSourceManager.getCharacterData(tok.getLocation());
910 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
914 PP.LexUnexpandedToken(tok);
917 if (tok.isNot(clang::tok::semi)) {
918 Error(
"Error: missing ; at end of rule", tok,
false);
922 if (end.is(clang::tok::unknown)) {
927 llvm::StringRef identifier(start,
fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
929 if (!
fOwner.
AddRule(
type.str(), identifier.str(), linkOn,
false, options.get())) {
950 clang::PragmaIntroducer Introducer,
951 clang::Token &tok)
override {
956 if (Introducer.Kind != clang::PIK_HashPragma)
return;
957 if (!tok.getIdentifierInfo())
return;
958 if (tok.getIdentifierInfo()->getName() !=
"create")
return;
964 if (tok.is(clang::tok::eod)) {
965 Error(
"Warning - lonely pragma statement: ", tok);
968 if ((tok.getIdentifierInfo()->getName() !=
"TClass")) {
969 Error(
"Error: currently only supporting TClass after '#pragma create':", tok);
974 const char *start =
fSourceManager.getCharacterData(tok.getLocation());
975 clang::Token end = tok;
976 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
981 if (tok.isNot(clang::tok::semi)) {
982 Error(
"Error: missing ; at end of rule", tok,
false);
986 llvm::StringRef identifier(start,
fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
988 if (!
fOwner.
AddRule(
"class", identifier.str(),
true,
true)) {
1007 std::vector<const char *> parserArgsC;
1008 for (
size_t i = 0,
n = parserArgs.size(); i <
n; ++i) {
1009 parserArgsC.push_back(parserArgs[i].c_str());
1013 std::unique_ptr<llvm::MemoryBuffer> memBuf = llvm::MemoryBuffer::getMemBuffer(code,
"CLING #pragma extraction");
1014 clang::CompilerInstance *pragmaCI = cling::CIFactory::createCI(std::move(memBuf), parserArgsC.size(),
1015 &parserArgsC[0], llvmdir,
nullptr ,
1018 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1019 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1020 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1022 PragmaLinkCollector pragmaLinkCollector(*
this, pragmaCI->getASTContext().getSourceManager());
1024 PragmaExtraInclude pragmaExtraInclude(*
this, pragmaCI->getASTContext().getSourceManager());
1025 PragmaIoReadInclude pragmaIoReadInclude(*
this, pragmaCI->getASTContext().getSourceManager());
1027 PP.AddPragmaHandler(&pragmaLinkCollector);
1028 PP.AddPragmaHandler(&pragmaCreateCollector);
1029 PP.AddPragmaHandler(&pragmaExtraInclude);
1030 PP.AddPragmaHandler(&pragmaIoReadInclude);
1033 PP.EnterMainSourceFile();
1037 }
while (tok.isNot(clang::tok::eof));
1040 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 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, clang::SourceManager &sm)
void Error(const char *message, const clang::Token &tok, bool source=true)
clang::SourceManager & fSourceManager
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)
bool AddRule(const std::string &ruletype, const std::string &identifier, bool linkOn, bool requestOnlyTClass, Options *option=0)
static std::map< std::string, EPragmaNames > fgMapPragmaNames
static void PopulatePragmaMap()
static void PopulateCppMap()
ROOT::TMetaUtils::RConstructorTypes * fIOConstructorTypesPtr
PragmaCreateCollector(LinkdefReader &owner, clang::SourceManager &sm)
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
PragmaIoReadInclude(LinkdefReader &owner, clang::SourceManager &sm)
PragmaLinkCollector(LinkdefReader &owner, clang::SourceManager &sm)
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.