 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
51.0% |
26 / 51 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
80.4% |
41 / 51 |
| |
|
Line Coverage: |
82.8% |
125 / 151 |
| |
 |
|
 |
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/Driver/Compilation.h"
21 : #include "clang/Driver/Driver.h"
22 : #include "clang/Driver/Job.h"
23 : #include "clang/Driver/Tool.h"
24 : #include "clang/Frontend/CompilerInstance.h"
25 : #include "clang/Frontend/FrontendActions.h"
26 : #include "clang/Frontend/FrontendDiagnostic.h"
27 : #include "clang/Frontend/FrontendOptions.h"
28 : #include "clang/Lex/HeaderSearch.h"
29 : #include "clang/Lex/Preprocessor.h"
30 : #include "clang/Basic/TargetOptions.h"
31 : #include "clang/Basic/TargetInfo.h"
32 : #include "clang/Basic/Diagnostic.h"
33 : #include "llvm/Support/MemoryBuffer.h"
34 : #include "llvm/System/Host.h"
35 : #include "llvm/System/Path.h"
36 : using namespace clang;
37 :
38 22: ASTUnit::ASTUnit(bool _MainFileIsAST)
39 22: : tempFile(false), MainFileIsAST(_MainFileIsAST) {
40 22: }
41 19: ASTUnit::~ASTUnit() {
1: branch 0 taken
18: branch 1 taken
18: branch 2 taken
18: branch 3 taken
42 19: if (tempFile)
43 1: llvm::sys::Path(getPCHFileName()).eraseFromDisk();
44 19: }
45 :
46 : namespace {
47 :
48 : /// \brief Gathers information from PCHReader that will be used to initialize
49 : /// a Preprocessor.
10: branch 1 taken
0: branch 2 not taken
0: branch 5 not taken
0: branch 6 not taken
50 10: class PCHInfoCollector : public PCHReaderListener {
51 : LangOptions &LangOpt;
52 : HeaderSearch &HSI;
53 : std::string &TargetTriple;
54 : std::string &Predefines;
55 : unsigned &Counter;
56 :
57 : unsigned NumHeaderInfos;
58 :
59 : public:
60 : PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
61 : std::string &TargetTriple, std::string &Predefines,
62 13: unsigned &Counter)
63 : : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
64 13: Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
65 :
66 13: virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
67 13: LangOpt = LangOpts;
68 13: return false;
69 : }
70 :
71 13: virtual bool ReadTargetTriple(llvm::StringRef Triple) {
72 13: TargetTriple = Triple;
73 13: return false;
74 : }
75 :
76 : virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
77 : FileID PCHBufferID,
78 : llvm::StringRef OriginalFileName,
79 13: std::string &SuggestedPredefines) {
80 13: Predefines = PCHPredef;
81 13: return false;
82 : }
83 :
84 17: virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
85 17: HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
86 17: }
87 :
88 0: virtual void ReadCounter(unsigned Value) {
89 0: Counter = Value;
90 0: }
91 : };
92 :
93 : } // anonymous namespace
94 :
95 0: const std::string &ASTUnit::getOriginalSourceFileName() {
96 0: return OriginalSourceFile;
97 : }
98 :
99 1: const std::string &ASTUnit::getPCHFileName() {
1: branch 1 taken
0: branch 2 not taken
100 1: assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
1: branch 2 taken
0: branch 3 not taken
101 2: return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
102 : }
103 :
104 : ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
105 : Diagnostic &Diags,
106 : bool OnlyLocalDecls,
107 : bool UseBumpAllocator,
108 : RemappedFile *RemappedFiles,
109 13: unsigned NumRemappedFiles) {
110 13: llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
111 13: AST->OnlyLocalDecls = OnlyLocalDecls;
112 13: AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
113 :
1: branch 0 taken
13: branch 1 taken
114 14: for (unsigned I = 0; I != NumRemappedFiles; ++I) {
115 : // Create the file entry for the file that we're mapping from.
116 : const FileEntry *FromFile
117 : = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
118 : RemappedFiles[I].second->getBufferSize(),
119 1: 0);
0: branch 0 not taken
1: branch 1 taken
120 1: if (!FromFile) {
121 : Diags.Report(diag::err_fe_remap_missing_from_file)
122 0: << RemappedFiles[I].first;
123 0: continue;
124 : }
125 :
126 : // Override the contents of the "from" file with the contents of
127 : // the "to" file.
128 : AST->getSourceManager().overrideFileContents(FromFile,
129 1: RemappedFiles[I].second);
130 : }
131 :
132 : // Gather Info for preprocessor construction later on.
133 :
134 13: LangOptions LangInfo;
135 13: HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
136 13: std::string TargetTriple;
137 13: std::string Predefines;
138 : unsigned Counter;
139 :
140 13: llvm::OwningPtr<PCHReader> Reader;
141 13: llvm::OwningPtr<ExternalASTSource> Source;
142 :
143 : Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
144 13: Diags));
145 : Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
146 13: Predefines, Counter));
147 :
13: branch 2 taken
0: branch 3 not taken
0: branch 4 not taken
148 13: switch (Reader->ReadPCH(Filename)) {
149 : case PCHReader::Success:
150 13: break;
151 :
152 : case PCHReader::Failure:
153 : case PCHReader::IgnorePCH:
154 0: Diags.Report(diag::err_fe_unable_to_load_pch);
155 0: return NULL;
156 : }
157 :
158 13: AST->OriginalSourceFile = Reader->getOriginalSourceFile();
159 :
160 : // PCH loaded successfully. Now create the preprocessor.
161 :
162 : // Get information about the target being compiled for.
163 : //
164 : // FIXME: This is broken, we should store the TargetOptions in the PCH.
165 13: TargetOptions TargetOpts;
166 13: TargetOpts.ABI = "";
167 13: TargetOpts.CPU = "";
168 13: TargetOpts.Features.clear();
169 13: TargetOpts.Triple = TargetTriple;
170 13: AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
171 : AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
172 13: AST->getSourceManager(), HeaderInfo));
173 13: Preprocessor &PP = *AST->PP.get();
174 :
175 13: PP.setPredefines(Reader->getSuggestedPredefines());
176 13: PP.setCounterValue(Counter);
177 13: Reader->setPreprocessor(PP);
178 :
179 : // Create and initialize the ASTContext.
180 :
181 : AST->Ctx.reset(new ASTContext(LangInfo,
182 : AST->getSourceManager(),
183 : *AST->Target.get(),
184 : PP.getIdentifierTable(),
185 : PP.getSelectorTable(),
186 : PP.getBuiltinInfo(),
187 : /* FreeMemory = */ !UseBumpAllocator,
188 13: /* size_reserve = */0));
189 13: ASTContext &Context = *AST->Ctx.get();
190 :
191 13: Reader->InitializeContext(Context);
192 :
193 : // Attach the PCH reader to the AST context as an external AST
194 : // source, so that declarations will be deserialized from the
195 : // PCH file as needed.
13: branch 1 taken
0: branch 2 not taken
196 13: Source.reset(Reader.take());
197 13: Context.setExternalSource(Source);
198 :
199 13: return AST.take();
200 : }
201 :
202 : namespace {
203 :
0: branch 1 not taken
0: branch 2 not taken
0: branch 5 not taken
0: branch 6 not taken
204 0: class TopLevelDeclTrackerConsumer : public ASTConsumer {
205 : ASTUnit &Unit;
206 :
207 : public:
208 9: TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
209 :
210 23: void HandleTopLevelDecl(DeclGroupRef D) {
23: branch 2 taken
23: branch 3 taken
211 46: for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
212 23: Unit.getTopLevelDecls().push_back(*it);
213 23: }
214 : };
215 :
9: branch 1 taken
0: branch 2 not taken
0: branch 5 not taken
0: branch 6 not taken
216 9: class TopLevelDeclTrackerAction : public ASTFrontendAction {
217 : public:
218 : ASTUnit &Unit;
219 :
220 : virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
221 9: llvm::StringRef InFile) {
222 9: return new TopLevelDeclTrackerConsumer(Unit);
223 : }
224 :
225 : public:
226 9: TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
227 :
228 9: virtual bool hasCodeCompletionSupport() const { return false; }
229 : };
230 :
231 : }
232 :
233 : ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
234 : Diagnostic &Diags,
235 9: bool OnlyLocalDecls) {
236 : // Create the compiler instance to use for building the AST.
237 9: CompilerInstance Clang;
238 9: llvm::OwningPtr<ASTUnit> AST;
239 9: llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
240 :
241 9: Clang.setInvocation(const_cast<CompilerInvocation*>(&CI));
242 :
243 9: Clang.setDiagnostics(&Diags);
244 9: Clang.setDiagnosticClient(Diags.getClient());
245 :
246 : // Create the target instance.
247 : Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
248 9: Clang.getTargetOpts()));
9: branch 1 taken
0: branch 2 not taken
249 9: if (!Clang.hasTarget())
250 0: goto error;
251 :
252 : // Inform the target of the language options.
253 : //
254 : // FIXME: We shouldn't need to do this, the target should be immutable once
255 : // created. This complexity should be lifted elsewhere.
256 9: Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
257 :
258 : assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
9: branch 2 taken
0: branch 3 not taken
259 9: "Invocation must have exactly one source file!");
260 : assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
9: branch 2 taken
0: branch 3 not taken
261 9: "FIXME: AST inputs not yet supported here!");
262 :
263 : // Create the AST unit.
264 9: AST.reset(new ASTUnit(false));
265 :
266 9: AST->OnlyLocalDecls = OnlyLocalDecls;
267 9: AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
268 :
269 : // Create a file manager object to provide access to and cache the filesystem.
270 9: Clang.setFileManager(&AST->getFileManager());
271 :
272 : // Create the source manager.
273 9: Clang.setSourceManager(&AST->getSourceManager());
274 :
275 : // Create the preprocessor.
276 9: Clang.createPreprocessor();
277 :
278 9: Act.reset(new TopLevelDeclTrackerAction(*AST));
0: branch 5 not taken
9: branch 6 taken
279 9: if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
280 : /*IsAST=*/false))
281 0: goto error;
282 :
283 9: Act->Execute();
284 :
285 : // Steal the created target, context, and preprocessor, and take back the
286 : // source and file managers.
287 9: AST->Ctx.reset(Clang.takeASTContext());
288 9: AST->PP.reset(Clang.takePreprocessor());
289 9: Clang.takeSourceManager();
290 9: Clang.takeFileManager();
291 9: AST->Target.reset(Clang.takeTarget());
292 :
293 9: Act->EndSourceFile();
294 :
295 9: Clang.takeDiagnosticClient();
296 9: Clang.takeDiagnostics();
297 9: Clang.takeInvocation();
298 :
299 9: return AST.take();
300 :
301 0: error:
302 0: Clang.takeSourceManager();
303 0: Clang.takeFileManager();
304 0: Clang.takeDiagnosticClient();
305 0: Clang.takeDiagnostics();
306 0: return 0;
307 : }
308 :
309 : ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
310 : const char **ArgEnd,
311 : Diagnostic &Diags,
312 : llvm::StringRef ResourceFilesPath,
313 : bool OnlyLocalDecls,
314 : bool UseBumpAllocator,
315 : RemappedFile *RemappedFiles,
316 9: unsigned NumRemappedFiles) {
317 9: llvm::SmallVector<const char *, 16> Args;
318 9: Args.push_back("<clang>"); // FIXME: Remove dummy argument.
319 9: Args.insert(Args.end(), ArgBegin, ArgEnd);
320 :
321 : // FIXME: Find a cleaner way to force the driver into restricted modes. We
322 : // also want to force it to use clang.
323 9: Args.push_back("-fsyntax-only");
324 :
325 : // FIXME: We shouldn't have to pass in the path info.
326 : driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
327 9: "a.out", false, Diags);
328 :
329 : // Don't check that inputs exist, they have been remapped.
330 9: TheDriver.setCheckInputsExist(false);
331 :
332 : llvm::OwningPtr<driver::Compilation> C(
333 9: TheDriver.BuildCompilation(Args.size(), Args.data()));
334 :
335 : // We expect to get back exactly one command job, if we didn't something
336 : // failed.
337 9: const driver::JobList &Jobs = C->getJobs();
9: branch 1 taken
0: branch 2 not taken
0: branch 5 not taken
9: branch 6 taken
0: branch 7 not taken
9: branch 8 taken
338 9: if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
339 0: llvm::SmallString<256> Msg;
340 0: llvm::raw_svector_ostream OS(Msg);
341 0: C->PrintJob(OS, C->getJobs(), "; ", true);
342 0: Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
343 0: return 0;
344 : }
345 :
346 9: const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
0: branch 5 not taken
9: branch 6 taken
347 9: if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
348 0: Diags.Report(diag::err_fe_expected_clang_command);
349 0: return 0;
350 : }
351 :
352 9: const driver::ArgStringList &CCArgs = Cmd->getArguments();
353 9: llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
354 : CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
355 : (const char**) CCArgs.data()+CCArgs.size(),
356 9: Diags);
357 :
358 : // Override any files that need remapping
3: branch 0 taken
9: branch 1 taken
359 12: for (unsigned I = 0; I != NumRemappedFiles; ++I)
360 : CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
361 3: RemappedFiles[I].second);
362 :
363 : // Override the resources path.
364 9: CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
365 :
366 9: CI->getFrontendOpts().DisableFree = UseBumpAllocator;
367 9: ASTUnit *Unit = LoadFromCompilerInvocation(*CI, Diags, OnlyLocalDecls);
9: branch 0 taken
0: branch 1 not taken
368 9: if (Unit)
369 9: Unit->Invocation.reset(CI.take());
370 :
371 9: return Unit;
372 0: }
Generated: 2010-02-10 01:31 by zcov