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:
632public:
633 LinkdefReaderPragmaHandler(const char *which, LinkdefReader &owner) :
634 // This handler only cares about "#pragma link"
635 clang::PragmaHandler(which), fOwner(owner) {
636 }
637
638 void Error(const char *message, const clang::Token &tok,
639 const clang::Preprocessor& PP, bool source = true) {
640
641 std::cerr << message << " at ";
642 const clang::SourceManager &SM = PP.getSourceManager();
643 tok.getLocation().dump(SM);
644 if (source) {
645 std::cerr << ":";
646 std::cerr << SM.getCharacterData(tok.getLocation());
647 }
648 std::cerr << '\n';
649 }
650
652 clang::Preprocessor &PP,
653 clang::Token &tok) {
654 // Constructor parsing:
655 /* options=...
656 * possible options:
657 * nostreamer: set G__NOSTREAMER flag
658 * noinputoper: set G__NOINPUTOPERATOR flag
659 * evolution: set G__USEBYTECOUNT flag
660 * nomap: (ignored by roocling; prevents entry in ROOT's rootmap file)
661 * stub: (ignored by rootcling was a directly for CINT code generation)
662 * version(x): sets the version number of the class to x
663 */
664
665 // We assume that the first toke in option or options
666 // assert( tok.getIdentifierInfo()->getName() != "option" or "options")
667
668 PP.Lex(tok);
669 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
670 Error("Error: the 'options' keyword must be followed by an '='", tok, PP);
671 return false;
672 }
673
674 PP.Lex(tok);
675 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
676 if (!tok.getIdentifierInfo()) {
677 Error("Error: Malformed version option.", tok, PP);
678 } else if (tok.getIdentifierInfo()->getName() == "nomap") {
679 // For rlibmap rather than rootcling
680 // so ignore
681 } else if (tok.getIdentifierInfo()->getName() == "nostreamer") options.fNoStreamer = 1;
682 else if (tok.getIdentifierInfo()->getName() == "noinputoper") options.fNoInputOper = 1;
683 else if (tok.getIdentifierInfo()->getName() == "evolution") options.fRequestStreamerInfo = 1;
684 else if (tok.getIdentifierInfo()->getName() == "stub") {
685 // This was solely for CINT dictionary, ignore for now.
686 // options.fUseStubs = 1;
687 } else if (tok.getIdentifierInfo()->getName() == "version") {
688 clang::Token start = tok;
689 PP.Lex(tok);
690 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
691 Error("Error: missing left parenthesis after version.", start, PP);
692 return false;
693 }
694 PP.Lex(tok);
695 clang::Token number = tok;
696 if (tok.isNot(clang::tok::eod)) PP.Lex(tok);
697 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
698 Error("Error: missing right parenthesis after version.", start, PP);
699 return false;
700 }
701 if (!number.isLiteral()) {
702 std::cerr << "Error: Malformed version option, the value is not a non-negative number!";
703 Error("", tok, PP);
704 }
705 std::string verStr(number.getLiteralData(), number.getLength());
706 bool noDigit = false;
707 for (std::string::size_type i = 0; i < verStr.size(); ++i)
708 if (!isdigit(verStr[i])) noDigit = true;
709
710 if (noDigit) {
711 std::cerr << "Error: Malformed version option! \"" << verStr << "\" is not a non-negative number!";
712 Error("", start, PP);
713 } else
714 options.fVersionNumber = atoi(verStr.c_str());
715 } else {
716 Error("Warning: ignoring unknown #pragma link option=", tok, PP);
717 }
718 PP.Lex(tok);
719 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
720 // no more options, we are done.
721 break;
722 }
723 PP.Lex(tok);
724 }
725 return true;
726 }
727
728};
729
731public:
733 // This handler only cares about "#pragma link"
734 LinkdefReaderPragmaHandler("extra_include", owner) {
735 }
736
737 void HandlePragma(clang::Preprocessor &PP,
738 clang::PragmaIntroducer Introducer,
739 clang::Token &tok) override {
740 // Handle a #pragma found by the Preprocessor.
741
742 // check whether we care about the pragma - we are a named handler,
743 // thus this could actually be transformed into an assert:
744 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
745 if (!tok.getIdentifierInfo()) return; // must be "link"
746 if (tok.getIdentifierInfo()->getName() != "extra_include") return;
747
748 PP.Lex(tok);
749 // if (DClient.hasErrorOccured()) {
750 // return;
751 // }
752 if (tok.is(clang::tok::eod)) {
753 Error("Warning - lonely pragma statement: ", tok, PP);
754 return;
755 }
756 const clang::SourceManager &SM = PP.getSourceManager();
757 const char *start = SM.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, PP, false);
766 return;
767 }
768 if (end.is(clang::tok::unknown)) {
769 Error("Error: Unknown token!", tok, PP);
770 } else {
771 llvm::StringRef include(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
772
773 if (!fOwner.AddInclude(include.str())) {
774 Error("", tok, PP);
775 }
776 }
777 }
778};
779
781public:
783 // This handler only cares about "#pragma link"
784 LinkdefReaderPragmaHandler("read", owner) {
785 }
786
787 void HandlePragma(clang::Preprocessor &PP,
788 clang::PragmaIntroducer Introducer,
789 clang::Token &tok) override {
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.Kind != 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, PP);
804 return;
805 }
806 const clang::SourceManager& SM = PP.getSourceManager();
807 const char *start = SM.getCharacterData(tok.getLocation());
808 clang::Token end;
809 end.startToken(); // Initialize token.
810 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
811 end = tok;
812 PP.Lex(tok);
813 }
814 // Pragma read rule do not need to end in a semi colon
815 // if (tok.isNot(clang::tok::semi)) {
816 // Error("Error: missing ; at end of rule",tok, PP);
817 // return;
818 // }
819 if (end.is(clang::tok::unknown)) {
820 Error("Error: unknown token", tok, PP);
821 } else {
822 llvm::StringRef rule_text(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
823
824 std::string error_string;
825 ROOT::ProcessReadPragma(rule_text.str().c_str(), error_string);
826 if (!error_string.empty())
827 std::cerr << error_string;
828 //std::cerr << "Warning: #pragma read not yet handled: " << include.str() << "\n";
829 // if (!fOwner.AddInclude(include))
830 // {
831 // Error("",tok);
832 // }
833 }
834 }
835};
836
838 // Handles:
839 // #pragma link [spec] options=... class classname[+-!]
840 //
841public:
843 // This handler only cares about "#pragma link"
844 LinkdefReaderPragmaHandler("link", owner) {
845 }
846
847 void HandlePragma(clang::Preprocessor &PP,
848 clang::PragmaIntroducer Introducer,
849 clang::Token &tok) override {
850 // Handle a #pragma found by the Preprocessor.
851
852 // check whether we care about the pragma - we are a named handler,
853 // thus this could actually be transformed into an assert:
854 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
855 if (!tok.getIdentifierInfo()) return; // must be "link"
856 if (tok.getIdentifierInfo()->getName() != "link") return;
857
858 PP.Lex(tok);
859// if (DClient.hasErrorOccured()) {
860// return;
861// }
862 if (tok.is(clang::tok::eod)) {
863 Error("Warning - lonely pragma statement: ", tok, PP);
864 return;
865 }
866 bool linkOn;
867 if (tok.isAnyIdentifier()) {
868 if ((tok.getIdentifierInfo()->getName() == "off")) {
869 linkOn = false;
870 } else if ((tok.getIdentifierInfo()->getName() == "C")) {
871 linkOn = true;
872 PP.Lex(tok);
873 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
874 Error("Error ++ expected after '#pragma link C' at ", tok, PP);
875 return;
876 }
877 } else {
878 Error("Error #pragma link should be followed by off or C", tok, PP);
879 return;
880 }
881 } else {
882 Error("Error bad #pragma format. ", tok, PP);
883 return;
884 }
885
886 PP.Lex(tok);
887 if (tok.is(clang::tok::eod)) {
888 Error("Error no arguments after #pragma link C++/off: ", tok, PP);
889 return;
890 }
891 auto identifier = tok.getIdentifierInfo();
892 if (identifier == nullptr) {
893 if (linkOn) Error("Error #pragma link C++ should be followed by identifier", tok, PP);
894 else Error("Error #pragma link off should be followed by identifier", tok, PP);
895 return;
896 }
897
898 llvm::StringRef type = identifier->getName();
899
900 std::unique_ptr<LinkdefReader::Options> options;
901 if (type == "options" || type == "option") {
902 options.reset(new LinkdefReader::Options());
903 if (!ProcessOptions(*options, PP, tok)) {
904 return;
905 }
906 if (tok.getIdentifierInfo()) type = tok.getIdentifierInfo()->getName();
907 }
908
909 PP.LexUnexpandedToken(tok);
910 const clang::SourceManager &SM = PP.getSourceManager();
911 const char *start = SM.getCharacterData(tok.getLocation());
912 clang::Token end;
913 end.startToken(); // Initialize token.
914 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
915 // PP.DumpToken(tok, true);
916 // llvm::errs() << "\n";
917 end = tok;
918 PP.LexUnexpandedToken(tok);
919 }
920
921 if (tok.isNot(clang::tok::semi)) {
922 Error("Error: missing ; at end of rule", tok, PP, false);
923 return;
924 }
925
926 if (end.is(clang::tok::unknown)) {
927 if (!fOwner.AddRule(type.data(), "", linkOn, false, options.get())) {
928 Error(type.data(), tok, PP, false);
929 }
930 } else {
931 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
932
933 if (!fOwner.AddRule(type.str(), identifier.str(), linkOn, false, options.get())) {
934 Error(type.data(), tok, PP, false);
935 }
936 }
937// do {
938// PP.Lex(tok);
939// PP.DumpToken(tok, true);
940// llvm::errs() << "\n";
941// } while (tok.isNot(clang::tok::eod));
942 }
943
944};
945
947public:
949 // This handler only cares about "#pragma create"
950 LinkdefReaderPragmaHandler("create", owner) {
951 }
952
953 void HandlePragma(clang::Preprocessor &PP,
954 clang::PragmaIntroducer Introducer,
955 clang::Token &tok) override {
956 // Handle a #pragma found by the Preprocessor.
957
958 // check whether we care about the pragma - we are a named handler,
959 // thus this could actually be transformed into an assert:
960 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
961 if (!tok.getIdentifierInfo()) return; // must be "link"
962 if (tok.getIdentifierInfo()->getName() != "create") return;
963
964 PP.Lex(tok);
965 // if (DClient.hasErrorOccured()) {
966 // return;
967 // }
968 if (tok.is(clang::tok::eod)) {
969 Error("Warning - lonely pragma statement: ", tok, PP);
970 return;
971 }
972 if ((tok.getIdentifierInfo()->getName() != "TClass")) {
973 Error("Error: currently only supporting TClass after '#pragma create':", tok, PP);
974 return;
975 }
976
977 PP.Lex(tok);
978 const clang::SourceManager &SM = PP.getSourceManager();
979 const char *start = SM.getCharacterData(tok.getLocation());
980 clang::Token end = tok;
981 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
982 end = tok;
983 PP.Lex(tok);
984 }
985
986 if (tok.isNot(clang::tok::semi)) {
987 Error("Error: missing ; at end of rule", tok, PP, false);
988 return;
989 }
990
991 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
992
993 if (!fOwner.AddRule("class", identifier.str(), true, true)) {
994 Error("", tok, PP);
995 }
996
997// do {
998// PP.Lex(tok);
999// PP.DumpToken(tok, true);
1000// llvm::errs() << "\n";
1001// } while (tok.isNot(clang::tok::eod));
1002 };
1003
1004};
1005
1006
1007// Parse using clang and its pragma handlers callbacks.
1008bool LinkdefReader::Parse(SelectionRules &sr, llvm::StringRef code, const std::vector<std::string> &parserArgs, const char *llvmdir)
1009{
1010 fSelectionRules = &sr;
1011
1012 std::vector<const char *> parserArgsC;
1013 for (size_t i = 0, n = parserArgs.size(); i < n; ++i) {
1014 parserArgsC.push_back(parserArgs[i].c_str());
1015 }
1016
1017 // Extract all #pragmas
1018 std::unique_ptr<llvm::MemoryBuffer> memBuf = llvm::MemoryBuffer::getMemBuffer(code, "CLING #pragma extraction");
1019 clang::CompilerInstance *pragmaCI = cling::CIFactory::createCI(std::move(memBuf), parserArgsC.size(),
1020 &parserArgsC[0], llvmdir, nullptr /*Consumer*/,
1021 {} /*ModuleFileExtension*/, true /*OnlyLex*/);
1022
1023 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1024 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1025 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1026
1027 // FIXME: Reduce the code duplication across these collector classes.
1028 PragmaLinkCollector pragmaLinkCollector(*this);
1029 PragmaCreateCollector pragmaCreateCollector(*this);
1030 PragmaExtraInclude pragmaExtraInclude(*this);
1031 PragmaIoReadInclude pragmaIoReadInclude(*this);
1032
1033 PP.AddPragmaHandler(&pragmaLinkCollector);
1034 PP.AddPragmaHandler(&pragmaCreateCollector);
1035 PP.AddPragmaHandler(&pragmaExtraInclude);
1036 PP.AddPragmaHandler(&pragmaIoReadInclude);
1037
1038 // Start parsing the specified input file.
1039 PP.EnterMainSourceFile();
1040 clang::Token tok;
1041 do {
1042 PP.Lex(tok);
1043 } while (tok.isNot(clang::tok::eof));
1044
1045 fSelectionRules = nullptr;
1046 return 0 == DClient.getNumErrors();
1047}
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:17536
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)
void Error(const char *message, const clang::Token &tok, const clang::Preprocessor &PP, bool source=true)
bool ProcessOperators(std::string &pattern)
bool LoadIncludes(std::string &extraInclude)
SelectionRules * fSelectionRules
LinkdefReader(cling::Interpreter &interp, ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes)
bool ProcessFunctionPrototype(std::string &proto, bool &name)
static std::map< std::string, ECppNames > fgMapCppNames
cling::Interpreter & fInterp
bool IsPatternRule(const std::string &rule_token)
bool AddInclude(const std::string &include)
std::string fIncludes
bool Parse(SelectionRules &sr, llvm::StringRef code, const std::vector< std::string > &parserArgs, const char *llvmdir)
static std::map< std::string, EPragmaNames > fgMapPragmaNames
static void PopulatePragmaMap()
static void PopulateCppMap()
bool AddRule(const std::string &ruletype, const std::string &identifier, bool linkOn, bool requestOnlyTClass, Options *option=nullptr)
ROOT::TMetaUtils::RConstructorTypes * fIOConstructorTypesPtr
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
PragmaCreateCollector(LinkdefReader &owner)
PragmaExtraInclude(LinkdefReader &owner)
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)
PragmaLinkCollector(LinkdefReader &owner)
void HandlePragma(clang::Preprocessor &PP, clang::PragmaIntroducer Introducer, clang::Token &tok) override
The class representing the collection of selection rules.
void AddVariableSelectionRule(const VariableSelectionRule &varSel)
void AddClassSelectionRule(const ClassSelectionRule &classSel)
bool GetHasFileNameRule() const
void AddEnumSelectionRule(const EnumSelectionRule &enumSel)
void AddFunctionSelectionRule(const FunctionSelectionRule &funcSel)
void SetHasFileNameRule(bool file_rule)
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.