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;
 
  620      pattern.erase(pos, 1);
 
  623   if (open_br != close_br) {
 
  624      std::cout << 
"Error at line " << 
fLine << 
" - number of < doesn't match number of >" << std::endl;
 
  627   pattern = 
"operator*(*" + pattern + 
"*)";
 
  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::PragmaIntroducer Introducer,
 
  745      if (Introducer.Kind != 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::PragmaIntroducer Introducer,
 
  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);
 
  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::PragmaIntroducer Introducer,
 
  853      if (Introducer.Kind != 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::PragmaIntroducer Introducer,
 
  958      if (Introducer.Kind != 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,...)
Use this function in case an error occurred.
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.