xref: /llvm-project/clang/lib/Frontend/CompilerInstance.cpp (revision 081425343b18b6e057a89ab92d89984257fda370)
1 //===--- CompilerInstance.cpp ---------------------------------------------===//
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 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Sema/Sema.h"
12 #include "clang/AST/ASTConsumer.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/Basic/Diagnostic.h"
15 #include "clang/Basic/FileManager.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Basic/Version.h"
19 #include "clang/Lex/HeaderSearch.h"
20 #include "clang/Lex/Preprocessor.h"
21 #include "clang/Lex/PTHManager.h"
22 #include "clang/Frontend/ChainedDiagnosticClient.h"
23 #include "clang/Frontend/FrontendAction.h"
24 #include "clang/Frontend/FrontendDiagnostic.h"
25 #include "clang/Frontend/LogDiagnosticPrinter.h"
26 #include "clang/Frontend/TextDiagnosticPrinter.h"
27 #include "clang/Frontend/VerifyDiagnosticsClient.h"
28 #include "clang/Frontend/Utils.h"
29 #include "clang/Serialization/ASTReader.h"
30 #include "clang/Sema/CodeCompleteConsumer.h"
31 #include "llvm/Support/FileSystem.h"
32 #include "llvm/Support/MemoryBuffer.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include "llvm/ADT/Statistic.h"
35 #include "llvm/Support/Timer.h"
36 #include "llvm/Support/Host.h"
37 #include "llvm/Support/Path.h"
38 #include "llvm/Support/Program.h"
39 #include "llvm/Support/Signals.h"
40 #include "llvm/Support/system_error.h"
41 #include "llvm/Config/config.h"
42 using namespace clang;
43 
44 CompilerInstance::CompilerInstance()
45   : Invocation(new CompilerInvocation()), ModuleManager(0) {
46 }
47 
48 CompilerInstance::~CompilerInstance() {
49 }
50 
51 void CompilerInstance::setInvocation(CompilerInvocation *Value) {
52   Invocation = Value;
53 }
54 
55 void CompilerInstance::setDiagnostics(Diagnostic *Value) {
56   Diagnostics = Value;
57 }
58 
59 void CompilerInstance::setTarget(TargetInfo *Value) {
60   Target = Value;
61 }
62 
63 void CompilerInstance::setFileManager(FileManager *Value) {
64   FileMgr = Value;
65 }
66 
67 void CompilerInstance::setSourceManager(SourceManager *Value) {
68   SourceMgr = Value;
69 }
70 
71 void CompilerInstance::setPreprocessor(Preprocessor *Value) { PP = Value; }
72 
73 void CompilerInstance::setASTContext(ASTContext *Value) { Context = Value; }
74 
75 void CompilerInstance::setSema(Sema *S) {
76   TheSema.reset(S);
77 }
78 
79 void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
80   Consumer.reset(Value);
81 }
82 
83 void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
84   CompletionConsumer.reset(Value);
85 }
86 
87 // Diagnostics
88 static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
89                               unsigned argc, const char* const *argv,
90                               Diagnostic &Diags) {
91   std::string ErrorInfo;
92   llvm::OwningPtr<raw_ostream> OS(
93     new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo));
94   if (!ErrorInfo.empty()) {
95     Diags.Report(diag::err_fe_unable_to_open_logfile)
96                  << DiagOpts.DumpBuildInformation << ErrorInfo;
97     return;
98   }
99 
100   (*OS) << "clang -cc1 command line arguments: ";
101   for (unsigned i = 0; i != argc; ++i)
102     (*OS) << argv[i] << ' ';
103   (*OS) << '\n';
104 
105   // Chain in a diagnostic client which will log the diagnostics.
106   DiagnosticClient *Logger =
107     new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
108   Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
109 }
110 
111 static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
112                                const CodeGenOptions *CodeGenOpts,
113                                Diagnostic &Diags) {
114   std::string ErrorInfo;
115   bool OwnsStream = false;
116   raw_ostream *OS = &llvm::errs();
117   if (DiagOpts.DiagnosticLogFile != "-") {
118     // Create the output stream.
119     llvm::raw_fd_ostream *FileOS(
120       new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(),
121                                ErrorInfo, llvm::raw_fd_ostream::F_Append));
122     if (!ErrorInfo.empty()) {
123       Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
124         << DiagOpts.DumpBuildInformation << ErrorInfo;
125     } else {
126       FileOS->SetUnbuffered();
127       FileOS->SetUseAtomicWrites(true);
128       OS = FileOS;
129       OwnsStream = true;
130     }
131   }
132 
133   // Chain in the diagnostic client which will log the diagnostics.
134   LogDiagnosticPrinter *Logger = new LogDiagnosticPrinter(*OS, DiagOpts,
135                                                           OwnsStream);
136   if (CodeGenOpts)
137     Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
138   Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
139 }
140 
141 void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
142                                          DiagnosticClient *Client) {
143   Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client,
144                                   &getCodeGenOpts());
145 }
146 
147 llvm::IntrusiveRefCntPtr<Diagnostic>
148 CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
149                                     int Argc, const char* const *Argv,
150                                     DiagnosticClient *Client,
151                                     const CodeGenOptions *CodeGenOpts) {
152   llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
153   llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID));
154 
155   // Create the diagnostic client for reporting errors or for
156   // implementing -verify.
157   if (Client)
158     Diags->setClient(Client);
159   else
160     Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
161 
162   // Chain in -verify checker, if requested.
163   if (Opts.VerifyDiagnostics)
164     Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient()));
165 
166   // Chain in -diagnostic-log-file dumper, if requested.
167   if (!Opts.DiagnosticLogFile.empty())
168     SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
169 
170   if (!Opts.DumpBuildInformation.empty())
171     SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
172 
173   // Configure our handling of diagnostics.
174   ProcessWarningOptions(*Diags, Opts);
175 
176   return Diags;
177 }
178 
179 // File Manager
180 
181 void CompilerInstance::createFileManager() {
182   FileMgr = new FileManager(getFileSystemOpts());
183 }
184 
185 // Source Manager
186 
187 void CompilerInstance::createSourceManager(FileManager &FileMgr) {
188   SourceMgr = new SourceManager(getDiagnostics(), FileMgr);
189 }
190 
191 // Preprocessor
192 
193 void CompilerInstance::createPreprocessor() {
194   const PreprocessorOptions &PPOpts = getPreprocessorOpts();
195 
196   // Create a PTH manager if we are using some form of a token cache.
197   PTHManager *PTHMgr = 0;
198   if (!PPOpts.TokenCache.empty())
199     PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
200 
201   // Create the Preprocessor.
202   HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager());
203   PP = new Preprocessor(getDiagnostics(), getLangOpts(), getTarget(),
204                         getSourceManager(), *HeaderInfo, *this, PTHMgr,
205                         /*OwnsHeaderSearch=*/true);
206 
207   // Note that this is different then passing PTHMgr to Preprocessor's ctor.
208   // That argument is used as the IdentifierInfoLookup argument to
209   // IdentifierTable's ctor.
210   if (PTHMgr) {
211     PTHMgr->setPreprocessor(&*PP);
212     PP->setPTHManager(PTHMgr);
213   }
214 
215   if (PPOpts.DetailedRecord)
216     PP->createPreprocessingRecord(
217                                   PPOpts.DetailedRecordIncludesNestedMacroExpansions);
218 
219   InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
220 
221   // Handle generating dependencies, if requested.
222   const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
223   if (!DepOpts.OutputFile.empty())
224     AttachDependencyFileGen(*PP, DepOpts);
225 
226   // Handle generating header include information, if requested.
227   if (DepOpts.ShowHeaderIncludes)
228     AttachHeaderIncludeGen(*PP);
229   if (!DepOpts.HeaderIncludeOutputFile.empty()) {
230     StringRef OutputPath = DepOpts.HeaderIncludeOutputFile;
231     if (OutputPath == "-")
232       OutputPath = "";
233     AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath,
234                            /*ShowDepth=*/false);
235   }
236 }
237 
238 // ASTContext
239 
240 void CompilerInstance::createASTContext() {
241   Preprocessor &PP = getPreprocessor();
242   Context = new ASTContext(getLangOpts(), PP.getSourceManager(),
243                            getTarget(), PP.getIdentifierTable(),
244                            PP.getSelectorTable(), PP.getBuiltinInfo(),
245                            /*size_reserve=*/ 0);
246 }
247 
248 // ExternalASTSource
249 
250 void CompilerInstance::createPCHExternalASTSource(StringRef Path,
251                                                   bool DisablePCHValidation,
252                                                   bool DisableStatCache,
253                                                  void *DeserializationListener){
254   llvm::OwningPtr<ExternalASTSource> Source;
255   bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
256   Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
257                                           DisablePCHValidation,
258                                           DisableStatCache,
259                                           getPreprocessor(), getASTContext(),
260                                           DeserializationListener,
261                                           Preamble));
262   ModuleManager = static_cast<ASTReader*>(Source.get());
263   getASTContext().setExternalSource(Source);
264 }
265 
266 ExternalASTSource *
267 CompilerInstance::createPCHExternalASTSource(StringRef Path,
268                                              const std::string &Sysroot,
269                                              bool DisablePCHValidation,
270                                              bool DisableStatCache,
271                                              Preprocessor &PP,
272                                              ASTContext &Context,
273                                              void *DeserializationListener,
274                                              bool Preamble) {
275   llvm::OwningPtr<ASTReader> Reader;
276   Reader.reset(new ASTReader(PP, &Context,
277                              Sysroot.empty() ? "" : Sysroot.c_str(),
278                              DisablePCHValidation, DisableStatCache));
279 
280   Reader->setDeserializationListener(
281             static_cast<ASTDeserializationListener *>(DeserializationListener));
282   switch (Reader->ReadAST(Path,
283                           Preamble ? serialization::MK_Preamble
284                                    : serialization::MK_PCH)) {
285   case ASTReader::Success:
286     // Set the predefines buffer as suggested by the PCH reader. Typically, the
287     // predefines buffer will be empty.
288     PP.setPredefines(Reader->getSuggestedPredefines());
289     return Reader.take();
290 
291   case ASTReader::Failure:
292     // Unrecoverable failure: don't even try to process the input file.
293     break;
294 
295   case ASTReader::IgnorePCH:
296     // No suitable PCH file could be found. Return an error.
297     break;
298   }
299 
300   return 0;
301 }
302 
303 // Code Completion
304 
305 static bool EnableCodeCompletion(Preprocessor &PP,
306                                  const std::string &Filename,
307                                  unsigned Line,
308                                  unsigned Column) {
309   // Tell the source manager to chop off the given file at a specific
310   // line and column.
311   const FileEntry *Entry = PP.getFileManager().getFile(Filename);
312   if (!Entry) {
313     PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
314       << Filename;
315     return true;
316   }
317 
318   // Truncate the named file at the given line/column.
319   PP.SetCodeCompletionPoint(Entry, Line, Column);
320   return false;
321 }
322 
323 void CompilerInstance::createCodeCompletionConsumer() {
324   const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt;
325   if (!CompletionConsumer) {
326     CompletionConsumer.reset(
327       createCodeCompletionConsumer(getPreprocessor(),
328                                    Loc.FileName, Loc.Line, Loc.Column,
329                                    getFrontendOpts().ShowMacrosInCodeCompletion,
330                              getFrontendOpts().ShowCodePatternsInCodeCompletion,
331                            getFrontendOpts().ShowGlobalSymbolsInCodeCompletion,
332                                    llvm::outs()));
333     if (!CompletionConsumer)
334       return;
335   } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName,
336                                   Loc.Line, Loc.Column)) {
337     CompletionConsumer.reset();
338     return;
339   }
340 
341   if (CompletionConsumer->isOutputBinary() &&
342       llvm::sys::Program::ChangeStdoutToBinary()) {
343     getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
344     CompletionConsumer.reset();
345   }
346 }
347 
348 void CompilerInstance::createFrontendTimer() {
349   FrontendTimer.reset(new llvm::Timer("Clang front-end timer"));
350 }
351 
352 CodeCompleteConsumer *
353 CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
354                                                const std::string &Filename,
355                                                unsigned Line,
356                                                unsigned Column,
357                                                bool ShowMacros,
358                                                bool ShowCodePatterns,
359                                                bool ShowGlobals,
360                                                raw_ostream &OS) {
361   if (EnableCodeCompletion(PP, Filename, Line, Column))
362     return 0;
363 
364   // Set up the creation routine for code-completion.
365   return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
366                                           ShowGlobals, OS);
367 }
368 
369 void CompilerInstance::createSema(TranslationUnitKind TUKind,
370                                   CodeCompleteConsumer *CompletionConsumer) {
371   TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
372                          TUKind, CompletionConsumer));
373 }
374 
375 // Output Files
376 
377 void CompilerInstance::addOutputFile(const OutputFile &OutFile) {
378   assert(OutFile.OS && "Attempt to add empty stream to output list!");
379   OutputFiles.push_back(OutFile);
380 }
381 
382 void CompilerInstance::clearOutputFiles(bool EraseFiles) {
383   for (std::list<OutputFile>::iterator
384          it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
385     delete it->OS;
386     if (!it->TempFilename.empty()) {
387       if (EraseFiles) {
388         bool existed;
389         llvm::sys::fs::remove(it->TempFilename, existed);
390       } else {
391         llvm::SmallString<128> NewOutFile(it->Filename);
392 
393         // If '-working-directory' was passed, the output filename should be
394         // relative to that.
395         FileMgr->FixupRelativePath(NewOutFile);
396         if (llvm::error_code ec = llvm::sys::fs::rename(it->TempFilename,
397                                                         NewOutFile.str())) {
398           getDiagnostics().Report(diag::err_fe_unable_to_rename_temp)
399             << it->TempFilename << it->Filename << ec.message();
400 
401           bool existed;
402           llvm::sys::fs::remove(it->TempFilename, existed);
403         }
404       }
405     } else if (!it->Filename.empty() && EraseFiles)
406       llvm::sys::Path(it->Filename).eraseFromDisk();
407 
408   }
409   OutputFiles.clear();
410 }
411 
412 llvm::raw_fd_ostream *
413 CompilerInstance::createDefaultOutputFile(bool Binary,
414                                           StringRef InFile,
415                                           StringRef Extension) {
416   return createOutputFile(getFrontendOpts().OutputFile, Binary,
417                           /*RemoveFileOnSignal=*/true, InFile, Extension);
418 }
419 
420 llvm::raw_fd_ostream *
421 CompilerInstance::createOutputFile(StringRef OutputPath,
422                                    bool Binary, bool RemoveFileOnSignal,
423                                    StringRef InFile,
424                                    StringRef Extension,
425                                    bool UseTemporary) {
426   std::string Error, OutputPathName, TempPathName;
427   llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
428                                               RemoveFileOnSignal,
429                                               InFile, Extension,
430                                               UseTemporary,
431                                               &OutputPathName,
432                                               &TempPathName);
433   if (!OS) {
434     getDiagnostics().Report(diag::err_fe_unable_to_open_output)
435       << OutputPath << Error;
436     return 0;
437   }
438 
439   // Add the output file -- but don't try to remove "-", since this means we are
440   // using stdin.
441   addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "",
442                 TempPathName, OS));
443 
444   return OS;
445 }
446 
447 llvm::raw_fd_ostream *
448 CompilerInstance::createOutputFile(StringRef OutputPath,
449                                    std::string &Error,
450                                    bool Binary,
451                                    bool RemoveFileOnSignal,
452                                    StringRef InFile,
453                                    StringRef Extension,
454                                    bool UseTemporary,
455                                    std::string *ResultPathName,
456                                    std::string *TempPathName) {
457   std::string OutFile, TempFile;
458   if (!OutputPath.empty()) {
459     OutFile = OutputPath;
460   } else if (InFile == "-") {
461     OutFile = "-";
462   } else if (!Extension.empty()) {
463     llvm::sys::Path Path(InFile);
464     Path.eraseSuffix();
465     Path.appendSuffix(Extension);
466     OutFile = Path.str();
467   } else {
468     OutFile = "-";
469   }
470 
471   llvm::OwningPtr<llvm::raw_fd_ostream> OS;
472   std::string OSFile;
473 
474   if (UseTemporary && OutFile != "-") {
475     llvm::sys::Path OutPath(OutFile);
476     // Only create the temporary if we can actually write to OutPath, otherwise
477     // we want to fail early.
478     bool Exists;
479     if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) ||
480         (OutPath.isRegularFile() && OutPath.canWrite())) {
481       // Create a temporary file.
482       llvm::SmallString<128> TempPath;
483       TempPath = OutFile;
484       TempPath += "-%%%%%%%%";
485       int fd;
486       if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
487                                /*makeAbsolute=*/false) == llvm::errc::success) {
488         OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
489         OSFile = TempFile = TempPath.str();
490       }
491     }
492   }
493 
494   if (!OS) {
495     OSFile = OutFile;
496     OS.reset(
497       new llvm::raw_fd_ostream(OSFile.c_str(), Error,
498                                (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
499     if (!Error.empty())
500       return 0;
501   }
502 
503   // Make sure the out stream file gets removed if we crash.
504   if (RemoveFileOnSignal)
505     llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile));
506 
507   if (ResultPathName)
508     *ResultPathName = OutFile;
509   if (TempPathName)
510     *TempPathName = TempFile;
511 
512   return OS.take();
513 }
514 
515 // Initialization Utilities
516 
517 bool CompilerInstance::InitializeSourceManager(StringRef InputFile) {
518   return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
519                                  getSourceManager(), getFrontendOpts());
520 }
521 
522 bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
523                                                Diagnostic &Diags,
524                                                FileManager &FileMgr,
525                                                SourceManager &SourceMgr,
526                                                const FrontendOptions &Opts) {
527   // Figure out where to get and map in the main file, unless it's already
528   // been created (e.g., by a precompiled preamble).
529   if (!SourceMgr.getMainFileID().isInvalid()) {
530     // Do nothing: the main file has already been set.
531   } else if (InputFile != "-") {
532     const FileEntry *File = FileMgr.getFile(InputFile);
533     if (!File) {
534       Diags.Report(diag::err_fe_error_reading) << InputFile;
535       return false;
536     }
537     SourceMgr.createMainFileID(File);
538   } else {
539     llvm::OwningPtr<llvm::MemoryBuffer> SB;
540     if (llvm::MemoryBuffer::getSTDIN(SB)) {
541       // FIXME: Give ec.message() in this diag.
542       Diags.Report(diag::err_fe_error_reading_stdin);
543       return false;
544     }
545     const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(),
546                                                    SB->getBufferSize(), 0);
547     SourceMgr.createMainFileID(File);
548     SourceMgr.overrideFileContents(File, SB.take());
549   }
550 
551   assert(!SourceMgr.getMainFileID().isInvalid() &&
552          "Couldn't establish MainFileID!");
553   return true;
554 }
555 
556 // High-Level Operations
557 
558 bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
559   assert(hasDiagnostics() && "Diagnostics engine is not initialized!");
560   assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!");
561   assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!");
562 
563   // FIXME: Take this as an argument, once all the APIs we used have moved to
564   // taking it as an input instead of hard-coding llvm::errs.
565   raw_ostream &OS = llvm::errs();
566 
567   // Create the target instance.
568   setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
569   if (!hasTarget())
570     return false;
571 
572   // Inform the target of the language options.
573   //
574   // FIXME: We shouldn't need to do this, the target should be immutable once
575   // created. This complexity should be lifted elsewhere.
576   getTarget().setForcedLangOptions(getLangOpts());
577 
578   // Validate/process some options.
579   if (getHeaderSearchOpts().Verbose)
580     OS << "clang -cc1 version " CLANG_VERSION_STRING
581        << " based upon " << PACKAGE_STRING
582        << " hosted on " << llvm::sys::getHostTriple() << "\n";
583 
584   if (getFrontendOpts().ShowTimers)
585     createFrontendTimer();
586 
587   if (getFrontendOpts().ShowStats)
588     llvm::EnableStatistics();
589 
590   for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
591     const std::string &InFile = getFrontendOpts().Inputs[i].second;
592 
593     // Reset the ID tables if we are reusing the SourceManager.
594     if (hasSourceManager())
595       getSourceManager().clearIDTables();
596 
597     if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) {
598       Act.Execute();
599       Act.EndSourceFile();
600     }
601   }
602 
603   if (getDiagnosticOpts().ShowCarets) {
604     // We can have multiple diagnostics sharing one diagnostic client.
605     // Get the total number of warnings/errors from the client.
606     unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings();
607     unsigned NumErrors = getDiagnostics().getClient()->getNumErrors();
608 
609     if (NumWarnings)
610       OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
611     if (NumWarnings && NumErrors)
612       OS << " and ";
613     if (NumErrors)
614       OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
615     if (NumWarnings || NumErrors)
616       OS << " generated.\n";
617   }
618 
619   if (getFrontendOpts().ShowStats && hasFileManager()) {
620     getFileManager().PrintStats();
621     OS << "\n";
622   }
623 
624   return !getDiagnostics().getClient()->getNumErrors();
625 }
626 
627 ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
628                                        IdentifierInfo &ModuleName,
629                                        SourceLocation ModuleNameLoc) {
630   // Determine what file we're searching from.
631   SourceManager &SourceMgr = getSourceManager();
632   SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc);
633   const FileEntry *CurFile
634     = SourceMgr.getFileEntryForID(SourceMgr.getFileID(ExpandedImportLoc));
635   if (!CurFile)
636     CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
637 
638   // Search for a module with the given name.
639   std::string Filename = ModuleName.getName().str();
640   Filename += ".pcm";
641   const DirectoryLookup *CurDir = 0;
642   const FileEntry *ModuleFile
643     = PP->getHeaderSearchInfo().LookupFile(Filename, /*isAngled=*/false,
644                                            /*FromDir=*/0, CurDir, CurFile,
645                                            /*SearchPath=*/0,
646                                            /*RelativePath=*/0);
647   if (!ModuleFile) {
648     getDiagnostics().Report(ModuleNameLoc, diag::warn_module_not_found)
649       << ModuleName.getName()
650       << SourceRange(ImportLoc, ModuleNameLoc);
651     return 0;
652   }
653 
654   // If we don't already have an ASTReader, create one now.
655   if (!ModuleManager) {
656     std::string Sysroot = getHeaderSearchOpts().Sysroot;
657     const PreprocessorOptions &PPOpts = getPreprocessorOpts();
658     ModuleManager = new ASTReader(getPreprocessor(), &*Context,
659                                   Sysroot.empty() ? "" : Sysroot.c_str(),
660                                   PPOpts.DisablePCHValidation,
661                                   PPOpts.DisableStatCache);
662     ModuleManager->setDeserializationListener(
663       getASTConsumer().GetASTDeserializationListener());
664     getASTContext().setASTMutationListener(
665       getASTConsumer().GetASTMutationListener());
666     llvm::OwningPtr<ExternalASTSource> Source;
667     Source.reset(ModuleManager);
668     getASTContext().setExternalSource(Source);
669     ModuleManager->InitializeSema(getSema());
670   }
671 
672   // Try to load the module we found.
673   switch (ModuleManager->ReadAST(ModuleFile->getName(),
674                                  serialization::MK_Module)) {
675   case ASTReader::Success:
676     break;
677 
678   case ASTReader::IgnorePCH:
679     // FIXME: The ASTReader will already have complained, but can we showhorn
680     // that diagnostic information into a more useful form?
681     return 0;
682 
683   case ASTReader::Failure:
684     // Already complained.
685     return 0;
686   }
687 
688   // FIXME: The module file's FileEntry makes a poor key indeed!
689   return (ModuleKey)ModuleFile;
690 }
691 
692