ASTUnit.cpp revision 64a32baec6fdc7e5fbcba417a2754f78ab876245
1//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// ASTUnit Implementation. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Frontend/ASTUnit.h" 15#include "clang/Frontend/PCHReader.h" 16#include "clang/AST/ASTContext.h" 17#include "clang/AST/ASTConsumer.h" 18#include "clang/AST/DeclVisitor.h" 19#include "clang/AST/StmtVisitor.h" 20#include "clang/Frontend/CompilerInstance.h" 21#include "clang/Frontend/FrontendActions.h" 22#include "clang/Frontend/FrontendOptions.h" 23#include "clang/Lex/HeaderSearch.h" 24#include "clang/Lex/Preprocessor.h" 25#include "clang/Basic/TargetOptions.h" 26#include "clang/Basic/TargetInfo.h" 27#include "clang/Basic/Diagnostic.h" 28#include "llvm/LLVMContext.h" 29#include "llvm/System/Path.h" 30using namespace clang; 31 32ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { 33 Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer()); 34} 35ASTUnit::~ASTUnit() { 36 if (tempFile) 37 llvm::sys::Path(getPCHFileName()).eraseFromDisk(); 38 39 // The ASTUnit object owns the DiagnosticClient. 40 delete Diags.getClient(); 41} 42 43namespace { 44 45/// \brief Gathers information from PCHReader that will be used to initialize 46/// a Preprocessor. 47class PCHInfoCollector : public PCHReaderListener { 48 LangOptions &LangOpt; 49 HeaderSearch &HSI; 50 std::string &TargetTriple; 51 std::string &Predefines; 52 unsigned &Counter; 53 54 unsigned NumHeaderInfos; 55 56public: 57 PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, 58 std::string &TargetTriple, std::string &Predefines, 59 unsigned &Counter) 60 : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple), 61 Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {} 62 63 virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { 64 LangOpt = LangOpts; 65 return false; 66 } 67 68 virtual bool ReadTargetTriple(llvm::StringRef Triple) { 69 TargetTriple = Triple; 70 return false; 71 } 72 73 virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef, 74 FileID PCHBufferID, 75 llvm::StringRef OriginalFileName, 76 std::string &SuggestedPredefines) { 77 Predefines = PCHPredef; 78 return false; 79 } 80 81 virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) { 82 HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); 83 } 84 85 virtual void ReadCounter(unsigned Value) { 86 Counter = Value; 87 } 88}; 89 90} // anonymous namespace 91 92const std::string &ASTUnit::getOriginalSourceFileName() { 93 return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile(); 94} 95 96const std::string &ASTUnit::getPCHFileName() { 97 return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName(); 98} 99 100ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, 101 std::string *ErrMsg, 102 DiagnosticClient *diagClient, 103 bool OnlyLocalDecls, 104 bool UseBumpAllocator) { 105 llvm::OwningPtr<ASTUnit> AST(new ASTUnit(diagClient)); 106 AST->OnlyLocalDecls = OnlyLocalDecls; 107 AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); 108 109 // Gather Info for preprocessor construction later on. 110 111 LangOptions LangInfo; 112 HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); 113 std::string TargetTriple; 114 std::string Predefines; 115 unsigned Counter; 116 117 llvm::OwningPtr<PCHReader> Reader; 118 llvm::OwningPtr<ExternalASTSource> Source; 119 120 Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), 121 AST->Diags)); 122 Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, 123 Predefines, Counter)); 124 125 switch (Reader->ReadPCH(Filename)) { 126 case PCHReader::Success: 127 break; 128 129 case PCHReader::Failure: 130 case PCHReader::IgnorePCH: 131 if (ErrMsg) 132 *ErrMsg = "Could not load PCH file"; 133 return NULL; 134 } 135 136 // PCH loaded successfully. Now create the preprocessor. 137 138 // Get information about the target being compiled for. 139 // 140 // FIXME: This is broken, we should store the TargetOptions in the PCH. 141 TargetOptions TargetOpts; 142 TargetOpts.ABI = ""; 143 TargetOpts.CPU = ""; 144 TargetOpts.Features.clear(); 145 TargetOpts.Triple = TargetTriple; 146 AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts)); 147 AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(), 148 AST->getSourceManager(), HeaderInfo)); 149 Preprocessor &PP = *AST->PP.get(); 150 151 PP.setPredefines(Reader->getSuggestedPredefines()); 152 PP.setCounterValue(Counter); 153 Reader->setPreprocessor(PP); 154 155 // Create and initialize the ASTContext. 156 157 AST->Ctx.reset(new ASTContext(LangInfo, 158 AST->getSourceManager(), 159 *AST->Target.get(), 160 PP.getIdentifierTable(), 161 PP.getSelectorTable(), 162 PP.getBuiltinInfo(), 163 /* FreeMemory = */ !UseBumpAllocator, 164 /* size_reserve = */0)); 165 ASTContext &Context = *AST->Ctx.get(); 166 167 Reader->InitializeContext(Context); 168 169 // Attach the PCH reader to the AST context as an external AST 170 // source, so that declarations will be deserialized from the 171 // PCH file as needed. 172 Source.reset(Reader.take()); 173 Context.setExternalSource(Source); 174 175 return AST.take(); 176} 177 178namespace { 179 180class NullAction : public ASTFrontendAction { 181 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 182 llvm::StringRef InFile) { 183 return new ASTConsumer(); 184 } 185 186public: 187 virtual bool hasCodeCompletionSupport() const { return false; } 188}; 189 190} 191 192ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, 193 Diagnostic &Diags, 194 bool OnlyLocalDecls, 195 bool UseBumpAllocator) { 196 // Create the compiler instance to use for building the AST. 197 CompilerInstance Clang(&llvm::getGlobalContext(), false); 198 llvm::OwningPtr<ASTUnit> AST; 199 NullAction Act; 200 201 Clang.getInvocation() = CI; 202 203 Clang.setDiagnostics(&Diags); 204 Clang.setDiagnosticClient(Diags.getClient()); 205 206 // Create the target instance. 207 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), 208 Clang.getTargetOpts())); 209 if (!Clang.hasTarget()) 210 goto error; 211 212 // Inform the target of the language options. 213 // 214 // FIXME: We shouldn't need to do this, the target should be immutable once 215 // created. This complexity should be lifted elsewhere. 216 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); 217 218 assert(Clang.getFrontendOpts().Inputs.size() == 1 && 219 "Invocation must have exactly one source file!"); 220 assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST && 221 "FIXME: AST inputs not yet supported here!"); 222 223 // Create the AST unit. 224 // 225 // FIXME: Use the provided diagnostic client. 226 AST.reset(new ASTUnit()); 227 228 // Create a file manager object to provide access to and cache the filesystem. 229 Clang.setFileManager(&AST->getFileManager()); 230 231 // Create the source manager. 232 Clang.setSourceManager(&AST->getSourceManager()); 233 234 // Create the preprocessor. 235 Clang.createPreprocessor(); 236 237 if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, 238 /*IsAST=*/false)) 239 goto error; 240 241 Act.Execute(); 242 243 // Steal the created target, context, and preprocessor, and take back the 244 // source and file managers. 245 AST->Ctx.reset(Clang.takeASTContext()); 246 AST->PP.reset(Clang.takePreprocessor()); 247 Clang.takeSourceManager(); 248 Clang.takeFileManager(); 249 AST->Target.reset(Clang.takeTarget()); 250 251 Act.EndSourceFile(); 252 253 Clang.takeDiagnosticClient(); 254 Clang.takeDiagnostics(); 255 256 return AST.take(); 257 258error: 259 Clang.takeSourceManager(); 260 Clang.takeFileManager(); 261 Clang.takeDiagnosticClient(); 262 Clang.takeDiagnostics(); 263 return 0; 264} 265