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