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"
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
46std::map<std::string, LinkdefReader::EPragmaNames> LinkdefReader::fgMapPragmaNames;
47std::map<std::string, LinkdefReader::ECppNames> LinkdefReader::fgMapCppNames;
48
51
54 union {
57 };
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;
88}
89
91{
92 if (!(fgMapCppNames.empty())) return; // if the map has already been populated, return, else populate it
93
99}
100
101LinkdefReader::LinkdefReader(cling::Interpreter &interp,
102 ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes):
103 fLine(1), fCount(0), fSelectionRules(nullptr), fIOConstructorTypesPtr(&IOConstructorTypes), fInterp(interp)
104{
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 */
113bool 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 */
127bool 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
202 csr.SetAttributeValue("pattern", "*");
203 csr2.SetAttributeValue("pattern", "*::*");
204 csr.SetSelected(BaseSelectionRule::kYes);
206
209 } else {
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
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 '!':
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;
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
497bool 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 */
508bool 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 while (true) {
575 pos = pattern.find(" ", pos + 1);
576 pos1 = pattern.find("<", pos1 + 1);
577 pos2 = pattern.find(">", pos2 + 1);
578
579 if ((pos < 0) && (pos1 < 0) && (pos2 < 0)) break;
580
581 if (pos1 > -1) ++open_br;
582 if (pos2 > -1) ++close_br;
583
584 if (pos < 0) continue;
585 char before = '$';
586 char after = '$';
587 bool ok1 = false;
588 bool ok2 = false;
589
590 if (pos > 0) before = pattern.at(pos - 1);
591 if (pos < (int)(pattern.length() - 1)) after = pattern.at(pos + 1);
592
593 //std::cout<<"before: "<<before<<", after: "<<after<<", pos: "<<pos<<std::endl;
594 switch (before) {
595 case '<':
596 case ',':
597 case ' ':
598 ok1 = true;
599 break;
600 default:
601 ok1 = false;
602 }
603 switch (after) {
604 case '>':
605 case '<':
606 case ',':
607 case ' ':
608 ok2 = true;
609 break;
610 default:
611 ok2 = false;
612 }
613 //std::cout<<"ok1: "<<ok1<<", ok2: "<<ok2<<std::endl;
614 if (!ok1 && !ok2) {
615 std::cout << "Error at line " << fLine - 1 << " - extra space" << std::endl;
616 return false;
617 }
618 pattern.erase(pos, 1);
619 }
620
621 if (open_br != close_br) {
622 std::cout << "Error at line " << fLine << " - number of < doesn't match number of >" << std::endl;
623 return false;
624 }
625 pattern = "operator*(*" + pattern + "*)";
626 return true;
627}
628
629class LinkdefReaderPragmaHandler : public clang::PragmaHandler {
630protected:
632 clang::SourceManager &fSourceManager;
633public:
634 LinkdefReaderPragmaHandler(const char *which, LinkdefReader &owner, clang::SourceManager &sm) :
635 // This handler only cares about "#pragma link"
636 clang::PragmaHandler(which), fOwner(owner), fSourceManager(sm) {
637 }
638
639 void Error(const char *message, const clang::Token &tok, bool source = true) {
640
641 std::cerr << message << " at ";
642 tok.getLocation().dump(fSourceManager);
643 if (source) {
644 std::cerr << ":";
645 std::cerr << fSourceManager.getCharacterData(tok.getLocation());
646 }
647 std::cerr << '\n';
648 }
649
651 clang::Preprocessor &PP,
652 clang::Token &tok) {
653 // Constructor parsing:
654 /* options=...
655 * possible options:
656 * nostreamer: set G__NOSTREAMER flag
657 * noinputoper: set G__NOINPUTOPERATOR flag
658 * evolution: set G__USEBYTECOUNT flag
659 * nomap: (ignored by roocling; prevents entry in ROOT's rootmap file)
660 * stub: (ignored by rootcling was a directly for CINT code generation)
661 * version(x): sets the version number of the class to x
662 */
663
664 // We assume that the first toke in option or options
665 // assert( tok.getIdentifierInfo()->getName() != "option" or "options")
666
667 PP.Lex(tok);
668 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
669 Error("Error: the 'options' keyword must be followed by an '='", tok);
670 return false;
671 }
672
673 PP.Lex(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") {
678 // For rlibmap rather than rootcling
679 // so ignore
680 } else if (tok.getIdentifierInfo()->getName() == "nostreamer") options.fNoStreamer = 1;
681 else if (tok.getIdentifierInfo()->getName() == "noinputoper") options.fNoInputOper = 1;
682 else if (tok.getIdentifierInfo()->getName() == "evolution") options.fRequestStreamerInfo = 1;
683 else if (tok.getIdentifierInfo()->getName() == "stub") {
684 // This was solely for CINT dictionary, ignore for now.
685 // options.fUseStubs = 1;
686 } else if (tok.getIdentifierInfo()->getName() == "version") {
687 clang::Token start = tok;
688 PP.Lex(tok);
689 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
690 Error("Error: missing left parenthesis after version.", start);
691 return false;
692 }
693 PP.Lex(tok);
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);
698 return false;
699 }
700 if (!number.isLiteral()) {
701 std::cerr << "Error: Malformed version option, the value is not a non-negative number!";
702 Error("", tok);
703 }
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;
708
709 if (noDigit) {
710 std::cerr << "Error: Malformed version option! \"" << verStr << "\" is not a non-negative number!";
711 Error("", start);
712 } else
713 options.fVersionNumber = atoi(verStr.c_str());
714 } else {
715 Error("Warning: ignoring unknown #pragma link option=", tok);
716 }
717 PP.Lex(tok);
718 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
719 // no more options, we are done.
720 break;
721 }
722 PP.Lex(tok);
723 }
724 return true;
725 }
726
727};
728
730public:
731 PragmaExtraInclude(LinkdefReader &owner, clang::SourceManager &sm) :
732 // This handler only cares about "#pragma link"
733 LinkdefReaderPragmaHandler("extra_include", owner, sm) {
734 }
735
736 void HandlePragma(clang::Preprocessor &PP,
737 clang::PragmaIntroducer Introducer,
738 clang::Token &tok) override {
739 // Handle a #pragma found by the Preprocessor.
740
741 // check whether we care about the pragma - we are a named handler,
742 // thus this could actually be transformed into an assert:
743 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
744 if (!tok.getIdentifierInfo()) return; // must be "link"
745 if (tok.getIdentifierInfo()->getName() != "extra_include") return;
746
747 PP.Lex(tok);
748 // if (DClient.hasErrorOccured()) {
749 // return;
750 // }
751 if (tok.is(clang::tok::eod)) {
752 Error("Warning - lonely pragma statement: ", tok);
753 return;
754 }
755 const char *start = fSourceManager.getCharacterData(tok.getLocation());
756 clang::Token end;
757 end.startToken(); // Initialize token.
758 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
759 end = tok;
760 PP.Lex(tok);
761 }
762 if (tok.isNot(clang::tok::semi)) {
763 Error("Error: missing ; at end of rule", tok, false);
764 return;
765 }
766 if (end.is(clang::tok::unknown)) {
767 Error("Error: Unknown token!", tok);
768 } else {
769 llvm::StringRef include(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
770
771 if (!fOwner.AddInclude(include)) {
772 Error("", tok);
773 }
774 }
775 }
776};
777
779public:
780 PragmaIoReadInclude(LinkdefReader &owner, clang::SourceManager &sm) :
781 // This handler only cares about "#pragma link"
782 LinkdefReaderPragmaHandler("read", owner, sm) {
783 }
784
785 void HandlePragma(clang::Preprocessor &PP,
786 clang::PragmaIntroducer Introducer,
787 clang::Token &tok) override {
788 // Handle a #pragma found by the Preprocessor.
789
790 // check whether we care about the pragma - we are a named handler,
791 // thus this could actually be transformed into an assert:
792 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
793 if (!tok.getIdentifierInfo()) return; // must be "link"
794 if (tok.getIdentifierInfo()->getName() != "read") return;
795
796 PP.Lex(tok);
797 // if (DClient.hasErrorOccured()) {
798 // return;
799 // }
800 if (tok.is(clang::tok::eod)) {
801 Error("Warning - lonely pragma statement: ", tok);
802 return;
803 }
804 const char *start = fSourceManager.getCharacterData(tok.getLocation());
805 clang::Token end;
806 end.startToken(); // Initialize token.
807 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
808 end = tok;
809 PP.Lex(tok);
810 }
811 // Pragma read rule do not need to end in a semi colon
812 // if (tok.isNot(clang::tok::semi)) {
813 // Error("Error: missing ; at end of rule",tok);
814 // return;
815 // }
816 if (end.is(clang::tok::unknown)) {
817 Error("Error: unknown token", tok);
818 } else {
819 llvm::StringRef rule_text(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
820
821 std::string error_string;
822 ROOT::ProcessReadPragma(rule_text.str().c_str(), error_string);
823 if (!error_string.empty())
824 std::cerr << error_string;
825 //std::cerr << "Warning: #pragma read not yet handled: " << include.str() << "\n";
826 // if (!fOwner.AddInclude(include))
827 // {
828 // Error("",tok);
829 // }
830 }
831 }
832};
833
835 // Handles:
836 // #pragma link [spec] options=... class classname[+-!]
837 //
838public:
839 PragmaLinkCollector(LinkdefReader &owner, clang::SourceManager &sm) :
840 // This handler only cares about "#pragma link"
841 LinkdefReaderPragmaHandler("link", owner, sm) {
842 }
843
844 void HandlePragma(clang::Preprocessor &PP,
845 clang::PragmaIntroducer Introducer,
846 clang::Token &tok) override {
847 // Handle a #pragma found by the Preprocessor.
848
849 // check whether we care about the pragma - we are a named handler,
850 // thus this could actually be transformed into an assert:
851 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
852 if (!tok.getIdentifierInfo()) return; // must be "link"
853 if (tok.getIdentifierInfo()->getName() != "link") return;
854
855 PP.Lex(tok);
856// if (DClient.hasErrorOccured()) {
857// return;
858// }
859 if (tok.is(clang::tok::eod)) {
860 Error("Warning - lonely pragma statement: ", tok);
861 return;
862 }
863 bool linkOn;
864 if (tok.isAnyIdentifier()) {
865 if ((tok.getIdentifierInfo()->getName() == "off")) {
866 linkOn = false;
867 } else if ((tok.getIdentifierInfo()->getName() == "C")) {
868 linkOn = true;
869 PP.Lex(tok);
870 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
871 Error("Error ++ expected after '#pragma link C' at ", tok);
872 return;
873 }
874 } else {
875 Error("Error #pragma link should be followed by off or C", tok);
876 return;
877 }
878 } else {
879 Error("Error bad #pragma format. ", tok);
880 return;
881 }
882
883 PP.Lex(tok);
884 if (tok.is(clang::tok::eod)) {
885 Error("Error no arguments after #pragma link C++/off: ", tok);
886 return;
887 }
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);
892 return;
893 }
894
895 llvm::StringRef type = identifier->getName();
896
897 std::unique_ptr<LinkdefReader::Options> options;
898 if (type == "options" || type == "option") {
899 options.reset(new LinkdefReader::Options());
900 if (!ProcessOptions(*options, PP, tok)) {
901 return;
902 }
903 if (tok.getIdentifierInfo()) type = tok.getIdentifierInfo()->getName();
904 }
905
906 PP.LexUnexpandedToken(tok);
907 const char *start = fSourceManager.getCharacterData(tok.getLocation());
908 clang::Token end;
909 end.startToken(); // Initialize token.
910 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
911 // PP.DumpToken(tok, true);
912 // llvm::errs() << "\n";
913 end = tok;
914 PP.LexUnexpandedToken(tok);
915 }
916
917 if (tok.isNot(clang::tok::semi)) {
918 Error("Error: missing ; at end of rule", tok, false);
919 return;
920 }
921
922 if (end.is(clang::tok::unknown)) {
923 if (!fOwner.AddRule(type.data(), "", linkOn, false, options.get())) {
924 Error(type.data(), tok, false);
925 }
926 } else {
927 llvm::StringRef identifier(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
928
929 if (!fOwner.AddRule(type, identifier, linkOn, false, options.get())) {
930 Error(type.data(), tok, false);
931 }
932 }
933// do {
934// PP.Lex(tok);
935// PP.DumpToken(tok, true);
936// llvm::errs() << "\n";
937// } while (tok.isNot(clang::tok::eod));
938 }
939
940};
941
943public:
944 PragmaCreateCollector(LinkdefReader &owner, clang::SourceManager &sm) :
945 // This handler only cares about "#pragma create"
946 LinkdefReaderPragmaHandler("create", owner, sm) {
947 }
948
949 void HandlePragma(clang::Preprocessor &PP,
950 clang::PragmaIntroducer Introducer,
951 clang::Token &tok) override {
952 // Handle a #pragma found by the Preprocessor.
953
954 // check whether we care about the pragma - we are a named handler,
955 // thus this could actually be transformed into an assert:
956 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
957 if (!tok.getIdentifierInfo()) return; // must be "link"
958 if (tok.getIdentifierInfo()->getName() != "create") return;
959
960 PP.Lex(tok);
961 // if (DClient.hasErrorOccured()) {
962 // return;
963 // }
964 if (tok.is(clang::tok::eod)) {
965 Error("Warning - lonely pragma statement: ", tok);
966 return;
967 }
968 if ((tok.getIdentifierInfo()->getName() != "TClass")) {
969 Error("Error: currently only supporting TClass after '#pragma create':", tok);
970 return;
971 }
972
973 PP.Lex(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)) {
977 end = tok;
978 PP.Lex(tok);
979 }
980
981 if (tok.isNot(clang::tok::semi)) {
982 Error("Error: missing ; at end of rule", tok, false);
983 return;
984 }
985
986 llvm::StringRef identifier(start, fSourceManager.getCharacterData(end.getLocation()) - start + end.getLength());
987
988 if (!fOwner.AddRule("class", identifier, true, true)) {
989 Error("", tok);
990 }
991
992// do {
993// PP.Lex(tok);
994// PP.DumpToken(tok, true);
995// llvm::errs() << "\n";
996// } while (tok.isNot(clang::tok::eod));
997 };
998
999};
1000
1001
1002// Parse using clang and its pragma handlers callbacks.
1003bool LinkdefReader::Parse(SelectionRules &sr, llvm::StringRef code, const std::vector<std::string> &parserArgs, const char *llvmdir)
1004{
1006
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());
1010 }
1011
1012 // Extract all #pragmas
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 /*Consumer*/,
1016 {} /*ModuleFileExtension*/, true /*OnlyLex*/);
1017
1018 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1019 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1020 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1021
1022 PragmaLinkCollector pragmaLinkCollector(*this, pragmaCI->getASTContext().getSourceManager());
1023 PragmaCreateCollector pragmaCreateCollector(*this, pragmaCI->getASTContext().getSourceManager());
1024 PragmaExtraInclude pragmaExtraInclude(*this, pragmaCI->getASTContext().getSourceManager());
1025 PragmaIoReadInclude pragmaIoReadInclude(*this, pragmaCI->getASTContext().getSourceManager());
1026
1027 PP.AddPragmaHandler(&pragmaLinkCollector);
1028 PP.AddPragmaHandler(&pragmaCreateCollector);
1029 PP.AddPragmaHandler(&pragmaExtraInclude);
1030 PP.AddPragmaHandler(&pragmaIoReadInclude);
1031
1032 // Start parsing the specified input file.
1033 PP.EnterMainSourceFile();
1034 clang::Token tok;
1035 do {
1036 PP.Lex(tok);
1037 } while (tok.isNot(clang::tok::eof));
1038
1039 fSelectionRules = nullptr;
1040 return 0 == DClient.getNumErrors();
1041}
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
char name[80]
Definition: TGX11.cxx:110
const char * proto
Definition: civetweb.c:17502
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
Definition: LinkdefReader.h:60
LinkdefReader(cling::Interpreter &interp, ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes)
bool ProcessFunctionPrototype(std::string &proto, bool &name)
static std::map< std::string, ECppNames > fgMapCppNames
Definition: LinkdefReader.h:94
cling::Interpreter & fInterp
Definition: LinkdefReader.h:63
bool IsPatternRule(const std::string &rule_token)
bool AddInclude(const std::string &include)
std::string fIncludes
Definition: LinkdefReader.h:61
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
Definition: LinkdefReader.h:93
static void PopulatePragmaMap()
static void PopulateCppMap()
ROOT::TMetaUtils::RConstructorTypes * fIOConstructorTypesPtr
Definition: LinkdefReader.h:62
PragmaCreateCollector(LinkdefReader &owner, clang::SourceManager &sm)
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
PragmaExtraInclude(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)
const Int_t n
Definition: legend1.C:16
static const std::string pattern("pattern")
void Info(const char *location, const char *fmt,...)
Definition: TClingUtils.h:809
std::list< RConstructorType > RConstructorTypes
Definition: TClingUtils.h:321
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
void Warning(const char *location, const char *fmt,...)
Definition: TClingUtils.h:819
void ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.
static constexpr double sr