blob: f0bf9773251ce11c9fa5cc19be7bf8196c511d6c [file] [log] [blame]
Chris Lattner59a9ebd2006-10-18 05:34:33 +00001//===--- HeaderSearch.cpp - Resolve Header File Locations ---===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the DirectoryLookup and HeaderSearch interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Basic/FileManager.h"
15#include "clang/Lex/HeaderSearch.h"
16#include "clang/Lex/IdentifierTable.h"
17#include "llvm/System/Path.h"
18#include <iostream>
19using namespace llvm;
20using namespace clang;
21
22void HeaderSearch::PrintStats() {
23 std::cerr << "\n*** HeaderSearch Stats:\n";
24 std::cerr << FileInfo.size() << " files tracked.\n";
25 unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
26 for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
27 NumOnceOnlyFiles += FileInfo[i].isImport;
28 if (MaxNumIncludes < FileInfo[i].NumIncludes)
29 MaxNumIncludes = FileInfo[i].NumIncludes;
30 NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
31 }
32 std::cerr << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n";
33 std::cerr << " " << NumSingleIncludedFiles << " included exactly once.\n";
34 std::cerr << " " << MaxNumIncludes << " max times a file is included.\n";
35
36 std::cerr << " " << NumIncluded << " #include/#include_next/#import.\n";
37 std::cerr << " " << NumMultiIncludeFileOptzn << " #includes skipped due to"
38 << " the multi-include optimization.\n";
39
40}
41
42//===----------------------------------------------------------------------===//
43// Header File Location.
44//===----------------------------------------------------------------------===//
45
46static std::string DoFrameworkLookup(const DirectoryEntry *Dir,
47 const std::string &Filename) {
48 // TODO: caching.
49
50 // Framework names must have a '/' in the filename.
51 std::string::size_type SlashPos = Filename.find('/');
52 if (SlashPos == std::string::npos) return "";
53
54 // FrameworkName = "/System/Library/Frameworks/"
55 std::string FrameworkName = Dir->getName();
56 if (FrameworkName.empty() || FrameworkName[FrameworkName.size()-1] != '/')
57 FrameworkName += '/';
58
59 // FrameworkName = "/System/Library/Frameworks/Cocoa"
60 FrameworkName += std::string(Filename.begin(), Filename.begin()+SlashPos);
61
62 // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
63 FrameworkName += ".framework/";
64
65 // If the dir doesn't exist, give up.
66 if (!sys::Path(FrameworkName).exists()) return "";
67
68 // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
69 std::string HeadersFilename = FrameworkName + "Headers/" +
70 std::string(Filename.begin()+SlashPos+1, Filename.end());
71 if (sys::Path(HeadersFilename).exists()) return HeadersFilename;
72
73 // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
74 std::string PrivateHeadersFilename = FrameworkName + "PrivateHeaders/" +
75 std::string(Filename.begin()+SlashPos+1, Filename.end());
76 if (sys::Path(PrivateHeadersFilename).exists()) return HeadersFilename;
77
78 return "";
79}
80
81/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
82/// return null on failure. isAngled indicates whether the file reference is
83/// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if
84/// non-null, indicates where the #including file is, in case a relative search
85/// is needed.
86const FileEntry *HeaderSearch::LookupFile(const std::string &Filename,
87 bool isAngled,
88 const DirectoryLookup *FromDir,
89 const DirectoryLookup *&CurDir,
90 const FileEntry *CurFileEnt) {
91 // If 'Filename' is absolute, check to see if it exists and no searching.
92 // FIXME: Portability. This should be a sys::Path interface, this doesn't
93 // handle things like C:\foo.txt right, nor win32 \\network\device\blah.
94 if (Filename[0] == '/') {
95 CurDir = 0;
96
97 // If this was an #include_next "/absolute/file", fail.
98 if (FromDir) return 0;
99
100 // Otherwise, just return the file.
101 return FileMgr.getFile(Filename);
102 }
103
104 // Step #0, unless disabled, check to see if the file is in the #includer's
105 // directory. This search is not done for <> headers.
106 if (CurFileEnt && !NoCurDirSearch) {
107 // Concatenate the requested file onto the directory.
108 // FIXME: Portability. Filename concatenation should be in sys::Path.
109 if (const FileEntry *FE =
110 FileMgr.getFile(CurFileEnt->getDir()->getName()+"/"+Filename)) {
111 // Leave CurDir unset.
112
113 // This file is a system header or C++ unfriendly if the old file is.
114 getFileInfo(CurFileEnt).DirInfo = getFileInfo(CurFileEnt).DirInfo;
115 return FE;
116 }
117 }
118
119 CurDir = 0;
120
121 // If this is a system #include, ignore the user #include locs.
122 unsigned i = isAngled ? SystemDirIdx : 0;
123
124 // If this is a #include_next request, start searching after the directory the
125 // file was found in.
126 if (FromDir)
127 i = FromDir-&SearchDirs[0];
128
129 // Check each directory in sequence to see if it contains this file.
130 for (; i != SearchDirs.size(); ++i) {
131 // Concatenate the requested file onto the directory.
132 std::string SearchDir;
133
134 if (!SearchDirs[i].isFramework()) {
135 // FIXME: Portability. Adding file to dir should be in sys::Path.
136 SearchDir = SearchDirs[i].getDir()->getName()+"/"+Filename;
137 } else {
138 SearchDir = DoFrameworkLookup(SearchDirs[i].getDir(), Filename);
139 if (SearchDir.empty()) continue;
140 }
141
142 if (const FileEntry *FE = FileMgr.getFile(SearchDir)) {
143 CurDir = &SearchDirs[i];
144
145 // This file is a system header or C++ unfriendly if the dir is.
146 getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic();
147 return FE;
148 }
149 }
150
151 // Otherwise, didn't find it.
152 return 0;
153}
154
155//===----------------------------------------------------------------------===//
156// File Info Management.
157//===----------------------------------------------------------------------===//
158
159
160/// getFileInfo - Return the PerFileInfo structure for the specified
161/// FileEntry.
162HeaderSearch::PerFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
163 if (FE->getUID() >= FileInfo.size())
164 FileInfo.resize(FE->getUID()+1);
165 return FileInfo[FE->getUID()];
166}
167
168/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
169/// #include, #include_next, or #import directive. Return false if #including
170/// the file will have no effect or true if we should include it.
171bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
172 ++NumIncluded; // Count # of attempted #includes.
173
174 // Get information about this file.
175 PerFileInfo &FileInfo = getFileInfo(File);
176
177 // If this is a #import directive, check that we have not already imported
178 // this header.
179 if (isImport) {
180 // If this has already been imported, don't import it again.
181 FileInfo.isImport = true;
182
183 // Has this already been #import'ed or #include'd?
184 if (FileInfo.NumIncludes) return false;
185 } else {
186 // Otherwise, if this is a #include of a file that was previously #import'd
187 // or if this is the second #include of a #pragma once file, ignore it.
188 if (FileInfo.isImport)
189 return false;
190 }
191
192 // Next, check to see if the file is wrapped with #ifndef guards. If so, and
193 // if the macro that guards it is defined, we know the #include has no effect.
194 if (FileInfo.ControllingMacro && FileInfo.ControllingMacro->getMacroInfo()) {
195 ++NumMultiIncludeFileOptzn;
196 return false;
197 }
198
199 // Increment the number of times this file has been included.
200 ++FileInfo.NumIncludes;
201
202 return true;
203}
204
205