 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
39.8% |
47 / 118 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
49.2% |
58 / 118 |
| |
|
Line Coverage: |
58.7% |
105 / 179 |
| |
 |
|
 |
1 : //===--- HeaderSearch.cpp - Resolve Header File Locations ---===//
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 : // This file implements the DirectoryLookup and HeaderSearch interfaces.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "clang/Lex/HeaderSearch.h"
15 : #include "clang/Lex/HeaderMap.h"
16 : #include "clang/Basic/FileManager.h"
17 : #include "clang/Basic/IdentifierTable.h"
18 : #include "llvm/System/Path.h"
19 : #include "llvm/ADT/SmallString.h"
20 : #include <cstdio>
21 : using namespace clang;
22 :
23 : const IdentifierInfo *
24 681: HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
118: branch 0 taken
563: branch 1 taken
25 681: if (ControllingMacro)
26 118: return ControllingMacro;
27 :
1: branch 0 taken
562: branch 1 taken
0: branch 2 not taken
1: branch 3 taken
28 563: if (!ControllingMacroID || !External)
29 562: return 0;
30 :
31 1: ControllingMacro = External->GetIdentifier(ControllingMacroID);
32 1: return ControllingMacro;
33 : }
34 :
35 2533: HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) {
36 2533: SystemDirIdx = 0;
37 2533: NoCurDirSearch = false;
38 :
39 2533: ExternalLookup = 0;
40 2533: NumIncluded = 0;
41 2533: NumMultiIncludeFileOptzn = 0;
42 2533: NumFrameworkLookups = NumSubFrameworkLookups = 0;
43 2533: }
44 :
45 2530: HeaderSearch::~HeaderSearch() {
46 : // Delete headermaps.
0: branch 1 not taken
2530: branch 2 taken
0: branch 4 not taken
0: branch 5 not taken
47 2530: for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
0: branch 1 not taken
0: branch 2 not taken
0: branch 6 not taken
0: branch 7 not taken
48 0: delete HeaderMaps[i].second;
49 2530: }
50 :
51 2: void HeaderSearch::PrintStats() {
52 2: fprintf(stderr, "\n*** HeaderSearch Stats:\n");
53 2: fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size());
54 2: unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
2: branch 1 taken
2: branch 2 taken
55 4: for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
56 2: NumOnceOnlyFiles += FileInfo[i].isImport;
2: branch 1 taken
0: branch 2 not taken
57 2: if (MaxNumIncludes < FileInfo[i].NumIncludes)
58 2: MaxNumIncludes = FileInfo[i].NumIncludes;
59 2: NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
60 : }
61 2: fprintf(stderr, " %d #import/#pragma once files.\n", NumOnceOnlyFiles);
62 2: fprintf(stderr, " %d included exactly once.\n", NumSingleIncludedFiles);
63 2: fprintf(stderr, " %d max times a file is included.\n", MaxNumIncludes);
64 :
65 2: fprintf(stderr, " %d #include/#include_next/#import.\n", NumIncluded);
66 : fprintf(stderr, " %d #includes skipped due to"
67 2: " the multi-include optimization.\n", NumMultiIncludeFileOptzn);
68 :
69 2: fprintf(stderr, "%d framework lookups.\n", NumFrameworkLookups);
70 2: fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups);
71 2: }
72 :
73 : /// CreateHeaderMap - This method returns a HeaderMap for the specified
74 : /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
75 0: const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
76 : // We expect the number of headermaps to be small, and almost always empty.
77 : // If it ever grows, use of a linear search should be re-evaluated.
0: branch 1 not taken
0: branch 2 not taken
78 0: if (!HeaderMaps.empty()) {
0: branch 1 not taken
0: branch 2 not taken
79 0: for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
80 : // Pointer equality comparison of FileEntries works because they are
81 : // already uniqued by inode.
0: branch 1 not taken
0: branch 2 not taken
82 0: if (HeaderMaps[i].first == FE)
83 0: return HeaderMaps[i].second;
84 : }
85 :
0: branch 1 not taken
0: branch 2 not taken
86 0: if (const HeaderMap *HM = HeaderMap::Create(FE)) {
87 0: HeaderMaps.push_back(std::make_pair(FE, HM));
88 0: return HM;
89 : }
90 :
91 0: return 0;
92 : }
93 :
94 : //===----------------------------------------------------------------------===//
95 : // File lookup within a DirectoryLookup scope
96 : //===----------------------------------------------------------------------===//
97 :
98 : /// getName - Return the directory or filename corresponding to this lookup
99 : /// object.
100 3: const char *DirectoryLookup::getName() const {
3: branch 1 taken
0: branch 2 not taken
101 3: if (isNormalDir())
102 3: return getDir()->getName();
0: branch 1 not taken
0: branch 2 not taken
103 0: if (isFramework())
104 0: return getFrameworkDir()->getName();
0: branch 1 not taken
0: branch 2 not taken
105 0: assert(isHeaderMap() && "Unknown DirectoryLookup");
106 0: return getHeaderMap()->getFileName();
107 : }
108 :
109 :
110 : /// LookupFile - Lookup the specified file in this search path, returning it
111 : /// if it exists or returning null if not.
112 : const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename,
113 1502: HeaderSearch &HS) const {
114 1502: llvm::SmallString<1024> TmpDir;
1502: branch 1 taken
0: branch 2 not taken
115 1502: if (isNormalDir()) {
116 : // Concatenate the requested file onto the directory.
117 : // FIXME: Portability. Filename concatenation should be in sys::Path.
118 1502: TmpDir += getDir()->getName();
119 1502: TmpDir.push_back('/');
120 1502: TmpDir.append(Filename.begin(), Filename.end());
121 1502: return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end());
122 : }
123 :
0: branch 1 not taken
0: branch 2 not taken
124 0: if (isFramework())
125 0: return DoFrameworkLookup(Filename, HS);
126 :
0: branch 1 not taken
0: branch 2 not taken
127 0: assert(isHeaderMap() && "Unknown directory lookup");
128 1502: return getHeaderMap()->LookupFile(Filename, HS.getFileMgr());
129 : }
130 :
131 :
132 : /// DoFrameworkLookup - Do a lookup of the specified file in the current
133 : /// DirectoryLookup, which is a framework directory.
134 : const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
135 0: HeaderSearch &HS) const {
136 0: FileManager &FileMgr = HS.getFileMgr();
137 :
138 : // Framework names must have a '/' in the filename.
139 0: size_t SlashPos = Filename.find('/');
0: branch 0 not taken
0: branch 1 not taken
140 0: if (SlashPos == llvm::StringRef::npos) return 0;
141 :
142 : // Find out if this is the home for the specified framework, by checking
143 : // HeaderSearch. Possible answer are yes/no and unknown.
144 : const DirectoryEntry *&FrameworkDirCache =
145 0: HS.LookupFrameworkCache(Filename.substr(0, SlashPos));
146 :
147 : // If it is known and in some other directory, fail.
0: branch 0 not taken
0: branch 1 not taken
0: branch 3 not taken
0: branch 4 not taken
0: branch 5 not taken
0: branch 6 not taken
148 0: if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir())
149 0: return 0;
150 :
151 : // Otherwise, construct the path to this framework dir.
152 :
153 : // FrameworkName = "/System/Library/Frameworks/"
154 0: llvm::SmallString<1024> FrameworkName;
155 0: FrameworkName += getFrameworkDir()->getName();
0: branch 1 not taken
0: branch 2 not taken
0: branch 4 not taken
0: branch 5 not taken
0: branch 6 not taken
0: branch 7 not taken
156 0: if (FrameworkName.empty() || FrameworkName.back() != '/')
157 0: FrameworkName.push_back('/');
158 :
159 : // FrameworkName = "/System/Library/Frameworks/Cocoa"
160 0: FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
161 :
162 : // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
163 0: FrameworkName += ".framework/";
164 :
165 : // If the cache entry is still unresolved, query to see if the cache entry is
166 : // still unresolved. If so, check its existence now.
0: branch 0 not taken
0: branch 1 not taken
167 0: if (FrameworkDirCache == 0) {
168 0: HS.IncrementFrameworkLookupCount();
169 :
170 : // If the framework dir doesn't exist, we fail.
171 : // FIXME: It's probably more efficient to query this with FileMgr.getDir.
0: branch 10 not taken
0: branch 11 not taken
172 0: if (!llvm::sys::Path(std::string(FrameworkName.begin(),
173 : FrameworkName.end())).exists())
174 0: return 0;
175 :
176 : // Otherwise, if it does, remember that this is the right direntry for this
177 : // framework.
178 0: FrameworkDirCache = getFrameworkDir();
179 : }
180 :
181 : // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
182 0: unsigned OrigSize = FrameworkName.size();
183 :
184 0: FrameworkName += "Headers/";
185 0: FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
0: branch 0 not taken
0: branch 1 not taken
186 0: if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(),
187 0: FrameworkName.end())) {
188 0: return FE;
189 : }
190 :
191 : // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
192 0: const char *Private = "Private";
193 : FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
194 0: Private+strlen(Private));
195 0: return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end());
196 : }
197 :
198 :
199 : //===----------------------------------------------------------------------===//
200 : // Header File Location.
201 : //===----------------------------------------------------------------------===//
202 :
203 :
204 : /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
205 : /// return null on failure. isAngled indicates whether the file reference is
206 : /// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if
207 : /// non-null, indicates where the #including file is, in case a relative search
208 : /// is needed.
209 : const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
210 : bool isAngled,
211 : const DirectoryLookup *FromDir,
212 : const DirectoryLookup *&CurDir,
213 727: const FileEntry *CurFileEnt) {
214 : // If 'Filename' is absolute, check to see if it exists and no searching.
31: branch 3 taken
696: branch 4 taken
215 727: if (llvm::sys::Path::isAbsolute(Filename.begin(), Filename.size())) {
216 31: CurDir = 0;
217 :
218 : // If this was an #include_next "/absolute/file", fail.
0: branch 0 not taken
31: branch 1 taken
219 31: if (FromDir) return 0;
220 :
221 : // Otherwise, just return the file.
222 31: return FileMgr.getFile(Filename);
223 : }
224 :
225 : // Step #0, unless disabled, check to see if the file is in the #includer's
226 : // directory. This has to be based on CurFileEnt, not CurDir, because
227 : // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
228 : // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
229 : // This search is not done for <> headers.
652: branch 0 taken
44: branch 1 taken
63: branch 2 taken
589: branch 3 taken
63: branch 4 taken
0: branch 5 not taken
230 696: if (CurFileEnt && !isAngled && !NoCurDirSearch) {
231 63: llvm::SmallString<1024> TmpDir;
232 : // Concatenate the requested file onto the directory.
233 : // FIXME: Portability. Filename concatenation should be in sys::Path.
234 63: TmpDir += CurFileEnt->getDir()->getName();
235 63: TmpDir.push_back('/');
236 63: TmpDir.append(Filename.begin(), Filename.end());
48: branch 2 taken
15: branch 3 taken
237 63: if (const FileEntry *FE = FileMgr.getFile(TmpDir.str())) {
238 : // Leave CurDir unset.
239 : // This file is a system header or C++ unfriendly if the old file is.
240 : //
241 : // Note that the temporary 'DirInfo' is required here, as either call to
242 : // getFileInfo could resize the vector and we don't want to rely on order
243 : // of evaluation.
244 48: unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo;
245 48: getFileInfo(FE).DirInfo = DirInfo;
246 96: return FE;
15: branch 1 taken
48: branch 2 taken
247 63: }
248 : }
249 :
250 648: CurDir = 0;
251 :
252 : // If this is a system #include, ignore the user #include locs.
633: branch 0 taken
15: branch 1 taken
253 648: unsigned i = isAngled ? SystemDirIdx : 0;
254 :
255 : // If this is a #include_next request, start searching after the directory the
256 : // file was found in.
43: branch 0 taken
605: branch 1 taken
257 648: if (FromDir)
258 43: i = FromDir-&SearchDirs[0];
259 :
260 : // Cache all of the lookups performed by this method. Many headers are
261 : // multiply included, and the "pragma once" optimization prevents them from
262 : // being relex/pp'd, but they would still have to search through a
263 : // (potentially huge) series of SearchDirs to find it.
264 : std::pair<unsigned, unsigned> &CacheLookup =
265 648: LookupFileCache.GetOrCreateValue(Filename).getValue();
266 :
267 : // If the entry has been previously looked up, the first value will be
268 : // non-zero. If the value is equal to i (the start point of our search), then
269 : // this is a matching hit.
203: branch 0 taken
445: branch 1 taken
270 648: if (CacheLookup.first == i+1) {
271 : // Skip querying potentially lots of directories for this lookup.
272 203: i = CacheLookup.second;
273 : } else {
274 : // Otherwise, this is the first query, or the previous query didn't match
275 : // our search start. We will fill in our found location below, so prime the
276 : // start point value.
277 445: CacheLookup.first = i+1;
278 : }
279 :
280 : // Check each directory in sequence to see if it contains this file.
1502: branch 1 taken
7: branch 2 taken
281 1509: for (; i != SearchDirs.size(); ++i) {
282 : const FileEntry *FE =
283 1502: SearchDirs[i].LookupFile(Filename, *this);
641: branch 0 taken
861: branch 1 taken
284 1502: if (!FE) continue;
285 :
286 641: CurDir = &SearchDirs[i];
287 :
288 : // This file is a system header or C++ unfriendly if the dir is.
289 641: getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic();
290 :
291 : // Remember this location for the next lookup we do.
292 641: CacheLookup.second = i;
293 641: return FE;
294 : }
295 :
296 : // Otherwise, didn't find it. Remember we didn't find this.
297 7: CacheLookup.second = SearchDirs.size();
298 7: return 0;
299 : }
300 :
301 : /// LookupSubframeworkHeader - Look up a subframework for the specified
302 : /// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
303 : /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
304 : /// is a subframework within Carbon.framework. If so, return the FileEntry
305 : /// for the designated file, otherwise return null.
306 : const FileEntry *HeaderSearch::
307 : LookupSubframeworkHeader(llvm::StringRef Filename,
308 7: const FileEntry *ContextFileEnt) {
0: branch 0 not taken
7: branch 1 taken
309 7: assert(ContextFileEnt && "No context file?");
310 :
311 : // Framework names must have a '/' in the filename. Find it.
312 7: size_t SlashPos = Filename.find('/');
7: branch 0 taken
0: branch 1 not taken
313 7: if (SlashPos == llvm::StringRef::npos) return 0;
314 :
315 : // Look up the base framework name of the ContextFileEnt.
316 0: const char *ContextName = ContextFileEnt->getName();
317 :
318 : // If the context info wasn't a framework, couldn't be a subframework.
319 0: const char *FrameworkPos = strstr(ContextName, ".framework/");
0: branch 0 not taken
0: branch 1 not taken
320 0: if (FrameworkPos == 0)
321 0: return 0;
322 :
323 : llvm::SmallString<1024> FrameworkName(ContextName,
324 0: FrameworkPos+strlen(".framework/"));
325 :
326 : // Append Frameworks/HIToolbox.framework/
327 0: FrameworkName += "Frameworks/";
328 0: FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
329 0: FrameworkName += ".framework/";
330 :
331 : llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
332 0: FrameworkMap.GetOrCreateValue(Filename.begin(), Filename.begin()+SlashPos);
333 :
334 : // Some other location?
0: branch 1 not taken
0: branch 2 not taken
0: branch 5 not taken
0: branch 6 not taken
0: branch 11 not taken
0: branch 12 not taken
0: branch 13 not taken
0: branch 14 not taken
335 0: if (CacheLookup.getValue() &&
336 : CacheLookup.getKeyLength() == FrameworkName.size() &&
337 : memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
338 : CacheLookup.getKeyLength()) != 0)
339 0: return 0;
340 :
341 : // Cache subframework.
0: branch 1 not taken
0: branch 2 not taken
342 0: if (CacheLookup.getValue() == 0) {
343 0: ++NumSubFrameworkLookups;
344 :
345 : // If the framework dir doesn't exist, we fail.
346 : const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.begin(),
347 0: FrameworkName.end());
0: branch 0 not taken
0: branch 1 not taken
348 0: if (Dir == 0) return 0;
349 :
350 : // Otherwise, if it does, remember that this is the right direntry for this
351 : // framework.
352 0: CacheLookup.setValue(Dir);
353 : }
354 :
355 0: const FileEntry *FE = 0;
356 :
357 : // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
358 0: llvm::SmallString<1024> HeadersFilename(FrameworkName);
359 0: HeadersFilename += "Headers/";
360 0: HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
0: branch 3 not taken
0: branch 4 not taken
361 0: if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
362 : HeadersFilename.end()))) {
363 :
364 : // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
365 0: HeadersFilename = FrameworkName;
366 0: HeadersFilename += "PrivateHeaders/";
367 0: HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
0: branch 3 not taken
0: branch 4 not taken
368 0: if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end())))
369 0: return 0;
370 : }
371 :
372 : // This file is a system header or C++ unfriendly if the old file is.
373 : //
374 : // Note that the temporary 'DirInfo' is required here, as either call to
375 : // getFileInfo could resize the vector and we don't want to rely on order
376 : // of evaluation.
377 0: unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
378 0: getFileInfo(FE).DirInfo = DirInfo;
379 0: return FE;
380 : }
381 :
382 : //===----------------------------------------------------------------------===//
383 : // File Info Management.
384 : //===----------------------------------------------------------------------===//
385 :
386 :
387 : /// getFileInfo - Return the HeaderFileInfo structure for the specified
388 : /// FileEntry.
389 4695: HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
2927: branch 2 taken
1768: branch 3 taken
390 4695: if (FE->getUID() >= FileInfo.size())
391 2927: FileInfo.resize(FE->getUID()+1);
392 4695: return FileInfo[FE->getUID()];
393 : }
394 :
395 56: void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
56: branch 1 taken
0: branch 2 not taken
396 56: if (UID >= FileInfo.size())
397 56: FileInfo.resize(UID+1);
398 56: FileInfo[UID] = HFI;
399 56: }
400 :
401 : /// ShouldEnterIncludeFile - Mark the specified file as a target of of a
402 : /// #include, #include_next, or #import directive. Return false if #including
403 : /// the file will have no effect or true if we should include it.
404 684: bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
405 684: ++NumIncluded; // Count # of attempted #includes.
406 :
407 : // Get information about this file.
408 684: HeaderFileInfo &FileInfo = getFileInfo(File);
409 :
410 : // If this is a #import directive, check that we have not already imported
411 : // this header.
4: branch 0 taken
680: branch 1 taken
412 684: if (isImport) {
413 : // If this has already been imported, don't import it again.
414 4: FileInfo.isImport = true;
415 :
416 : // Has this already been #import'ed or #include'd?
3: branch 0 taken
1: branch 1 taken
417 4: if (FileInfo.NumIncludes) return false;
418 : } else {
419 : // Otherwise, if this is a #include of a file that was previously #import'd
420 : // or if this is the second #include of a #pragma once file, ignore it.
0: branch 0 not taken
680: branch 1 taken
421 680: if (FileInfo.isImport)
422 0: return false;
423 : }
424 :
425 : // Next, check to see if the file is wrapped with #ifndef guards. If so, and
426 : // if the macro that guards it is defined, we know the #include has no effect.
119: branch 0 taken
562: branch 1 taken
427 681: if (const IdentifierInfo *ControllingMacro
428 681: = FileInfo.getControllingMacro(ExternalLookup))
113: branch 1 taken
6: branch 2 taken
429 119: if (ControllingMacro->hasMacroDefinition()) {
430 113: ++NumMultiIncludeFileOptzn;
431 113: return false;
432 : }
433 :
434 : // Increment the number of times this file has been included.
435 568: ++FileInfo.NumIncludes;
436 :
437 568: return true;
438 : }
439 :
440 :
Generated: 2010-02-10 01:31 by zcov