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 int fRNTupleSplitMode; // 0: unset, -1: enforce unsplit, 1: enforce split
60};
61
62/*
63 This is a static function - which in our context means it is populated only ones
64 */
66{
67 if (!(fgMapPragmaNames.empty())) return; // if the map has already been populated, return, else populate it
68
86 // The following are listed here so we can officially ignore them
87 LinkdefReader::fgMapPragmaNames["nestedtypedefs"] = kIgnore;
89}
90
92{
93 if (!(fgMapCppNames.empty())) return; // if the map has already been populated, return, else populate it
94
100}
101
102LinkdefReader::LinkdefReader(cling::Interpreter &interp,
103 ROOT::TMetaUtils::RConstructorTypes &IOConstructorTypes):
104 fLine(1), fCount(0), fSelectionRules(nullptr), fIOConstructorTypesPtr(&IOConstructorTypes), fInterp(interp)
105{
108}
109
110/*
111 * The method records that 'include' has been explicitly requested in the linkdef file
112 * to be added to the dictionary and interpreter.
113 */
114bool LinkdefReader::AddInclude(const std::string& include)
115{
116 fIncludes += "#include ";
117 fIncludes += include;
118 fIncludes += "\n";
119
120 return true;
121}
122
123
124/*
125 * The method that processes the pragma statement.
126 * Sometimes I had to do strange things to reflect the strange behavior of rootcint
127 */
128bool LinkdefReader::AddRule(const std::string& ruletype,
129 const std::string& identifier,
130 bool linkOn,
131 bool request_only_tclass,
132 LinkdefReader::Options *options /* = 0 */)
133{
134
136 ROOT::TMetaUtils::Info("LinkdefReader::AddRule", "Ruletype is %s with the identifier %s\n", ruletype.c_str(), identifier.c_str());
137 auto it = fgMapPragmaNames.find(ruletype);
138 if (it != fgMapPragmaNames.end()) {
139 name = it->second;
140 }
141
142 switch (name) {
143 case kAll:
144 if (identifier == "globals" || identifier == "global") {
146 if (linkOn) {
147 vsr.SetAttributeValue("pattern", "*");
150 } else {
151 if (fSelectionRules->GetHasFileNameRule()) { // only if we had previous defined_in -> create that
152 // we don't create anything which is OK - if I don't have a selection rule for something
153 // this something will not be generated
154 // This is valid also for the other all ... cases
155 vsr.SetAttributeValue("pattern", "*");
158 }
159 }
160 //else vsr.SetSelected(BaseSelectionRule::kNo);
161 //fSelectionRules->AddVariableSelectionRule(vsr);
162
164 if (linkOn) {
166 esr.SetAttributeValue("pattern", "*");
168
169 //EnumSelectionRule esr2; //Problem wih the enums - if I deselect them here
172 esr2.SetAttributeValue("pattern", "*::*");
174 } else {
176 esr.SetAttributeValue("pattern", "*");
179 }
180 }
181 } else if (identifier == "functions" || identifier == "function") {
183 fsr.SetAttributeValue("pattern", "*");
184 if (linkOn) {
187 } else {
191 }
192 }
193 } else if (identifier == "classes" || identifier == "namespaces" ||
194 identifier == "class" || identifier == "namespace") {
195 if (linkOn) {
196
199 csr3.SetAttributeValue("pattern", "__va_*"); // don't generate for the built-in classes/structs
201
203 csr.SetAttributeValue("pattern", "*");
204 csr2.SetAttributeValue("pattern", "*::*");
205 csr.SetSelected(BaseSelectionRule::kYes);
207
210 } else {
213 csr.SetAttributeValue("pattern", "*");
214 csr2.SetAttributeValue("pattern", "*::*");
215
216 csr.SetSelected(BaseSelectionRule::kNo);
220 }
221 }
222 } else if (identifier == "typedefs" || identifier == "typedef") {
223 // Silently ignore
224 } else {
225 ROOT::TMetaUtils::Warning("Unimplemented pragma statement: %s\n",identifier.c_str());
226 return false;
227 }
228
229 break;
230 case kNestedclasses: {
231 // we don't really process that one
232 }
233 break;
234 case kDefinedIn: {
236
237 // add selection rules for everything
238 std::string localIdentifier(identifier);
239 if (localIdentifier.length() && localIdentifier[0] == '"' && localIdentifier[localIdentifier.length() - 1] == '"') {
240 localIdentifier = localIdentifier.substr(1, localIdentifier.length() - 2);
241 }
242
244 vsr.SetAttributeValue("pattern", "*");
245 vsr.SetAttributeValue("file_name", localIdentifier);
246 if (linkOn) vsr.SetSelected(BaseSelectionRule::kYes);
249
251 esr.SetAttributeValue("pattern", "*");
252 esr.SetAttributeValue("file_name", localIdentifier);
253 if (linkOn) esr.SetSelected(BaseSelectionRule::kYes);
256
258 fsr.SetAttributeValue("pattern", "*");
259 fsr.SetAttributeValue("file_name", localIdentifier);
260 if (linkOn) fsr.SetSelected(BaseSelectionRule::kYes);
263
265 csr.SetAttributeValue("pattern", "*");
266 csr2.SetAttributeValue("pattern", "*::*");
267
268 csr.SetAttributeValue("file_name", localIdentifier);
269 csr2.SetAttributeValue("file_name", localIdentifier);
270 if (linkOn) {
271 csr.SetSelected(BaseSelectionRule::kYes);
273 } else {
274 csr.SetSelected(BaseSelectionRule::kNo);
276 }
277 csr.SetRequestStreamerInfo(true);
278 csr2.SetRequestStreamerInfo(true);
281
282 }
283 break;
284
285 case kFunction: {
286 std::string localIdentifier(identifier);
287 bool name_or_proto = false; // if true = name, if flase = proto_name
288 if (!ProcessFunctionPrototype(localIdentifier, name_or_proto)) {
289 return false;
290 }
292 if (linkOn) fsr.SetSelected(BaseSelectionRule::kYes);
294 if (localIdentifier.at(localIdentifier.length() - 1) == '*') fsr.SetAttributeValue("pattern", localIdentifier);
295 else if (name_or_proto) fsr.SetAttributeValue("name", localIdentifier);
296 else {
297 int pos = localIdentifier.find("(*)"); //rootcint generates error here but I decided to implement that pattern
298 if (pos > -1) fsr.SetAttributeValue("proto_pattern", localIdentifier);
299 else {
300 // No multiline
301 ROOT::TMetaUtils::ReplaceAll(localIdentifier, "\\\n", "", true);
302 // Types: We do not do IO of functions, so it is safe to
303 // put in some heuristics
304 ROOT::TMetaUtils::ReplaceAll(localIdentifier, "ULong_t", "unsigned long");
305 ROOT::TMetaUtils::ReplaceAll(localIdentifier, "Long_t", "long");
306 ROOT::TMetaUtils::ReplaceAll(localIdentifier, "Int_t", "int");
307 // Remove space after/before the commas if any
308 ROOT::TMetaUtils::ReplaceAll(localIdentifier, ", ", ",", true);
309 ROOT::TMetaUtils::ReplaceAll(localIdentifier, " ,", ",", true);
310 // Remove any space before/after the ( as well
311 ROOT::TMetaUtils::ReplaceAll(localIdentifier, " (", "(", true);
312 ROOT::TMetaUtils::ReplaceAll(localIdentifier, "( ", "(", true);
313 ROOT::TMetaUtils::ReplaceAll(localIdentifier, " )", ")", true);
314 fsr.SetAttributeValue("proto_name", localIdentifier);
315 }
316 }
318
319 }
320 break;
321
322 case kOperators: {
323 std::string localIdentifier(identifier);
324 if (!ProcessOperators(localIdentifier)) // this creates the proto_pattern
325 return false;
326
328 if (linkOn) fsr.SetSelected(BaseSelectionRule::kYes);
330 fsr.SetAttributeValue("proto_pattern", localIdentifier);
332 }
333 break;
334 case kGlobal: {
336 if (linkOn) vsr.SetSelected(BaseSelectionRule::kYes);
338 if (IsPatternRule(identifier)) vsr.SetAttributeValue("pattern", identifier);
339 else vsr.SetAttributeValue("name", identifier);
341 }
342 break;
343 case kEnum: {
344
346 if (linkOn) esr.SetSelected(BaseSelectionRule::kYes);
348 if (IsPatternRule(identifier)) esr.SetAttributeValue("pattern", identifier);
349 else esr.SetAttributeValue("name", identifier);
351 }
352 break;
353 case kClass:
354 case kTypeDef:
355 case kNamespace:
356 case kUnion:
357 case kStruct: {
358 std::string localIdentifier(identifier);
360
361 if (request_only_tclass) {
362 csr.SetRequestOnlyTClass(true);
363 }
364 int len = localIdentifier.length();
365 if (len > 8) { // process class+protected and class+private
366 const std::string protStr("+protected");
367 const std::string privStr("+private");
368
369 if (localIdentifier.compare(0, protStr.length(), protStr) == 0) {
370 csr.SetRequestProtected(true);
371 localIdentifier.erase(0, protStr.length() + 1);
372 len = localIdentifier.length();
373 } else if (localIdentifier.compare(0, privStr.length(), privStr) == 0) {
374 csr.SetRequestPrivate(true);
375 localIdentifier.erase(0, privStr.length() + 1);
376 len = localIdentifier.length();
377 }
378 }
379 if (len > 1) { // process the +, -, -! endings of the classes
380
381 bool ending = false;
382 int where = 1;
383 while (!ending && where < len) {
384 char last = localIdentifier.at(len - where);
385 switch (last) {
386 case ';':
387 break;
388 case '+':
389 csr.SetRequestStreamerInfo(true);
390 break;
391 case '!':
393 break;
394 case '-':
395 csr.SetRequestNoStreamer(true);
396 break;
397 case ' ':
398 case '\t':
399 break;
400 default:
401 ending = true;
402 }
403 ++where;
404 }
405 if (options) {
406 if (options->fNoStreamer) csr.SetRequestNoStreamer(true);
407 if (options->fNoInputOper) csr.SetRequestNoInputOperator(true);
408 if (options->fRequestStreamerInfo) csr.SetRequestStreamerInfo(true);
409 if (options->fVersionNumber >= 0) csr.SetRequestedVersionNumber(options->fVersionNumber);
410 if (options->fRNTupleSplitMode != 0)
412 }
413 if (csr.RequestStreamerInfo() && csr.RequestNoStreamer()) {
414 std::cerr << "Warning: " << localIdentifier << " option + mutual exclusive with -, + prevails\n";
415 csr.SetRequestNoStreamer(false);
416 }
417 if (ending) {
418 localIdentifier.erase(len - (where - 2)); // We 'consumed' one of the class token
419 } else {
420 localIdentifier.erase(len - (where - 1));
421 }
422 }
423
424 if (linkOn) {
426
427 if (localIdentifier == "*") { // rootcint generates error here, but I decided to implement it
430 csr2.SetAttributeValue("pattern", "*::*");
432
435 csr3.SetAttributeValue("pattern", "__va_*");
437 }
438 } else {
440 if (localIdentifier == "*") { // rootcint generates error here, but I decided to implement it
443 csr2.SetAttributeValue("pattern", "*::*");
445
446 EnumSelectionRule esr(fCount++, fInterp); // we need this because of implicit/explicit rules - check my notes on rootcint
448 esr.SetAttributeValue("pattern", "*::*");
450
451 }
452 // Since the rootcling default is 'off' (we need to explicilty annotate to turn it on), the nested type and function
453 // should be off by default. Note that anyway, this is not yet relevant since the pcm actually ignore the on/off
454 // request and contains everything (for now).
455 // else {
456 // EnumSelectionRule esr(fCount++); // we need this because of implicit/explicit rules - check my notes on rootcint
457 // esr.SetSelected(BaseSelectionRule::kNo);
458 // esr.SetAttributeValue("pattern", localIdentifier+"::*");
459 // fSelectionRules->AddEnumSelectionRule(esr);
460
461 // if (fSelectionRules->GetHasFileNameRule()) {
462 // FunctionSelectionRule fsr(fCount++); // we need this because of implicit/explicit rules - check my notes on rootcint
463 // fsr.SetSelected(BaseSelectionRule::kNo);
464 // std::string value = localIdentifier + "::*";
465 // fsr.SetAttributeValue("pattern", value);
466 // fSelectionRules->AddFunctionSelectionRule(fsr);
467 // }
468 // }
469 }
470 if (IsPatternRule(localIdentifier)) {
471 csr.SetAttributeValue("pattern", localIdentifier);
472 }
473 csr.SetAttributeValue("name", localIdentifier);
474
475 if (name == kTypeDef) {
476 csr.SetAttributeValue("fromTypedef", "true");
477 }
478
480 //csr.PrintAttributes(std::cout,3);
481 }
482 break;
483 case kIOCtorType:
484 // #pragma link C++ IOCtorType typename;
486 break;
487 case kIgnore:
488 // All the pragma that were supported in CINT but are currently not relevant for CLING
489 // (mostly because we do not yet filter the dictionary/pcm).
490 break;
491 case kUnknown:
492 ROOT::TMetaUtils::Warning("Unimplemented pragma statement - it has no effect: %s\n", identifier.c_str());
493 return false;
494 break;
495 }
496
497 return true;
498}
499
500bool LinkdefReader::IsPatternRule(const std::string &rule_token)
501{
502 int pos = rule_token.find("*");
503 if (pos > -1) return true;
504 else return false;
505}
506
507/*
508 * The method records that 'include' has been explicitly requested in the linkdef file
509 * to be added to the dictionary and interpreter.
510 */
511bool LinkdefReader::LoadIncludes(std::string &extraIncludes)
512{
513 extraIncludes += fIncludes;
514 return cling::Interpreter::kSuccess == fInterp.declare(fIncludes);
515}
516
518{
519 int pos1, pos1_1, pos2, pos2_1;
520
521 pos1 = proto.find_first_of("(");
522 pos1_1 = proto.find_last_of("(");
523
524 if (pos1 != pos1_1) {
525 std::cout << "Error at line " << fLine << " - too many ( in function prototype!" << std::endl;
526 return false;
527 }
528
529 pos2 = proto.find_first_of(")");
530 pos2_1 = proto.find_last_of(")");
531
532 if (pos2 != pos2_1) {
533 std::cout << "Error at line " << fLine << " - too many ) in function prototype!" << std::endl;
534 return false;
535 }
536
537 if (pos1 > -1) {
538 if (pos2 < 0) {
539 std::cout << "Error at line " << fLine << " - missing ) in function prototype" << std::endl;
540 return false;
541 }
542 if (pos2 < pos1) {
543 std::cout << "Error at line " << fLine << " - wrong order of ( and ) in function prototype" << std::endl;
544 return false;
545 }
546
547 // I don't have to escape the *-s because in rootcint there is no pattern recognition
548 int pos3 = pos1;
549 while (true) {
550 pos3 = proto.find(" ", pos3);
551 if (pos3 > -1) {
552 proto.erase(pos3, 1);
553 }
554 if (pos3 < 0) break;
555 }
556 name = false;
557 } else {
558 if (pos2 > -1) {
559 std::cout << "Error at line " << fLine << " - missing ( in function prototype" << std::endl;
560 return false;
561 } else {
562 //std::cout<<"Debug - no prototype, name = true"<<std::endl;
563 name = true;
564 }
565 }
566 return true;
567}
568
569// This function is really very basic - it just checks whether everything is OK with the
570// spaces and if the number of opening < matches the number of >.
571// But it doesn't catch situations like vector>int<, etc.
572bool LinkdefReader::ProcessOperators(std::string &pattern)
573{
574 int pos = -1;
575 int pos1 = -1, pos2 = -1;
576 int open_br = 0, close_br = 0;
577 while (true) {
578 pos = pattern.find(" ", pos + 1);
579 pos1 = pattern.find("<", pos1 + 1);
580 pos2 = pattern.find(">", pos2 + 1);
581
582 if ((pos < 0) && (pos1 < 0) && (pos2 < 0)) break;
583
584 if (pos1 > -1) ++open_br;
585 if (pos2 > -1) ++close_br;
586
587 if (pos < 0) continue;
588 char before = '$';
589 char after = '$';
590 bool ok1 = false;
591 bool ok2 = false;
592
593 if (pos > 0) before = pattern.at(pos - 1);
594 if (pos < (int)(pattern.length() - 1)) after = pattern.at(pos + 1);
595
596 //std::cout<<"before: "<<before<<", after: "<<after<<", pos: "<<pos<<std::endl;
597 switch (before) {
598 case '<':
599 case ',':
600 case ' ':
601 ok1 = true;
602 break;
603 default:
604 ok1 = false;
605 }
606 switch (after) {
607 case '>':
608 case '<':
609 case ',':
610 case ' ':
611 ok2 = true;
612 break;
613 default:
614 ok2 = false;
615 }
616 //std::cout<<"ok1: "<<ok1<<", ok2: "<<ok2<<std::endl;
617 if (!ok1 && !ok2) {
618 std::cout << "Error at line " << fLine - 1 << " - extra space" << std::endl;
619 return false;
620 }
621 pattern.erase(pos, 1);
622 }
623
624 if (open_br != close_br) {
625 std::cout << "Error at line " << fLine << " - number of < doesn't match number of >" << std::endl;
626 return false;
627 }
628 pattern = "operator*(*" + pattern + "*)";
629 return true;
630}
631
632class LinkdefReaderPragmaHandler : public clang::PragmaHandler {
633protected:
635public:
636 LinkdefReaderPragmaHandler(const char *which, LinkdefReader &owner) :
637 // This handler only cares about "#pragma link"
638 clang::PragmaHandler(which), fOwner(owner) {
639 }
640
641 void Error(const char *message, const clang::Token &tok,
642 const clang::Preprocessor& PP, bool source = true) {
643
644 std::cerr << message << " at ";
645 const clang::SourceManager &SM = PP.getSourceManager();
646 tok.getLocation().dump(SM);
647 if (source) {
648 std::cerr << ":";
649 std::cerr << SM.getCharacterData(tok.getLocation());
650 }
651 std::cerr << '\n';
652 }
653
655 clang::Preprocessor &PP,
656 clang::Token &tok) {
657 // Constructor parsing:
658 /* options=...
659 * possible options:
660 * nostreamer: set G__NOSTREAMER flag
661 * noinputoper: set G__NOINPUTOPERATOR flag
662 * evolution: set G__USEBYTECOUNT flag
663 * nomap: (ignored by roocling; prevents entry in ROOT's rootmap file)
664 * stub: (ignored by rootcling was a directly for CINT code generation)
665 * version(x): sets the version number of the class to x
666 * rntuple[un]split: enforce split/unsplit encoding in RNTuple
667 */
668
669 // We assume that the first toke in option or options
670 // assert( tok.getIdentifierInfo()->getName() != "option" or "options")
671
672 PP.Lex(tok);
673 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::equal)) {
674 Error("Error: the 'options' keyword must be followed by an '='", tok, PP);
675 return false;
676 }
677
678 PP.Lex(tok);
679 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
680 if (!tok.getIdentifierInfo()) {
681 Error("Error: Malformed version option.", tok, PP);
682 } else if (tok.getIdentifierInfo()->getName() == "nomap") {
683 // For rlibmap rather than rootcling
684 // so ignore
685 } else if (tok.getIdentifierInfo()->getName() == "nostreamer") options.fNoStreamer = 1;
686 else if (tok.getIdentifierInfo()->getName() == "noinputoper") options.fNoInputOper = 1;
687 else if (tok.getIdentifierInfo()->getName() == "evolution") options.fRequestStreamerInfo = 1;
688 else if (tok.getIdentifierInfo()->getName() == "rntupleSplit") {
689 clang::Token start = tok;
690 PP.Lex(tok);
691 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
692 Error("Error: missing left parenthesis after rntupleSplit.", start, PP);
693 return false;
694 }
695 PP.Lex(tok);
696 clang::Token boolval = tok;
697 if (tok.isNot(clang::tok::eod))
698 PP.Lex(tok);
699 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
700 Error("Error: missing right parenthesis after rntupleSplit.", start, PP);
701 return false;
702 }
703 if (!boolval.getIdentifierInfo()) {
704 Error("Error: Malformed rntupleSplit option (either 'true' or 'false').", boolval, PP);
705 }
706
707 if (boolval.getIdentifierInfo()->getName() == "true") {
708 if (options.fRNTupleSplitMode == -1) {
709 Error("Error: Can only specify a single rntuple option "
710 "(either rntupleSplit(true) or rntupleSplit(false))",
711 boolval, PP);
712 } else {
713 options.fRNTupleSplitMode = 1;
714 }
715 } else if (boolval.getIdentifierInfo()->getName() == "false") {
716 if (options.fRNTupleSplitMode == 1) {
717 Error("Error: Can only specify a single rntuple option "
718 "(either rntupleSplit(true) or rntupleSplit(false))",
719 boolval, PP);
720 } else {
721 options.fRNTupleSplitMode = -1;
722 }
723 } else {
724 Error("Error: Malformed rntupleSplit option (either 'true' or 'false').", boolval, PP);
725 }
726 } else if (tok.getIdentifierInfo()->getName() == "stub") {
727 // This was solely for CINT dictionary, ignore for now.
728 // options.fUseStubs = 1;
729 } else if (tok.getIdentifierInfo()->getName() == "version") {
730 clang::Token start = tok;
731 PP.Lex(tok);
732 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::l_paren)) {
733 Error("Error: missing left parenthesis after version.", start, PP);
734 return false;
735 }
736 PP.Lex(tok);
737 clang::Token number = tok;
738 if (tok.isNot(clang::tok::eod)) PP.Lex(tok);
739 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::r_paren)) {
740 Error("Error: missing right parenthesis after version.", start, PP);
741 return false;
742 }
743 if (!number.isLiteral()) {
744 std::cerr << "Error: Malformed version option, the value is not a non-negative number!";
745 Error("", tok, PP);
746 }
747 std::string verStr(number.getLiteralData(), number.getLength());
748 bool noDigit = false;
749 for (std::string::size_type i = 0; i < verStr.size(); ++i)
750 if (!isdigit(verStr[i])) noDigit = true;
751
752 if (noDigit) {
753 std::cerr << "Error: Malformed version option! \"" << verStr << "\" is not a non-negative number!";
754 Error("", start, PP);
755 } else
756 options.fVersionNumber = atoi(verStr.c_str());
757 } else {
758 Error("Warning: ignoring unknown #pragma link option=", tok, PP);
759 }
760 PP.Lex(tok);
761 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::comma)) {
762 // no more options, we are done.
763 break;
764 }
765 PP.Lex(tok);
766 }
767 return true;
768 }
769
770};
771
773public:
775 // This handler only cares about "#pragma link"
776 LinkdefReaderPragmaHandler("extra_include", owner) {
777 }
778
779 void HandlePragma(clang::Preprocessor &PP,
780 clang::PragmaIntroducer Introducer,
781 clang::Token &tok) override {
782 // Handle a #pragma found by the Preprocessor.
783
784 // check whether we care about the pragma - we are a named handler,
785 // thus this could actually be transformed into an assert:
786 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
787 if (!tok.getIdentifierInfo()) return; // must be "link"
788 if (tok.getIdentifierInfo()->getName() != "extra_include") return;
789
790 PP.Lex(tok);
791 // if (DClient.hasErrorOccured()) {
792 // return;
793 // }
794 if (tok.is(clang::tok::eod)) {
795 Error("Warning - lonely pragma statement: ", tok, PP);
796 return;
797 }
798 const clang::SourceManager &SM = PP.getSourceManager();
799 const char *start = SM.getCharacterData(tok.getLocation());
800 clang::Token end;
801 end.startToken(); // Initialize token.
802 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
803 end = tok;
804 PP.Lex(tok);
805 }
806 if (tok.isNot(clang::tok::semi)) {
807 Error("Error: missing ; at end of rule", tok, PP, false);
808 return;
809 }
810 if (end.is(clang::tok::unknown)) {
811 Error("Error: Unknown token!", tok, PP);
812 } else {
813 llvm::StringRef include(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
814
815 if (!fOwner.AddInclude(include.str())) {
816 Error("", tok, PP);
817 }
818 }
819 }
820};
821
823public:
825 // This handler only cares about "#pragma link"
826 LinkdefReaderPragmaHandler("read", owner) {
827 }
828
829 void HandlePragma(clang::Preprocessor &PP,
830 clang::PragmaIntroducer Introducer,
831 clang::Token &tok) override {
832 // Handle a #pragma found by the Preprocessor.
833
834 // check whether we care about the pragma - we are a named handler,
835 // thus this could actually be transformed into an assert:
836 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
837 if (!tok.getIdentifierInfo()) return; // must be "link"
838 if (tok.getIdentifierInfo()->getName() != "read") return;
839
840 PP.Lex(tok);
841 // if (DClient.hasErrorOccured()) {
842 // return;
843 // }
844 if (tok.is(clang::tok::eod)) {
845 Error("Warning - lonely pragma statement: ", tok, PP);
846 return;
847 }
848 const clang::SourceManager& SM = PP.getSourceManager();
849 const char *start = SM.getCharacterData(tok.getLocation());
850 clang::Token end;
851 end.startToken(); // Initialize token.
852 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
853 end = tok;
854 PP.Lex(tok);
855 }
856 // Pragma read rule do not need to end in a semi colon
857 // if (tok.isNot(clang::tok::semi)) {
858 // Error("Error: missing ; at end of rule",tok, PP);
859 // return;
860 // }
861 if (end.is(clang::tok::unknown)) {
862 Error("Error: unknown token", tok, PP);
863 } else {
864 llvm::StringRef rule_text(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
865
866 std::string error_string;
867 ROOT::ProcessReadPragma(rule_text.str().c_str(), error_string);
868 if (!error_string.empty())
869 std::cerr << error_string;
870 //std::cerr << "Warning: #pragma read not yet handled: " << include.str() << "\n";
871 // if (!fOwner.AddInclude(include))
872 // {
873 // Error("",tok);
874 // }
875 }
876 }
877};
878
880 // Handles:
881 // #pragma link [spec] options=... class classname[+-!]
882 //
883public:
885 // This handler only cares about "#pragma link"
886 LinkdefReaderPragmaHandler("link", owner) {
887 }
888
889 void HandlePragma(clang::Preprocessor &PP,
890 clang::PragmaIntroducer Introducer,
891 clang::Token &tok) override {
892 // Handle a #pragma found by the Preprocessor.
893
894 // check whether we care about the pragma - we are a named handler,
895 // thus this could actually be transformed into an assert:
896 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
897 if (!tok.getIdentifierInfo()) return; // must be "link"
898 if (tok.getIdentifierInfo()->getName() != "link") return;
899
900 PP.Lex(tok);
901// if (DClient.hasErrorOccured()) {
902// return;
903// }
904 if (tok.is(clang::tok::eod)) {
905 Error("Warning - lonely pragma statement: ", tok, PP);
906 return;
907 }
908 bool linkOn;
909 if (tok.isAnyIdentifier()) {
910 if ((tok.getIdentifierInfo()->getName() == "off")) {
911 linkOn = false;
912 } else if ((tok.getIdentifierInfo()->getName() == "C")) {
913 linkOn = true;
914 PP.Lex(tok);
915 if (tok.is(clang::tok::eod) || tok.isNot(clang::tok::plusplus)) {
916 Error("Error ++ expected after '#pragma link C' at ", tok, PP);
917 return;
918 }
919 } else {
920 Error("Error #pragma link should be followed by off or C", tok, PP);
921 return;
922 }
923 } else {
924 Error("Error bad #pragma format. ", tok, PP);
925 return;
926 }
927
928 PP.Lex(tok);
929 if (tok.is(clang::tok::eod)) {
930 Error("Error no arguments after #pragma link C++/off: ", tok, PP);
931 return;
932 }
933 auto identifier = tok.getIdentifierInfo();
934 if (identifier == nullptr) {
935 if (linkOn) Error("Error #pragma link C++ should be followed by identifier", tok, PP);
936 else Error("Error #pragma link off should be followed by identifier", tok, PP);
937 return;
938 }
939
940 llvm::StringRef type = identifier->getName();
941
942 std::unique_ptr<LinkdefReader::Options> options;
943 if (type == "options" || type == "option") {
944 options.reset(new LinkdefReader::Options());
945 if (!ProcessOptions(*options, PP, tok)) {
946 return;
947 }
948 if (tok.getIdentifierInfo()) type = tok.getIdentifierInfo()->getName();
949 }
950
951 PP.LexUnexpandedToken(tok);
952 const clang::SourceManager &SM = PP.getSourceManager();
953 const char *start = SM.getCharacterData(tok.getLocation());
954 clang::Token end;
955 end.startToken(); // Initialize token.
956 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
957 // PP.DumpToken(tok, true);
958 // llvm::errs() << "\n";
959 end = tok;
960 PP.LexUnexpandedToken(tok);
961 }
962
963 if (tok.isNot(clang::tok::semi)) {
964 Error("Error: missing ; at end of rule", tok, PP, false);
965 return;
966 }
967
968 if (end.is(clang::tok::unknown)) {
969 if (!fOwner.AddRule(type.data(), "", linkOn, false, options.get())) {
970 Error(type.data(), tok, PP, false);
971 }
972 } else {
973 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
974
975 if (!fOwner.AddRule(type.str(), identifier.str(), linkOn, false, options.get())) {
976 Error(type.data(), tok, PP, false);
977 }
978 }
979// do {
980// PP.Lex(tok);
981// PP.DumpToken(tok, true);
982// llvm::errs() << "\n";
983// } while (tok.isNot(clang::tok::eod));
984 }
985
986};
987
989public:
991 // This handler only cares about "#pragma create"
992 LinkdefReaderPragmaHandler("create", owner) {
993 }
994
995 void HandlePragma(clang::Preprocessor &PP,
996 clang::PragmaIntroducer Introducer,
997 clang::Token &tok) override {
998 // Handle a #pragma found by the Preprocessor.
999
1000 // check whether we care about the pragma - we are a named handler,
1001 // thus this could actually be transformed into an assert:
1002 if (Introducer.Kind != clang::PIK_HashPragma) return; // only #pragma, not C-style.
1003 if (!tok.getIdentifierInfo()) return; // must be "link"
1004 if (tok.getIdentifierInfo()->getName() != "create") return;
1005
1006 PP.Lex(tok);
1007 // if (DClient.hasErrorOccured()) {
1008 // return;
1009 // }
1010 if (tok.is(clang::tok::eod)) {
1011 Error("Warning - lonely pragma statement: ", tok, PP);
1012 return;
1013 }
1014 if ((tok.getIdentifierInfo()->getName() != "TClass")) {
1015 Error("Error: currently only supporting TClass after '#pragma create':", tok, PP);
1016 return;
1017 }
1018
1019 PP.Lex(tok);
1020 const clang::SourceManager &SM = PP.getSourceManager();
1021 const char *start = SM.getCharacterData(tok.getLocation());
1022 clang::Token end = tok;
1023 while (tok.isNot(clang::tok::eod) && tok.isNot(clang::tok::semi)) {
1024 end = tok;
1025 PP.Lex(tok);
1026 }
1027
1028 if (tok.isNot(clang::tok::semi)) {
1029 Error("Error: missing ; at end of rule", tok, PP, false);
1030 return;
1031 }
1032
1033 llvm::StringRef identifier(start, SM.getCharacterData(end.getLocation()) - start + end.getLength());
1034
1035 if (!fOwner.AddRule("class", identifier.str(), true, true)) {
1036 Error("", tok, PP);
1037 }
1038
1039// do {
1040// PP.Lex(tok);
1041// PP.DumpToken(tok, true);
1042// llvm::errs() << "\n";
1043// } while (tok.isNot(clang::tok::eod));
1044 };
1045
1046};
1047
1048
1049// Parse using clang and its pragma handlers callbacks.
1050bool LinkdefReader::Parse(SelectionRules &sr, llvm::StringRef code, const std::vector<std::string> &parserArgs, const char *llvmdir)
1051{
1052 fSelectionRules = &sr;
1053
1054 std::vector<const char *> parserArgsC;
1055 for (size_t i = 0, n = parserArgs.size(); i < n; ++i) {
1056 parserArgsC.push_back(parserArgs[i].c_str());
1057 }
1058
1059 // Extract all #pragmas
1060 std::unique_ptr<llvm::MemoryBuffer> memBuf = llvm::MemoryBuffer::getMemBuffer(code, "CLING #pragma extraction");
1061 clang::CompilerInstance *pragmaCI = cling::CIFactory::createCI(std::move(memBuf), parserArgsC.size(),
1062 &parserArgsC[0], llvmdir, nullptr /*Consumer*/,
1063 {} /*ModuleFileExtension*/, true /*OnlyLex*/);
1064
1065 clang::Preprocessor &PP = pragmaCI->getPreprocessor();
1066 clang::DiagnosticConsumer &DClient = pragmaCI->getDiagnosticClient();
1067 DClient.BeginSourceFile(pragmaCI->getLangOpts(), &PP);
1068
1069 // FIXME: Reduce the code duplication across these collector classes.
1070 PragmaLinkCollector pragmaLinkCollector(*this);
1071 PragmaCreateCollector pragmaCreateCollector(*this);
1072 PragmaExtraInclude pragmaExtraInclude(*this);
1073 PragmaIoReadInclude pragmaIoReadInclude(*this);
1074
1075 PP.AddPragmaHandler(&pragmaLinkCollector);
1076 PP.AddPragmaHandler(&pragmaCreateCollector);
1077 PP.AddPragmaHandler(&pragmaExtraInclude);
1078 PP.AddPragmaHandler(&pragmaIoReadInclude);
1079
1080 // Start parsing the specified input file.
1081 PP.EnterMainSourceFile();
1082 clang::Token tok;
1083 do {
1084 PP.Lex(tok);
1085 } while (tok.isNot(clang::tok::eof));
1086
1087 fSelectionRules = nullptr;
1088 return 0 == DClient.getNumErrors();
1089}
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 SetRequestedRNTupleSplitMode(int splitMode)
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.