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