Logo ROOT  
Reference Guide
LinkdefReader.cxx
Go to the documentation of this file.
1 // @(#)root/core/utils:$Id: LinkdefReader.cxx 41697 2011-11-01 21:03:41Z pcanal $
2 // Author: Velislava Spasova September 2010
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2011, Rene Brun, Fons Rademakers and al. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // LinkdefReader //
15 // //
16 // //
17 // Note: some inconsistency in the way CINT parsed the #pragma: //
18 // "#pragma link C++ class" is terminated by either a ';' or a newline//
19 // which ever come first and does NOT support line continuation. //
20 // "#pragma read ..." is terminated by newline but support line //
21 // continuation (i.e. '\' followed by newline means to also use the//
22 // next line. //
23 // This was change in CINT to consistently ignore the continuation //
24 // //
25 // //
26 //////////////////////////////////////////////////////////////////////////
27 
28 #include <iostream>
29 #include <memory>
30 #include "LinkdefReader.h"
31 #include "SelectionRules.h"
32 #include "RConversionRuleParser.h"
33 
34 #include "llvm/Support/raw_ostream.h"
35 
36 #include "clang/AST/ASTContext.h"
37 
38 #include "clang/Frontend/CompilerInstance.h"
39 
40 #include "clang/Lex/Preprocessor.h"
41 #include "clang/Lex/Pragma.h"
42 
43 #include "cling/Interpreter/CIFactory.h"
44 #include "cling/Interpreter/Interpreter.h"
45 
46 std::map<std::string, LinkdefReader::EPragmaNames> LinkdefReader::fgMapPragmaNames;
47 std::map<std::string, LinkdefReader::ECppNames> LinkdefReader::fgMapCppNames;
48 
49 struct LinkdefReader::Options {
50  Options() : fNoStreamer(0), fNoInputOper(0), fUseByteCount(0), fVersionNumber(-1) {}
51 
52  int fNoStreamer;
53  int fNoInputOper;
54  union {
55  int fUseByteCount;
56  int fRequestStreamerInfo;
57  };
58  int fVersionNumber;
59 };
60 
61 /*
62  This is a static function - which in our context means it is populated only ones
63  */
65 {
66  if (!(fgMapPragmaNames.empty())) return; // if the map has already been populated, return, else populate it
67 
85  // The following are listed here so we can officially ignore them
86  LinkdefReader::fgMapPragmaNames["nestedtypedefs"] = kIgnore;
87  LinkdefReader::fgMapPragmaNames["nestedtypedef"] = kIgnore;
88 }
89 
91 {
92  if (!(fgMapCppNames.empty())) return; // if the map has already been populated, return, else populate it
93 
99 }
100 
101 LinkdefReader::LinkdefReader(cling::Interpreter &interp,
102  ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes):
103  fLine(1), fCount(0), fSelectionRules(nullptr), fIOConstructorTypesPtr(&IOConstructorTypes), fInterp(interp)
104 {
106  PopulateCppMap();
107 }
108 
109 /*
110  * The method records that 'include' has been explicitly requested in the linkdef file
111  * to be added to the dictionary and interpreter.
112  */
113 bool LinkdefReader::AddInclude(const std::string& include)
114 {
115  fIncludes += "#include ";
116  fIncludes += include;
117  fIncludes += "\n";
118 
119  return true;
120 }
121 
122 
123 /*
124  * The method that processes the pragma statement.
125  * Sometimes I had to do strange things to reflect the strange behavior of rootcint
126  */
127 bool LinkdefReader::AddRule(const std::string& ruletype,
128  const std::string& identifier,
129  bool linkOn,
130  bool request_only_tclass,
131  LinkdefReader::Options *options /* = 0 */)
132 {
133 
135  ROOT::TMetaUtils::Info("LinkdefReader::AddRule", "Ruletype is %s with the identifier %s\n", ruletype.c_str(), identifier.c_str());
136  auto it = fgMapPragmaNames.find(ruletype);
137  if (it != fgMapPragmaNames.end()) {
138  name = it->second;
139  }
140 
141  switch (name) {
142  case kAll:
143  if (identifier == "globals" || identifier == "global") {
145  if (linkOn) {
146  vsr.SetAttributeValue("pattern", "*");
149  } else {
150  if (fSelectionRules->GetHasFileNameRule()) { // only if we had previous defined_in -> create that
151  // we don't create anything which is OK - if I don't have a selection rule for something
152  // this something will not be generated
153  // This is valid also for the other all ... cases
154  vsr.SetAttributeValue("pattern", "*");
157  }
158  }
159  //else vsr.SetSelected(BaseSelectionRule::kNo);
160  //fSelectionRules->AddVariableSelectionRule(vsr);
161 
163  if (linkOn) {
165  esr.SetAttributeValue("pattern", "*");
167 
168  //EnumSelectionRule esr2; //Problem wih the enums - if I deselect them here
171  esr2.SetAttributeValue("pattern", "*::*");
173  } else {
175  esr.SetAttributeValue("pattern", "*");
178  }
179  }
180  } else if (identifier == "functions" || identifier == "function") {
182  fsr.SetAttributeValue("pattern", "*");
183  if (linkOn) {
186  } else {
190  }
191  }
192  } else if (identifier == "classes" || identifier == "namespaces" ||
193  identifier == "class" || identifier == "namespace") {
194  if (linkOn) {
195 
198  csr3.SetAttributeValue("pattern", "__va_*"); // don't generate for the built-in classes/structs
200 
201  ClassSelectionRule csr(fCount++, fInterp), csr2(fCount++, fInterp);
202  csr.SetAttributeValue("pattern", "*");
203  csr2.SetAttributeValue("pattern", "*::*");
204  csr.SetSelected(BaseSelectionRule::kYes);
206 
209  } else {
211  ClassSelectionRule csr(fCount++, fInterp), csr2(fCount++, fInterp);
212  csr.SetAttributeValue("pattern", "*");
213  csr2.SetAttributeValue("pattern", "*::*");
214 
215  csr.SetSelected(BaseSelectionRule::kNo);
219  }
220  }
221  } else if (identifier == "typedefs" || identifier == "typedef") {
222  // Silently ignore
223  } else {
224  ROOT::TMetaUtils::Warning("Unimplemented pragma statement: %s\n",identifier.c_str());
225  return false;
226  }
227 
228  break;
229  case kNestedclasses: {
230  // we don't really process that one
231  }
232  break;
233  case kDefinedIn: {
235 
236  // add selection rules for everything
237  std::string localIdentifier(identifier);
238  if (localIdentifier.length() && localIdentifier[0] == '"' && localIdentifier[localIdentifier.length() - 1] == '"') {
239  localIdentifier = localIdentifier.substr(1, localIdentifier.length() - 2);
240  }
241 
243  vsr.SetAttributeValue("pattern", "*");
244  vsr.SetAttributeValue("file_name", localIdentifier);
245  if (linkOn) vsr.SetSelected(BaseSelectionRule::kYes);
248 
250  esr.SetAttributeValue("pattern", "*");
251  esr.SetAttributeValue("file_name", localIdentifier);
252  if (linkOn) esr.SetSelected(BaseSelectionRule::kYes);
255 
257  fsr.SetAttributeValue("pattern", "*");
258  fsr.SetAttributeValue("file_name", localIdentifier);
259  if (linkOn) fsr.SetSelected(BaseSelectionRule::kYes);
262 
263  ClassSelectionRule csr(fCount++, fInterp), csr2(fCount++, fInterp);
264  csr.SetAttributeValue("pattern", "*");
265  csr2.SetAttributeValue("pattern", "*::*");
266 
267  csr.SetAttributeValue("file_name", localIdentifier);
268  csr2.SetAttributeValue("file_name", localIdentifier);
269  if (linkOn) {
270  csr.SetSelected(BaseSelectionRule::kYes);
272  } else {
273  csr.SetSelected(BaseSelectionRule::kNo);
275  }
276  csr.SetRequestStreamerInfo(true);
277  csr2.SetRequestStreamerInfo(true);
280 
281  }
282  break;
283 
284  case kFunction: {
285  std::string localIdentifier(identifier);
286  bool name_or_proto = false; // if true = name, if flase = proto_name
287  if (!ProcessFunctionPrototype(localIdentifier, name_or_proto)) {
288  return false;
289  }
291  if (linkOn) fsr.SetSelected(BaseSelectionRule::kYes);
293  if (localIdentifier.at(localIdentifier.length() - 1) == '*') fsr.SetAttributeValue("pattern", localIdentifier);
294  else if (name_or_proto) fsr.SetAttributeValue("name", localIdentifier);
295  else {
296  int pos = localIdentifier.find("(*)"); //rootcint generates error here but I decided to implement that pattern
297  if (pos > -1) fsr.SetAttributeValue("proto_pattern", localIdentifier);
298  else {
299  // No multiline
300  ROOT::TMetaUtils::ReplaceAll(localIdentifier, "\\\n", "", true);
301  // Types: We do not do IO of functions, so it is safe to
302  // put in some heuristics
303  ROOT::TMetaUtils::ReplaceAll(localIdentifier, "ULong_t", "unsigned long");
304  ROOT::TMetaUtils::ReplaceAll(localIdentifier, "Long_t", "long");
305  ROOT::TMetaUtils::ReplaceAll(localIdentifier, "Int_t", "int");
306  // Remove space after/before the commas if any
307  ROOT::TMetaUtils::ReplaceAll(localIdentifier, ", ", ",", true);
308  ROOT::TMetaUtils::ReplaceAll(localIdentifier, " ,", ",", true);
309  // Remove any space before/after the ( as well
310  ROOT::TMetaUtils::ReplaceAll(localIdentifier, " (", "(", true);
311  ROOT::TMetaUtils::ReplaceAll(localIdentifier, "( ", "(", true);
312  ROOT::TMetaUtils::ReplaceAll(localIdentifier, " )", ")", true);
313  fsr.SetAttributeValue("proto_name", localIdentifier);
314  }
315  }
317 
318  }
319  break;
320 
321  case kOperators: {
322  std::string localIdentifier(identifier);
323  if (!ProcessOperators(localIdentifier)) // this creates the proto_pattern
324  return false;
325 
327  if (linkOn) fsr.SetSelected(BaseSelectionRule::kYes);
329  fsr.SetAttributeValue("proto_pattern", localIdentifier);
331  }
332  break;
333  case kGlobal: {
335  if (linkOn) vsr.SetSelected(BaseSelectionRule::kYes);
337  if (IsPatternRule(identifier)) vsr.SetAttributeValue("pattern", identifier);
338  else vsr.SetAttributeValue("name", identifier);
340  }
341  break;
342  case kEnum: {
343 
345  if (linkOn) esr.SetSelected(BaseSelectionRule::kYes);
347  if (IsPatternRule(identifier)) esr.SetAttributeValue("pattern", identifier);
348  else esr.SetAttributeValue("name", identifier);
350  }
351  break;
352  case kClass:
353  case kTypeDef:
354  case kNamespace:
355  case kUnion:
356  case kStruct: {
357  std::string localIdentifier(identifier);
359 
360  if (request_only_tclass) {
361  csr.SetRequestOnlyTClass(true);
362  }
363  int len = localIdentifier.length();
364  if (len > 8) { // process class+protected and class+private
365  const std::string protStr("+protected");
366  const std::string privStr("+private");
367 
368  if (localIdentifier.compare(0, protStr.length(), protStr) == 0) {
369  csr.SetRequestProtected(true);
370  localIdentifier.erase(0, protStr.length() + 1);
371  len = localIdentifier.length();
372  } else if (localIdentifier.compare(0, privStr.length(), privStr) == 0) {
373  csr.SetRequestPrivate(true);
374  localIdentifier.erase(0, privStr.length() + 1);
375  len = localIdentifier.length();
376  }
377  }
378  if (len > 1) { // process the +, -, -! endings of the classes
379 
380  bool ending = false;
381  int where = 1;
382  while (!ending && where < len) {
383  char last = localIdentifier.at(len - where);
384  switch (last) {
385  case ';':
386  break;
387  case '+':
388  csr.SetRequestStreamerInfo(true);
389  break;
390  case '!':
391  csr.SetRequestNoInputOperator(true);
392  break;
393  case '-':
394  csr.SetRequestNoStreamer(true);
395  break;
396  case ' ':
397  case '\t':
398  break;
399  default:
400  ending = true;
401  }
402  ++where;
403  }
404  if (options) {
405  if (options->fNoStreamer) csr.SetRequestNoStreamer(true);
406  if (options->fNoInputOper) csr.SetRequestNoInputOperator(true);
407  if (options->fRequestStreamerInfo) csr.SetRequestStreamerInfo(true);
408  if (options->fVersionNumber >= 0) csr.SetRequestedVersionNumber(options->fVersionNumber);
409  }
410  if (csr.RequestStreamerInfo() && csr.RequestNoStreamer()) {
411  std::cerr << "Warning: " << localIdentifier << " option + mutual exclusive with -, + prevails\n";
412  csr.SetRequestNoStreamer(false);
413  }
414  if (ending) {
415  localIdentifier.erase(len - (where - 2)); // We 'consumed' one of the class token
416  } else {
417  localIdentifier.erase(len - (where - 1));
418  }
419  }
420 
421  if (linkOn) {
423 
424  if (localIdentifier == "*") { // rootcint generates error here, but I decided to implement it
427  csr2.SetAttributeValue("pattern", "*::*");
429 
432  csr3.SetAttributeValue("pattern", "__va_*");
434  }
435  } else {
437  if (localIdentifier == "*") { // rootcint generates error here, but I decided to implement it
440  csr2.SetAttributeValue("pattern", "*::*");
442 
443  EnumSelectionRule esr(fCount++, fInterp); // we need this because of implicit/explicit rules - check my notes on rootcint
445  esr.SetAttributeValue("pattern", "*::*");
447 
448  }
449  // Since the rootcling default is 'off' (we need to explicilty annotate to turn it on), the nested type and function
450  // should be off by default. Note that anyway, this is not yet relevant since the pcm actually ignore the on/off
451  // request and contains everything (for now).
452  // else {
453  // EnumSelectionRule esr(fCount++); // we need this because of implicit/explicit rules - check my notes on rootcint
454  // esr.SetSelected(BaseSelectionRule::kNo);
455  // esr.SetAttributeValue("pattern", localIdentifier+"::*");
456  // fSelectionRules->AddEnumSelectionRule(esr);
457 
458  // if (fSelectionRules->GetHasFileNameRule()) {
459  // FunctionSelectionRule fsr(fCount++); // we need this because of implicit/explicit rules - check my notes on rootcint
460  // fsr.SetSelected(BaseSelectionRule::kNo);
461  // std::string value = localIdentifier + "::*";
462  // fsr.SetAttributeValue("pattern", value);
463  // fSelectionRules->AddFunctionSelectionRule(fsr);
464  // }
465  // }
466  }
467  if (IsPatternRule(localIdentifier)) {
468  csr.SetAttributeValue("pattern", localIdentifier);
469  }
470  csr.SetAttributeValue("name", localIdentifier);
471 
472  if (name == kTypeDef) {
473  csr.SetAttributeValue("fromTypedef", "true");
474  }
475 
477  //csr.PrintAttributes(std::cout,3);
478  }
479  break;
480  case kIOCtorType:
481  // #pragma link C++ IOCtorType typename;
482  fIOConstructorTypesPtr->push_back(ROOT::TMetaUtils::RConstructorType(identifier.c_str(), fInterp));
483  break;
484  case kIgnore:
485  // All the pragma that were supported in CINT but are currently not relevant for CLING
486  // (mostly because we do not yet filter the dictionary/pcm).
487  break;
488  case kUnknown:
489  ROOT::TMetaUtils::Warning("Unimplemented pragma statement - it has no effect: %s\n", identifier.c_str());
490  return false;
491  break;
492  }
493 
494  return true;
495 }
496 
497 bool LinkdefReader::IsPatternRule(const std::string &rule_token)
498 {
499  int pos = rule_token.find("*");
500  if (pos > -1) return true;
501  else return false;
502 }
503 
504 /*
505  * The method records that 'include' has been explicitly requested in the linkdef file
506  * to be added to the dictionary and interpreter.
507  */
508 bool LinkdefReader::LoadIncludes(std::string &extraIncludes)
509 {
510  extraIncludes += fIncludes;
511  return cling::Interpreter::kSuccess == fInterp.declare(fIncludes);
512 }
513 
515 {
516  int pos1, pos1_1, pos2, pos2_1;
517 
518  pos1 = proto.find_first_of("(");
519  pos1_1 = proto.find_last_of("(");
520 
521  if (pos1 != pos1_1) {
522  std::cout << "Error at line " << fLine << " - too many ( in function prototype!" << std::endl;
523  return false;
524  }
525 
526  pos2 = proto.find_first_of(")");
527  pos2_1 = proto.find_last_of(")");
528 
529  if (pos2 != pos2_1) {
530  std::cout << "Error at line " << fLine << " - too many ) in function prototype!" << std::endl;
531  return false;
532  }
533 
534  if (pos1 > -1) {
535  if (pos2 < 0) {
536  std::cout << "Error at line " << fLine << " - missing ) in function prototype" << std::endl;
537  return false;
538  }
539  if (pos2 < pos1) {
540  std::cout << "Error at line " << fLine << " - wrong order of ( and ) in function prototype" << std::endl;
541  return false;
542  }
543 
544  // I don't have to escape the *-s because in rootcint there is no pattern recognition
545  int pos3 = pos1;
546  while (true) {
547  pos3 = proto.find(" ", pos3);
548  if (pos3 > -1) {
549  proto.erase(pos3, 1);
550  }
551  if (pos3 < 0) break;
552  }
553  name = false;
554  } else {
555  if (pos2 > -1) {
556  std::cout << "Error at line " << fLine << " - missing ( in function prototype" << std::endl;
557  return false;
558  } else {
559  //std::cout<<"Debug - no prototype, name = true"<<std::endl;
560  name = true;
561  }
562  }
563  return true;
564 }
565 
566 // This function is really very basic - it just checks whether everything is OK with the
567 // spaces and if the number of opening < matches the number of >.
568 // But it doesn't catch situations like vector>int<, etc.
570 {
571  int pos = -1;
572  int pos1 = -1, pos2 = -1;
573  int open_br = 0, close_br = 0;
574  int i = 0;
575  while (true) {
576  i++;
577  pos = pattern.find(" ", pos + 1);
578  pos1 = pattern.find("<", pos1 + 1);
579  pos2 = pattern.find(">", pos2 + 1);
580 
581  if ((pos < 0) && (pos1 < 0) && (pos2 < 0)) break;
582 
583  if (pos1 > -1) ++open_br;
584  if (pos2 > -1) ++close_br;
585 
586  if (pos < 0) continue;
587  char before = '$';
588  char after = '$';
589  bool ok1 = false;
590  bool ok2 = false;
591 
592  if (pos > 0) before = pattern.at(pos - 1);
593  if (pos < (int)(pattern.length() - 1)) after = pattern.at(pos + 1);
594 
595  //std::cout<<"before: "<<before<<", after: "<<after<<", pos: "<<pos<<std::endl;
596  switch (before) {
597  case '<':
598  case ',':
599  case ' ':
600  ok1 = true;
601  break;
602  default:
603  ok1 = false;
604  }
605  switch (after) {
606  case '>':
607  case '<':
608  case ',':
609  case ' ':
610  ok2 = true;
611  break;
612  default:
613  ok2 = false;
614  }
615  //std::cout<<"ok1: "<<ok1<<", ok2: "<<ok2<<std::endl;
616  if (!ok1 && !ok2) {
617  std::cout << "Error at line " << fLine - 1 << " - extra space" << std::endl;
618  return false;
619  }
620  pattern.erase(pos, 1);
621  }
622 
623  if (open_br != close_br) {
624  std::cout << "Error at line " << fLine << " - number of < doesn't match number of >" << std::endl;
625  return false;
626  }
627  pattern = "operator*(*" + pattern + "*)";
628  return true;
629 }
630 
631 class LinkdefReaderPragmaHandler : public clang::PragmaHandler {
632 protected:
633  LinkdefReader &fOwner;
634  clang::SourceManager &fSourceManager;
635 public:
636  LinkdefReaderPragmaHandler(const char *which, LinkdefReader &owner, clang::SourceManager &sm) :
637  // This handler only cares about "#pragma link"
638  clang::PragmaHandler(which), fOwner(owner), fSourceManager(sm) {
639  }
640 
641  void Error(const char *message, const clang::Token &tok, bool source = true) {
642 
643  std::cerr << message << " at ";
644  tok.getLocation().dump(fSourceManager);
645  if (source) {
646  std::cerr << ":";
647  std::cerr << fSourceManager.getCharacterData(tok.getLocation());
648  }
649  std::cerr << '\n';
650  }
651 
652  bool ProcessOptions(LinkdefReader::Options &options,
653  clang::Preprocessor &PP,
654  clang::Token &tok) {
655  // Constructor parsing:
656  /* options=...
657  * possible options:
658  * nostreamer: set G__NOSTREAMER flag
659  * noinputoper: set G__NOINPUTOPERATOR flag
660  * evolution: set G__USEBYTECOUNT flag
661  * nomap: (ignored by roocling; prevents entry in ROOT's rootmap file)
662  * stub: (ignored by rootcling was a directly for CINT code generation)
663  * version(x): sets the version number of the class to x
664  */
665 
666  // We assume that the first toke in option or options
667  // assert( tok.getIdentifierInfo()->getName() != "option" or "options")
668 
669  PP.Lex(tok);
670  if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
671  Error("Error: the 'options' keyword must be followed by an '='", tok);
672  return false;
673  }
674 
675  PP.Lex(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") {
680  // For rlibmap rather than rootcling
681  // so ignore
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") {
686  // This was solely for CINT dictionary, ignore for now.
687  // options.fUseStubs = 1;
688  } else if (tok.getIdentifierInfo()->getName() == "version") {
689  clang::Token start = tok;
690  PP.Lex(tok);
691  if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
692  Error("Error: missing left parenthesis after version.", start);
693  return false;
694  }
695  PP.Lex(tok);
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);
700  return false;
701  }
702  if (!number.isLiteral()) {
703  std::cerr << "Error: Malformed version option, the value is not a non-negative number!";
704  Error("", tok);
705  }
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;
710 
711  if (noDigit) {
712  std::cerr << "Error: Malformed version option! \"" << verStr << "\" is not a non-negative number!";
713  Error("", start);
714  } else
715  options.fVersionNumber = atoi(verStr.c_str());
716  } else {
717  Error("Warning: ignoring unknown #pragma link option=", tok);
718  }
719  PP.Lex(tok);
720  if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
721  // no more options, we are done.
722  break;
723  }
724  PP.Lex(tok);
725  }
726  return true;
727  }
728 
729 };
730 
731 class PragmaExtraInclude : public LinkdefReaderPragmaHandler {
732 public:
733  PragmaExtraInclude(LinkdefReader &owner, clang::SourceManager &sm) :
734  // This handler only cares about "#pragma link"
735  LinkdefReaderPragmaHandler("extra_include", owner, sm) {
736  }
737 
738  void HandlePragma(clang::Preprocessor &PP,
739  clang::PragmaIntroducerKind Introducer,
740  clang::Token &tok) {
741  // Handle a #pragma found by the Preprocessor.
742 
743  // check whether we care about the pragma - we are a named handler,
744  // thus this could actually be transformed into an assert:
745  if (Introducer != clang::PIK_HashPragma) return; // only #pragma, not C-style.
746  if (!tok.getIdentifierInfo()) return; // must be "link"
747  if (tok.getIdentifierInfo()->getName() != "extra_include") return;
748 
749  PP.Lex(tok);
750  // if (DClient.hasErrorOccured()) {
751  // return;
752  // }
753  if (tok.is(clang::tok::eod)) {
754  Error("Warning - lonely pragma statement: ", tok);
755  return;
756  }
757  const char *start = fSourceManager.getCharacterData(tok.getLocation());
758  clang::Token end;
759  end.startToken(); // Initialize token.
760  while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
761  end = tok;
762  PP.Lex(tok);
763  }
764  if (tok.isNot(clang::tok::semi)) {
765  Error("Error: missing ; at end of rule", tok, false);
766  return;
767  }
768  if (end.is(clang::tok::unknown)) {
769  Error("Error: Unknown token!", tok);
770  } else {
771  llvm::StringRef include(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
772 
773  if (!fOwner.AddInclude(include)) {
774  Error("", tok);
775  }
776  }
777  }
778 };
779 
780 class PragmaIoReadInclude : public LinkdefReaderPragmaHandler {
781 public:
782  PragmaIoReadInclude(LinkdefReader &owner, clang::SourceManager &sm) :
783  // This handler only cares about "#pragma link"
784  LinkdefReaderPragmaHandler("read", owner, sm) {
785  }
786 
787  void HandlePragma(clang::Preprocessor &PP,
788  clang::PragmaIntroducerKind Introducer,
789  clang::Token &tok) {
790  // Handle a #pragma found by the Preprocessor.
791 
792  // check whether we care about the pragma - we are a named handler,
793  // thus this could actually be transformed into an assert:
794  if (Introducer != clang::PIK_HashPragma) return; // only #pragma, not C-style.
795  if (!tok.getIdentifierInfo()) return; // must be "link"
796  if (tok.getIdentifierInfo()->getName() != "read") return;
797 
798  PP.Lex(tok);
799  // if (DClient.hasErrorOccured()) {
800  // return;
801  // }
802  if (tok.is(clang::tok::eod)) {
803  Error("Warning - lonely pragma statement: ", tok);
804  return;
805  }
806  const char *start = fSourceManager.getCharacterData(tok.getLocation());
807  clang::Token end;
808  end.startToken(); // Initialize token.
809  while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
810  end = tok;
811  PP.Lex(tok);
812  }
813  // Pragma read rule do not need to end in a semi colon
814  // if (tok.isNot(clang::tok::semi)) {
815  // Error("Error: missing ; at end of rule",tok);
816  // return;
817  // }
818  if (end.is(clang::tok::unknown)) {
819  Error("Error: unknown token", tok);
820  } else {
821  llvm::StringRef rule_text(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
822 
823  std::string error_string;
824  ROOT::ProcessReadPragma(rule_text.str().c_str(), error_string);
825  if (!error_string.empty())
826  std::cerr << error_string;
827  //std::cerr << "Warning: #pragma read not yet handled: " << include.str() << "\n";
828  // if (!fOwner.AddInclude(include))
829  // {
830  // Error("",tok);
831  // }
832  }
833  }
834 };
835 
836 class PragmaLinkCollector : public LinkdefReaderPragmaHandler {
837  // Handles:
838  // #pragma link [spec] options=... class classname[+-!]
839  //
840 public:
841  PragmaLinkCollector(LinkdefReader &owner, clang::SourceManager &sm) :
842  // This handler only cares about "#pragma link"
843  LinkdefReaderPragmaHandler("link", owner, sm) {
844  }
845 
846  void HandlePragma(clang::Preprocessor &PP,
847  clang::PragmaIntroducerKind Introducer,
848  clang::Token &tok) {
849  // Handle a #pragma found by the Preprocessor.
850 
851  // check whether we care about the pragma - we are a named handler,
852  // thus this could actually be transformed into an assert:
853  if (Introducer != clang::PIK_HashPragma) return; // only #pragma, not C-style.
854  if (!tok.getIdentifierInfo()) return; // must be "link"
855  if (tok.getIdentifierInfo()->getName() != "link") return;
856 
857  PP.Lex(tok);
858 // if (DClient.hasErrorOccured()) {
859 // return;
860 // }
861  if (tok.is(clang::tok::eod)) {
862  Error("Warning - lonely pragma statement: ", tok);
863  return;
864  }
865  bool linkOn;
866  if (tok.isAnyIdentifier()) {
867  if ((tok.getIdentifierInfo()->getName() == "off")) {
868  linkOn = false;
869  } else if ((tok.getIdentifierInfo()->getName() == "C")) {
870  linkOn = true;
871  PP.Lex(tok);
872  if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
873  Error("Error ++ expected after '#pragma link C' at ", tok);
874  return;
875  }
876  } else {
877  Error("Error #pragma link should be followed by off or C", tok);
878  return;
879  }
880  } else {
881  Error("Error bad #pragma format. ", tok);
882  return;
883  }
884 
885  PP.Lex(tok);
886  if (tok.is(clang::tok::eod)) {
887  Error("Error no arguments after #pragma link C++/off: ", tok);
888  return;
889  }
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);
894  return;
895  }
896 
897  llvm::StringRef type = identifier->getName();
898 
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)) {
903  return;
904  }
905  if (tok.getIdentifierInfo()) type = tok.getIdentifierInfo()->getName();
906  }
907 
908  PP.LexUnexpandedToken(tok);
909  const char *start = fSourceManager.getCharacterData(tok.getLocation());
910  clang::Token end;
911  end.startToken(); // Initialize token.
912  while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
913  // PP.DumpToken(tok, true);
914  // llvm::errs() << "\n";
915  end = tok;
916  PP.LexUnexpandedToken(tok);
917  }
918 
919  if (tok.isNot(clang::tok::semi)) {
920  Error("Error: missing ; at end of rule", tok, false);
921  return;
922  }
923 
924  if (end.is(clang::tok::unknown)) {
925  if (!fOwner.AddRule(type.data(), "", linkOn, false, options.get())) {
926  Error(type.data(), tok, false);
927  }
928  } else {
929  llvm::StringRef identifier(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
930 
931  if (!fOwner.AddRule(type, identifier, linkOn, false, options.get())) {
932  Error(type.data(), tok, false);
933  }
934  }
935 // do {
936 // PP.Lex(tok);
937 // PP.DumpToken(tok, true);
938 // llvm::errs() << "\n";
939 // } while (tok.isNot(clang::tok::eod));
940  }
941 
942 };
943 
944 class PragmaCreateCollector : public LinkdefReaderPragmaHandler {
945 public:
946  PragmaCreateCollector(LinkdefReader &owner, clang::SourceManager &sm) :
947  // This handler only cares about "#pragma create"
948  LinkdefReaderPragmaHandler("create", owner, sm) {
949  }
950 
951  void HandlePragma(clang::Preprocessor &PP,
952  clang::PragmaIntroducerKind Introducer,
953  clang::Token &tok) {
954  // Handle a #pragma found by the Preprocessor.
955 
956  // check whether we care about the pragma - we are a named handler,
957  // thus this could actually be transformed into an assert:
958  if (Introducer != clang::PIK_HashPragma) return; // only #pragma, not C-style.
959  if (!tok.getIdentifierInfo()) return; // must be "link"
960  if (tok.getIdentifierInfo()->getName() != "create") return;
961 
962  PP.Lex(tok);
963  // if (DClient.hasErrorOccured()) {
964  // return;
965  // }
966  if (tok.is(clang::tok::eod)) {
967  Error("Warning - lonely pragma statement: ", tok);
968  return;
969  }
970  if ((tok.getIdentifierInfo()->getName() != "TClass")) {
971  Error("Error: currently only supporting TClass after '#pragma create':", tok);
972  return;
973  }
974 
975  PP.Lex(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)) {
979  end = tok;
980  PP.Lex(tok);
981  }
982 
983  if (tok.isNot(clang::tok::semi)) {
984  Error("Error: missing ; at end of rule", tok, false);
985  return;
986  }
987 
988  llvm::StringRef identifier(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
989 
990  if (!fOwner.AddRule("class", identifier, true, true)) {
991  Error("", tok);
992  }
993 
994 // do {
995 // PP.Lex(tok);
996 // PP.DumpToken(tok, true);
997 // llvm::errs() << "\n";
998 // } while (tok.isNot(clang::tok::eod));
999  };
1000 
1001 };
1002 
1003 
1004 // Parse using clang and its pragma handlers callbacks.
1005 bool LinkdefReader::Parse(SelectionRules &sr, llvm::StringRef code, const std::vector<std::string> &parserArgs, const char *llvmdir)
1006 {
1007  fSelectionRules = &sr;
1008 
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());
1012  }
1013 
1014  // Extract all #pragmas
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 /*Consumer*/,
1018  {} /*ModuleFileExtension*/, true /*OnlyLex*/);
1019 
1020  clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1021  clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1022  DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1023 
1024  PragmaLinkCollector pragmaLinkCollector(*this, pragmaCI->getASTContext().getSourceManager());
1025  PragmaCreateCollector pragmaCreateCollector(*this, pragmaCI->getASTContext().getSourceManager());
1026  PragmaExtraInclude pragmaExtraInclude(*this, pragmaCI->getASTContext().getSourceManager());
1027  PragmaIoReadInclude pragmaIoReadInclude(*this, pragmaCI->getASTContext().getSourceManager());
1028 
1029  PP.AddPragmaHandler(&pragmaLinkCollector);
1030  PP.AddPragmaHandler(&pragmaCreateCollector);
1031  PP.AddPragmaHandler(&pragmaExtraInclude);
1032  PP.AddPragmaHandler(&pragmaIoReadInclude);
1033 
1034  // Start parsing the specified input file.
1035  PP.EnterMainSourceFile();
1036  clang::Token tok;
1037  do {
1038  PP.Lex(tok);
1039  } while (tok.isNot(clang::tok::eof));
1040 
1041  fSelectionRules = 0;
1042  return 0 == DClient.getNumErrors();
1043 }
LinkdefReader::kUnion
@ kUnion
Definition: LinkdefReader.h:75
n
const Int_t n
Definition: legend1.C:16
LinkdefReader::PopulateCppMap
static void PopulateCppMap()
Definition: LinkdefReader.cxx:90
LinkdefReader::kFunction
@ kFunction
Definition: LinkdefReader.h:70
LinkdefReader::kNestedclasses
@ kNestedclasses
Definition: LinkdefReader.h:67
LinkdefReader::fIOConstructorTypesPtr
ROOT::TMetaUtils::RConstructorTypes * fIOConstructorTypesPtr
Definition: LinkdefReader.h:62
LinkdefReader::fLine
long fLine
Definition: LinkdefReader.h:58
ClassSelectionRule::SetRequestedVersionNumber
void SetRequestedVersionNumber(int version)
Definition: ClassSelectionRule.cxx:155
LinkdefReader::EPragmaNames
EPragmaNames
Definition: LinkdefReader.h:65
ROOT::TMetaUtils::ReplaceAll
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
Definition: TClingUtils.cxx:5018
ClassSelectionRule::SetRequestNoInputOperator
void SetRequestNoInputOperator(bool excl)
Definition: ClassSelectionRule.cxx:135
LinkdefReader::PopulatePragmaMap
static void PopulatePragmaMap()
Definition: LinkdefReader.cxx:64
ROOT::TMetaUtils::Warning
void Warning(const char *location, const char *va_(fmt),...)
Definition: TClingUtils.h:819
LinkdefReader::PragmaExtraInclude
friend class PragmaExtraInclude
Definition: LinkdefReader.h:56
LinkdefReader::kPragma
@ kPragma
Definition: LinkdefReader.h:84
ClassSelectionRule::SetRequestOnlyTClass
void SetRequestOnlyTClass(bool val)
Definition: ClassSelectionRule.cxx:140
LinkdefReader::kTypeDef
@ kTypeDef
Definition: LinkdefReader.h:73
SelectionRules::AddEnumSelectionRule
void AddEnumSelectionRule(const EnumSelectionRule &enumSel)
Definition: SelectionRules.cxx:69
ROOT::ProcessReadPragma
void ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.
Definition: RConversionRuleParser.cxx:885
SelectionRules.h
BaseSelectionRule::kNo
@ kNo
Definition: BaseSelectionRule.h:45
LinkdefReader::kAll
@ kAll
Definition: LinkdefReader.h:66
LinkdefReader::fCount
long fCount
Definition: LinkdefReader.h:59
LinkdefReader::PragmaLinkCollector
friend class PragmaLinkCollector
Definition: LinkdefReader.h:54
LinkdefReader::fgMapPragmaNames
static std::map< std::string, EPragmaNames > fgMapPragmaNames
Definition: LinkdefReader.h:93
LinkdefReader::kOperators
@ kOperators
Definition: LinkdefReader.h:77
RConversionRuleParser.h
LinkdefReader::kClass
@ kClass
Definition: LinkdefReader.h:72
LinkdefReader::kElse
@ kElse
Definition: LinkdefReader.h:88
LinkdefReader::Parse
bool Parse(SelectionRules &sr, llvm::StringRef code, const std::vector< std::string > &parserArgs, const char *llvmdir)
Definition: LinkdefReader.cxx:1005
LinkdefReader::kUnknown
@ kUnknown
Definition: LinkdefReader.h:80
LinkdefReader::AddInclude
bool AddInclude(const std::string &include)
Definition: LinkdefReader.cxx:113
ROOT::TMetaUtils::Info
void Info(const char *location, const char *va_(fmt),...)
Definition: TClingUtils.h:809
LinkdefReader::PragmaCreateCollector
friend class PragmaCreateCollector
Definition: LinkdefReader.h:53
ClassSelectionRule::SetRequestProtected
void SetRequestProtected(bool val)
Definition: ClassSelectionRule.cxx:145
ClassSelectionRule::SetRequestStreamerInfo
void SetRequestStreamerInfo(bool needStreamerInfo)
Definition: ClassSelectionRule.cxx:115
LinkdefReader::IsPatternRule
bool IsPatternRule(const std::string &rule_token)
Definition: LinkdefReader.cxx:497
LinkdefReader::kIfdef
@ kIfdef
Definition: LinkdefReader.h:85
LinkdefReader::kStruct
@ kStruct
Definition: LinkdefReader.h:76
LinkdefReader::AddRule
bool AddRule(const std::string &ruletype, const std::string &identifier, bool linkOn, bool requestOnlyTClass, Options *option=0)
Definition: LinkdefReader.cxx:127
ClassSelectionRule::SetRequestPrivate
void SetRequestPrivate(bool val)
Definition: ClassSelectionRule.cxx:150
VariableSelectionRule
Definition: VariableSelectionRule.h:25
TGeant4Unit::sr
static constexpr double sr
Definition: TGeant4SystemOfUnits.h:150
ClassSelectionRule::RequestStreamerInfo
bool RequestStreamerInfo() const
Definition: ClassSelectionRule.cxx:110
ClassSelectionRule
Definition: ClassSelectionRule.h:33
SelectionRules::SetHasFileNameRule
void SetHasFileNameRule(bool file_rule)
Definition: SelectionRules.h:152
LinkdefReader::fgMapCppNames
static std::map< std::string, ECppNames > fgMapCppNames
Definition: LinkdefReader.h:94
BaseSelectionRule::kYes
@ kYes
Definition: BaseSelectionRule.h:44
LinkdefReader::kEndif
@ kEndif
Definition: LinkdefReader.h:86
LinkdefReader::kEnum
@ kEnum
Definition: LinkdefReader.h:71
LinkdefReader::kIf
@ kIf
Definition: LinkdefReader.h:87
LinkdefReader::ProcessFunctionPrototype
bool ProcessFunctionPrototype(std::string &proto, bool &name)
Definition: LinkdefReader.cxx:514
LinkdefReader.h
LinkdefReader::fIncludes
std::string fIncludes
Definition: LinkdefReader.h:61
LinkdefReader::kIOCtorType
@ kIOCtorType
Definition: LinkdefReader.h:78
proto
const char * proto
Definition: civetweb.c:16604
ClassSelectionRule::SetRequestNoStreamer
void SetRequestNoStreamer(bool noStreamer)
Definition: ClassSelectionRule.cxx:125
LinkdefReader::LoadIncludes
bool LoadIncludes(std::string &extraInclude)
Definition: LinkdefReader.cxx:508
SelectionRules::AddFunctionSelectionRule
void AddFunctionSelectionRule(const FunctionSelectionRule &funcSel)
Definition: SelectionRules.cxx:49
BaseSelectionRule::SetAttributeValue
void SetAttributeValue(const std::string &attributeName, const std::string &attributeValue)
Definition: BaseSelectionRule.cxx:125
LinkdefReader::ProcessOperators
bool ProcessOperators(std::string &pattern)
Definition: LinkdefReader.cxx:569
SelectionRules::AddClassSelectionRule
void AddClassSelectionRule(const ClassSelectionRule &classSel)
Definition: SelectionRules.cxx:39
clang
Definition: BaseSelectionRule.h:29
BaseSelectionRule::SetSelected
void SetSelected(ESelect sel)
Definition: BaseSelectionRule.cxx:98
LinkdefReader::kNamespace
@ kNamespace
Definition: LinkdefReader.h:74
LinkdefReader::fSelectionRules
SelectionRules * fSelectionRules
Definition: LinkdefReader.h:60
name
char name[80]
Definition: TGX11.cxx:110
SelectionRules::GetHasFileNameRule
bool GetHasFileNameRule() const
Definition: SelectionRules.h:153
LinkdefReader::LinkdefReader
LinkdefReader(cling::Interpreter &interp, ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes)
Definition: LinkdefReader.cxx:101
LinkdefReader::fInterp
cling::Interpreter & fInterp
Definition: LinkdefReader.h:63
type
int type
Definition: TGX11.cxx:121
LinkdefReader::kIgnore
@ kIgnore
Definition: LinkdefReader.h:79
LinkdefReader::kDefinedIn
@ kDefinedIn
Definition: LinkdefReader.h:68
ROOT::TMetaUtils::RConstructorTypes
std::list< RConstructorType > RConstructorTypes
Definition: TClingUtils.h:321
SelectionRules::AddVariableSelectionRule
void AddVariableSelectionRule(const VariableSelectionRule &varSel)
Definition: SelectionRules.cxx:59
LinkdefReader::kGlobal
@ kGlobal
Definition: LinkdefReader.h:69
ClassSelectionRule::RequestNoStreamer
bool RequestNoStreamer() const
Definition: ClassSelectionRule.cxx:120
ROOT::TMetaUtils::propNames::pattern
static const std::string pattern("pattern")
SelectionRules
Definition: SelectionRules.h:92
Error
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
LinkdefReader
Definition: LinkdefReader.h:41
ROOT::TMetaUtils::RConstructorType
Definition: TClingUtils.h:310