13a08ec16SArgyrios Kyrtzidis //===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===// 23a08ec16SArgyrios Kyrtzidis // 33a08ec16SArgyrios Kyrtzidis // The LLVM Compiler Infrastructure 43a08ec16SArgyrios Kyrtzidis // 53a08ec16SArgyrios Kyrtzidis // This file is distributed under the University of Illinois Open Source 63a08ec16SArgyrios Kyrtzidis // License. See LICENSE.TXT for details. 73a08ec16SArgyrios Kyrtzidis // 83a08ec16SArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 93a08ec16SArgyrios Kyrtzidis // 103a08ec16SArgyrios Kyrtzidis // ASTUnit Implementation. 113a08ec16SArgyrios Kyrtzidis // 123a08ec16SArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 133a08ec16SArgyrios Kyrtzidis 14ce379752SArgyrios Kyrtzidis #include "clang/Frontend/ASTUnit.h" 15ce379752SArgyrios Kyrtzidis #include "clang/AST/ASTContext.h" 16764c0820SDaniel Dunbar #include "clang/AST/ASTConsumer.h" 17ce379752SArgyrios Kyrtzidis #include "clang/AST/DeclVisitor.h" 18b61c07acSDouglas Gregor #include "clang/AST/TypeOrdering.h" 19ce379752SArgyrios Kyrtzidis #include "clang/AST/StmtVisitor.h" 20764c0820SDaniel Dunbar #include "clang/Frontend/CompilerInstance.h" 21764c0820SDaniel Dunbar #include "clang/Frontend/FrontendActions.h" 2255a17b66SDaniel Dunbar #include "clang/Frontend/FrontendDiagnostic.h" 23764c0820SDaniel Dunbar #include "clang/Frontend/FrontendOptions.h" 24b11f5a4cSArgyrios Kyrtzidis #include "clang/Frontend/MultiplexConsumer.h" 2536e3b5c7SDouglas Gregor #include "clang/Frontend/Utils.h" 26f5b13467SSebastian Redl #include "clang/Serialization/ASTReader.h" 271914c6feSSebastian Redl #include "clang/Serialization/ASTWriter.h" 28ce379752SArgyrios Kyrtzidis #include "clang/Lex/HeaderSearch.h" 29ce379752SArgyrios Kyrtzidis #include "clang/Lex/Preprocessor.h" 30b9bbd54fSDaniel Dunbar #include "clang/Basic/TargetOptions.h" 31ce379752SArgyrios Kyrtzidis #include "clang/Basic/TargetInfo.h" 32ce379752SArgyrios Kyrtzidis #include "clang/Basic/Diagnostic.h" 33ce6c42f6SChris Lattner #include "llvm/ADT/ArrayRef.h" 34df7a79a9SDouglas Gregor #include "llvm/ADT/StringExtras.h" 3540a5a7deSDouglas Gregor #include "llvm/ADT/StringSet.h" 369aeaa4d6SDouglas Gregor #include "llvm/Support/Atomic.h" 37aa98ed9aSDouglas Gregor #include "llvm/Support/MemoryBuffer.h" 388aaf4995SMichael J. Spencer #include "llvm/Support/Host.h" 398aaf4995SMichael J. Spencer #include "llvm/Support/Path.h" 40028d3e4dSDouglas Gregor #include "llvm/Support/raw_ostream.h" 4115ba0b34SDouglas Gregor #include "llvm/Support/Timer.h" 4255e75574SArgyrios Kyrtzidis #include "llvm/Support/FileSystem.h" 43ebf01369SArgyrios Kyrtzidis #include "llvm/Support/Mutex.h" 44bd307a53STed Kremenek #include "llvm/Support/MutexGuard.h" 454422bfeaSTed Kremenek #include "llvm/Support/CrashRecoveryContext.h" 46be2d8c60SDouglas Gregor #include <cstdlib> 47318e4036SZhongxing Xu #include <cstdio> 480e11955cSDouglas Gregor #include <sys/stat.h> 49ce379752SArgyrios Kyrtzidis using namespace clang; 50ce379752SArgyrios Kyrtzidis 5116896c45SDouglas Gregor using llvm::TimeRecord; 5216896c45SDouglas Gregor 5316896c45SDouglas Gregor namespace { 5416896c45SDouglas Gregor class SimpleTimer { 5516896c45SDouglas Gregor bool WantTiming; 5616896c45SDouglas Gregor TimeRecord Start; 5716896c45SDouglas Gregor std::string Output; 5816896c45SDouglas Gregor 5916896c45SDouglas Gregor public: 601cbdd951SDouglas Gregor explicit SimpleTimer(bool WantTiming) : WantTiming(WantTiming) { 61f2e5a91fSBenjamin Kramer if (WantTiming) 6216896c45SDouglas Gregor Start = TimeRecord::getCurrentTime(); 6316896c45SDouglas Gregor } 6416896c45SDouglas Gregor 650e62c1ccSChris Lattner void setOutput(const Twine &Output) { 6616896c45SDouglas Gregor if (WantTiming) 6716896c45SDouglas Gregor this->Output = Output.str(); 6816896c45SDouglas Gregor } 6916896c45SDouglas Gregor 7016896c45SDouglas Gregor ~SimpleTimer() { 7116896c45SDouglas Gregor if (WantTiming) { 7216896c45SDouglas Gregor TimeRecord Elapsed = TimeRecord::getCurrentTime(); 7316896c45SDouglas Gregor Elapsed -= Start; 7416896c45SDouglas Gregor llvm::errs() << Output << ':'; 7516896c45SDouglas Gregor Elapsed.print(Elapsed, llvm::errs()); 7616896c45SDouglas Gregor llvm::errs() << '\n'; 7716896c45SDouglas Gregor } 7816896c45SDouglas Gregor } 7916896c45SDouglas Gregor }; 8006b4f919STed Kremenek 8106b4f919STed Kremenek struct OnDiskData { 8206b4f919STed Kremenek /// \brief The file in which the precompiled preamble is stored. 8306b4f919STed Kremenek std::string PreambleFile; 8406b4f919STed Kremenek 8506b4f919STed Kremenek /// \brief Temporary files that should be removed when the ASTUnit is 8606b4f919STed Kremenek /// destroyed. 8706b4f919STed Kremenek SmallVector<llvm::sys::Path, 4> TemporaryFiles; 8806b4f919STed Kremenek 8906b4f919STed Kremenek /// \brief Erase temporary files. 9006b4f919STed Kremenek void CleanTemporaryFiles(); 9106b4f919STed Kremenek 9206b4f919STed Kremenek /// \brief Erase the preamble file. 9306b4f919STed Kremenek void CleanPreambleFile(); 9406b4f919STed Kremenek 9506b4f919STed Kremenek /// \brief Erase temporary files and the preamble file. 9606b4f919STed Kremenek void Cleanup(); 9706b4f919STed Kremenek }; 9806b4f919STed Kremenek } 9906b4f919STed Kremenek 100bd307a53STed Kremenek static llvm::sys::SmartMutex<false> &getOnDiskMutex() { 101bd307a53STed Kremenek static llvm::sys::SmartMutex<false> M(/* recursive = */ true); 102bd307a53STed Kremenek return M; 103bd307a53STed Kremenek } 104bd307a53STed Kremenek 10506b4f919STed Kremenek static void cleanupOnDiskMapAtExit(void); 10606b4f919STed Kremenek 10706b4f919STed Kremenek typedef llvm::DenseMap<const ASTUnit *, OnDiskData *> OnDiskDataMap; 10806b4f919STed Kremenek static OnDiskDataMap &getOnDiskDataMap() { 10906b4f919STed Kremenek static OnDiskDataMap M; 11006b4f919STed Kremenek static bool hasRegisteredAtExit = false; 11106b4f919STed Kremenek if (!hasRegisteredAtExit) { 11206b4f919STed Kremenek hasRegisteredAtExit = true; 11306b4f919STed Kremenek atexit(cleanupOnDiskMapAtExit); 11406b4f919STed Kremenek } 11506b4f919STed Kremenek return M; 11606b4f919STed Kremenek } 11706b4f919STed Kremenek 11806b4f919STed Kremenek static void cleanupOnDiskMapAtExit(void) { 1194cf2ffe2SArgyrios Kyrtzidis // Use the mutex because there can be an alive thread destroying an ASTUnit. 1204cf2ffe2SArgyrios Kyrtzidis llvm::MutexGuard Guard(getOnDiskMutex()); 12106b4f919STed Kremenek OnDiskDataMap &M = getOnDiskDataMap(); 12206b4f919STed Kremenek for (OnDiskDataMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { 12306b4f919STed Kremenek // We don't worry about freeing the memory associated with OnDiskDataMap. 12406b4f919STed Kremenek // All we care about is erasing stale files. 12506b4f919STed Kremenek I->second->Cleanup(); 12606b4f919STed Kremenek } 12706b4f919STed Kremenek } 12806b4f919STed Kremenek 12906b4f919STed Kremenek static OnDiskData &getOnDiskData(const ASTUnit *AU) { 130bd307a53STed Kremenek // We require the mutex since we are modifying the structure of the 131bd307a53STed Kremenek // DenseMap. 132bd307a53STed Kremenek llvm::MutexGuard Guard(getOnDiskMutex()); 13306b4f919STed Kremenek OnDiskDataMap &M = getOnDiskDataMap(); 13406b4f919STed Kremenek OnDiskData *&D = M[AU]; 13506b4f919STed Kremenek if (!D) 13606b4f919STed Kremenek D = new OnDiskData(); 13706b4f919STed Kremenek return *D; 13806b4f919STed Kremenek } 13906b4f919STed Kremenek 14006b4f919STed Kremenek static void erasePreambleFile(const ASTUnit *AU) { 14106b4f919STed Kremenek getOnDiskData(AU).CleanPreambleFile(); 14206b4f919STed Kremenek } 14306b4f919STed Kremenek 14406b4f919STed Kremenek static void removeOnDiskEntry(const ASTUnit *AU) { 145bd307a53STed Kremenek // We require the mutex since we are modifying the structure of the 146bd307a53STed Kremenek // DenseMap. 147bd307a53STed Kremenek llvm::MutexGuard Guard(getOnDiskMutex()); 14806b4f919STed Kremenek OnDiskDataMap &M = getOnDiskDataMap(); 14906b4f919STed Kremenek OnDiskDataMap::iterator I = M.find(AU); 15006b4f919STed Kremenek if (I != M.end()) { 15106b4f919STed Kremenek I->second->Cleanup(); 15206b4f919STed Kremenek delete I->second; 15306b4f919STed Kremenek M.erase(AU); 15406b4f919STed Kremenek } 15506b4f919STed Kremenek } 15606b4f919STed Kremenek 15706b4f919STed Kremenek static void setPreambleFile(const ASTUnit *AU, llvm::StringRef preambleFile) { 15806b4f919STed Kremenek getOnDiskData(AU).PreambleFile = preambleFile; 15906b4f919STed Kremenek } 16006b4f919STed Kremenek 16106b4f919STed Kremenek static const std::string &getPreambleFile(const ASTUnit *AU) { 16206b4f919STed Kremenek return getOnDiskData(AU).PreambleFile; 16306b4f919STed Kremenek } 16406b4f919STed Kremenek 16506b4f919STed Kremenek void OnDiskData::CleanTemporaryFiles() { 16606b4f919STed Kremenek for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) 16706b4f919STed Kremenek TemporaryFiles[I].eraseFromDisk(); 16806b4f919STed Kremenek TemporaryFiles.clear(); 16906b4f919STed Kremenek } 17006b4f919STed Kremenek 17106b4f919STed Kremenek void OnDiskData::CleanPreambleFile() { 17206b4f919STed Kremenek if (!PreambleFile.empty()) { 17306b4f919STed Kremenek llvm::sys::Path(PreambleFile).eraseFromDisk(); 17406b4f919STed Kremenek PreambleFile.clear(); 17506b4f919STed Kremenek } 17606b4f919STed Kremenek } 17706b4f919STed Kremenek 17806b4f919STed Kremenek void OnDiskData::Cleanup() { 17906b4f919STed Kremenek CleanTemporaryFiles(); 18006b4f919STed Kremenek CleanPreambleFile(); 18106b4f919STed Kremenek } 18206b4f919STed Kremenek 183e54568d6SArgyrios Kyrtzidis void ASTUnit::clearFileLevelDecls() { 184e54568d6SArgyrios Kyrtzidis for (FileDeclsTy::iterator 185e54568d6SArgyrios Kyrtzidis I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I) 186e54568d6SArgyrios Kyrtzidis delete I->second; 187e54568d6SArgyrios Kyrtzidis FileDecls.clear(); 188e54568d6SArgyrios Kyrtzidis } 189e54568d6SArgyrios Kyrtzidis 19006b4f919STed Kremenek void ASTUnit::CleanTemporaryFiles() { 19106b4f919STed Kremenek getOnDiskData(this).CleanTemporaryFiles(); 19206b4f919STed Kremenek } 19306b4f919STed Kremenek 19406b4f919STed Kremenek void ASTUnit::addTemporaryFile(const llvm::sys::Path &TempFile) { 19506b4f919STed Kremenek getOnDiskData(this).TemporaryFiles.push_back(TempFile); 19616896c45SDouglas Gregor } 19716896c45SDouglas Gregor 198bb420abdSDouglas Gregor /// \brief After failing to build a precompiled preamble (due to 199bb420abdSDouglas Gregor /// errors in the source that occurs in the preamble), the number of 200bb420abdSDouglas Gregor /// reparses during which we'll skip even trying to precompile the 201bb420abdSDouglas Gregor /// preamble. 202bb420abdSDouglas Gregor const unsigned DefaultPreambleRebuildInterval = 5; 203bb420abdSDouglas Gregor 20468dbaeadSDouglas Gregor /// \brief Tracks the number of ASTUnit objects that are currently active. 20568dbaeadSDouglas Gregor /// 20668dbaeadSDouglas Gregor /// Used for debugging purposes only. 2079aeaa4d6SDouglas Gregor static llvm::sys::cas_flag ActiveASTUnitObjects; 20868dbaeadSDouglas Gregor 209d03e823fSDouglas Gregor ASTUnit::ASTUnit(bool _MainFileIsAST) 210244ce8b2SArgyrios Kyrtzidis : Reader(0), OnlyLocalDecls(false), CaptureDiagnostics(false), 21135dcda79SArgyrios Kyrtzidis MainFileIsAST(_MainFileIsAST), 21269f74f80SDouglas Gregor TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")), 2134954bc1dSArgyrios Kyrtzidis OwnsRemappedFileBuffers(true), 21416896c45SDouglas Gregor NumStoredDiagnosticsFromDriver(0), 215a0734c5fSDouglas Gregor PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), 21685b4a37dSArgyrios Kyrtzidis NumWarningsInPreamble(0), 2172c8bd47aSDouglas Gregor ShouldCacheCodeCompletionResults(false), 2186d7833f1SArgyrios Kyrtzidis IncludeBriefCommentsInCodeCompletion(false), UserFilesAreVolatile(false), 219df7a79a9SDouglas Gregor CompletionCacheTopLevelHashValue(0), 220df7a79a9SDouglas Gregor PreambleTopLevelHashValue(0), 221df7a79a9SDouglas Gregor CurrentTopLevelHashValue(0), 2224740c450SDouglas Gregor UnsafeToFree(false) { 22368dbaeadSDouglas Gregor if (getenv("LIBCLANG_OBJTRACKING")) { 2249aeaa4d6SDouglas Gregor llvm::sys::AtomicIncrement(&ActiveASTUnitObjects); 22568dbaeadSDouglas Gregor fprintf(stderr, "+++ %d translation units\n", ActiveASTUnitObjects); 22668dbaeadSDouglas Gregor } 22715ba0b34SDouglas Gregor } 228d03e823fSDouglas Gregor 22944cd60eeSSteve Naroff ASTUnit::~ASTUnit() { 230e54568d6SArgyrios Kyrtzidis clearFileLevelDecls(); 231e54568d6SArgyrios Kyrtzidis 23206b4f919STed Kremenek // Clean up the temporary files and the preamble file. 23306b4f919STed Kremenek removeOnDiskEntry(this); 2343f4bea06SDouglas Gregor 2353f4bea06SDouglas Gregor // Free the buffers associated with remapped files. We are required to 2363f4bea06SDouglas Gregor // perform this operation here because we explicitly request that the 2373f4bea06SDouglas Gregor // compiler instance *not* free these buffers for each invocation of the 2383f4bea06SDouglas Gregor // parser. 2395e14d39aSTed Kremenek if (Invocation.getPtr() && OwnsRemappedFileBuffers) { 2403f4bea06SDouglas Gregor PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); 2413f4bea06SDouglas Gregor for (PreprocessorOptions::remapped_file_buffer_iterator 2423f4bea06SDouglas Gregor FB = PPOpts.remapped_file_buffer_begin(), 2433f4bea06SDouglas Gregor FBEnd = PPOpts.remapped_file_buffer_end(); 2443f4bea06SDouglas Gregor FB != FBEnd; 2453f4bea06SDouglas Gregor ++FB) 2463f4bea06SDouglas Gregor delete FB->second; 2473f4bea06SDouglas Gregor } 24896c04261SDouglas Gregor 24996c04261SDouglas Gregor delete SavedMainFileBuffer; 250a0734c5fSDouglas Gregor delete PreambleBuffer; 25115ba0b34SDouglas Gregor 252b14904c4SDouglas Gregor ClearCachedCompletionResults(); 25368dbaeadSDouglas Gregor 25468dbaeadSDouglas Gregor if (getenv("LIBCLANG_OBJTRACKING")) { 2559aeaa4d6SDouglas Gregor llvm::sys::AtomicDecrement(&ActiveASTUnitObjects); 25668dbaeadSDouglas Gregor fprintf(stderr, "--- %d translation units\n", ActiveASTUnitObjects); 25768dbaeadSDouglas Gregor } 258aa21cc40SDouglas Gregor } 259aa21cc40SDouglas Gregor 260da6e0547SArgyrios Kyrtzidis void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; } 261da6e0547SArgyrios Kyrtzidis 26239982197SDouglas Gregor /// \brief Determine the set of code-completion contexts in which this 26339982197SDouglas Gregor /// declaration should be shown. 26439982197SDouglas Gregor static unsigned getDeclShowContexts(NamedDecl *ND, 26559cab556SDouglas Gregor const LangOptions &LangOpts, 26659cab556SDouglas Gregor bool &IsNestedNameSpecifier) { 26759cab556SDouglas Gregor IsNestedNameSpecifier = false; 26859cab556SDouglas Gregor 26939982197SDouglas Gregor if (isa<UsingShadowDecl>(ND)) 27039982197SDouglas Gregor ND = dyn_cast<NamedDecl>(ND->getUnderlyingDecl()); 27139982197SDouglas Gregor if (!ND) 27239982197SDouglas Gregor return 0; 27339982197SDouglas Gregor 274697cc9e6SRichard Smith uint64_t Contexts = 0; 27539982197SDouglas Gregor if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) || 27639982197SDouglas Gregor isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) { 27739982197SDouglas Gregor // Types can appear in these contexts. 27839982197SDouglas Gregor if (LangOpts.CPlusPlus || !isa<TagDecl>(ND)) 279697cc9e6SRichard Smith Contexts |= (1LL << CodeCompletionContext::CCC_TopLevel) 280697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCIvarList) 281697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ClassStructUnion) 282697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Statement) 283697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Type) 284697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression); 28539982197SDouglas Gregor 28639982197SDouglas Gregor // In C++, types can appear in expressions contexts (for functional casts). 28739982197SDouglas Gregor if (LangOpts.CPlusPlus) 288697cc9e6SRichard Smith Contexts |= (1LL << CodeCompletionContext::CCC_Expression); 28939982197SDouglas Gregor 29039982197SDouglas Gregor // In Objective-C, message sends can send interfaces. In Objective-C++, 29139982197SDouglas Gregor // all types are available due to functional casts. 29239982197SDouglas Gregor if (LangOpts.CPlusPlus || isa<ObjCInterfaceDecl>(ND)) 293697cc9e6SRichard Smith Contexts |= (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver); 29439982197SDouglas Gregor 2952132584dSDouglas Gregor // In Objective-C, you can only be a subclass of another Objective-C class 2962132584dSDouglas Gregor if (isa<ObjCInterfaceDecl>(ND)) 297697cc9e6SRichard Smith Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName); 2982132584dSDouglas Gregor 29939982197SDouglas Gregor // Deal with tag names. 30039982197SDouglas Gregor if (isa<EnumDecl>(ND)) { 301697cc9e6SRichard Smith Contexts |= (1LL << CodeCompletionContext::CCC_EnumTag); 30239982197SDouglas Gregor 30359cab556SDouglas Gregor // Part of the nested-name-specifier in C++0x. 30439982197SDouglas Gregor if (LangOpts.CPlusPlus0x) 30559cab556SDouglas Gregor IsNestedNameSpecifier = true; 30639982197SDouglas Gregor } else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) { 30739982197SDouglas Gregor if (Record->isUnion()) 308697cc9e6SRichard Smith Contexts |= (1LL << CodeCompletionContext::CCC_UnionTag); 30939982197SDouglas Gregor else 310697cc9e6SRichard Smith Contexts |= (1LL << CodeCompletionContext::CCC_ClassOrStructTag); 31139982197SDouglas Gregor 31239982197SDouglas Gregor if (LangOpts.CPlusPlus) 31359cab556SDouglas Gregor IsNestedNameSpecifier = true; 3140ac41389SDouglas Gregor } else if (isa<ClassTemplateDecl>(ND)) 31559cab556SDouglas Gregor IsNestedNameSpecifier = true; 31639982197SDouglas Gregor } else if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) { 31739982197SDouglas Gregor // Values can appear in these contexts. 318697cc9e6SRichard Smith Contexts = (1LL << CodeCompletionContext::CCC_Statement) 319697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Expression) 320697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) 321697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver); 32239982197SDouglas Gregor } else if (isa<ObjCProtocolDecl>(ND)) { 323697cc9e6SRichard Smith Contexts = (1LL << CodeCompletionContext::CCC_ObjCProtocolName); 3242132584dSDouglas Gregor } else if (isa<ObjCCategoryDecl>(ND)) { 325697cc9e6SRichard Smith Contexts = (1LL << CodeCompletionContext::CCC_ObjCCategoryName); 32639982197SDouglas Gregor } else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) { 327697cc9e6SRichard Smith Contexts = (1LL << CodeCompletionContext::CCC_Namespace); 32839982197SDouglas Gregor 32939982197SDouglas Gregor // Part of the nested-name-specifier. 33059cab556SDouglas Gregor IsNestedNameSpecifier = true; 33139982197SDouglas Gregor } 33239982197SDouglas Gregor 33339982197SDouglas Gregor return Contexts; 33439982197SDouglas Gregor } 33539982197SDouglas Gregor 336b14904c4SDouglas Gregor void ASTUnit::CacheCodeCompletionResults() { 337b14904c4SDouglas Gregor if (!TheSema) 338b14904c4SDouglas Gregor return; 339b14904c4SDouglas Gregor 34016896c45SDouglas Gregor SimpleTimer Timer(WantTiming); 34116896c45SDouglas Gregor Timer.setOutput("Cache global code completions for " + getMainFileName()); 342b14904c4SDouglas Gregor 343b14904c4SDouglas Gregor // Clear out the previous results. 344b14904c4SDouglas Gregor ClearCachedCompletionResults(); 345b14904c4SDouglas Gregor 346b14904c4SDouglas Gregor // Gather the set of global code completions. 347276321a9SJohn McCall typedef CodeCompletionResult Result; 3480e62c1ccSChris Lattner SmallVector<Result, 8> Results; 349162b712dSDouglas Gregor CachedCompletionAllocator = new GlobalCodeCompletionAllocator; 3509d7c0fefSArgyrios Kyrtzidis TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, 3519d7c0fefSArgyrios Kyrtzidis getCodeCompletionTUInfo(), Results); 352b14904c4SDouglas Gregor 353b14904c4SDouglas Gregor // Translate global code completions into cached completions. 354b61c07acSDouglas Gregor llvm::DenseMap<CanQualType, unsigned> CompletionTypes; 355b61c07acSDouglas Gregor 356b14904c4SDouglas Gregor for (unsigned I = 0, N = Results.size(); I != N; ++I) { 357b14904c4SDouglas Gregor switch (Results[I].Kind) { 35839982197SDouglas Gregor case Result::RK_Declaration: { 35959cab556SDouglas Gregor bool IsNestedNameSpecifier = false; 36039982197SDouglas Gregor CachedCodeCompletionResult CachedResult; 361b278aafbSDouglas Gregor CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, 3629d7c0fefSArgyrios Kyrtzidis *CachedCompletionAllocator, 3633292d06aSDmitri Gribenko getCodeCompletionTUInfo(), 3643292d06aSDmitri Gribenko IncludeBriefCommentsInCodeCompletion); 36539982197SDouglas Gregor CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, 366bbafb8a7SDavid Blaikie Ctx->getLangOpts(), 36759cab556SDouglas Gregor IsNestedNameSpecifier); 36839982197SDouglas Gregor CachedResult.Priority = Results[I].Priority; 36939982197SDouglas Gregor CachedResult.Kind = Results[I].CursorKind; 370f757a12dSDouglas Gregor CachedResult.Availability = Results[I].Availability; 37124747408SDouglas Gregor 372b61c07acSDouglas Gregor // Keep track of the type of this completion in an ASTContext-agnostic 373b61c07acSDouglas Gregor // way. 37424747408SDouglas Gregor QualType UsageType = getDeclUsageType(*Ctx, Results[I].Declaration); 375b61c07acSDouglas Gregor if (UsageType.isNull()) { 37624747408SDouglas Gregor CachedResult.TypeClass = STC_Void; 377b61c07acSDouglas Gregor CachedResult.Type = 0; 378b61c07acSDouglas Gregor } else { 379b61c07acSDouglas Gregor CanQualType CanUsageType 380b61c07acSDouglas Gregor = Ctx->getCanonicalType(UsageType.getUnqualifiedType()); 381b61c07acSDouglas Gregor CachedResult.TypeClass = getSimplifiedTypeClass(CanUsageType); 382b61c07acSDouglas Gregor 383b61c07acSDouglas Gregor // Determine whether we have already seen this type. If so, we save 384b61c07acSDouglas Gregor // ourselves the work of formatting the type string by using the 385b61c07acSDouglas Gregor // temporary, CanQualType-based hash table to find the associated value. 386b61c07acSDouglas Gregor unsigned &TypeValue = CompletionTypes[CanUsageType]; 387b61c07acSDouglas Gregor if (TypeValue == 0) { 388b61c07acSDouglas Gregor TypeValue = CompletionTypes.size(); 389b61c07acSDouglas Gregor CachedCompletionTypes[QualType(CanUsageType).getAsString()] 390b61c07acSDouglas Gregor = TypeValue; 39124747408SDouglas Gregor } 392b61c07acSDouglas Gregor 393b61c07acSDouglas Gregor CachedResult.Type = TypeValue; 394b61c07acSDouglas Gregor } 395b61c07acSDouglas Gregor 39639982197SDouglas Gregor CachedCompletionResults.push_back(CachedResult); 39759cab556SDouglas Gregor 39859cab556SDouglas Gregor /// Handle nested-name-specifiers in C++. 399bbafb8a7SDavid Blaikie if (TheSema->Context.getLangOpts().CPlusPlus && 40059cab556SDouglas Gregor IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) { 40159cab556SDouglas Gregor // The contexts in which a nested-name-specifier can appear in C++. 402697cc9e6SRichard Smith uint64_t NNSContexts 403697cc9e6SRichard Smith = (1LL << CodeCompletionContext::CCC_TopLevel) 404697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCIvarList) 405697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ClassStructUnion) 406697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Statement) 407697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Expression) 408697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) 409697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_EnumTag) 410697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_UnionTag) 411697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ClassOrStructTag) 412697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Type) 413697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_PotentiallyQualifiedName) 414697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression); 41559cab556SDouglas Gregor 41659cab556SDouglas Gregor if (isa<NamespaceDecl>(Results[I].Declaration) || 41759cab556SDouglas Gregor isa<NamespaceAliasDecl>(Results[I].Declaration)) 418697cc9e6SRichard Smith NNSContexts |= (1LL << CodeCompletionContext::CCC_Namespace); 41959cab556SDouglas Gregor 42059cab556SDouglas Gregor if (unsigned RemainingContexts 42159cab556SDouglas Gregor = NNSContexts & ~CachedResult.ShowInContexts) { 42259cab556SDouglas Gregor // If there any contexts where this completion can be a 42359cab556SDouglas Gregor // nested-name-specifier but isn't already an option, create a 42459cab556SDouglas Gregor // nested-name-specifier completion. 42559cab556SDouglas Gregor Results[I].StartsNestedNameSpecifier = true; 426b278aafbSDouglas Gregor CachedResult.Completion 427b278aafbSDouglas Gregor = Results[I].CreateCodeCompletionString(*TheSema, 4289d7c0fefSArgyrios Kyrtzidis *CachedCompletionAllocator, 4293292d06aSDmitri Gribenko getCodeCompletionTUInfo(), 4303292d06aSDmitri Gribenko IncludeBriefCommentsInCodeCompletion); 43159cab556SDouglas Gregor CachedResult.ShowInContexts = RemainingContexts; 43259cab556SDouglas Gregor CachedResult.Priority = CCP_NestedNameSpecifier; 43359cab556SDouglas Gregor CachedResult.TypeClass = STC_Void; 43459cab556SDouglas Gregor CachedResult.Type = 0; 43559cab556SDouglas Gregor CachedCompletionResults.push_back(CachedResult); 43659cab556SDouglas Gregor } 43759cab556SDouglas Gregor } 438b14904c4SDouglas Gregor break; 43939982197SDouglas Gregor } 440b14904c4SDouglas Gregor 441b14904c4SDouglas Gregor case Result::RK_Keyword: 442b14904c4SDouglas Gregor case Result::RK_Pattern: 443b14904c4SDouglas Gregor // Ignore keywords and patterns; we don't care, since they are so 444b14904c4SDouglas Gregor // easily regenerated. 445b14904c4SDouglas Gregor break; 446b14904c4SDouglas Gregor 447b14904c4SDouglas Gregor case Result::RK_Macro: { 448b14904c4SDouglas Gregor CachedCodeCompletionResult CachedResult; 449b278aafbSDouglas Gregor CachedResult.Completion 450b278aafbSDouglas Gregor = Results[I].CreateCodeCompletionString(*TheSema, 4519d7c0fefSArgyrios Kyrtzidis *CachedCompletionAllocator, 4523292d06aSDmitri Gribenko getCodeCompletionTUInfo(), 4533292d06aSDmitri Gribenko IncludeBriefCommentsInCodeCompletion); 454b14904c4SDouglas Gregor CachedResult.ShowInContexts 455697cc9e6SRichard Smith = (1LL << CodeCompletionContext::CCC_TopLevel) 456697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCInterface) 457697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCImplementation) 458697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCIvarList) 459697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ClassStructUnion) 460697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Statement) 461697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Expression) 462697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) 463697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_MacroNameUse) 464697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_PreprocessorExpression) 465697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) 466697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_OtherWithMacros); 467c49f5b2fSDouglas Gregor 468b14904c4SDouglas Gregor CachedResult.Priority = Results[I].Priority; 469b14904c4SDouglas Gregor CachedResult.Kind = Results[I].CursorKind; 470f757a12dSDouglas Gregor CachedResult.Availability = Results[I].Availability; 4716e24033bSDouglas Gregor CachedResult.TypeClass = STC_Void; 472b61c07acSDouglas Gregor CachedResult.Type = 0; 473b14904c4SDouglas Gregor CachedCompletionResults.push_back(CachedResult); 474b14904c4SDouglas Gregor break; 475b14904c4SDouglas Gregor } 476b14904c4SDouglas Gregor } 477b14904c4SDouglas Gregor } 478b14904c4SDouglas Gregor 479df7a79a9SDouglas Gregor // Save the current top-level hash value. 480df7a79a9SDouglas Gregor CompletionCacheTopLevelHashValue = CurrentTopLevelHashValue; 481b14904c4SDouglas Gregor } 482b14904c4SDouglas Gregor 483b14904c4SDouglas Gregor void ASTUnit::ClearCachedCompletionResults() { 484b14904c4SDouglas Gregor CachedCompletionResults.clear(); 485b61c07acSDouglas Gregor CachedCompletionTypes.clear(); 486162b712dSDouglas Gregor CachedCompletionAllocator = 0; 487b14904c4SDouglas Gregor } 488b14904c4SDouglas Gregor 489ce379752SArgyrios Kyrtzidis namespace { 490ce379752SArgyrios Kyrtzidis 4912c499f65SSebastian Redl /// \brief Gathers information from ASTReader that will be used to initialize 492ce379752SArgyrios Kyrtzidis /// a Preprocessor. 493d44cd6adSSebastian Redl class ASTInfoCollector : public ASTReaderListener { 49483297dfcSDouglas Gregor Preprocessor &PP; 495e8bbc121SDouglas Gregor ASTContext &Context; 496ce379752SArgyrios Kyrtzidis LangOptions &LangOpt; 497ce379752SArgyrios Kyrtzidis HeaderSearch &HSI; 498c95d8192SDylan Noblesmith IntrusiveRefCntPtr<TargetInfo> &Target; 499ce379752SArgyrios Kyrtzidis std::string &Predefines; 500ce379752SArgyrios Kyrtzidis unsigned &Counter; 501ce379752SArgyrios Kyrtzidis 502ce379752SArgyrios Kyrtzidis unsigned NumHeaderInfos; 503ce379752SArgyrios Kyrtzidis 504e8bbc121SDouglas Gregor bool InitializedLanguage; 505ce379752SArgyrios Kyrtzidis public: 506e8bbc121SDouglas Gregor ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt, 507e8bbc121SDouglas Gregor HeaderSearch &HSI, 508c95d8192SDylan Noblesmith IntrusiveRefCntPtr<TargetInfo> &Target, 50983297dfcSDouglas Gregor std::string &Predefines, 510ce379752SArgyrios Kyrtzidis unsigned &Counter) 511e8bbc121SDouglas Gregor : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target), 51283297dfcSDouglas Gregor Predefines(Predefines), Counter(Counter), NumHeaderInfos(0), 513e8bbc121SDouglas Gregor InitializedLanguage(false) {} 514ce379752SArgyrios Kyrtzidis 515ce379752SArgyrios Kyrtzidis virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { 516e8bbc121SDouglas Gregor if (InitializedLanguage) 51783297dfcSDouglas Gregor return false; 51883297dfcSDouglas Gregor 519ce379752SArgyrios Kyrtzidis LangOpt = LangOpts; 52083297dfcSDouglas Gregor 52183297dfcSDouglas Gregor // Initialize the preprocessor. 52283297dfcSDouglas Gregor PP.Initialize(*Target); 523e8bbc121SDouglas Gregor 524e8bbc121SDouglas Gregor // Initialize the ASTContext 525e8bbc121SDouglas Gregor Context.InitBuiltinTypes(*Target); 526e8bbc121SDouglas Gregor 527e8bbc121SDouglas Gregor InitializedLanguage = true; 5289e1fb563SArgyrios Kyrtzidis 5299e1fb563SArgyrios Kyrtzidis applyLangOptsToTarget(); 530ce379752SArgyrios Kyrtzidis return false; 531ce379752SArgyrios Kyrtzidis } 532ce379752SArgyrios Kyrtzidis 5330e62c1ccSChris Lattner virtual bool ReadTargetTriple(StringRef Triple) { 53483297dfcSDouglas Gregor // If we've already initialized the target, don't do it again. 53583297dfcSDouglas Gregor if (Target) 53683297dfcSDouglas Gregor return false; 53783297dfcSDouglas Gregor 53883297dfcSDouglas Gregor // FIXME: This is broken, we should store the TargetOptions in the AST file. 53983297dfcSDouglas Gregor TargetOptions TargetOpts; 54083297dfcSDouglas Gregor TargetOpts.ABI = ""; 54183297dfcSDouglas Gregor TargetOpts.CXXABI = ""; 54283297dfcSDouglas Gregor TargetOpts.CPU = ""; 54383297dfcSDouglas Gregor TargetOpts.Features.clear(); 54483297dfcSDouglas Gregor TargetOpts.Triple = Triple; 54583297dfcSDouglas Gregor Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts); 5469e1fb563SArgyrios Kyrtzidis 5479e1fb563SArgyrios Kyrtzidis applyLangOptsToTarget(); 548ce379752SArgyrios Kyrtzidis return false; 549ce379752SArgyrios Kyrtzidis } 550ce379752SArgyrios Kyrtzidis 5518b41f300SSebastian Redl virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, 5520e62c1ccSChris Lattner StringRef OriginalFileName, 55336079898SNick Lewycky std::string &SuggestedPredefines, 55436079898SNick Lewycky FileManager &FileMgr) { 5558b41f300SSebastian Redl Predefines = Buffers[0].Data; 5568b41f300SSebastian Redl for (unsigned I = 1, N = Buffers.size(); I != N; ++I) { 5578b41f300SSebastian Redl Predefines += Buffers[I].Data; 5588b41f300SSebastian Redl } 559ce379752SArgyrios Kyrtzidis return false; 560ce379752SArgyrios Kyrtzidis } 561ce379752SArgyrios Kyrtzidis 562a2f49450SDouglas Gregor virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) { 563ce379752SArgyrios Kyrtzidis HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); 564ce379752SArgyrios Kyrtzidis } 565ce379752SArgyrios Kyrtzidis 566ce379752SArgyrios Kyrtzidis virtual void ReadCounter(unsigned Value) { 567ce379752SArgyrios Kyrtzidis Counter = Value; 568ce379752SArgyrios Kyrtzidis } 5699e1fb563SArgyrios Kyrtzidis 5709e1fb563SArgyrios Kyrtzidis private: 5719e1fb563SArgyrios Kyrtzidis void applyLangOptsToTarget() { 5729e1fb563SArgyrios Kyrtzidis if (Target && InitializedLanguage) { 5739e1fb563SArgyrios Kyrtzidis // Inform the target of the language options. 5749e1fb563SArgyrios Kyrtzidis // 5759e1fb563SArgyrios Kyrtzidis // FIXME: We shouldn't need to do this, the target should be immutable once 5769e1fb563SArgyrios Kyrtzidis // created. This complexity should be lifted elsewhere. 5779e1fb563SArgyrios Kyrtzidis Target->setForcedLangOptions(LangOpt); 5789e1fb563SArgyrios Kyrtzidis } 5799e1fb563SArgyrios Kyrtzidis } 580ce379752SArgyrios Kyrtzidis }; 581ce379752SArgyrios Kyrtzidis 582f18d91a4SDavid Blaikie class StoredDiagnosticConsumer : public DiagnosticConsumer { 5830e62c1ccSChris Lattner SmallVectorImpl<StoredDiagnostic> &StoredDiags; 58433cdd810SDouglas Gregor 58533cdd810SDouglas Gregor public: 586f18d91a4SDavid Blaikie explicit StoredDiagnosticConsumer( 5870e62c1ccSChris Lattner SmallVectorImpl<StoredDiagnostic> &StoredDiags) 58833cdd810SDouglas Gregor : StoredDiags(StoredDiags) { } 58933cdd810SDouglas Gregor 5909c902b55SDavid Blaikie virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, 591b5784324SDavid Blaikie const Diagnostic &Info); 592d0e9e3a6SDouglas Gregor 593d0e9e3a6SDouglas Gregor DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { 594d0e9e3a6SDouglas Gregor // Just drop any diagnostics that come from cloned consumers; they'll 595d0e9e3a6SDouglas Gregor // have different source managers anyway. 596e1fbde55SDouglas Gregor // FIXME: We'd like to be able to capture these somehow, even if it's just 597e1fbde55SDouglas Gregor // file/line/column, because they could occur when parsing module maps or 598e1fbde55SDouglas Gregor // building modules on-demand. 599d0e9e3a6SDouglas Gregor return new IgnoringDiagConsumer(); 600d0e9e3a6SDouglas Gregor } 60133cdd810SDouglas Gregor }; 60233cdd810SDouglas Gregor 60333cdd810SDouglas Gregor /// \brief RAII object that optionally captures diagnostics, if 60433cdd810SDouglas Gregor /// there is no diagnostic client to capture them already. 60533cdd810SDouglas Gregor class CaptureDroppedDiagnostics { 6069c902b55SDavid Blaikie DiagnosticsEngine &Diags; 607f18d91a4SDavid Blaikie StoredDiagnosticConsumer Client; 608e2eefaecSDavid Blaikie DiagnosticConsumer *PreviousClient; 60933cdd810SDouglas Gregor 61033cdd810SDouglas Gregor public: 6119c902b55SDavid Blaikie CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags, 6120e62c1ccSChris Lattner SmallVectorImpl<StoredDiagnostic> &StoredDiags) 6132dd19f1dSDouglas Gregor : Diags(Diags), Client(StoredDiags), PreviousClient(0) 61433cdd810SDouglas Gregor { 6152dd19f1dSDouglas Gregor if (RequestCapture || Diags.getClient() == 0) { 6162dd19f1dSDouglas Gregor PreviousClient = Diags.takeClient(); 61733cdd810SDouglas Gregor Diags.setClient(&Client); 61833cdd810SDouglas Gregor } 6192dd19f1dSDouglas Gregor } 62033cdd810SDouglas Gregor 62133cdd810SDouglas Gregor ~CaptureDroppedDiagnostics() { 6222dd19f1dSDouglas Gregor if (Diags.getClient() == &Client) { 6232dd19f1dSDouglas Gregor Diags.takeClient(); 62433cdd810SDouglas Gregor Diags.setClient(PreviousClient); 62533cdd810SDouglas Gregor } 6262dd19f1dSDouglas Gregor } 62733cdd810SDouglas Gregor }; 62833cdd810SDouglas Gregor 629ce379752SArgyrios Kyrtzidis } // anonymous namespace 630ce379752SArgyrios Kyrtzidis 631f18d91a4SDavid Blaikie void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, 632b5784324SDavid Blaikie const Diagnostic &Info) { 633c79346a5SArgyrios Kyrtzidis // Default implementation (Warnings/errors count). 634e2eefaecSDavid Blaikie DiagnosticConsumer::HandleDiagnostic(Level, Info); 635c79346a5SArgyrios Kyrtzidis 63633cdd810SDouglas Gregor StoredDiags.push_back(StoredDiagnostic(Level, Info)); 63733cdd810SDouglas Gregor } 63833cdd810SDouglas Gregor 639c0683b90SSteve Naroff const std::string &ASTUnit::getOriginalSourceFileName() { 640a8a50937SDaniel Dunbar return OriginalSourceFile; 641c0683b90SSteve Naroff } 642ce379752SArgyrios Kyrtzidis 6430e62c1ccSChris Lattner llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename, 64426b5c190SChris Lattner std::string *ErrorStr) { 6455159f616SChris Lattner assert(FileMgr); 64626b5c190SChris Lattner return FileMgr->getBufferForFile(Filename, ErrorStr); 64771731d6bSArgyrios Kyrtzidis } 64871731d6bSArgyrios Kyrtzidis 64944c6ee77SDouglas Gregor /// \brief Configure the diagnostics object for use with ASTUnit. 650c95d8192SDylan Noblesmith void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, 651345c1bcbSDouglas Gregor const char **ArgBegin, const char **ArgEnd, 65244c6ee77SDouglas Gregor ASTUnit &AST, bool CaptureDiagnostics) { 65344c6ee77SDouglas Gregor if (!Diags.getPtr()) { 65444c6ee77SDouglas Gregor // No diagnostics engine was provided, so create our own diagnostics object 65544c6ee77SDouglas Gregor // with the default options. 65644c6ee77SDouglas Gregor DiagnosticOptions DiagOpts; 657e2eefaecSDavid Blaikie DiagnosticConsumer *Client = 0; 65844c6ee77SDouglas Gregor if (CaptureDiagnostics) 659f18d91a4SDavid Blaikie Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); 660345c1bcbSDouglas Gregor Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin, 661ffe7c7f4SBenjamin Kramer ArgBegin, Client, 662ffe7c7f4SBenjamin Kramer /*ShouldOwnClient=*/true, 663ffe7c7f4SBenjamin Kramer /*ShouldCloneClient=*/false); 66444c6ee77SDouglas Gregor } else if (CaptureDiagnostics) { 665f18d91a4SDavid Blaikie Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); 66644c6ee77SDouglas Gregor } 66744c6ee77SDouglas Gregor } 66844c6ee77SDouglas Gregor 669d44cd6adSSebastian Redl ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, 670c95d8192SDylan Noblesmith IntrusiveRefCntPtr<DiagnosticsEngine> Diags, 67171731d6bSArgyrios Kyrtzidis const FileSystemOptions &FileSystemOpts, 6728bcb1c68STed Kremenek bool OnlyLocalDecls, 673aa98ed9aSDouglas Gregor RemappedFile *RemappedFiles, 67433cdd810SDouglas Gregor unsigned NumRemappedFiles, 6754a280ff4SArgyrios Kyrtzidis bool CaptureDiagnostics, 6766d7833f1SArgyrios Kyrtzidis bool AllowPCHWithCompilerErrors, 6776d7833f1SArgyrios Kyrtzidis bool UserFilesAreVolatile) { 678e2778999SDylan Noblesmith OwningPtr<ASTUnit> AST(new ASTUnit(true)); 6794422bfeaSTed Kremenek 6804422bfeaSTed Kremenek // Recover resources if we crash before exiting this method. 681022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> 682022a4904STed Kremenek ASTUnitCleanup(AST.get()); 6839c902b55SDavid Blaikie llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, 6849c902b55SDavid Blaikie llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > 685022a4904STed Kremenek DiagCleanup(Diags.getPtr()); 6864422bfeaSTed Kremenek 687345c1bcbSDouglas Gregor ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); 688d03e823fSDouglas Gregor 68916bef857SDouglas Gregor AST->OnlyLocalDecls = OnlyLocalDecls; 69044c6ee77SDouglas Gregor AST->CaptureDiagnostics = CaptureDiagnostics; 6917f95d26eSDouglas Gregor AST->Diagnostics = Diags; 6925e14d39aSTed Kremenek AST->FileMgr = new FileManager(FileSystemOpts); 6936d7833f1SArgyrios Kyrtzidis AST->UserFilesAreVolatile = UserFilesAreVolatile; 6945e14d39aSTed Kremenek AST->SourceMgr = new SourceManager(AST->getDiagnostics(), 6956d7833f1SArgyrios Kyrtzidis AST->getFileManager(), 6966d7833f1SArgyrios Kyrtzidis UserFilesAreVolatile); 697197ac203SDouglas Gregor AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(), 6981fb5c3a6SDouglas Gregor AST->getDiagnostics(), 69989929282SDouglas Gregor AST->ASTFileLangOpts, 70089929282SDouglas Gregor /*Target=*/0)); 701ce379752SArgyrios Kyrtzidis 702aa98ed9aSDouglas Gregor for (unsigned I = 0; I != NumRemappedFiles; ++I) { 70311e6f0a6SArgyrios Kyrtzidis FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; 70411e6f0a6SArgyrios Kyrtzidis if (const llvm::MemoryBuffer * 70511e6f0a6SArgyrios Kyrtzidis memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { 706aa98ed9aSDouglas Gregor // Create the file entry for the file that we're mapping from. 707aa98ed9aSDouglas Gregor const FileEntry *FromFile 708aa98ed9aSDouglas Gregor = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, 70911e6f0a6SArgyrios Kyrtzidis memBuf->getBufferSize(), 7105159f616SChris Lattner 0); 711aa98ed9aSDouglas Gregor if (!FromFile) { 712d03e823fSDouglas Gregor AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) 713aa98ed9aSDouglas Gregor << RemappedFiles[I].first; 71411e6f0a6SArgyrios Kyrtzidis delete memBuf; 715aa98ed9aSDouglas Gregor continue; 716aa98ed9aSDouglas Gregor } 717aa98ed9aSDouglas Gregor 718aa98ed9aSDouglas Gregor // Override the contents of the "from" file with the contents of 719aa98ed9aSDouglas Gregor // the "to" file. 72011e6f0a6SArgyrios Kyrtzidis AST->getSourceManager().overrideFileContents(FromFile, memBuf); 72111e6f0a6SArgyrios Kyrtzidis 72211e6f0a6SArgyrios Kyrtzidis } else { 72311e6f0a6SArgyrios Kyrtzidis const char *fname = fileOrBuf.get<const char *>(); 72411e6f0a6SArgyrios Kyrtzidis const FileEntry *ToFile = AST->FileMgr->getFile(fname); 72511e6f0a6SArgyrios Kyrtzidis if (!ToFile) { 72611e6f0a6SArgyrios Kyrtzidis AST->getDiagnostics().Report(diag::err_fe_remap_missing_to_file) 72711e6f0a6SArgyrios Kyrtzidis << RemappedFiles[I].first << fname; 72811e6f0a6SArgyrios Kyrtzidis continue; 72911e6f0a6SArgyrios Kyrtzidis } 73011e6f0a6SArgyrios Kyrtzidis 73111e6f0a6SArgyrios Kyrtzidis // Create the file entry for the file that we're mapping from. 73211e6f0a6SArgyrios Kyrtzidis const FileEntry *FromFile 73311e6f0a6SArgyrios Kyrtzidis = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, 73411e6f0a6SArgyrios Kyrtzidis ToFile->getSize(), 73511e6f0a6SArgyrios Kyrtzidis 0); 73611e6f0a6SArgyrios Kyrtzidis if (!FromFile) { 73711e6f0a6SArgyrios Kyrtzidis AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) 73811e6f0a6SArgyrios Kyrtzidis << RemappedFiles[I].first; 73911e6f0a6SArgyrios Kyrtzidis delete memBuf; 74011e6f0a6SArgyrios Kyrtzidis continue; 74111e6f0a6SArgyrios Kyrtzidis } 74211e6f0a6SArgyrios Kyrtzidis 74311e6f0a6SArgyrios Kyrtzidis // Override the contents of the "from" file with the contents of 74411e6f0a6SArgyrios Kyrtzidis // the "to" file. 74511e6f0a6SArgyrios Kyrtzidis AST->getSourceManager().overrideFileContents(FromFile, ToFile); 74611e6f0a6SArgyrios Kyrtzidis } 747aa98ed9aSDouglas Gregor } 748aa98ed9aSDouglas Gregor 749ce379752SArgyrios Kyrtzidis // Gather Info for preprocessor construction later on. 750ce379752SArgyrios Kyrtzidis 751ce379752SArgyrios Kyrtzidis HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); 752ce379752SArgyrios Kyrtzidis std::string Predefines; 753ce379752SArgyrios Kyrtzidis unsigned Counter; 754ce379752SArgyrios Kyrtzidis 755e2778999SDylan Noblesmith OwningPtr<ASTReader> Reader; 756ce379752SArgyrios Kyrtzidis 75783297dfcSDouglas Gregor AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts, 75883297dfcSDouglas Gregor /*Target=*/0, AST->getSourceManager(), HeaderInfo, 75983297dfcSDouglas Gregor *AST, 76083297dfcSDouglas Gregor /*IILookup=*/0, 76183297dfcSDouglas Gregor /*OwnsHeaderSearch=*/false, 76283297dfcSDouglas Gregor /*DelayInitialization=*/true); 763e8bbc121SDouglas Gregor Preprocessor &PP = *AST->PP; 764e8bbc121SDouglas Gregor 765e8bbc121SDouglas Gregor AST->Ctx = new ASTContext(AST->ASTFileLangOpts, 766e8bbc121SDouglas Gregor AST->getSourceManager(), 767e8bbc121SDouglas Gregor /*Target=*/0, 768e8bbc121SDouglas Gregor PP.getIdentifierTable(), 769e8bbc121SDouglas Gregor PP.getSelectorTable(), 770e8bbc121SDouglas Gregor PP.getBuiltinInfo(), 771e8bbc121SDouglas Gregor /* size_reserve = */0, 772e8bbc121SDouglas Gregor /*DelayInitialization=*/true); 773e8bbc121SDouglas Gregor ASTContext &Context = *AST->Ctx; 77483297dfcSDouglas Gregor 775945a8193SArgyrios Kyrtzidis bool disableValid = false; 776945a8193SArgyrios Kyrtzidis if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION")) 777945a8193SArgyrios Kyrtzidis disableValid = true; 7784a280ff4SArgyrios Kyrtzidis Reader.reset(new ASTReader(PP, Context, 7794a280ff4SArgyrios Kyrtzidis /*isysroot=*/"", 780945a8193SArgyrios Kyrtzidis /*DisableValidation=*/disableValid, 7814a280ff4SArgyrios Kyrtzidis /*DisableStatCache=*/false, 7824a280ff4SArgyrios Kyrtzidis AllowPCHWithCompilerErrors)); 7832159b8d2STed Kremenek 7842159b8d2STed Kremenek // Recover resources if we crash before exiting this method. 7852159b8d2STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<ASTReader> 7862159b8d2STed Kremenek ReaderCleanup(Reader.get()); 7872159b8d2STed Kremenek 788e8bbc121SDouglas Gregor Reader->setListener(new ASTInfoCollector(*AST->PP, Context, 78983297dfcSDouglas Gregor AST->ASTFileLangOpts, HeaderInfo, 79083297dfcSDouglas Gregor AST->Target, Predefines, Counter)); 7912d9c740cSDaniel Dunbar 792a6895d8aSDouglas Gregor switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) { 7932c499f65SSebastian Redl case ASTReader::Success: 794ce379752SArgyrios Kyrtzidis break; 795ce379752SArgyrios Kyrtzidis 7962c499f65SSebastian Redl case ASTReader::Failure: 7972c499f65SSebastian Redl case ASTReader::IgnorePCH: 798d03e823fSDouglas Gregor AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch); 799ce379752SArgyrios Kyrtzidis return NULL; 800ce379752SArgyrios Kyrtzidis } 801ce379752SArgyrios Kyrtzidis 802a8a50937SDaniel Dunbar AST->OriginalSourceFile = Reader->getOriginalSourceFile(); 803a8a50937SDaniel Dunbar 804b7bbfdd9SDaniel Dunbar PP.setPredefines(Reader->getSuggestedPredefines()); 805ce379752SArgyrios Kyrtzidis PP.setCounterValue(Counter); 806ce379752SArgyrios Kyrtzidis 8072c499f65SSebastian Redl // Attach the AST reader to the AST context as an external AST 808ce379752SArgyrios Kyrtzidis // source, so that declarations will be deserialized from the 809d44cd6adSSebastian Redl // AST file as needed. 8102c499f65SSebastian Redl ASTReader *ReaderPtr = Reader.get(); 811e2778999SDylan Noblesmith OwningPtr<ExternalASTSource> Source(Reader.take()); 8122159b8d2STed Kremenek 8132159b8d2STed Kremenek // Unregister the cleanup for ASTReader. It will get cleaned up 8142159b8d2STed Kremenek // by the ASTUnit cleanup. 8152159b8d2STed Kremenek ReaderCleanup.unregister(); 8162159b8d2STed Kremenek 817ce379752SArgyrios Kyrtzidis Context.setExternalSource(Source); 818ce379752SArgyrios Kyrtzidis 8196fd55e06SDouglas Gregor // Create an AST consumer, even though it isn't used. 8206fd55e06SDouglas Gregor AST->Consumer.reset(new ASTConsumer); 8216fd55e06SDouglas Gregor 8222c499f65SSebastian Redl // Create a semantic analysis object and tell the AST reader about it. 8236fd55e06SDouglas Gregor AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer)); 8246fd55e06SDouglas Gregor AST->TheSema->Initialize(); 8256fd55e06SDouglas Gregor ReaderPtr->InitializeSema(*AST->TheSema); 826244ce8b2SArgyrios Kyrtzidis AST->Reader = ReaderPtr; 8276fd55e06SDouglas Gregor 828ce379752SArgyrios Kyrtzidis return AST.take(); 829ce379752SArgyrios Kyrtzidis } 830764c0820SDaniel Dunbar 831764c0820SDaniel Dunbar namespace { 832764c0820SDaniel Dunbar 833df7a79a9SDouglas Gregor /// \brief Preprocessor callback class that updates a hash value with the names 834df7a79a9SDouglas Gregor /// of all macros that have been defined by the translation unit. 835df7a79a9SDouglas Gregor class MacroDefinitionTrackerPPCallbacks : public PPCallbacks { 836df7a79a9SDouglas Gregor unsigned &Hash; 837644dca07SDaniel Dunbar 838644dca07SDaniel Dunbar public: 839df7a79a9SDouglas Gregor explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { } 840df7a79a9SDouglas Gregor 841df7a79a9SDouglas Gregor virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { 842df7a79a9SDouglas Gregor Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); 843df7a79a9SDouglas Gregor } 844df7a79a9SDouglas Gregor }; 845df7a79a9SDouglas Gregor 846df7a79a9SDouglas Gregor /// \brief Add the given declaration to the hash of all top-level entities. 847df7a79a9SDouglas Gregor void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) { 848df7a79a9SDouglas Gregor if (!D) 849df7a79a9SDouglas Gregor return; 850df7a79a9SDouglas Gregor 851df7a79a9SDouglas Gregor DeclContext *DC = D->getDeclContext(); 852df7a79a9SDouglas Gregor if (!DC) 853df7a79a9SDouglas Gregor return; 854df7a79a9SDouglas Gregor 855df7a79a9SDouglas Gregor if (!(DC->isTranslationUnit() || DC->getLookupParent()->isTranslationUnit())) 856df7a79a9SDouglas Gregor return; 857df7a79a9SDouglas Gregor 858df7a79a9SDouglas Gregor if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { 859df7a79a9SDouglas Gregor if (ND->getIdentifier()) 860df7a79a9SDouglas Gregor Hash = llvm::HashString(ND->getIdentifier()->getName(), Hash); 861df7a79a9SDouglas Gregor else if (DeclarationName Name = ND->getDeclName()) { 862df7a79a9SDouglas Gregor std::string NameStr = Name.getAsString(); 863df7a79a9SDouglas Gregor Hash = llvm::HashString(NameStr, Hash); 864df7a79a9SDouglas Gregor } 865df7a79a9SDouglas Gregor return; 866df7a79a9SDouglas Gregor } 867df7a79a9SDouglas Gregor } 868df7a79a9SDouglas Gregor 869df7a79a9SDouglas Gregor class TopLevelDeclTrackerConsumer : public ASTConsumer { 870df7a79a9SDouglas Gregor ASTUnit &Unit; 871df7a79a9SDouglas Gregor unsigned &Hash; 872df7a79a9SDouglas Gregor 873df7a79a9SDouglas Gregor public: 874df7a79a9SDouglas Gregor TopLevelDeclTrackerConsumer(ASTUnit &_Unit, unsigned &Hash) 875df7a79a9SDouglas Gregor : Unit(_Unit), Hash(Hash) { 876df7a79a9SDouglas Gregor Hash = 0; 877df7a79a9SDouglas Gregor } 878644dca07SDaniel Dunbar 879e54568d6SArgyrios Kyrtzidis void handleTopLevelDecl(Decl *D) { 880516eec2dSArgyrios Kyrtzidis if (!D) 881516eec2dSArgyrios Kyrtzidis return; 882516eec2dSArgyrios Kyrtzidis 883acc59c3eSTed Kremenek // FIXME: Currently ObjC method declarations are incorrectly being 884acc59c3eSTed Kremenek // reported as top-level declarations, even though their DeclContext 885acc59c3eSTed Kremenek // is the containing ObjC @interface/@implementation. This is a 886acc59c3eSTed Kremenek // fundamental problem in the parser right now. 887acc59c3eSTed Kremenek if (isa<ObjCMethodDecl>(D)) 888e54568d6SArgyrios Kyrtzidis return; 889df7a79a9SDouglas Gregor 890df7a79a9SDouglas Gregor AddTopLevelDeclarationToHash(D, Hash); 891e9db88f9SDouglas Gregor Unit.addTopLevelDecl(D); 892e54568d6SArgyrios Kyrtzidis 893e54568d6SArgyrios Kyrtzidis handleFileLevelDecl(D); 894acc59c3eSTed Kremenek } 895e54568d6SArgyrios Kyrtzidis 896e54568d6SArgyrios Kyrtzidis void handleFileLevelDecl(Decl *D) { 897e54568d6SArgyrios Kyrtzidis Unit.addFileLevelDecl(D); 898e54568d6SArgyrios Kyrtzidis if (NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(D)) { 899e54568d6SArgyrios Kyrtzidis for (NamespaceDecl::decl_iterator 900e54568d6SArgyrios Kyrtzidis I = NSD->decls_begin(), E = NSD->decls_end(); I != E; ++I) 901e54568d6SArgyrios Kyrtzidis handleFileLevelDecl(*I); 902e54568d6SArgyrios Kyrtzidis } 903e54568d6SArgyrios Kyrtzidis } 904e54568d6SArgyrios Kyrtzidis 905841dd886SArgyrios Kyrtzidis bool HandleTopLevelDecl(DeclGroupRef D) { 906e54568d6SArgyrios Kyrtzidis for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) 907e54568d6SArgyrios Kyrtzidis handleTopLevelDecl(*it); 908841dd886SArgyrios Kyrtzidis return true; 909644dca07SDaniel Dunbar } 910eaa4ade8SSebastian Redl 911eaa4ade8SSebastian Redl // We're not interested in "interesting" decls. 912eaa4ade8SSebastian Redl void HandleInterestingDecl(DeclGroupRef) {} 913e54568d6SArgyrios Kyrtzidis 914e54568d6SArgyrios Kyrtzidis void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) { 915e54568d6SArgyrios Kyrtzidis for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) 916e54568d6SArgyrios Kyrtzidis handleTopLevelDecl(*it); 917e54568d6SArgyrios Kyrtzidis } 918644dca07SDaniel Dunbar }; 919644dca07SDaniel Dunbar 920644dca07SDaniel Dunbar class TopLevelDeclTrackerAction : public ASTFrontendAction { 921644dca07SDaniel Dunbar public: 922644dca07SDaniel Dunbar ASTUnit &Unit; 923644dca07SDaniel Dunbar 924764c0820SDaniel Dunbar virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 9250e62c1ccSChris Lattner StringRef InFile) { 926df7a79a9SDouglas Gregor CI.getPreprocessor().addPPCallbacks( 927df7a79a9SDouglas Gregor new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); 928df7a79a9SDouglas Gregor return new TopLevelDeclTrackerConsumer(Unit, 929df7a79a9SDouglas Gregor Unit.getCurrentTopLevelHashValue()); 930764c0820SDaniel Dunbar } 931764c0820SDaniel Dunbar 932764c0820SDaniel Dunbar public: 933644dca07SDaniel Dunbar TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} 934644dca07SDaniel Dunbar 935764c0820SDaniel Dunbar virtual bool hasCodeCompletionSupport() const { return false; } 93669f74f80SDouglas Gregor virtual TranslationUnitKind getTranslationUnitKind() { 93769f74f80SDouglas Gregor return Unit.getTranslationUnitKind(); 938028d3e4dSDouglas Gregor } 939764c0820SDaniel Dunbar }; 940764c0820SDaniel Dunbar 94157332719SArgyrios Kyrtzidis class PrecompilePreambleConsumer : public PCHGenerator { 94248c8cd3fSDouglas Gregor ASTUnit &Unit; 943df7a79a9SDouglas Gregor unsigned &Hash; 944e9db88f9SDouglas Gregor std::vector<Decl *> TopLevelDecls; 94548c8cd3fSDouglas Gregor 94648c8cd3fSDouglas Gregor public: 94736db4f96SDouglas Gregor PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP, 9480e62c1ccSChris Lattner StringRef isysroot, raw_ostream *Out) 949f7a700fdSDouglas Gregor : PCHGenerator(PP, "", 0, isysroot, Out), Unit(Unit), 950df7a79a9SDouglas Gregor Hash(Unit.getCurrentTopLevelHashValue()) { 951df7a79a9SDouglas Gregor Hash = 0; 952df7a79a9SDouglas Gregor } 95348c8cd3fSDouglas Gregor 954841dd886SArgyrios Kyrtzidis virtual bool HandleTopLevelDecl(DeclGroupRef D) { 95548c8cd3fSDouglas Gregor for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) { 95648c8cd3fSDouglas Gregor Decl *D = *it; 95748c8cd3fSDouglas Gregor // FIXME: Currently ObjC method declarations are incorrectly being 95848c8cd3fSDouglas Gregor // reported as top-level declarations, even though their DeclContext 95948c8cd3fSDouglas Gregor // is the containing ObjC @interface/@implementation. This is a 96048c8cd3fSDouglas Gregor // fundamental problem in the parser right now. 96148c8cd3fSDouglas Gregor if (isa<ObjCMethodDecl>(D)) 96248c8cd3fSDouglas Gregor continue; 963df7a79a9SDouglas Gregor AddTopLevelDeclarationToHash(D, Hash); 964e9db88f9SDouglas Gregor TopLevelDecls.push_back(D); 965e9db88f9SDouglas Gregor } 966841dd886SArgyrios Kyrtzidis return true; 967e9db88f9SDouglas Gregor } 968e9db88f9SDouglas Gregor 969e9db88f9SDouglas Gregor virtual void HandleTranslationUnit(ASTContext &Ctx) { 970e9db88f9SDouglas Gregor PCHGenerator::HandleTranslationUnit(Ctx); 971e9db88f9SDouglas Gregor if (!Unit.getDiagnostics().hasErrorOccurred()) { 972e9db88f9SDouglas Gregor // Translate the top-level declarations we captured during 973e9db88f9SDouglas Gregor // parsing into declaration IDs in the precompiled 974e9db88f9SDouglas Gregor // preamble. This will allow us to deserialize those top-level 975e9db88f9SDouglas Gregor // declarations when requested. 976e9db88f9SDouglas Gregor for (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I) 977e9db88f9SDouglas Gregor Unit.addTopLevelDeclFromPreamble( 978e9db88f9SDouglas Gregor getWriter().getDeclID(TopLevelDecls[I])); 97948c8cd3fSDouglas Gregor } 98048c8cd3fSDouglas Gregor } 98148c8cd3fSDouglas Gregor }; 98248c8cd3fSDouglas Gregor 98348c8cd3fSDouglas Gregor class PrecompilePreambleAction : public ASTFrontendAction { 98448c8cd3fSDouglas Gregor ASTUnit &Unit; 98548c8cd3fSDouglas Gregor 98648c8cd3fSDouglas Gregor public: 98748c8cd3fSDouglas Gregor explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {} 98848c8cd3fSDouglas Gregor 98948c8cd3fSDouglas Gregor virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 9900e62c1ccSChris Lattner StringRef InFile) { 99148c8cd3fSDouglas Gregor std::string Sysroot; 99210b2368eSArgyrios Kyrtzidis std::string OutputFile; 9930e62c1ccSChris Lattner raw_ostream *OS = 0; 99448c8cd3fSDouglas Gregor if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, 99510b2368eSArgyrios Kyrtzidis OutputFile, 99636db4f96SDouglas Gregor OS)) 99748c8cd3fSDouglas Gregor return 0; 99848c8cd3fSDouglas Gregor 999c567ba26SDouglas Gregor if (!CI.getFrontendOpts().RelocatablePCH) 1000c567ba26SDouglas Gregor Sysroot.clear(); 1001c567ba26SDouglas Gregor 1002df7a79a9SDouglas Gregor CI.getPreprocessor().addPPCallbacks( 1003df7a79a9SDouglas Gregor new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); 100436db4f96SDouglas Gregor return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Sysroot, 100536db4f96SDouglas Gregor OS); 100648c8cd3fSDouglas Gregor } 100748c8cd3fSDouglas Gregor 100848c8cd3fSDouglas Gregor virtual bool hasCodeCompletionSupport() const { return false; } 100948c8cd3fSDouglas Gregor virtual bool hasASTFileSupport() const { return false; } 101069f74f80SDouglas Gregor virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; } 101148c8cd3fSDouglas Gregor }; 101248c8cd3fSDouglas Gregor 1013764c0820SDaniel Dunbar } 1014764c0820SDaniel Dunbar 101538bacf34SArgyrios Kyrtzidis static void checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> & 101638bacf34SArgyrios Kyrtzidis StoredDiagnostics) { 101738bacf34SArgyrios Kyrtzidis // Get rid of stored diagnostics except the ones from the driver which do not 101838bacf34SArgyrios Kyrtzidis // have a source location. 101938bacf34SArgyrios Kyrtzidis for (unsigned I = 0; I < StoredDiagnostics.size(); ++I) { 102038bacf34SArgyrios Kyrtzidis if (StoredDiagnostics[I].getLocation().isValid()) { 102138bacf34SArgyrios Kyrtzidis StoredDiagnostics.erase(StoredDiagnostics.begin()+I); 102238bacf34SArgyrios Kyrtzidis --I; 102338bacf34SArgyrios Kyrtzidis } 102438bacf34SArgyrios Kyrtzidis } 102538bacf34SArgyrios Kyrtzidis } 102638bacf34SArgyrios Kyrtzidis 102738bacf34SArgyrios Kyrtzidis static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> & 102838bacf34SArgyrios Kyrtzidis StoredDiagnostics, 102938bacf34SArgyrios Kyrtzidis SourceManager &SM) { 103038bacf34SArgyrios Kyrtzidis // The stored diagnostic has the old source manager in it; update 103138bacf34SArgyrios Kyrtzidis // the locations to refer into the new source manager. Since we've 103238bacf34SArgyrios Kyrtzidis // been careful to make sure that the source manager's state 103338bacf34SArgyrios Kyrtzidis // before and after are identical, so that we can reuse the source 103438bacf34SArgyrios Kyrtzidis // location itself. 103538bacf34SArgyrios Kyrtzidis for (unsigned I = 0, N = StoredDiagnostics.size(); I < N; ++I) { 103638bacf34SArgyrios Kyrtzidis if (StoredDiagnostics[I].getLocation().isValid()) { 103738bacf34SArgyrios Kyrtzidis FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SM); 103838bacf34SArgyrios Kyrtzidis StoredDiagnostics[I].setLocation(Loc); 103938bacf34SArgyrios Kyrtzidis } 104038bacf34SArgyrios Kyrtzidis } 104138bacf34SArgyrios Kyrtzidis } 104238bacf34SArgyrios Kyrtzidis 1043aa21cc40SDouglas Gregor /// Parse the source file into a translation unit using the given compiler 1044aa21cc40SDouglas Gregor /// invocation, replacing the current translation unit. 1045aa21cc40SDouglas Gregor /// 1046aa21cc40SDouglas Gregor /// \returns True if a failure occurred that causes the ASTUnit not to 1047aa21cc40SDouglas Gregor /// contain any translation-unit information, false otherwise. 10486481ef1fSDouglas Gregor bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { 104996c04261SDouglas Gregor delete SavedMainFileBuffer; 105096c04261SDouglas Gregor SavedMainFileBuffer = 0; 105196c04261SDouglas Gregor 10525e14d39aSTed Kremenek if (!Invocation) { 1053a0734c5fSDouglas Gregor delete OverrideMainBuffer; 1054aa21cc40SDouglas Gregor return true; 1055a0734c5fSDouglas Gregor } 1056aa21cc40SDouglas Gregor 1057764c0820SDaniel Dunbar // Create the compiler instance to use for building the AST. 1058e2778999SDylan Noblesmith OwningPtr<CompilerInstance> Clang(new CompilerInstance()); 105984de4a17STed Kremenek 106084de4a17STed Kremenek // Recover resources if we crash before exiting this method. 1061022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> 1062022a4904STed Kremenek CICleanup(Clang.get()); 106384de4a17STed Kremenek 1064c95d8192SDylan Noblesmith IntrusiveRefCntPtr<CompilerInvocation> 106514c32e88SArgyrios Kyrtzidis CCInvocation(new CompilerInvocation(*Invocation)); 106614c32e88SArgyrios Kyrtzidis 106714c32e88SArgyrios Kyrtzidis Clang->setInvocation(CCInvocation.getPtr()); 106832fbe312SDouglas Gregor OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; 1069764c0820SDaniel Dunbar 10708e984da8SDouglas Gregor // Set up diagnostics, capturing any diagnostics that would 10718e984da8SDouglas Gregor // otherwise be dropped. 107284de4a17STed Kremenek Clang->setDiagnostics(&getDiagnostics()); 1073764c0820SDaniel Dunbar 1074764c0820SDaniel Dunbar // Create the target instance. 107584de4a17STed Kremenek Clang->getTargetOpts().Features = TargetFeatures; 107684de4a17STed Kremenek Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), 107784de4a17STed Kremenek Clang->getTargetOpts())); 107884de4a17STed Kremenek if (!Clang->hasTarget()) { 1079a0734c5fSDouglas Gregor delete OverrideMainBuffer; 1080aa21cc40SDouglas Gregor return true; 1081a0734c5fSDouglas Gregor } 1082764c0820SDaniel Dunbar 1083764c0820SDaniel Dunbar // Inform the target of the language options. 1084764c0820SDaniel Dunbar // 1085764c0820SDaniel Dunbar // FIXME: We shouldn't need to do this, the target should be immutable once 1086764c0820SDaniel Dunbar // created. This complexity should be lifted elsewhere. 108784de4a17STed Kremenek Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); 1088764c0820SDaniel Dunbar 108984de4a17STed Kremenek assert(Clang->getFrontendOpts().Inputs.size() == 1 && 1090764c0820SDaniel Dunbar "Invocation must have exactly one source file!"); 109132fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && 1092764c0820SDaniel Dunbar "FIXME: AST inputs not yet supported here!"); 109332fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && 10949507f9ccSDaniel Dunbar "IR inputs not support here!"); 1095764c0820SDaniel Dunbar 1096aa21cc40SDouglas Gregor // Configure the various subsystems. 1097aa21cc40SDouglas Gregor // FIXME: Should we retain the previous file manager? 10988cf47df7STed Kremenek LangOpts = &Clang->getLangOpts(); 109984de4a17STed Kremenek FileSystemOpts = Clang->getFileSystemOpts(); 11005e14d39aSTed Kremenek FileMgr = new FileManager(FileSystemOpts); 11016d7833f1SArgyrios Kyrtzidis SourceMgr = new SourceManager(getDiagnostics(), *FileMgr, 11026d7833f1SArgyrios Kyrtzidis UserFilesAreVolatile); 11036fd55e06SDouglas Gregor TheSema.reset(); 11045e14d39aSTed Kremenek Ctx = 0; 11055e14d39aSTed Kremenek PP = 0; 1106244ce8b2SArgyrios Kyrtzidis Reader = 0; 1107aa21cc40SDouglas Gregor 1108aa21cc40SDouglas Gregor // Clear out old caches and data. 1109aa21cc40SDouglas Gregor TopLevelDecls.clear(); 1110e54568d6SArgyrios Kyrtzidis clearFileLevelDecls(); 1111aa21cc40SDouglas Gregor CleanTemporaryFiles(); 1112a8a50937SDaniel Dunbar 11137b02b583SDouglas Gregor if (!OverrideMainBuffer) { 111438bacf34SArgyrios Kyrtzidis checkAndRemoveNonDriverDiags(StoredDiagnostics); 11157b02b583SDouglas Gregor TopLevelDeclsInPreamble.clear(); 11167b02b583SDouglas Gregor } 1117d9a30af2SDouglas Gregor 1118764c0820SDaniel Dunbar // Create a file manager object to provide access to and cache the filesystem. 111984de4a17STed Kremenek Clang->setFileManager(&getFileManager()); 1120764c0820SDaniel Dunbar 1121764c0820SDaniel Dunbar // Create the source manager. 112284de4a17STed Kremenek Clang->setSourceManager(&getSourceManager()); 1123764c0820SDaniel Dunbar 11243f4bea06SDouglas Gregor // If the main file has been overridden due to the use of a preamble, 11253f4bea06SDouglas Gregor // make that override happen and introduce the preamble. 112684de4a17STed Kremenek PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); 11273f4bea06SDouglas Gregor if (OverrideMainBuffer) { 11283f4bea06SDouglas Gregor PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); 11293f4bea06SDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); 11303f4bea06SDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.second 11313f4bea06SDouglas Gregor = PreambleEndsAtStartOfLine; 113206b4f919STed Kremenek PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); 1133ce3a8293SDouglas Gregor PreprocessorOpts.DisablePCHValidation = true; 113496c04261SDouglas Gregor 1135d9a30af2SDouglas Gregor // The stored diagnostic has the old source manager in it; update 1136d9a30af2SDouglas Gregor // the locations to refer into the new source manager. Since we've 1137d9a30af2SDouglas Gregor // been careful to make sure that the source manager's state 1138d9a30af2SDouglas Gregor // before and after are identical, so that we can reuse the source 1139d9a30af2SDouglas Gregor // location itself. 114038bacf34SArgyrios Kyrtzidis checkAndSanitizeDiags(StoredDiagnostics, getSourceManager()); 11417bb8af61SDouglas Gregor 11427bb8af61SDouglas Gregor // Keep track of the override buffer; 11437bb8af61SDouglas Gregor SavedMainFileBuffer = OverrideMainBuffer; 11443f4bea06SDouglas Gregor } 11453f4bea06SDouglas Gregor 1146e2778999SDylan Noblesmith OwningPtr<TopLevelDeclTrackerAction> Act( 1147022a4904STed Kremenek new TopLevelDeclTrackerAction(*this)); 1148022a4904STed Kremenek 1149022a4904STed Kremenek // Recover resources if we crash before exiting this method. 1150022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction> 1151022a4904STed Kremenek ActCleanup(Act.get()); 1152022a4904STed Kremenek 115332fbe312SDouglas Gregor if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) 1154764c0820SDaniel Dunbar goto error; 1155764c0820SDaniel Dunbar 1156925296b4SDouglas Gregor if (OverrideMainBuffer) { 115706b4f919STed Kremenek std::string ModName = getPreambleFile(this); 1158925296b4SDouglas Gregor TranslateStoredDiagnostics(Clang->getModuleManager(), ModName, 1159925296b4SDouglas Gregor getSourceManager(), PreambleDiagnostics, 1160925296b4SDouglas Gregor StoredDiagnostics); 1161925296b4SDouglas Gregor } 1162925296b4SDouglas Gregor 11631416e17cSArgyrios Kyrtzidis if (!Act->Execute()) 11641416e17cSArgyrios Kyrtzidis goto error; 1165764c0820SDaniel Dunbar 1166ac1cc934SArgyrios Kyrtzidis transferASTDataFromCompilerInstance(*Clang); 1167764c0820SDaniel Dunbar 1168644dca07SDaniel Dunbar Act->EndSourceFile(); 1169764c0820SDaniel Dunbar 1170ac1cc934SArgyrios Kyrtzidis FailedParseDiagnostics.clear(); 1171ac1cc934SArgyrios Kyrtzidis 1172aa21cc40SDouglas Gregor return false; 1173764c0820SDaniel Dunbar 1174764c0820SDaniel Dunbar error: 11753f4bea06SDouglas Gregor // Remove the overridden buffer we used for the preamble. 1176ce3a8293SDouglas Gregor if (OverrideMainBuffer) { 1177a0734c5fSDouglas Gregor delete OverrideMainBuffer; 1178a3d3ba1cSDouglas Gregor SavedMainFileBuffer = 0; 1179ce3a8293SDouglas Gregor } 11803f4bea06SDouglas Gregor 1181ac1cc934SArgyrios Kyrtzidis // Keep the ownership of the data in the ASTUnit because the client may 1182ac1cc934SArgyrios Kyrtzidis // want to see the diagnostics. 1183ac1cc934SArgyrios Kyrtzidis transferASTDataFromCompilerInstance(*Clang); 1184ac1cc934SArgyrios Kyrtzidis FailedParseDiagnostics.swap(StoredDiagnostics); 1185efc46958SDouglas Gregor StoredDiagnostics.clear(); 1186067cbfa2SArgyrios Kyrtzidis NumStoredDiagnosticsFromDriver = 0; 1187aa21cc40SDouglas Gregor return true; 1188aa21cc40SDouglas Gregor } 1189aa21cc40SDouglas Gregor 1190be2d8c60SDouglas Gregor /// \brief Simple function to retrieve a path for a preamble precompiled header. 1191be2d8c60SDouglas Gregor static std::string GetPreamblePCHPath() { 1192be2d8c60SDouglas Gregor // FIXME: This is lame; sys::Path should provide this function (in particular, 1193be2d8c60SDouglas Gregor // it should know how to find the temporary files dir). 1194be2d8c60SDouglas Gregor // FIXME: This is really lame. I copied this code from the Driver! 1195250ab1dcSDouglas Gregor // FIXME: This is a hack so that we can override the preamble file during 1196250ab1dcSDouglas Gregor // crash-recovery testing, which is the only case where the preamble files 1197250ab1dcSDouglas Gregor // are not necessarily cleaned up. 1198250ab1dcSDouglas Gregor const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); 1199250ab1dcSDouglas Gregor if (TmpFile) 1200250ab1dcSDouglas Gregor return TmpFile; 1201250ab1dcSDouglas Gregor 1202be2d8c60SDouglas Gregor std::string Error; 1203be2d8c60SDouglas Gregor const char *TmpDir = ::getenv("TMPDIR"); 1204be2d8c60SDouglas Gregor if (!TmpDir) 1205be2d8c60SDouglas Gregor TmpDir = ::getenv("TEMP"); 1206be2d8c60SDouglas Gregor if (!TmpDir) 1207be2d8c60SDouglas Gregor TmpDir = ::getenv("TMP"); 1208ce3449f5SDouglas Gregor #ifdef LLVM_ON_WIN32 1209ce3449f5SDouglas Gregor if (!TmpDir) 1210ce3449f5SDouglas Gregor TmpDir = ::getenv("USERPROFILE"); 1211ce3449f5SDouglas Gregor #endif 1212be2d8c60SDouglas Gregor if (!TmpDir) 1213be2d8c60SDouglas Gregor TmpDir = "/tmp"; 1214be2d8c60SDouglas Gregor llvm::sys::Path P(TmpDir); 1215ce3449f5SDouglas Gregor P.createDirectoryOnDisk(true); 1216be2d8c60SDouglas Gregor P.appendComponent("preamble"); 121720975b25SDouglas Gregor P.appendSuffix("pch"); 1218ff9a5506SArgyrios Kyrtzidis if (P.makeUnique(/*reuse_current=*/false, /*ErrMsg*/0)) 1219be2d8c60SDouglas Gregor return std::string(); 1220be2d8c60SDouglas Gregor 1221be2d8c60SDouglas Gregor return P.str(); 1222be2d8c60SDouglas Gregor } 1223be2d8c60SDouglas Gregor 12243f4bea06SDouglas Gregor /// \brief Compute the preamble for the main file, providing the source buffer 12253f4bea06SDouglas Gregor /// that corresponds to the main file along with a pair (bytes, start-of-line) 12263f4bea06SDouglas Gregor /// that describes the preamble. 12273f4bea06SDouglas Gregor std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > 1228028d3e4dSDouglas Gregor ASTUnit::ComputePreamble(CompilerInvocation &Invocation, 1229028d3e4dSDouglas Gregor unsigned MaxLines, bool &CreatedBuffer) { 12304dde7498SDouglas Gregor FrontendOptions &FrontendOpts = Invocation.getFrontendOpts(); 12315159f616SChris Lattner PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts(); 12324dde7498SDouglas Gregor CreatedBuffer = false; 1233be2d8c60SDouglas Gregor 1234be2d8c60SDouglas Gregor // Try to determine if the main file has been remapped, either from the 1235be2d8c60SDouglas Gregor // command line (to another file) or directly through the compiler invocation 1236be2d8c60SDouglas Gregor // (to a memory buffer). 1237be2d8c60SDouglas Gregor llvm::MemoryBuffer *Buffer = 0; 123832fbe312SDouglas Gregor llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File); 1239be2d8c60SDouglas Gregor if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) { 1240be2d8c60SDouglas Gregor // Check whether there is a file-file remapping of the main file 1241be2d8c60SDouglas Gregor for (PreprocessorOptions::remapped_file_iterator 1242be2d8c60SDouglas Gregor M = PreprocessorOpts.remapped_file_begin(), 1243be2d8c60SDouglas Gregor E = PreprocessorOpts.remapped_file_end(); 1244be2d8c60SDouglas Gregor M != E; 1245be2d8c60SDouglas Gregor ++M) { 1246be2d8c60SDouglas Gregor llvm::sys::PathWithStatus MPath(M->first); 1247be2d8c60SDouglas Gregor if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) { 1248be2d8c60SDouglas Gregor if (MainFileStatus->uniqueID == MStatus->uniqueID) { 1249be2d8c60SDouglas Gregor // We found a remapping. Try to load the resulting, remapped source. 12504dde7498SDouglas Gregor if (CreatedBuffer) { 1251be2d8c60SDouglas Gregor delete Buffer; 12524dde7498SDouglas Gregor CreatedBuffer = false; 12534dde7498SDouglas Gregor } 12544dde7498SDouglas Gregor 125571731d6bSArgyrios Kyrtzidis Buffer = getBufferForFile(M->second); 1256be2d8c60SDouglas Gregor if (!Buffer) 12573f4bea06SDouglas Gregor return std::make_pair((llvm::MemoryBuffer*)0, 12583f4bea06SDouglas Gregor std::make_pair(0, true)); 12594dde7498SDouglas Gregor CreatedBuffer = true; 1260be2d8c60SDouglas Gregor } 1261be2d8c60SDouglas Gregor } 1262be2d8c60SDouglas Gregor } 1263be2d8c60SDouglas Gregor 1264be2d8c60SDouglas Gregor // Check whether there is a file-buffer remapping. It supercedes the 1265be2d8c60SDouglas Gregor // file-file remapping. 1266be2d8c60SDouglas Gregor for (PreprocessorOptions::remapped_file_buffer_iterator 1267be2d8c60SDouglas Gregor M = PreprocessorOpts.remapped_file_buffer_begin(), 1268be2d8c60SDouglas Gregor E = PreprocessorOpts.remapped_file_buffer_end(); 1269be2d8c60SDouglas Gregor M != E; 1270be2d8c60SDouglas Gregor ++M) { 1271be2d8c60SDouglas Gregor llvm::sys::PathWithStatus MPath(M->first); 1272be2d8c60SDouglas Gregor if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) { 1273be2d8c60SDouglas Gregor if (MainFileStatus->uniqueID == MStatus->uniqueID) { 1274be2d8c60SDouglas Gregor // We found a remapping. 12754dde7498SDouglas Gregor if (CreatedBuffer) { 1276be2d8c60SDouglas Gregor delete Buffer; 12774dde7498SDouglas Gregor CreatedBuffer = false; 12784dde7498SDouglas Gregor } 12794dde7498SDouglas Gregor 1280be2d8c60SDouglas Gregor Buffer = const_cast<llvm::MemoryBuffer *>(M->second); 1281be2d8c60SDouglas Gregor } 1282be2d8c60SDouglas Gregor } 1283be2d8c60SDouglas Gregor } 1284be2d8c60SDouglas Gregor } 1285be2d8c60SDouglas Gregor 1286be2d8c60SDouglas Gregor // If the main source file was not remapped, load it now. 1287be2d8c60SDouglas Gregor if (!Buffer) { 128832fbe312SDouglas Gregor Buffer = getBufferForFile(FrontendOpts.Inputs[0].File); 1289be2d8c60SDouglas Gregor if (!Buffer) 12903f4bea06SDouglas Gregor return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true)); 12914dde7498SDouglas Gregor 12924dde7498SDouglas Gregor CreatedBuffer = true; 1293be2d8c60SDouglas Gregor } 1294be2d8c60SDouglas Gregor 12957aecbc76SArgyrios Kyrtzidis return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, 12968cf47df7STed Kremenek *Invocation.getLangOpts(), 12977aecbc76SArgyrios Kyrtzidis MaxLines)); 12984dde7498SDouglas Gregor } 12994dde7498SDouglas Gregor 13006481ef1fSDouglas Gregor static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, 13016481ef1fSDouglas Gregor unsigned NewSize, 13020e62c1ccSChris Lattner StringRef NewName) { 13036481ef1fSDouglas Gregor llvm::MemoryBuffer *Result 13046481ef1fSDouglas Gregor = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName); 13056481ef1fSDouglas Gregor memcpy(const_cast<char*>(Result->getBufferStart()), 13066481ef1fSDouglas Gregor Old->getBufferStart(), Old->getBufferSize()); 13076481ef1fSDouglas Gregor memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(), 13083f4bea06SDouglas Gregor ' ', NewSize - Old->getBufferSize() - 1); 13093f4bea06SDouglas Gregor const_cast<char*>(Result->getBufferEnd())[-1] = '\n'; 13106481ef1fSDouglas Gregor 13116481ef1fSDouglas Gregor return Result; 13126481ef1fSDouglas Gregor } 13136481ef1fSDouglas Gregor 13144dde7498SDouglas Gregor /// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing 13154dde7498SDouglas Gregor /// the source file. 13164dde7498SDouglas Gregor /// 13174dde7498SDouglas Gregor /// This routine will compute the preamble of the main source file. If a 13184dde7498SDouglas Gregor /// non-trivial preamble is found, it will precompile that preamble into a 13194dde7498SDouglas Gregor /// precompiled header so that the precompiled preamble can be used to reduce 13204dde7498SDouglas Gregor /// reparsing time. If a precompiled preamble has already been constructed, 13214dde7498SDouglas Gregor /// this routine will determine if it is still valid and, if so, avoid 13224dde7498SDouglas Gregor /// rebuilding the precompiled preamble. 13234dde7498SDouglas Gregor /// 1324028d3e4dSDouglas Gregor /// \param AllowRebuild When true (the default), this routine is 1325028d3e4dSDouglas Gregor /// allowed to rebuild the precompiled preamble if it is found to be 1326028d3e4dSDouglas Gregor /// out-of-date. 1327028d3e4dSDouglas Gregor /// 1328028d3e4dSDouglas Gregor /// \param MaxLines When non-zero, the maximum number of lines that 1329028d3e4dSDouglas Gregor /// can occur within the preamble. 1330028d3e4dSDouglas Gregor /// 13316481ef1fSDouglas Gregor /// \returns If the precompiled preamble can be used, returns a newly-allocated 13326481ef1fSDouglas Gregor /// buffer that should be used in place of the main file when doing so. 13336481ef1fSDouglas Gregor /// Otherwise, returns a NULL pointer. 1334028d3e4dSDouglas Gregor llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( 13353cc15810SDouglas Gregor const CompilerInvocation &PreambleInvocationIn, 1336028d3e4dSDouglas Gregor bool AllowRebuild, 1337028d3e4dSDouglas Gregor unsigned MaxLines) { 13383cc15810SDouglas Gregor 1339c95d8192SDylan Noblesmith IntrusiveRefCntPtr<CompilerInvocation> 13403cc15810SDouglas Gregor PreambleInvocation(new CompilerInvocation(PreambleInvocationIn)); 13413cc15810SDouglas Gregor FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts(); 13424dde7498SDouglas Gregor PreprocessorOptions &PreprocessorOpts 13433cc15810SDouglas Gregor = PreambleInvocation->getPreprocessorOpts(); 13444dde7498SDouglas Gregor 13454dde7498SDouglas Gregor bool CreatedPreambleBuffer = false; 13463f4bea06SDouglas Gregor std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble 13473cc15810SDouglas Gregor = ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer); 13484dde7498SDouglas Gregor 1349925296b4SDouglas Gregor // If ComputePreamble() Take ownership of the preamble buffer. 1350e2778999SDylan Noblesmith OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer; 13513edb1676SDouglas Gregor if (CreatedPreambleBuffer) 13523edb1676SDouglas Gregor OwnedPreambleBuffer.reset(NewPreamble.first); 13533edb1676SDouglas Gregor 13543f4bea06SDouglas Gregor if (!NewPreamble.second.first) { 13554dde7498SDouglas Gregor // We couldn't find a preamble in the main source. Clear out the current 13564dde7498SDouglas Gregor // preamble, if we have one. It's obviously no good any more. 13574dde7498SDouglas Gregor Preamble.clear(); 135806b4f919STed Kremenek erasePreambleFile(this); 13594dde7498SDouglas Gregor 1360bb420abdSDouglas Gregor // The next time we actually see a preamble, precompile it. 1361bb420abdSDouglas Gregor PreambleRebuildCounter = 1; 13626481ef1fSDouglas Gregor return 0; 13634dde7498SDouglas Gregor } 13644dde7498SDouglas Gregor 13654dde7498SDouglas Gregor if (!Preamble.empty()) { 13664dde7498SDouglas Gregor // We've previously computed a preamble. Check whether we have the same 13674dde7498SDouglas Gregor // preamble now that we did before, and that there's enough space in 13684dde7498SDouglas Gregor // the main-file buffer within the precompiled preamble to fit the 13694dde7498SDouglas Gregor // new main file. 13703f4bea06SDouglas Gregor if (Preamble.size() == NewPreamble.second.first && 13713f4bea06SDouglas Gregor PreambleEndsAtStartOfLine == NewPreamble.second.second && 1372f5275a83SDouglas Gregor NewPreamble.first->getBufferSize() < PreambleReservedSize-2 && 13737c06d866SArgyrios Kyrtzidis memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(), 13743f4bea06SDouglas Gregor NewPreamble.second.first) == 0) { 13754dde7498SDouglas Gregor // The preamble has not changed. We may be able to re-use the precompiled 13764dde7498SDouglas Gregor // preamble. 13774dde7498SDouglas Gregor 13780e11955cSDouglas Gregor // Check that none of the files used by the preamble have changed. 13790e11955cSDouglas Gregor bool AnyFileChanged = false; 13804dde7498SDouglas Gregor 13810e11955cSDouglas Gregor // First, make a record of those files that have been overridden via 13820e11955cSDouglas Gregor // remapping or unsaved_files. 13830e11955cSDouglas Gregor llvm::StringMap<std::pair<off_t, time_t> > OverriddenFiles; 13840e11955cSDouglas Gregor for (PreprocessorOptions::remapped_file_iterator 13850e11955cSDouglas Gregor R = PreprocessorOpts.remapped_file_begin(), 13860e11955cSDouglas Gregor REnd = PreprocessorOpts.remapped_file_end(); 13870e11955cSDouglas Gregor !AnyFileChanged && R != REnd; 13880e11955cSDouglas Gregor ++R) { 13890e11955cSDouglas Gregor struct stat StatBuf; 13909583f794SAnders Carlsson if (FileMgr->getNoncachedStatValue(R->second, StatBuf)) { 13910e11955cSDouglas Gregor // If we can't stat the file we're remapping to, assume that something 13920e11955cSDouglas Gregor // horrible happened. 13930e11955cSDouglas Gregor AnyFileChanged = true; 13940e11955cSDouglas Gregor break; 13950e11955cSDouglas Gregor } 13960e11955cSDouglas Gregor 13970e11955cSDouglas Gregor OverriddenFiles[R->first] = std::make_pair(StatBuf.st_size, 13980e11955cSDouglas Gregor StatBuf.st_mtime); 13990e11955cSDouglas Gregor } 14000e11955cSDouglas Gregor for (PreprocessorOptions::remapped_file_buffer_iterator 14010e11955cSDouglas Gregor R = PreprocessorOpts.remapped_file_buffer_begin(), 14020e11955cSDouglas Gregor REnd = PreprocessorOpts.remapped_file_buffer_end(); 14030e11955cSDouglas Gregor !AnyFileChanged && R != REnd; 14040e11955cSDouglas Gregor ++R) { 14050e11955cSDouglas Gregor // FIXME: Should we actually compare the contents of file->buffer 14060e11955cSDouglas Gregor // remappings? 14070e11955cSDouglas Gregor OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(), 14080e11955cSDouglas Gregor 0); 14090e11955cSDouglas Gregor } 14100e11955cSDouglas Gregor 14110e11955cSDouglas Gregor // Check whether anything has changed. 14120e11955cSDouglas Gregor for (llvm::StringMap<std::pair<off_t, time_t> >::iterator 14130e11955cSDouglas Gregor F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end(); 14140e11955cSDouglas Gregor !AnyFileChanged && F != FEnd; 14150e11955cSDouglas Gregor ++F) { 14160e11955cSDouglas Gregor llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden 14170e11955cSDouglas Gregor = OverriddenFiles.find(F->first()); 14180e11955cSDouglas Gregor if (Overridden != OverriddenFiles.end()) { 14190e11955cSDouglas Gregor // This file was remapped; check whether the newly-mapped file 14200e11955cSDouglas Gregor // matches up with the previous mapping. 14210e11955cSDouglas Gregor if (Overridden->second != F->second) 14220e11955cSDouglas Gregor AnyFileChanged = true; 14230e11955cSDouglas Gregor continue; 14240e11955cSDouglas Gregor } 14250e11955cSDouglas Gregor 14260e11955cSDouglas Gregor // The file was not remapped; check whether it has changed on disk. 14270e11955cSDouglas Gregor struct stat StatBuf; 14289583f794SAnders Carlsson if (FileMgr->getNoncachedStatValue(F->first(), StatBuf)) { 14290e11955cSDouglas Gregor // If we can't stat the file, assume that something horrible happened. 14300e11955cSDouglas Gregor AnyFileChanged = true; 14310e11955cSDouglas Gregor } else if (StatBuf.st_size != F->second.first || 14320e11955cSDouglas Gregor StatBuf.st_mtime != F->second.second) 14330e11955cSDouglas Gregor AnyFileChanged = true; 14340e11955cSDouglas Gregor } 14350e11955cSDouglas Gregor 14360e11955cSDouglas Gregor if (!AnyFileChanged) { 1437d9a30af2SDouglas Gregor // Okay! We can re-use the precompiled preamble. 1438d9a30af2SDouglas Gregor 1439d9a30af2SDouglas Gregor // Set the state of the diagnostic object to mimic its state 1440d9a30af2SDouglas Gregor // after parsing the preamble. 1441d9a30af2SDouglas Gregor getDiagnostics().Reset(); 144236e3b5c7SDouglas Gregor ProcessWarningOptions(getDiagnostics(), 14433cc15810SDouglas Gregor PreambleInvocation->getDiagnosticOpts()); 1444d9a30af2SDouglas Gregor getDiagnostics().setNumWarnings(NumWarningsInPreamble); 1445d9a30af2SDouglas Gregor 1446d9a30af2SDouglas Gregor // Create a version of the main file buffer that is padded to 1447d9a30af2SDouglas Gregor // buffer size we reserved when creating the preamble. 14486481ef1fSDouglas Gregor return CreatePaddedMainFileBuffer(NewPreamble.first, 14496481ef1fSDouglas Gregor PreambleReservedSize, 145032fbe312SDouglas Gregor FrontendOpts.Inputs[0].File); 14514dde7498SDouglas Gregor } 14520e11955cSDouglas Gregor } 14534dde7498SDouglas Gregor 1454028d3e4dSDouglas Gregor // If we aren't allowed to rebuild the precompiled preamble, just 1455028d3e4dSDouglas Gregor // return now. 1456028d3e4dSDouglas Gregor if (!AllowRebuild) 1457028d3e4dSDouglas Gregor return 0; 1458028d3e4dSDouglas Gregor 14594dde7498SDouglas Gregor // We can't reuse the previously-computed preamble. Build a new one. 14604dde7498SDouglas Gregor Preamble.clear(); 1461925296b4SDouglas Gregor PreambleDiagnostics.clear(); 146206b4f919STed Kremenek erasePreambleFile(this); 1463bb420abdSDouglas Gregor PreambleRebuildCounter = 1; 1464028d3e4dSDouglas Gregor } else if (!AllowRebuild) { 1465028d3e4dSDouglas Gregor // We aren't allowed to rebuild the precompiled preamble; just 1466028d3e4dSDouglas Gregor // return now. 1467028d3e4dSDouglas Gregor return 0; 1468bb420abdSDouglas Gregor } 1469bb420abdSDouglas Gregor 1470bb420abdSDouglas Gregor // If the preamble rebuild counter > 1, it's because we previously 1471bb420abdSDouglas Gregor // failed to build a preamble and we're not yet ready to try 1472bb420abdSDouglas Gregor // again. Decrement the counter and return a failure. 1473bb420abdSDouglas Gregor if (PreambleRebuildCounter > 1) { 1474bb420abdSDouglas Gregor --PreambleRebuildCounter; 1475bb420abdSDouglas Gregor return 0; 14764dde7498SDouglas Gregor } 14774dde7498SDouglas Gregor 1478e10f0e56SDouglas Gregor // Create a temporary file for the precompiled preamble. In rare 1479e10f0e56SDouglas Gregor // circumstances, this can fail. 1480e10f0e56SDouglas Gregor std::string PreamblePCHPath = GetPreamblePCHPath(); 1481e10f0e56SDouglas Gregor if (PreamblePCHPath.empty()) { 1482e10f0e56SDouglas Gregor // Try again next time. 1483e10f0e56SDouglas Gregor PreambleRebuildCounter = 1; 1484e10f0e56SDouglas Gregor return 0; 1485e10f0e56SDouglas Gregor } 1486e10f0e56SDouglas Gregor 14874dde7498SDouglas Gregor // We did not previously compute a preamble, or it can't be reused anyway. 148816896c45SDouglas Gregor SimpleTimer PreambleTimer(WantTiming); 148916896c45SDouglas Gregor PreambleTimer.setOutput("Precompiling preamble"); 1490be2d8c60SDouglas Gregor 1491be2d8c60SDouglas Gregor // Create a new buffer that stores the preamble. The buffer also contains 1492be2d8c60SDouglas Gregor // extra space for the original contents of the file (which will be present 1493be2d8c60SDouglas Gregor // when we actually parse the file) along with more room in case the file 1494be2d8c60SDouglas Gregor // grows. 14954dde7498SDouglas Gregor PreambleReservedSize = NewPreamble.first->getBufferSize(); 14964dde7498SDouglas Gregor if (PreambleReservedSize < 4096) 14973f4bea06SDouglas Gregor PreambleReservedSize = 8191; 1498be2d8c60SDouglas Gregor else 14994dde7498SDouglas Gregor PreambleReservedSize *= 2; 1500be2d8c60SDouglas Gregor 1501d9a30af2SDouglas Gregor // Save the preamble text for later; we'll need to compare against it for 1502d9a30af2SDouglas Gregor // subsequent reparses. 150332fbe312SDouglas Gregor StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].File; 15047c06d866SArgyrios Kyrtzidis Preamble.assign(FileMgr->getFile(MainFilename), 15057c06d866SArgyrios Kyrtzidis NewPreamble.first->getBufferStart(), 1506d9a30af2SDouglas Gregor NewPreamble.first->getBufferStart() 1507d9a30af2SDouglas Gregor + NewPreamble.second.first); 1508d9a30af2SDouglas Gregor PreambleEndsAtStartOfLine = NewPreamble.second.second; 1509d9a30af2SDouglas Gregor 1510a0734c5fSDouglas Gregor delete PreambleBuffer; 1511a0734c5fSDouglas Gregor PreambleBuffer 15124dde7498SDouglas Gregor = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize, 151332fbe312SDouglas Gregor FrontendOpts.Inputs[0].File); 1514be2d8c60SDouglas Gregor memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()), 15154dde7498SDouglas Gregor NewPreamble.first->getBufferStart(), Preamble.size()); 15164dde7498SDouglas Gregor memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(), 15173f4bea06SDouglas Gregor ' ', PreambleReservedSize - Preamble.size() - 1); 15183f4bea06SDouglas Gregor const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n'; 15194dde7498SDouglas Gregor 1520be2d8c60SDouglas Gregor // Remap the main source file to the preamble buffer. 152132fbe312SDouglas Gregor llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File); 1522be2d8c60SDouglas Gregor PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer); 1523be2d8c60SDouglas Gregor 1524be2d8c60SDouglas Gregor // Tell the compiler invocation to generate a temporary precompiled header. 1525be2d8c60SDouglas Gregor FrontendOpts.ProgramAction = frontend::GeneratePCH; 1526be2d8c60SDouglas Gregor // FIXME: Generate the precompiled header into memory? 1527e10f0e56SDouglas Gregor FrontendOpts.OutputFile = PreamblePCHPath; 1528bb6a8818SDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.first = 0; 1529bb6a8818SDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.second = false; 1530be2d8c60SDouglas Gregor 1531be2d8c60SDouglas Gregor // Create the compiler instance to use for building the precompiled preamble. 1532e2778999SDylan Noblesmith OwningPtr<CompilerInstance> Clang(new CompilerInstance()); 153384de4a17STed Kremenek 153484de4a17STed Kremenek // Recover resources if we crash before exiting this method. 1535022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> 1536022a4904STed Kremenek CICleanup(Clang.get()); 153784de4a17STed Kremenek 15383cc15810SDouglas Gregor Clang->setInvocation(&*PreambleInvocation); 153932fbe312SDouglas Gregor OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; 1540be2d8c60SDouglas Gregor 15418e984da8SDouglas Gregor // Set up diagnostics, capturing all of the diagnostics produced. 154284de4a17STed Kremenek Clang->setDiagnostics(&getDiagnostics()); 1543be2d8c60SDouglas Gregor 1544be2d8c60SDouglas Gregor // Create the target instance. 154584de4a17STed Kremenek Clang->getTargetOpts().Features = TargetFeatures; 154684de4a17STed Kremenek Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), 154784de4a17STed Kremenek Clang->getTargetOpts())); 154884de4a17STed Kremenek if (!Clang->hasTarget()) { 15494dde7498SDouglas Gregor llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); 15504dde7498SDouglas Gregor Preamble.clear(); 1551bb420abdSDouglas Gregor PreambleRebuildCounter = DefaultPreambleRebuildInterval; 1552a0734c5fSDouglas Gregor PreprocessorOpts.eraseRemappedFile( 1553a0734c5fSDouglas Gregor PreprocessorOpts.remapped_file_buffer_end() - 1); 15546481ef1fSDouglas Gregor return 0; 1555be2d8c60SDouglas Gregor } 1556be2d8c60SDouglas Gregor 1557be2d8c60SDouglas Gregor // Inform the target of the language options. 1558be2d8c60SDouglas Gregor // 1559be2d8c60SDouglas Gregor // FIXME: We shouldn't need to do this, the target should be immutable once 1560be2d8c60SDouglas Gregor // created. This complexity should be lifted elsewhere. 156184de4a17STed Kremenek Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); 1562be2d8c60SDouglas Gregor 156384de4a17STed Kremenek assert(Clang->getFrontendOpts().Inputs.size() == 1 && 1564be2d8c60SDouglas Gregor "Invocation must have exactly one source file!"); 156532fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && 1566be2d8c60SDouglas Gregor "FIXME: AST inputs not yet supported here!"); 156732fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && 1568be2d8c60SDouglas Gregor "IR inputs not support here!"); 1569be2d8c60SDouglas Gregor 1570be2d8c60SDouglas Gregor // Clear out old caches and data. 1571bb6a8818SDouglas Gregor getDiagnostics().Reset(); 157284de4a17STed Kremenek ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts()); 157338bacf34SArgyrios Kyrtzidis checkAndRemoveNonDriverDiags(StoredDiagnostics); 1574e9db88f9SDouglas Gregor TopLevelDecls.clear(); 1575e9db88f9SDouglas Gregor TopLevelDeclsInPreamble.clear(); 1576be2d8c60SDouglas Gregor 1577be2d8c60SDouglas Gregor // Create a file manager object to provide access to and cache the filesystem. 157884de4a17STed Kremenek Clang->setFileManager(new FileManager(Clang->getFileSystemOpts())); 1579be2d8c60SDouglas Gregor 1580be2d8c60SDouglas Gregor // Create the source manager. 158184de4a17STed Kremenek Clang->setSourceManager(new SourceManager(getDiagnostics(), 158284de4a17STed Kremenek Clang->getFileManager())); 1583be2d8c60SDouglas Gregor 1584e2778999SDylan Noblesmith OwningPtr<PrecompilePreambleAction> Act; 158548c8cd3fSDouglas Gregor Act.reset(new PrecompilePreambleAction(*this)); 158632fbe312SDouglas Gregor if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { 15874dde7498SDouglas Gregor llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); 15884dde7498SDouglas Gregor Preamble.clear(); 1589bb420abdSDouglas Gregor PreambleRebuildCounter = DefaultPreambleRebuildInterval; 1590a0734c5fSDouglas Gregor PreprocessorOpts.eraseRemappedFile( 1591a0734c5fSDouglas Gregor PreprocessorOpts.remapped_file_buffer_end() - 1); 15926481ef1fSDouglas Gregor return 0; 1593be2d8c60SDouglas Gregor } 1594be2d8c60SDouglas Gregor 1595be2d8c60SDouglas Gregor Act->Execute(); 1596be2d8c60SDouglas Gregor Act->EndSourceFile(); 1597be2d8c60SDouglas Gregor 1598e9db88f9SDouglas Gregor if (Diagnostics->hasErrorOccurred()) { 15994dde7498SDouglas Gregor // There were errors parsing the preamble, so no precompiled header was 16004dde7498SDouglas Gregor // generated. Forget that we even tried. 1601a6f74e27SDouglas Gregor // FIXME: Should we leave a note for ourselves to try again? 16024dde7498SDouglas Gregor llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); 16034dde7498SDouglas Gregor Preamble.clear(); 1604e9db88f9SDouglas Gregor TopLevelDeclsInPreamble.clear(); 1605bb420abdSDouglas Gregor PreambleRebuildCounter = DefaultPreambleRebuildInterval; 1606a0734c5fSDouglas Gregor PreprocessorOpts.eraseRemappedFile( 1607a0734c5fSDouglas Gregor PreprocessorOpts.remapped_file_buffer_end() - 1); 16086481ef1fSDouglas Gregor return 0; 16094dde7498SDouglas Gregor } 16104dde7498SDouglas Gregor 1611925296b4SDouglas Gregor // Transfer any diagnostics generated when parsing the preamble into the set 1612925296b4SDouglas Gregor // of preamble diagnostics. 1613925296b4SDouglas Gregor PreambleDiagnostics.clear(); 1614925296b4SDouglas Gregor PreambleDiagnostics.insert(PreambleDiagnostics.end(), 1615067cbfa2SArgyrios Kyrtzidis stored_diag_afterDriver_begin(), stored_diag_end()); 161638bacf34SArgyrios Kyrtzidis checkAndRemoveNonDriverDiags(StoredDiagnostics); 1617925296b4SDouglas Gregor 16184dde7498SDouglas Gregor // Keep track of the preamble we precompiled. 161906b4f919STed Kremenek setPreambleFile(this, FrontendOpts.OutputFile); 1620d9a30af2SDouglas Gregor NumWarningsInPreamble = getDiagnostics().getNumWarnings(); 16210e11955cSDouglas Gregor 16220e11955cSDouglas Gregor // Keep track of all of the files that the source manager knows about, 16230e11955cSDouglas Gregor // so we can verify whether they have changed or not. 16240e11955cSDouglas Gregor FilesInPreamble.clear(); 162584de4a17STed Kremenek SourceManager &SourceMgr = Clang->getSourceManager(); 16260e11955cSDouglas Gregor const llvm::MemoryBuffer *MainFileBuffer 16270e11955cSDouglas Gregor = SourceMgr.getBuffer(SourceMgr.getMainFileID()); 16280e11955cSDouglas Gregor for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(), 16290e11955cSDouglas Gregor FEnd = SourceMgr.fileinfo_end(); 16300e11955cSDouglas Gregor F != FEnd; 16310e11955cSDouglas Gregor ++F) { 163211e6f0a6SArgyrios Kyrtzidis const FileEntry *File = F->second->OrigEntry; 16330e11955cSDouglas Gregor if (!File || F->second->getRawBuffer() == MainFileBuffer) 16340e11955cSDouglas Gregor continue; 16350e11955cSDouglas Gregor 16360e11955cSDouglas Gregor FilesInPreamble[File->getName()] 16370e11955cSDouglas Gregor = std::make_pair(F->second->getSize(), File->getModificationTime()); 16380e11955cSDouglas Gregor } 16390e11955cSDouglas Gregor 1640bb420abdSDouglas Gregor PreambleRebuildCounter = 1; 1641a0734c5fSDouglas Gregor PreprocessorOpts.eraseRemappedFile( 1642a0734c5fSDouglas Gregor PreprocessorOpts.remapped_file_buffer_end() - 1); 1643df7a79a9SDouglas Gregor 1644df7a79a9SDouglas Gregor // If the hash of top-level entities differs from the hash of the top-level 1645df7a79a9SDouglas Gregor // entities the last time we rebuilt the preamble, clear out the completion 1646df7a79a9SDouglas Gregor // cache. 1647df7a79a9SDouglas Gregor if (CurrentTopLevelHashValue != PreambleTopLevelHashValue) { 1648df7a79a9SDouglas Gregor CompletionCacheTopLevelHashValue = 0; 1649df7a79a9SDouglas Gregor PreambleTopLevelHashValue = CurrentTopLevelHashValue; 1650df7a79a9SDouglas Gregor } 1651df7a79a9SDouglas Gregor 16526481ef1fSDouglas Gregor return CreatePaddedMainFileBuffer(NewPreamble.first, 16536481ef1fSDouglas Gregor PreambleReservedSize, 165432fbe312SDouglas Gregor FrontendOpts.Inputs[0].File); 1655be2d8c60SDouglas Gregor } 1656aa21cc40SDouglas Gregor 1657e9db88f9SDouglas Gregor void ASTUnit::RealizeTopLevelDeclsFromPreamble() { 1658e9db88f9SDouglas Gregor std::vector<Decl *> Resolved; 1659e9db88f9SDouglas Gregor Resolved.reserve(TopLevelDeclsInPreamble.size()); 1660e9db88f9SDouglas Gregor ExternalASTSource &Source = *getASTContext().getExternalSource(); 1661e9db88f9SDouglas Gregor for (unsigned I = 0, N = TopLevelDeclsInPreamble.size(); I != N; ++I) { 1662e9db88f9SDouglas Gregor // Resolve the declaration ID to an actual declaration, possibly 1663e9db88f9SDouglas Gregor // deserializing the declaration in the process. 1664e9db88f9SDouglas Gregor Decl *D = Source.GetExternalDecl(TopLevelDeclsInPreamble[I]); 1665e9db88f9SDouglas Gregor if (D) 1666e9db88f9SDouglas Gregor Resolved.push_back(D); 1667e9db88f9SDouglas Gregor } 1668e9db88f9SDouglas Gregor TopLevelDeclsInPreamble.clear(); 1669e9db88f9SDouglas Gregor TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); 1670e9db88f9SDouglas Gregor } 1671e9db88f9SDouglas Gregor 1672ac1cc934SArgyrios Kyrtzidis void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { 1673ac1cc934SArgyrios Kyrtzidis // Steal the created target, context, and preprocessor. 1674ac1cc934SArgyrios Kyrtzidis TheSema.reset(CI.takeSema()); 1675ac1cc934SArgyrios Kyrtzidis Consumer.reset(CI.takeASTConsumer()); 1676ac1cc934SArgyrios Kyrtzidis Ctx = &CI.getASTContext(); 1677ac1cc934SArgyrios Kyrtzidis PP = &CI.getPreprocessor(); 1678ac1cc934SArgyrios Kyrtzidis CI.setSourceManager(0); 1679ac1cc934SArgyrios Kyrtzidis CI.setFileManager(0); 1680ac1cc934SArgyrios Kyrtzidis Target = &CI.getTarget(); 1681ac1cc934SArgyrios Kyrtzidis Reader = CI.getModuleManager(); 1682ac1cc934SArgyrios Kyrtzidis } 1683ac1cc934SArgyrios Kyrtzidis 16840e62c1ccSChris Lattner StringRef ASTUnit::getMainFileName() const { 168532fbe312SDouglas Gregor return Invocation->getFrontendOpts().Inputs[0].File; 168616896c45SDouglas Gregor } 168716896c45SDouglas Gregor 168835dcda79SArgyrios Kyrtzidis ASTUnit *ASTUnit::create(CompilerInvocation *CI, 1689c95d8192SDylan Noblesmith IntrusiveRefCntPtr<DiagnosticsEngine> Diags, 16906d7833f1SArgyrios Kyrtzidis bool CaptureDiagnostics, 16916d7833f1SArgyrios Kyrtzidis bool UserFilesAreVolatile) { 1692e2778999SDylan Noblesmith OwningPtr<ASTUnit> AST; 169335dcda79SArgyrios Kyrtzidis AST.reset(new ASTUnit(false)); 169467aa7db0SArgyrios Kyrtzidis ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); 169535dcda79SArgyrios Kyrtzidis AST->Diagnostics = Diags; 16965e14d39aSTed Kremenek AST->Invocation = CI; 1697c30dcecbSAnders Carlsson AST->FileSystemOpts = CI->getFileSystemOpts(); 16985e14d39aSTed Kremenek AST->FileMgr = new FileManager(AST->FileSystemOpts); 16996d7833f1SArgyrios Kyrtzidis AST->UserFilesAreVolatile = UserFilesAreVolatile; 17006d7833f1SArgyrios Kyrtzidis AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr, 17016d7833f1SArgyrios Kyrtzidis UserFilesAreVolatile); 170235dcda79SArgyrios Kyrtzidis 170335dcda79SArgyrios Kyrtzidis return AST.take(); 170435dcda79SArgyrios Kyrtzidis } 170535dcda79SArgyrios Kyrtzidis 1706f1f67597SArgyrios Kyrtzidis ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, 1707c95d8192SDylan Noblesmith IntrusiveRefCntPtr<DiagnosticsEngine> Diags, 17081ac5da10SArgyrios Kyrtzidis ASTFrontendAction *Action, 1709b11f5a4cSArgyrios Kyrtzidis ASTUnit *Unit, 1710b11f5a4cSArgyrios Kyrtzidis bool Persistent, 1711b11f5a4cSArgyrios Kyrtzidis StringRef ResourceFilesPath, 1712b11f5a4cSArgyrios Kyrtzidis bool OnlyLocalDecls, 1713b11f5a4cSArgyrios Kyrtzidis bool CaptureDiagnostics, 1714b11f5a4cSArgyrios Kyrtzidis bool PrecompilePreamble, 1715ac1cc934SArgyrios Kyrtzidis bool CacheCodeCompletionResults, 17163292d06aSDmitri Gribenko bool IncludeBriefCommentsInCodeCompletion, 17176d7833f1SArgyrios Kyrtzidis bool UserFilesAreVolatile, 1718ac1cc934SArgyrios Kyrtzidis OwningPtr<ASTUnit> *ErrAST) { 1719f1f67597SArgyrios Kyrtzidis assert(CI && "A CompilerInvocation is required"); 1720f1f67597SArgyrios Kyrtzidis 1721e2778999SDylan Noblesmith OwningPtr<ASTUnit> OwnAST; 17221ac5da10SArgyrios Kyrtzidis ASTUnit *AST = Unit; 17231ac5da10SArgyrios Kyrtzidis if (!AST) { 1724f1f67597SArgyrios Kyrtzidis // Create the AST unit. 17256d7833f1SArgyrios Kyrtzidis OwnAST.reset(create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile)); 17261ac5da10SArgyrios Kyrtzidis AST = OwnAST.get(); 17271ac5da10SArgyrios Kyrtzidis } 17281ac5da10SArgyrios Kyrtzidis 1729b11f5a4cSArgyrios Kyrtzidis if (!ResourceFilesPath.empty()) { 1730b11f5a4cSArgyrios Kyrtzidis // Override the resources path. 1731b11f5a4cSArgyrios Kyrtzidis CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; 1732b11f5a4cSArgyrios Kyrtzidis } 1733b11f5a4cSArgyrios Kyrtzidis AST->OnlyLocalDecls = OnlyLocalDecls; 1734b11f5a4cSArgyrios Kyrtzidis AST->CaptureDiagnostics = CaptureDiagnostics; 1735b11f5a4cSArgyrios Kyrtzidis if (PrecompilePreamble) 1736b11f5a4cSArgyrios Kyrtzidis AST->PreambleRebuildCounter = 2; 173769f74f80SDouglas Gregor AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete; 1738b11f5a4cSArgyrios Kyrtzidis AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; 17393292d06aSDmitri Gribenko AST->IncludeBriefCommentsInCodeCompletion 17403292d06aSDmitri Gribenko = IncludeBriefCommentsInCodeCompletion; 1741f1f67597SArgyrios Kyrtzidis 1742f1f67597SArgyrios Kyrtzidis // Recover resources if we crash before exiting this method. 1743f1f67597SArgyrios Kyrtzidis llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> 17441ac5da10SArgyrios Kyrtzidis ASTUnitCleanup(OwnAST.get()); 17459c902b55SDavid Blaikie llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, 17469c902b55SDavid Blaikie llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > 1747f1f67597SArgyrios Kyrtzidis DiagCleanup(Diags.getPtr()); 1748f1f67597SArgyrios Kyrtzidis 1749f1f67597SArgyrios Kyrtzidis // We'll manage file buffers ourselves. 1750f1f67597SArgyrios Kyrtzidis CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; 1751f1f67597SArgyrios Kyrtzidis CI->getFrontendOpts().DisableFree = false; 1752f1f67597SArgyrios Kyrtzidis ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts()); 1753f1f67597SArgyrios Kyrtzidis 1754f1f67597SArgyrios Kyrtzidis // Save the target features. 1755f1f67597SArgyrios Kyrtzidis AST->TargetFeatures = CI->getTargetOpts().Features; 1756f1f67597SArgyrios Kyrtzidis 1757f1f67597SArgyrios Kyrtzidis // Create the compiler instance to use for building the AST. 1758e2778999SDylan Noblesmith OwningPtr<CompilerInstance> Clang(new CompilerInstance()); 1759f1f67597SArgyrios Kyrtzidis 1760f1f67597SArgyrios Kyrtzidis // Recover resources if we crash before exiting this method. 1761f1f67597SArgyrios Kyrtzidis llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> 1762f1f67597SArgyrios Kyrtzidis CICleanup(Clang.get()); 1763f1f67597SArgyrios Kyrtzidis 1764f1f67597SArgyrios Kyrtzidis Clang->setInvocation(CI); 176532fbe312SDouglas Gregor AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; 1766f1f67597SArgyrios Kyrtzidis 1767f1f67597SArgyrios Kyrtzidis // Set up diagnostics, capturing any diagnostics that would 1768f1f67597SArgyrios Kyrtzidis // otherwise be dropped. 1769f1f67597SArgyrios Kyrtzidis Clang->setDiagnostics(&AST->getDiagnostics()); 1770f1f67597SArgyrios Kyrtzidis 1771f1f67597SArgyrios Kyrtzidis // Create the target instance. 1772f1f67597SArgyrios Kyrtzidis Clang->getTargetOpts().Features = AST->TargetFeatures; 1773f1f67597SArgyrios Kyrtzidis Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), 1774f1f67597SArgyrios Kyrtzidis Clang->getTargetOpts())); 1775f1f67597SArgyrios Kyrtzidis if (!Clang->hasTarget()) 1776f1f67597SArgyrios Kyrtzidis return 0; 1777f1f67597SArgyrios Kyrtzidis 1778f1f67597SArgyrios Kyrtzidis // Inform the target of the language options. 1779f1f67597SArgyrios Kyrtzidis // 1780f1f67597SArgyrios Kyrtzidis // FIXME: We shouldn't need to do this, the target should be immutable once 1781f1f67597SArgyrios Kyrtzidis // created. This complexity should be lifted elsewhere. 1782f1f67597SArgyrios Kyrtzidis Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); 1783f1f67597SArgyrios Kyrtzidis 1784f1f67597SArgyrios Kyrtzidis assert(Clang->getFrontendOpts().Inputs.size() == 1 && 1785f1f67597SArgyrios Kyrtzidis "Invocation must have exactly one source file!"); 178632fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && 1787f1f67597SArgyrios Kyrtzidis "FIXME: AST inputs not yet supported here!"); 178832fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && 1789f1f67597SArgyrios Kyrtzidis "IR inputs not supported here!"); 1790f1f67597SArgyrios Kyrtzidis 1791f1f67597SArgyrios Kyrtzidis // Configure the various subsystems. 1792f1f67597SArgyrios Kyrtzidis AST->TheSema.reset(); 1793f1f67597SArgyrios Kyrtzidis AST->Ctx = 0; 1794f1f67597SArgyrios Kyrtzidis AST->PP = 0; 1795244ce8b2SArgyrios Kyrtzidis AST->Reader = 0; 1796f1f67597SArgyrios Kyrtzidis 1797f1f67597SArgyrios Kyrtzidis // Create a file manager object to provide access to and cache the filesystem. 1798f1f67597SArgyrios Kyrtzidis Clang->setFileManager(&AST->getFileManager()); 1799f1f67597SArgyrios Kyrtzidis 1800f1f67597SArgyrios Kyrtzidis // Create the source manager. 1801f1f67597SArgyrios Kyrtzidis Clang->setSourceManager(&AST->getSourceManager()); 1802f1f67597SArgyrios Kyrtzidis 1803f1f67597SArgyrios Kyrtzidis ASTFrontendAction *Act = Action; 1804f1f67597SArgyrios Kyrtzidis 1805e2778999SDylan Noblesmith OwningPtr<TopLevelDeclTrackerAction> TrackerAct; 1806f1f67597SArgyrios Kyrtzidis if (!Act) { 1807f1f67597SArgyrios Kyrtzidis TrackerAct.reset(new TopLevelDeclTrackerAction(*AST)); 1808f1f67597SArgyrios Kyrtzidis Act = TrackerAct.get(); 1809f1f67597SArgyrios Kyrtzidis } 1810f1f67597SArgyrios Kyrtzidis 1811f1f67597SArgyrios Kyrtzidis // Recover resources if we crash before exiting this method. 1812f1f67597SArgyrios Kyrtzidis llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction> 1813f1f67597SArgyrios Kyrtzidis ActCleanup(TrackerAct.get()); 1814f1f67597SArgyrios Kyrtzidis 1815ac1cc934SArgyrios Kyrtzidis if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { 1816ac1cc934SArgyrios Kyrtzidis AST->transferASTDataFromCompilerInstance(*Clang); 1817ac1cc934SArgyrios Kyrtzidis if (OwnAST && ErrAST) 1818ac1cc934SArgyrios Kyrtzidis ErrAST->swap(OwnAST); 1819ac1cc934SArgyrios Kyrtzidis 1820f1f67597SArgyrios Kyrtzidis return 0; 1821ac1cc934SArgyrios Kyrtzidis } 1822f1f67597SArgyrios Kyrtzidis 1823b11f5a4cSArgyrios Kyrtzidis if (Persistent && !TrackerAct) { 1824b11f5a4cSArgyrios Kyrtzidis Clang->getPreprocessor().addPPCallbacks( 1825b11f5a4cSArgyrios Kyrtzidis new MacroDefinitionTrackerPPCallbacks(AST->getCurrentTopLevelHashValue())); 1826b11f5a4cSArgyrios Kyrtzidis std::vector<ASTConsumer*> Consumers; 1827b11f5a4cSArgyrios Kyrtzidis if (Clang->hasASTConsumer()) 1828b11f5a4cSArgyrios Kyrtzidis Consumers.push_back(Clang->takeASTConsumer()); 1829b11f5a4cSArgyrios Kyrtzidis Consumers.push_back(new TopLevelDeclTrackerConsumer(*AST, 1830b11f5a4cSArgyrios Kyrtzidis AST->getCurrentTopLevelHashValue())); 1831b11f5a4cSArgyrios Kyrtzidis Clang->setASTConsumer(new MultiplexConsumer(Consumers)); 1832b11f5a4cSArgyrios Kyrtzidis } 18331416e17cSArgyrios Kyrtzidis if (!Act->Execute()) { 18341416e17cSArgyrios Kyrtzidis AST->transferASTDataFromCompilerInstance(*Clang); 18351416e17cSArgyrios Kyrtzidis if (OwnAST && ErrAST) 18361416e17cSArgyrios Kyrtzidis ErrAST->swap(OwnAST); 18371416e17cSArgyrios Kyrtzidis 18381416e17cSArgyrios Kyrtzidis return 0; 18391416e17cSArgyrios Kyrtzidis } 1840f1f67597SArgyrios Kyrtzidis 1841f1f67597SArgyrios Kyrtzidis // Steal the created target, context, and preprocessor. 1842ac1cc934SArgyrios Kyrtzidis AST->transferASTDataFromCompilerInstance(*Clang); 1843f1f67597SArgyrios Kyrtzidis 1844f1f67597SArgyrios Kyrtzidis Act->EndSourceFile(); 1845f1f67597SArgyrios Kyrtzidis 18461ac5da10SArgyrios Kyrtzidis if (OwnAST) 18471ac5da10SArgyrios Kyrtzidis return OwnAST.take(); 18481ac5da10SArgyrios Kyrtzidis else 18491ac5da10SArgyrios Kyrtzidis return AST; 1850f1f67597SArgyrios Kyrtzidis } 1851f1f67597SArgyrios Kyrtzidis 18527bb8af61SDouglas Gregor bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { 18537bb8af61SDouglas Gregor if (!Invocation) 18547bb8af61SDouglas Gregor return true; 18557bb8af61SDouglas Gregor 18567bb8af61SDouglas Gregor // We'll manage file buffers ourselves. 18577bb8af61SDouglas Gregor Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true; 18587bb8af61SDouglas Gregor Invocation->getFrontendOpts().DisableFree = false; 1859345c1bcbSDouglas Gregor ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); 18607bb8af61SDouglas Gregor 1861ffd6dc43SDouglas Gregor // Save the target features. 1862ffd6dc43SDouglas Gregor TargetFeatures = Invocation->getTargetOpts().Features; 1863ffd6dc43SDouglas Gregor 18647bb8af61SDouglas Gregor llvm::MemoryBuffer *OverrideMainBuffer = 0; 1865f5a18546SDouglas Gregor if (PrecompilePreamble) { 1866c6592929SDouglas Gregor PreambleRebuildCounter = 2; 18677bb8af61SDouglas Gregor OverrideMainBuffer 18687bb8af61SDouglas Gregor = getMainBufferWithPrecompiledPreamble(*Invocation); 18697bb8af61SDouglas Gregor } 18707bb8af61SDouglas Gregor 187116896c45SDouglas Gregor SimpleTimer ParsingTimer(WantTiming); 187216896c45SDouglas Gregor ParsingTimer.setOutput("Parsing " + getMainFileName()); 18737bb8af61SDouglas Gregor 1874022a4904STed Kremenek // Recover resources if we crash before exiting this method. 1875022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer> 1876022a4904STed Kremenek MemBufferCleanup(OverrideMainBuffer); 1877022a4904STed Kremenek 187816896c45SDouglas Gregor return Parse(OverrideMainBuffer); 18797bb8af61SDouglas Gregor } 18807bb8af61SDouglas Gregor 1881aa21cc40SDouglas Gregor ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, 1882c95d8192SDylan Noblesmith IntrusiveRefCntPtr<DiagnosticsEngine> Diags, 1883aa21cc40SDouglas Gregor bool OnlyLocalDecls, 1884be2d8c60SDouglas Gregor bool CaptureDiagnostics, 1885028d3e4dSDouglas Gregor bool PrecompilePreamble, 188669f74f80SDouglas Gregor TranslationUnitKind TUKind, 18873292d06aSDmitri Gribenko bool CacheCodeCompletionResults, 18886d7833f1SArgyrios Kyrtzidis bool IncludeBriefCommentsInCodeCompletion, 18896d7833f1SArgyrios Kyrtzidis bool UserFilesAreVolatile) { 1890aa21cc40SDouglas Gregor // Create the AST unit. 1891e2778999SDylan Noblesmith OwningPtr<ASTUnit> AST; 1892aa21cc40SDouglas Gregor AST.reset(new ASTUnit(false)); 1893345c1bcbSDouglas Gregor ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); 1894aa21cc40SDouglas Gregor AST->Diagnostics = Diags; 1895aa21cc40SDouglas Gregor AST->OnlyLocalDecls = OnlyLocalDecls; 189644c6ee77SDouglas Gregor AST->CaptureDiagnostics = CaptureDiagnostics; 189769f74f80SDouglas Gregor AST->TUKind = TUKind; 1898b14904c4SDouglas Gregor AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; 18993292d06aSDmitri Gribenko AST->IncludeBriefCommentsInCodeCompletion 19003292d06aSDmitri Gribenko = IncludeBriefCommentsInCodeCompletion; 19015e14d39aSTed Kremenek AST->Invocation = CI; 19026d7833f1SArgyrios Kyrtzidis AST->UserFilesAreVolatile = UserFilesAreVolatile; 1903aa21cc40SDouglas Gregor 19044422bfeaSTed Kremenek // Recover resources if we crash before exiting this method. 1905022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> 1906022a4904STed Kremenek ASTUnitCleanup(AST.get()); 19079c902b55SDavid Blaikie llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, 19089c902b55SDavid Blaikie llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > 1909022a4904STed Kremenek DiagCleanup(Diags.getPtr()); 19104422bfeaSTed Kremenek 19117bb8af61SDouglas Gregor return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take(); 1912764c0820SDaniel Dunbar } 191355a17b66SDaniel Dunbar 191455a17b66SDaniel Dunbar ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, 191555a17b66SDaniel Dunbar const char **ArgEnd, 1916c95d8192SDylan Noblesmith IntrusiveRefCntPtr<DiagnosticsEngine> Diags, 19170e62c1ccSChris Lattner StringRef ResourceFilesPath, 191855a17b66SDaniel Dunbar bool OnlyLocalDecls, 191944c6ee77SDouglas Gregor bool CaptureDiagnostics, 1920aa98ed9aSDouglas Gregor RemappedFile *RemappedFiles, 192133cdd810SDouglas Gregor unsigned NumRemappedFiles, 192297d3a38cSArgyrios Kyrtzidis bool RemappedFilesKeepOriginalName, 1923028d3e4dSDouglas Gregor bool PrecompilePreamble, 192469f74f80SDouglas Gregor TranslationUnitKind TUKind, 19254a280ff4SArgyrios Kyrtzidis bool CacheCodeCompletionResults, 19263292d06aSDmitri Gribenko bool IncludeBriefCommentsInCodeCompletion, 1927ac1cc934SArgyrios Kyrtzidis bool AllowPCHWithCompilerErrors, 19286e92251fSErik Verbruggen bool SkipFunctionBodies, 19296d7833f1SArgyrios Kyrtzidis bool UserFilesAreVolatile, 1930ac1cc934SArgyrios Kyrtzidis OwningPtr<ASTUnit> *ErrAST) { 19317f95d26eSDouglas Gregor if (!Diags.getPtr()) { 1932d03e823fSDouglas Gregor // No diagnostics engine was provided, so create our own diagnostics object 1933d03e823fSDouglas Gregor // with the default options. 1934d03e823fSDouglas Gregor DiagnosticOptions DiagOpts; 1935345c1bcbSDouglas Gregor Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin, 1936345c1bcbSDouglas Gregor ArgBegin); 1937d03e823fSDouglas Gregor } 1938d03e823fSDouglas Gregor 19390e62c1ccSChris Lattner SmallVector<StoredDiagnostic, 4> StoredDiagnostics; 19407bb8af61SDouglas Gregor 1941c95d8192SDylan Noblesmith IntrusiveRefCntPtr<CompilerInvocation> CI; 194244c6ee77SDouglas Gregor 19437bb8af61SDouglas Gregor { 1944925296b4SDouglas Gregor 194544c6ee77SDouglas Gregor CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, 19467bb8af61SDouglas Gregor StoredDiagnostics); 19477bb8af61SDouglas Gregor 19485cf423ecSArgyrios Kyrtzidis CI = clang::createInvocationFromCommandLine( 1949717d7eddSFrits van Bommel llvm::makeArrayRef(ArgBegin, ArgEnd), 1950f606b82eSArgyrios Kyrtzidis Diags); 1951f606b82eSArgyrios Kyrtzidis if (!CI) 1952bc1f48f6SArgyrios Kyrtzidis return 0; 1953bc1f48f6SArgyrios Kyrtzidis } 1954bc1f48f6SArgyrios Kyrtzidis 1955aa98ed9aSDouglas Gregor // Override any files that need remapping 195611e6f0a6SArgyrios Kyrtzidis for (unsigned I = 0; I != NumRemappedFiles; ++I) { 195711e6f0a6SArgyrios Kyrtzidis FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; 195811e6f0a6SArgyrios Kyrtzidis if (const llvm::MemoryBuffer * 195911e6f0a6SArgyrios Kyrtzidis memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { 196011e6f0a6SArgyrios Kyrtzidis CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, memBuf); 196111e6f0a6SArgyrios Kyrtzidis } else { 196211e6f0a6SArgyrios Kyrtzidis const char *fname = fileOrBuf.get<const char *>(); 196311e6f0a6SArgyrios Kyrtzidis CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname); 196411e6f0a6SArgyrios Kyrtzidis } 196511e6f0a6SArgyrios Kyrtzidis } 19664a280ff4SArgyrios Kyrtzidis PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); 19674a280ff4SArgyrios Kyrtzidis PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; 19684a280ff4SArgyrios Kyrtzidis PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; 1969aa98ed9aSDouglas Gregor 1970a5a166d0SDaniel Dunbar // Override the resources path. 19716b03ecefSDaniel Dunbar CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; 197255a17b66SDaniel Dunbar 19736e92251fSErik Verbruggen CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies; 19746e92251fSErik Verbruggen 19757bb8af61SDouglas Gregor // Create the AST unit. 1976e2778999SDylan Noblesmith OwningPtr<ASTUnit> AST; 19777bb8af61SDouglas Gregor AST.reset(new ASTUnit(false)); 1978345c1bcbSDouglas Gregor ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics); 19797bb8af61SDouglas Gregor AST->Diagnostics = Diags; 198025047602STed Kremenek Diags = 0; // Zero out now to ease cleanup during crash recovery. 1981c30dcecbSAnders Carlsson AST->FileSystemOpts = CI->getFileSystemOpts(); 19825e14d39aSTed Kremenek AST->FileMgr = new FileManager(AST->FileSystemOpts); 19837bb8af61SDouglas Gregor AST->OnlyLocalDecls = OnlyLocalDecls; 198444c6ee77SDouglas Gregor AST->CaptureDiagnostics = CaptureDiagnostics; 198569f74f80SDouglas Gregor AST->TUKind = TUKind; 19867bb8af61SDouglas Gregor AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; 19873292d06aSDmitri Gribenko AST->IncludeBriefCommentsInCodeCompletion 19883292d06aSDmitri Gribenko = IncludeBriefCommentsInCodeCompletion; 19896d7833f1SArgyrios Kyrtzidis AST->UserFilesAreVolatile = UserFilesAreVolatile; 19907bb8af61SDouglas Gregor AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); 19917bb8af61SDouglas Gregor AST->StoredDiagnostics.swap(StoredDiagnostics); 19925e14d39aSTed Kremenek AST->Invocation = CI; 199325047602STed Kremenek CI = 0; // Zero out now to ease cleanup during crash recovery. 19944422bfeaSTed Kremenek 19954422bfeaSTed Kremenek // Recover resources if we crash before exiting this method. 1996022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> 1997022a4904STed Kremenek ASTUnitCleanup(AST.get()); 19984422bfeaSTed Kremenek 1999ac1cc934SArgyrios Kyrtzidis if (AST->LoadFromCompilerInvocation(PrecompilePreamble)) { 2000ac1cc934SArgyrios Kyrtzidis // Some error occurred, if caller wants to examine diagnostics, pass it the 2001ac1cc934SArgyrios Kyrtzidis // ASTUnit. 2002ac1cc934SArgyrios Kyrtzidis if (ErrAST) { 2003ac1cc934SArgyrios Kyrtzidis AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); 2004ac1cc934SArgyrios Kyrtzidis ErrAST->swap(AST); 2005ac1cc934SArgyrios Kyrtzidis } 2006ac1cc934SArgyrios Kyrtzidis return 0; 2007ac1cc934SArgyrios Kyrtzidis } 2008ac1cc934SArgyrios Kyrtzidis 2009ac1cc934SArgyrios Kyrtzidis return AST.take(); 201055a17b66SDaniel Dunbar } 2011aa21cc40SDouglas Gregor 2012aa21cc40SDouglas Gregor bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { 20135e14d39aSTed Kremenek if (!Invocation) 2014aa21cc40SDouglas Gregor return true; 2015aa21cc40SDouglas Gregor 2016e54568d6SArgyrios Kyrtzidis clearFileLevelDecls(); 2017e54568d6SArgyrios Kyrtzidis 201816896c45SDouglas Gregor SimpleTimer ParsingTimer(WantTiming); 201916896c45SDouglas Gregor ParsingTimer.setOutput("Reparsing " + getMainFileName()); 202015ba0b34SDouglas Gregor 20210e11955cSDouglas Gregor // Remap files. 20227b02b583SDouglas Gregor PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); 2023606c4ac3SDouglas Gregor PPOpts.DisableStatCache = true; 20247b02b583SDouglas Gregor for (PreprocessorOptions::remapped_file_buffer_iterator 20257b02b583SDouglas Gregor R = PPOpts.remapped_file_buffer_begin(), 20267b02b583SDouglas Gregor REnd = PPOpts.remapped_file_buffer_end(); 20277b02b583SDouglas Gregor R != REnd; 20287b02b583SDouglas Gregor ++R) { 20297b02b583SDouglas Gregor delete R->second; 20307b02b583SDouglas Gregor } 20310e11955cSDouglas Gregor Invocation->getPreprocessorOpts().clearRemappedFiles(); 203211e6f0a6SArgyrios Kyrtzidis for (unsigned I = 0; I != NumRemappedFiles; ++I) { 203311e6f0a6SArgyrios Kyrtzidis FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; 203411e6f0a6SArgyrios Kyrtzidis if (const llvm::MemoryBuffer * 203511e6f0a6SArgyrios Kyrtzidis memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { 20360e11955cSDouglas Gregor Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, 203711e6f0a6SArgyrios Kyrtzidis memBuf); 203811e6f0a6SArgyrios Kyrtzidis } else { 203911e6f0a6SArgyrios Kyrtzidis const char *fname = fileOrBuf.get<const char *>(); 204011e6f0a6SArgyrios Kyrtzidis Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, 204111e6f0a6SArgyrios Kyrtzidis fname); 204211e6f0a6SArgyrios Kyrtzidis } 204311e6f0a6SArgyrios Kyrtzidis } 20440e11955cSDouglas Gregor 2045bb420abdSDouglas Gregor // If we have a preamble file lying around, or if we might try to 2046bb420abdSDouglas Gregor // build a precompiled preamble, do so now. 20476481ef1fSDouglas Gregor llvm::MemoryBuffer *OverrideMainBuffer = 0; 204806b4f919STed Kremenek if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0) 2049b97b666cSDouglas Gregor OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation); 20504dde7498SDouglas Gregor 2051aa21cc40SDouglas Gregor // Clear out the diagnostics state. 2052aa21cc40SDouglas Gregor getDiagnostics().Reset(); 205336e3b5c7SDouglas Gregor ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); 2054462ff35dSArgyrios Kyrtzidis if (OverrideMainBuffer) 2055462ff35dSArgyrios Kyrtzidis getDiagnostics().setNumWarnings(NumWarningsInPreamble); 2056aa21cc40SDouglas Gregor 20574dde7498SDouglas Gregor // Parse the sources 20586481ef1fSDouglas Gregor bool Result = Parse(OverrideMainBuffer); 2059df7a79a9SDouglas Gregor 20603689337cSArgyrios Kyrtzidis // If we're caching global code-completion results, and the top-level 20613689337cSArgyrios Kyrtzidis // declarations have changed, clear out the code-completion cache. 20623689337cSArgyrios Kyrtzidis if (!Result && ShouldCacheCodeCompletionResults && 20633689337cSArgyrios Kyrtzidis CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue) 20643689337cSArgyrios Kyrtzidis CacheCodeCompletionResults(); 20653689337cSArgyrios Kyrtzidis 20669d7c0fefSArgyrios Kyrtzidis // We now need to clear out the completion info related to this translation 20679d7c0fefSArgyrios Kyrtzidis // unit; it'll be recreated if necessary. 20689d7c0fefSArgyrios Kyrtzidis CCTUInfo.reset(); 20693f35bb2dSDouglas Gregor 20704dde7498SDouglas Gregor return Result; 2071aa21cc40SDouglas Gregor } 20728e984da8SDouglas Gregor 2073b14904c4SDouglas Gregor //----------------------------------------------------------------------------// 2074b14904c4SDouglas Gregor // Code completion 2075b14904c4SDouglas Gregor //----------------------------------------------------------------------------// 2076b14904c4SDouglas Gregor 2077b14904c4SDouglas Gregor namespace { 2078b14904c4SDouglas Gregor /// \brief Code completion consumer that combines the cached code-completion 2079b14904c4SDouglas Gregor /// results from an ASTUnit with the code-completion results provided to it, 2080b14904c4SDouglas Gregor /// then passes the result on to 2081b14904c4SDouglas Gregor class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer { 2082697cc9e6SRichard Smith uint64_t NormalContexts; 2083b14904c4SDouglas Gregor ASTUnit &AST; 2084b14904c4SDouglas Gregor CodeCompleteConsumer &Next; 2085b14904c4SDouglas Gregor 2086b14904c4SDouglas Gregor public: 2087b14904c4SDouglas Gregor AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next, 20883292d06aSDmitri Gribenko const CodeCompleteOptions &CodeCompleteOpts) 20893292d06aSDmitri Gribenko : CodeCompleteConsumer(CodeCompleteOpts, Next.isOutputBinary()), 20903292d06aSDmitri Gribenko AST(AST), Next(Next) 2091b14904c4SDouglas Gregor { 2092b14904c4SDouglas Gregor // Compute the set of contexts in which we will look when we don't have 2093b14904c4SDouglas Gregor // any information about the specific context. 2094b14904c4SDouglas Gregor NormalContexts 2095697cc9e6SRichard Smith = (1LL << CodeCompletionContext::CCC_TopLevel) 2096697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCInterface) 2097697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCImplementation) 2098697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCIvarList) 2099697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Statement) 2100697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Expression) 2101697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) 2102697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_DotMemberAccess) 2103697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ArrowMemberAccess) 2104697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCPropertyAccess) 2105697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ObjCProtocolName) 2106697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) 2107697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_Recovery); 2108b14904c4SDouglas Gregor 2109bbafb8a7SDavid Blaikie if (AST.getASTContext().getLangOpts().CPlusPlus) 2110697cc9e6SRichard Smith NormalContexts |= (1LL << CodeCompletionContext::CCC_EnumTag) 2111697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_UnionTag) 2112697cc9e6SRichard Smith | (1LL << CodeCompletionContext::CCC_ClassOrStructTag); 2113b14904c4SDouglas Gregor } 2114b14904c4SDouglas Gregor 2115b14904c4SDouglas Gregor virtual void ProcessCodeCompleteResults(Sema &S, 2116b14904c4SDouglas Gregor CodeCompletionContext Context, 2117276321a9SJohn McCall CodeCompletionResult *Results, 2118d46cf182SDouglas Gregor unsigned NumResults); 2119d46cf182SDouglas Gregor 2120d46cf182SDouglas Gregor virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, 2121d46cf182SDouglas Gregor OverloadCandidate *Candidates, 2122d46cf182SDouglas Gregor unsigned NumCandidates) { 2123d46cf182SDouglas Gregor Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); 2124d46cf182SDouglas Gregor } 2125b278aafbSDouglas Gregor 2126bcbf46c7SDouglas Gregor virtual CodeCompletionAllocator &getAllocator() { 2127b278aafbSDouglas Gregor return Next.getAllocator(); 2128b278aafbSDouglas Gregor } 21299d7c0fefSArgyrios Kyrtzidis 21309d7c0fefSArgyrios Kyrtzidis virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() { 21319d7c0fefSArgyrios Kyrtzidis return Next.getCodeCompletionTUInfo(); 21329d7c0fefSArgyrios Kyrtzidis } 2133d46cf182SDouglas Gregor }; 2134d46cf182SDouglas Gregor } 2135d46cf182SDouglas Gregor 21366199f2d1SDouglas Gregor /// \brief Helper function that computes which global names are hidden by the 21376199f2d1SDouglas Gregor /// local code-completion results. 21386a15337dSTed Kremenek static void CalculateHiddenNames(const CodeCompletionContext &Context, 2139276321a9SJohn McCall CodeCompletionResult *Results, 21406199f2d1SDouglas Gregor unsigned NumResults, 21416199f2d1SDouglas Gregor ASTContext &Ctx, 21426a15337dSTed Kremenek llvm::StringSet<llvm::BumpPtrAllocator> &HiddenNames){ 21436199f2d1SDouglas Gregor bool OnlyTagNames = false; 21446199f2d1SDouglas Gregor switch (Context.getKind()) { 21450ac41389SDouglas Gregor case CodeCompletionContext::CCC_Recovery: 21466199f2d1SDouglas Gregor case CodeCompletionContext::CCC_TopLevel: 21476199f2d1SDouglas Gregor case CodeCompletionContext::CCC_ObjCInterface: 21486199f2d1SDouglas Gregor case CodeCompletionContext::CCC_ObjCImplementation: 21496199f2d1SDouglas Gregor case CodeCompletionContext::CCC_ObjCIvarList: 21506199f2d1SDouglas Gregor case CodeCompletionContext::CCC_ClassStructUnion: 21516199f2d1SDouglas Gregor case CodeCompletionContext::CCC_Statement: 21526199f2d1SDouglas Gregor case CodeCompletionContext::CCC_Expression: 21536199f2d1SDouglas Gregor case CodeCompletionContext::CCC_ObjCMessageReceiver: 21542132584dSDouglas Gregor case CodeCompletionContext::CCC_DotMemberAccess: 21552132584dSDouglas Gregor case CodeCompletionContext::CCC_ArrowMemberAccess: 21562132584dSDouglas Gregor case CodeCompletionContext::CCC_ObjCPropertyAccess: 21576199f2d1SDouglas Gregor case CodeCompletionContext::CCC_Namespace: 21586199f2d1SDouglas Gregor case CodeCompletionContext::CCC_Type: 2159c49f5b2fSDouglas Gregor case CodeCompletionContext::CCC_Name: 2160c49f5b2fSDouglas Gregor case CodeCompletionContext::CCC_PotentiallyQualifiedName: 21615e35d591SDouglas Gregor case CodeCompletionContext::CCC_ParenthesizedExpression: 21622c595adfSDouglas Gregor case CodeCompletionContext::CCC_ObjCInterfaceName: 21636199f2d1SDouglas Gregor break; 21646199f2d1SDouglas Gregor 21656199f2d1SDouglas Gregor case CodeCompletionContext::CCC_EnumTag: 21666199f2d1SDouglas Gregor case CodeCompletionContext::CCC_UnionTag: 21676199f2d1SDouglas Gregor case CodeCompletionContext::CCC_ClassOrStructTag: 21686199f2d1SDouglas Gregor OnlyTagNames = true; 21696199f2d1SDouglas Gregor break; 21706199f2d1SDouglas Gregor 21716199f2d1SDouglas Gregor case CodeCompletionContext::CCC_ObjCProtocolName: 217212785108SDouglas Gregor case CodeCompletionContext::CCC_MacroName: 217312785108SDouglas Gregor case CodeCompletionContext::CCC_MacroNameUse: 2174ec00a268SDouglas Gregor case CodeCompletionContext::CCC_PreprocessorExpression: 21750de55cecSDouglas Gregor case CodeCompletionContext::CCC_PreprocessorDirective: 2176ea14705cSDouglas Gregor case CodeCompletionContext::CCC_NaturalLanguage: 217767c692ccSDouglas Gregor case CodeCompletionContext::CCC_SelectorName: 217828c7843eSDouglas Gregor case CodeCompletionContext::CCC_TypeQualifiers: 21790ac41389SDouglas Gregor case CodeCompletionContext::CCC_Other: 21803a69eafaSDouglas Gregor case CodeCompletionContext::CCC_OtherWithMacros: 21812132584dSDouglas Gregor case CodeCompletionContext::CCC_ObjCInstanceMessage: 21822132584dSDouglas Gregor case CodeCompletionContext::CCC_ObjCClassMessage: 21832132584dSDouglas Gregor case CodeCompletionContext::CCC_ObjCCategoryName: 21840de55cecSDouglas Gregor // We're looking for nothing, or we're looking for names that cannot 21850de55cecSDouglas Gregor // be hidden. 21866199f2d1SDouglas Gregor return; 21876199f2d1SDouglas Gregor } 21886199f2d1SDouglas Gregor 2189276321a9SJohn McCall typedef CodeCompletionResult Result; 21906199f2d1SDouglas Gregor for (unsigned I = 0; I != NumResults; ++I) { 21916199f2d1SDouglas Gregor if (Results[I].Kind != Result::RK_Declaration) 21926199f2d1SDouglas Gregor continue; 21936199f2d1SDouglas Gregor 21946199f2d1SDouglas Gregor unsigned IDNS 21956199f2d1SDouglas Gregor = Results[I].Declaration->getUnderlyingDecl()->getIdentifierNamespace(); 21966199f2d1SDouglas Gregor 21976199f2d1SDouglas Gregor bool Hiding = false; 21986199f2d1SDouglas Gregor if (OnlyTagNames) 21996199f2d1SDouglas Gregor Hiding = (IDNS & Decl::IDNS_Tag); 22006199f2d1SDouglas Gregor else { 22016199f2d1SDouglas Gregor unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member | 22026199f2d1SDouglas Gregor Decl::IDNS_Namespace | Decl::IDNS_Ordinary | 22036199f2d1SDouglas Gregor Decl::IDNS_NonMemberOperator); 2204bbafb8a7SDavid Blaikie if (Ctx.getLangOpts().CPlusPlus) 22056199f2d1SDouglas Gregor HiddenIDNS |= Decl::IDNS_Tag; 22066199f2d1SDouglas Gregor Hiding = (IDNS & HiddenIDNS); 22076199f2d1SDouglas Gregor } 22086199f2d1SDouglas Gregor 22096199f2d1SDouglas Gregor if (!Hiding) 22106199f2d1SDouglas Gregor continue; 22116199f2d1SDouglas Gregor 22126199f2d1SDouglas Gregor DeclarationName Name = Results[I].Declaration->getDeclName(); 22136199f2d1SDouglas Gregor if (IdentifierInfo *Identifier = Name.getAsIdentifierInfo()) 22146199f2d1SDouglas Gregor HiddenNames.insert(Identifier->getName()); 22156199f2d1SDouglas Gregor else 22166199f2d1SDouglas Gregor HiddenNames.insert(Name.getAsString()); 22176199f2d1SDouglas Gregor } 22186199f2d1SDouglas Gregor } 22196199f2d1SDouglas Gregor 22206199f2d1SDouglas Gregor 2221d46cf182SDouglas Gregor void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, 2222d46cf182SDouglas Gregor CodeCompletionContext Context, 2223276321a9SJohn McCall CodeCompletionResult *Results, 2224b14904c4SDouglas Gregor unsigned NumResults) { 2225b14904c4SDouglas Gregor // Merge the results we were given with the results we cached. 2226b14904c4SDouglas Gregor bool AddedResult = false; 2227697cc9e6SRichard Smith uint64_t InContexts = 2228697cc9e6SRichard Smith Context.getKind() == CodeCompletionContext::CCC_Recovery 2229697cc9e6SRichard Smith ? NormalContexts : (1LL << Context.getKind()); 22306199f2d1SDouglas Gregor // Contains the set of names that are hidden by "local" completion results. 22316a15337dSTed Kremenek llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames; 2232276321a9SJohn McCall typedef CodeCompletionResult Result; 22330e62c1ccSChris Lattner SmallVector<Result, 8> AllResults; 2234b14904c4SDouglas Gregor for (ASTUnit::cached_completion_iterator 2235b14904c4SDouglas Gregor C = AST.cached_completion_begin(), 2236b14904c4SDouglas Gregor CEnd = AST.cached_completion_end(); 2237b14904c4SDouglas Gregor C != CEnd; ++C) { 2238b14904c4SDouglas Gregor // If the context we are in matches any of the contexts we are 2239b14904c4SDouglas Gregor // interested in, we'll add this result. 2240b14904c4SDouglas Gregor if ((C->ShowInContexts & InContexts) == 0) 2241b14904c4SDouglas Gregor continue; 2242b14904c4SDouglas Gregor 2243b14904c4SDouglas Gregor // If we haven't added any results previously, do so now. 2244b14904c4SDouglas Gregor if (!AddedResult) { 22456199f2d1SDouglas Gregor CalculateHiddenNames(Context, Results, NumResults, S.Context, 22466199f2d1SDouglas Gregor HiddenNames); 2247b14904c4SDouglas Gregor AllResults.insert(AllResults.end(), Results, Results + NumResults); 2248b14904c4SDouglas Gregor AddedResult = true; 2249b14904c4SDouglas Gregor } 2250b14904c4SDouglas Gregor 22516199f2d1SDouglas Gregor // Determine whether this global completion result is hidden by a local 22526199f2d1SDouglas Gregor // completion result. If so, skip it. 22536199f2d1SDouglas Gregor if (C->Kind != CXCursor_MacroDefinition && 22546199f2d1SDouglas Gregor HiddenNames.count(C->Completion->getTypedText())) 22556199f2d1SDouglas Gregor continue; 22566199f2d1SDouglas Gregor 22576e24033bSDouglas Gregor // Adjust priority based on similar type classes. 22586e24033bSDouglas Gregor unsigned Priority = C->Priority; 225912785108SDouglas Gregor CodeCompletionString *Completion = C->Completion; 22606e24033bSDouglas Gregor if (!Context.getPreferredType().isNull()) { 22616e24033bSDouglas Gregor if (C->Kind == CXCursor_MacroDefinition) { 22626e24033bSDouglas Gregor Priority = getMacroUsagePriority(C->Completion->getTypedText(), 2263bbafb8a7SDavid Blaikie S.getLangOpts(), 22646e24033bSDouglas Gregor Context.getPreferredType()->isAnyPointerType()); 2265b61c07acSDouglas Gregor } else if (C->Type) { 22666e24033bSDouglas Gregor CanQualType Expected 2267b61c07acSDouglas Gregor = S.Context.getCanonicalType( 2268b61c07acSDouglas Gregor Context.getPreferredType().getUnqualifiedType()); 22696e24033bSDouglas Gregor SimplifiedTypeClass ExpectedSTC = getSimplifiedTypeClass(Expected); 22706e24033bSDouglas Gregor if (ExpectedSTC == C->TypeClass) { 2271b61c07acSDouglas Gregor // We know this type is similar; check for an exact match. 2272b61c07acSDouglas Gregor llvm::StringMap<unsigned> &CachedCompletionTypes 2273b61c07acSDouglas Gregor = AST.getCachedCompletionTypes(); 2274b61c07acSDouglas Gregor llvm::StringMap<unsigned>::iterator Pos 2275b61c07acSDouglas Gregor = CachedCompletionTypes.find(QualType(Expected).getAsString()); 2276b61c07acSDouglas Gregor if (Pos != CachedCompletionTypes.end() && Pos->second == C->Type) 2277b61c07acSDouglas Gregor Priority /= CCF_ExactTypeMatch; 2278b61c07acSDouglas Gregor else 22796e24033bSDouglas Gregor Priority /= CCF_SimilarTypeMatch; 22806e24033bSDouglas Gregor } 22816e24033bSDouglas Gregor } 22826e24033bSDouglas Gregor } 22836e24033bSDouglas Gregor 228412785108SDouglas Gregor // Adjust the completion string, if required. 228512785108SDouglas Gregor if (C->Kind == CXCursor_MacroDefinition && 228612785108SDouglas Gregor Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) { 228712785108SDouglas Gregor // Create a new code-completion string that just contains the 228812785108SDouglas Gregor // macro name, without its arguments. 22899d7c0fefSArgyrios Kyrtzidis CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(), 22909d7c0fefSArgyrios Kyrtzidis CCP_CodePattern, C->Availability); 2291b278aafbSDouglas Gregor Builder.AddTypedTextChunk(C->Completion->getTypedText()); 22928850aa3fSDouglas Gregor Priority = CCP_CodePattern; 2293b278aafbSDouglas Gregor Completion = Builder.TakeString(); 229412785108SDouglas Gregor } 229512785108SDouglas Gregor 22965c8b1cd2SArgyrios Kyrtzidis AllResults.push_back(Result(Completion, Priority, C->Kind, 2297f757a12dSDouglas Gregor C->Availability)); 2298b14904c4SDouglas Gregor } 2299b14904c4SDouglas Gregor 2300b14904c4SDouglas Gregor // If we did not add any cached completion results, just forward the 2301b14904c4SDouglas Gregor // results we were given to the next consumer. 2302b14904c4SDouglas Gregor if (!AddedResult) { 2303b14904c4SDouglas Gregor Next.ProcessCodeCompleteResults(S, Context, Results, NumResults); 2304b14904c4SDouglas Gregor return; 2305b14904c4SDouglas Gregor } 2306b14904c4SDouglas Gregor 2307b14904c4SDouglas Gregor Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), 2308b14904c4SDouglas Gregor AllResults.size()); 2309b14904c4SDouglas Gregor } 2310b14904c4SDouglas Gregor 2311d46cf182SDouglas Gregor 2312d46cf182SDouglas Gregor 23130e62c1ccSChris Lattner void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, 23148e984da8SDouglas Gregor RemappedFile *RemappedFiles, 23158e984da8SDouglas Gregor unsigned NumRemappedFiles, 2316b68bc59aSDouglas Gregor bool IncludeMacros, 2317b68bc59aSDouglas Gregor bool IncludeCodePatterns, 23183292d06aSDmitri Gribenko bool IncludeBriefComments, 23198e984da8SDouglas Gregor CodeCompleteConsumer &Consumer, 23209c902b55SDavid Blaikie DiagnosticsEngine &Diag, LangOptions &LangOpts, 23218e984da8SDouglas Gregor SourceManager &SourceMgr, FileManager &FileMgr, 23220e62c1ccSChris Lattner SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, 23230e62c1ccSChris Lattner SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) { 23245e14d39aSTed Kremenek if (!Invocation) 23258e984da8SDouglas Gregor return; 23268e984da8SDouglas Gregor 232716896c45SDouglas Gregor SimpleTimer CompletionTimer(WantTiming); 2328f2e5a91fSBenjamin Kramer CompletionTimer.setOutput("Code completion @ " + File + ":" + 23290e62c1ccSChris Lattner Twine(Line) + ":" + Twine(Column)); 2330028d3e4dSDouglas Gregor 2331c95d8192SDylan Noblesmith IntrusiveRefCntPtr<CompilerInvocation> 23325e14d39aSTed Kremenek CCInvocation(new CompilerInvocation(*Invocation)); 23335e14d39aSTed Kremenek 23345e14d39aSTed Kremenek FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts(); 23353292d06aSDmitri Gribenko CodeCompleteOptions &CodeCompleteOpts = FrontendOpts.CodeCompleteOpts; 23365e14d39aSTed Kremenek PreprocessorOptions &PreprocessorOpts = CCInvocation->getPreprocessorOpts(); 23378e984da8SDouglas Gregor 23383292d06aSDmitri Gribenko CodeCompleteOpts.IncludeMacros = IncludeMacros && 23393292d06aSDmitri Gribenko CachedCompletionResults.empty(); 23403292d06aSDmitri Gribenko CodeCompleteOpts.IncludeCodePatterns = IncludeCodePatterns; 23413292d06aSDmitri Gribenko CodeCompleteOpts.IncludeGlobals = CachedCompletionResults.empty(); 23423292d06aSDmitri Gribenko CodeCompleteOpts.IncludeBriefComments = IncludeBriefComments; 23433292d06aSDmitri Gribenko 23443292d06aSDmitri Gribenko assert(IncludeBriefComments == this->IncludeBriefCommentsInCodeCompletion); 23453292d06aSDmitri Gribenko 23468e984da8SDouglas Gregor FrontendOpts.CodeCompletionAt.FileName = File; 23478e984da8SDouglas Gregor FrontendOpts.CodeCompletionAt.Line = Line; 23488e984da8SDouglas Gregor FrontendOpts.CodeCompletionAt.Column = Column; 23498e984da8SDouglas Gregor 23508e984da8SDouglas Gregor // Set the language options appropriately. 23518cf47df7STed Kremenek LangOpts = *CCInvocation->getLangOpts(); 23528e984da8SDouglas Gregor 2353e2778999SDylan Noblesmith OwningPtr<CompilerInstance> Clang(new CompilerInstance()); 235484de4a17STed Kremenek 235584de4a17STed Kremenek // Recover resources if we crash before exiting this method. 2356022a4904STed Kremenek llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> 2357022a4904STed Kremenek CICleanup(Clang.get()); 235884de4a17STed Kremenek 23595e14d39aSTed Kremenek Clang->setInvocation(&*CCInvocation); 236032fbe312SDouglas Gregor OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; 23618e984da8SDouglas Gregor 23628e984da8SDouglas Gregor // Set up diagnostics, capturing any diagnostics produced. 236384de4a17STed Kremenek Clang->setDiagnostics(&Diag); 23645e14d39aSTed Kremenek ProcessWarningOptions(Diag, CCInvocation->getDiagnosticOpts()); 23658e984da8SDouglas Gregor CaptureDroppedDiagnostics Capture(true, 236684de4a17STed Kremenek Clang->getDiagnostics(), 23678e984da8SDouglas Gregor StoredDiagnostics); 23688e984da8SDouglas Gregor 23698e984da8SDouglas Gregor // Create the target instance. 237084de4a17STed Kremenek Clang->getTargetOpts().Features = TargetFeatures; 237184de4a17STed Kremenek Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), 237284de4a17STed Kremenek Clang->getTargetOpts())); 237384de4a17STed Kremenek if (!Clang->hasTarget()) { 23745e14d39aSTed Kremenek Clang->setInvocation(0); 23752dd19f1dSDouglas Gregor return; 23768e984da8SDouglas Gregor } 23778e984da8SDouglas Gregor 23788e984da8SDouglas Gregor // Inform the target of the language options. 23798e984da8SDouglas Gregor // 23808e984da8SDouglas Gregor // FIXME: We shouldn't need to do this, the target should be immutable once 23818e984da8SDouglas Gregor // created. This complexity should be lifted elsewhere. 238284de4a17STed Kremenek Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); 23838e984da8SDouglas Gregor 238484de4a17STed Kremenek assert(Clang->getFrontendOpts().Inputs.size() == 1 && 23858e984da8SDouglas Gregor "Invocation must have exactly one source file!"); 238632fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && 23878e984da8SDouglas Gregor "FIXME: AST inputs not yet supported here!"); 238832fbe312SDouglas Gregor assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && 23898e984da8SDouglas Gregor "IR inputs not support here!"); 23908e984da8SDouglas Gregor 23918e984da8SDouglas Gregor 23928e984da8SDouglas Gregor // Use the source and file managers that we were given. 239384de4a17STed Kremenek Clang->setFileManager(&FileMgr); 239484de4a17STed Kremenek Clang->setSourceManager(&SourceMgr); 23958e984da8SDouglas Gregor 23968e984da8SDouglas Gregor // Remap files. 23978e984da8SDouglas Gregor PreprocessorOpts.clearRemappedFiles(); 2398d8a5dba9SDouglas Gregor PreprocessorOpts.RetainRemappedFileBuffers = true; 2399b97b666cSDouglas Gregor for (unsigned I = 0; I != NumRemappedFiles; ++I) { 240011e6f0a6SArgyrios Kyrtzidis FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; 240111e6f0a6SArgyrios Kyrtzidis if (const llvm::MemoryBuffer * 240211e6f0a6SArgyrios Kyrtzidis memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { 240311e6f0a6SArgyrios Kyrtzidis PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, memBuf); 240411e6f0a6SArgyrios Kyrtzidis OwnedBuffers.push_back(memBuf); 240511e6f0a6SArgyrios Kyrtzidis } else { 240611e6f0a6SArgyrios Kyrtzidis const char *fname = fileOrBuf.get<const char *>(); 240711e6f0a6SArgyrios Kyrtzidis PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, fname); 240811e6f0a6SArgyrios Kyrtzidis } 2409b97b666cSDouglas Gregor } 24108e984da8SDouglas Gregor 2411b14904c4SDouglas Gregor // Use the code completion consumer we were given, but adding any cached 2412b14904c4SDouglas Gregor // code-completion results. 2413e9186e6dSDouglas Gregor AugmentedCodeCompleteConsumer *AugmentedConsumer 24143292d06aSDmitri Gribenko = new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts); 241584de4a17STed Kremenek Clang->setCodeCompletionConsumer(AugmentedConsumer); 24168e984da8SDouglas Gregor 24176e92251fSErik Verbruggen Clang->getFrontendOpts().SkipFunctionBodies = true; 24186e92251fSErik Verbruggen 2419028d3e4dSDouglas Gregor // If we have a precompiled preamble, try to use it. We only allow 2420028d3e4dSDouglas Gregor // the use of the precompiled preamble if we're if the completion 2421028d3e4dSDouglas Gregor // point is within the main file, after the end of the precompiled 2422028d3e4dSDouglas Gregor // preamble. 2423028d3e4dSDouglas Gregor llvm::MemoryBuffer *OverrideMainBuffer = 0; 242406b4f919STed Kremenek if (!getPreambleFile(this).empty()) { 2425028d3e4dSDouglas Gregor using llvm::sys::FileStatus; 2426028d3e4dSDouglas Gregor llvm::sys::PathWithStatus CompleteFilePath(File); 2427028d3e4dSDouglas Gregor llvm::sys::PathWithStatus MainPath(OriginalSourceFile); 2428028d3e4dSDouglas Gregor if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus()) 2429028d3e4dSDouglas Gregor if (const FileStatus *MainStatus = MainPath.getFileStatus()) 2430a3deaeebSArgyrios Kyrtzidis if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID() && 2431a3deaeebSArgyrios Kyrtzidis Line > 1) 2432b97b666cSDouglas Gregor OverrideMainBuffer 24335e14d39aSTed Kremenek = getMainBufferWithPrecompiledPreamble(*CCInvocation, false, 24348e817b6aSDouglas Gregor Line - 1); 2435028d3e4dSDouglas Gregor } 2436028d3e4dSDouglas Gregor 2437028d3e4dSDouglas Gregor // If the main file has been overridden due to the use of a preamble, 2438028d3e4dSDouglas Gregor // make that override happen and introduce the preamble. 2439606c4ac3SDouglas Gregor PreprocessorOpts.DisableStatCache = true; 24407bb8af61SDouglas Gregor StoredDiagnostics.insert(StoredDiagnostics.end(), 2441067cbfa2SArgyrios Kyrtzidis stored_diag_begin(), 2442067cbfa2SArgyrios Kyrtzidis stored_diag_afterDriver_begin()); 2443028d3e4dSDouglas Gregor if (OverrideMainBuffer) { 2444028d3e4dSDouglas Gregor PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); 2445028d3e4dSDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); 2446028d3e4dSDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.second 2447028d3e4dSDouglas Gregor = PreambleEndsAtStartOfLine; 244806b4f919STed Kremenek PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); 2449028d3e4dSDouglas Gregor PreprocessorOpts.DisablePCHValidation = true; 2450028d3e4dSDouglas Gregor 2451b97b666cSDouglas Gregor OwnedBuffers.push_back(OverrideMainBuffer); 24527b02b583SDouglas Gregor } else { 24537b02b583SDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.first = 0; 24547b02b583SDouglas Gregor PreprocessorOpts.PrecompiledPreambleBytes.second = false; 2455028d3e4dSDouglas Gregor } 2456028d3e4dSDouglas Gregor 2457998caeadSDouglas Gregor // Disable the preprocessing record 2458998caeadSDouglas Gregor PreprocessorOpts.DetailedRecord = false; 2459998caeadSDouglas Gregor 2460e2778999SDylan Noblesmith OwningPtr<SyntaxOnlyAction> Act; 24618e984da8SDouglas Gregor Act.reset(new SyntaxOnlyAction); 246232fbe312SDouglas Gregor if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { 2463925296b4SDouglas Gregor if (OverrideMainBuffer) { 246406b4f919STed Kremenek std::string ModName = getPreambleFile(this); 2465925296b4SDouglas Gregor TranslateStoredDiagnostics(Clang->getModuleManager(), ModName, 2466925296b4SDouglas Gregor getSourceManager(), PreambleDiagnostics, 2467925296b4SDouglas Gregor StoredDiagnostics); 2468925296b4SDouglas Gregor } 24698e984da8SDouglas Gregor Act->Execute(); 24708e984da8SDouglas Gregor Act->EndSourceFile(); 24718e984da8SDouglas Gregor } 247238bacf34SArgyrios Kyrtzidis 247338bacf34SArgyrios Kyrtzidis checkAndSanitizeDiags(StoredDiagnostics, getSourceManager()); 24748e984da8SDouglas Gregor } 2475e9386680SDouglas Gregor 247639a76387SArgyrios Kyrtzidis bool ASTUnit::Save(StringRef File) { 247755e75574SArgyrios Kyrtzidis // Write to a temporary file and later rename it to the actual file, to avoid 247855e75574SArgyrios Kyrtzidis // possible race conditions. 24792c1dd271SDylan Noblesmith SmallString<128> TempPath; 248008a2bfd2SArgyrios Kyrtzidis TempPath = File; 248108a2bfd2SArgyrios Kyrtzidis TempPath += "-%%%%%%%%"; 248208a2bfd2SArgyrios Kyrtzidis int fd; 248308a2bfd2SArgyrios Kyrtzidis if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, 248408a2bfd2SArgyrios Kyrtzidis /*makeAbsolute=*/false)) 248539a76387SArgyrios Kyrtzidis return true; 248655e75574SArgyrios Kyrtzidis 2487e9386680SDouglas Gregor // FIXME: Can we somehow regenerate the stat cache here, or do we need to 2488e9386680SDouglas Gregor // unconditionally create a stat cache when we parse the file? 248908a2bfd2SArgyrios Kyrtzidis llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true); 2490e9386680SDouglas Gregor 249135dcda79SArgyrios Kyrtzidis serialize(Out); 249235dcda79SArgyrios Kyrtzidis Out.close(); 2493eeea16a0SArgyrios Kyrtzidis if (Out.has_error()) { 2494eeea16a0SArgyrios Kyrtzidis Out.clear_error(); 249539a76387SArgyrios Kyrtzidis return true; 2496eeea16a0SArgyrios Kyrtzidis } 249755e75574SArgyrios Kyrtzidis 249865e025caSRafael Espindola if (llvm::sys::fs::rename(TempPath.str(), File)) { 249955e75574SArgyrios Kyrtzidis bool exists; 250055e75574SArgyrios Kyrtzidis llvm::sys::fs::remove(TempPath.str(), exists); 250139a76387SArgyrios Kyrtzidis return true; 250255e75574SArgyrios Kyrtzidis } 250355e75574SArgyrios Kyrtzidis 250439a76387SArgyrios Kyrtzidis return false; 250535dcda79SArgyrios Kyrtzidis } 250635dcda79SArgyrios Kyrtzidis 25070e62c1ccSChris Lattner bool ASTUnit::serialize(raw_ostream &OS) { 25084a280ff4SArgyrios Kyrtzidis bool hasErrors = getDiagnostics().hasErrorOccurred(); 250935dcda79SArgyrios Kyrtzidis 25109a96386eSDaniel Dunbar SmallString<128> Buffer; 2511e9386680SDouglas Gregor llvm::BitstreamWriter Stream(Buffer); 251255c0ad57SSebastian Redl ASTWriter Writer(Stream); 25134a69c2e6SDouglas Gregor // FIXME: Handle modules 25144a280ff4SArgyrios Kyrtzidis Writer.WriteAST(getSema(), 0, std::string(), 0, "", hasErrors); 2515e9386680SDouglas Gregor 2516e9386680SDouglas Gregor // Write the generated bitstream to "Out". 25172dd19f1dSDouglas Gregor if (!Buffer.empty()) 251835dcda79SArgyrios Kyrtzidis OS.write((char *)&Buffer.front(), Buffer.size()); 251935dcda79SArgyrios Kyrtzidis 252035dcda79SArgyrios Kyrtzidis return false; 2521e9386680SDouglas Gregor } 2522925296b4SDouglas Gregor 2523925296b4SDouglas Gregor typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap; 2524925296b4SDouglas Gregor 2525925296b4SDouglas Gregor static void TranslateSLoc(SourceLocation &L, SLocRemap &Remap) { 2526925296b4SDouglas Gregor unsigned Raw = L.getRawEncoding(); 2527925296b4SDouglas Gregor const unsigned MacroBit = 1U << 31; 2528925296b4SDouglas Gregor L = SourceLocation::getFromRawEncoding((Raw & MacroBit) | 2529925296b4SDouglas Gregor ((Raw & ~MacroBit) + Remap.find(Raw & ~MacroBit)->second)); 2530925296b4SDouglas Gregor } 2531925296b4SDouglas Gregor 2532925296b4SDouglas Gregor void ASTUnit::TranslateStoredDiagnostics( 2533925296b4SDouglas Gregor ASTReader *MMan, 25340e62c1ccSChris Lattner StringRef ModName, 2535925296b4SDouglas Gregor SourceManager &SrcMgr, 25360e62c1ccSChris Lattner const SmallVectorImpl<StoredDiagnostic> &Diags, 25370e62c1ccSChris Lattner SmallVectorImpl<StoredDiagnostic> &Out) { 2538925296b4SDouglas Gregor // The stored diagnostic has the old source manager in it; update 2539925296b4SDouglas Gregor // the locations to refer into the new source manager. We also need to remap 2540925296b4SDouglas Gregor // all the locations to the new view. This includes the diag location, any 2541925296b4SDouglas Gregor // associated source ranges, and the source ranges of associated fix-its. 2542925296b4SDouglas Gregor // FIXME: There should be a cleaner way to do this. 2543925296b4SDouglas Gregor 25440e62c1ccSChris Lattner SmallVector<StoredDiagnostic, 4> Result; 2545925296b4SDouglas Gregor Result.reserve(Diags.size()); 2546925296b4SDouglas Gregor assert(MMan && "Don't have a module manager"); 2547de3ef502SDouglas Gregor serialization::ModuleFile *Mod = MMan->ModuleMgr.lookup(ModName); 2548925296b4SDouglas Gregor assert(Mod && "Don't have preamble module"); 2549925296b4SDouglas Gregor SLocRemap &Remap = Mod->SLocRemap; 2550925296b4SDouglas Gregor for (unsigned I = 0, N = Diags.size(); I != N; ++I) { 2551925296b4SDouglas Gregor // Rebuild the StoredDiagnostic. 2552925296b4SDouglas Gregor const StoredDiagnostic &SD = Diags[I]; 2553925296b4SDouglas Gregor SourceLocation L = SD.getLocation(); 2554925296b4SDouglas Gregor TranslateSLoc(L, Remap); 2555925296b4SDouglas Gregor FullSourceLoc Loc(L, SrcMgr); 2556925296b4SDouglas Gregor 25570e62c1ccSChris Lattner SmallVector<CharSourceRange, 4> Ranges; 2558925296b4SDouglas Gregor Ranges.reserve(SD.range_size()); 2559925296b4SDouglas Gregor for (StoredDiagnostic::range_iterator I = SD.range_begin(), 2560925296b4SDouglas Gregor E = SD.range_end(); 2561925296b4SDouglas Gregor I != E; ++I) { 2562925296b4SDouglas Gregor SourceLocation BL = I->getBegin(); 2563925296b4SDouglas Gregor TranslateSLoc(BL, Remap); 2564925296b4SDouglas Gregor SourceLocation EL = I->getEnd(); 2565925296b4SDouglas Gregor TranslateSLoc(EL, Remap); 2566925296b4SDouglas Gregor Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange())); 2567925296b4SDouglas Gregor } 2568925296b4SDouglas Gregor 25690e62c1ccSChris Lattner SmallVector<FixItHint, 2> FixIts; 2570925296b4SDouglas Gregor FixIts.reserve(SD.fixit_size()); 2571925296b4SDouglas Gregor for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(), 2572925296b4SDouglas Gregor E = SD.fixit_end(); 2573925296b4SDouglas Gregor I != E; ++I) { 2574925296b4SDouglas Gregor FixIts.push_back(FixItHint()); 2575925296b4SDouglas Gregor FixItHint &FH = FixIts.back(); 2576925296b4SDouglas Gregor FH.CodeToInsert = I->CodeToInsert; 2577925296b4SDouglas Gregor SourceLocation BL = I->RemoveRange.getBegin(); 2578925296b4SDouglas Gregor TranslateSLoc(BL, Remap); 2579925296b4SDouglas Gregor SourceLocation EL = I->RemoveRange.getEnd(); 2580925296b4SDouglas Gregor TranslateSLoc(EL, Remap); 2581925296b4SDouglas Gregor FH.RemoveRange = CharSourceRange(SourceRange(BL, EL), 2582925296b4SDouglas Gregor I->RemoveRange.isTokenRange()); 2583925296b4SDouglas Gregor } 2584925296b4SDouglas Gregor 2585925296b4SDouglas Gregor Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(), 2586925296b4SDouglas Gregor SD.getMessage(), Loc, Ranges, FixIts)); 2587925296b4SDouglas Gregor } 2588925296b4SDouglas Gregor Result.swap(Out); 2589925296b4SDouglas Gregor } 25907c06d866SArgyrios Kyrtzidis 2591e54568d6SArgyrios Kyrtzidis static inline bool compLocDecl(std::pair<unsigned, Decl *> L, 2592e54568d6SArgyrios Kyrtzidis std::pair<unsigned, Decl *> R) { 2593e54568d6SArgyrios Kyrtzidis return L.first < R.first; 2594e54568d6SArgyrios Kyrtzidis } 2595e54568d6SArgyrios Kyrtzidis 2596e54568d6SArgyrios Kyrtzidis void ASTUnit::addFileLevelDecl(Decl *D) { 2597e54568d6SArgyrios Kyrtzidis assert(D); 259861d63d0fSDouglas Gregor 259961d63d0fSDouglas Gregor // We only care about local declarations. 260061d63d0fSDouglas Gregor if (D->isFromASTFile()) 260161d63d0fSDouglas Gregor return; 2602e54568d6SArgyrios Kyrtzidis 2603e54568d6SArgyrios Kyrtzidis SourceManager &SM = *SourceMgr; 2604e54568d6SArgyrios Kyrtzidis SourceLocation Loc = D->getLocation(); 2605e54568d6SArgyrios Kyrtzidis if (Loc.isInvalid() || !SM.isLocalSourceLocation(Loc)) 2606e54568d6SArgyrios Kyrtzidis return; 2607e54568d6SArgyrios Kyrtzidis 2608e54568d6SArgyrios Kyrtzidis // We only keep track of the file-level declarations of each file. 2609e54568d6SArgyrios Kyrtzidis if (!D->getLexicalDeclContext()->isFileContext()) 2610e54568d6SArgyrios Kyrtzidis return; 2611e54568d6SArgyrios Kyrtzidis 2612e54568d6SArgyrios Kyrtzidis SourceLocation FileLoc = SM.getFileLoc(Loc); 2613e54568d6SArgyrios Kyrtzidis assert(SM.isLocalSourceLocation(FileLoc)); 2614e54568d6SArgyrios Kyrtzidis FileID FID; 2615e54568d6SArgyrios Kyrtzidis unsigned Offset; 2616e54568d6SArgyrios Kyrtzidis llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc); 2617e54568d6SArgyrios Kyrtzidis if (FID.isInvalid()) 2618e54568d6SArgyrios Kyrtzidis return; 2619e54568d6SArgyrios Kyrtzidis 2620e54568d6SArgyrios Kyrtzidis LocDeclsTy *&Decls = FileDecls[FID]; 2621e54568d6SArgyrios Kyrtzidis if (!Decls) 2622e54568d6SArgyrios Kyrtzidis Decls = new LocDeclsTy(); 2623e54568d6SArgyrios Kyrtzidis 2624e54568d6SArgyrios Kyrtzidis std::pair<unsigned, Decl *> LocDecl(Offset, D); 2625e54568d6SArgyrios Kyrtzidis 2626e54568d6SArgyrios Kyrtzidis if (Decls->empty() || Decls->back().first <= Offset) { 2627e54568d6SArgyrios Kyrtzidis Decls->push_back(LocDecl); 2628e54568d6SArgyrios Kyrtzidis return; 2629e54568d6SArgyrios Kyrtzidis } 2630e54568d6SArgyrios Kyrtzidis 2631e54568d6SArgyrios Kyrtzidis LocDeclsTy::iterator 2632e54568d6SArgyrios Kyrtzidis I = std::upper_bound(Decls->begin(), Decls->end(), LocDecl, compLocDecl); 2633e54568d6SArgyrios Kyrtzidis 2634e54568d6SArgyrios Kyrtzidis Decls->insert(I, LocDecl); 2635e54568d6SArgyrios Kyrtzidis } 2636e54568d6SArgyrios Kyrtzidis 2637e9681525SArgyrios Kyrtzidis void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length, 2638e9681525SArgyrios Kyrtzidis SmallVectorImpl<Decl *> &Decls) { 2639e9681525SArgyrios Kyrtzidis if (File.isInvalid()) 2640e9681525SArgyrios Kyrtzidis return; 2641e9681525SArgyrios Kyrtzidis 2642e9681525SArgyrios Kyrtzidis if (SourceMgr->isLoadedFileID(File)) { 2643e9681525SArgyrios Kyrtzidis assert(Ctx->getExternalSource() && "No external source!"); 2644e9681525SArgyrios Kyrtzidis return Ctx->getExternalSource()->FindFileRegionDecls(File, Offset, Length, 2645e9681525SArgyrios Kyrtzidis Decls); 2646e9681525SArgyrios Kyrtzidis } 2647e9681525SArgyrios Kyrtzidis 2648e9681525SArgyrios Kyrtzidis FileDeclsTy::iterator I = FileDecls.find(File); 2649e9681525SArgyrios Kyrtzidis if (I == FileDecls.end()) 2650e9681525SArgyrios Kyrtzidis return; 2651e9681525SArgyrios Kyrtzidis 2652e9681525SArgyrios Kyrtzidis LocDeclsTy &LocDecls = *I->second; 2653e9681525SArgyrios Kyrtzidis if (LocDecls.empty()) 2654e9681525SArgyrios Kyrtzidis return; 2655e9681525SArgyrios Kyrtzidis 2656e9681525SArgyrios Kyrtzidis LocDeclsTy::iterator 2657e9681525SArgyrios Kyrtzidis BeginIt = std::lower_bound(LocDecls.begin(), LocDecls.end(), 2658e9681525SArgyrios Kyrtzidis std::make_pair(Offset, (Decl*)0), compLocDecl); 2659e9681525SArgyrios Kyrtzidis if (BeginIt != LocDecls.begin()) 2660e9681525SArgyrios Kyrtzidis --BeginIt; 2661e9681525SArgyrios Kyrtzidis 26628ad3bab5SArgyrios Kyrtzidis // If we are pointing at a top-level decl inside an objc container, we need 26638ad3bab5SArgyrios Kyrtzidis // to backtrack until we find it otherwise we will fail to report that the 26648ad3bab5SArgyrios Kyrtzidis // region overlaps with an objc container. 26658ad3bab5SArgyrios Kyrtzidis while (BeginIt != LocDecls.begin() && 26668ad3bab5SArgyrios Kyrtzidis BeginIt->second->isTopLevelDeclInObjCContainer()) 26678ad3bab5SArgyrios Kyrtzidis --BeginIt; 26688ad3bab5SArgyrios Kyrtzidis 2669e9681525SArgyrios Kyrtzidis LocDeclsTy::iterator 2670e9681525SArgyrios Kyrtzidis EndIt = std::upper_bound(LocDecls.begin(), LocDecls.end(), 2671e9681525SArgyrios Kyrtzidis std::make_pair(Offset+Length, (Decl*)0), 2672e9681525SArgyrios Kyrtzidis compLocDecl); 2673e9681525SArgyrios Kyrtzidis if (EndIt != LocDecls.end()) 2674e9681525SArgyrios Kyrtzidis ++EndIt; 2675e9681525SArgyrios Kyrtzidis 2676e9681525SArgyrios Kyrtzidis for (LocDeclsTy::iterator DIt = BeginIt; DIt != EndIt; ++DIt) 2677e9681525SArgyrios Kyrtzidis Decls.push_back(DIt->second); 2678e9681525SArgyrios Kyrtzidis } 2679e9681525SArgyrios Kyrtzidis 26807c06d866SArgyrios Kyrtzidis SourceLocation ASTUnit::getLocation(const FileEntry *File, 26817c06d866SArgyrios Kyrtzidis unsigned Line, unsigned Col) const { 26827c06d866SArgyrios Kyrtzidis const SourceManager &SM = getSourceManager(); 26834cdfcae7SArgyrios Kyrtzidis SourceLocation Loc = SM.translateFileLineCol(File, Line, Col); 26847c06d866SArgyrios Kyrtzidis return SM.getMacroArgExpandedLocation(Loc); 26857c06d866SArgyrios Kyrtzidis } 26867c06d866SArgyrios Kyrtzidis 26877c06d866SArgyrios Kyrtzidis SourceLocation ASTUnit::getLocation(const FileEntry *File, 26887c06d866SArgyrios Kyrtzidis unsigned Offset) const { 26897c06d866SArgyrios Kyrtzidis const SourceManager &SM = getSourceManager(); 26904cdfcae7SArgyrios Kyrtzidis SourceLocation FileLoc = SM.translateFileLineCol(File, 1, 1); 26917c06d866SArgyrios Kyrtzidis return SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset)); 26927c06d866SArgyrios Kyrtzidis } 26937c06d866SArgyrios Kyrtzidis 26944cdfcae7SArgyrios Kyrtzidis /// \brief If \arg Loc is a loaded location from the preamble, returns 26954cdfcae7SArgyrios Kyrtzidis /// the corresponding local location of the main file, otherwise it returns 26964cdfcae7SArgyrios Kyrtzidis /// \arg Loc. 26974cdfcae7SArgyrios Kyrtzidis SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { 26984cdfcae7SArgyrios Kyrtzidis FileID PreambleID; 26994cdfcae7SArgyrios Kyrtzidis if (SourceMgr) 27004cdfcae7SArgyrios Kyrtzidis PreambleID = SourceMgr->getPreambleFileID(); 27014cdfcae7SArgyrios Kyrtzidis 27024cdfcae7SArgyrios Kyrtzidis if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) 27034cdfcae7SArgyrios Kyrtzidis return Loc; 27044cdfcae7SArgyrios Kyrtzidis 27054cdfcae7SArgyrios Kyrtzidis unsigned Offs; 27064cdfcae7SArgyrios Kyrtzidis if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) { 27074cdfcae7SArgyrios Kyrtzidis SourceLocation FileLoc 27084cdfcae7SArgyrios Kyrtzidis = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()); 27094cdfcae7SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(Offs); 27104cdfcae7SArgyrios Kyrtzidis } 27114cdfcae7SArgyrios Kyrtzidis 27124cdfcae7SArgyrios Kyrtzidis return Loc; 27134cdfcae7SArgyrios Kyrtzidis } 27144cdfcae7SArgyrios Kyrtzidis 27154cdfcae7SArgyrios Kyrtzidis /// \brief If \arg Loc is a local location of the main file but inside the 27164cdfcae7SArgyrios Kyrtzidis /// preamble chunk, returns the corresponding loaded location from the 27174cdfcae7SArgyrios Kyrtzidis /// preamble, otherwise it returns \arg Loc. 27184cdfcae7SArgyrios Kyrtzidis SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { 27194cdfcae7SArgyrios Kyrtzidis FileID PreambleID; 27204cdfcae7SArgyrios Kyrtzidis if (SourceMgr) 27214cdfcae7SArgyrios Kyrtzidis PreambleID = SourceMgr->getPreambleFileID(); 27224cdfcae7SArgyrios Kyrtzidis 27234cdfcae7SArgyrios Kyrtzidis if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) 27244cdfcae7SArgyrios Kyrtzidis return Loc; 27254cdfcae7SArgyrios Kyrtzidis 27264cdfcae7SArgyrios Kyrtzidis unsigned Offs; 27274cdfcae7SArgyrios Kyrtzidis if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) && 27284cdfcae7SArgyrios Kyrtzidis Offs < Preamble.size()) { 27294cdfcae7SArgyrios Kyrtzidis SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID); 27304cdfcae7SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(Offs); 27314cdfcae7SArgyrios Kyrtzidis } 27324cdfcae7SArgyrios Kyrtzidis 27334cdfcae7SArgyrios Kyrtzidis return Loc; 27344cdfcae7SArgyrios Kyrtzidis } 27354cdfcae7SArgyrios Kyrtzidis 2736429ec024SArgyrios Kyrtzidis bool ASTUnit::isInPreambleFileID(SourceLocation Loc) { 2737429ec024SArgyrios Kyrtzidis FileID FID; 2738429ec024SArgyrios Kyrtzidis if (SourceMgr) 2739429ec024SArgyrios Kyrtzidis FID = SourceMgr->getPreambleFileID(); 2740429ec024SArgyrios Kyrtzidis 2741429ec024SArgyrios Kyrtzidis if (Loc.isInvalid() || FID.isInvalid()) 2742429ec024SArgyrios Kyrtzidis return false; 2743429ec024SArgyrios Kyrtzidis 2744429ec024SArgyrios Kyrtzidis return SourceMgr->isInFileID(Loc, FID); 2745429ec024SArgyrios Kyrtzidis } 2746429ec024SArgyrios Kyrtzidis 2747429ec024SArgyrios Kyrtzidis bool ASTUnit::isInMainFileID(SourceLocation Loc) { 2748429ec024SArgyrios Kyrtzidis FileID FID; 2749429ec024SArgyrios Kyrtzidis if (SourceMgr) 2750429ec024SArgyrios Kyrtzidis FID = SourceMgr->getMainFileID(); 2751429ec024SArgyrios Kyrtzidis 2752429ec024SArgyrios Kyrtzidis if (Loc.isInvalid() || FID.isInvalid()) 2753429ec024SArgyrios Kyrtzidis return false; 2754429ec024SArgyrios Kyrtzidis 2755429ec024SArgyrios Kyrtzidis return SourceMgr->isInFileID(Loc, FID); 2756429ec024SArgyrios Kyrtzidis } 2757429ec024SArgyrios Kyrtzidis 2758429ec024SArgyrios Kyrtzidis SourceLocation ASTUnit::getEndOfPreambleFileID() { 2759429ec024SArgyrios Kyrtzidis FileID FID; 2760429ec024SArgyrios Kyrtzidis if (SourceMgr) 2761429ec024SArgyrios Kyrtzidis FID = SourceMgr->getPreambleFileID(); 2762429ec024SArgyrios Kyrtzidis 2763429ec024SArgyrios Kyrtzidis if (FID.isInvalid()) 2764429ec024SArgyrios Kyrtzidis return SourceLocation(); 2765429ec024SArgyrios Kyrtzidis 2766429ec024SArgyrios Kyrtzidis return SourceMgr->getLocForEndOfFile(FID); 2767429ec024SArgyrios Kyrtzidis } 2768429ec024SArgyrios Kyrtzidis 2769429ec024SArgyrios Kyrtzidis SourceLocation ASTUnit::getStartOfMainFileID() { 2770429ec024SArgyrios Kyrtzidis FileID FID; 2771429ec024SArgyrios Kyrtzidis if (SourceMgr) 2772429ec024SArgyrios Kyrtzidis FID = SourceMgr->getMainFileID(); 2773429ec024SArgyrios Kyrtzidis 2774429ec024SArgyrios Kyrtzidis if (FID.isInvalid()) 2775429ec024SArgyrios Kyrtzidis return SourceLocation(); 2776429ec024SArgyrios Kyrtzidis 2777429ec024SArgyrios Kyrtzidis return SourceMgr->getLocForStartOfFile(FID); 2778429ec024SArgyrios Kyrtzidis } 2779429ec024SArgyrios Kyrtzidis 2780d4fcf580SArgyrios Kyrtzidis std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> 2781d4fcf580SArgyrios Kyrtzidis ASTUnit::getLocalPreprocessingEntities() const { 2782d4fcf580SArgyrios Kyrtzidis if (isMainFileAST()) { 2783d4fcf580SArgyrios Kyrtzidis serialization::ModuleFile & 2784d4fcf580SArgyrios Kyrtzidis Mod = Reader->getModuleManager().getPrimaryModule(); 2785d4fcf580SArgyrios Kyrtzidis return Reader->getModulePreprocessedEntities(Mod); 2786d4fcf580SArgyrios Kyrtzidis } 2787d4fcf580SArgyrios Kyrtzidis 2788d4fcf580SArgyrios Kyrtzidis if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) 2789d4fcf580SArgyrios Kyrtzidis return std::make_pair(PPRec->local_begin(), PPRec->local_end()); 2790d4fcf580SArgyrios Kyrtzidis 2791d4fcf580SArgyrios Kyrtzidis return std::make_pair(PreprocessingRecord::iterator(), 2792d4fcf580SArgyrios Kyrtzidis PreprocessingRecord::iterator()); 2793d4fcf580SArgyrios Kyrtzidis } 2794d4fcf580SArgyrios Kyrtzidis 2795*e514b200SArgyrios Kyrtzidis bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) { 279610e7846aSArgyrios Kyrtzidis if (isMainFileAST()) { 279710e7846aSArgyrios Kyrtzidis serialization::ModuleFile & 279810e7846aSArgyrios Kyrtzidis Mod = Reader->getModuleManager().getPrimaryModule(); 279910e7846aSArgyrios Kyrtzidis ASTReader::ModuleDeclIterator MDI, MDE; 280010e7846aSArgyrios Kyrtzidis llvm::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod); 280110e7846aSArgyrios Kyrtzidis for (; MDI != MDE; ++MDI) { 280210e7846aSArgyrios Kyrtzidis if (!Fn(context, *MDI)) 280310e7846aSArgyrios Kyrtzidis return false; 280410e7846aSArgyrios Kyrtzidis } 280510e7846aSArgyrios Kyrtzidis 280610e7846aSArgyrios Kyrtzidis return true; 280710e7846aSArgyrios Kyrtzidis } 280810e7846aSArgyrios Kyrtzidis 280910e7846aSArgyrios Kyrtzidis for (ASTUnit::top_level_iterator TL = top_level_begin(), 281010e7846aSArgyrios Kyrtzidis TLEnd = top_level_end(); 281110e7846aSArgyrios Kyrtzidis TL != TLEnd; ++TL) { 281210e7846aSArgyrios Kyrtzidis if (!Fn(context, *TL)) 281310e7846aSArgyrios Kyrtzidis return false; 281410e7846aSArgyrios Kyrtzidis } 281510e7846aSArgyrios Kyrtzidis 281610e7846aSArgyrios Kyrtzidis return true; 281710e7846aSArgyrios Kyrtzidis } 281810e7846aSArgyrios Kyrtzidis 28197c06d866SArgyrios Kyrtzidis void ASTUnit::PreambleData::countLines() const { 28207c06d866SArgyrios Kyrtzidis NumLines = 0; 28217c06d866SArgyrios Kyrtzidis if (empty()) 28227c06d866SArgyrios Kyrtzidis return; 28237c06d866SArgyrios Kyrtzidis 28247c06d866SArgyrios Kyrtzidis for (std::vector<char>::const_iterator 28257c06d866SArgyrios Kyrtzidis I = Buffer.begin(), E = Buffer.end(); I != E; ++I) { 28267c06d866SArgyrios Kyrtzidis if (*I == '\n') 28277c06d866SArgyrios Kyrtzidis ++NumLines; 28287c06d866SArgyrios Kyrtzidis } 28297c06d866SArgyrios Kyrtzidis if (Buffer.back() != '\n') 28307c06d866SArgyrios Kyrtzidis ++NumLines; 28317c06d866SArgyrios Kyrtzidis } 2832ebf01369SArgyrios Kyrtzidis 2833ebf01369SArgyrios Kyrtzidis #ifndef NDEBUG 2834ebf01369SArgyrios Kyrtzidis ASTUnit::ConcurrencyState::ConcurrencyState() { 2835ebf01369SArgyrios Kyrtzidis Mutex = new llvm::sys::MutexImpl(/*recursive=*/true); 2836ebf01369SArgyrios Kyrtzidis } 2837ebf01369SArgyrios Kyrtzidis 2838ebf01369SArgyrios Kyrtzidis ASTUnit::ConcurrencyState::~ConcurrencyState() { 2839ebf01369SArgyrios Kyrtzidis delete static_cast<llvm::sys::MutexImpl *>(Mutex); 2840ebf01369SArgyrios Kyrtzidis } 2841ebf01369SArgyrios Kyrtzidis 2842ebf01369SArgyrios Kyrtzidis void ASTUnit::ConcurrencyState::start() { 2843ebf01369SArgyrios Kyrtzidis bool acquired = static_cast<llvm::sys::MutexImpl *>(Mutex)->tryacquire(); 2844ebf01369SArgyrios Kyrtzidis assert(acquired && "Concurrent access to ASTUnit!"); 2845ebf01369SArgyrios Kyrtzidis } 2846ebf01369SArgyrios Kyrtzidis 2847ebf01369SArgyrios Kyrtzidis void ASTUnit::ConcurrencyState::finish() { 2848ebf01369SArgyrios Kyrtzidis static_cast<llvm::sys::MutexImpl *>(Mutex)->release(); 2849ebf01369SArgyrios Kyrtzidis } 2850ebf01369SArgyrios Kyrtzidis 2851ebf01369SArgyrios Kyrtzidis #else // NDEBUG 2852ebf01369SArgyrios Kyrtzidis 2853ebf01369SArgyrios Kyrtzidis ASTUnit::ConcurrencyState::ConcurrencyState() {} 2854ebf01369SArgyrios Kyrtzidis ASTUnit::ConcurrencyState::~ConcurrencyState() {} 2855ebf01369SArgyrios Kyrtzidis void ASTUnit::ConcurrencyState::start() {} 2856ebf01369SArgyrios Kyrtzidis void ASTUnit::ConcurrencyState::finish() {} 2857ebf01369SArgyrios Kyrtzidis 2858ebf01369SArgyrios Kyrtzidis #endif 2859