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