CompilerInstance.cpp revision 8a9f569262860b8d03203327afd6047be2a9b5a6
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/AST/ASTContext.h" 12#include "clang/Basic/Diagnostic.h" 13#include "clang/Basic/FileManager.h" 14#include "clang/Basic/SourceManager.h" 15#include "clang/Basic/TargetInfo.h" 16#include "clang/Lex/HeaderSearch.h" 17#include "clang/Lex/Preprocessor.h" 18#include "clang/Lex/PTHManager.h" 19#include "clang/Frontend/ChainedDiagnosticClient.h" 20#include "clang/Frontend/PCHReader.h" 21#include "clang/Frontend/FrontendDiagnostic.h" 22#include "clang/Frontend/TextDiagnosticBuffer.h" 23#include "clang/Frontend/TextDiagnosticPrinter.h" 24#include "clang/Frontend/Utils.h" 25#include "clang/Sema/CodeCompleteConsumer.h" 26#include "llvm/LLVMContext.h" 27#include "llvm/Support/raw_ostream.h" 28#include "llvm/System/Path.h" 29using namespace clang; 30 31CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, 32 bool _OwnsLLVMContext) 33 : LLVMContext(_LLVMContext), 34 OwnsLLVMContext(_OwnsLLVMContext) { 35 } 36 37CompilerInstance::~CompilerInstance() { 38 if (OwnsLLVMContext) 39 delete LLVMContext; 40} 41 42void CompilerInstance::setDiagnostics(Diagnostic *Value) { 43 Diagnostics.reset(Value); 44} 45 46void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) { 47 DiagClient.reset(Value); 48} 49 50void CompilerInstance::setTarget(TargetInfo *Value) { 51 Target.reset(Value); 52} 53 54void CompilerInstance::setFileManager(FileManager *Value) { 55 FileMgr.reset(Value); 56} 57 58void CompilerInstance::setSourceManager(SourceManager *Value) { 59 SourceMgr.reset(Value); 60} 61 62void CompilerInstance::setPreprocessor(Preprocessor *Value) { 63 PP.reset(Value); 64} 65 66void CompilerInstance::setASTContext(ASTContext *Value) { 67 Context.reset(Value); 68} 69 70void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { 71 CompletionConsumer.reset(Value); 72} 73 74// Diagnostics 75 76static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, 77 unsigned argc, char **argv, 78 llvm::OwningPtr<DiagnosticClient> &DiagClient) { 79 std::string ErrorInfo; 80 llvm::raw_ostream *OS = 81 new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo); 82 if (!ErrorInfo.empty()) { 83 // FIXME: Do not fail like this. 84 llvm::errs() << "error opening -dump-build-information file '" 85 << DiagOpts.DumpBuildInformation << "', option ignored!\n"; 86 delete OS; 87 return; 88 } 89 90 (*OS) << "clang-cc command line arguments: "; 91 for (unsigned i = 0; i != argc; ++i) 92 (*OS) << argv[i] << ' '; 93 (*OS) << '\n'; 94 95 // Chain in a diagnostic client which will log the diagnostics. 96 DiagnosticClient *Logger = 97 new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true); 98 DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger)); 99} 100 101void CompilerInstance::createDiagnostics(int Argc, char **Argv) { 102 Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv)); 103 104 if (Diagnostics) 105 DiagClient.reset(Diagnostics->getClient()); 106} 107 108Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, 109 int Argc, char **Argv) { 110 // Create the diagnostic client for reporting errors or for 111 // implementing -verify. 112 llvm::OwningPtr<DiagnosticClient> DiagClient; 113 if (Opts.VerifyDiagnostics) { 114 // When checking diagnostics, just buffer them up. 115 DiagClient.reset(new TextDiagnosticBuffer()); 116 } else { 117 DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); 118 } 119 120 if (!Opts.DumpBuildInformation.empty()) 121 SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient); 122 123 // Configure our handling of diagnostics. 124 Diagnostic *Diags = new Diagnostic(DiagClient.take()); 125 if (ProcessWarningOptions(*Diags, Opts)) 126 return 0; 127 128 return Diags; 129} 130 131// File Manager 132 133void CompilerInstance::createFileManager() { 134 FileMgr.reset(new FileManager()); 135} 136 137// Source Manager 138 139void CompilerInstance::createSourceManager() { 140 SourceMgr.reset(new SourceManager()); 141} 142 143// Preprocessor 144 145void CompilerInstance::createPreprocessor() { 146 PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), 147 getPreprocessorOpts(), getHeaderSearchOpts(), 148 getDependencyOutputOpts(), getTarget(), 149 getSourceManager(), getFileManager())); 150} 151 152Preprocessor * 153CompilerInstance::createPreprocessor(Diagnostic &Diags, 154 const LangOptions &LangInfo, 155 const PreprocessorOptions &PPOpts, 156 const HeaderSearchOptions &HSOpts, 157 const DependencyOutputOptions &DepOpts, 158 const TargetInfo &Target, 159 SourceManager &SourceMgr, 160 FileManager &FileMgr) { 161 // Create a PTH manager if we are using some form of a token cache. 162 PTHManager *PTHMgr = 0; 163 if (!PPOpts.getTokenCache().empty()) 164 PTHMgr = PTHManager::Create(PPOpts.getTokenCache(), Diags); 165 166 // FIXME: Don't fail like this. 167 if (Diags.hasErrorOccurred()) 168 exit(1); 169 170 // Create the Preprocessor. 171 HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); 172 Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, 173 SourceMgr, *HeaderInfo, PTHMgr, 174 /*OwnsHeaderSearch=*/true); 175 176 // Note that this is different then passing PTHMgr to Preprocessor's ctor. 177 // That argument is used as the IdentifierInfoLookup argument to 178 // IdentifierTable's ctor. 179 if (PTHMgr) { 180 PTHMgr->setPreprocessor(PP); 181 PP->setPTHManager(PTHMgr); 182 } 183 184 InitializePreprocessor(*PP, PPOpts, HSOpts); 185 186 // Handle generating dependencies, if requested. 187 if (!DepOpts.OutputFile.empty()) 188 AttachDependencyFileGen(*PP, DepOpts); 189 190 return PP; 191} 192 193// ASTContext 194 195void CompilerInstance::createASTContext() { 196 Preprocessor &PP = getPreprocessor(); 197 Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), 198 getTarget(), PP.getIdentifierTable(), 199 PP.getSelectorTable(), PP.getBuiltinInfo(), 200 /*FreeMemory=*/ !getFrontendOpts().DisableFree, 201 /*size_reserve=*/ 0)); 202} 203 204// ExternalASTSource 205 206void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { 207 llvm::OwningPtr<ExternalASTSource> Source; 208 Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, 209 getPreprocessor(), getASTContext())); 210 getASTContext().setExternalSource(Source); 211} 212 213ExternalASTSource * 214CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 215 const std::string &Sysroot, 216 Preprocessor &PP, 217 ASTContext &Context) { 218 llvm::OwningPtr<PCHReader> Reader; 219 Reader.reset(new PCHReader(PP, &Context, 220 Sysroot.empty() ? 0 : Sysroot.c_str())); 221 222 switch (Reader->ReadPCH(Path)) { 223 case PCHReader::Success: 224 // Set the predefines buffer as suggested by the PCH reader. Typically, the 225 // predefines buffer will be empty. 226 PP.setPredefines(Reader->getSuggestedPredefines()); 227 return Reader.take(); 228 229 case PCHReader::Failure: 230 // Unrecoverable failure: don't even try to process the input file. 231 break; 232 233 case PCHReader::IgnorePCH: 234 // No suitable PCH file could be found. Return an error. 235 break; 236 } 237 238 return 0; 239} 240 241// Code Completion 242 243void CompilerInstance::createCodeCompletionConsumer() { 244 const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; 245 CompletionConsumer.reset( 246 createCodeCompletionConsumer(getPreprocessor(), 247 Loc.FileName, Loc.Line, Loc.Column, 248 getFrontendOpts().DebugCodeCompletionPrinter, 249 getFrontendOpts().ShowMacrosInCodeCompletion, 250 llvm::outs())); 251} 252 253CodeCompleteConsumer * 254CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, 255 const std::string &Filename, 256 unsigned Line, 257 unsigned Column, 258 bool UseDebugPrinter, 259 bool ShowMacros, 260 llvm::raw_ostream &OS) { 261 // Tell the source manager to chop off the given file at a specific 262 // line and column. 263 const FileEntry *Entry = PP.getFileManager().getFile(Filename); 264 if (!Entry) { 265 PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) 266 << Filename; 267 return 0; 268 } 269 270 // Truncate the named file at the given line/column. 271 PP.getSourceManager().truncateFileAt(Entry, Line, Column); 272 273 // Set up the creation routine for code-completion. 274 if (UseDebugPrinter) 275 return new PrintingCodeCompleteConsumer(ShowMacros, OS); 276 else 277 return new CIndexCodeCompleteConsumer(ShowMacros, OS); 278} 279 280// Output Files 281 282void CompilerInstance::addOutputFile(llvm::StringRef Path, 283 llvm::raw_ostream *OS) { 284 assert(OS && "Attempt to add empty stream to output list!"); 285 OutputFiles.push_back(std::make_pair(Path, OS)); 286} 287 288void CompilerInstance::ClearOutputFiles(bool EraseFiles) { 289 for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator 290 it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { 291 delete it->second; 292 if (EraseFiles && !it->first.empty()) 293 llvm::sys::Path(it->first).eraseFromDisk(); 294 } 295 OutputFiles.clear(); 296} 297 298llvm::raw_fd_ostream * 299CompilerInstance::createDefaultOutputFile(bool Binary, 300 llvm::StringRef InFile, 301 llvm::StringRef Extension) { 302 return createOutputFile(getFrontendOpts().OutputFile, Binary, 303 InFile, Extension); 304} 305 306llvm::raw_fd_ostream * 307CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 308 bool Binary, 309 llvm::StringRef InFile, 310 llvm::StringRef Extension) { 311 std::string Error, OutputPathName; 312 llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, 313 InFile, Extension, 314 &OutputPathName); 315 if (!OS) { 316 // FIXME: Don't fail this way. 317 llvm::errs() << "ERROR: " << Error << "\n"; 318 ::exit(1); 319 } 320 321 // Add the output file -- but don't try to remove "-", since this means we are 322 // using stdin. 323 addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); 324 325 return OS; 326} 327 328llvm::raw_fd_ostream * 329CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 330 std::string &Error, 331 bool Binary, 332 llvm::StringRef InFile, 333 llvm::StringRef Extension, 334 std::string *ResultPathName) { 335 std::string OutFile; 336 if (!OutputPath.empty()) { 337 OutFile = OutputPath; 338 } else if (InFile == "-") { 339 OutFile = "-"; 340 } else if (!Extension.empty()) { 341 llvm::sys::Path Path(InFile); 342 Path.eraseSuffix(); 343 Path.appendSuffix(Extension); 344 OutFile = Path.str(); 345 } else { 346 OutFile = "-"; 347 } 348 349 llvm::raw_fd_ostream *OS = 350 new llvm::raw_fd_ostream(OutFile.c_str(), Error, 351 (Binary ? llvm::raw_fd_ostream::F_Binary : 0)); 352 if (!OS) 353 return 0; 354 355 if (ResultPathName) 356 *ResultPathName = OutFile; 357 358 return OS; 359} 360