22#include "llvm/ADT/STLExtras.h"
61 SourceLocation::UIntTy Location;
62 unsigned StringLength;
65 const char *StringData;
78 bool is(TokenKind K)
const {
return Kind == K; }
80 SourceLocation getLocation()
const {
81 return SourceLocation::getFromRawEncoding(Location);
85 return Kind == IntegerLiteral ? IntegerValue : 0;
88 StringRef getString()
const {
89 return Kind == IntegerLiteral ? StringRef()
90 : StringRef(StringData, StringLength);
94struct ModuleMapFileParser {
97 DiagnosticsEngine &Diags;
102 bool HadError =
false;
107 bool parseTopLevelDecls();
108 std::optional<ModuleDecl> parseModuleDecl(
bool TopLevel);
109 std::optional<ExternModuleDecl> parseExternModuleDecl();
110 std::optional<ConfigMacrosDecl> parseConfigMacrosDecl();
111 std::optional<ConflictDecl> parseConflictDecl();
112 std::optional<ExportDecl> parseExportDecl();
113 std::optional<ExportAsDecl> parseExportAsDecl();
114 std::optional<UseDecl> parseUseDecl();
115 std::optional<RequiresDecl> parseRequiresDecl();
116 std::optional<HeaderDecl> parseHeaderDecl(MMToken::TokenKind LeadingToken,
117 SourceLocation LeadingLoc);
118 std::optional<ExcludeDecl> parseExcludeDecl(clang::SourceLocation LeadingLoc);
119 std::optional<UmbrellaDirDecl>
120 parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
121 std::optional<LinkDecl> parseLinkDecl();
123 SourceLocation consumeToken();
124 void skipUntil(MMToken::TokenKind K);
126 bool parseOptionalAttributes(ModuleAttributes &Attrs);
128 SourceLocation getLocation()
const {
return Tok.getLocation(); };
131std::string formatModuleId(
const ModuleId &Id) {
134 llvm::raw_string_ostream
OS(result);
136 for (
unsigned I = 0, N = Id.size(); I != N; ++I) {
147std::optional<ModuleMapFile>
150 bool IsSystem,
unsigned *Offset) {
151 std::optional<llvm::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());
159 ModuleMapFileParser
Parser{L, Diags};
160 bool Failed =
Parser.parseTopLevelDecls();
163 auto Loc =
SM.getDecomposedLoc(
Parser.getLocation());
164 assert(Loc.first == ID &&
"stopped in a different file?");
165 *Offset = Loc.second;
173 Parser.MMF.IsSystem = IsSystem;
174 return std::move(
Parser.MMF);
177bool ModuleMapFileParser::parseTopLevelDecls() {
182 case MMToken::EndOfFile:
184 case MMToken::ExternKeyword: {
185 std::optional<ExternModuleDecl> EMD = parseExternModuleDecl();
187 MMF.
Decls.push_back(std::move(*EMD));
190 case MMToken::ExplicitKeyword:
191 case MMToken::ModuleKeyword:
192 case MMToken::FrameworkKeyword: {
193 std::optional<ModuleDecl> MD = parseModuleDecl(
true);
195 MMF.
Decls.push_back(std::move(*MD));
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:
216 case MMToken::StringLiteral:
217 case MMToken::IntegerLiteral:
218 case MMToken::TextualKeyword:
219 case MMToken::UmbrellaKeyword:
220 case MMToken::UseKeyword:
247std::optional<ModuleDecl> ModuleMapFileParser::parseModuleDecl(
bool TopLevel) {
248 assert(
Tok.
is(MMToken::ExplicitKeyword) ||
Tok.
is(MMToken::ModuleKeyword) ||
249 Tok.
is(MMToken::FrameworkKeyword));
253 SourceLocation ExplicitLoc;
258 if (
Tok.
is(MMToken::ExplicitKeyword)) {
259 MDecl.
Location = ExplicitLoc = consumeToken();
264 if (
Tok.
is(MMToken::FrameworkKeyword)) {
265 SourceLocation FrameworkLoc = consumeToken();
272 if (!
Tok.
is(MMToken::ModuleKeyword)) {
278 SourceLocation ModuleLoc = consumeToken();
284 if (
Tok.
is(MMToken::Star)) {
285 SourceLocation StarLoc = consumeToken();
286 MDecl.
Id.push_back({
"*", StarLoc});
288 Diags.
Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
294 if (parseModuleId(MDecl.
Id)) {
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);
306 }
else if (MDecl.
Id.size() == 1 && MDecl.
Explicit) {
308 Diags.
Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
315 if (parseOptionalAttributes(MDecl.
Attrs))
319 if (!
Tok.
is(MMToken::LBrace)) {
321 << MDecl.
Id.back().first;
325 SourceLocation LBraceLoc = consumeToken();
329 std::optional<Decl> SubDecl;
331 case MMToken::EndOfFile:
332 case MMToken::RBrace:
336 case MMToken::ConfigMacros:
340 SubDecl = parseConfigMacrosDecl();
343 case MMToken::Conflict:
344 SubDecl = parseConflictDecl();
347 case MMToken::ExternKeyword:
348 SubDecl = parseExternModuleDecl();
351 case MMToken::ExplicitKeyword:
352 case MMToken::FrameworkKeyword:
353 case MMToken::ModuleKeyword:
354 SubDecl = parseModuleDecl(
false);
357 case MMToken::ExportKeyword:
358 SubDecl = parseExportDecl();
361 case MMToken::ExportAsKeyword:
366 SubDecl = parseExportAsDecl();
369 case MMToken::UseKeyword:
370 SubDecl = parseUseDecl();
373 case MMToken::RequiresKeyword:
374 SubDecl = parseRequiresDecl();
377 case MMToken::TextualKeyword:
378 SubDecl = parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
381 case MMToken::UmbrellaKeyword: {
382 SourceLocation UmbrellaLoc = consumeToken();
383 if (
Tok.
is(MMToken::HeaderKeyword))
384 SubDecl = parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
386 SubDecl = parseUmbrellaDirDecl(UmbrellaLoc);
390 case MMToken::ExcludeKeyword: {
391 SourceLocation ExcludeLoc = consumeToken();
392 if (
Tok.
is(MMToken::HeaderKeyword))
393 SubDecl = parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
395 SubDecl = parseExcludeDecl(ExcludeLoc);
399 case MMToken::PrivateKeyword:
400 SubDecl = parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
403 case MMToken::HeaderKeyword:
404 SubDecl = parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
407 case MMToken::LinkKeyword:
408 SubDecl = parseLinkDecl();
417 MDecl.
Decls.push_back(std::move(*SubDecl));
420 if (
Tok.
is(MMToken::RBrace))
424 Diags.
Report(LBraceLoc, diag::note_mmap_lbrace_match);
427 return std::move(MDecl);
430std::optional<ExternModuleDecl> ModuleMapFileParser::parseExternModuleDecl() {
431 assert(
Tok.
is(MMToken::ExternKeyword));
432 ExternModuleDecl EMD;
436 if (!
Tok.
is(MMToken::ModuleKeyword)) {
445 if (parseModuleId(EMD.
Id)) {
451 if (!
Tok.
is(MMToken::StringLiteral)) {
459 return std::move(EMD);
469std::optional<ConfigMacrosDecl> ModuleMapFileParser::parseConfigMacrosDecl() {
470 assert(
Tok.
is(MMToken::ConfigMacros));
471 ConfigMacrosDecl CMDecl;
475 ModuleAttributes Attrs;
476 if (parseOptionalAttributes(Attrs))
483 if (!
Tok.
is(MMToken::Identifier))
487 CMDecl.
Macros.push_back(
Tok.getString());
492 if (!
Tok.
is(MMToken::Comma))
498 if (!
Tok.
is(MMToken::Identifier)) {
504 CMDecl.
Macros.push_back(
Tok.getString());
507 return std::move(CMDecl);
514std::optional<ConflictDecl> ModuleMapFileParser::parseConflictDecl() {
515 assert(
Tok.
is(MMToken::Conflict));
520 if (parseModuleId(CD.
Id))
524 if (!
Tok.
is(MMToken::Comma)) {
532 if (!
Tok.
is(MMToken::StringLiteral)) {
534 << formatModuleId(CD.
Id);
539 return std::move(CD);
551std::optional<ExportDecl> ModuleMapFileParser::parseExportDecl() {
552 assert(
Tok.
is(MMToken::ExportKeyword));
554 ED.Location = consumeToken();
560 if (
Tok.
is(MMToken::Identifier)) {
565 if (
Tok.
is(MMToken::Period)) {
573 if (
Tok.
is(MMToken::Star)) {
584 return std::move(ED);
591std::optional<ExportAsDecl> ModuleMapFileParser::parseExportAsDecl() {
592 assert(
Tok.
is(MMToken::ExportAsKeyword));
596 if (!
Tok.
is(MMToken::Identifier)) {
602 if (parseModuleId(EAD.
Id))
604 if (EAD.
Id.size() > 1)
605 Diags.
Report(EAD.
Id[1].second, diag::err_mmap_qualified_export_as);
606 return std::move(EAD);
613std::optional<UseDecl> ModuleMapFileParser::parseUseDecl() {
614 assert(
Tok.
is(MMToken::UseKeyword));
617 if (parseModuleId(UD.
Id))
619 return std::move(UD);
633std::optional<RequiresDecl> ModuleMapFileParser::parseRequiresDecl() {
634 assert(
Tok.
is(MMToken::RequiresKeyword));
640 bool RequiredState =
true;
641 if (
Tok.
is(MMToken::Exclaim)) {
642 RequiredState =
false;
646 if (!
Tok.
is(MMToken::Identifier)) {
658 RD.
Features.push_back(std::move(RF));
660 if (!
Tok.
is(MMToken::Comma))
666 return std::move(RD);
676std::optional<HeaderDecl>
677ModuleMapFileParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
678 clang::SourceLocation LeadingLoc) {
686 if (LeadingToken == MMToken::PrivateKeyword) {
689 if (
Tok.
is(MMToken::TextualKeyword)) {
691 LeadingToken =
Tok.Kind;
694 }
else if (LeadingToken == MMToken::ExcludeKeyword)
696 else if (LeadingToken == MMToken::TextualKeyword)
699 if (LeadingToken != MMToken::HeaderKeyword) {
700 if (!
Tok.
is(MMToken::HeaderKeyword)) {
702 << (LeadingToken == MMToken::PrivateKeyword ?
"private"
703 : LeadingToken == MMToken::ExcludeKeyword ?
"exclude"
704 : LeadingToken == MMToken::TextualKeyword ?
"textual"
712 if (!
Tok.
is(MMToken::StringLiteral)) {
719 HD.
Umbrella = LeadingToken == MMToken::UmbrellaKeyword;
723 if (
Tok.
is(MMToken::LBrace)) {
724 SourceLocation LBraceLoc = consumeToken();
726 while (!
Tok.
is(MMToken::RBrace) && !
Tok.
is(MMToken::EndOfFile)) {
728 StringRef Str =
Tok.getString();
729 SourceLocation Loc = consumeToken();
730 switch (llvm::StringSwitch<Attribute>(Str)
732 .Case(
"mtime", ModTime)
736 Diags.
Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
737 if (!
Tok.
is(MMToken::IntegerLiteral)) {
739 diag::err_mmap_invalid_header_attribute_value)
741 skipUntil(MMToken::RBrace);
750 Diags.
Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
751 if (!
Tok.
is(MMToken::IntegerLiteral)) {
753 diag::err_mmap_invalid_header_attribute_value)
755 skipUntil(MMToken::RBrace);
763 Diags.
Report(Loc, diag::err_mmap_expected_header_attribute);
764 skipUntil(MMToken::RBrace);
769 if (
Tok.
is(MMToken::RBrace))
773 Diags.
Report(LBraceLoc, diag::note_mmap_lbrace_match);
777 return std::move(HD);
784std::optional<ExcludeDecl>
785ModuleMapFileParser::parseExcludeDecl(clang::SourceLocation LeadingLoc) {
787 if (!
Tok.
is(MMToken::Identifier)) {
797 return std::move(ED);
804std::optional<UmbrellaDirDecl>
805ModuleMapFileParser::parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc) {
809 if (!
Tok.
is(MMToken::StringLiteral)) {
818 return std::move(UDD);
825std::optional<LinkDecl> ModuleMapFileParser::parseLinkDecl() {
826 assert(
Tok.
is(MMToken::LinkKeyword));
832 if (
Tok.
is(MMToken::FrameworkKeyword)) {
838 if (!
Tok.
is(MMToken::StringLiteral)) {
847 return std::move(LD);
850SourceLocation ModuleMapFileParser::consumeToken() {
859 case tok::raw_identifier: {
861 Tok.StringData = RI.data();
862 Tok.StringLength = RI.size();
863 Tok.Kind = llvm::StringSwitch<MMToken::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);
885 Tok.Kind = MMToken::Comma;
889 Tok.Kind = MMToken::EndOfFile;
893 Tok.Kind = MMToken::LBrace;
897 Tok.Kind = MMToken::LSquare;
901 Tok.Kind = MMToken::Period;
905 Tok.Kind = MMToken::RBrace;
909 Tok.Kind = MMToken::RSquare;
913 Tok.Kind = MMToken::Star;
917 Tok.Kind = MMToken::Exclaim;
920 case tok::string_literal: {
928 Tok.Kind = MMToken::StringLiteral;
934 case tok::numeric_constant: {
938 .getAsInteger(0,
Value)) {
944 Tok.Kind = MMToken::IntegerLiteral;
958 auto NextIsIdent = [&](StringRef Str) ->
bool {
963 if (NextIsIdent(
"pragma") && NextIsIdent(
"clang") &&
964 NextIsIdent(
"module") && NextIsIdent(
"contents")) {
965 Tok.Kind = MMToken::EndOfFile;
980void ModuleMapFileParser::skipUntil(MMToken::TokenKind K) {
981 unsigned braceDepth = 0;
982 unsigned squareDepth = 0;
985 case MMToken::EndOfFile:
988 case MMToken::LBrace:
989 if (
Tok.
is(K) && braceDepth == 0 && squareDepth == 0)
995 case MMToken::LSquare:
996 if (
Tok.
is(K) && braceDepth == 0 && squareDepth == 0)
1002 case MMToken::RBrace:
1009 case MMToken::RSquare:
1010 if (squareDepth > 0)
1017 if (braceDepth == 0 && squareDepth == 0 &&
Tok.
is(K))
1033bool ModuleMapFileParser::parseModuleId(
ModuleId &Id) {
1036 if (
Tok.
is(MMToken::Identifier) ||
Tok.
is(MMToken::StringLiteral)) {
1045 if (!
Tok.
is(MMToken::Period))
1066bool ModuleMapFileParser::parseOptionalAttributes(ModuleAttributes &Attrs) {
1069 while (
Tok.
is(MMToken::LSquare)) {
1071 SourceLocation LSquareLoc = consumeToken();
1074 if (!
Tok.
is(MMToken::Identifier)) {
1076 skipUntil(MMToken::RSquare);
1077 if (
Tok.
is(MMToken::RSquare))
1083 enum AttributeKind {
1097 AT_no_undeclared_includes
1101 AttributeKind Attribute =
1102 llvm::StringSwitch<AttributeKind>(
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) {
1126 case AT_no_undeclared_includes:
1133 if (!
Tok.
is(MMToken::RSquare)) {
1135 Diags.
Report(LSquareLoc, diag::note_mmap_lsquare_match);
1136 skipUntil(MMToken::RSquare);
1140 if (
Tok.
is(MMToken::RSquare))
1150static void dumpModule(
const ModuleDecl &MD, llvm::raw_ostream &
out,
int depth);
1153 llvm::raw_ostream &
out,
int depth) {
1154 out.indent(depth * 2);
1155 out <<
"extern module " << formatModuleId(EMD.
Id) <<
" \"" << EMD.
Path
1160 for (
const auto &
Decl : Decls) {
1161 std::visit(llvm::makeVisitor(
1163 out.indent(depth * 2);
1164 out <<
"requires\n";
1167 out.indent(depth * 2);
1176 out <<
"header \"" << HD.
Path <<
"\"\n";
1179 out.indent(depth * 2);
1180 out <<
"umbrella\n";
1184 out.indent(depth * 2);
1188 out.indent(depth * 2);
1190 << (ED.Wildcard ?
"*" : formatModuleId(ED.Id)) <<
"\n";
1193 out.indent(depth * 2);
1194 out <<
"export as\n";
1200 out.indent(depth * 2);
1204 out.indent(depth * 2);
1208 out.indent(depth * 2);
1209 out <<
"config_macros ";
1211 out <<
"[exhaustive] ";
1212 for (
auto Macro : CMD.Macros) {
1218 out.indent(depth * 2);
1219 out <<
"conflicts\n";
1227 out.indent(depth * 2);
1228 out <<
"module " << formatModuleId(MD.
Id) <<
"\n";
Defines the Diagnostic-related interfaces.
Defines the clang::LangOptions interface.
static void dumpModule(const ModuleDecl &MD, llvm::raw_ostream &out, int depth)
static void dumpDecls(ArrayRef< Decl > Decls, llvm::raw_ostream &out, int depth)
static void dumpExternModule(const ExternModuleDecl &EMD, llvm::raw_ostream &out, int depth)
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.
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
std::vector< RequiresFeature > Features