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,
bool ImplicitlyDiscovered,
152 std::optional<llvm::MemoryBufferRef> Buffer =
SM.getBufferOrNone(ID);
154 LOpts.
LangStd = clang::LangStandard::lang_c99;
155 Lexer L(
SM.getLocForStartOfFile(ID), LOpts, Buffer->getBufferStart(),
156 Buffer->getBufferStart() + (Offset ? *Offset : 0),
157 Buffer->getBufferEnd());
160 ModuleMapFileParser
Parser{L, Diags};
161 bool Failed =
Parser.parseTopLevelDecls();
164 auto Loc =
SM.getDecomposedLoc(
Parser.getLocation());
165 assert(Loc.first == ID &&
"stopped in a different file?");
166 *Offset = Loc.second;
174 Parser.MMF.IsSystem = IsSystem;
175 Parser.MMF.ImplicitlyDiscovered = ImplicitlyDiscovered;
176 return std::move(
Parser.MMF);
179bool ModuleMapFileParser::parseTopLevelDecls() {
184 case MMToken::EndOfFile:
186 case MMToken::ExternKeyword: {
187 std::optional<ExternModuleDecl> EMD = parseExternModuleDecl();
189 MMF.
Decls.push_back(std::move(*EMD));
192 case MMToken::ExplicitKeyword:
193 case MMToken::ModuleKeyword:
194 case MMToken::FrameworkKeyword: {
195 std::optional<ModuleDecl> MD = parseModuleDecl(
true);
197 MMF.
Decls.push_back(std::move(*MD));
201 case MMToken::ConfigMacros:
202 case MMToken::Conflict:
203 case MMToken::Exclaim:
204 case MMToken::ExcludeKeyword:
205 case MMToken::ExportKeyword:
206 case MMToken::ExportAsKeyword:
207 case MMToken::HeaderKeyword:
208 case MMToken::Identifier:
209 case MMToken::LBrace:
210 case MMToken::LinkKeyword:
211 case MMToken::LSquare:
212 case MMToken::Period:
213 case MMToken::PrivateKeyword:
214 case MMToken::RBrace:
215 case MMToken::RSquare:
216 case MMToken::RequiresKeyword:
218 case MMToken::StringLiteral:
219 case MMToken::IntegerLiteral:
220 case MMToken::TextualKeyword:
221 case MMToken::UmbrellaKeyword:
222 case MMToken::UseKeyword:
249std::optional<ModuleDecl> ModuleMapFileParser::parseModuleDecl(
bool TopLevel) {
250 assert(
Tok.
is(MMToken::ExplicitKeyword) ||
Tok.
is(MMToken::ModuleKeyword) ||
251 Tok.
is(MMToken::FrameworkKeyword));
255 SourceLocation ExplicitLoc;
260 if (
Tok.
is(MMToken::ExplicitKeyword)) {
261 MDecl.
Location = ExplicitLoc = consumeToken();
266 if (
Tok.
is(MMToken::FrameworkKeyword)) {
267 SourceLocation FrameworkLoc = consumeToken();
274 if (!
Tok.
is(MMToken::ModuleKeyword)) {
280 SourceLocation ModuleLoc = consumeToken();
286 if (
Tok.
is(MMToken::Star)) {
287 SourceLocation StarLoc = consumeToken();
288 MDecl.
Id.push_back({
"*", StarLoc});
290 Diags.
Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
296 if (parseModuleId(MDecl.
Id)) {
301 if (MDecl.
Id.size() > 1) {
302 Diags.
Report(MDecl.
Id.front().second,
303 diag::err_mmap_nested_submodule_id)
304 << SourceRange(MDecl.
Id.front().second, MDecl.
Id.back().second);
308 }
else if (MDecl.
Id.size() == 1 && MDecl.
Explicit) {
310 Diags.
Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
317 if (parseOptionalAttributes(MDecl.
Attrs))
321 if (!
Tok.
is(MMToken::LBrace)) {
323 << MDecl.
Id.back().first;
327 SourceLocation LBraceLoc = consumeToken();
331 std::optional<Decl> SubDecl;
333 case MMToken::EndOfFile:
334 case MMToken::RBrace:
338 case MMToken::ConfigMacros:
342 SubDecl = parseConfigMacrosDecl();
345 case MMToken::Conflict:
346 SubDecl = parseConflictDecl();
349 case MMToken::ExternKeyword:
350 SubDecl = parseExternModuleDecl();
353 case MMToken::ExplicitKeyword:
354 case MMToken::FrameworkKeyword:
355 case MMToken::ModuleKeyword:
356 SubDecl = parseModuleDecl(
false);
359 case MMToken::ExportKeyword:
360 SubDecl = parseExportDecl();
363 case MMToken::ExportAsKeyword:
368 SubDecl = parseExportAsDecl();
371 case MMToken::UseKeyword:
372 SubDecl = parseUseDecl();
375 case MMToken::RequiresKeyword:
376 SubDecl = parseRequiresDecl();
379 case MMToken::TextualKeyword:
380 SubDecl = parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
383 case MMToken::UmbrellaKeyword: {
384 SourceLocation UmbrellaLoc = consumeToken();
385 if (
Tok.
is(MMToken::HeaderKeyword))
386 SubDecl = parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
388 SubDecl = parseUmbrellaDirDecl(UmbrellaLoc);
392 case MMToken::ExcludeKeyword: {
393 SourceLocation ExcludeLoc = consumeToken();
394 if (
Tok.
is(MMToken::HeaderKeyword))
395 SubDecl = parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
397 SubDecl = parseExcludeDecl(ExcludeLoc);
401 case MMToken::PrivateKeyword:
402 SubDecl = parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
405 case MMToken::HeaderKeyword:
406 SubDecl = parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
409 case MMToken::LinkKeyword:
410 SubDecl = parseLinkDecl();
419 MDecl.
Decls.push_back(std::move(*SubDecl));
422 if (
Tok.
is(MMToken::RBrace))
426 Diags.
Report(LBraceLoc, diag::note_mmap_lbrace_match);
429 return std::move(MDecl);
432std::optional<ExternModuleDecl> ModuleMapFileParser::parseExternModuleDecl() {
433 assert(
Tok.
is(MMToken::ExternKeyword));
434 ExternModuleDecl EMD;
438 if (!
Tok.
is(MMToken::ModuleKeyword)) {
447 if (parseModuleId(EMD.
Id)) {
453 if (!
Tok.
is(MMToken::StringLiteral)) {
461 return std::move(EMD);
471std::optional<ConfigMacrosDecl> ModuleMapFileParser::parseConfigMacrosDecl() {
472 assert(
Tok.
is(MMToken::ConfigMacros));
473 ConfigMacrosDecl CMDecl;
477 ModuleAttributes Attrs;
478 if (parseOptionalAttributes(Attrs))
485 if (!
Tok.
is(MMToken::Identifier))
489 CMDecl.
Macros.push_back(
Tok.getString());
494 if (!
Tok.
is(MMToken::Comma))
500 if (!
Tok.
is(MMToken::Identifier)) {
506 CMDecl.
Macros.push_back(
Tok.getString());
509 return std::move(CMDecl);
516std::optional<ConflictDecl> ModuleMapFileParser::parseConflictDecl() {
517 assert(
Tok.
is(MMToken::Conflict));
522 if (parseModuleId(CD.
Id))
526 if (!
Tok.
is(MMToken::Comma)) {
534 if (!
Tok.
is(MMToken::StringLiteral)) {
536 << formatModuleId(CD.
Id);
541 return std::move(CD);
553std::optional<ExportDecl> ModuleMapFileParser::parseExportDecl() {
554 assert(
Tok.
is(MMToken::ExportKeyword));
556 ED.Location = consumeToken();
562 if (
Tok.
is(MMToken::Identifier)) {
567 if (
Tok.
is(MMToken::Period)) {
575 if (
Tok.
is(MMToken::Star)) {
586 return std::move(ED);
593std::optional<ExportAsDecl> ModuleMapFileParser::parseExportAsDecl() {
594 assert(
Tok.
is(MMToken::ExportAsKeyword));
598 if (!
Tok.
is(MMToken::Identifier)) {
604 if (parseModuleId(EAD.
Id))
606 if (EAD.
Id.size() > 1)
607 Diags.
Report(EAD.
Id[1].second, diag::err_mmap_qualified_export_as);
608 return std::move(EAD);
615std::optional<UseDecl> ModuleMapFileParser::parseUseDecl() {
616 assert(
Tok.
is(MMToken::UseKeyword));
619 if (parseModuleId(UD.
Id))
621 return std::move(UD);
635std::optional<RequiresDecl> ModuleMapFileParser::parseRequiresDecl() {
636 assert(
Tok.
is(MMToken::RequiresKeyword));
642 bool RequiredState =
true;
643 if (
Tok.
is(MMToken::Exclaim)) {
644 RequiredState =
false;
648 if (!
Tok.
is(MMToken::Identifier)) {
660 RD.
Features.push_back(std::move(RF));
662 if (!
Tok.
is(MMToken::Comma))
668 return std::move(RD);
678std::optional<HeaderDecl>
679ModuleMapFileParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
680 clang::SourceLocation LeadingLoc) {
688 if (LeadingToken == MMToken::PrivateKeyword) {
691 if (
Tok.
is(MMToken::TextualKeyword)) {
693 LeadingToken =
Tok.Kind;
696 }
else if (LeadingToken == MMToken::ExcludeKeyword)
698 else if (LeadingToken == MMToken::TextualKeyword)
701 if (LeadingToken != MMToken::HeaderKeyword) {
702 if (!
Tok.
is(MMToken::HeaderKeyword)) {
704 << (LeadingToken == MMToken::PrivateKeyword ?
"private"
705 : LeadingToken == MMToken::ExcludeKeyword ?
"exclude"
706 : LeadingToken == MMToken::TextualKeyword ?
"textual"
714 if (!
Tok.
is(MMToken::StringLiteral)) {
721 HD.
Umbrella = LeadingToken == MMToken::UmbrellaKeyword;
725 if (
Tok.
is(MMToken::LBrace)) {
726 SourceLocation LBraceLoc = consumeToken();
728 while (!
Tok.
is(MMToken::RBrace) && !
Tok.
is(MMToken::EndOfFile)) {
730 StringRef Str =
Tok.getString();
731 SourceLocation Loc = consumeToken();
732 switch (llvm::StringSwitch<Attribute>(Str)
734 .Case(
"mtime", ModTime)
738 Diags.
Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
739 if (!
Tok.
is(MMToken::IntegerLiteral)) {
741 diag::err_mmap_invalid_header_attribute_value)
743 skipUntil(MMToken::RBrace);
752 Diags.
Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
753 if (!
Tok.
is(MMToken::IntegerLiteral)) {
755 diag::err_mmap_invalid_header_attribute_value)
757 skipUntil(MMToken::RBrace);
765 Diags.
Report(Loc, diag::err_mmap_expected_header_attribute);
766 skipUntil(MMToken::RBrace);
771 if (
Tok.
is(MMToken::RBrace))
775 Diags.
Report(LBraceLoc, diag::note_mmap_lbrace_match);
779 return std::move(HD);
786std::optional<ExcludeDecl>
787ModuleMapFileParser::parseExcludeDecl(clang::SourceLocation LeadingLoc) {
789 if (!
Tok.
is(MMToken::Identifier)) {
799 return std::move(ED);
806std::optional<UmbrellaDirDecl>
807ModuleMapFileParser::parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc) {
811 if (!
Tok.
is(MMToken::StringLiteral)) {
820 return std::move(UDD);
827std::optional<LinkDecl> ModuleMapFileParser::parseLinkDecl() {
828 assert(
Tok.
is(MMToken::LinkKeyword));
834 if (
Tok.
is(MMToken::FrameworkKeyword)) {
840 if (!
Tok.
is(MMToken::StringLiteral)) {
849 return std::move(LD);
852SourceLocation ModuleMapFileParser::consumeToken() {
861 case tok::raw_identifier: {
863 Tok.StringData = RI.data();
864 Tok.StringLength = RI.size();
865 Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI)
866 .Case(
"config_macros", MMToken::ConfigMacros)
867 .Case(
"conflict", MMToken::Conflict)
868 .Case(
"exclude", MMToken::ExcludeKeyword)
869 .Case(
"explicit", MMToken::ExplicitKeyword)
870 .Case(
"export", MMToken::ExportKeyword)
871 .Case(
"export_as", MMToken::ExportAsKeyword)
872 .Case(
"extern", MMToken::ExternKeyword)
873 .Case(
"framework", MMToken::FrameworkKeyword)
874 .Case(
"header", MMToken::HeaderKeyword)
875 .Case(
"link", MMToken::LinkKeyword)
876 .Case(
"module", MMToken::ModuleKeyword)
877 .Case(
"private", MMToken::PrivateKeyword)
878 .Case(
"requires", MMToken::RequiresKeyword)
879 .Case(
"textual", MMToken::TextualKeyword)
880 .Case(
"umbrella", MMToken::UmbrellaKeyword)
881 .Case(
"use", MMToken::UseKeyword)
882 .Default(MMToken::Identifier);
887 Tok.Kind = MMToken::Comma;
891 Tok.Kind = MMToken::EndOfFile;
895 Tok.Kind = MMToken::LBrace;
899 Tok.Kind = MMToken::LSquare;
903 Tok.Kind = MMToken::Period;
907 Tok.Kind = MMToken::RBrace;
911 Tok.Kind = MMToken::RSquare;
915 Tok.Kind = MMToken::Star;
919 Tok.Kind = MMToken::Exclaim;
922 case tok::string_literal: {
930 Tok.Kind = MMToken::StringLiteral;
936 case tok::numeric_constant: {
940 .getAsInteger(0,
Value)) {
946 Tok.Kind = MMToken::IntegerLiteral;
960 auto NextIsIdent = [&](StringRef Str) ->
bool {
965 if (NextIsIdent(
"pragma") && NextIsIdent(
"clang") &&
966 NextIsIdent(
"module") && NextIsIdent(
"contents")) {
967 Tok.Kind = MMToken::EndOfFile;
982void ModuleMapFileParser::skipUntil(MMToken::TokenKind K) {
983 unsigned braceDepth = 0;
984 unsigned squareDepth = 0;
987 case MMToken::EndOfFile:
990 case MMToken::LBrace:
991 if (
Tok.
is(K) && braceDepth == 0 && squareDepth == 0)
997 case MMToken::LSquare:
998 if (
Tok.
is(K) && braceDepth == 0 && squareDepth == 0)
1004 case MMToken::RBrace:
1011 case MMToken::RSquare:
1012 if (squareDepth > 0)
1019 if (braceDepth == 0 && squareDepth == 0 &&
Tok.
is(K))
1035bool ModuleMapFileParser::parseModuleId(
ModuleId &Id) {
1038 if (
Tok.
is(MMToken::Identifier) ||
Tok.
is(MMToken::StringLiteral)) {
1047 if (!
Tok.
is(MMToken::Period))
1068bool ModuleMapFileParser::parseOptionalAttributes(ModuleAttributes &Attrs) {
1071 while (
Tok.
is(MMToken::LSquare)) {
1073 SourceLocation LSquareLoc = consumeToken();
1076 if (!
Tok.
is(MMToken::Identifier)) {
1078 skipUntil(MMToken::RSquare);
1079 if (
Tok.
is(MMToken::RSquare))
1085 enum AttributeKind {
1099 AT_no_undeclared_includes
1103 AttributeKind Attribute =
1104 llvm::StringSwitch<AttributeKind>(
Tok.getString())
1105 .Case(
"exhaustive", AT_exhaustive)
1106 .Case(
"extern_c", AT_extern_c)
1107 .Case(
"no_undeclared_includes", AT_no_undeclared_includes)
1108 .Case(
"system", AT_system)
1109 .Default(AT_unknown);
1110 switch (Attribute) {
1128 case AT_no_undeclared_includes:
1135 if (!
Tok.
is(MMToken::RSquare)) {
1137 Diags.
Report(LSquareLoc, diag::note_mmap_lsquare_match);
1138 skipUntil(MMToken::RSquare);
1142 if (
Tok.
is(MMToken::RSquare))
1152static void dumpModule(
const ModuleDecl &MD, llvm::raw_ostream &
out,
int depth);
1155 llvm::raw_ostream &
out,
int depth) {
1156 out.indent(depth * 2);
1157 out <<
"extern module " << formatModuleId(EMD.
Id) <<
" \"" << EMD.
Path
1162 for (
const auto &
Decl : Decls) {
1163 std::visit(llvm::makeVisitor(
1165 out.indent(depth * 2);
1166 out <<
"requires\n";
1169 out.indent(depth * 2);
1178 out <<
"header \"" << HD.
Path <<
"\"\n";
1181 out.indent(depth * 2);
1182 out <<
"umbrella\n";
1186 out.indent(depth * 2);
1190 out.indent(depth * 2);
1192 << (ED.Wildcard ?
"*" : formatModuleId(ED.Id)) <<
"\n";
1195 out.indent(depth * 2);
1196 out <<
"export as\n";
1202 out.indent(depth * 2);
1206 out.indent(depth * 2);
1210 out.indent(depth * 2);
1211 out <<
"config_macros ";
1213 out <<
"[exhaustive] ";
1214 for (
auto Macro : CMD.Macros) {
1220 out.indent(depth * 2);
1221 out <<
"conflicts\n";
1229 out.indent(depth * 2);
1230 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::optional< ModuleMapFile > parseModuleMap(FileID ID, clang::DirectoryEntryRef Dir, SourceManager &SM, DiagnosticsEngine &Diags, bool IsSystem, bool ImplicitlyDiscovered, unsigned *Offset)
Parse a module map file into an in memory representation.
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.
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