ASTUnit.cpp revision 4ae8f6b1ae99f3c56057508e840a8d00dcc0e755
1d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===// 2d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// 3d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// The LLVM Compiler Infrastructure 4d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// 5d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// This file is distributed under the University of Illinois Open Source 6d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// License. See LICENSE.TXT for details. 7d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// 8d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//===----------------------------------------------------------------------===// 9d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// 10d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// ASTUnit Implementation. 11d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// 12d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//===----------------------------------------------------------------------===// 13d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa 14d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/ASTUnit.h" 15d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/PCHReader.h" 16d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/ASTContext.h" 17d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/ASTConsumer.h" 18d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/DeclVisitor.h" 19d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/StmtVisitor.h" 20d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Compilation.h" 21d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Driver.h" 22d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Job.h" 23d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Tool.h" 248481d64e329bf5f70886add36165bc4b0459bd13Adrian Roos#include "clang/Frontend/CompilerInstance.h" 25d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/FrontendActions.h" 26d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/FrontendDiagnostic.h" 27771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Frontend/FrontendOptions.h" 28771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Lex/HeaderSearch.h" 29771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Lex/Preprocessor.h" 30771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Basic/TargetOptions.h" 31771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Basic/TargetInfo.h" 32771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Basic/Diagnostic.h" 33771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "llvm/Support/MemoryBuffer.h" 34771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "llvm/System/Host.h" 35771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "llvm/System/Path.h" 36771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lamusing namespace clang; 37771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam 38771fac591f6e00221713e6eb763148e3d191d7c2Maurice LamASTUnit::ASTUnit(bool _MainFileIsAST) 39771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) { 40771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam} 41771fac591f6e00221713e6eb763148e3d191d7c2Maurice LamASTUnit::~ASTUnit() { 42771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#ifdef _DEBUG 43d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa ConcurrencyCheckValue = CheckLocked; 44d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#endif 45d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) 46771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam TemporaryFiles[I].eraseFromDisk(); 47d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa} 482662df843327dd938225c75722d0bbf3b01068f7Maurice Lam 492662df843327dd938225c75722d0bbf3b01068f7Maurice Lamnamespace { 50d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa 51d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa/// \brief Gathers information from PCHReader that will be used to initialize 52d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa/// a Preprocessor. 53d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawaclass PCHInfoCollector : public PCHReaderListener { 54d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa LangOptions &LangOpt; 55d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa HeaderSearch &HSI; 56d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa std::string &TargetTriple; 57d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa std::string &Predefines; 58d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa unsigned &Counter; 59d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa 60 unsigned NumHeaderInfos; 61 62public: 63 PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, 64 std::string &TargetTriple, std::string &Predefines, 65 unsigned &Counter) 66 : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple), 67 Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {} 68 69 virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { 70 LangOpt = LangOpts; 71 return false; 72 } 73 74 virtual bool ReadTargetTriple(llvm::StringRef Triple) { 75 TargetTriple = Triple; 76 return false; 77 } 78 79 virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef, 80 FileID PCHBufferID, 81 llvm::StringRef OriginalFileName, 82 std::string &SuggestedPredefines) { 83 Predefines = PCHPredef; 84 return false; 85 } 86 87 virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) { 88 HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); 89 } 90 91 virtual void ReadCounter(unsigned Value) { 92 Counter = Value; 93 } 94}; 95 96class StoredDiagnosticClient : public DiagnosticClient { 97 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags; 98 99public: 100 explicit StoredDiagnosticClient( 101 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) 102 : StoredDiags(StoredDiags) { } 103 104 virtual void HandleDiagnostic(Diagnostic::Level Level, 105 const DiagnosticInfo &Info); 106}; 107 108/// \brief RAII object that optionally captures diagnostics, if 109/// there is no diagnostic client to capture them already. 110class CaptureDroppedDiagnostics { 111 Diagnostic &Diags; 112 StoredDiagnosticClient Client; 113 DiagnosticClient *PreviousClient; 114 115public: 116 CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, 117 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) 118 : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient()) 119 { 120 if (RequestCapture || Diags.getClient() == 0) 121 Diags.setClient(&Client); 122 } 123 124 ~CaptureDroppedDiagnostics() { 125 Diags.setClient(PreviousClient); 126 } 127}; 128 129} // anonymous namespace 130 131void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level, 132 const DiagnosticInfo &Info) { 133 StoredDiags.push_back(StoredDiagnostic(Level, Info)); 134} 135 136const std::string &ASTUnit::getOriginalSourceFileName() { 137 return OriginalSourceFile; 138} 139 140const std::string &ASTUnit::getPCHFileName() { 141 assert(isMainFileAST() && "Not an ASTUnit from a PCH file!"); 142 return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName(); 143} 144 145ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, 146 Diagnostic &Diags, 147 bool OnlyLocalDecls, 148 RemappedFile *RemappedFiles, 149 unsigned NumRemappedFiles, 150 bool CaptureDiagnostics) { 151 llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); 152 AST->OnlyLocalDecls = OnlyLocalDecls; 153 AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); 154 155 // If requested, capture diagnostics in the ASTUnit. 156 CaptureDroppedDiagnostics Capture(CaptureDiagnostics, Diags, 157 AST->Diagnostics); 158 159 for (unsigned I = 0; I != NumRemappedFiles; ++I) { 160 // Create the file entry for the file that we're mapping from. 161 const FileEntry *FromFile 162 = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, 163 RemappedFiles[I].second->getBufferSize(), 164 0); 165 if (!FromFile) { 166 Diags.Report(diag::err_fe_remap_missing_from_file) 167 << RemappedFiles[I].first; 168 delete RemappedFiles[I].second; 169 continue; 170 } 171 172 // Override the contents of the "from" file with the contents of 173 // the "to" file. 174 AST->getSourceManager().overrideFileContents(FromFile, 175 RemappedFiles[I].second); 176 } 177 178 // Gather Info for preprocessor construction later on. 179 180 LangOptions LangInfo; 181 HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); 182 std::string TargetTriple; 183 std::string Predefines; 184 unsigned Counter; 185 186 llvm::OwningPtr<PCHReader> Reader; 187 llvm::OwningPtr<ExternalASTSource> Source; 188 189 Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), 190 Diags)); 191 Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, 192 Predefines, Counter)); 193 194 switch (Reader->ReadPCH(Filename)) { 195 case PCHReader::Success: 196 break; 197 198 case PCHReader::Failure: 199 case PCHReader::IgnorePCH: 200 Diags.Report(diag::err_fe_unable_to_load_pch); 201 return NULL; 202 } 203 204 AST->OriginalSourceFile = Reader->getOriginalSourceFile(); 205 206 // PCH loaded successfully. Now create the preprocessor. 207 208 // Get information about the target being compiled for. 209 // 210 // FIXME: This is broken, we should store the TargetOptions in the PCH. 211 TargetOptions TargetOpts; 212 TargetOpts.ABI = ""; 213 TargetOpts.CPU = ""; 214 TargetOpts.Features.clear(); 215 TargetOpts.Triple = TargetTriple; 216 AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts)); 217 AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(), 218 AST->getSourceManager(), HeaderInfo)); 219 Preprocessor &PP = *AST->PP.get(); 220 221 PP.setPredefines(Reader->getSuggestedPredefines()); 222 PP.setCounterValue(Counter); 223 Reader->setPreprocessor(PP); 224 225 // Create and initialize the ASTContext. 226 227 AST->Ctx.reset(new ASTContext(LangInfo, 228 AST->getSourceManager(), 229 *AST->Target.get(), 230 PP.getIdentifierTable(), 231 PP.getSelectorTable(), 232 PP.getBuiltinInfo(), 233 /* FreeMemory = */ false, 234 /* size_reserve = */0)); 235 ASTContext &Context = *AST->Ctx.get(); 236 237 Reader->InitializeContext(Context); 238 239 // Attach the PCH reader to the AST context as an external AST 240 // source, so that declarations will be deserialized from the 241 // PCH file as needed. 242 Source.reset(Reader.take()); 243 Context.setExternalSource(Source); 244 245 return AST.take(); 246} 247 248namespace { 249 250class TopLevelDeclTrackerConsumer : public ASTConsumer { 251 ASTUnit &Unit; 252 253public: 254 TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {} 255 256 void HandleTopLevelDecl(DeclGroupRef D) { 257 for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) 258 Unit.getTopLevelDecls().push_back(*it); 259 } 260}; 261 262class TopLevelDeclTrackerAction : public ASTFrontendAction { 263public: 264 ASTUnit &Unit; 265 266 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 267 llvm::StringRef InFile) { 268 return new TopLevelDeclTrackerConsumer(Unit); 269 } 270 271public: 272 TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} 273 274 virtual bool hasCodeCompletionSupport() const { return false; } 275}; 276 277} 278 279ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, 280 Diagnostic &Diags, 281 bool OnlyLocalDecls, 282 bool CaptureDiagnostics) { 283 // Create the compiler instance to use for building the AST. 284 CompilerInstance Clang; 285 llvm::OwningPtr<ASTUnit> AST; 286 llvm::OwningPtr<TopLevelDeclTrackerAction> Act; 287 288 Clang.setInvocation(CI); 289 290 Clang.setDiagnostics(&Diags); 291 Clang.setDiagnosticClient(Diags.getClient()); 292 293 // Create the target instance. 294 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), 295 Clang.getTargetOpts())); 296 if (!Clang.hasTarget()) { 297 Clang.takeSourceManager(); 298 Clang.takeFileManager(); 299 Clang.takeDiagnosticClient(); 300 Clang.takeDiagnostics(); 301 return 0; 302 } 303 304 // Inform the target of the language options. 305 // 306 // FIXME: We shouldn't need to do this, the target should be immutable once 307 // created. This complexity should be lifted elsewhere. 308 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); 309 310 assert(Clang.getFrontendOpts().Inputs.size() == 1 && 311 "Invocation must have exactly one source file!"); 312 assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST && 313 "FIXME: AST inputs not yet supported here!"); 314 315 // Create the AST unit. 316 AST.reset(new ASTUnit(false)); 317 AST->OnlyLocalDecls = OnlyLocalDecls; 318 AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; 319 320 // Capture any diagnostics that would otherwise be dropped. 321 CaptureDroppedDiagnostics Capture(CaptureDiagnostics, 322 Clang.getDiagnostics(), 323 AST->Diagnostics); 324 325 // Create a file manager object to provide access to and cache the filesystem. 326 Clang.setFileManager(&AST->getFileManager()); 327 328 // Create the source manager. 329 Clang.setSourceManager(&AST->getSourceManager()); 330 331 // Create the preprocessor. 332 Clang.createPreprocessor(); 333 334 Act.reset(new TopLevelDeclTrackerAction(*AST)); 335 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, 336 /*IsAST=*/false)) 337 goto error; 338 339 Act->Execute(); 340 341 // Steal the created target, context, and preprocessor, and take back the 342 // source and file managers. 343 AST->Ctx.reset(Clang.takeASTContext()); 344 AST->PP.reset(Clang.takePreprocessor()); 345 Clang.takeSourceManager(); 346 Clang.takeFileManager(); 347 AST->Target.reset(Clang.takeTarget()); 348 349 Act->EndSourceFile(); 350 351 Clang.takeDiagnosticClient(); 352 Clang.takeDiagnostics(); 353 Clang.takeInvocation(); 354 355 AST->Invocation.reset(Clang.takeInvocation()); 356 return AST.take(); 357 358error: 359 Clang.takeSourceManager(); 360 Clang.takeFileManager(); 361 Clang.takeDiagnosticClient(); 362 Clang.takeDiagnostics(); 363 return 0; 364} 365 366ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, 367 const char **ArgEnd, 368 Diagnostic &Diags, 369 llvm::StringRef ResourceFilesPath, 370 bool OnlyLocalDecls, 371 RemappedFile *RemappedFiles, 372 unsigned NumRemappedFiles, 373 bool CaptureDiagnostics) { 374 llvm::SmallVector<const char *, 16> Args; 375 Args.push_back("<clang>"); // FIXME: Remove dummy argument. 376 Args.insert(Args.end(), ArgBegin, ArgEnd); 377 378 // FIXME: Find a cleaner way to force the driver into restricted modes. We 379 // also want to force it to use clang. 380 Args.push_back("-fsyntax-only"); 381 382 // FIXME: We shouldn't have to pass in the path info. 383 driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(), 384 "a.out", false, Diags); 385 386 // Don't check that inputs exist, they have been remapped. 387 TheDriver.setCheckInputsExist(false); 388 389 llvm::OwningPtr<driver::Compilation> C( 390 TheDriver.BuildCompilation(Args.size(), Args.data())); 391 392 // We expect to get back exactly one command job, if we didn't something 393 // failed. 394 const driver::JobList &Jobs = C->getJobs(); 395 if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { 396 llvm::SmallString<256> Msg; 397 llvm::raw_svector_ostream OS(Msg); 398 C->PrintJob(OS, C->getJobs(), "; ", true); 399 Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); 400 return 0; 401 } 402 403 const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); 404 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { 405 Diags.Report(diag::err_fe_expected_clang_command); 406 return 0; 407 } 408 409 const driver::ArgStringList &CCArgs = Cmd->getArguments(); 410 llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation); 411 CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(), 412 (const char**) CCArgs.data()+CCArgs.size(), 413 Diags); 414 415 // Override any files that need remapping 416 for (unsigned I = 0; I != NumRemappedFiles; ++I) 417 CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, 418 RemappedFiles[I].second); 419 420 // Override the resources path. 421 CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; 422 423 CI->getFrontendOpts().DisableFree = true; 424 return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls, 425 CaptureDiagnostics); 426} 427