1 //===--- ModuleMap.cpp - Describe the layout of modules ---------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines the ModuleMap implementation, which describes the layout 11 // of a module as it relates to headers. 12 // 13 //===----------------------------------------------------------------------===// 14 #include "clang/Lex/ModuleMap.h" 15 #include "clang/Lex/Lexer.h" 16 #include "clang/Lex/LiteralSupport.h" 17 #include "clang/Lex/LexDiagnostic.h" 18 #include "clang/Basic/Diagnostic.h" 19 #include "clang/Basic/FileManager.h" 20 #include "clang/Basic/TargetInfo.h" 21 #include "clang/Basic/TargetOptions.h" 22 #include "llvm/Support/Allocator.h" 23 #include "llvm/Support/Host.h" 24 #include "llvm/Support/PathV2.h" 25 #include "llvm/Support/raw_ostream.h" 26 #include "llvm/ADT/StringRef.h" 27 #include "llvm/ADT/StringSwitch.h" 28 using namespace clang; 29 30 //----------------------------------------------------------------------------// 31 // Module 32 //----------------------------------------------------------------------------// 33 34 ModuleMap::Module::~Module() { 35 for (llvm::StringMap<Module *>::iterator I = SubModules.begin(), 36 IEnd = SubModules.end(); 37 I != IEnd; ++I) { 38 delete I->getValue(); 39 } 40 41 } 42 43 std::string ModuleMap::Module::getFullModuleName() const { 44 llvm::SmallVector<StringRef, 2> Names; 45 46 // Build up the set of module names (from innermost to outermost). 47 for (const Module *M = this; M; M = M->Parent) 48 Names.push_back(M->Name); 49 50 std::string Result; 51 for (llvm::SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(), 52 IEnd = Names.rend(); 53 I != IEnd; ++I) { 54 if (!Result.empty()) 55 Result += '.'; 56 57 Result += *I; 58 } 59 60 return Result; 61 } 62 63 StringRef ModuleMap::Module::getTopLevelModuleName() const { 64 const Module *Top = this; 65 while (Top->Parent) 66 Top = Top->Parent; 67 68 return Top->Name; 69 } 70 71 static void indent(llvm::raw_ostream &OS, unsigned Spaces) { 72 OS << std::string(' ', Spaces); 73 } 74 75 void ModuleMap::Module::print(llvm::raw_ostream &OS, unsigned Indent) const { 76 indent(OS, Indent); 77 if (IsFramework) 78 OS << "framework "; 79 if (IsExplicit) 80 OS << "explicit "; 81 OS << Name << " {\n"; 82 83 if (UmbrellaHeader) { 84 indent(OS, Indent + 2); 85 OS << "umbrella \"" << UmbrellaHeader->getName() << "\"\n"; 86 } 87 88 for (unsigned I = 0, N = Headers.size(); I != N; ++I) { 89 indent(OS, Indent + 2); 90 OS << "header \"" << Headers[I]->getName() << "\"\n"; 91 } 92 93 for (llvm::StringMap<Module *>::const_iterator MI = SubModules.begin(), 94 MIEnd = SubModules.end(); 95 MI != MIEnd; ++MI) 96 MI->getValue()->print(OS, Indent + 2); 97 98 indent(OS, Indent); 99 OS << "}\n"; 100 } 101 102 void ModuleMap::Module::dump() const { 103 print(llvm::errs()); 104 } 105 106 //----------------------------------------------------------------------------// 107 // Module map 108 //----------------------------------------------------------------------------// 109 110 ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC) { 111 llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs); 112 Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>( 113 new DiagnosticsEngine(DiagIDs)); 114 Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true); 115 SourceMgr = new SourceManager(*Diags, FileMgr); 116 } 117 118 ModuleMap::~ModuleMap() { 119 for (llvm::StringMap<Module *>::iterator I = Modules.begin(), 120 IEnd = Modules.end(); 121 I != IEnd; ++I) { 122 delete I->getValue(); 123 } 124 125 delete SourceMgr; 126 } 127 128 ModuleMap::Module *ModuleMap::findModuleForHeader(const FileEntry *File) { 129 llvm::DenseMap<const FileEntry *, Module *>::iterator Known 130 = Headers.find(File); 131 if (Known != Headers.end()) 132 return Known->second; 133 134 const DirectoryEntry *Dir = File->getDir(); 135 llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir 136 = UmbrellaDirs.find(Dir); 137 if (KnownDir != UmbrellaDirs.end()) 138 return KnownDir->second; 139 140 // Walk up the directory hierarchy looking for umbrella headers. 141 llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs; 142 StringRef DirName = Dir->getName(); 143 do { 144 // Retrieve our parent path. 145 DirName = llvm::sys::path::parent_path(DirName); 146 if (DirName.empty()) 147 break; 148 149 // Resolve the parent path to a directory entry. 150 Dir = SourceMgr->getFileManager().getDirectory(DirName); 151 if (!Dir) 152 break; 153 154 KnownDir = UmbrellaDirs.find(Dir); 155 if (KnownDir != UmbrellaDirs.end()) { 156 Module *Result = KnownDir->second; 157 158 // Record each of the directories we stepped through as being part of 159 // the module we found, since the umbrella header covers them all. 160 for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I) 161 UmbrellaDirs[SkippedDirs[I]] = Result; 162 163 return Result; 164 } 165 166 SkippedDirs.push_back(Dir); 167 } while (true); 168 169 return 0; 170 } 171 172 ModuleMap::Module *ModuleMap::findModule(StringRef Name) { 173 llvm::StringMap<Module *>::iterator Known = Modules.find(Name); 174 if (Known != Modules.end()) 175 return Known->getValue(); 176 177 return 0; 178 } 179 180 ModuleMap::Module * 181 ModuleMap::inferFrameworkModule(StringRef ModuleName, 182 const DirectoryEntry *FrameworkDir) { 183 // Check whether we've already found this module. 184 if (Module *Module = findModule(ModuleName)) 185 return Module; 186 187 // Look for an umbrella header. 188 llvm::SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName()); 189 llvm::sys::path::append(UmbrellaName, "Headers"); 190 llvm::sys::path::append(UmbrellaName, ModuleName + ".h"); 191 const FileEntry *UmbrellaHeader 192 = SourceMgr->getFileManager().getFile(UmbrellaName); 193 194 // FIXME: If there's no umbrella header, we could probably scan the 195 // framework to load *everything*. But, it's not clear that this is a good 196 // idea. 197 if (!UmbrellaHeader) 198 return 0; 199 200 Module *Result = new Module(ModuleName, SourceLocation(), 201 /*IsFramework=*/true); 202 Result->UmbrellaHeader = UmbrellaHeader; 203 Headers[UmbrellaHeader] = Result; 204 UmbrellaDirs[FrameworkDir] = Result; 205 Modules[ModuleName] = Result; 206 return Result; 207 } 208 209 const FileEntry * 210 ModuleMap::getContainingModuleMapFile(ModuleMap::Module *Module) { 211 if (Module->DefinitionLoc.isInvalid() || !SourceMgr) 212 return 0; 213 214 return SourceMgr->getFileEntryForID( 215 SourceMgr->getFileID(Module->DefinitionLoc)); 216 } 217 218 void ModuleMap::dump() { 219 llvm::errs() << "Modules:"; 220 for (llvm::StringMap<Module *>::iterator M = Modules.begin(), 221 MEnd = Modules.end(); 222 M != MEnd; ++M) 223 M->getValue()->print(llvm::errs(), 2); 224 225 llvm::errs() << "Headers:"; 226 for (llvm::DenseMap<const FileEntry *, Module *>::iterator 227 H = Headers.begin(), 228 HEnd = Headers.end(); 229 H != HEnd; ++H) { 230 llvm::errs() << " \"" << H->first->getName() << "\" -> " 231 << H->second->getFullModuleName() << "\n"; 232 } 233 } 234 235 //----------------------------------------------------------------------------// 236 // Module map file parser 237 //----------------------------------------------------------------------------// 238 239 namespace clang { 240 /// \brief A token in a module map file. 241 struct MMToken { 242 enum TokenKind { 243 EndOfFile, 244 HeaderKeyword, 245 Identifier, 246 ExplicitKeyword, 247 FrameworkKeyword, 248 ModuleKeyword, 249 UmbrellaKeyword, 250 StringLiteral, 251 LBrace, 252 RBrace 253 } Kind; 254 255 unsigned Location; 256 unsigned StringLength; 257 const char *StringData; 258 259 void clear() { 260 Kind = EndOfFile; 261 Location = 0; 262 StringLength = 0; 263 StringData = 0; 264 } 265 266 bool is(TokenKind K) const { return Kind == K; } 267 268 SourceLocation getLocation() const { 269 return SourceLocation::getFromRawEncoding(Location); 270 } 271 272 StringRef getString() const { 273 return StringRef(StringData, StringLength); 274 } 275 }; 276 277 class ModuleMapParser { 278 Lexer &L; 279 SourceManager &SourceMgr; 280 DiagnosticsEngine &Diags; 281 ModuleMap ⤅ 282 283 /// \brief The directory that this module map resides in. 284 const DirectoryEntry *Directory; 285 286 /// \brief Whether an error occurred. 287 bool HadError; 288 289 /// \brief Default target information, used only for string literal 290 /// parsing. 291 TargetInfo *Target; 292 293 /// \brief Stores string data for the various string literals referenced 294 /// during parsing. 295 llvm::BumpPtrAllocator StringData; 296 297 /// \brief The current token. 298 MMToken Tok; 299 300 /// \brief The active module. 301 ModuleMap::Module *ActiveModule; 302 303 /// \brief Consume the current token and return its location. 304 SourceLocation consumeToken(); 305 306 /// \brief Skip tokens until we reach the a token with the given kind 307 /// (or the end of the file). 308 void skipUntil(MMToken::TokenKind K); 309 310 void parseModuleDecl(); 311 void parseUmbrellaDecl(); 312 void parseHeaderDecl(); 313 314 public: 315 typedef ModuleMap::Module Module; 316 317 explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, 318 DiagnosticsEngine &Diags, 319 ModuleMap &Map, 320 const DirectoryEntry *Directory) 321 : L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map), 322 Directory(Directory), HadError(false), ActiveModule(0) 323 { 324 TargetOptions TargetOpts; 325 TargetOpts.Triple = llvm::sys::getDefaultTargetTriple(); 326 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); 327 328 Tok.clear(); 329 consumeToken(); 330 } 331 332 bool parseModuleMapFile(); 333 }; 334 } 335 336 SourceLocation ModuleMapParser::consumeToken() { 337 retry: 338 SourceLocation Result = Tok.getLocation(); 339 Tok.clear(); 340 341 Token LToken; 342 L.LexFromRawLexer(LToken); 343 Tok.Location = LToken.getLocation().getRawEncoding(); 344 switch (LToken.getKind()) { 345 case tok::raw_identifier: 346 Tok.StringData = LToken.getRawIdentifierData(); 347 Tok.StringLength = LToken.getLength(); 348 Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString()) 349 .Case("header", MMToken::HeaderKeyword) 350 .Case("explicit", MMToken::ExplicitKeyword) 351 .Case("framework", MMToken::FrameworkKeyword) 352 .Case("module", MMToken::ModuleKeyword) 353 .Case("umbrella", MMToken::UmbrellaKeyword) 354 .Default(MMToken::Identifier); 355 break; 356 357 case tok::eof: 358 Tok.Kind = MMToken::EndOfFile; 359 break; 360 361 case tok::l_brace: 362 Tok.Kind = MMToken::LBrace; 363 break; 364 365 case tok::r_brace: 366 Tok.Kind = MMToken::RBrace; 367 break; 368 369 case tok::string_literal: { 370 // Parse the string literal. 371 LangOptions LangOpts; 372 StringLiteralParser StringLiteral(<oken, 1, SourceMgr, LangOpts, *Target); 373 if (StringLiteral.hadError) 374 goto retry; 375 376 // Copy the string literal into our string data allocator. 377 unsigned Length = StringLiteral.GetStringLength(); 378 char *Saved = StringData.Allocate<char>(Length + 1); 379 memcpy(Saved, StringLiteral.GetString().data(), Length); 380 Saved[Length] = 0; 381 382 // Form the token. 383 Tok.Kind = MMToken::StringLiteral; 384 Tok.StringData = Saved; 385 Tok.StringLength = Length; 386 break; 387 } 388 389 case tok::comment: 390 goto retry; 391 392 default: 393 Diags.Report(LToken.getLocation(), diag::err_mmap_unknown_token); 394 HadError = true; 395 goto retry; 396 } 397 398 return Result; 399 } 400 401 void ModuleMapParser::skipUntil(MMToken::TokenKind K) { 402 unsigned braceDepth = 0; 403 do { 404 switch (Tok.Kind) { 405 case MMToken::EndOfFile: 406 return; 407 408 case MMToken::LBrace: 409 if (Tok.is(K) && braceDepth == 0) 410 return; 411 412 ++braceDepth; 413 break; 414 415 case MMToken::RBrace: 416 if (braceDepth > 0) 417 --braceDepth; 418 else if (Tok.is(K)) 419 return; 420 break; 421 422 default: 423 if (braceDepth == 0 && Tok.is(K)) 424 return; 425 break; 426 } 427 428 consumeToken(); 429 } while (true); 430 } 431 432 /// \brief Parse a module declaration. 433 /// 434 /// module-declaration: 435 /// 'framework'[opt] 'module' identifier { module-member* } 436 /// 437 /// module-member: 438 /// umbrella-declaration 439 /// header-declaration 440 /// 'explicit'[opt] module-declaration 441 void ModuleMapParser::parseModuleDecl() { 442 assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) || 443 Tok.is(MMToken::FrameworkKeyword)); 444 445 // Parse 'framework' or 'explicit' keyword, if present. 446 bool Framework = false; 447 bool Explicit = false; 448 449 if (Tok.is(MMToken::FrameworkKeyword)) { 450 consumeToken(); 451 Framework = true; 452 } 453 // Parse 'explicit' keyword, if present. 454 else if (Tok.is(MMToken::ExplicitKeyword)) { 455 consumeToken(); 456 Explicit = true; 457 } 458 459 // Parse 'module' keyword. 460 if (!Tok.is(MMToken::ModuleKeyword)) { 461 Diags.Report(Tok.getLocation(), 462 diag::err_mmap_expected_module_after_explicit); 463 consumeToken(); 464 HadError = true; 465 return; 466 } 467 consumeToken(); // 'module' keyword 468 469 // Parse the module name. 470 if (!Tok.is(MMToken::Identifier)) { 471 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name); 472 HadError = true; 473 return; 474 } 475 StringRef ModuleName = Tok.getString(); 476 SourceLocation ModuleNameLoc = consumeToken(); 477 478 // Parse the opening brace. 479 if (!Tok.is(MMToken::LBrace)) { 480 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace) 481 << ModuleName; 482 HadError = true; 483 return; 484 } 485 SourceLocation LBraceLoc = consumeToken(); 486 487 // Determine whether this (sub)module has already been defined. 488 llvm::StringMap<Module *> &ModuleSpace 489 = ActiveModule? ActiveModule->SubModules : Map.Modules; 490 llvm::StringMap<Module *>::iterator ExistingModule 491 = ModuleSpace.find(ModuleName); 492 if (ExistingModule != ModuleSpace.end()) { 493 Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition) 494 << ModuleName; 495 Diags.Report(ExistingModule->getValue()->DefinitionLoc, 496 diag::note_mmap_prev_definition); 497 498 // Skip the module definition. 499 skipUntil(MMToken::RBrace); 500 if (Tok.is(MMToken::RBrace)) 501 consumeToken(); 502 503 HadError = true; 504 return; 505 } 506 507 // Start defining this module. 508 ActiveModule = new Module(ModuleName, ModuleNameLoc, ActiveModule, Framework, 509 Explicit); 510 ModuleSpace[ModuleName] = ActiveModule; 511 512 bool Done = false; 513 do { 514 switch (Tok.Kind) { 515 case MMToken::EndOfFile: 516 case MMToken::RBrace: 517 Done = true; 518 break; 519 520 case MMToken::ExplicitKeyword: 521 case MMToken::ModuleKeyword: 522 parseModuleDecl(); 523 break; 524 525 case MMToken::HeaderKeyword: 526 parseHeaderDecl(); 527 break; 528 529 case MMToken::UmbrellaKeyword: 530 parseUmbrellaDecl(); 531 break; 532 533 default: 534 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member); 535 consumeToken(); 536 break; 537 } 538 } while (!Done); 539 540 if (Tok.is(MMToken::RBrace)) 541 consumeToken(); 542 else { 543 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace); 544 Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match); 545 HadError = true; 546 } 547 548 // We're done parsing this module. Pop back to our parent scope. 549 ActiveModule = ActiveModule->Parent; 550 } 551 552 /// \brief Parse an umbrella header declaration. 553 /// 554 /// umbrella-declaration: 555 /// 'umbrella' string-literal 556 void ModuleMapParser::parseUmbrellaDecl() { 557 assert(Tok.is(MMToken::UmbrellaKeyword)); 558 SourceLocation UmbrellaLoc = consumeToken(); 559 560 // Parse the header name. 561 if (!Tok.is(MMToken::StringLiteral)) { 562 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) 563 << "umbrella"; 564 HadError = true; 565 return; 566 } 567 StringRef FileName = Tok.getString(); 568 SourceLocation FileNameLoc = consumeToken(); 569 570 // Check whether we already have an umbrella header. 571 if (ActiveModule->UmbrellaHeader) { 572 Diags.Report(FileNameLoc, diag::err_mmap_umbrella_header_conflict) 573 << ActiveModule->getFullModuleName() 574 << ActiveModule->UmbrellaHeader->getName(); 575 HadError = true; 576 return; 577 } 578 579 // Only top-level modules can have umbrella headers. 580 if (ActiveModule->Parent) { 581 Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_header_submodule) 582 << ActiveModule->getFullModuleName(); 583 HadError = true; 584 return; 585 } 586 587 // Look for this file. 588 llvm::SmallString<128> PathName; 589 PathName += Directory->getName(); 590 unsigned PathLength = PathName.size(); 591 const FileEntry *File = 0; 592 if (ActiveModule->isPartOfFramework()) { 593 // Check whether this file is in the public headers. 594 llvm::sys::path::append(PathName, "Headers"); 595 llvm::sys::path::append(PathName, FileName); 596 File = SourceMgr.getFileManager().getFile(PathName); 597 598 if (!File) { 599 // Check whether this file is in the private headers. 600 PathName.resize(PathLength); 601 llvm::sys::path::append(PathName, "PrivateHeaders"); 602 llvm::sys::path::append(PathName, FileName); 603 File = SourceMgr.getFileManager().getFile(PathName); 604 } 605 606 // FIXME: Deal with subframeworks. 607 } else { 608 // Lookup for normal headers. 609 llvm::sys::path::append(PathName, FileName); 610 File = SourceMgr.getFileManager().getFile(PathName); 611 } 612 613 // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. 614 // Come up with a lazy way to do this. 615 if (File) { 616 if (const Module *OwningModule = Map.Headers[File]) { 617 Diags.Report(FileNameLoc, diag::err_mmap_header_conflict) 618 << FileName << OwningModule->getFullModuleName(); 619 HadError = true; 620 } else if ((OwningModule = Map.UmbrellaDirs[Directory])) { 621 Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash) 622 << OwningModule->getFullModuleName(); 623 HadError = true; 624 } else { 625 // Record this umbrella header. 626 ActiveModule->UmbrellaHeader = File; 627 Map.Headers[File] = ActiveModule; 628 Map.UmbrellaDirs[Directory] = ActiveModule; 629 } 630 } else { 631 Diags.Report(FileNameLoc, diag::err_mmap_header_not_found) 632 << true << FileName; 633 HadError = true; 634 } 635 } 636 637 /// \brief Parse a header declaration. 638 /// 639 /// header-declaration: 640 /// 'header' string-literal 641 void ModuleMapParser::parseHeaderDecl() { 642 assert(Tok.is(MMToken::HeaderKeyword)); 643 consumeToken(); 644 645 // Parse the header name. 646 if (!Tok.is(MMToken::StringLiteral)) { 647 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) 648 << "header"; 649 HadError = true; 650 return; 651 } 652 StringRef FileName = Tok.getString(); 653 SourceLocation FileNameLoc = consumeToken(); 654 655 // Look for this file. 656 llvm::SmallString<128> PathName; 657 PathName += Directory->getName(); 658 659 if (ActiveModule->isPartOfFramework()) 660 llvm::sys::path::append(PathName, "Headers"); 661 662 llvm::sys::path::append(PathName, FileName); 663 664 // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. 665 // Come up with a lazy way to do this. 666 if (const FileEntry *File = SourceMgr.getFileManager().getFile(PathName)) { 667 if (const Module *OwningModule = Map.Headers[File]) { 668 Diags.Report(FileNameLoc, diag::err_mmap_header_conflict) 669 << FileName << OwningModule->getFullModuleName(); 670 HadError = true; 671 } else { 672 // Record this file. 673 ActiveModule->Headers.push_back(File); 674 Map.Headers[File] = ActiveModule; 675 } 676 } else { 677 Diags.Report(FileNameLoc, diag::err_mmap_header_not_found) 678 << false << FileName; 679 HadError = true; 680 } 681 } 682 683 /// \brief Parse a module map file. 684 /// 685 /// module-map-file: 686 /// module-declaration* 687 bool ModuleMapParser::parseModuleMapFile() { 688 do { 689 switch (Tok.Kind) { 690 case MMToken::EndOfFile: 691 return HadError; 692 693 case MMToken::ModuleKeyword: 694 case MMToken::FrameworkKeyword: 695 parseModuleDecl(); 696 break; 697 698 case MMToken::ExplicitKeyword: 699 case MMToken::HeaderKeyword: 700 case MMToken::Identifier: 701 case MMToken::LBrace: 702 case MMToken::RBrace: 703 case MMToken::StringLiteral: 704 case MMToken::UmbrellaKeyword: 705 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module); 706 HadError = true; 707 consumeToken(); 708 break; 709 } 710 } while (true); 711 712 return HadError; 713 } 714 715 bool ModuleMap::parseModuleMapFile(const FileEntry *File) { 716 FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User); 717 const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID); 718 if (!Buffer) 719 return true; 720 721 // Parse this module map file. 722 Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, LangOpts); 723 Diags->getClient()->BeginSourceFile(LangOpts); 724 ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir()); 725 bool Result = Parser.parseModuleMapFile(); 726 Diags->getClient()->EndSourceFile(); 727 728 return Result; 729 } 730