1*700637cbSDimitry Andric //===- ModuleMapFile.cpp - ------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric ///
9*700637cbSDimitry Andric /// \file
10*700637cbSDimitry Andric /// This file handles parsing of modulemap files into a simple AST.
11*700637cbSDimitry Andric ///
12*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
13*700637cbSDimitry Andric
14*700637cbSDimitry Andric #include "clang/Lex/ModuleMapFile.h"
15*700637cbSDimitry Andric #include "clang/Basic/Diagnostic.h"
16*700637cbSDimitry Andric #include "clang/Basic/LangOptions.h"
17*700637cbSDimitry Andric #include "clang/Basic/Module.h"
18*700637cbSDimitry Andric #include "clang/Basic/SourceManager.h"
19*700637cbSDimitry Andric #include "clang/Lex/LexDiagnostic.h"
20*700637cbSDimitry Andric #include "clang/Lex/Lexer.h"
21*700637cbSDimitry Andric #include "clang/Lex/ModuleMap.h"
22*700637cbSDimitry Andric #include "llvm/ADT/STLExtras.h"
23*700637cbSDimitry Andric #include <optional>
24*700637cbSDimitry Andric
25*700637cbSDimitry Andric using namespace clang;
26*700637cbSDimitry Andric using namespace modulemap;
27*700637cbSDimitry Andric
28*700637cbSDimitry Andric namespace {
29*700637cbSDimitry Andric struct MMToken {
30*700637cbSDimitry Andric enum TokenKind {
31*700637cbSDimitry Andric Comma,
32*700637cbSDimitry Andric ConfigMacros,
33*700637cbSDimitry Andric Conflict,
34*700637cbSDimitry Andric EndOfFile,
35*700637cbSDimitry Andric HeaderKeyword,
36*700637cbSDimitry Andric Identifier,
37*700637cbSDimitry Andric Exclaim,
38*700637cbSDimitry Andric ExcludeKeyword,
39*700637cbSDimitry Andric ExplicitKeyword,
40*700637cbSDimitry Andric ExportKeyword,
41*700637cbSDimitry Andric ExportAsKeyword,
42*700637cbSDimitry Andric ExternKeyword,
43*700637cbSDimitry Andric FrameworkKeyword,
44*700637cbSDimitry Andric LinkKeyword,
45*700637cbSDimitry Andric ModuleKeyword,
46*700637cbSDimitry Andric Period,
47*700637cbSDimitry Andric PrivateKeyword,
48*700637cbSDimitry Andric UmbrellaKeyword,
49*700637cbSDimitry Andric UseKeyword,
50*700637cbSDimitry Andric RequiresKeyword,
51*700637cbSDimitry Andric Star,
52*700637cbSDimitry Andric StringLiteral,
53*700637cbSDimitry Andric IntegerLiteral,
54*700637cbSDimitry Andric TextualKeyword,
55*700637cbSDimitry Andric LBrace,
56*700637cbSDimitry Andric RBrace,
57*700637cbSDimitry Andric LSquare,
58*700637cbSDimitry Andric RSquare
59*700637cbSDimitry Andric } Kind;
60*700637cbSDimitry Andric
61*700637cbSDimitry Andric SourceLocation::UIntTy Location;
62*700637cbSDimitry Andric unsigned StringLength;
63*700637cbSDimitry Andric union {
64*700637cbSDimitry Andric // If Kind != IntegerLiteral.
65*700637cbSDimitry Andric const char *StringData;
66*700637cbSDimitry Andric
67*700637cbSDimitry Andric // If Kind == IntegerLiteral.
68*700637cbSDimitry Andric uint64_t IntegerValue;
69*700637cbSDimitry Andric };
70*700637cbSDimitry Andric
clear__anon5501bfd60111::MMToken71*700637cbSDimitry Andric void clear() {
72*700637cbSDimitry Andric Kind = EndOfFile;
73*700637cbSDimitry Andric Location = 0;
74*700637cbSDimitry Andric StringLength = 0;
75*700637cbSDimitry Andric StringData = nullptr;
76*700637cbSDimitry Andric }
77*700637cbSDimitry Andric
is__anon5501bfd60111::MMToken78*700637cbSDimitry Andric bool is(TokenKind K) const { return Kind == K; }
79*700637cbSDimitry Andric
getLocation__anon5501bfd60111::MMToken80*700637cbSDimitry Andric SourceLocation getLocation() const {
81*700637cbSDimitry Andric return SourceLocation::getFromRawEncoding(Location);
82*700637cbSDimitry Andric }
83*700637cbSDimitry Andric
getInteger__anon5501bfd60111::MMToken84*700637cbSDimitry Andric uint64_t getInteger() const {
85*700637cbSDimitry Andric return Kind == IntegerLiteral ? IntegerValue : 0;
86*700637cbSDimitry Andric }
87*700637cbSDimitry Andric
getString__anon5501bfd60111::MMToken88*700637cbSDimitry Andric StringRef getString() const {
89*700637cbSDimitry Andric return Kind == IntegerLiteral ? StringRef()
90*700637cbSDimitry Andric : StringRef(StringData, StringLength);
91*700637cbSDimitry Andric }
92*700637cbSDimitry Andric };
93*700637cbSDimitry Andric
94*700637cbSDimitry Andric struct ModuleMapFileParser {
95*700637cbSDimitry Andric // External context
96*700637cbSDimitry Andric Lexer &L;
97*700637cbSDimitry Andric DiagnosticsEngine &Diags;
98*700637cbSDimitry Andric
99*700637cbSDimitry Andric /// Parsed representation of the module map file
100*700637cbSDimitry Andric ModuleMapFile MMF{};
101*700637cbSDimitry Andric
102*700637cbSDimitry Andric bool HadError = false;
103*700637cbSDimitry Andric
104*700637cbSDimitry Andric /// The current token.
105*700637cbSDimitry Andric MMToken Tok{};
106*700637cbSDimitry Andric
107*700637cbSDimitry Andric bool parseTopLevelDecls();
108*700637cbSDimitry Andric std::optional<ModuleDecl> parseModuleDecl(bool TopLevel);
109*700637cbSDimitry Andric std::optional<ExternModuleDecl> parseExternModuleDecl();
110*700637cbSDimitry Andric std::optional<ConfigMacrosDecl> parseConfigMacrosDecl();
111*700637cbSDimitry Andric std::optional<ConflictDecl> parseConflictDecl();
112*700637cbSDimitry Andric std::optional<ExportDecl> parseExportDecl();
113*700637cbSDimitry Andric std::optional<ExportAsDecl> parseExportAsDecl();
114*700637cbSDimitry Andric std::optional<UseDecl> parseUseDecl();
115*700637cbSDimitry Andric std::optional<RequiresDecl> parseRequiresDecl();
116*700637cbSDimitry Andric std::optional<HeaderDecl> parseHeaderDecl(MMToken::TokenKind LeadingToken,
117*700637cbSDimitry Andric SourceLocation LeadingLoc);
118*700637cbSDimitry Andric std::optional<ExcludeDecl> parseExcludeDecl(clang::SourceLocation LeadingLoc);
119*700637cbSDimitry Andric std::optional<UmbrellaDirDecl>
120*700637cbSDimitry Andric parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
121*700637cbSDimitry Andric std::optional<LinkDecl> parseLinkDecl();
122*700637cbSDimitry Andric
123*700637cbSDimitry Andric SourceLocation consumeToken();
124*700637cbSDimitry Andric void skipUntil(MMToken::TokenKind K);
125*700637cbSDimitry Andric bool parseModuleId(ModuleId &Id);
126*700637cbSDimitry Andric bool parseOptionalAttributes(ModuleAttributes &Attrs);
127*700637cbSDimitry Andric
getLocation__anon5501bfd60111::ModuleMapFileParser128*700637cbSDimitry Andric SourceLocation getLocation() const { return Tok.getLocation(); };
129*700637cbSDimitry Andric };
130*700637cbSDimitry Andric
formatModuleId(const ModuleId & Id)131*700637cbSDimitry Andric std::string formatModuleId(const ModuleId &Id) {
132*700637cbSDimitry Andric std::string result;
133*700637cbSDimitry Andric {
134*700637cbSDimitry Andric llvm::raw_string_ostream OS(result);
135*700637cbSDimitry Andric
136*700637cbSDimitry Andric for (unsigned I = 0, N = Id.size(); I != N; ++I) {
137*700637cbSDimitry Andric if (I)
138*700637cbSDimitry Andric OS << ".";
139*700637cbSDimitry Andric OS << Id[I].first;
140*700637cbSDimitry Andric }
141*700637cbSDimitry Andric }
142*700637cbSDimitry Andric
143*700637cbSDimitry Andric return result;
144*700637cbSDimitry Andric }
145*700637cbSDimitry Andric } // end anonymous namespace
146*700637cbSDimitry Andric
147*700637cbSDimitry Andric std::optional<ModuleMapFile>
parseModuleMap(FileID ID,clang::DirectoryEntryRef Dir,SourceManager & SM,DiagnosticsEngine & Diags,bool IsSystem,unsigned * Offset)148*700637cbSDimitry Andric modulemap::parseModuleMap(FileID ID, clang::DirectoryEntryRef Dir,
149*700637cbSDimitry Andric SourceManager &SM, DiagnosticsEngine &Diags,
150*700637cbSDimitry Andric bool IsSystem, unsigned *Offset) {
151*700637cbSDimitry Andric std::optional<llvm::MemoryBufferRef> Buffer = SM.getBufferOrNone(ID);
152*700637cbSDimitry Andric LangOptions LOpts;
153*700637cbSDimitry Andric LOpts.LangStd = clang::LangStandard::lang_c99;
154*700637cbSDimitry Andric Lexer L(SM.getLocForStartOfFile(ID), LOpts, Buffer->getBufferStart(),
155*700637cbSDimitry Andric Buffer->getBufferStart() + (Offset ? *Offset : 0),
156*700637cbSDimitry Andric Buffer->getBufferEnd());
157*700637cbSDimitry Andric SourceLocation Start = L.getSourceLocation();
158*700637cbSDimitry Andric
159*700637cbSDimitry Andric ModuleMapFileParser Parser{L, Diags};
160*700637cbSDimitry Andric bool Failed = Parser.parseTopLevelDecls();
161*700637cbSDimitry Andric
162*700637cbSDimitry Andric if (Offset) {
163*700637cbSDimitry Andric auto Loc = SM.getDecomposedLoc(Parser.getLocation());
164*700637cbSDimitry Andric assert(Loc.first == ID && "stopped in a different file?");
165*700637cbSDimitry Andric *Offset = Loc.second;
166*700637cbSDimitry Andric }
167*700637cbSDimitry Andric
168*700637cbSDimitry Andric if (Failed)
169*700637cbSDimitry Andric return std::nullopt;
170*700637cbSDimitry Andric Parser.MMF.ID = ID;
171*700637cbSDimitry Andric Parser.MMF.Dir = Dir;
172*700637cbSDimitry Andric Parser.MMF.Start = Start;
173*700637cbSDimitry Andric Parser.MMF.IsSystem = IsSystem;
174*700637cbSDimitry Andric return std::move(Parser.MMF);
175*700637cbSDimitry Andric }
176*700637cbSDimitry Andric
parseTopLevelDecls()177*700637cbSDimitry Andric bool ModuleMapFileParser::parseTopLevelDecls() {
178*700637cbSDimitry Andric Tok.clear();
179*700637cbSDimitry Andric consumeToken();
180*700637cbSDimitry Andric do {
181*700637cbSDimitry Andric switch (Tok.Kind) {
182*700637cbSDimitry Andric case MMToken::EndOfFile:
183*700637cbSDimitry Andric return HadError;
184*700637cbSDimitry Andric case MMToken::ExternKeyword: {
185*700637cbSDimitry Andric std::optional<ExternModuleDecl> EMD = parseExternModuleDecl();
186*700637cbSDimitry Andric if (EMD)
187*700637cbSDimitry Andric MMF.Decls.push_back(std::move(*EMD));
188*700637cbSDimitry Andric break;
189*700637cbSDimitry Andric }
190*700637cbSDimitry Andric case MMToken::ExplicitKeyword:
191*700637cbSDimitry Andric case MMToken::ModuleKeyword:
192*700637cbSDimitry Andric case MMToken::FrameworkKeyword: {
193*700637cbSDimitry Andric std::optional<ModuleDecl> MD = parseModuleDecl(true);
194*700637cbSDimitry Andric if (MD)
195*700637cbSDimitry Andric MMF.Decls.push_back(std::move(*MD));
196*700637cbSDimitry Andric break;
197*700637cbSDimitry Andric }
198*700637cbSDimitry Andric case MMToken::Comma:
199*700637cbSDimitry Andric case MMToken::ConfigMacros:
200*700637cbSDimitry Andric case MMToken::Conflict:
201*700637cbSDimitry Andric case MMToken::Exclaim:
202*700637cbSDimitry Andric case MMToken::ExcludeKeyword:
203*700637cbSDimitry Andric case MMToken::ExportKeyword:
204*700637cbSDimitry Andric case MMToken::ExportAsKeyword:
205*700637cbSDimitry Andric case MMToken::HeaderKeyword:
206*700637cbSDimitry Andric case MMToken::Identifier:
207*700637cbSDimitry Andric case MMToken::LBrace:
208*700637cbSDimitry Andric case MMToken::LinkKeyword:
209*700637cbSDimitry Andric case MMToken::LSquare:
210*700637cbSDimitry Andric case MMToken::Period:
211*700637cbSDimitry Andric case MMToken::PrivateKeyword:
212*700637cbSDimitry Andric case MMToken::RBrace:
213*700637cbSDimitry Andric case MMToken::RSquare:
214*700637cbSDimitry Andric case MMToken::RequiresKeyword:
215*700637cbSDimitry Andric case MMToken::Star:
216*700637cbSDimitry Andric case MMToken::StringLiteral:
217*700637cbSDimitry Andric case MMToken::IntegerLiteral:
218*700637cbSDimitry Andric case MMToken::TextualKeyword:
219*700637cbSDimitry Andric case MMToken::UmbrellaKeyword:
220*700637cbSDimitry Andric case MMToken::UseKeyword:
221*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
222*700637cbSDimitry Andric HadError = true;
223*700637cbSDimitry Andric consumeToken();
224*700637cbSDimitry Andric break;
225*700637cbSDimitry Andric }
226*700637cbSDimitry Andric } while (true);
227*700637cbSDimitry Andric }
228*700637cbSDimitry Andric
229*700637cbSDimitry Andric /// Parse a module declaration.
230*700637cbSDimitry Andric ///
231*700637cbSDimitry Andric /// module-declaration:
232*700637cbSDimitry Andric /// 'extern' 'module' module-id string-literal
233*700637cbSDimitry Andric /// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
234*700637cbSDimitry Andric /// { module-member* }
235*700637cbSDimitry Andric ///
236*700637cbSDimitry Andric /// module-member:
237*700637cbSDimitry Andric /// requires-declaration
238*700637cbSDimitry Andric /// header-declaration
239*700637cbSDimitry Andric /// submodule-declaration
240*700637cbSDimitry Andric /// export-declaration
241*700637cbSDimitry Andric /// export-as-declaration
242*700637cbSDimitry Andric /// link-declaration
243*700637cbSDimitry Andric ///
244*700637cbSDimitry Andric /// submodule-declaration:
245*700637cbSDimitry Andric /// module-declaration
246*700637cbSDimitry Andric /// inferred-submodule-declaration
parseModuleDecl(bool TopLevel)247*700637cbSDimitry Andric std::optional<ModuleDecl> ModuleMapFileParser::parseModuleDecl(bool TopLevel) {
248*700637cbSDimitry Andric assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
249*700637cbSDimitry Andric Tok.is(MMToken::FrameworkKeyword));
250*700637cbSDimitry Andric
251*700637cbSDimitry Andric ModuleDecl MDecl;
252*700637cbSDimitry Andric
253*700637cbSDimitry Andric SourceLocation ExplicitLoc;
254*700637cbSDimitry Andric MDecl.Explicit = false;
255*700637cbSDimitry Andric MDecl.Framework = false;
256*700637cbSDimitry Andric
257*700637cbSDimitry Andric // Parse 'explicit' keyword, if present.
258*700637cbSDimitry Andric if (Tok.is(MMToken::ExplicitKeyword)) {
259*700637cbSDimitry Andric MDecl.Location = ExplicitLoc = consumeToken();
260*700637cbSDimitry Andric MDecl.Explicit = true;
261*700637cbSDimitry Andric }
262*700637cbSDimitry Andric
263*700637cbSDimitry Andric // Parse 'framework' keyword, if present.
264*700637cbSDimitry Andric if (Tok.is(MMToken::FrameworkKeyword)) {
265*700637cbSDimitry Andric SourceLocation FrameworkLoc = consumeToken();
266*700637cbSDimitry Andric if (!MDecl.Location.isValid())
267*700637cbSDimitry Andric MDecl.Location = FrameworkLoc;
268*700637cbSDimitry Andric MDecl.Framework = true;
269*700637cbSDimitry Andric }
270*700637cbSDimitry Andric
271*700637cbSDimitry Andric // Parse 'module' keyword.
272*700637cbSDimitry Andric if (!Tok.is(MMToken::ModuleKeyword)) {
273*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
274*700637cbSDimitry Andric consumeToken();
275*700637cbSDimitry Andric HadError = true;
276*700637cbSDimitry Andric return std::nullopt;
277*700637cbSDimitry Andric }
278*700637cbSDimitry Andric SourceLocation ModuleLoc = consumeToken();
279*700637cbSDimitry Andric if (!MDecl.Location.isValid())
280*700637cbSDimitry Andric MDecl.Location = ModuleLoc; // 'module' keyword
281*700637cbSDimitry Andric
282*700637cbSDimitry Andric // If we have a wildcard for the module name, this is an inferred submodule.
283*700637cbSDimitry Andric // We treat it as a normal module at this point.
284*700637cbSDimitry Andric if (Tok.is(MMToken::Star)) {
285*700637cbSDimitry Andric SourceLocation StarLoc = consumeToken();
286*700637cbSDimitry Andric MDecl.Id.push_back({"*", StarLoc});
287*700637cbSDimitry Andric if (TopLevel && !MDecl.Framework) {
288*700637cbSDimitry Andric Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
289*700637cbSDimitry Andric HadError = true;
290*700637cbSDimitry Andric return std::nullopt;
291*700637cbSDimitry Andric }
292*700637cbSDimitry Andric } else {
293*700637cbSDimitry Andric // Parse the module name.
294*700637cbSDimitry Andric if (parseModuleId(MDecl.Id)) {
295*700637cbSDimitry Andric HadError = true;
296*700637cbSDimitry Andric return std::nullopt;
297*700637cbSDimitry Andric }
298*700637cbSDimitry Andric if (!TopLevel) {
299*700637cbSDimitry Andric if (MDecl.Id.size() > 1) {
300*700637cbSDimitry Andric Diags.Report(MDecl.Id.front().second,
301*700637cbSDimitry Andric diag::err_mmap_nested_submodule_id)
302*700637cbSDimitry Andric << SourceRange(MDecl.Id.front().second, MDecl.Id.back().second);
303*700637cbSDimitry Andric
304*700637cbSDimitry Andric HadError = true;
305*700637cbSDimitry Andric }
306*700637cbSDimitry Andric } else if (MDecl.Id.size() == 1 && MDecl.Explicit) {
307*700637cbSDimitry Andric // Top-level modules can't be explicit.
308*700637cbSDimitry Andric Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
309*700637cbSDimitry Andric MDecl.Explicit = false;
310*700637cbSDimitry Andric HadError = true;
311*700637cbSDimitry Andric }
312*700637cbSDimitry Andric }
313*700637cbSDimitry Andric
314*700637cbSDimitry Andric // Parse the optional attribute list.
315*700637cbSDimitry Andric if (parseOptionalAttributes(MDecl.Attrs))
316*700637cbSDimitry Andric return std::nullopt;
317*700637cbSDimitry Andric
318*700637cbSDimitry Andric // Parse the opening brace.
319*700637cbSDimitry Andric if (!Tok.is(MMToken::LBrace)) {
320*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
321*700637cbSDimitry Andric << MDecl.Id.back().first;
322*700637cbSDimitry Andric HadError = true;
323*700637cbSDimitry Andric return std::nullopt;
324*700637cbSDimitry Andric }
325*700637cbSDimitry Andric SourceLocation LBraceLoc = consumeToken();
326*700637cbSDimitry Andric
327*700637cbSDimitry Andric bool Done = false;
328*700637cbSDimitry Andric do {
329*700637cbSDimitry Andric std::optional<Decl> SubDecl;
330*700637cbSDimitry Andric switch (Tok.Kind) {
331*700637cbSDimitry Andric case MMToken::EndOfFile:
332*700637cbSDimitry Andric case MMToken::RBrace:
333*700637cbSDimitry Andric Done = true;
334*700637cbSDimitry Andric break;
335*700637cbSDimitry Andric
336*700637cbSDimitry Andric case MMToken::ConfigMacros:
337*700637cbSDimitry Andric // Only top-level modules can have configuration macros.
338*700637cbSDimitry Andric if (!TopLevel)
339*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_config_macro_submodule);
340*700637cbSDimitry Andric SubDecl = parseConfigMacrosDecl();
341*700637cbSDimitry Andric break;
342*700637cbSDimitry Andric
343*700637cbSDimitry Andric case MMToken::Conflict:
344*700637cbSDimitry Andric SubDecl = parseConflictDecl();
345*700637cbSDimitry Andric break;
346*700637cbSDimitry Andric
347*700637cbSDimitry Andric case MMToken::ExternKeyword:
348*700637cbSDimitry Andric SubDecl = parseExternModuleDecl();
349*700637cbSDimitry Andric break;
350*700637cbSDimitry Andric
351*700637cbSDimitry Andric case MMToken::ExplicitKeyword:
352*700637cbSDimitry Andric case MMToken::FrameworkKeyword:
353*700637cbSDimitry Andric case MMToken::ModuleKeyword:
354*700637cbSDimitry Andric SubDecl = parseModuleDecl(false);
355*700637cbSDimitry Andric break;
356*700637cbSDimitry Andric
357*700637cbSDimitry Andric case MMToken::ExportKeyword:
358*700637cbSDimitry Andric SubDecl = parseExportDecl();
359*700637cbSDimitry Andric break;
360*700637cbSDimitry Andric
361*700637cbSDimitry Andric case MMToken::ExportAsKeyword:
362*700637cbSDimitry Andric if (!TopLevel) {
363*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as);
364*700637cbSDimitry Andric parseExportAsDecl();
365*700637cbSDimitry Andric } else
366*700637cbSDimitry Andric SubDecl = parseExportAsDecl();
367*700637cbSDimitry Andric break;
368*700637cbSDimitry Andric
369*700637cbSDimitry Andric case MMToken::UseKeyword:
370*700637cbSDimitry Andric SubDecl = parseUseDecl();
371*700637cbSDimitry Andric break;
372*700637cbSDimitry Andric
373*700637cbSDimitry Andric case MMToken::RequiresKeyword:
374*700637cbSDimitry Andric SubDecl = parseRequiresDecl();
375*700637cbSDimitry Andric break;
376*700637cbSDimitry Andric
377*700637cbSDimitry Andric case MMToken::TextualKeyword:
378*700637cbSDimitry Andric SubDecl = parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
379*700637cbSDimitry Andric break;
380*700637cbSDimitry Andric
381*700637cbSDimitry Andric case MMToken::UmbrellaKeyword: {
382*700637cbSDimitry Andric SourceLocation UmbrellaLoc = consumeToken();
383*700637cbSDimitry Andric if (Tok.is(MMToken::HeaderKeyword))
384*700637cbSDimitry Andric SubDecl = parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
385*700637cbSDimitry Andric else
386*700637cbSDimitry Andric SubDecl = parseUmbrellaDirDecl(UmbrellaLoc);
387*700637cbSDimitry Andric break;
388*700637cbSDimitry Andric }
389*700637cbSDimitry Andric
390*700637cbSDimitry Andric case MMToken::ExcludeKeyword: {
391*700637cbSDimitry Andric SourceLocation ExcludeLoc = consumeToken();
392*700637cbSDimitry Andric if (Tok.is(MMToken::HeaderKeyword))
393*700637cbSDimitry Andric SubDecl = parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
394*700637cbSDimitry Andric else
395*700637cbSDimitry Andric SubDecl = parseExcludeDecl(ExcludeLoc);
396*700637cbSDimitry Andric break;
397*700637cbSDimitry Andric }
398*700637cbSDimitry Andric
399*700637cbSDimitry Andric case MMToken::PrivateKeyword:
400*700637cbSDimitry Andric SubDecl = parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
401*700637cbSDimitry Andric break;
402*700637cbSDimitry Andric
403*700637cbSDimitry Andric case MMToken::HeaderKeyword:
404*700637cbSDimitry Andric SubDecl = parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
405*700637cbSDimitry Andric break;
406*700637cbSDimitry Andric
407*700637cbSDimitry Andric case MMToken::LinkKeyword:
408*700637cbSDimitry Andric SubDecl = parseLinkDecl();
409*700637cbSDimitry Andric break;
410*700637cbSDimitry Andric
411*700637cbSDimitry Andric default:
412*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
413*700637cbSDimitry Andric consumeToken();
414*700637cbSDimitry Andric break;
415*700637cbSDimitry Andric }
416*700637cbSDimitry Andric if (SubDecl)
417*700637cbSDimitry Andric MDecl.Decls.push_back(std::move(*SubDecl));
418*700637cbSDimitry Andric } while (!Done);
419*700637cbSDimitry Andric
420*700637cbSDimitry Andric if (Tok.is(MMToken::RBrace))
421*700637cbSDimitry Andric consumeToken();
422*700637cbSDimitry Andric else {
423*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
424*700637cbSDimitry Andric Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
425*700637cbSDimitry Andric HadError = true;
426*700637cbSDimitry Andric }
427*700637cbSDimitry Andric return std::move(MDecl);
428*700637cbSDimitry Andric }
429*700637cbSDimitry Andric
parseExternModuleDecl()430*700637cbSDimitry Andric std::optional<ExternModuleDecl> ModuleMapFileParser::parseExternModuleDecl() {
431*700637cbSDimitry Andric assert(Tok.is(MMToken::ExternKeyword));
432*700637cbSDimitry Andric ExternModuleDecl EMD;
433*700637cbSDimitry Andric EMD.Location = consumeToken(); // 'extern' keyword
434*700637cbSDimitry Andric
435*700637cbSDimitry Andric // Parse 'module' keyword.
436*700637cbSDimitry Andric if (!Tok.is(MMToken::ModuleKeyword)) {
437*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
438*700637cbSDimitry Andric consumeToken();
439*700637cbSDimitry Andric HadError = true;
440*700637cbSDimitry Andric return std::nullopt;
441*700637cbSDimitry Andric }
442*700637cbSDimitry Andric consumeToken(); // 'module' keyword
443*700637cbSDimitry Andric
444*700637cbSDimitry Andric // Parse the module name.
445*700637cbSDimitry Andric if (parseModuleId(EMD.Id)) {
446*700637cbSDimitry Andric HadError = true;
447*700637cbSDimitry Andric return std::nullopt;
448*700637cbSDimitry Andric }
449*700637cbSDimitry Andric
450*700637cbSDimitry Andric // Parse the referenced module map file name.
451*700637cbSDimitry Andric if (!Tok.is(MMToken::StringLiteral)) {
452*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file);
453*700637cbSDimitry Andric HadError = true;
454*700637cbSDimitry Andric return std::nullopt;
455*700637cbSDimitry Andric }
456*700637cbSDimitry Andric EMD.Path = Tok.getString();
457*700637cbSDimitry Andric consumeToken(); // filename
458*700637cbSDimitry Andric
459*700637cbSDimitry Andric return std::move(EMD);
460*700637cbSDimitry Andric }
461*700637cbSDimitry Andric
462*700637cbSDimitry Andric /// Parse a configuration macro declaration.
463*700637cbSDimitry Andric ///
464*700637cbSDimitry Andric /// module-declaration:
465*700637cbSDimitry Andric /// 'config_macros' attributes[opt] config-macro-list?
466*700637cbSDimitry Andric ///
467*700637cbSDimitry Andric /// config-macro-list:
468*700637cbSDimitry Andric /// identifier (',' identifier)?
parseConfigMacrosDecl()469*700637cbSDimitry Andric std::optional<ConfigMacrosDecl> ModuleMapFileParser::parseConfigMacrosDecl() {
470*700637cbSDimitry Andric assert(Tok.is(MMToken::ConfigMacros));
471*700637cbSDimitry Andric ConfigMacrosDecl CMDecl;
472*700637cbSDimitry Andric CMDecl.Location = consumeToken();
473*700637cbSDimitry Andric
474*700637cbSDimitry Andric // Parse the optional attributes.
475*700637cbSDimitry Andric ModuleAttributes Attrs;
476*700637cbSDimitry Andric if (parseOptionalAttributes(Attrs))
477*700637cbSDimitry Andric return std::nullopt;
478*700637cbSDimitry Andric
479*700637cbSDimitry Andric CMDecl.Exhaustive = Attrs.IsExhaustive;
480*700637cbSDimitry Andric
481*700637cbSDimitry Andric // If we don't have an identifier, we're done.
482*700637cbSDimitry Andric // FIXME: Support macros with the same name as a keyword here.
483*700637cbSDimitry Andric if (!Tok.is(MMToken::Identifier))
484*700637cbSDimitry Andric return std::nullopt;
485*700637cbSDimitry Andric
486*700637cbSDimitry Andric // Consume the first identifier.
487*700637cbSDimitry Andric CMDecl.Macros.push_back(Tok.getString());
488*700637cbSDimitry Andric consumeToken();
489*700637cbSDimitry Andric
490*700637cbSDimitry Andric do {
491*700637cbSDimitry Andric // If there's a comma, consume it.
492*700637cbSDimitry Andric if (!Tok.is(MMToken::Comma))
493*700637cbSDimitry Andric break;
494*700637cbSDimitry Andric consumeToken();
495*700637cbSDimitry Andric
496*700637cbSDimitry Andric // We expect to see a macro name here.
497*700637cbSDimitry Andric // FIXME: Support macros with the same name as a keyword here.
498*700637cbSDimitry Andric if (!Tok.is(MMToken::Identifier)) {
499*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
500*700637cbSDimitry Andric return std::nullopt;
501*700637cbSDimitry Andric }
502*700637cbSDimitry Andric
503*700637cbSDimitry Andric // Consume the macro name.
504*700637cbSDimitry Andric CMDecl.Macros.push_back(Tok.getString());
505*700637cbSDimitry Andric consumeToken();
506*700637cbSDimitry Andric } while (true);
507*700637cbSDimitry Andric return std::move(CMDecl);
508*700637cbSDimitry Andric }
509*700637cbSDimitry Andric
510*700637cbSDimitry Andric /// Parse a conflict declaration.
511*700637cbSDimitry Andric ///
512*700637cbSDimitry Andric /// module-declaration:
513*700637cbSDimitry Andric /// 'conflict' module-id ',' string-literal
parseConflictDecl()514*700637cbSDimitry Andric std::optional<ConflictDecl> ModuleMapFileParser::parseConflictDecl() {
515*700637cbSDimitry Andric assert(Tok.is(MMToken::Conflict));
516*700637cbSDimitry Andric ConflictDecl CD;
517*700637cbSDimitry Andric CD.Location = consumeToken();
518*700637cbSDimitry Andric
519*700637cbSDimitry Andric // Parse the module-id.
520*700637cbSDimitry Andric if (parseModuleId(CD.Id))
521*700637cbSDimitry Andric return std::nullopt;
522*700637cbSDimitry Andric
523*700637cbSDimitry Andric // Parse the ','.
524*700637cbSDimitry Andric if (!Tok.is(MMToken::Comma)) {
525*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)
526*700637cbSDimitry Andric << SourceRange(CD.Location);
527*700637cbSDimitry Andric return std::nullopt;
528*700637cbSDimitry Andric }
529*700637cbSDimitry Andric consumeToken();
530*700637cbSDimitry Andric
531*700637cbSDimitry Andric // Parse the message.
532*700637cbSDimitry Andric if (!Tok.is(MMToken::StringLiteral)) {
533*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)
534*700637cbSDimitry Andric << formatModuleId(CD.Id);
535*700637cbSDimitry Andric return std::nullopt;
536*700637cbSDimitry Andric }
537*700637cbSDimitry Andric CD.Message = Tok.getString();
538*700637cbSDimitry Andric consumeToken();
539*700637cbSDimitry Andric return std::move(CD);
540*700637cbSDimitry Andric }
541*700637cbSDimitry Andric
542*700637cbSDimitry Andric /// Parse a module export declaration.
543*700637cbSDimitry Andric ///
544*700637cbSDimitry Andric /// export-declaration:
545*700637cbSDimitry Andric /// 'export' wildcard-module-id
546*700637cbSDimitry Andric ///
547*700637cbSDimitry Andric /// wildcard-module-id:
548*700637cbSDimitry Andric /// identifier
549*700637cbSDimitry Andric /// '*'
550*700637cbSDimitry Andric /// identifier '.' wildcard-module-id
parseExportDecl()551*700637cbSDimitry Andric std::optional<ExportDecl> ModuleMapFileParser::parseExportDecl() {
552*700637cbSDimitry Andric assert(Tok.is(MMToken::ExportKeyword));
553*700637cbSDimitry Andric ExportDecl ED;
554*700637cbSDimitry Andric ED.Location = consumeToken();
555*700637cbSDimitry Andric
556*700637cbSDimitry Andric // Parse the module-id with an optional wildcard at the end.
557*700637cbSDimitry Andric ED.Wildcard = false;
558*700637cbSDimitry Andric do {
559*700637cbSDimitry Andric // FIXME: Support string-literal module names here.
560*700637cbSDimitry Andric if (Tok.is(MMToken::Identifier)) {
561*700637cbSDimitry Andric ED.Id.push_back(
562*700637cbSDimitry Andric std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
563*700637cbSDimitry Andric consumeToken();
564*700637cbSDimitry Andric
565*700637cbSDimitry Andric if (Tok.is(MMToken::Period)) {
566*700637cbSDimitry Andric consumeToken();
567*700637cbSDimitry Andric continue;
568*700637cbSDimitry Andric }
569*700637cbSDimitry Andric
570*700637cbSDimitry Andric break;
571*700637cbSDimitry Andric }
572*700637cbSDimitry Andric
573*700637cbSDimitry Andric if (Tok.is(MMToken::Star)) {
574*700637cbSDimitry Andric ED.Wildcard = true;
575*700637cbSDimitry Andric consumeToken();
576*700637cbSDimitry Andric break;
577*700637cbSDimitry Andric }
578*700637cbSDimitry Andric
579*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
580*700637cbSDimitry Andric HadError = true;
581*700637cbSDimitry Andric return std::nullopt;
582*700637cbSDimitry Andric } while (true);
583*700637cbSDimitry Andric
584*700637cbSDimitry Andric return std::move(ED);
585*700637cbSDimitry Andric }
586*700637cbSDimitry Andric
587*700637cbSDimitry Andric /// Parse a module export_as declaration.
588*700637cbSDimitry Andric ///
589*700637cbSDimitry Andric /// export-as-declaration:
590*700637cbSDimitry Andric /// 'export_as' identifier
parseExportAsDecl()591*700637cbSDimitry Andric std::optional<ExportAsDecl> ModuleMapFileParser::parseExportAsDecl() {
592*700637cbSDimitry Andric assert(Tok.is(MMToken::ExportAsKeyword));
593*700637cbSDimitry Andric ExportAsDecl EAD;
594*700637cbSDimitry Andric EAD.Location = consumeToken();
595*700637cbSDimitry Andric
596*700637cbSDimitry Andric if (!Tok.is(MMToken::Identifier)) {
597*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
598*700637cbSDimitry Andric HadError = true;
599*700637cbSDimitry Andric return std::nullopt;
600*700637cbSDimitry Andric }
601*700637cbSDimitry Andric
602*700637cbSDimitry Andric if (parseModuleId(EAD.Id))
603*700637cbSDimitry Andric return std::nullopt;
604*700637cbSDimitry Andric if (EAD.Id.size() > 1)
605*700637cbSDimitry Andric Diags.Report(EAD.Id[1].second, diag::err_mmap_qualified_export_as);
606*700637cbSDimitry Andric return std::move(EAD);
607*700637cbSDimitry Andric }
608*700637cbSDimitry Andric
609*700637cbSDimitry Andric /// Parse a module use declaration.
610*700637cbSDimitry Andric ///
611*700637cbSDimitry Andric /// use-declaration:
612*700637cbSDimitry Andric /// 'use' wildcard-module-id
parseUseDecl()613*700637cbSDimitry Andric std::optional<UseDecl> ModuleMapFileParser::parseUseDecl() {
614*700637cbSDimitry Andric assert(Tok.is(MMToken::UseKeyword));
615*700637cbSDimitry Andric UseDecl UD;
616*700637cbSDimitry Andric UD.Location = consumeToken();
617*700637cbSDimitry Andric if (parseModuleId(UD.Id))
618*700637cbSDimitry Andric return std::nullopt;
619*700637cbSDimitry Andric return std::move(UD);
620*700637cbSDimitry Andric }
621*700637cbSDimitry Andric
622*700637cbSDimitry Andric /// Parse a requires declaration.
623*700637cbSDimitry Andric ///
624*700637cbSDimitry Andric /// requires-declaration:
625*700637cbSDimitry Andric /// 'requires' feature-list
626*700637cbSDimitry Andric ///
627*700637cbSDimitry Andric /// feature-list:
628*700637cbSDimitry Andric /// feature ',' feature-list
629*700637cbSDimitry Andric /// feature
630*700637cbSDimitry Andric ///
631*700637cbSDimitry Andric /// feature:
632*700637cbSDimitry Andric /// '!'[opt] identifier
parseRequiresDecl()633*700637cbSDimitry Andric std::optional<RequiresDecl> ModuleMapFileParser::parseRequiresDecl() {
634*700637cbSDimitry Andric assert(Tok.is(MMToken::RequiresKeyword));
635*700637cbSDimitry Andric RequiresDecl RD;
636*700637cbSDimitry Andric RD.Location = consumeToken();
637*700637cbSDimitry Andric
638*700637cbSDimitry Andric // Parse the feature-list.
639*700637cbSDimitry Andric do {
640*700637cbSDimitry Andric bool RequiredState = true;
641*700637cbSDimitry Andric if (Tok.is(MMToken::Exclaim)) {
642*700637cbSDimitry Andric RequiredState = false;
643*700637cbSDimitry Andric consumeToken();
644*700637cbSDimitry Andric }
645*700637cbSDimitry Andric
646*700637cbSDimitry Andric if (!Tok.is(MMToken::Identifier)) {
647*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
648*700637cbSDimitry Andric HadError = true;
649*700637cbSDimitry Andric return std::nullopt;
650*700637cbSDimitry Andric }
651*700637cbSDimitry Andric
652*700637cbSDimitry Andric // Consume the feature name.
653*700637cbSDimitry Andric RequiresFeature RF;
654*700637cbSDimitry Andric RF.Feature = Tok.getString();
655*700637cbSDimitry Andric RF.Location = consumeToken();
656*700637cbSDimitry Andric RF.RequiredState = RequiredState;
657*700637cbSDimitry Andric
658*700637cbSDimitry Andric RD.Features.push_back(std::move(RF));
659*700637cbSDimitry Andric
660*700637cbSDimitry Andric if (!Tok.is(MMToken::Comma))
661*700637cbSDimitry Andric break;
662*700637cbSDimitry Andric
663*700637cbSDimitry Andric // Consume the comma.
664*700637cbSDimitry Andric consumeToken();
665*700637cbSDimitry Andric } while (true);
666*700637cbSDimitry Andric return std::move(RD);
667*700637cbSDimitry Andric }
668*700637cbSDimitry Andric
669*700637cbSDimitry Andric /// Parse a header declaration.
670*700637cbSDimitry Andric ///
671*700637cbSDimitry Andric /// header-declaration:
672*700637cbSDimitry Andric /// 'textual'[opt] 'header' string-literal
673*700637cbSDimitry Andric /// 'private' 'textual'[opt] 'header' string-literal
674*700637cbSDimitry Andric /// 'exclude' 'header' string-literal
675*700637cbSDimitry Andric /// 'umbrella' 'header' string-literal
676*700637cbSDimitry Andric std::optional<HeaderDecl>
parseHeaderDecl(MMToken::TokenKind LeadingToken,clang::SourceLocation LeadingLoc)677*700637cbSDimitry Andric ModuleMapFileParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
678*700637cbSDimitry Andric clang::SourceLocation LeadingLoc) {
679*700637cbSDimitry Andric HeaderDecl HD;
680*700637cbSDimitry Andric HD.Private = false;
681*700637cbSDimitry Andric HD.Excluded = false;
682*700637cbSDimitry Andric HD.Textual = false;
683*700637cbSDimitry Andric // We've already consumed the first token.
684*700637cbSDimitry Andric HD.Location = LeadingLoc;
685*700637cbSDimitry Andric
686*700637cbSDimitry Andric if (LeadingToken == MMToken::PrivateKeyword) {
687*700637cbSDimitry Andric HD.Private = true;
688*700637cbSDimitry Andric // 'private' may optionally be followed by 'textual'.
689*700637cbSDimitry Andric if (Tok.is(MMToken::TextualKeyword)) {
690*700637cbSDimitry Andric HD.Textual = true;
691*700637cbSDimitry Andric LeadingToken = Tok.Kind;
692*700637cbSDimitry Andric consumeToken();
693*700637cbSDimitry Andric }
694*700637cbSDimitry Andric } else if (LeadingToken == MMToken::ExcludeKeyword)
695*700637cbSDimitry Andric HD.Excluded = true;
696*700637cbSDimitry Andric else if (LeadingToken == MMToken::TextualKeyword)
697*700637cbSDimitry Andric HD.Textual = true;
698*700637cbSDimitry Andric
699*700637cbSDimitry Andric if (LeadingToken != MMToken::HeaderKeyword) {
700*700637cbSDimitry Andric if (!Tok.is(MMToken::HeaderKeyword)) {
701*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
702*700637cbSDimitry Andric << (LeadingToken == MMToken::PrivateKeyword ? "private"
703*700637cbSDimitry Andric : LeadingToken == MMToken::ExcludeKeyword ? "exclude"
704*700637cbSDimitry Andric : LeadingToken == MMToken::TextualKeyword ? "textual"
705*700637cbSDimitry Andric : "umbrella");
706*700637cbSDimitry Andric return std::nullopt;
707*700637cbSDimitry Andric }
708*700637cbSDimitry Andric consumeToken();
709*700637cbSDimitry Andric }
710*700637cbSDimitry Andric
711*700637cbSDimitry Andric // Parse the header name.
712*700637cbSDimitry Andric if (!Tok.is(MMToken::StringLiteral)) {
713*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) << "header";
714*700637cbSDimitry Andric HadError = true;
715*700637cbSDimitry Andric return std::nullopt;
716*700637cbSDimitry Andric }
717*700637cbSDimitry Andric HD.Path = Tok.getString();
718*700637cbSDimitry Andric HD.PathLoc = consumeToken();
719*700637cbSDimitry Andric HD.Umbrella = LeadingToken == MMToken::UmbrellaKeyword;
720*700637cbSDimitry Andric
721*700637cbSDimitry Andric // If we were given stat information, parse it so we can skip looking for
722*700637cbSDimitry Andric // the file.
723*700637cbSDimitry Andric if (Tok.is(MMToken::LBrace)) {
724*700637cbSDimitry Andric SourceLocation LBraceLoc = consumeToken();
725*700637cbSDimitry Andric
726*700637cbSDimitry Andric while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {
727*700637cbSDimitry Andric enum Attribute { Size, ModTime, Unknown };
728*700637cbSDimitry Andric StringRef Str = Tok.getString();
729*700637cbSDimitry Andric SourceLocation Loc = consumeToken();
730*700637cbSDimitry Andric switch (llvm::StringSwitch<Attribute>(Str)
731*700637cbSDimitry Andric .Case("size", Size)
732*700637cbSDimitry Andric .Case("mtime", ModTime)
733*700637cbSDimitry Andric .Default(Unknown)) {
734*700637cbSDimitry Andric case Size:
735*700637cbSDimitry Andric if (HD.Size)
736*700637cbSDimitry Andric Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
737*700637cbSDimitry Andric if (!Tok.is(MMToken::IntegerLiteral)) {
738*700637cbSDimitry Andric Diags.Report(Tok.getLocation(),
739*700637cbSDimitry Andric diag::err_mmap_invalid_header_attribute_value)
740*700637cbSDimitry Andric << Str;
741*700637cbSDimitry Andric skipUntil(MMToken::RBrace);
742*700637cbSDimitry Andric break;
743*700637cbSDimitry Andric }
744*700637cbSDimitry Andric HD.Size = Tok.getInteger();
745*700637cbSDimitry Andric consumeToken();
746*700637cbSDimitry Andric break;
747*700637cbSDimitry Andric
748*700637cbSDimitry Andric case ModTime:
749*700637cbSDimitry Andric if (HD.MTime)
750*700637cbSDimitry Andric Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
751*700637cbSDimitry Andric if (!Tok.is(MMToken::IntegerLiteral)) {
752*700637cbSDimitry Andric Diags.Report(Tok.getLocation(),
753*700637cbSDimitry Andric diag::err_mmap_invalid_header_attribute_value)
754*700637cbSDimitry Andric << Str;
755*700637cbSDimitry Andric skipUntil(MMToken::RBrace);
756*700637cbSDimitry Andric break;
757*700637cbSDimitry Andric }
758*700637cbSDimitry Andric HD.MTime = Tok.getInteger();
759*700637cbSDimitry Andric consumeToken();
760*700637cbSDimitry Andric break;
761*700637cbSDimitry Andric
762*700637cbSDimitry Andric case Unknown:
763*700637cbSDimitry Andric Diags.Report(Loc, diag::err_mmap_expected_header_attribute);
764*700637cbSDimitry Andric skipUntil(MMToken::RBrace);
765*700637cbSDimitry Andric break;
766*700637cbSDimitry Andric }
767*700637cbSDimitry Andric }
768*700637cbSDimitry Andric
769*700637cbSDimitry Andric if (Tok.is(MMToken::RBrace))
770*700637cbSDimitry Andric consumeToken();
771*700637cbSDimitry Andric else {
772*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
773*700637cbSDimitry Andric Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
774*700637cbSDimitry Andric HadError = true;
775*700637cbSDimitry Andric }
776*700637cbSDimitry Andric }
777*700637cbSDimitry Andric return std::move(HD);
778*700637cbSDimitry Andric }
779*700637cbSDimitry Andric
780*700637cbSDimitry Andric /// Parse an exclude declaration.
781*700637cbSDimitry Andric ///
782*700637cbSDimitry Andric /// exclude-declaration:
783*700637cbSDimitry Andric /// 'exclude' identifier
784*700637cbSDimitry Andric std::optional<ExcludeDecl>
parseExcludeDecl(clang::SourceLocation LeadingLoc)785*700637cbSDimitry Andric ModuleMapFileParser::parseExcludeDecl(clang::SourceLocation LeadingLoc) {
786*700637cbSDimitry Andric // FIXME: Support string-literal module names here.
787*700637cbSDimitry Andric if (!Tok.is(MMToken::Identifier)) {
788*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);
789*700637cbSDimitry Andric HadError = true;
790*700637cbSDimitry Andric return std::nullopt;
791*700637cbSDimitry Andric }
792*700637cbSDimitry Andric
793*700637cbSDimitry Andric ExcludeDecl ED;
794*700637cbSDimitry Andric ED.Location = LeadingLoc;
795*700637cbSDimitry Andric ED.Module = Tok.getString();
796*700637cbSDimitry Andric consumeToken();
797*700637cbSDimitry Andric return std::move(ED);
798*700637cbSDimitry Andric }
799*700637cbSDimitry Andric
800*700637cbSDimitry Andric /// Parse an umbrella directory declaration.
801*700637cbSDimitry Andric ///
802*700637cbSDimitry Andric /// umbrella-dir-declaration:
803*700637cbSDimitry Andric /// umbrella string-literal
804*700637cbSDimitry Andric std::optional<UmbrellaDirDecl>
parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc)805*700637cbSDimitry Andric ModuleMapFileParser::parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc) {
806*700637cbSDimitry Andric UmbrellaDirDecl UDD;
807*700637cbSDimitry Andric UDD.Location = UmbrellaLoc;
808*700637cbSDimitry Andric // Parse the directory name.
809*700637cbSDimitry Andric if (!Tok.is(MMToken::StringLiteral)) {
810*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
811*700637cbSDimitry Andric << "umbrella";
812*700637cbSDimitry Andric HadError = true;
813*700637cbSDimitry Andric return std::nullopt;
814*700637cbSDimitry Andric }
815*700637cbSDimitry Andric
816*700637cbSDimitry Andric UDD.Path = Tok.getString();
817*700637cbSDimitry Andric consumeToken();
818*700637cbSDimitry Andric return std::move(UDD);
819*700637cbSDimitry Andric }
820*700637cbSDimitry Andric
821*700637cbSDimitry Andric /// Parse a link declaration.
822*700637cbSDimitry Andric ///
823*700637cbSDimitry Andric /// module-declaration:
824*700637cbSDimitry Andric /// 'link' 'framework'[opt] string-literal
parseLinkDecl()825*700637cbSDimitry Andric std::optional<LinkDecl> ModuleMapFileParser::parseLinkDecl() {
826*700637cbSDimitry Andric assert(Tok.is(MMToken::LinkKeyword));
827*700637cbSDimitry Andric LinkDecl LD;
828*700637cbSDimitry Andric LD.Location = consumeToken();
829*700637cbSDimitry Andric
830*700637cbSDimitry Andric // Parse the optional 'framework' keyword.
831*700637cbSDimitry Andric LD.Framework = false;
832*700637cbSDimitry Andric if (Tok.is(MMToken::FrameworkKeyword)) {
833*700637cbSDimitry Andric consumeToken();
834*700637cbSDimitry Andric LD.Framework = true;
835*700637cbSDimitry Andric }
836*700637cbSDimitry Andric
837*700637cbSDimitry Andric // Parse the library name
838*700637cbSDimitry Andric if (!Tok.is(MMToken::StringLiteral)) {
839*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name)
840*700637cbSDimitry Andric << LD.Framework << SourceRange(LD.Location);
841*700637cbSDimitry Andric HadError = true;
842*700637cbSDimitry Andric return std::nullopt;
843*700637cbSDimitry Andric }
844*700637cbSDimitry Andric
845*700637cbSDimitry Andric LD.Library = Tok.getString();
846*700637cbSDimitry Andric consumeToken();
847*700637cbSDimitry Andric return std::move(LD);
848*700637cbSDimitry Andric }
849*700637cbSDimitry Andric
consumeToken()850*700637cbSDimitry Andric SourceLocation ModuleMapFileParser::consumeToken() {
851*700637cbSDimitry Andric SourceLocation Result = Tok.getLocation();
852*700637cbSDimitry Andric
853*700637cbSDimitry Andric retry:
854*700637cbSDimitry Andric Tok.clear();
855*700637cbSDimitry Andric Token LToken;
856*700637cbSDimitry Andric L.LexFromRawLexer(LToken);
857*700637cbSDimitry Andric Tok.Location = LToken.getLocation().getRawEncoding();
858*700637cbSDimitry Andric switch (LToken.getKind()) {
859*700637cbSDimitry Andric case tok::raw_identifier: {
860*700637cbSDimitry Andric StringRef RI = LToken.getRawIdentifier();
861*700637cbSDimitry Andric Tok.StringData = RI.data();
862*700637cbSDimitry Andric Tok.StringLength = RI.size();
863*700637cbSDimitry Andric Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI)
864*700637cbSDimitry Andric .Case("config_macros", MMToken::ConfigMacros)
865*700637cbSDimitry Andric .Case("conflict", MMToken::Conflict)
866*700637cbSDimitry Andric .Case("exclude", MMToken::ExcludeKeyword)
867*700637cbSDimitry Andric .Case("explicit", MMToken::ExplicitKeyword)
868*700637cbSDimitry Andric .Case("export", MMToken::ExportKeyword)
869*700637cbSDimitry Andric .Case("export_as", MMToken::ExportAsKeyword)
870*700637cbSDimitry Andric .Case("extern", MMToken::ExternKeyword)
871*700637cbSDimitry Andric .Case("framework", MMToken::FrameworkKeyword)
872*700637cbSDimitry Andric .Case("header", MMToken::HeaderKeyword)
873*700637cbSDimitry Andric .Case("link", MMToken::LinkKeyword)
874*700637cbSDimitry Andric .Case("module", MMToken::ModuleKeyword)
875*700637cbSDimitry Andric .Case("private", MMToken::PrivateKeyword)
876*700637cbSDimitry Andric .Case("requires", MMToken::RequiresKeyword)
877*700637cbSDimitry Andric .Case("textual", MMToken::TextualKeyword)
878*700637cbSDimitry Andric .Case("umbrella", MMToken::UmbrellaKeyword)
879*700637cbSDimitry Andric .Case("use", MMToken::UseKeyword)
880*700637cbSDimitry Andric .Default(MMToken::Identifier);
881*700637cbSDimitry Andric break;
882*700637cbSDimitry Andric }
883*700637cbSDimitry Andric
884*700637cbSDimitry Andric case tok::comma:
885*700637cbSDimitry Andric Tok.Kind = MMToken::Comma;
886*700637cbSDimitry Andric break;
887*700637cbSDimitry Andric
888*700637cbSDimitry Andric case tok::eof:
889*700637cbSDimitry Andric Tok.Kind = MMToken::EndOfFile;
890*700637cbSDimitry Andric break;
891*700637cbSDimitry Andric
892*700637cbSDimitry Andric case tok::l_brace:
893*700637cbSDimitry Andric Tok.Kind = MMToken::LBrace;
894*700637cbSDimitry Andric break;
895*700637cbSDimitry Andric
896*700637cbSDimitry Andric case tok::l_square:
897*700637cbSDimitry Andric Tok.Kind = MMToken::LSquare;
898*700637cbSDimitry Andric break;
899*700637cbSDimitry Andric
900*700637cbSDimitry Andric case tok::period:
901*700637cbSDimitry Andric Tok.Kind = MMToken::Period;
902*700637cbSDimitry Andric break;
903*700637cbSDimitry Andric
904*700637cbSDimitry Andric case tok::r_brace:
905*700637cbSDimitry Andric Tok.Kind = MMToken::RBrace;
906*700637cbSDimitry Andric break;
907*700637cbSDimitry Andric
908*700637cbSDimitry Andric case tok::r_square:
909*700637cbSDimitry Andric Tok.Kind = MMToken::RSquare;
910*700637cbSDimitry Andric break;
911*700637cbSDimitry Andric
912*700637cbSDimitry Andric case tok::star:
913*700637cbSDimitry Andric Tok.Kind = MMToken::Star;
914*700637cbSDimitry Andric break;
915*700637cbSDimitry Andric
916*700637cbSDimitry Andric case tok::exclaim:
917*700637cbSDimitry Andric Tok.Kind = MMToken::Exclaim;
918*700637cbSDimitry Andric break;
919*700637cbSDimitry Andric
920*700637cbSDimitry Andric case tok::string_literal: {
921*700637cbSDimitry Andric if (LToken.hasUDSuffix()) {
922*700637cbSDimitry Andric Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
923*700637cbSDimitry Andric HadError = true;
924*700637cbSDimitry Andric goto retry;
925*700637cbSDimitry Andric }
926*700637cbSDimitry Andric
927*700637cbSDimitry Andric // Form the token.
928*700637cbSDimitry Andric Tok.Kind = MMToken::StringLiteral;
929*700637cbSDimitry Andric Tok.StringData = LToken.getLiteralData() + 1;
930*700637cbSDimitry Andric Tok.StringLength = LToken.getLength() - 2;
931*700637cbSDimitry Andric break;
932*700637cbSDimitry Andric }
933*700637cbSDimitry Andric
934*700637cbSDimitry Andric case tok::numeric_constant: {
935*700637cbSDimitry Andric // We don't support any suffixes or other complications.
936*700637cbSDimitry Andric uint64_t Value;
937*700637cbSDimitry Andric if (StringRef(LToken.getLiteralData(), LToken.getLength())
938*700637cbSDimitry Andric .getAsInteger(0, Value)) {
939*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
940*700637cbSDimitry Andric HadError = true;
941*700637cbSDimitry Andric goto retry;
942*700637cbSDimitry Andric }
943*700637cbSDimitry Andric
944*700637cbSDimitry Andric Tok.Kind = MMToken::IntegerLiteral;
945*700637cbSDimitry Andric Tok.IntegerValue = Value;
946*700637cbSDimitry Andric break;
947*700637cbSDimitry Andric }
948*700637cbSDimitry Andric
949*700637cbSDimitry Andric case tok::comment:
950*700637cbSDimitry Andric goto retry;
951*700637cbSDimitry Andric
952*700637cbSDimitry Andric case tok::hash:
953*700637cbSDimitry Andric // A module map can be terminated prematurely by
954*700637cbSDimitry Andric // #pragma clang module contents
955*700637cbSDimitry Andric // When building the module, we'll treat the rest of the file as the
956*700637cbSDimitry Andric // contents of the module.
957*700637cbSDimitry Andric {
958*700637cbSDimitry Andric auto NextIsIdent = [&](StringRef Str) -> bool {
959*700637cbSDimitry Andric L.LexFromRawLexer(LToken);
960*700637cbSDimitry Andric return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) &&
961*700637cbSDimitry Andric LToken.getRawIdentifier() == Str;
962*700637cbSDimitry Andric };
963*700637cbSDimitry Andric if (NextIsIdent("pragma") && NextIsIdent("clang") &&
964*700637cbSDimitry Andric NextIsIdent("module") && NextIsIdent("contents")) {
965*700637cbSDimitry Andric Tok.Kind = MMToken::EndOfFile;
966*700637cbSDimitry Andric break;
967*700637cbSDimitry Andric }
968*700637cbSDimitry Andric }
969*700637cbSDimitry Andric [[fallthrough]];
970*700637cbSDimitry Andric
971*700637cbSDimitry Andric default:
972*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
973*700637cbSDimitry Andric HadError = true;
974*700637cbSDimitry Andric goto retry;
975*700637cbSDimitry Andric }
976*700637cbSDimitry Andric
977*700637cbSDimitry Andric return Result;
978*700637cbSDimitry Andric }
979*700637cbSDimitry Andric
skipUntil(MMToken::TokenKind K)980*700637cbSDimitry Andric void ModuleMapFileParser::skipUntil(MMToken::TokenKind K) {
981*700637cbSDimitry Andric unsigned braceDepth = 0;
982*700637cbSDimitry Andric unsigned squareDepth = 0;
983*700637cbSDimitry Andric do {
984*700637cbSDimitry Andric switch (Tok.Kind) {
985*700637cbSDimitry Andric case MMToken::EndOfFile:
986*700637cbSDimitry Andric return;
987*700637cbSDimitry Andric
988*700637cbSDimitry Andric case MMToken::LBrace:
989*700637cbSDimitry Andric if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
990*700637cbSDimitry Andric return;
991*700637cbSDimitry Andric
992*700637cbSDimitry Andric ++braceDepth;
993*700637cbSDimitry Andric break;
994*700637cbSDimitry Andric
995*700637cbSDimitry Andric case MMToken::LSquare:
996*700637cbSDimitry Andric if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
997*700637cbSDimitry Andric return;
998*700637cbSDimitry Andric
999*700637cbSDimitry Andric ++squareDepth;
1000*700637cbSDimitry Andric break;
1001*700637cbSDimitry Andric
1002*700637cbSDimitry Andric case MMToken::RBrace:
1003*700637cbSDimitry Andric if (braceDepth > 0)
1004*700637cbSDimitry Andric --braceDepth;
1005*700637cbSDimitry Andric else if (Tok.is(K))
1006*700637cbSDimitry Andric return;
1007*700637cbSDimitry Andric break;
1008*700637cbSDimitry Andric
1009*700637cbSDimitry Andric case MMToken::RSquare:
1010*700637cbSDimitry Andric if (squareDepth > 0)
1011*700637cbSDimitry Andric --squareDepth;
1012*700637cbSDimitry Andric else if (Tok.is(K))
1013*700637cbSDimitry Andric return;
1014*700637cbSDimitry Andric break;
1015*700637cbSDimitry Andric
1016*700637cbSDimitry Andric default:
1017*700637cbSDimitry Andric if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))
1018*700637cbSDimitry Andric return;
1019*700637cbSDimitry Andric break;
1020*700637cbSDimitry Andric }
1021*700637cbSDimitry Andric
1022*700637cbSDimitry Andric consumeToken();
1023*700637cbSDimitry Andric } while (true);
1024*700637cbSDimitry Andric }
1025*700637cbSDimitry Andric
1026*700637cbSDimitry Andric /// Parse a module-id.
1027*700637cbSDimitry Andric ///
1028*700637cbSDimitry Andric /// module-id:
1029*700637cbSDimitry Andric /// identifier
1030*700637cbSDimitry Andric /// identifier '.' module-id
1031*700637cbSDimitry Andric ///
1032*700637cbSDimitry Andric /// \returns true if an error occurred, false otherwise.
parseModuleId(ModuleId & Id)1033*700637cbSDimitry Andric bool ModuleMapFileParser::parseModuleId(ModuleId &Id) {
1034*700637cbSDimitry Andric Id.clear();
1035*700637cbSDimitry Andric do {
1036*700637cbSDimitry Andric if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {
1037*700637cbSDimitry Andric Id.push_back(
1038*700637cbSDimitry Andric std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
1039*700637cbSDimitry Andric consumeToken();
1040*700637cbSDimitry Andric } else {
1041*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
1042*700637cbSDimitry Andric return true;
1043*700637cbSDimitry Andric }
1044*700637cbSDimitry Andric
1045*700637cbSDimitry Andric if (!Tok.is(MMToken::Period))
1046*700637cbSDimitry Andric break;
1047*700637cbSDimitry Andric
1048*700637cbSDimitry Andric consumeToken();
1049*700637cbSDimitry Andric } while (true);
1050*700637cbSDimitry Andric
1051*700637cbSDimitry Andric return false;
1052*700637cbSDimitry Andric }
1053*700637cbSDimitry Andric
1054*700637cbSDimitry Andric /// Parse optional attributes.
1055*700637cbSDimitry Andric ///
1056*700637cbSDimitry Andric /// attributes:
1057*700637cbSDimitry Andric /// attribute attributes
1058*700637cbSDimitry Andric /// attribute
1059*700637cbSDimitry Andric ///
1060*700637cbSDimitry Andric /// attribute:
1061*700637cbSDimitry Andric /// [ identifier ]
1062*700637cbSDimitry Andric ///
1063*700637cbSDimitry Andric /// \param Attrs Will be filled in with the parsed attributes.
1064*700637cbSDimitry Andric ///
1065*700637cbSDimitry Andric /// \returns true if an error occurred, false otherwise.
parseOptionalAttributes(ModuleAttributes & Attrs)1066*700637cbSDimitry Andric bool ModuleMapFileParser::parseOptionalAttributes(ModuleAttributes &Attrs) {
1067*700637cbSDimitry Andric bool Error = false;
1068*700637cbSDimitry Andric
1069*700637cbSDimitry Andric while (Tok.is(MMToken::LSquare)) {
1070*700637cbSDimitry Andric // Consume the '['.
1071*700637cbSDimitry Andric SourceLocation LSquareLoc = consumeToken();
1072*700637cbSDimitry Andric
1073*700637cbSDimitry Andric // Check whether we have an attribute name here.
1074*700637cbSDimitry Andric if (!Tok.is(MMToken::Identifier)) {
1075*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
1076*700637cbSDimitry Andric skipUntil(MMToken::RSquare);
1077*700637cbSDimitry Andric if (Tok.is(MMToken::RSquare))
1078*700637cbSDimitry Andric consumeToken();
1079*700637cbSDimitry Andric Error = true;
1080*700637cbSDimitry Andric }
1081*700637cbSDimitry Andric
1082*700637cbSDimitry Andric /// Enumerates the known attributes.
1083*700637cbSDimitry Andric enum AttributeKind {
1084*700637cbSDimitry Andric /// An unknown attribute.
1085*700637cbSDimitry Andric AT_unknown,
1086*700637cbSDimitry Andric
1087*700637cbSDimitry Andric /// The 'system' attribute.
1088*700637cbSDimitry Andric AT_system,
1089*700637cbSDimitry Andric
1090*700637cbSDimitry Andric /// The 'extern_c' attribute.
1091*700637cbSDimitry Andric AT_extern_c,
1092*700637cbSDimitry Andric
1093*700637cbSDimitry Andric /// The 'exhaustive' attribute.
1094*700637cbSDimitry Andric AT_exhaustive,
1095*700637cbSDimitry Andric
1096*700637cbSDimitry Andric /// The 'no_undeclared_includes' attribute.
1097*700637cbSDimitry Andric AT_no_undeclared_includes
1098*700637cbSDimitry Andric };
1099*700637cbSDimitry Andric
1100*700637cbSDimitry Andric // Decode the attribute name.
1101*700637cbSDimitry Andric AttributeKind Attribute =
1102*700637cbSDimitry Andric llvm::StringSwitch<AttributeKind>(Tok.getString())
1103*700637cbSDimitry Andric .Case("exhaustive", AT_exhaustive)
1104*700637cbSDimitry Andric .Case("extern_c", AT_extern_c)
1105*700637cbSDimitry Andric .Case("no_undeclared_includes", AT_no_undeclared_includes)
1106*700637cbSDimitry Andric .Case("system", AT_system)
1107*700637cbSDimitry Andric .Default(AT_unknown);
1108*700637cbSDimitry Andric switch (Attribute) {
1109*700637cbSDimitry Andric case AT_unknown:
1110*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
1111*700637cbSDimitry Andric << Tok.getString();
1112*700637cbSDimitry Andric break;
1113*700637cbSDimitry Andric
1114*700637cbSDimitry Andric case AT_system:
1115*700637cbSDimitry Andric Attrs.IsSystem = true;
1116*700637cbSDimitry Andric break;
1117*700637cbSDimitry Andric
1118*700637cbSDimitry Andric case AT_extern_c:
1119*700637cbSDimitry Andric Attrs.IsExternC = true;
1120*700637cbSDimitry Andric break;
1121*700637cbSDimitry Andric
1122*700637cbSDimitry Andric case AT_exhaustive:
1123*700637cbSDimitry Andric Attrs.IsExhaustive = true;
1124*700637cbSDimitry Andric break;
1125*700637cbSDimitry Andric
1126*700637cbSDimitry Andric case AT_no_undeclared_includes:
1127*700637cbSDimitry Andric Attrs.NoUndeclaredIncludes = true;
1128*700637cbSDimitry Andric break;
1129*700637cbSDimitry Andric }
1130*700637cbSDimitry Andric consumeToken();
1131*700637cbSDimitry Andric
1132*700637cbSDimitry Andric // Consume the ']'.
1133*700637cbSDimitry Andric if (!Tok.is(MMToken::RSquare)) {
1134*700637cbSDimitry Andric Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
1135*700637cbSDimitry Andric Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
1136*700637cbSDimitry Andric skipUntil(MMToken::RSquare);
1137*700637cbSDimitry Andric Error = true;
1138*700637cbSDimitry Andric }
1139*700637cbSDimitry Andric
1140*700637cbSDimitry Andric if (Tok.is(MMToken::RSquare))
1141*700637cbSDimitry Andric consumeToken();
1142*700637cbSDimitry Andric }
1143*700637cbSDimitry Andric
1144*700637cbSDimitry Andric if (Error)
1145*700637cbSDimitry Andric HadError = true;
1146*700637cbSDimitry Andric
1147*700637cbSDimitry Andric return Error;
1148*700637cbSDimitry Andric }
1149*700637cbSDimitry Andric
1150*700637cbSDimitry Andric static void dumpModule(const ModuleDecl &MD, llvm::raw_ostream &out, int depth);
1151*700637cbSDimitry Andric
dumpExternModule(const ExternModuleDecl & EMD,llvm::raw_ostream & out,int depth)1152*700637cbSDimitry Andric static void dumpExternModule(const ExternModuleDecl &EMD,
1153*700637cbSDimitry Andric llvm::raw_ostream &out, int depth) {
1154*700637cbSDimitry Andric out.indent(depth * 2);
1155*700637cbSDimitry Andric out << "extern module " << formatModuleId(EMD.Id) << " \"" << EMD.Path
1156*700637cbSDimitry Andric << "\"\n";
1157*700637cbSDimitry Andric }
1158*700637cbSDimitry Andric
dumpDecls(ArrayRef<Decl> Decls,llvm::raw_ostream & out,int depth)1159*700637cbSDimitry Andric static void dumpDecls(ArrayRef<Decl> Decls, llvm::raw_ostream &out, int depth) {
1160*700637cbSDimitry Andric for (const auto &Decl : Decls) {
1161*700637cbSDimitry Andric std::visit(llvm::makeVisitor(
1162*700637cbSDimitry Andric [&](const RequiresDecl &RD) {
1163*700637cbSDimitry Andric out.indent(depth * 2);
1164*700637cbSDimitry Andric out << "requires\n";
1165*700637cbSDimitry Andric },
1166*700637cbSDimitry Andric [&](const HeaderDecl &HD) {
1167*700637cbSDimitry Andric out.indent(depth * 2);
1168*700637cbSDimitry Andric if (HD.Private)
1169*700637cbSDimitry Andric out << "private ";
1170*700637cbSDimitry Andric if (HD.Textual)
1171*700637cbSDimitry Andric out << "textual ";
1172*700637cbSDimitry Andric if (HD.Excluded)
1173*700637cbSDimitry Andric out << "excluded ";
1174*700637cbSDimitry Andric if (HD.Umbrella)
1175*700637cbSDimitry Andric out << "umbrella ";
1176*700637cbSDimitry Andric out << "header \"" << HD.Path << "\"\n";
1177*700637cbSDimitry Andric },
1178*700637cbSDimitry Andric [&](const UmbrellaDirDecl &UDD) {
1179*700637cbSDimitry Andric out.indent(depth * 2);
1180*700637cbSDimitry Andric out << "umbrella\n";
1181*700637cbSDimitry Andric },
1182*700637cbSDimitry Andric [&](const ModuleDecl &MD) { dumpModule(MD, out, depth); },
1183*700637cbSDimitry Andric [&](const ExcludeDecl &ED) {
1184*700637cbSDimitry Andric out.indent(depth * 2);
1185*700637cbSDimitry Andric out << "exclude " << ED.Module << "\n";
1186*700637cbSDimitry Andric },
1187*700637cbSDimitry Andric [&](const ExportDecl &ED) {
1188*700637cbSDimitry Andric out.indent(depth * 2);
1189*700637cbSDimitry Andric out << "export "
1190*700637cbSDimitry Andric << (ED.Wildcard ? "*" : formatModuleId(ED.Id)) << "\n";
1191*700637cbSDimitry Andric },
1192*700637cbSDimitry Andric [&](const ExportAsDecl &EAD) {
1193*700637cbSDimitry Andric out.indent(depth * 2);
1194*700637cbSDimitry Andric out << "export as\n";
1195*700637cbSDimitry Andric },
1196*700637cbSDimitry Andric [&](const ExternModuleDecl &EMD) {
1197*700637cbSDimitry Andric dumpExternModule(EMD, out, depth);
1198*700637cbSDimitry Andric },
1199*700637cbSDimitry Andric [&](const UseDecl &UD) {
1200*700637cbSDimitry Andric out.indent(depth * 2);
1201*700637cbSDimitry Andric out << "use\n";
1202*700637cbSDimitry Andric },
1203*700637cbSDimitry Andric [&](const LinkDecl &LD) {
1204*700637cbSDimitry Andric out.indent(depth * 2);
1205*700637cbSDimitry Andric out << "link\n";
1206*700637cbSDimitry Andric },
1207*700637cbSDimitry Andric [&](const ConfigMacrosDecl &CMD) {
1208*700637cbSDimitry Andric out.indent(depth * 2);
1209*700637cbSDimitry Andric out << "config_macros ";
1210*700637cbSDimitry Andric if (CMD.Exhaustive)
1211*700637cbSDimitry Andric out << "[exhaustive] ";
1212*700637cbSDimitry Andric for (auto Macro : CMD.Macros) {
1213*700637cbSDimitry Andric out << Macro << " ";
1214*700637cbSDimitry Andric }
1215*700637cbSDimitry Andric out << "\n";
1216*700637cbSDimitry Andric },
1217*700637cbSDimitry Andric [&](const ConflictDecl &CD) {
1218*700637cbSDimitry Andric out.indent(depth * 2);
1219*700637cbSDimitry Andric out << "conflicts\n";
1220*700637cbSDimitry Andric }),
1221*700637cbSDimitry Andric Decl);
1222*700637cbSDimitry Andric }
1223*700637cbSDimitry Andric }
1224*700637cbSDimitry Andric
dumpModule(const ModuleDecl & MD,llvm::raw_ostream & out,int depth)1225*700637cbSDimitry Andric static void dumpModule(const ModuleDecl &MD, llvm::raw_ostream &out,
1226*700637cbSDimitry Andric int depth) {
1227*700637cbSDimitry Andric out.indent(depth * 2);
1228*700637cbSDimitry Andric out << "module " << formatModuleId(MD.Id) << "\n";
1229*700637cbSDimitry Andric dumpDecls(MD.Decls, out, depth + 1);
1230*700637cbSDimitry Andric }
1231*700637cbSDimitry Andric
dump(llvm::raw_ostream & out) const1232*700637cbSDimitry Andric void ModuleMapFile::dump(llvm::raw_ostream &out) const {
1233*700637cbSDimitry Andric for (const auto &Decl : Decls) {
1234*700637cbSDimitry Andric std::visit(
1235*700637cbSDimitry Andric llvm::makeVisitor([&](const ModuleDecl &MD) { dumpModule(MD, out, 0); },
1236*700637cbSDimitry Andric [&](const ExternModuleDecl &EMD) {
1237*700637cbSDimitry Andric dumpExternModule(EMD, out, 0);
1238*700637cbSDimitry Andric }),
1239*700637cbSDimitry Andric Decl);
1240*700637cbSDimitry Andric }
1241*700637cbSDimitry Andric }
1242