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