Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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.
569bool LinkdefReader::ProcessOperators(std::string &pattern)
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.str())) {
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.str(), identifier.str(), 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.str(), 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{
1005 fSelectionRules = &sr;
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)
void SetRequestNoInputOperator(bool excl)
void SetRequestProtected(bool val)
void SetRequestedVersionNumber(int version)
void SetRequestPrivate(bool val)
void SetRequestNoStreamer(bool noStreamer)
void SetRequestOnlyTClass(bool val)
void SetRequestStreamerInfo(bool needStreamerInfo)
bool ProcessOptions(LinkdefReader::Options &options, clang::Preprocessor &PP, clang::Token &tok)
LinkdefReaderPragmaHandler(const char *which, LinkdefReader &owner, clang::SourceManager &sm)
void Error(const char *message, const clang::Token &tok, bool source=true)
clang::SourceManager & fSourceManager
bool ProcessOperators(std::string &pattern)
bool LoadIncludes(std::string &extraInclude)
SelectionRules * fSelectionRules
LinkdefReader(cling::Interpreter &interp, ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes)
bool ProcessFunctionPrototype(std::string &proto, bool &name)
static std::map< std::string, ECppNames > fgMapCppNames
cling::Interpreter & fInterp
bool IsPatternRule(const std::string &rule_token)
bool AddInclude(const std::string &include)
std::string fIncludes
bool Parse(SelectionRules &sr, llvm::StringRef code, const std::vector< std::string > &parserArgs, const char *llvmdir)
bool AddRule(const std::string &ruletype, const std::string &identifier, bool linkOn, bool requestOnlyTClass, Options *option=0)
static std::map< std::string, EPragmaNames > fgMapPragmaNames
static void PopulatePragmaMap()
static void PopulateCppMap()
ROOT::TMetaUtils::RConstructorTypes * fIOConstructorTypesPtr
PragmaCreateCollector(LinkdefReader &owner, clang::SourceManager &sm)
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
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
void Info(const char *location, const char *fmt,...)
std::list< RConstructorType > RConstructorTypes
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
void Warning(const char *location, const char *fmt,...)
void ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.