xref: /llvm-project/clang/lib/Frontend/CompilerInstance.cpp (revision 7d75afc56abd29c41d68f7cfddf215a49ddbe6cf)
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/Basic/Diagnostic.h"
12 #include "clang/Basic/FileManager.h"
13 #include "clang/Basic/SourceManager.h"
14 #include "clang/Basic/TargetInfo.h"
15 #include "clang/Lex/HeaderSearch.h"
16 #include "clang/Lex/Preprocessor.h"
17 #include "clang/Lex/PTHManager.h"
18 #include "clang/Frontend/ChainedDiagnosticClient.h"
19 #include "clang/Frontend/TextDiagnosticBuffer.h"
20 #include "clang/Frontend/TextDiagnosticPrinter.h"
21 #include "clang/Frontend/Utils.h"
22 #include "llvm/LLVMContext.h"
23 #include "llvm/Support/raw_ostream.h"
24 using namespace clang;
25 
26 CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
27                                    bool _OwnsLLVMContext)
28   : LLVMContext(_LLVMContext),
29     OwnsLLVMContext(_OwnsLLVMContext) {
30 }
31 
32 CompilerInstance::~CompilerInstance() {
33   if (OwnsLLVMContext)
34     delete LLVMContext;
35 }
36 
37 // Diagnostics
38 
39 static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
40                               unsigned argc, char **argv,
41                               llvm::OwningPtr<DiagnosticClient> &DiagClient) {
42   std::string ErrorInfo;
43   llvm::raw_ostream *OS =
44     new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo);
45   if (!ErrorInfo.empty()) {
46     // FIXME: Do not fail like this.
47     llvm::errs() << "error opening -dump-build-information file '"
48                  << DiagOpts.DumpBuildInformation << "', option ignored!\n";
49     delete OS;
50     return;
51   }
52 
53   (*OS) << "clang-cc command line arguments: ";
54   for (unsigned i = 0; i != argc; ++i)
55     (*OS) << argv[i] << ' ';
56   (*OS) << '\n';
57 
58   // Chain in a diagnostic client which will log the diagnostics.
59   DiagnosticClient *Logger =
60     new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true);
61   DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger));
62 }
63 
64 void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
65   Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv));
66 
67   if (Diagnostics)
68     DiagClient.reset(Diagnostics->getClient());
69 }
70 
71 Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
72                                                 int Argc, char **Argv) {
73   // Create the diagnostic client for reporting errors or for
74   // implementing -verify.
75   llvm::OwningPtr<DiagnosticClient> DiagClient;
76   if (Opts.VerifyDiagnostics) {
77     // When checking diagnostics, just buffer them up.
78     DiagClient.reset(new TextDiagnosticBuffer());
79   } else {
80     DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
81   }
82 
83   if (!Opts.DumpBuildInformation.empty())
84     SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient);
85 
86   // Configure our handling of diagnostics.
87   Diagnostic *Diags = new Diagnostic(DiagClient.take());
88   if (ProcessWarningOptions(*Diags, Opts))
89     return 0;
90 
91   return Diags;
92 }
93 
94 // File Manager
95 
96 void CompilerInstance::createFileManager() {
97   FileMgr.reset(new FileManager());
98 }
99 
100 // Source Manager
101 
102 void CompilerInstance::createSourceManager() {
103   SourceMgr.reset(new SourceManager());
104 }
105 
106 // Preprocessor
107 
108 void CompilerInstance::createPreprocessor() {
109   PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
110                               getPreprocessorOpts(), getHeaderSearchOpts(),
111                               getDependencyOutputOpts(), getTarget(),
112                               getSourceManager(), getFileManager()));
113 }
114 
115 Preprocessor *
116 CompilerInstance::createPreprocessor(Diagnostic &Diags,
117                                      const LangOptions &LangInfo,
118                                      const PreprocessorOptions &PPOpts,
119                                      const HeaderSearchOptions &HSOpts,
120                                      const DependencyOutputOptions &DepOpts,
121                                      const TargetInfo &Target,
122                                      SourceManager &SourceMgr,
123                                      FileManager &FileMgr) {
124   // Create a PTH manager if we are using some form of a token cache.
125   PTHManager *PTHMgr = 0;
126   if (!PPOpts.getTokenCache().empty())
127     PTHMgr = PTHManager::Create(PPOpts.getTokenCache(), Diags);
128 
129   // FIXME: Don't fail like this.
130   if (Diags.hasErrorOccurred())
131     exit(1);
132 
133   // Create the Preprocessor.
134   HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
135   Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
136                                       SourceMgr, *HeaderInfo, PTHMgr,
137                                       /*OwnsHeaderSearch=*/true);
138 
139   // Note that this is different then passing PTHMgr to Preprocessor's ctor.
140   // That argument is used as the IdentifierInfoLookup argument to
141   // IdentifierTable's ctor.
142   if (PTHMgr) {
143     PTHMgr->setPreprocessor(PP);
144     PP->setPTHManager(PTHMgr);
145   }
146 
147   InitializePreprocessor(*PP, PPOpts, HSOpts);
148 
149   // Handle generating dependencies, if requested.
150   if (!DepOpts.OutputFile.empty())
151     AttachDependencyFileGen(*PP, DepOpts);
152 
153   return PP;
154 }
155