1 //===--- HeaderSearch.cpp - Resolve Header File Locations ---===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the DirectoryLookup and HeaderSearch interfaces.
12 //===----------------------------------------------------------------------===//
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/Support/FileSystem.h"
19 #include "llvm/Support/Path.h"
20 #include "llvm/ADT/SmallString.h"
22 using namespace clang
;
24 const IdentifierInfo
*
25 HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup
*External
) {
27 return ControllingMacro
;
29 if (!ControllingMacroID
|| !External
)
32 ControllingMacro
= External
->GetIdentifier(ControllingMacroID
);
33 return ControllingMacro
;
36 ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
38 HeaderSearch::HeaderSearch(FileManager
&FM
)
39 : FileMgr(FM
), FrameworkMap(64) {
41 NoCurDirSearch
= false;
46 NumMultiIncludeFileOptzn
= 0;
47 NumFrameworkLookups
= NumSubFrameworkLookups
= 0;
50 HeaderSearch::~HeaderSearch() {
52 for (unsigned i
= 0, e
= HeaderMaps
.size(); i
!= e
; ++i
)
53 delete HeaderMaps
[i
].second
;
56 void HeaderSearch::PrintStats() {
57 fprintf(stderr
, "\n*** HeaderSearch Stats:\n");
58 fprintf(stderr
, "%d files tracked.\n", (int)FileInfo
.size());
59 unsigned NumOnceOnlyFiles
= 0, MaxNumIncludes
= 0, NumSingleIncludedFiles
= 0;
60 for (unsigned i
= 0, e
= FileInfo
.size(); i
!= e
; ++i
) {
61 NumOnceOnlyFiles
+= FileInfo
[i
].isImport
;
62 if (MaxNumIncludes
< FileInfo
[i
].NumIncludes
)
63 MaxNumIncludes
= FileInfo
[i
].NumIncludes
;
64 NumSingleIncludedFiles
+= FileInfo
[i
].NumIncludes
== 1;
66 fprintf(stderr
, " %d #import/#pragma once files.\n", NumOnceOnlyFiles
);
67 fprintf(stderr
, " %d included exactly once.\n", NumSingleIncludedFiles
);
68 fprintf(stderr
, " %d max times a file is included.\n", MaxNumIncludes
);
70 fprintf(stderr
, " %d #include/#include_next/#import.\n", NumIncluded
);
71 fprintf(stderr
, " %d #includes skipped due to"
72 " the multi-include optimization.\n", NumMultiIncludeFileOptzn
);
74 fprintf(stderr
, "%d framework lookups.\n", NumFrameworkLookups
);
75 fprintf(stderr
, "%d subframework lookups.\n", NumSubFrameworkLookups
);
78 /// CreateHeaderMap - This method returns a HeaderMap for the specified
79 /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
80 const HeaderMap
*HeaderSearch::CreateHeaderMap(const FileEntry
*FE
) {
81 // We expect the number of headermaps to be small, and almost always empty.
82 // If it ever grows, use of a linear search should be re-evaluated.
83 if (!HeaderMaps
.empty()) {
84 for (unsigned i
= 0, e
= HeaderMaps
.size(); i
!= e
; ++i
)
85 // Pointer equality comparison of FileEntries works because they are
86 // already uniqued by inode.
87 if (HeaderMaps
[i
].first
== FE
)
88 return HeaderMaps
[i
].second
;
91 if (const HeaderMap
*HM
= HeaderMap::Create(FE
, FileMgr
)) {
92 HeaderMaps
.push_back(std::make_pair(FE
, HM
));
99 //===----------------------------------------------------------------------===//
100 // File lookup within a DirectoryLookup scope
101 //===----------------------------------------------------------------------===//
103 /// getName - Return the directory or filename corresponding to this lookup
105 const char *DirectoryLookup::getName() const {
107 return getDir()->getName();
109 return getFrameworkDir()->getName();
110 assert(isHeaderMap() && "Unknown DirectoryLookup");
111 return getHeaderMap()->getFileName();
115 /// LookupFile - Lookup the specified file in this search path, returning it
116 /// if it exists or returning null if not.
117 const FileEntry
*DirectoryLookup::LookupFile(llvm::StringRef Filename
,
118 HeaderSearch
&HS
) const {
119 llvm::SmallString
<1024> TmpDir
;
121 // Concatenate the requested file onto the directory.
122 // FIXME: Portability. Filename concatenation should be in sys::Path.
123 TmpDir
+= getDir()->getName();
124 TmpDir
.push_back('/');
125 TmpDir
.append(Filename
.begin(), Filename
.end());
126 return HS
.getFileMgr().getFile(TmpDir
.str());
130 return DoFrameworkLookup(Filename
, HS
);
132 assert(isHeaderMap() && "Unknown directory lookup");
133 return getHeaderMap()->LookupFile(Filename
, HS
.getFileMgr());
137 /// DoFrameworkLookup - Do a lookup of the specified file in the current
138 /// DirectoryLookup, which is a framework directory.
139 const FileEntry
*DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename
,
140 HeaderSearch
&HS
) const {
141 FileManager
&FileMgr
= HS
.getFileMgr();
143 // Framework names must have a '/' in the filename.
144 size_t SlashPos
= Filename
.find('/');
145 if (SlashPos
== llvm::StringRef::npos
) return 0;
147 // Find out if this is the home for the specified framework, by checking
148 // HeaderSearch. Possible answer are yes/no and unknown.
149 const DirectoryEntry
*&FrameworkDirCache
=
150 HS
.LookupFrameworkCache(Filename
.substr(0, SlashPos
));
152 // If it is known and in some other directory, fail.
153 if (FrameworkDirCache
&& FrameworkDirCache
!= getFrameworkDir())
156 // Otherwise, construct the path to this framework dir.
158 // FrameworkName = "/System/Library/Frameworks/"
159 llvm::SmallString
<1024> FrameworkName
;
160 FrameworkName
+= getFrameworkDir()->getName();
161 if (FrameworkName
.empty() || FrameworkName
.back() != '/')
162 FrameworkName
.push_back('/');
164 // FrameworkName = "/System/Library/Frameworks/Cocoa"
165 FrameworkName
.append(Filename
.begin(), Filename
.begin()+SlashPos
);
167 // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
168 FrameworkName
+= ".framework/";
170 // If the cache entry is still unresolved, query to see if the cache entry is
171 // still unresolved. If so, check its existence now.
172 if (FrameworkDirCache
== 0) {
173 HS
.IncrementFrameworkLookupCount();
175 // If the framework dir doesn't exist, we fail.
176 // FIXME: It's probably more efficient to query this with FileMgr.getDir.
178 if (llvm::sys::fs::exists(FrameworkName
.str(), Exists
) || !Exists
)
181 // Otherwise, if it does, remember that this is the right direntry for this
183 FrameworkDirCache
= getFrameworkDir();
186 // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
187 unsigned OrigSize
= FrameworkName
.size();
189 FrameworkName
+= "Headers/";
190 FrameworkName
.append(Filename
.begin()+SlashPos
+1, Filename
.end());
191 if (const FileEntry
*FE
= FileMgr
.getFile(FrameworkName
.str()))
194 // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
195 const char *Private
= "Private";
196 FrameworkName
.insert(FrameworkName
.begin()+OrigSize
, Private
,
197 Private
+strlen(Private
));
198 return FileMgr
.getFile(FrameworkName
.str());
202 //===----------------------------------------------------------------------===//
203 // Header File Location.
204 //===----------------------------------------------------------------------===//
207 /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
208 /// return null on failure. isAngled indicates whether the file reference is
209 /// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if
210 /// non-null, indicates where the #including file is, in case a relative search
212 const FileEntry
*HeaderSearch::LookupFile(llvm::StringRef Filename
,
214 const DirectoryLookup
*FromDir
,
215 const DirectoryLookup
*&CurDir
,
216 const FileEntry
*CurFileEnt
) {
217 // If 'Filename' is absolute, check to see if it exists and no searching.
218 if (llvm::sys::path::is_absolute(Filename
)) {
221 // If this was an #include_next "/absolute/file", fail.
222 if (FromDir
) return 0;
224 // Otherwise, just return the file.
225 return FileMgr
.getFile(Filename
);
228 // Step #0, unless disabled, check to see if the file is in the #includer's
229 // directory. This has to be based on CurFileEnt, not CurDir, because
230 // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
231 // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
232 // This search is not done for <> headers.
233 if (CurFileEnt
&& !isAngled
&& !NoCurDirSearch
) {
234 llvm::SmallString
<1024> TmpDir
;
235 // Concatenate the requested file onto the directory.
236 // FIXME: Portability. Filename concatenation should be in sys::Path.
237 TmpDir
+= CurFileEnt
->getDir()->getName();
238 TmpDir
.push_back('/');
239 TmpDir
.append(Filename
.begin(), Filename
.end());
240 if (const FileEntry
*FE
= FileMgr
.getFile(TmpDir
.str())) {
241 // Leave CurDir unset.
242 // This file is a system header or C++ unfriendly if the old file is.
244 // Note that the temporary 'DirInfo' is required here, as either call to
245 // getFileInfo could resize the vector and we don't want to rely on order
247 unsigned DirInfo
= getFileInfo(CurFileEnt
).DirInfo
;
248 getFileInfo(FE
).DirInfo
= DirInfo
;
255 // If this is a system #include, ignore the user #include locs.
256 unsigned i
= isAngled
? SystemDirIdx
: 0;
258 // If this is a #include_next request, start searching after the directory the
259 // file was found in.
261 i
= FromDir
-&SearchDirs
[0];
263 // Cache all of the lookups performed by this method. Many headers are
264 // multiply included, and the "pragma once" optimization prevents them from
265 // being relex/pp'd, but they would still have to search through a
266 // (potentially huge) series of SearchDirs to find it.
267 std::pair
<unsigned, unsigned> &CacheLookup
=
268 LookupFileCache
.GetOrCreateValue(Filename
).getValue();
270 // If the entry has been previously looked up, the first value will be
271 // non-zero. If the value is equal to i (the start point of our search), then
272 // this is a matching hit.
273 if (CacheLookup
.first
== i
+1) {
274 // Skip querying potentially lots of directories for this lookup.
275 i
= CacheLookup
.second
;
277 // Otherwise, this is the first query, or the previous query didn't match
278 // our search start. We will fill in our found location below, so prime the
279 // start point value.
280 CacheLookup
.first
= i
+1;
283 // Check each directory in sequence to see if it contains this file.
284 for (; i
!= SearchDirs
.size(); ++i
) {
285 const FileEntry
*FE
=
286 SearchDirs
[i
].LookupFile(Filename
, *this);
289 CurDir
= &SearchDirs
[i
];
291 // This file is a system header or C++ unfriendly if the dir is.
292 getFileInfo(FE
).DirInfo
= CurDir
->getDirCharacteristic();
294 // Remember this location for the next lookup we do.
295 CacheLookup
.second
= i
;
299 // Otherwise, didn't find it. Remember we didn't find this.
300 CacheLookup
.second
= SearchDirs
.size();
304 /// LookupSubframeworkHeader - Look up a subframework for the specified
305 /// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
306 /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
307 /// is a subframework within Carbon.framework. If so, return the FileEntry
308 /// for the designated file, otherwise return null.
309 const FileEntry
*HeaderSearch::
310 LookupSubframeworkHeader(llvm::StringRef Filename
,
311 const FileEntry
*ContextFileEnt
) {
312 assert(ContextFileEnt
&& "No context file?");
314 // Framework names must have a '/' in the filename. Find it.
315 size_t SlashPos
= Filename
.find('/');
316 if (SlashPos
== llvm::StringRef::npos
) return 0;
318 // Look up the base framework name of the ContextFileEnt.
319 const char *ContextName
= ContextFileEnt
->getName();
321 // If the context info wasn't a framework, couldn't be a subframework.
322 const char *FrameworkPos
= strstr(ContextName
, ".framework/");
323 if (FrameworkPos
== 0)
326 llvm::SmallString
<1024> FrameworkName(ContextName
,
327 FrameworkPos
+strlen(".framework/"));
329 // Append Frameworks/HIToolbox.framework/
330 FrameworkName
+= "Frameworks/";
331 FrameworkName
.append(Filename
.begin(), Filename
.begin()+SlashPos
);
332 FrameworkName
+= ".framework/";
334 llvm::StringMapEntry
<const DirectoryEntry
*> &CacheLookup
=
335 FrameworkMap
.GetOrCreateValue(Filename
.substr(0, SlashPos
));
337 // Some other location?
338 if (CacheLookup
.getValue() &&
339 CacheLookup
.getKeyLength() == FrameworkName
.size() &&
340 memcmp(CacheLookup
.getKeyData(), &FrameworkName
[0],
341 CacheLookup
.getKeyLength()) != 0)
344 // Cache subframework.
345 if (CacheLookup
.getValue() == 0) {
346 ++NumSubFrameworkLookups
;
348 // If the framework dir doesn't exist, we fail.
349 const DirectoryEntry
*Dir
= FileMgr
.getDirectory(FrameworkName
.str());
350 if (Dir
== 0) return 0;
352 // Otherwise, if it does, remember that this is the right direntry for this
354 CacheLookup
.setValue(Dir
);
357 const FileEntry
*FE
= 0;
359 // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
360 llvm::SmallString
<1024> HeadersFilename(FrameworkName
);
361 HeadersFilename
+= "Headers/";
362 HeadersFilename
.append(Filename
.begin()+SlashPos
+1, Filename
.end());
363 if (!(FE
= FileMgr
.getFile(HeadersFilename
.str()))) {
365 // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
366 HeadersFilename
= FrameworkName
;
367 HeadersFilename
+= "PrivateHeaders/";
368 HeadersFilename
.append(Filename
.begin()+SlashPos
+1, Filename
.end());
369 if (!(FE
= FileMgr
.getFile(HeadersFilename
.str())))
373 // This file is a system header or C++ unfriendly if the old file is.
375 // Note that the temporary 'DirInfo' is required here, as either call to
376 // getFileInfo could resize the vector and we don't want to rely on order
378 unsigned DirInfo
= getFileInfo(ContextFileEnt
).DirInfo
;
379 getFileInfo(FE
).DirInfo
= DirInfo
;
383 //===----------------------------------------------------------------------===//
384 // File Info Management.
385 //===----------------------------------------------------------------------===//
388 /// getFileInfo - Return the HeaderFileInfo structure for the specified
390 HeaderFileInfo
&HeaderSearch::getFileInfo(const FileEntry
*FE
) {
391 if (FE
->getUID() >= FileInfo
.size())
392 FileInfo
.resize(FE
->getUID()+1);
394 HeaderFileInfo
&HFI
= FileInfo
[FE
->getUID()];
395 if (ExternalSource
&& !HFI
.Resolved
) {
396 HFI
= ExternalSource
->GetHeaderFileInfo(FE
);
402 void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI
, unsigned UID
) {
403 if (UID
>= FileInfo
.size())
404 FileInfo
.resize(UID
+1);
409 /// ShouldEnterIncludeFile - Mark the specified file as a target of of a
410 /// #include, #include_next, or #import directive. Return false if #including
411 /// the file will have no effect or true if we should include it.
412 bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry
*File
, bool isImport
){
413 ++NumIncluded
; // Count # of attempted #includes.
415 // Get information about this file.
416 HeaderFileInfo
&FileInfo
= getFileInfo(File
);
418 // If this is a #import directive, check that we have not already imported
421 // If this has already been imported, don't import it again.
422 FileInfo
.isImport
= true;
424 // Has this already been #import'ed or #include'd?
425 if (FileInfo
.NumIncludes
) return false;
427 // Otherwise, if this is a #include of a file that was previously #import'd
428 // or if this is the second #include of a #pragma once file, ignore it.
429 if (FileInfo
.isImport
)
433 // Next, check to see if the file is wrapped with #ifndef guards. If so, and
434 // if the macro that guards it is defined, we know the #include has no effect.
435 if (const IdentifierInfo
*ControllingMacro
436 = FileInfo
.getControllingMacro(ExternalLookup
))
437 if (ControllingMacro
->hasMacroDefinition()) {
438 ++NumMultiIncludeFileOptzn
;
442 // Increment the number of times this file has been included.
443 ++FileInfo
.NumIncludes
;