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 * 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 36 ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {} 37 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 51 HeaderSearch::~HeaderSearch() { 52 // Delete headermaps. 53 for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i) 54 delete HeaderMaps[i].second; 55 } 56 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. 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. 106 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. 118 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. 163 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. 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:: 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. 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 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 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. 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