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 +
"*)";
638 void Error(
const char *message,
const clang::Token &tok,
639 const clang::Preprocessor& PP,
bool source =
true) {
641 std::cerr << message <<
" at ";
642 const clang::SourceManager &SM = PP.getSourceManager();
643 tok.getLocation().dump(SM);
646 std::cerr << SM.getCharacterData(tok.getLocation());
652 clang::Preprocessor &PP,
669 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
670 Error(
"Error: the 'options' keyword must be followed by an '='", tok, PP);
675 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
676 if (!tok.getIdentifierInfo()) {
677 Error(
"Error: Malformed version option.", tok, PP);
678 }
else if (tok.getIdentifierInfo()->getName() ==
"nomap") {
681 }
else if (tok.getIdentifierInfo()->getName() ==
"nostreamer") options.
fNoStreamer = 1;
682 else if (tok.getIdentifierInfo()->getName() ==
"noinputoper") options.
fNoInputOper = 1;
684 else if (tok.getIdentifierInfo()->getName() ==
"stub") {
687 }
else if (tok.getIdentifierInfo()->getName() ==
"version") {
688 clang::Token start = tok;
690 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
691 Error(
"Error: missing left parenthesis after version.", start, PP);
695 clang::Token number = tok;
696 if (tok.isNot(clang::tok::eod)) PP.Lex(tok);
697 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
698 Error(
"Error: missing right parenthesis after version.", start, PP);
701 if (!number.isLiteral()) {
702 std::cerr <<
"Error: Malformed version option, the value is not a non-negative number!";
705 std::string verStr(number.getLiteralData(), number.getLength());
706 bool noDigit =
false;
707 for (std::string::size_type i = 0; i < verStr.size(); ++i)
708 if (!isdigit(verStr[i])) noDigit =
true;
711 std::cerr <<
"Error: Malformed version option! \"" << verStr <<
"\" is not a non-negative number!";
712 Error(
"", start, PP);
716 Error(
"Warning: ignoring unknown #pragma link option=", tok, PP);
719 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
738 clang::PragmaIntroducer Introducer,
739 clang::Token &tok)
override {
744 if (Introducer.Kind != clang::PIK_HashPragma)
return;
745 if (!tok.getIdentifierInfo())
return;
746 if (tok.getIdentifierInfo()->getName() !=
"extra_include")
return;
752 if (tok.is(clang::tok::eod)) {
753 Error(
"Warning - lonely pragma statement: ", tok, PP);
756 const clang::SourceManager &SM = PP.getSourceManager();
757 const char *start = SM.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, PP,
false);
768 if (end.is(clang::tok::unknown)) {
769 Error(
"Error: Unknown token!", tok, PP);
771 llvm::StringRef include(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
788 clang::PragmaIntroducer Introducer,
789 clang::Token &tok)
override {
794 if (Introducer.Kind != 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, PP);
806 const clang::SourceManager& SM = PP.getSourceManager();
807 const char *start = SM.getCharacterData(tok.getLocation());
810 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
819 if (end.is(clang::tok::unknown)) {
820 Error(
"Error: unknown token", tok, PP);
822 llvm::StringRef rule_text(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
824 std::string error_string;
826 if (!error_string.empty())
827 std::cerr << error_string;
848 clang::PragmaIntroducer Introducer,
849 clang::Token &tok)
override {
854 if (Introducer.Kind != clang::PIK_HashPragma)
return;
855 if (!tok.getIdentifierInfo())
return;
856 if (tok.getIdentifierInfo()->getName() !=
"link")
return;
862 if (tok.is(clang::tok::eod)) {
863 Error(
"Warning - lonely pragma statement: ", tok, PP);
867 if (tok.isAnyIdentifier()) {
868 if ((tok.getIdentifierInfo()->getName() ==
"off")) {
870 }
else if ((tok.getIdentifierInfo()->getName() ==
"C")) {
873 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
874 Error(
"Error ++ expected after '#pragma link C' at ", tok, PP);
878 Error(
"Error #pragma link should be followed by off or C", tok, PP);
882 Error(
"Error bad #pragma format. ", tok, PP);
887 if (tok.is(clang::tok::eod)) {
888 Error(
"Error no arguments after #pragma link C++/off: ", tok, PP);
891 auto identifier = tok.getIdentifierInfo();
892 if (identifier ==
nullptr) {
893 if (linkOn)
Error(
"Error #pragma link C++ should be followed by identifier", tok, PP);
894 else Error(
"Error #pragma link off should be followed by identifier", tok, PP);
898 llvm::StringRef
type = identifier->getName();
900 std::unique_ptr<LinkdefReader::Options> options;
901 if (
type ==
"options" ||
type ==
"option") {
906 if (tok.getIdentifierInfo())
type = tok.getIdentifierInfo()->getName();
909 PP.LexUnexpandedToken(tok);
910 const clang::SourceManager &SM = PP.getSourceManager();
911 const char *start = SM.getCharacterData(tok.getLocation());
914 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
918 PP.LexUnexpandedToken(tok);
921 if (tok.isNot(clang::tok::semi)) {
922 Error(
"Error: missing ; at end of rule", tok, PP,
false);
926 if (end.is(clang::tok::unknown)) {
931 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
933 if (!
fOwner.
AddRule(
type.str(), identifier.str(), linkOn,
false, options.get())) {
954 clang::PragmaIntroducer Introducer,
955 clang::Token &tok)
override {
960 if (Introducer.Kind != clang::PIK_HashPragma)
return;
961 if (!tok.getIdentifierInfo())
return;
962 if (tok.getIdentifierInfo()->getName() !=
"create")
return;
968 if (tok.is(clang::tok::eod)) {
969 Error(
"Warning - lonely pragma statement: ", tok, PP);
972 if ((tok.getIdentifierInfo()->getName() !=
"TClass")) {
973 Error(
"Error: currently only supporting TClass after '#pragma create':", tok, PP);
978 const clang::SourceManager &SM = PP.getSourceManager();
979 const char *start = SM.getCharacterData(tok.getLocation());
980 clang::Token end = tok;
981 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
986 if (tok.isNot(clang::tok::semi)) {
987 Error(
"Error: missing ; at end of rule", tok, PP,
false);
991 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
993 if (!
fOwner.
AddRule(
"class", identifier.str(),
true,
true)) {
1012 std::vector<const char *> parserArgsC;
1013 for (
size_t i = 0,
n = parserArgs.size(); i <
n; ++i) {
1014 parserArgsC.push_back(parserArgs[i].c_str());
1018 std::unique_ptr<llvm::MemoryBuffer> memBuf = llvm::MemoryBuffer::getMemBuffer(code,
"CLING #pragma extraction");
1019 clang::CompilerInstance *pragmaCI = cling::CIFactory::createCI(std::move(memBuf), parserArgsC.size(),
1020 &parserArgsC[0], llvmdir,
nullptr ,
1023 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1024 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1025 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1033 PP.AddPragmaHandler(&pragmaLinkCollector);
1034 PP.AddPragmaHandler(&pragmaCreateCollector);
1035 PP.AddPragmaHandler(&pragmaExtraInclude);
1036 PP.AddPragmaHandler(&pragmaIoReadInclude);
1039 PP.EnterMainSourceFile();
1043 }
while (tok.isNot(clang::tok::eof));
1046 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)
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.