clang: lib/Lex/ModuleMapFile.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
22#include "llvm/ADT/STLExtras.h"
23#include
24
25using namespace clang;
27
28namespace {
29struct MMToken {
30 enum TokenKind {
31 Comma,
32 ConfigMacros,
33 Conflict,
34 EndOfFile,
35 HeaderKeyword,
36 Identifier,
37 Exclaim,
38 ExcludeKeyword,
39 ExplicitKeyword,
40 ExportKeyword,
41 ExportAsKeyword,
42 ExternKeyword,
43 FrameworkKeyword,
44 LinkKeyword,
45 ModuleKeyword,
46 Period,
47 PrivateKeyword,
48 UmbrellaKeyword,
49 UseKeyword,
50 RequiresKeyword,
51 Star,
52 StringLiteral,
53 IntegerLiteral,
54 TextualKeyword,
55 LBrace,
56 RBrace,
57 LSquare,
58 RSquare
59 } Kind;
60
61 SourceLocation::UIntTy Location;
62 unsigned StringLength;
63 union {
64
65 const char *StringData;
66
67
69 };
70
71 void clear() {
72 Kind = EndOfFile;
73 Location = 0;
74 StringLength = 0;
75 StringData = nullptr;
76 }
77
78 bool is(TokenKind K) const { return Kind == K; }
79
80 SourceLocation getLocation() const {
81 return SourceLocation::getFromRawEncoding(Location);
82 }
83
85 return Kind == IntegerLiteral ? IntegerValue : 0;
86 }
87
88 StringRef getString() const {
89 return Kind == IntegerLiteral ? StringRef()
90 : StringRef(StringData, StringLength);
91 }
92};
93
94struct ModuleMapFileParser {
95
96 Lexer &L;
97 DiagnosticsEngine &Diags;
98
99
100 ModuleMapFile MMF{};
101
102 bool HadError = false;
103
104
105 MMToken Tok{};
106
107 bool parseTopLevelDecls();
108 std::optional parseModuleDecl(bool TopLevel);
109 std::optional parseExternModuleDecl();
110 std::optional parseConfigMacrosDecl();
111 std::optional parseConflictDecl();
112 std::optional parseExportDecl();
113 std::optional parseExportAsDecl();
114 std::optional parseUseDecl();
115 std::optional parseRequiresDecl();
116 std::optional parseHeaderDecl(MMToken::TokenKind LeadingToken,
117 SourceLocation LeadingLoc);
118 std::optional parseExcludeDecl(clang::SourceLocation LeadingLoc);
119 std::optional
120 parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
121 std::optional parseLinkDecl();
122
123 SourceLocation consumeToken();
124 void skipUntil(MMToken::TokenKind K);
125 bool parseModuleId(ModuleId &Id);
126 bool parseOptionalAttributes(ModuleAttributes &Attrs);
127
128 SourceLocation getLocation() const { return Tok.getLocation(); };
129};
130
131std::string formatModuleId(const ModuleId &Id) {
132 std::string result;
133 {
134 llvm::raw_string_ostream OS(result);
135
136 for (unsigned I = 0, N = Id.size(); I != N; ++I) {
137 if (I)
138 OS << ".";
139 OS << Id[I].first;
140 }
141 }
142
143 return result;
144}
145}
146
147std::optional
150 bool IsSystem, unsigned *Offset) {
151 std::optionalllvm::MemoryBufferRef Buffer = SM.getBufferOrNone(ID);
153 LOpts.LangStd = clang::LangStandard::lang_c99;
154 Lexer L(SM.getLocForStartOfFile(ID), LOpts, Buffer->getBufferStart(),
155 Buffer->getBufferStart() + (Offset ? *Offset : 0),
156 Buffer->getBufferEnd());
158
159 ModuleMapFileParser Parser{L, Diags};
160 bool Failed = Parser.parseTopLevelDecls();
161
162 if (Offset) {
163 auto Loc = SM.getDecomposedLoc(Parser.getLocation());
164 assert(Loc.first == ID && "stopped in a different file?");
165 *Offset = Loc.second;
166 }
167
168 if (Failed)
169 return std::nullopt;
171 Parser.MMF.Dir = Dir;
172 Parser.MMF.Start = Start;
173 Parser.MMF.IsSystem = IsSystem;
174 return std::move(Parser.MMF);
175}
176
177bool ModuleMapFileParser::parseTopLevelDecls() {
178 Tok.clear();
179 consumeToken();
180 do {
181 switch (Tok.Kind) {
182 case MMToken::EndOfFile:
183 return HadError;
184 case MMToken::ExternKeyword: {
185 std::optional EMD = parseExternModuleDecl();
186 if (EMD)
187 MMF.Decls.push_back(std::move(*EMD));
188 break;
189 }
190 case MMToken::ExplicitKeyword:
191 case MMToken::ModuleKeyword:
192 case MMToken::FrameworkKeyword: {
193 std::optional MD = parseModuleDecl(true);
194 if (MD)
195 MMF.Decls.push_back(std::move(*MD));
196 break;
197 }
198 case MMToken::Comma:
199 case MMToken::ConfigMacros:
200 case MMToken::Conflict:
201 case MMToken::Exclaim:
202 case MMToken::ExcludeKeyword:
203 case MMToken::ExportKeyword:
204 case MMToken::ExportAsKeyword:
205 case MMToken::HeaderKeyword:
206 case MMToken::Identifier:
207 case MMToken::LBrace:
208 case MMToken::LinkKeyword:
209 case MMToken::LSquare:
210 case MMToken::Period:
211 case MMToken::PrivateKeyword:
212 case MMToken::RBrace:
213 case MMToken::RSquare:
214 case MMToken::RequiresKeyword:
215 case MMToken::Star:
216 case MMToken::StringLiteral:
217 case MMToken::IntegerLiteral:
218 case MMToken::TextualKeyword:
219 case MMToken::UmbrellaKeyword:
220 case MMToken::UseKeyword:
222 HadError = true;
223 consumeToken();
224 break;
225 }
226 } while (true);
227}
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247std::optional ModuleMapFileParser::parseModuleDecl(bool TopLevel) {
248 assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
249 Tok.is(MMToken::FrameworkKeyword));
250
251 ModuleDecl MDecl;
252
253 SourceLocation ExplicitLoc;
256
257
258 if (Tok.is(MMToken::ExplicitKeyword)) {
259 MDecl.Location = ExplicitLoc = consumeToken();
261 }
262
263
264 if (Tok.is(MMToken::FrameworkKeyword)) {
265 SourceLocation FrameworkLoc = consumeToken();
267 MDecl.Location = FrameworkLoc;
269 }
270
271
272 if (.is(MMToken::ModuleKeyword)) {
274 consumeToken();
275 HadError = true;
276 return std::nullopt;
277 }
278 SourceLocation ModuleLoc = consumeToken();
280 MDecl.Location = ModuleLoc;
281
282
283
284 if (Tok.is(MMToken::Star)) {
285 SourceLocation StarLoc = consumeToken();
286 MDecl.Id.push_back({"*", StarLoc});
287 if (TopLevel && !MDecl.Framework) {
288 Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
289 HadError = true;
290 return std::nullopt;
291 }
292 } else {
293
294 if (parseModuleId(MDecl.Id)) {
295 HadError = true;
296 return std::nullopt;
297 }
298 if (!TopLevel) {
299 if (MDecl.Id.size() > 1) {
300 Diags.Report(MDecl.Id.front().second,
301 diag::err_mmap_nested_submodule_id)
302 << SourceRange(MDecl.Id.front().second, MDecl.Id.back().second);
303
304 HadError = true;
305 }
306 } else if (MDecl.Id.size() == 1 && MDecl.Explicit) {
307
308 Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
310 HadError = true;
311 }
312 }
313
314
315 if (parseOptionalAttributes(MDecl.Attrs))
316 return std::nullopt;
317
318
319 if (.is(MMToken::LBrace)) {
321 << MDecl.Id.back().first;
322 HadError = true;
323 return std::nullopt;
324 }
325 SourceLocation LBraceLoc = consumeToken();
326
327 bool Done = false;
328 do {
329 std::optional SubDecl;
330 switch (Tok.Kind) {
331 case MMToken::EndOfFile:
332 case MMToken::RBrace:
333 Done = true;
334 break;
335
336 case MMToken::ConfigMacros:
337
338 if (!TopLevel)
340 SubDecl = parseConfigMacrosDecl();
341 break;
342
343 case MMToken::Conflict:
344 SubDecl = parseConflictDecl();
345 break;
346
347 case MMToken::ExternKeyword:
348 SubDecl = parseExternModuleDecl();
349 break;
350
351 case MMToken::ExplicitKeyword:
352 case MMToken::FrameworkKeyword:
353 case MMToken::ModuleKeyword:
354 SubDecl = parseModuleDecl(false);
355 break;
356
357 case MMToken::ExportKeyword:
358 SubDecl = parseExportDecl();
359 break;
360
361 case MMToken::ExportAsKeyword:
362 if (!TopLevel) {
364 parseExportAsDecl();
365 } else
366 SubDecl = parseExportAsDecl();
367 break;
368
369 case MMToken::UseKeyword:
370 SubDecl = parseUseDecl();
371 break;
372
373 case MMToken::RequiresKeyword:
374 SubDecl = parseRequiresDecl();
375 break;
376
377 case MMToken::TextualKeyword:
378 SubDecl = parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
379 break;
380
381 case MMToken::UmbrellaKeyword: {
382 SourceLocation UmbrellaLoc = consumeToken();
383 if (Tok.is(MMToken::HeaderKeyword))
384 SubDecl = parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
385 else
386 SubDecl = parseUmbrellaDirDecl(UmbrellaLoc);
387 break;
388 }
389
390 case MMToken::ExcludeKeyword: {
391 SourceLocation ExcludeLoc = consumeToken();
392 if (Tok.is(MMToken::HeaderKeyword))
393 SubDecl = parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
394 else
395 SubDecl = parseExcludeDecl(ExcludeLoc);
396 break;
397 }
398
399 case MMToken::PrivateKeyword:
400 SubDecl = parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
401 break;
402
403 case MMToken::HeaderKeyword:
404 SubDecl = parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
405 break;
406
407 case MMToken::LinkKeyword:
408 SubDecl = parseLinkDecl();
409 break;
410
411 default:
413 consumeToken();
414 break;
415 }
416 if (SubDecl)
417 MDecl.Decls.push_back(std::move(*SubDecl));
418 } while (!Done);
419
420 if (Tok.is(MMToken::RBrace))
421 consumeToken();
422 else {
424 Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
425 HadError = true;
426 }
427 return std::move(MDecl);
428}
429
430std::optional ModuleMapFileParser::parseExternModuleDecl() {
431 assert(Tok.is(MMToken::ExternKeyword));
432 ExternModuleDecl EMD;
433 EMD.Location = consumeToken();
434
435
436 if (.is(MMToken::ModuleKeyword)) {
438 consumeToken();
439 HadError = true;
440 return std::nullopt;
441 }
442 consumeToken();
443
444
445 if (parseModuleId(EMD.Id)) {
446 HadError = true;
447 return std::nullopt;
448 }
449
450
451 if (.is(MMToken::StringLiteral)) {
453 HadError = true;
454 return std::nullopt;
455 }
456 EMD.Path = Tok.getString();
457 consumeToken();
458
459 return std::move(EMD);
460}
461
462
463
464
465
466
467
468
469std::optional ModuleMapFileParser::parseConfigMacrosDecl() {
470 assert(Tok.is(MMToken::ConfigMacros));
471 ConfigMacrosDecl CMDecl;
472 CMDecl.Location = consumeToken();
473
474
475 ModuleAttributes Attrs;
476 if (parseOptionalAttributes(Attrs))
477 return std::nullopt;
478
480
481
482
483 if (.is(MMToken::Identifier))
484 return std::nullopt;
485
486
487 CMDecl.Macros.push_back(Tok.getString());
488 consumeToken();
489
490 do {
491
492 if (.is(MMToken::Comma))
493 break;
494 consumeToken();
495
496
497
498 if (.is(MMToken::Identifier)) {
500 return std::nullopt;
501 }
502
503
504 CMDecl.Macros.push_back(Tok.getString());
505 consumeToken();
506 } while (true);
507 return std::move(CMDecl);
508}
509
510
511
512
513
514std::optional ModuleMapFileParser::parseConflictDecl() {
515 assert(Tok.is(MMToken::Conflict));
516 ConflictDecl CD;
517 CD.Location = consumeToken();
518
519
520 if (parseModuleId(CD.Id))
521 return std::nullopt;
522
523
524 if (.is(MMToken::Comma)) {
527 return std::nullopt;
528 }
529 consumeToken();
530
531
532 if (.is(MMToken::StringLiteral)) {
534 << formatModuleId(CD.Id);
535 return std::nullopt;
536 }
538 consumeToken();
539 return std::move(CD);
540}
541
542
543
544
545
546
547
548
549
550
551std::optional ModuleMapFileParser::parseExportDecl() {
552 assert(Tok.is(MMToken::ExportKeyword));
553 ExportDecl ED;
554 ED.Location = consumeToken();
555
556
557 ED.Wildcard = false;
558 do {
559
560 if (Tok.is(MMToken::Identifier)) {
561 ED.Id.push_back(
562 std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
563 consumeToken();
564
565 if (Tok.is(MMToken::Period)) {
566 consumeToken();
567 continue;
568 }
569
570 break;
571 }
572
573 if (Tok.is(MMToken::Star)) {
574 ED.Wildcard = true;
575 consumeToken();
576 break;
577 }
578
580 HadError = true;
581 return std::nullopt;
582 } while (true);
583
584 return std::move(ED);
585}
586
587
588
589
590
591std::optional ModuleMapFileParser::parseExportAsDecl() {
592 assert(Tok.is(MMToken::ExportAsKeyword));
593 ExportAsDecl EAD;
594 EAD.Location = consumeToken();
595
596 if (.is(MMToken::Identifier)) {
598 HadError = true;
599 return std::nullopt;
600 }
601
602 if (parseModuleId(EAD.Id))
603 return std::nullopt;
604 if (EAD.Id.size() > 1)
605 Diags.Report(EAD.Id[1].second, diag::err_mmap_qualified_export_as);
606 return std::move(EAD);
607}
608
609
610
611
612
613std::optional ModuleMapFileParser::parseUseDecl() {
614 assert(Tok.is(MMToken::UseKeyword));
615 UseDecl UD;
616 UD.Location = consumeToken();
617 if (parseModuleId(UD.Id))
618 return std::nullopt;
619 return std::move(UD);
620}
621
622
623
624
625
626
627
628
629
630
631
632
633std::optional ModuleMapFileParser::parseRequiresDecl() {
634 assert(Tok.is(MMToken::RequiresKeyword));
635 RequiresDecl RD;
636 RD.Location = consumeToken();
637
638
639 do {
640 bool RequiredState = true;
641 if (Tok.is(MMToken::Exclaim)) {
642 RequiredState = false;
643 consumeToken();
644 }
645
646 if (.is(MMToken::Identifier)) {
648 HadError = true;
649 return std::nullopt;
650 }
651
652
653 RequiresFeature RF;
655 RF.Location = consumeToken();
657
658 RD.Features.push_back(std::move(RF));
659
660 if (.is(MMToken::Comma))
661 break;
662
663
664 consumeToken();
665 } while (true);
666 return std::move(RD);
667}
668
669
670
671
672
673
674
675
676std::optional
677ModuleMapFileParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
678 clang::SourceLocation LeadingLoc) {
679 HeaderDecl HD;
683
685
686 if (LeadingToken == MMToken::PrivateKeyword) {
688
689 if (Tok.is(MMToken::TextualKeyword)) {
691 LeadingToken = Tok.Kind;
692 consumeToken();
693 }
694 } else if (LeadingToken == MMToken::ExcludeKeyword)
696 else if (LeadingToken == MMToken::TextualKeyword)
698
699 if (LeadingToken != MMToken::HeaderKeyword) {
700 if (.is(MMToken::HeaderKeyword)) {
702 << (LeadingToken == MMToken::PrivateKeyword ? "private"
703 : LeadingToken == MMToken::ExcludeKeyword ? "exclude"
704 : LeadingToken == MMToken::TextualKeyword ? "textual"
705 : "umbrella");
706 return std::nullopt;
707 }
708 consumeToken();
709 }
710
711
712 if (.is(MMToken::StringLiteral)) {
714 HadError = true;
715 return std::nullopt;
716 }
717 HD.Path = Tok.getString();
718 HD.PathLoc = consumeToken();
719 HD.Umbrella = LeadingToken == MMToken::UmbrellaKeyword;
720
721
722
723 if (Tok.is(MMToken::LBrace)) {
724 SourceLocation LBraceLoc = consumeToken();
725
726 while (.is(MMToken::RBrace) &&
.is(MMToken::EndOfFile)) {
727 enum Attribute { Size, ModTime, Unknown };
728 StringRef Str = Tok.getString();
729 SourceLocation Loc = consumeToken();
730 switch (llvm::StringSwitch(Str)
731 .Case("size", Size)
732 .Case("mtime", ModTime)
736 Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
737 if (.is(MMToken::IntegerLiteral)) {
739 diag::err_mmap_invalid_header_attribute_value)
740 << Str;
741 skipUntil(MMToken::RBrace);
742 break;
743 }
744 HD.Size = Tok.getInteger();
745 consumeToken();
746 break;
747
748 case ModTime:
750 Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
751 if (.is(MMToken::IntegerLiteral)) {
753 diag::err_mmap_invalid_header_attribute_value)
754 << Str;
755 skipUntil(MMToken::RBrace);
756 break;
757 }
759 consumeToken();
760 break;
761
763 Diags.Report(Loc, diag::err_mmap_expected_header_attribute);
764 skipUntil(MMToken::RBrace);
765 break;
766 }
767 }
768
769 if (Tok.is(MMToken::RBrace))
770 consumeToken();
771 else {
773 Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
774 HadError = true;
775 }
776 }
777 return std::move(HD);
778}
779
780
781
782
783
784std::optional
785ModuleMapFileParser::parseExcludeDecl(clang::SourceLocation LeadingLoc) {
786
787 if (.is(MMToken::Identifier)) {
789 HadError = true;
790 return std::nullopt;
791 }
792
793 ExcludeDecl ED;
796 consumeToken();
797 return std::move(ED);
798}
799
800
801
802
803
804std::optional
805ModuleMapFileParser::parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc) {
806 UmbrellaDirDecl UDD;
808
809 if (.is(MMToken::StringLiteral)) {
811 << "umbrella";
812 HadError = true;
813 return std::nullopt;
814 }
815
816 UDD.Path = Tok.getString();
817 consumeToken();
818 return std::move(UDD);
819}
820
821
822
823
824
825std::optional ModuleMapFileParser::parseLinkDecl() {
826 assert(Tok.is(MMToken::LinkKeyword));
827 LinkDecl LD;
828 LD.Location = consumeToken();
829
830
832 if (Tok.is(MMToken::FrameworkKeyword)) {
833 consumeToken();
835 }
836
837
838 if (.is(MMToken::StringLiteral)) {
841 HadError = true;
842 return std::nullopt;
843 }
844
846 consumeToken();
847 return std::move(LD);
848}
849
850SourceLocation ModuleMapFileParser::consumeToken() {
852
853retry:
854 Tok.clear();
855 Token LToken;
858 switch (LToken.getKind()) {
859 case tok::raw_identifier: {
861 Tok.StringData = RI.data();
862 Tok.StringLength = RI.size();
863 Tok.Kind = llvm::StringSwitchMMToken::TokenKind(RI)
864 .Case("config_macros", MMToken::ConfigMacros)
865 .Case("conflict", MMToken::Conflict)
866 .Case("exclude", MMToken::ExcludeKeyword)
867 .Case("explicit", MMToken::ExplicitKeyword)
868 .Case("export", MMToken::ExportKeyword)
869 .Case("export_as", MMToken::ExportAsKeyword)
870 .Case("extern", MMToken::ExternKeyword)
871 .Case("framework", MMToken::FrameworkKeyword)
872 .Case("header", MMToken::HeaderKeyword)
873 .Case("link", MMToken::LinkKeyword)
874 .Case("module", MMToken::ModuleKeyword)
875 .Case("private", MMToken::PrivateKeyword)
876 .Case("requires", MMToken::RequiresKeyword)
877 .Case("textual", MMToken::TextualKeyword)
878 .Case("umbrella", MMToken::UmbrellaKeyword)
879 .Case("use", MMToken::UseKeyword)
880 .Default(MMToken::Identifier);
881 break;
882 }
883
884 case tok::comma:
885 Tok.Kind = MMToken::Comma;
886 break;
887
888 case tok::eof:
889 Tok.Kind = MMToken::EndOfFile;
890 break;
891
892 case tok::l_brace:
893 Tok.Kind = MMToken::LBrace;
894 break;
895
896 case tok::l_square:
897 Tok.Kind = MMToken::LSquare;
898 break;
899
900 case tok::period:
901 Tok.Kind = MMToken::Period;
902 break;
903
904 case tok::r_brace:
905 Tok.Kind = MMToken::RBrace;
906 break;
907
908 case tok::r_square:
909 Tok.Kind = MMToken::RSquare;
910 break;
911
912 case tok:⭐
913 Tok.Kind = MMToken::Star;
914 break;
915
916 case tok::exclaim:
917 Tok.Kind = MMToken::Exclaim;
918 break;
919
920 case tok::string_literal: {
922 Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
923 HadError = true;
924 goto retry;
925 }
926
927
928 Tok.Kind = MMToken::StringLiteral;
931 break;
932 }
933
934 case tok::numeric_constant: {
935
938 .getAsInteger(0, Value)) {
940 HadError = true;
941 goto retry;
942 }
943
944 Tok.Kind = MMToken::IntegerLiteral;
946 break;
947 }
948
949 case tok::comment:
950 goto retry;
951
952 case tok::hash:
953
954
955
956
957 {
958 auto NextIsIdent = [&](StringRef Str) -> bool {
960 return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) &&
962 };
963 if (NextIsIdent("pragma") && NextIsIdent("clang") &&
964 NextIsIdent("module") && NextIsIdent("contents")) {
965 Tok.Kind = MMToken::EndOfFile;
966 break;
967 }
968 }
969 [[fallthrough]];
970
971 default:
973 HadError = true;
974 goto retry;
975 }
976
978}
979
980void ModuleMapFileParser::skipUntil(MMToken::TokenKind K) {
981 unsigned braceDepth = 0;
982 unsigned squareDepth = 0;
983 do {
984 switch (Tok.Kind) {
985 case MMToken::EndOfFile:
986 return;
987
988 case MMToken::LBrace:
989 if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
990 return;
991
992 ++braceDepth;
993 break;
994
995 case MMToken::LSquare:
996 if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
997 return;
998
999 ++squareDepth;
1000 break;
1001
1002 case MMToken::RBrace:
1003 if (braceDepth > 0)
1004 --braceDepth;
1006 return;
1007 break;
1008
1009 case MMToken::RSquare:
1010 if (squareDepth > 0)
1011 --squareDepth;
1013 return;
1014 break;
1015
1016 default:
1017 if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))
1018 return;
1019 break;
1020 }
1021
1022 consumeToken();
1023 } while (true);
1024}
1025
1026
1027
1028
1029
1030
1031
1032
1033bool ModuleMapFileParser::parseModuleId(ModuleId &Id) {
1034 Id.clear();
1035 do {
1036 if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {
1037 Id.push_back(
1038 std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
1039 consumeToken();
1040 } else {
1042 return true;
1043 }
1044
1045 if (.is(MMToken::Period))
1046 break;
1047
1048 consumeToken();
1049 } while (true);
1050
1051 return false;
1052}
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066bool ModuleMapFileParser::parseOptionalAttributes(ModuleAttributes &Attrs) {
1067 bool Error = false;
1068
1069 while (Tok.is(MMToken::LSquare)) {
1070
1071 SourceLocation LSquareLoc = consumeToken();
1072
1073
1074 if (.is(MMToken::Identifier)) {
1076 skipUntil(MMToken::RSquare);
1077 if (Tok.is(MMToken::RSquare))
1078 consumeToken();
1080 }
1081
1082
1083 enum AttributeKind {
1084
1085 AT_unknown,
1086
1087
1088 AT_system,
1089
1090
1091 AT_extern_c,
1092
1093
1094 AT_exhaustive,
1095
1096
1097 AT_no_undeclared_includes
1098 };
1099
1100
1101 AttributeKind Attribute =
1102 llvm::StringSwitch(Tok.getString())
1103 .Case("exhaustive", AT_exhaustive)
1104 .Case("extern_c", AT_extern_c)
1105 .Case("no_undeclared_includes", AT_no_undeclared_includes)
1106 .Case("system", AT_system)
1107 .Default(AT_unknown);
1108 switch (Attribute) {
1109 case AT_unknown:
1111 << Tok.getString();
1112 break;
1113
1114 case AT_system:
1116 break;
1117
1118 case AT_extern_c:
1120 break;
1121
1122 case AT_exhaustive:
1124 break;
1125
1126 case AT_no_undeclared_includes:
1128 break;
1129 }
1130 consumeToken();
1131
1132
1133 if (.is(MMToken::RSquare)) {
1135 Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
1136 skipUntil(MMToken::RSquare);
1138 }
1139
1140 if (Tok.is(MMToken::RSquare))
1141 consumeToken();
1142 }
1143
1145 HadError = true;
1146
1148}
1149
1150static void dumpModule(const ModuleDecl &MD, llvm::raw_ostream &out, int depth);
1151
1153 llvm::raw_ostream &out, int depth) {
1154 out.indent(depth * 2);
1155 out << "extern module " << formatModuleId(EMD.Id) << " \"" << EMD.Path
1156 << "\"\n";
1157}
1158
1160 for (const auto &Decl : Decls) {
1161 std::visit(llvm::makeVisitor(
1163 out.indent(depth * 2);
1164 out << "requires\n";
1165 },
1167 out.indent(depth * 2);
1169 out << "private ";
1171 out << "textual ";
1173 out << "excluded ";
1175 out << "umbrella ";
1176 out << "header \"" << HD.Path << "\"\n";
1177 },
1179 out.indent(depth * 2);
1180 out << "umbrella\n";
1181 },
1184 out.indent(depth * 2);
1185 out << "exclude " << ED.Module << "\n";
1186 },
1188 out.indent(depth * 2);
1189 out << "export "
1190 << (ED.Wildcard ? "*" : formatModuleId(ED.Id)) << "\n";
1191 },
1193 out.indent(depth * 2);
1194 out << "export as\n";
1195 },
1198 },
1199 [&](const UseDecl &UD) {
1200 out.indent(depth * 2);
1201 out << "use\n";
1202 },
1204 out.indent(depth * 2);
1205 out << "link\n";
1206 },
1208 out.indent(depth * 2);
1209 out << "config_macros ";
1210 if (CMD.Exhaustive)
1211 out << "[exhaustive] ";
1212 for (auto Macro : CMD.Macros) {
1214 }
1215 out << "\n";
1216 },
1218 out.indent(depth * 2);
1219 out << "conflicts\n";
1220 }),
1222 }
1223}
1224
1226 int depth) {
1227 out.indent(depth * 2);
1228 out << "module " << formatModuleId(MD.Id) << "\n";
1230}
1231
1233 for (const auto &Decl : Decls) {
1234 std::visit(
1238 }),
1240 }
1241}
Defines the Diagnostic-related interfaces.
bool is(tok::TokenKind Kind) const
Defines the clang::LangOptions interface.
static void dumpModule(const ModuleDecl &MD, llvm::raw_ostream &out, int depth)
Definition ModuleMapFile.cpp:1225
static void dumpDecls(ArrayRef< Decl > Decls, llvm::raw_ostream &out, int depth)
Definition ModuleMapFile.cpp:1159
static void dumpExternModule(const ExternModuleDecl &EMD, llvm::raw_ostream &out, int depth)
Definition ModuleMapFile.cpp:1152
Defines the clang::Module class, which describes a module in the source code.
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
A reference to a DirectoryEntry that includes the name of the directory as it was accessed by the Fil...
Represents a standard C++ module export declaration.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
LangStandard::Kind LangStd
The used language standard.
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
SourceLocation getSourceLocation(const char *Loc, unsigned TokLen=1) const
getSourceLocation - Return a source location identifier for the specified offset in the current file.
Parser - This implements a parser for the C family of languages.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
UIntTy getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it.
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
unsigned getLength() const
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
tok::TokenKind getKind() const
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
bool hasUDSuffix() const
Return true if this token is a string or character literal which has a ud-suffix.
StringRef getRawIdentifier() const
getRawIdentifier - For a raw identifier token (i.e., an identifier lexed in raw mode),...
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
std::optional< ModuleMapFile > parseModuleMap(FileID ID, clang::DirectoryEntryRef Dir, SourceManager &SM, DiagnosticsEngine &Diags, bool IsSystem, unsigned *Offset)
Parse a module map file into an in memory representation.
Definition ModuleMapFile.cpp:148
The JSON file list parser is used to communicate input to InstallAPI.
SmallVector< std::pair< std::string, SourceLocation >, 2 > ModuleId
Describes the name of a module.
@ Result
The result type of a method or function.
unsigned IsExternC
Whether this is an extern "C" module.
unsigned IsSystem
Whether this is a system module.
unsigned IsExhaustive
Whether this is an exhaustive set of configuration macros.
unsigned NoUndeclaredIncludes
Whether files in this module can only include non-modular headers and headers from used modules.
std::vector< StringRef > Macros
ModuleAttributes Attrs
Points to the first keyword in the decl.
std::vector< Decl > Decls
std::vector< TopLevelDecl > Decls
void dump(llvm::raw_ostream &out) const
Definition ModuleMapFile.cpp:1232
std::vector< RequiresFeature > Features