2006-10-18 13:34:33 +08:00
|
|
|
//===--- HeaderSearch.cpp - Resolve Header File Locations ---===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-10-18 13:34:33 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the DirectoryLookup and HeaderSearch interfaces.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
2007-10-07 16:58:51 +08:00
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Basic/IdentifierTable.h"
|
2015-07-01 10:29:35 +08:00
|
|
|
#include "clang/Lex/ExternalPreprocessorSource.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Lex/HeaderMap.h"
|
|
|
|
#include "clang/Lex/HeaderSearchOptions.h"
|
2013-12-28 03:46:16 +08:00
|
|
|
#include "clang/Lex/LexDiagnostic.h"
|
2014-01-07 19:51:46 +08:00
|
|
|
#include "clang/Lex/Lexer.h"
|
2015-04-30 07:20:19 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2014-04-15 02:00:01 +08:00
|
|
|
#include "llvm/ADT/APInt.h"
|
|
|
|
#include "llvm/ADT/Hashing.h"
|
2006-10-30 11:40:58 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2011-07-28 02:41:18 +08:00
|
|
|
#include "llvm/Support/Capacity.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2009-03-03 06:20:04 +08:00
|
|
|
#include <cstdio>
|
2016-05-27 22:27:13 +08:00
|
|
|
#include <utility>
|
2013-01-23 07:49:45 +08:00
|
|
|
#if defined(LLVM_ON_UNIX)
|
2013-01-27 00:29:36 +08:00
|
|
|
#include <limits.h>
|
2013-01-23 07:49:45 +08:00
|
|
|
#endif
|
2006-10-18 13:34:33 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-04-26 07:30:02 +08:00
|
|
|
const IdentifierInfo *
|
2015-07-01 10:29:35 +08:00
|
|
|
HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) {
|
|
|
|
if (ControllingMacro) {
|
2016-11-04 14:32:57 +08:00
|
|
|
if (ControllingMacro->isOutOfDate()) {
|
|
|
|
assert(External && "We must have an external source if we have a "
|
|
|
|
"controlling macro that is out of date.");
|
2015-07-01 10:29:35 +08:00
|
|
|
External->updateOutOfDateIdentifier(
|
|
|
|
*const_cast<IdentifierInfo *>(ControllingMacro));
|
2016-11-04 14:32:57 +08:00
|
|
|
}
|
2009-04-26 07:30:02 +08:00
|
|
|
return ControllingMacro;
|
2015-07-01 10:29:35 +08:00
|
|
|
}
|
2009-04-26 07:30:02 +08:00
|
|
|
|
|
|
|
if (!ControllingMacroID || !External)
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2009-04-26 07:30:02 +08:00
|
|
|
|
|
|
|
ControllingMacro = External->GetIdentifier(ControllingMacroID);
|
|
|
|
return ControllingMacro;
|
|
|
|
}
|
|
|
|
|
2015-10-20 21:23:58 +08:00
|
|
|
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
|
2017-01-06 09:04:46 +08:00
|
|
|
HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts,
|
Use the same SourceManager for ModuleMaps and compilations.
This allows using virtual file mappings on the original SourceManager to
map in virtual module.map files. Without this patch, the ModuleMap
search will find a module.map file (as the FileEntry exists in the
FileManager), but will be unable to get the content from the
SourceManager (as ModuleMap previously created its own SourceManager).
Two problems needed to be fixed which this patch exposed:
1. Storing the inferred module map
When writing out a module, the ASTWriter stores the names of the files
in the main source manager; when loading the AST again, the ASTReader
errs out if such a file is found missing, unless it is overridden.
Previously CompilerInstance's compileModule method would store the
inferred module map to a temporary file; the problem with this approach
is that now that the module map is handled by the main source manager,
the ASTWriter stores the name of the temporary module map as source to
the compilation; later, when the module is loaded, the temporary file
has already been deleted, which leads to a compilation error. This patch
changes the inferred module map to instead inject a virtual file into
the source manager. This both saves some disk IO, and works with how the
ASTWriter/ASTReader handle overridden source files.
2. Changing test input in test/Modules/Inputs/*
Now that the module map file is handled by the main source manager, the
VerifyDiagnosticConsumer will not ignore diagnostics created while
parsing the module map file. The module test test/Modules/renamed.m uses
-I test/Modules/Inputs and triggers recursive loading of all module maps
in test/Modules/Inputs, some of which had conflicting names, thus
leading errors while parsing the module maps. Those diagnostics already
occur on trunk, but before this patch they would not break the test, as
they were ignored by the VerifyDiagnosticConsumer. This patch thus
changes the module maps that have been recently introduced which broke
the invariant of compatible modules maps in test/Modules/Inputs.
llvm-svn: 193314
2013-10-24 15:51:24 +08:00
|
|
|
SourceManager &SourceMgr, DiagnosticsEngine &Diags,
|
2013-12-28 03:46:16 +08:00
|
|
|
const LangOptions &LangOpts,
|
2012-01-30 14:01:29 +08:00
|
|
|
const TargetInfo *Target)
|
2016-05-27 22:27:13 +08:00
|
|
|
: HSOpts(std::move(HSOpts)), Diags(Diags),
|
|
|
|
FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
|
|
|
|
ModMap(SourceMgr, Diags, LangOpts, Target, *this) {
|
2011-05-24 12:31:14 +08:00
|
|
|
AngledDirIdx = 0;
|
2006-10-20 14:23:14 +08:00
|
|
|
SystemDirIdx = 0;
|
|
|
|
NoCurDirSearch = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
ExternalLookup = nullptr;
|
|
|
|
ExternalSource = nullptr;
|
2006-10-20 14:23:14 +08:00
|
|
|
NumIncluded = 0;
|
|
|
|
NumMultiIncludeFileOptzn = 0;
|
|
|
|
NumFrameworkLookups = NumSubFrameworkLookups = 0;
|
|
|
|
}
|
|
|
|
|
2007-12-17 14:36:45 +08:00
|
|
|
HeaderSearch::~HeaderSearch() {
|
|
|
|
// Delete headermaps.
|
|
|
|
for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
|
|
|
|
delete HeaderMaps[i].second;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
void HeaderSearch::PrintStats() {
|
2007-06-16 07:05:46 +08:00
|
|
|
fprintf(stderr, "\n*** HeaderSearch Stats:\n");
|
|
|
|
fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size());
|
2006-10-18 13:34:33 +08:00
|
|
|
unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
|
|
|
|
for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
|
|
|
|
NumOnceOnlyFiles += FileInfo[i].isImport;
|
|
|
|
if (MaxNumIncludes < FileInfo[i].NumIncludes)
|
|
|
|
MaxNumIncludes = FileInfo[i].NumIncludes;
|
|
|
|
NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
|
|
|
|
}
|
2007-06-16 07:05:46 +08:00
|
|
|
fprintf(stderr, " %d #import/#pragma once files.\n", NumOnceOnlyFiles);
|
|
|
|
fprintf(stderr, " %d included exactly once.\n", NumSingleIncludedFiles);
|
|
|
|
fprintf(stderr, " %d max times a file is included.\n", MaxNumIncludes);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
fprintf(stderr, " %d #include/#include_next/#import.\n", NumIncluded);
|
|
|
|
fprintf(stderr, " %d #includes skipped due to"
|
|
|
|
" the multi-include optimization.\n", NumMultiIncludeFileOptzn);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
fprintf(stderr, "%d framework lookups.\n", NumFrameworkLookups);
|
|
|
|
fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups);
|
2006-10-18 13:34:33 +08:00
|
|
|
}
|
|
|
|
|
2007-12-17 14:36:45 +08:00
|
|
|
/// CreateHeaderMap - This method returns a HeaderMap for the specified
|
2012-07-23 16:59:39 +08:00
|
|
|
/// FileEntry, uniquing them through the 'HeaderMaps' datastructure.
|
2007-12-18 02:34:53 +08:00
|
|
|
const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
|
2007-12-17 14:36:45 +08:00
|
|
|
// We expect the number of headermaps to be small, and almost always empty.
|
2007-12-17 15:52:39 +08:00
|
|
|
// If it ever grows, use of a linear search should be re-evaluated.
|
2007-12-17 14:36:45 +08:00
|
|
|
if (!HeaderMaps.empty()) {
|
|
|
|
for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
|
2007-12-17 15:52:39 +08:00
|
|
|
// Pointer equality comparison of FileEntries works because they are
|
|
|
|
// already uniqued by inode.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (HeaderMaps[i].first == FE)
|
2007-12-17 14:36:45 +08:00
|
|
|
return HeaderMaps[i].second;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-23 16:35:12 +08:00
|
|
|
if (const HeaderMap *HM = HeaderMap::Create(FE, FileMgr)) {
|
2007-12-17 14:36:45 +08:00
|
|
|
HeaderMaps.push_back(std::make_pair(FE, HM));
|
|
|
|
return HM;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2007-12-17 14:36:45 +08:00
|
|
|
}
|
|
|
|
|
2016-12-11 12:27:28 +08:00
|
|
|
/// \brief Get filenames for all registered header maps.
|
|
|
|
void HeaderSearch::getHeaderMapFileNames(
|
|
|
|
SmallVectorImpl<std::string> &Names) const {
|
|
|
|
for (auto &HM : HeaderMaps)
|
|
|
|
Names.push_back(HM.first->getName());
|
|
|
|
}
|
|
|
|
|
2017-08-31 14:26:43 +08:00
|
|
|
std::string HeaderSearch::getCachedModuleFileName(Module *Module) {
|
2014-08-09 08:57:23 +08:00
|
|
|
const FileEntry *ModuleMap =
|
|
|
|
getModuleMap().getModuleMapFileForUniquing(Module);
|
2017-08-31 14:26:43 +08:00
|
|
|
return getCachedModuleFileName(Module->Name, ModuleMap->getName());
|
2012-01-30 01:08:11 +08:00
|
|
|
}
|
|
|
|
|
2017-08-31 14:26:43 +08:00
|
|
|
std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName,
|
|
|
|
bool FileMapOnly) {
|
|
|
|
// First check the module name to pcm file map.
|
|
|
|
auto i (HSOpts->PrebuiltModuleFiles.find(ModuleName));
|
|
|
|
if (i != HSOpts->PrebuiltModuleFiles.end())
|
|
|
|
return i->second;
|
|
|
|
|
|
|
|
if (FileMapOnly || HSOpts->PrebuiltModulePaths.empty())
|
2016-08-19 01:42:15 +08:00
|
|
|
return std::string();
|
|
|
|
|
2017-08-31 14:26:43 +08:00
|
|
|
// Then go through each prebuilt module directory and try to find the pcm
|
|
|
|
// file.
|
2016-08-19 01:42:15 +08:00
|
|
|
for (const std::string &Dir : HSOpts->PrebuiltModulePaths) {
|
|
|
|
SmallString<256> Result(Dir);
|
|
|
|
llvm::sys::fs::make_absolute(Result);
|
|
|
|
|
|
|
|
llvm::sys::path::append(Result, ModuleName + ".pcm");
|
|
|
|
if (getFileMgr().getFile(Result.str()))
|
|
|
|
return Result.str().str();
|
|
|
|
}
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
2017-08-31 14:26:43 +08:00
|
|
|
std::string HeaderSearch::getCachedModuleFileName(StringRef ModuleName,
|
|
|
|
StringRef ModuleMapPath) {
|
2015-07-22 02:07:47 +08:00
|
|
|
// If we don't have a module cache path or aren't supposed to use one, we
|
|
|
|
// can't do anything.
|
2015-08-15 08:34:15 +08:00
|
|
|
if (getModuleCachePath().empty())
|
2012-01-30 01:08:11 +08:00
|
|
|
return std::string();
|
2014-04-15 02:00:01 +08:00
|
|
|
|
2015-08-15 08:34:15 +08:00
|
|
|
SmallString<256> Result(getModuleCachePath());
|
2014-04-15 02:00:01 +08:00
|
|
|
llvm::sys::fs::make_absolute(Result);
|
|
|
|
|
|
|
|
if (HSOpts->DisableModuleHash) {
|
|
|
|
llvm::sys::path::append(Result, ModuleName + ".pcm");
|
|
|
|
} else {
|
|
|
|
// Construct the name <ModuleName>-<hash of ModuleMapPath>.pcm which should
|
2014-12-12 04:50:24 +08:00
|
|
|
// ideally be globally unique to this particular module. Name collisions
|
|
|
|
// in the hash are safe (because any translation unit can only import one
|
|
|
|
// module with each name), but result in a loss of caching.
|
|
|
|
//
|
|
|
|
// To avoid false-negatives, we form as canonical a path as we can, and map
|
|
|
|
// to lower-case in case we're on a case-insensitive file system.
|
2017-03-09 08:58:22 +08:00
|
|
|
std::string Parent = llvm::sys::path::parent_path(ModuleMapPath);
|
|
|
|
if (Parent.empty())
|
|
|
|
Parent = ".";
|
|
|
|
auto *Dir = FileMgr.getDirectory(Parent);
|
2014-12-12 04:50:24 +08:00
|
|
|
if (!Dir)
|
|
|
|
return std::string();
|
|
|
|
auto DirName = FileMgr.getCanonicalName(Dir);
|
|
|
|
auto FileName = llvm::sys::path::filename(ModuleMapPath);
|
|
|
|
|
|
|
|
llvm::hash_code Hash =
|
2016-01-13 05:01:56 +08:00
|
|
|
llvm::hash_combine(DirName.lower(), FileName.lower());
|
2014-12-12 04:50:24 +08:00
|
|
|
|
2014-04-15 02:00:01 +08:00
|
|
|
SmallString<128> HashStr;
|
2014-12-12 04:50:24 +08:00
|
|
|
llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
|
2015-03-18 18:17:07 +08:00
|
|
|
llvm::sys::path::append(Result, ModuleName + "-" + HashStr + ".pcm");
|
2014-04-15 02:00:01 +08:00
|
|
|
}
|
2012-01-30 01:08:11 +08:00
|
|
|
return Result.str().str();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
|
2011-11-12 08:05:07 +08:00
|
|
|
// Look in the module map to determine if there is a module by this name.
|
2012-01-30 01:08:11 +08:00
|
|
|
Module *Module = ModMap.findModule(ModuleName);
|
2015-06-16 08:08:24 +08:00
|
|
|
if (Module || !AllowSearch || !HSOpts->ImplicitModuleMaps)
|
2012-01-30 01:08:11 +08:00
|
|
|
return Module;
|
[modules] Handle modules with nonstandard names in module.private.modulemaps
Summary:
The module system supports accompanying a primary module (say Foo) with
an auxiliary "private" module (defined in an adjacent module.private.modulemap
file) that augments the primary module when associated private headers are
available. The feature is intended to be used to augment the primary
module with a submodule (say Foo.Private), however some users in the wild
are choosing to augment the primary module with an additional top-level module
with a "similar" name (in all cases so far: FooPrivate).
This "works" when a user of the module initially imports a private header,
such as '#import "Foo/something_private.h"' since the Foo import winds up
importing FooPrivate in passing. But if the import is subsequently recorded
in a PCH file, reloading the PCH will fail to validate because of a cross-check
that attempts to find the module.modulemap (or module.private.modulemap) using
HeaderSearch algorithm, applied to the "FooPrivate" name. Since it's stored in
Foo.framework/Modules, not FooPrivate.framework/Modules, the check fails and
the PCH is rejected.
This patch adds a compensatory workaround in the HeaderSearch algorithm
when searching (and failing to find) a module of the form FooPrivate: the
name used to derive filesystem paths is decoupled from the module name
being searched for, and if the initial search fails and the module is
named "FooPrivate", the filesystem search name is altered to remove the
"Private" suffix, and the algorithm is run a second time (still looking for
a module named FooPrivate, but looking in directories derived from Foo).
Accompanying this change is a new warning that triggers when a user loads
a module.private.modulemap that defines a top-level module with a different
name from the top-level module defined in its adjacent module.modulemap.
Reviewers: doug.gregor, manmanren, bruno
Subscribers: bruno, cfe-commits
Differential Revision: https://reviews.llvm.org/D27852
llvm-svn: 290219
2016-12-21 08:24:39 +08:00
|
|
|
|
|
|
|
StringRef SearchName = ModuleName;
|
|
|
|
Module = lookupModule(ModuleName, SearchName);
|
|
|
|
|
|
|
|
// The facility for "private modules" -- adjacent, optional module maps named
|
|
|
|
// module.private.modulemap that are supposed to define private submodules --
|
|
|
|
// is sometimes misused by frameworks that name their associated private
|
|
|
|
// module FooPrivate, rather than as a submodule named Foo.Private as
|
|
|
|
// intended. Here we compensate for such cases by looking in directories named
|
|
|
|
// Foo.framework, when we previously looked and failed to find a
|
|
|
|
// FooPrivate.framework.
|
|
|
|
if (!Module && SearchName.consume_back("Private"))
|
|
|
|
Module = lookupModule(ModuleName, SearchName);
|
|
|
|
return Module;
|
|
|
|
}
|
|
|
|
|
|
|
|
Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName) {
|
|
|
|
Module *Module = nullptr;
|
|
|
|
|
2013-01-10 09:43:00 +08:00
|
|
|
// Look through the various header search paths to load any available module
|
2012-01-30 01:08:11 +08:00
|
|
|
// maps, searching for a module map that describes this module.
|
|
|
|
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
|
|
|
|
if (SearchDirs[Idx].isFramework()) {
|
[modules] Handle modules with nonstandard names in module.private.modulemaps
Summary:
The module system supports accompanying a primary module (say Foo) with
an auxiliary "private" module (defined in an adjacent module.private.modulemap
file) that augments the primary module when associated private headers are
available. The feature is intended to be used to augment the primary
module with a submodule (say Foo.Private), however some users in the wild
are choosing to augment the primary module with an additional top-level module
with a "similar" name (in all cases so far: FooPrivate).
This "works" when a user of the module initially imports a private header,
such as '#import "Foo/something_private.h"' since the Foo import winds up
importing FooPrivate in passing. But if the import is subsequently recorded
in a PCH file, reloading the PCH will fail to validate because of a cross-check
that attempts to find the module.modulemap (or module.private.modulemap) using
HeaderSearch algorithm, applied to the "FooPrivate" name. Since it's stored in
Foo.framework/Modules, not FooPrivate.framework/Modules, the check fails and
the PCH is rejected.
This patch adds a compensatory workaround in the HeaderSearch algorithm
when searching (and failing to find) a module of the form FooPrivate: the
name used to derive filesystem paths is decoupled from the module name
being searched for, and if the initial search fails and the module is
named "FooPrivate", the filesystem search name is altered to remove the
"Private" suffix, and the algorithm is run a second time (still looking for
a module named FooPrivate, but looking in directories derived from Foo).
Accompanying this change is a new warning that triggers when a user loads
a module.private.modulemap that defines a top-level module with a different
name from the top-level module defined in its adjacent module.modulemap.
Reviewers: doug.gregor, manmanren, bruno
Subscribers: bruno, cfe-commits
Differential Revision: https://reviews.llvm.org/D27852
llvm-svn: 290219
2016-12-21 08:24:39 +08:00
|
|
|
// Search for or infer a module map for a framework. Here we use
|
|
|
|
// SearchName rather than ModuleName, to permit finding private modules
|
|
|
|
// named FooPrivate in buggy frameworks named Foo.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> FrameworkDirName;
|
2012-01-30 01:08:11 +08:00
|
|
|
FrameworkDirName += SearchDirs[Idx].getFrameworkDir()->getName();
|
[modules] Handle modules with nonstandard names in module.private.modulemaps
Summary:
The module system supports accompanying a primary module (say Foo) with
an auxiliary "private" module (defined in an adjacent module.private.modulemap
file) that augments the primary module when associated private headers are
available. The feature is intended to be used to augment the primary
module with a submodule (say Foo.Private), however some users in the wild
are choosing to augment the primary module with an additional top-level module
with a "similar" name (in all cases so far: FooPrivate).
This "works" when a user of the module initially imports a private header,
such as '#import "Foo/something_private.h"' since the Foo import winds up
importing FooPrivate in passing. But if the import is subsequently recorded
in a PCH file, reloading the PCH will fail to validate because of a cross-check
that attempts to find the module.modulemap (or module.private.modulemap) using
HeaderSearch algorithm, applied to the "FooPrivate" name. Since it's stored in
Foo.framework/Modules, not FooPrivate.framework/Modules, the check fails and
the PCH is rejected.
This patch adds a compensatory workaround in the HeaderSearch algorithm
when searching (and failing to find) a module of the form FooPrivate: the
name used to derive filesystem paths is decoupled from the module name
being searched for, and if the initial search fails and the module is
named "FooPrivate", the filesystem search name is altered to remove the
"Private" suffix, and the algorithm is run a second time (still looking for
a module named FooPrivate, but looking in directories derived from Foo).
Accompanying this change is a new warning that triggers when a user loads
a module.private.modulemap that defines a top-level module with a different
name from the top-level module defined in its adjacent module.modulemap.
Reviewers: doug.gregor, manmanren, bruno
Subscribers: bruno, cfe-commits
Differential Revision: https://reviews.llvm.org/D27852
llvm-svn: 290219
2016-12-21 08:24:39 +08:00
|
|
|
llvm::sys::path::append(FrameworkDirName, SearchName + ".framework");
|
|
|
|
if (const DirectoryEntry *FrameworkDir
|
2012-01-30 01:08:11 +08:00
|
|
|
= FileMgr.getDirectory(FrameworkDirName)) {
|
|
|
|
bool IsSystem
|
|
|
|
= SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User;
|
|
|
|
Module = loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
|
2011-11-12 08:05:07 +08:00
|
|
|
if (Module)
|
|
|
|
break;
|
|
|
|
}
|
2012-01-30 01:08:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Figure out how header maps and module maps will work together.
|
|
|
|
|
|
|
|
// Only deal with normal search directories.
|
|
|
|
if (!SearchDirs[Idx].isNormalDir())
|
|
|
|
continue;
|
2013-06-22 00:28:10 +08:00
|
|
|
|
|
|
|
bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
|
2012-01-30 01:08:11 +08:00
|
|
|
// Search for a module map file in this directory.
|
2014-03-20 04:23:34 +08:00
|
|
|
if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
|
|
|
|
/*IsFramework*/false) == LMM_NewlyLoaded) {
|
2012-01-30 01:08:11 +08:00
|
|
|
// We just loaded a module map file; check whether the module is
|
|
|
|
// available now.
|
|
|
|
Module = ModMap.findModule(ModuleName);
|
|
|
|
if (Module)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search for a module map in a subdirectory with the same name as the
|
|
|
|
// module.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> NestedModuleMapDirName;
|
2012-01-30 01:08:11 +08:00
|
|
|
NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName();
|
|
|
|
llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
|
2014-03-20 04:23:34 +08:00
|
|
|
if (loadModuleMapFile(NestedModuleMapDirName, IsSystem,
|
|
|
|
/*IsFramework*/false) == LMM_NewlyLoaded){
|
2012-01-30 01:08:11 +08:00
|
|
|
// If we just loaded a module map file, look for the module again.
|
|
|
|
Module = ModMap.findModule(ModuleName);
|
|
|
|
if (Module)
|
|
|
|
break;
|
2011-11-12 08:05:07 +08:00
|
|
|
}
|
2013-03-21 09:08:50 +08:00
|
|
|
|
|
|
|
// If we've already performed the exhaustive search for module maps in this
|
|
|
|
// search directory, don't do it again.
|
|
|
|
if (SearchDirs[Idx].haveSearchedAllModuleMaps())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Load all module maps in the immediate subdirectories of this search
|
|
|
|
// directory.
|
|
|
|
loadSubdirectoryModuleMaps(SearchDirs[Idx]);
|
|
|
|
|
|
|
|
// Look again for the module.
|
|
|
|
Module = ModMap.findModule(ModuleName);
|
|
|
|
if (Module)
|
|
|
|
break;
|
2011-11-12 08:05:07 +08:00
|
|
|
}
|
2013-03-21 09:08:50 +08:00
|
|
|
|
2012-01-30 01:08:11 +08:00
|
|
|
return Module;
|
2011-09-13 04:41:59 +08:00
|
|
|
}
|
|
|
|
|
2007-12-17 15:52:39 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// File lookup within a DirectoryLookup scope
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2007-12-18 01:57:27 +08:00
|
|
|
/// getName - Return the directory or filename corresponding to this lookup
|
|
|
|
/// object.
|
2016-10-02 00:38:28 +08:00
|
|
|
StringRef DirectoryLookup::getName() const {
|
2007-12-18 01:57:27 +08:00
|
|
|
if (isNormalDir())
|
|
|
|
return getDir()->getName();
|
|
|
|
if (isFramework())
|
|
|
|
return getFrameworkDir()->getName();
|
|
|
|
assert(isHeaderMap() && "Unknown DirectoryLookup");
|
|
|
|
return getHeaderMap()->getFileName();
|
|
|
|
}
|
|
|
|
|
2015-10-17 05:42:56 +08:00
|
|
|
const FileEntry *HeaderSearch::getFileAndSuggestModule(
|
2016-06-14 04:40:21 +08:00
|
|
|
StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
|
|
|
|
bool IsSystemHeaderDir, Module *RequestingModule,
|
|
|
|
ModuleMap::KnownHeader *SuggestedModule) {
|
2014-03-06 04:51:45 +08:00
|
|
|
// If we have a module map that might map this header, load it and
|
|
|
|
// check whether we'll have a suggestion for a module.
|
2015-10-17 05:42:56 +08:00
|
|
|
const FileEntry *File = getFileMgr().getFile(FileName, /*OpenFile=*/true);
|
2015-10-21 02:45:57 +08:00
|
|
|
if (!File)
|
|
|
|
return nullptr;
|
2014-03-06 04:51:45 +08:00
|
|
|
|
2015-10-17 05:42:56 +08:00
|
|
|
// If there is a module that corresponds to this header, suggest it.
|
|
|
|
if (!findUsableModuleForHeader(File, Dir ? Dir : File->getDir(),
|
|
|
|
RequestingModule, SuggestedModule,
|
|
|
|
IsSystemHeaderDir))
|
|
|
|
return nullptr;
|
2014-03-06 04:51:45 +08:00
|
|
|
|
2015-10-17 05:42:56 +08:00
|
|
|
return File;
|
2014-03-06 04:51:45 +08:00
|
|
|
}
|
2007-12-18 01:57:27 +08:00
|
|
|
|
2007-12-17 15:52:39 +08:00
|
|
|
/// LookupFile - Lookup the specified file in this search path, returning it
|
|
|
|
/// if it exists or returning null if not.
|
2011-03-17 02:34:36 +08:00
|
|
|
const FileEntry *DirectoryLookup::LookupFile(
|
2014-02-14 22:58:28 +08:00
|
|
|
StringRef &Filename,
|
2011-04-27 05:50:03 +08:00
|
|
|
HeaderSearch &HS,
|
2016-06-14 04:40:21 +08:00
|
|
|
SourceLocation IncludeLoc,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<char> *SearchPath,
|
2011-09-16 06:00:41 +08:00
|
|
|
SmallVectorImpl<char> *RelativePath,
|
2015-10-17 05:42:56 +08:00
|
|
|
Module *RequestingModule,
|
2013-06-21 05:14:14 +08:00
|
|
|
ModuleMap::KnownHeader *SuggestedModule,
|
2014-02-14 22:58:28 +08:00
|
|
|
bool &InUserSpecifiedSystemFramework,
|
2014-03-11 14:21:28 +08:00
|
|
|
bool &HasBeenMapped,
|
2014-02-14 22:58:28 +08:00
|
|
|
SmallVectorImpl<char> &MappedName) const {
|
2012-04-06 01:10:06 +08:00
|
|
|
InUserSpecifiedSystemFramework = false;
|
2014-03-11 14:21:28 +08:00
|
|
|
HasBeenMapped = false;
|
2012-04-06 01:10:06 +08:00
|
|
|
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<1024> TmpDir;
|
2007-12-17 16:13:48 +08:00
|
|
|
if (isNormalDir()) {
|
|
|
|
// Concatenate the requested file onto the directory.
|
2011-07-09 04:17:28 +08:00
|
|
|
TmpDir = getDir()->getName();
|
|
|
|
llvm::sys::path::append(TmpDir, Filename);
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath) {
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef SearchPathRef(getDir()->getName());
|
2011-04-27 05:50:03 +08:00
|
|
|
SearchPath->clear();
|
|
|
|
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
|
|
|
|
}
|
2014-05-18 07:10:59 +08:00
|
|
|
if (RelativePath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
RelativePath->clear();
|
|
|
|
RelativePath->append(Filename.begin(), Filename.end());
|
|
|
|
}
|
2014-03-06 04:51:45 +08:00
|
|
|
|
2016-06-14 04:40:21 +08:00
|
|
|
return HS.getFileAndSuggestModule(TmpDir, IncludeLoc, getDir(),
|
2015-10-17 05:42:56 +08:00
|
|
|
isSystemHeaderDirectory(),
|
|
|
|
RequestingModule, SuggestedModule);
|
2007-12-17 16:13:48 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
if (isFramework())
|
2011-09-16 06:00:41 +08:00
|
|
|
return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
|
2015-10-17 05:42:56 +08:00
|
|
|
RequestingModule, SuggestedModule,
|
|
|
|
InUserSpecifiedSystemFramework);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-17 16:17:39 +08:00
|
|
|
assert(isHeaderMap() && "Unknown directory lookup");
|
2014-02-14 22:58:28 +08:00
|
|
|
const HeaderMap *HM = getHeaderMap();
|
|
|
|
SmallString<1024> Path;
|
|
|
|
StringRef Dest = HM->lookupFilename(Filename, Path);
|
|
|
|
if (Dest.empty())
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2014-02-14 22:58:28 +08:00
|
|
|
|
|
|
|
const FileEntry *Result;
|
|
|
|
|
|
|
|
// Check if the headermap maps the filename to a framework include
|
|
|
|
// ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
|
|
|
|
// framework include.
|
|
|
|
if (llvm::sys::path::is_relative(Dest)) {
|
|
|
|
MappedName.clear();
|
|
|
|
MappedName.append(Dest.begin(), Dest.end());
|
|
|
|
Filename = StringRef(MappedName.begin(), MappedName.size());
|
2014-03-11 14:21:28 +08:00
|
|
|
HasBeenMapped = true;
|
2014-02-14 22:58:28 +08:00
|
|
|
Result = HM->LookupFile(Filename, HS.getFileMgr());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
Result = HS.getFileMgr().getFile(Dest);
|
|
|
|
}
|
|
|
|
|
2011-04-27 05:50:03 +08:00
|
|
|
if (Result) {
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath) {
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef SearchPathRef(getName());
|
2011-04-27 05:50:03 +08:00
|
|
|
SearchPath->clear();
|
|
|
|
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
|
|
|
|
}
|
2014-05-18 07:10:59 +08:00
|
|
|
if (RelativePath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
RelativePath->clear();
|
|
|
|
RelativePath->append(Filename.begin(), Filename.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Result;
|
2007-12-17 15:52:39 +08:00
|
|
|
}
|
|
|
|
|
2013-01-10 09:43:00 +08:00
|
|
|
/// \brief Given a framework directory, find the top-most framework directory.
|
|
|
|
///
|
|
|
|
/// \param FileMgr The file manager to use for directory lookups.
|
|
|
|
/// \param DirName The name of the framework directory.
|
|
|
|
/// \param SubmodulePath Will be populated with the submodule path from the
|
|
|
|
/// returned top-level module to the originally named framework.
|
|
|
|
static const DirectoryEntry *
|
|
|
|
getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
|
|
|
|
SmallVectorImpl<std::string> &SubmodulePath) {
|
|
|
|
assert(llvm::sys::path::extension(DirName) == ".framework" &&
|
|
|
|
"Not a framework directory");
|
|
|
|
|
|
|
|
// Note: as an egregious but useful hack we use the real path here, because
|
|
|
|
// frameworks moving between top-level frameworks to embedded frameworks tend
|
|
|
|
// to be symlinked, and we base the logical structure of modules on the
|
|
|
|
// physical layout. In particular, we need to deal with crazy includes like
|
|
|
|
//
|
|
|
|
// #include <Foo/Frameworks/Bar.framework/Headers/Wibble.h>
|
|
|
|
//
|
|
|
|
// where 'Bar' used to be embedded in 'Foo', is now a top-level framework
|
|
|
|
// which one should access with, e.g.,
|
|
|
|
//
|
|
|
|
// #include <Bar/Wibble.h>
|
|
|
|
//
|
|
|
|
// Similar issues occur when a top-level framework has moved into an
|
|
|
|
// embedded framework.
|
|
|
|
const DirectoryEntry *TopFrameworkDir = FileMgr.getDirectory(DirName);
|
2013-01-26 08:55:12 +08:00
|
|
|
DirName = FileMgr.getCanonicalName(TopFrameworkDir);
|
2013-01-10 09:43:00 +08:00
|
|
|
do {
|
|
|
|
// Get the parent directory name.
|
|
|
|
DirName = llvm::sys::path::parent_path(DirName);
|
|
|
|
if (DirName.empty())
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Determine whether this directory exists.
|
|
|
|
const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
|
|
|
|
if (!Dir)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// If this is a framework directory, then we're a subframework of this
|
|
|
|
// framework.
|
|
|
|
if (llvm::sys::path::extension(DirName) == ".framework") {
|
|
|
|
SubmodulePath.push_back(llvm::sys::path::stem(DirName));
|
|
|
|
TopFrameworkDir = Dir;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
return TopFrameworkDir;
|
|
|
|
}
|
2007-12-17 15:52:39 +08:00
|
|
|
|
2016-10-21 09:41:56 +08:00
|
|
|
static bool needModuleLookup(Module *RequestingModule,
|
|
|
|
bool HasSuggestedModule) {
|
|
|
|
return HasSuggestedModule ||
|
|
|
|
(RequestingModule && RequestingModule->NoUndeclaredIncludes);
|
|
|
|
}
|
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
/// DoFrameworkLookup - Do a lookup of the specified file in the current
|
|
|
|
/// DirectoryLookup, which is a framework directory.
|
2011-03-17 02:34:36 +08:00
|
|
|
const FileEntry *DirectoryLookup::DoFrameworkLookup(
|
2015-10-17 05:42:56 +08:00
|
|
|
StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
|
|
|
|
SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
|
2013-06-21 05:14:14 +08:00
|
|
|
ModuleMap::KnownHeader *SuggestedModule,
|
2015-10-17 05:42:56 +08:00
|
|
|
bool &InUserSpecifiedSystemFramework) const {
|
2007-12-17 16:13:48 +08:00
|
|
|
FileManager &FileMgr = HS.getFileMgr();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// Framework names must have a '/' in the filename.
|
2010-01-10 09:35:12 +08:00
|
|
|
size_t SlashPos = Filename.find('/');
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SlashPos == StringRef::npos) return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
// Find out if this is the home for the specified framework, by checking
|
2012-04-06 01:09:40 +08:00
|
|
|
// HeaderSearch. Possible answers are yes/no and unknown.
|
|
|
|
HeaderSearch::FrameworkCacheEntry &CacheEntry =
|
2010-01-10 09:35:12 +08:00
|
|
|
HS.LookupFrameworkCache(Filename.substr(0, SlashPos));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
// If it is known and in some other directory, fail.
|
2012-04-06 01:09:40 +08:00
|
|
|
if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir())
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
// Otherwise, construct the path to this framework dir.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// FrameworkName = "/System/Library/Frameworks/"
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<1024> FrameworkName;
|
2007-12-17 16:13:48 +08:00
|
|
|
FrameworkName += getFrameworkDir()->getName();
|
2006-10-30 13:09:49 +08:00
|
|
|
if (FrameworkName.empty() || FrameworkName.back() != '/')
|
|
|
|
FrameworkName.push_back('/');
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// FrameworkName = "/System/Library/Frameworks/Cocoa"
|
2011-11-17 09:41:17 +08:00
|
|
|
StringRef ModuleName(Filename.begin(), SlashPos);
|
|
|
|
FrameworkName += ModuleName;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
|
|
|
|
FrameworkName += ".framework/";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-04-06 01:09:40 +08:00
|
|
|
// If the cache entry was unresolved, populate it now.
|
2014-05-18 07:10:59 +08:00
|
|
|
if (!CacheEntry.Directory) {
|
2007-12-17 16:13:48 +08:00
|
|
|
HS.IncrementFrameworkLookupCount();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-22 15:24:13 +08:00
|
|
|
// If the framework dir doesn't exist, we fail.
|
2015-03-18 18:17:07 +08:00
|
|
|
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
|
2014-05-18 07:10:59 +08:00
|
|
|
if (!Dir) return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-22 15:24:13 +08:00
|
|
|
// Otherwise, if it does, remember that this is the right direntry for this
|
|
|
|
// framework.
|
2012-04-06 01:09:40 +08:00
|
|
|
CacheEntry.Directory = getFrameworkDir();
|
2012-04-06 01:10:06 +08:00
|
|
|
|
|
|
|
// If this is a user search directory, check if the framework has been
|
|
|
|
// user-specified as a system framework.
|
|
|
|
if (getDirCharacteristic() == SrcMgr::C_User) {
|
|
|
|
SmallString<1024> SystemFrameworkMarker(FrameworkName);
|
|
|
|
SystemFrameworkMarker += ".system_framework";
|
2015-03-18 18:17:07 +08:00
|
|
|
if (llvm::sys::fs::exists(SystemFrameworkMarker)) {
|
2012-04-06 01:10:06 +08:00
|
|
|
CacheEntry.IsUserSpecifiedSystemFramework = true;
|
|
|
|
}
|
|
|
|
}
|
2006-10-22 15:24:13 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-04-06 01:10:06 +08:00
|
|
|
// Set the 'user-specified system framework' flag.
|
|
|
|
InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework;
|
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
if (RelativePath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
RelativePath->clear();
|
|
|
|
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
|
|
|
|
}
|
2011-11-17 09:41:17 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
|
2006-10-30 13:09:49 +08:00
|
|
|
unsigned OrigSize = FrameworkName.size();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-30 13:09:49 +08:00
|
|
|
FrameworkName += "Headers/";
|
2011-04-27 05:50:03 +08:00
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
SearchPath->clear();
|
|
|
|
// Without trailing '/'.
|
|
|
|
SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
|
|
|
|
}
|
|
|
|
|
2010-01-10 09:35:12 +08:00
|
|
|
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
|
2015-03-18 18:17:07 +08:00
|
|
|
const FileEntry *FE = FileMgr.getFile(FrameworkName,
|
2013-01-10 09:43:00 +08:00
|
|
|
/*openFile=*/!SuggestedModule);
|
|
|
|
if (!FE) {
|
|
|
|
// Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
|
|
|
|
const char *Private = "Private";
|
|
|
|
FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
|
|
|
|
Private+strlen(Private));
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath)
|
2013-01-10 09:43:00 +08:00
|
|
|
SearchPath->insert(SearchPath->begin()+OrigSize, Private,
|
|
|
|
Private+strlen(Private));
|
|
|
|
|
2015-03-18 18:17:07 +08:00
|
|
|
FE = FileMgr.getFile(FrameworkName, /*openFile=*/!SuggestedModule);
|
2011-03-17 02:34:36 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-01-10 09:43:00 +08:00
|
|
|
// If we found the header and are allowed to suggest a module, do so now.
|
2016-10-21 09:41:56 +08:00
|
|
|
if (FE && needModuleLookup(RequestingModule, SuggestedModule)) {
|
2013-01-10 09:43:00 +08:00
|
|
|
// Find the framework in which this header occurs.
|
2014-05-16 00:20:33 +08:00
|
|
|
StringRef FrameworkPath = FE->getDir()->getName();
|
2013-01-10 09:43:00 +08:00
|
|
|
bool FoundFramework = false;
|
|
|
|
do {
|
|
|
|
// Determine whether this directory exists.
|
|
|
|
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath);
|
|
|
|
if (!Dir)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// If this is a framework directory, then we're a subframework of this
|
|
|
|
// framework.
|
|
|
|
if (llvm::sys::path::extension(FrameworkPath) == ".framework") {
|
|
|
|
FoundFramework = true;
|
|
|
|
break;
|
|
|
|
}
|
2014-05-16 00:20:33 +08:00
|
|
|
|
|
|
|
// Get the parent directory name.
|
|
|
|
FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
|
|
|
|
if (FrameworkPath.empty())
|
|
|
|
break;
|
2013-01-10 09:43:00 +08:00
|
|
|
} while (true);
|
|
|
|
|
2015-10-17 05:42:56 +08:00
|
|
|
bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
|
2013-01-10 09:43:00 +08:00
|
|
|
if (FoundFramework) {
|
2015-10-17 05:42:56 +08:00
|
|
|
if (!HS.findUsableModuleForFrameworkHeader(
|
|
|
|
FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem))
|
|
|
|
return nullptr;
|
2013-01-10 09:43:00 +08:00
|
|
|
} else {
|
2015-10-17 05:42:56 +08:00
|
|
|
if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule,
|
|
|
|
SuggestedModule, IsSystem))
|
|
|
|
return nullptr;
|
2013-01-10 09:43:00 +08:00
|
|
|
}
|
|
|
|
}
|
2011-09-16 06:00:41 +08:00
|
|
|
return FE;
|
2006-10-18 13:34:33 +08:00
|
|
|
}
|
|
|
|
|
2012-01-30 14:01:29 +08:00
|
|
|
void HeaderSearch::setTarget(const TargetInfo &Target) {
|
|
|
|
ModMap.setTarget(Target);
|
|
|
|
}
|
|
|
|
|
2007-12-17 15:52:39 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Header File Location.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2014-02-19 07:49:24 +08:00
|
|
|
/// \brief Return true with a diagnostic if the file that MSVC would have found
|
|
|
|
/// fails to match the one that Clang would have found with MSVC header search
|
|
|
|
/// disabled.
|
|
|
|
static bool checkMSVCHeaderSearch(DiagnosticsEngine &Diags,
|
|
|
|
const FileEntry *MSFE, const FileEntry *FE,
|
|
|
|
SourceLocation IncludeLoc) {
|
|
|
|
if (MSFE && FE != MSFE) {
|
|
|
|
Diags.Report(IncludeLoc, diag::ext_pp_include_search_ms) << MSFE->getName();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2007-12-17 16:13:48 +08:00
|
|
|
|
2014-03-11 14:21:28 +08:00
|
|
|
static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
|
|
|
|
assert(!Str.empty());
|
|
|
|
char *CopyStr = Alloc.Allocate<char>(Str.size()+1);
|
|
|
|
std::copy(Str.begin(), Str.end(), CopyStr);
|
|
|
|
CopyStr[Str.size()] = '\0';
|
|
|
|
return CopyStr;
|
|
|
|
}
|
|
|
|
|
2012-06-20 08:56:32 +08:00
|
|
|
/// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file,
|
2006-10-18 13:34:33 +08:00
|
|
|
/// return null on failure. isAngled indicates whether the file reference is
|
2013-12-28 03:46:16 +08:00
|
|
|
/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
|
|
|
|
/// non-empty, indicates where the \#including file(s) are, in case a relative
|
|
|
|
/// search is needed. Microsoft mode will pass all \#including files.
|
2011-03-17 02:34:36 +08:00
|
|
|
const FileEntry *HeaderSearch::LookupFile(
|
2013-12-28 03:46:16 +08:00
|
|
|
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
|
|
|
|
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
|
2014-08-12 16:25:57 +08:00
|
|
|
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
|
|
|
|
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
|
2015-10-17 05:42:56 +08:00
|
|
|
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
|
Preprocessor: Suppress -Wnonportable-include-path for header maps
If a file search involves a header map, suppress
-Wnonportable-include-path. It's firing lots of false positives for
framework authors internally, and it's not trivial to fix.
Consider a framework called "Foo" with a main (installed) framework header
"Foo/Foo.h". It's atypical for "Foo.h" to actually live inside a
directory called "Foo" in the source repository. Instead, the
build system generates a header map while building the framework.
If Foo.h lives at the top-level of the source repository (common), and
the git repo is called ssh://some.url/foo.git, then the header map will
have something like:
Foo/Foo.h -> /Users/myname/code/foo/Foo.h
where "/Users/myname/code/foo" is the clone of ssh://some.url/foo.git.
After #import <Foo/Foo.h>, the current implementation of
-Wnonportable-include-path will falsely assume that Foo.h was found in a
nonportable way, because of the name of the git clone (.../foo/Foo.h).
However, that directory name was not involved in the header search at
all.
This commit adds an extra parameter to Preprocessor::LookupFile and
HeaderSearch::LookupFile to track if the search used a header map,
making it easy to suppress the warning. Longer term, once we find a way
to avoid the false positive, we should turn the warning back on.
rdar://problem/28863903
llvm-svn: 301592
2017-04-28 05:41:51 +08:00
|
|
|
bool *IsMapped, bool SkipCache, bool BuildSystemModule) {
|
|
|
|
if (IsMapped)
|
|
|
|
*IsMapped = false;
|
|
|
|
|
2011-09-16 06:00:41 +08:00
|
|
|
if (SuggestedModule)
|
2013-06-21 05:14:14 +08:00
|
|
|
*SuggestedModule = ModuleMap::KnownHeader();
|
2011-09-16 06:00:41 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// If 'Filename' is absolute, check to see if it exists and no searching.
|
2010-12-18 05:22:22 +08:00
|
|
|
if (llvm::sys::path::is_absolute(Filename)) {
|
2014-05-18 07:10:59 +08:00
|
|
|
CurDir = nullptr;
|
2006-10-18 13:34:33 +08:00
|
|
|
|
|
|
|
// If this was an #include_next "/absolute/file", fail.
|
2014-05-18 07:10:59 +08:00
|
|
|
if (FromDir) return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath)
|
2011-04-27 05:50:03 +08:00
|
|
|
SearchPath->clear();
|
2014-05-18 07:10:59 +08:00
|
|
|
if (RelativePath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
RelativePath->clear();
|
|
|
|
RelativePath->append(Filename.begin(), Filename.end());
|
|
|
|
}
|
2006-10-18 13:34:33 +08:00
|
|
|
// Otherwise, just return the file.
|
2016-06-14 04:40:21 +08:00
|
|
|
return getFileAndSuggestModule(Filename, IncludeLoc, nullptr,
|
2015-10-17 05:42:56 +08:00
|
|
|
/*IsSystemHeaderDir*/false,
|
|
|
|
RequestingModule, SuggestedModule);
|
2006-10-18 13:34:33 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-02-19 07:49:24 +08:00
|
|
|
// This is the header that MSVC's header search would have found.
|
2014-05-18 07:10:59 +08:00
|
|
|
const FileEntry *MSFE = nullptr;
|
2014-03-06 04:51:45 +08:00
|
|
|
ModuleMap::KnownHeader MSSuggestedModule;
|
2014-02-19 07:49:24 +08:00
|
|
|
|
2011-07-28 12:45:53 +08:00
|
|
|
// Unless disabled, check to see if the file is in the #includer's
|
2013-12-28 03:46:16 +08:00
|
|
|
// directory. This cannot be based on CurDir, because each includer could be
|
|
|
|
// a #include of a subdirectory (#include "foo/bar.h") and a subsequent
|
|
|
|
// include of "baz.h" should resolve to "whatever/foo/baz.h".
|
2007-12-17 15:52:39 +08:00
|
|
|
// This search is not done for <> headers.
|
2013-12-28 03:46:16 +08:00
|
|
|
if (!Includers.empty() && !isAngled && !NoCurDirSearch) {
|
2013-12-10 10:36:28 +08:00
|
|
|
SmallString<1024> TmpDir;
|
2014-08-12 16:25:57 +08:00
|
|
|
bool First = true;
|
|
|
|
for (const auto &IncluderAndDir : Includers) {
|
|
|
|
const FileEntry *Includer = IncluderAndDir.first;
|
|
|
|
|
2013-12-28 03:46:16 +08:00
|
|
|
// Concatenate the requested file onto the directory.
|
2015-05-08 14:02:37 +08:00
|
|
|
// FIXME: Portability. Filename concatenation should be in sys::Path.
|
2014-08-12 16:25:57 +08:00
|
|
|
TmpDir = IncluderAndDir.second->getName();
|
2015-05-08 14:02:37 +08:00
|
|
|
TmpDir.push_back('/');
|
|
|
|
TmpDir.append(Filename.begin(), Filename.end());
|
2014-03-06 04:51:45 +08:00
|
|
|
|
2014-03-07 02:08:08 +08:00
|
|
|
// FIXME: We don't cache the result of getFileInfo across the call to
|
|
|
|
// getFileAndSuggestModule, because it's a reference to an element of
|
|
|
|
// a container that could be reallocated across this call.
|
2014-12-02 08:08:08 +08:00
|
|
|
//
|
2016-05-17 10:15:12 +08:00
|
|
|
// If we have no includer, that means we're processing a #include
|
2014-12-02 08:08:08 +08:00
|
|
|
// from a module build. We should treat this as a system header if we're
|
|
|
|
// building a [system] module.
|
2014-03-07 02:08:08 +08:00
|
|
|
bool IncluderIsSystemHeader =
|
2016-05-18 02:04:38 +08:00
|
|
|
Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
|
|
|
|
BuildSystemModule;
|
2014-08-12 16:25:57 +08:00
|
|
|
if (const FileEntry *FE = getFileAndSuggestModule(
|
2016-06-14 04:40:21 +08:00
|
|
|
TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
|
2015-10-17 05:42:56 +08:00
|
|
|
RequestingModule, SuggestedModule)) {
|
2014-12-02 08:08:08 +08:00
|
|
|
if (!Includer) {
|
|
|
|
assert(First && "only first includer can have no file");
|
|
|
|
return FE;
|
|
|
|
}
|
|
|
|
|
2013-12-28 03:46:16 +08:00
|
|
|
// Leave CurDir unset.
|
|
|
|
// This file is a system header or C++ unfriendly if the old file is.
|
|
|
|
//
|
|
|
|
// Note that we only use one of FromHFI/ToHFI at once, due to potential
|
|
|
|
// reallocation of the underlying vector potentially making the first
|
|
|
|
// reference binding dangling.
|
2014-03-07 02:08:08 +08:00
|
|
|
HeaderFileInfo &FromHFI = getFileInfo(Includer);
|
2013-12-28 03:46:16 +08:00
|
|
|
unsigned DirInfo = FromHFI.DirInfo;
|
|
|
|
bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
|
|
|
|
StringRef Framework = FromHFI.Framework;
|
|
|
|
|
|
|
|
HeaderFileInfo &ToHFI = getFileInfo(FE);
|
|
|
|
ToHFI.DirInfo = DirInfo;
|
|
|
|
ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
|
|
|
|
ToHFI.Framework = Framework;
|
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath) {
|
2014-08-12 16:25:57 +08:00
|
|
|
StringRef SearchPathRef(IncluderAndDir.second->getName());
|
2013-12-28 03:46:16 +08:00
|
|
|
SearchPath->clear();
|
|
|
|
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
|
|
|
|
}
|
2014-05-18 07:10:59 +08:00
|
|
|
if (RelativePath) {
|
2013-12-28 03:46:16 +08:00
|
|
|
RelativePath->clear();
|
|
|
|
RelativePath->append(Filename.begin(), Filename.end());
|
|
|
|
}
|
2014-08-12 16:25:57 +08:00
|
|
|
if (First)
|
2014-02-19 07:49:24 +08:00
|
|
|
return FE;
|
|
|
|
|
|
|
|
// Otherwise, we found the path via MSVC header search rules. If
|
|
|
|
// -Wmsvc-include is enabled, we have to keep searching to see if we
|
|
|
|
// would've found this header in -I or -isystem directories.
|
2014-06-16 07:30:39 +08:00
|
|
|
if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
|
2014-02-19 07:49:24 +08:00
|
|
|
return FE;
|
|
|
|
} else {
|
|
|
|
MSFE = FE;
|
2014-03-06 04:51:45 +08:00
|
|
|
if (SuggestedModule) {
|
|
|
|
MSSuggestedModule = *SuggestedModule;
|
|
|
|
*SuggestedModule = ModuleMap::KnownHeader();
|
|
|
|
}
|
2014-02-19 07:49:24 +08:00
|
|
|
break;
|
|
|
|
}
|
2011-04-27 05:50:03 +08:00
|
|
|
}
|
2014-08-12 16:25:57 +08:00
|
|
|
First = false;
|
2006-10-18 13:34:33 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
CurDir = nullptr;
|
2006-10-18 13:34:33 +08:00
|
|
|
|
|
|
|
// If this is a system #include, ignore the user #include locs.
|
2011-05-24 12:31:14 +08:00
|
|
|
unsigned i = isAngled ? AngledDirIdx : 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// If this is a #include_next request, start searching after the directory the
|
|
|
|
// file was found in.
|
|
|
|
if (FromDir)
|
|
|
|
i = FromDir-&SearchDirs[0];
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-22 15:28:00 +08:00
|
|
|
// Cache all of the lookups performed by this method. Many headers are
|
|
|
|
// multiply included, and the "pragma once" optimization prevents them from
|
|
|
|
// being relex/pp'd, but they would still have to search through a
|
|
|
|
// (potentially huge) series of SearchDirs to find it.
|
2014-11-19 11:06:06 +08:00
|
|
|
LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
|
2007-07-22 15:28:00 +08:00
|
|
|
|
|
|
|
// If the entry has been previously looked up, the first value will be
|
|
|
|
// non-zero. If the value is equal to i (the start point of our search), then
|
|
|
|
// this is a matching hit.
|
2014-03-11 14:21:28 +08:00
|
|
|
if (!SkipCache && CacheLookup.StartIdx == i+1) {
|
2007-07-22 15:28:00 +08:00
|
|
|
// Skip querying potentially lots of directories for this lookup.
|
2014-03-11 14:21:28 +08:00
|
|
|
i = CacheLookup.HitIdx;
|
Preprocessor: Suppress -Wnonportable-include-path for header maps
If a file search involves a header map, suppress
-Wnonportable-include-path. It's firing lots of false positives for
framework authors internally, and it's not trivial to fix.
Consider a framework called "Foo" with a main (installed) framework header
"Foo/Foo.h". It's atypical for "Foo.h" to actually live inside a
directory called "Foo" in the source repository. Instead, the
build system generates a header map while building the framework.
If Foo.h lives at the top-level of the source repository (common), and
the git repo is called ssh://some.url/foo.git, then the header map will
have something like:
Foo/Foo.h -> /Users/myname/code/foo/Foo.h
where "/Users/myname/code/foo" is the clone of ssh://some.url/foo.git.
After #import <Foo/Foo.h>, the current implementation of
-Wnonportable-include-path will falsely assume that Foo.h was found in a
nonportable way, because of the name of the git clone (.../foo/Foo.h).
However, that directory name was not involved in the header search at
all.
This commit adds an extra parameter to Preprocessor::LookupFile and
HeaderSearch::LookupFile to track if the search used a header map,
making it easy to suppress the warning. Longer term, once we find a way
to avoid the false positive, we should turn the warning back on.
rdar://problem/28863903
llvm-svn: 301592
2017-04-28 05:41:51 +08:00
|
|
|
if (CacheLookup.MappedName) {
|
2014-03-11 14:21:28 +08:00
|
|
|
Filename = CacheLookup.MappedName;
|
Preprocessor: Suppress -Wnonportable-include-path for header maps
If a file search involves a header map, suppress
-Wnonportable-include-path. It's firing lots of false positives for
framework authors internally, and it's not trivial to fix.
Consider a framework called "Foo" with a main (installed) framework header
"Foo/Foo.h". It's atypical for "Foo.h" to actually live inside a
directory called "Foo" in the source repository. Instead, the
build system generates a header map while building the framework.
If Foo.h lives at the top-level of the source repository (common), and
the git repo is called ssh://some.url/foo.git, then the header map will
have something like:
Foo/Foo.h -> /Users/myname/code/foo/Foo.h
where "/Users/myname/code/foo" is the clone of ssh://some.url/foo.git.
After #import <Foo/Foo.h>, the current implementation of
-Wnonportable-include-path will falsely assume that Foo.h was found in a
nonportable way, because of the name of the git clone (.../foo/Foo.h).
However, that directory name was not involved in the header search at
all.
This commit adds an extra parameter to Preprocessor::LookupFile and
HeaderSearch::LookupFile to track if the search used a header map,
making it easy to suppress the warning. Longer term, once we find a way
to avoid the false positive, we should turn the warning back on.
rdar://problem/28863903
llvm-svn: 301592
2017-04-28 05:41:51 +08:00
|
|
|
if (IsMapped)
|
|
|
|
*IsMapped = true;
|
|
|
|
}
|
2007-07-22 15:28:00 +08:00
|
|
|
} else {
|
|
|
|
// Otherwise, this is the first query, or the previous query didn't match
|
|
|
|
// our search start. We will fill in our found location below, so prime the
|
|
|
|
// start point value.
|
2014-03-29 11:22:54 +08:00
|
|
|
CacheLookup.reset(/*StartIdx=*/i+1);
|
2007-07-22 15:28:00 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-02-14 22:58:28 +08:00
|
|
|
SmallString<64> MappedName;
|
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// Check each directory in sequence to see if it contains this file.
|
|
|
|
for (; i != SearchDirs.size(); ++i) {
|
2012-04-06 01:10:06 +08:00
|
|
|
bool InUserSpecifiedSystemFramework = false;
|
2014-03-11 14:21:28 +08:00
|
|
|
bool HasBeenMapped = false;
|
2015-10-17 05:42:56 +08:00
|
|
|
const FileEntry *FE = SearchDirs[i].LookupFile(
|
2016-06-14 04:40:21 +08:00
|
|
|
Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
|
2015-10-17 05:42:56 +08:00
|
|
|
SuggestedModule, InUserSpecifiedSystemFramework, HasBeenMapped,
|
|
|
|
MappedName);
|
2014-03-11 14:21:28 +08:00
|
|
|
if (HasBeenMapped) {
|
|
|
|
CacheLookup.MappedName =
|
|
|
|
copyString(Filename, LookupFileCache.getAllocator());
|
Preprocessor: Suppress -Wnonportable-include-path for header maps
If a file search involves a header map, suppress
-Wnonportable-include-path. It's firing lots of false positives for
framework authors internally, and it's not trivial to fix.
Consider a framework called "Foo" with a main (installed) framework header
"Foo/Foo.h". It's atypical for "Foo.h" to actually live inside a
directory called "Foo" in the source repository. Instead, the
build system generates a header map while building the framework.
If Foo.h lives at the top-level of the source repository (common), and
the git repo is called ssh://some.url/foo.git, then the header map will
have something like:
Foo/Foo.h -> /Users/myname/code/foo/Foo.h
where "/Users/myname/code/foo" is the clone of ssh://some.url/foo.git.
After #import <Foo/Foo.h>, the current implementation of
-Wnonportable-include-path will falsely assume that Foo.h was found in a
nonportable way, because of the name of the git clone (.../foo/Foo.h).
However, that directory name was not involved in the header search at
all.
This commit adds an extra parameter to Preprocessor::LookupFile and
HeaderSearch::LookupFile to track if the search used a header map,
making it easy to suppress the warning. Longer term, once we find a way
to avoid the false positive, we should turn the warning back on.
rdar://problem/28863903
llvm-svn: 301592
2017-04-28 05:41:51 +08:00
|
|
|
if (IsMapped)
|
|
|
|
*IsMapped = true;
|
2014-03-11 14:21:28 +08:00
|
|
|
}
|
2007-12-17 16:13:48 +08:00
|
|
|
if (!FE) continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
CurDir = &SearchDirs[i];
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
// This file is a system header or C++ unfriendly if the dir is.
|
2011-07-28 12:45:53 +08:00
|
|
|
HeaderFileInfo &HFI = getFileInfo(FE);
|
|
|
|
HFI.DirInfo = CurDir->getDirCharacteristic();
|
|
|
|
|
2012-04-06 01:10:06 +08:00
|
|
|
// If the directory characteristic is User but this framework was
|
|
|
|
// user-specified to be treated as a system framework, promote the
|
|
|
|
// characteristic.
|
|
|
|
if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework)
|
|
|
|
HFI.DirInfo = SrcMgr::C_System;
|
|
|
|
|
2012-06-14 04:27:03 +08:00
|
|
|
// If the filename matches a known system header prefix, override
|
|
|
|
// whether the file is a system header.
|
2012-06-14 04:52:36 +08:00
|
|
|
for (unsigned j = SystemHeaderPrefixes.size(); j; --j) {
|
|
|
|
if (Filename.startswith(SystemHeaderPrefixes[j-1].first)) {
|
|
|
|
HFI.DirInfo = SystemHeaderPrefixes[j-1].second ? SrcMgr::C_System
|
2012-06-14 04:27:03 +08:00
|
|
|
: SrcMgr::C_User;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-28 12:45:53 +08:00
|
|
|
// If this file is found in a header map and uses the framework style of
|
|
|
|
// includes, then this header is part of a framework we're building.
|
|
|
|
if (CurDir->isIndexHeaderMap()) {
|
|
|
|
size_t SlashPos = Filename.find('/');
|
|
|
|
if (SlashPos != StringRef::npos) {
|
|
|
|
HFI.IndexHeaderMapHeader = 1;
|
|
|
|
HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(),
|
|
|
|
SlashPos));
|
|
|
|
}
|
|
|
|
}
|
2014-02-19 07:49:24 +08:00
|
|
|
|
2014-03-06 04:51:45 +08:00
|
|
|
if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
|
|
|
|
if (SuggestedModule)
|
|
|
|
*SuggestedModule = MSSuggestedModule;
|
2014-02-19 07:49:24 +08:00
|
|
|
return MSFE;
|
2014-03-06 04:51:45 +08:00
|
|
|
}
|
2014-02-19 07:49:24 +08:00
|
|
|
|
2007-12-17 16:13:48 +08:00
|
|
|
// Remember this location for the next lookup we do.
|
2014-03-11 14:21:28 +08:00
|
|
|
CacheLookup.HitIdx = i;
|
2007-12-17 16:13:48 +08:00
|
|
|
return FE;
|
2006-10-18 13:34:33 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-30 14:28:34 +08:00
|
|
|
// If we are including a file with a quoted include "foo.h" from inside
|
|
|
|
// a header in a framework that is currently being built, and we couldn't
|
|
|
|
// resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
|
|
|
|
// "Foo" is the name of the framework in which the including header was found.
|
2014-12-02 08:08:08 +08:00
|
|
|
if (!Includers.empty() && Includers.front().first && !isAngled &&
|
2013-12-28 03:46:16 +08:00
|
|
|
Filename.find('/') == StringRef::npos) {
|
2014-08-12 16:25:57 +08:00
|
|
|
HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front().first);
|
2011-07-30 14:28:34 +08:00
|
|
|
if (IncludingHFI.IndexHeaderMapHeader) {
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> ScratchFilename;
|
2011-07-30 14:28:34 +08:00
|
|
|
ScratchFilename += IncludingHFI.Framework;
|
|
|
|
ScratchFilename += '/';
|
|
|
|
ScratchFilename += Filename;
|
2013-12-28 03:46:16 +08:00
|
|
|
|
2015-10-17 05:42:56 +08:00
|
|
|
const FileEntry *FE =
|
|
|
|
LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir,
|
|
|
|
CurDir, Includers.front(), SearchPath, RelativePath,
|
Preprocessor: Suppress -Wnonportable-include-path for header maps
If a file search involves a header map, suppress
-Wnonportable-include-path. It's firing lots of false positives for
framework authors internally, and it's not trivial to fix.
Consider a framework called "Foo" with a main (installed) framework header
"Foo/Foo.h". It's atypical for "Foo.h" to actually live inside a
directory called "Foo" in the source repository. Instead, the
build system generates a header map while building the framework.
If Foo.h lives at the top-level of the source repository (common), and
the git repo is called ssh://some.url/foo.git, then the header map will
have something like:
Foo/Foo.h -> /Users/myname/code/foo/Foo.h
where "/Users/myname/code/foo" is the clone of ssh://some.url/foo.git.
After #import <Foo/Foo.h>, the current implementation of
-Wnonportable-include-path will falsely assume that Foo.h was found in a
nonportable way, because of the name of the git clone (.../foo/Foo.h).
However, that directory name was not involved in the header search at
all.
This commit adds an extra parameter to Preprocessor::LookupFile and
HeaderSearch::LookupFile to track if the search used a header map,
making it easy to suppress the warning. Longer term, once we find a way
to avoid the false positive, we should turn the warning back on.
rdar://problem/28863903
llvm-svn: 301592
2017-04-28 05:41:51 +08:00
|
|
|
RequestingModule, SuggestedModule, IsMapped);
|
2014-02-19 07:49:24 +08:00
|
|
|
|
2014-03-06 04:51:45 +08:00
|
|
|
if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
|
|
|
|
if (SuggestedModule)
|
|
|
|
*SuggestedModule = MSSuggestedModule;
|
2014-02-19 07:49:24 +08:00
|
|
|
return MSFE;
|
2014-03-06 04:51:45 +08:00
|
|
|
}
|
2014-02-19 07:49:24 +08:00
|
|
|
|
2014-11-19 13:48:40 +08:00
|
|
|
LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
|
2014-11-19 11:06:06 +08:00
|
|
|
CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx;
|
2014-03-06 04:51:45 +08:00
|
|
|
// FIXME: SuggestedModule.
|
2014-02-19 07:49:24 +08:00
|
|
|
return FE;
|
2011-07-30 14:28:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) {
|
2014-03-06 04:51:45 +08:00
|
|
|
if (SuggestedModule)
|
|
|
|
*SuggestedModule = MSSuggestedModule;
|
2014-02-19 07:49:24 +08:00
|
|
|
return MSFE;
|
2014-03-06 04:51:45 +08:00
|
|
|
}
|
2014-02-19 07:49:24 +08:00
|
|
|
|
2007-07-22 15:28:00 +08:00
|
|
|
// Otherwise, didn't find it. Remember we didn't find this.
|
2014-03-11 14:21:28 +08:00
|
|
|
CacheLookup.HitIdx = SearchDirs.size();
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2006-10-18 13:34:33 +08:00
|
|
|
}
|
|
|
|
|
2006-10-20 12:42:40 +08:00
|
|
|
/// LookupSubframeworkHeader - Look up a subframework for the specified
|
2012-06-20 08:56:32 +08:00
|
|
|
/// \#include file. For example, if \#include'ing <HIToolbox/HIToolbox.h> from
|
2006-10-20 12:42:40 +08:00
|
|
|
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
|
|
|
|
/// is a subframework within Carbon.framework. If so, return the FileEntry
|
|
|
|
/// for the designated file, otherwise return null.
|
|
|
|
const FileEntry *HeaderSearch::
|
2011-07-23 18:55:15 +08:00
|
|
|
LookupSubframeworkHeader(StringRef Filename,
|
2011-03-17 02:34:36 +08:00
|
|
|
const FileEntry *ContextFileEnt,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<char> *SearchPath,
|
2013-02-08 08:10:48 +08:00
|
|
|
SmallVectorImpl<char> *RelativePath,
|
2015-10-17 05:42:56 +08:00
|
|
|
Module *RequestingModule,
|
2013-06-21 05:14:14 +08:00
|
|
|
ModuleMap::KnownHeader *SuggestedModule) {
|
2008-02-01 13:34:02 +08:00
|
|
|
assert(ContextFileEnt && "No context file?");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-20 12:42:40 +08:00
|
|
|
// Framework names must have a '/' in the filename. Find it.
|
2011-12-10 00:48:01 +08:00
|
|
|
// FIXME: Should we permit '\' on Windows?
|
2010-01-10 09:35:12 +08:00
|
|
|
size_t SlashPos = Filename.find('/');
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SlashPos == StringRef::npos) return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-20 12:42:40 +08:00
|
|
|
// Look up the base framework name of the ContextFileEnt.
|
2016-10-11 06:52:47 +08:00
|
|
|
StringRef ContextName = ContextFileEnt->getName();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-20 12:42:40 +08:00
|
|
|
// If the context info wasn't a framework, couldn't be a subframework.
|
2011-12-10 00:48:01 +08:00
|
|
|
const unsigned DotFrameworkLen = 10;
|
2016-10-11 06:52:47 +08:00
|
|
|
auto FrameworkPos = ContextName.find(".framework");
|
|
|
|
if (FrameworkPos == StringRef::npos ||
|
|
|
|
(ContextName[FrameworkPos + DotFrameworkLen] != '/' &&
|
|
|
|
ContextName[FrameworkPos + DotFrameworkLen] != '\\'))
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2016-10-11 06:52:47 +08:00
|
|
|
SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() +
|
|
|
|
FrameworkPos +
|
|
|
|
DotFrameworkLen + 1);
|
2006-10-22 15:24:13 +08:00
|
|
|
|
2006-10-20 12:42:40 +08:00
|
|
|
// Append Frameworks/HIToolbox.framework/
|
|
|
|
FrameworkName += "Frameworks/";
|
2010-01-10 09:35:12 +08:00
|
|
|
FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
|
2006-10-20 12:42:40 +08:00
|
|
|
FrameworkName += ".framework/";
|
2006-10-20 12:55:45 +08:00
|
|
|
|
2014-11-19 11:06:06 +08:00
|
|
|
auto &CacheLookup =
|
|
|
|
*FrameworkMap.insert(std::make_pair(Filename.substr(0, SlashPos),
|
|
|
|
FrameworkCacheEntry())).first;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-22 15:24:13 +08:00
|
|
|
// Some other location?
|
2014-11-19 11:06:06 +08:00
|
|
|
if (CacheLookup.second.Directory &&
|
|
|
|
CacheLookup.first().size() == FrameworkName.size() &&
|
|
|
|
memcmp(CacheLookup.first().data(), &FrameworkName[0],
|
|
|
|
CacheLookup.first().size()) != 0)
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-22 15:24:13 +08:00
|
|
|
// Cache subframework.
|
2014-11-19 11:06:06 +08:00
|
|
|
if (!CacheLookup.second.Directory) {
|
2006-10-22 15:24:13 +08:00
|
|
|
++NumSubFrameworkLookups;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-22 15:24:13 +08:00
|
|
|
// If the framework dir doesn't exist, we fail.
|
2015-03-18 18:17:07 +08:00
|
|
|
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
|
2014-05-18 07:10:59 +08:00
|
|
|
if (!Dir) return nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-22 15:24:13 +08:00
|
|
|
// Otherwise, if it does, remember that this is the right direntry for this
|
|
|
|
// framework.
|
2014-11-19 11:06:06 +08:00
|
|
|
CacheLookup.second.Directory = Dir;
|
2006-10-22 15:24:13 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
const FileEntry *FE = nullptr;
|
2006-10-20 12:55:45 +08:00
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
if (RelativePath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
RelativePath->clear();
|
|
|
|
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
|
|
|
|
}
|
|
|
|
|
2006-10-20 12:42:40 +08:00
|
|
|
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<1024> HeadersFilename(FrameworkName);
|
2006-10-30 11:40:58 +08:00
|
|
|
HeadersFilename += "Headers/";
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
SearchPath->clear();
|
|
|
|
// Without trailing '/'.
|
|
|
|
SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
|
|
|
|
}
|
|
|
|
|
2010-01-10 09:35:12 +08:00
|
|
|
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
|
2015-03-18 18:17:07 +08:00
|
|
|
if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true))) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-20 12:42:40 +08:00
|
|
|
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
|
2006-10-30 11:40:58 +08:00
|
|
|
HeadersFilename = FrameworkName;
|
|
|
|
HeadersFilename += "PrivateHeaders/";
|
2014-05-18 07:10:59 +08:00
|
|
|
if (SearchPath) {
|
2011-04-27 05:50:03 +08:00
|
|
|
SearchPath->clear();
|
|
|
|
// Without trailing '/'.
|
|
|
|
SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
|
|
|
|
}
|
|
|
|
|
2010-01-10 09:35:12 +08:00
|
|
|
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
|
2015-03-18 18:17:07 +08:00
|
|
|
if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true)))
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2006-10-20 12:42:40 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-20 12:55:45 +08:00
|
|
|
// This file is a system header or C++ unfriendly if the old file is.
|
2008-02-24 11:55:14 +08:00
|
|
|
//
|
2008-02-26 05:38:21 +08:00
|
|
|
// Note that the temporary 'DirInfo' is required here, as either call to
|
|
|
|
// getFileInfo could resize the vector and we don't want to rely on order
|
|
|
|
// of evaluation.
|
|
|
|
unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
|
|
|
|
getFileInfo(FE).DirInfo = DirInfo;
|
2013-02-08 08:10:48 +08:00
|
|
|
|
2015-10-17 05:42:56 +08:00
|
|
|
FrameworkName.pop_back(); // remove the trailing '/'
|
|
|
|
if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule,
|
|
|
|
SuggestedModule, /*IsSystem*/ false))
|
|
|
|
return nullptr;
|
2013-02-08 08:10:48 +08:00
|
|
|
|
2006-10-20 12:55:45 +08:00
|
|
|
return FE;
|
2006-10-20 12:42:40 +08:00
|
|
|
}
|
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// File Info Management.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-09-17 13:35:18 +08:00
|
|
|
/// \brief Merge the header file info provided by \p OtherHFI into the current
|
|
|
|
/// header file info (\p HFI)
|
|
|
|
static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
|
|
|
|
const HeaderFileInfo &OtherHFI) {
|
2015-08-25 05:59:32 +08:00
|
|
|
assert(OtherHFI.External && "expected to merge external HFI");
|
|
|
|
|
2011-09-17 13:35:18 +08:00
|
|
|
HFI.isImport |= OtherHFI.isImport;
|
|
|
|
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
|
2013-03-14 05:13:51 +08:00
|
|
|
HFI.isModuleHeader |= OtherHFI.isModuleHeader;
|
2011-09-17 13:35:18 +08:00
|
|
|
HFI.NumIncludes += OtherHFI.NumIncludes;
|
2015-08-25 05:59:32 +08:00
|
|
|
|
2011-09-17 13:35:18 +08:00
|
|
|
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
|
|
|
|
HFI.ControllingMacro = OtherHFI.ControllingMacro;
|
|
|
|
HFI.ControllingMacroID = OtherHFI.ControllingMacroID;
|
|
|
|
}
|
2015-08-25 05:59:32 +08:00
|
|
|
|
|
|
|
HFI.DirInfo = OtherHFI.DirInfo;
|
|
|
|
HFI.External = (!HFI.IsValid || HFI.External);
|
|
|
|
HFI.IsValid = true;
|
|
|
|
HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;
|
2006-10-18 13:34:33 +08:00
|
|
|
|
2011-09-17 13:35:18 +08:00
|
|
|
if (HFI.Framework.empty())
|
|
|
|
HFI.Framework = OtherHFI.Framework;
|
|
|
|
}
|
|
|
|
|
2009-04-25 04:03:17 +08:00
|
|
|
/// getFileInfo - Return the HeaderFileInfo structure for the specified
|
2006-10-18 13:34:33 +08:00
|
|
|
/// FileEntry.
|
2009-04-25 04:03:17 +08:00
|
|
|
HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
|
2006-10-18 13:34:33 +08:00
|
|
|
if (FE->getUID() >= FileInfo.size())
|
2015-08-19 07:42:23 +08:00
|
|
|
FileInfo.resize(FE->getUID() + 1);
|
|
|
|
|
2015-08-25 05:59:32 +08:00
|
|
|
HeaderFileInfo *HFI = &FileInfo[FE->getUID()];
|
2015-08-19 07:42:23 +08:00
|
|
|
// FIXME: Use a generation count to check whether this is really up to date.
|
2015-08-25 05:59:32 +08:00
|
|
|
if (ExternalSource && !HFI->Resolved) {
|
|
|
|
HFI->Resolved = true;
|
|
|
|
auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
|
|
|
|
|
|
|
|
HFI = &FileInfo[FE->getUID()];
|
|
|
|
if (ExternalHFI.External)
|
|
|
|
mergeHeaderFileInfo(*HFI, ExternalHFI);
|
2015-08-19 07:42:23 +08:00
|
|
|
}
|
|
|
|
|
2015-08-25 05:59:32 +08:00
|
|
|
HFI->IsValid = true;
|
2015-08-19 07:42:23 +08:00
|
|
|
// We have local information about this header file, so it's no longer
|
|
|
|
// strictly external.
|
2015-08-25 05:59:32 +08:00
|
|
|
HFI->External = false;
|
|
|
|
return *HFI;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2006-10-18 13:34:33 +08:00
|
|
|
|
2015-08-19 07:42:23 +08:00
|
|
|
const HeaderFileInfo *
|
2015-08-25 05:59:32 +08:00
|
|
|
HeaderSearch::getExistingFileInfo(const FileEntry *FE,
|
|
|
|
bool WantExternal) const {
|
2015-08-19 07:42:23 +08:00
|
|
|
// If we have an external source, ensure we have the latest information.
|
|
|
|
// FIXME: Use a generation count to check whether this is really up to date.
|
2015-08-25 05:59:32 +08:00
|
|
|
HeaderFileInfo *HFI;
|
|
|
|
if (ExternalSource) {
|
|
|
|
if (FE->getUID() >= FileInfo.size()) {
|
|
|
|
if (!WantExternal)
|
|
|
|
return nullptr;
|
|
|
|
FileInfo.resize(FE->getUID() + 1);
|
2015-08-19 07:42:23 +08:00
|
|
|
}
|
|
|
|
|
2015-08-25 05:59:32 +08:00
|
|
|
HFI = &FileInfo[FE->getUID()];
|
|
|
|
if (!WantExternal && (!HFI->IsValid || HFI->External))
|
|
|
|
return nullptr;
|
|
|
|
if (!HFI->Resolved) {
|
|
|
|
HFI->Resolved = true;
|
|
|
|
auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
|
|
|
|
|
|
|
|
HFI = &FileInfo[FE->getUID()];
|
|
|
|
if (ExternalHFI.External)
|
|
|
|
mergeHeaderFileInfo(*HFI, ExternalHFI);
|
|
|
|
}
|
|
|
|
} else if (FE->getUID() >= FileInfo.size()) {
|
2015-08-19 07:42:23 +08:00
|
|
|
return nullptr;
|
2015-08-25 05:59:32 +08:00
|
|
|
} else {
|
|
|
|
HFI = &FileInfo[FE->getUID()];
|
|
|
|
}
|
2015-08-19 07:42:23 +08:00
|
|
|
|
2015-08-25 05:59:32 +08:00
|
|
|
if (!HFI->IsValid || (HFI->External && !WantExternal))
|
2015-08-19 07:42:23 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2015-08-25 05:59:32 +08:00
|
|
|
return HFI;
|
2014-03-14 00:46:36 +08:00
|
|
|
}
|
|
|
|
|
2011-05-04 08:14:37 +08:00
|
|
|
bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
|
|
|
|
// Check if we've ever seen this file as a header.
|
2015-08-19 07:42:23 +08:00
|
|
|
if (auto *HFI = getExistingFileInfo(File))
|
|
|
|
return HFI->isPragmaOnce || HFI->isImport || HFI->ControllingMacro ||
|
|
|
|
HFI->ControllingMacroID;
|
|
|
|
return false;
|
2011-05-04 08:14:37 +08:00
|
|
|
}
|
|
|
|
|
2013-05-09 07:46:46 +08:00
|
|
|
void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
|
2013-06-21 05:14:14 +08:00
|
|
|
ModuleMap::ModuleHeaderRole Role,
|
2013-05-09 07:46:46 +08:00
|
|
|
bool isCompilingModuleHeader) {
|
2015-08-25 05:59:32 +08:00
|
|
|
bool isModularHeader = !(Role & ModuleMap::TextualHeader);
|
|
|
|
|
|
|
|
// Don't mark the file info as non-external if there's nothing to change.
|
|
|
|
if (!isCompilingModuleHeader) {
|
|
|
|
if (!isModularHeader)
|
|
|
|
return;
|
|
|
|
auto *HFI = getExistingFileInfo(FE);
|
|
|
|
if (HFI && HFI->isModuleHeader)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-19 07:42:23 +08:00
|
|
|
auto &HFI = getFileInfo(FE);
|
2015-08-25 05:59:32 +08:00
|
|
|
HFI.isModuleHeader |= isModularHeader;
|
2015-07-11 06:27:17 +08:00
|
|
|
HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
|
2013-03-14 05:13:51 +08:00
|
|
|
}
|
|
|
|
|
2015-04-30 07:20:19 +08:00
|
|
|
bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
|
2017-01-11 10:14:51 +08:00
|
|
|
const FileEntry *File, bool isImport,
|
|
|
|
bool ModulesEnabled, Module *M) {
|
2006-10-18 13:34:33 +08:00
|
|
|
++NumIncluded; // Count # of attempted #includes.
|
|
|
|
|
|
|
|
// Get information about this file.
|
2009-04-25 04:03:17 +08:00
|
|
|
HeaderFileInfo &FileInfo = getFileInfo(File);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2017-01-11 10:14:51 +08:00
|
|
|
// FIXME: this is a workaround for the lack of proper modules-aware support
|
|
|
|
// for #import / #pragma once
|
|
|
|
auto TryEnterImported = [&](void) -> bool {
|
|
|
|
if (!ModulesEnabled)
|
|
|
|
return false;
|
2017-06-02 09:55:39 +08:00
|
|
|
// Ensure FileInfo bits are up to date.
|
|
|
|
ModMap.resolveHeaderDirectives(File);
|
2017-01-11 10:14:51 +08:00
|
|
|
// Modules with builtins are special; multiple modules use builtins as
|
|
|
|
// modular headers, example:
|
|
|
|
//
|
|
|
|
// module stddef { header "stddef.h" export * }
|
|
|
|
//
|
|
|
|
// After module map parsing, this expands to:
|
|
|
|
//
|
|
|
|
// module stddef {
|
|
|
|
// header "/path_to_builtin_dirs/stddef.h"
|
|
|
|
// textual "stddef.h"
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// It's common that libc++ and system modules will both define such
|
|
|
|
// submodules. Make sure cached results for a builtin header won't
|
|
|
|
// prevent other builtin modules to potentially enter the builtin header.
|
|
|
|
// Note that builtins are header guarded and the decision to actually
|
|
|
|
// enter them is postponed to the controlling macros logic below.
|
|
|
|
bool TryEnterHdr = false;
|
|
|
|
if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader)
|
|
|
|
TryEnterHdr = File->getDir() == ModMap.getBuiltinDir() &&
|
|
|
|
ModuleMap::isBuiltinHeader(
|
|
|
|
llvm::sys::path::filename(File->getName()));
|
|
|
|
|
|
|
|
// Textual headers can be #imported from different modules. Since ObjC
|
|
|
|
// headers find in the wild might rely only on #import and do not contain
|
|
|
|
// controlling macros, be conservative and only try to enter textual headers
|
|
|
|
// if such macro is present.
|
2017-08-12 09:38:26 +08:00
|
|
|
if (!FileInfo.isModuleHeader &&
|
2017-01-11 10:14:51 +08:00
|
|
|
FileInfo.getControllingMacro(ExternalLookup))
|
|
|
|
TryEnterHdr = true;
|
|
|
|
return TryEnterHdr;
|
|
|
|
};
|
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// If this is a #import directive, check that we have not already imported
|
|
|
|
// this header.
|
|
|
|
if (isImport) {
|
|
|
|
// If this has already been imported, don't import it again.
|
|
|
|
FileInfo.isImport = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// Has this already been #import'ed or #include'd?
|
2017-01-11 10:14:51 +08:00
|
|
|
if (FileInfo.NumIncludes && !TryEnterImported())
|
|
|
|
return false;
|
2006-10-18 13:34:33 +08:00
|
|
|
} else {
|
|
|
|
// Otherwise, if this is a #include of a file that was previously #import'd
|
|
|
|
// or if this is the second #include of a #pragma once file, ignore it.
|
2017-01-11 10:14:51 +08:00
|
|
|
if (FileInfo.isImport && !TryEnterImported())
|
2006-10-18 13:34:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// Next, check to see if the file is wrapped with #ifndef guards. If so, and
|
|
|
|
// if the macro that guards it is defined, we know the #include has no effect.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const IdentifierInfo *ControllingMacro
|
2015-07-11 06:27:17 +08:00
|
|
|
= FileInfo.getControllingMacro(ExternalLookup)) {
|
|
|
|
// If the header corresponds to a module, check whether the macro is already
|
|
|
|
// defined in that module rather than checking in the current set of visible
|
|
|
|
// modules.
|
|
|
|
if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M)
|
|
|
|
: PP.isMacroDefined(ControllingMacro)) {
|
2009-04-26 07:30:02 +08:00
|
|
|
++NumMultiIncludeFileOptzn;
|
|
|
|
return false;
|
|
|
|
}
|
2015-07-11 06:27:17 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
// Increment the number of times this file has been included.
|
|
|
|
++FileInfo.NumIncludes;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-10-18 13:34:33 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:46:11 +08:00
|
|
|
size_t HeaderSearch::getTotalMemory() const {
|
|
|
|
return SearchDirs.capacity()
|
2011-07-28 02:41:18 +08:00
|
|
|
+ llvm::capacity_in_bytes(FileInfo)
|
|
|
|
+ llvm::capacity_in_bytes(HeaderMaps)
|
2011-07-27 07:46:11 +08:00
|
|
|
+ LookupFileCache.getAllocator().getTotalMemory()
|
|
|
|
+ FrameworkMap.getAllocator().getTotalMemory();
|
|
|
|
}
|
2011-07-28 12:45:53 +08:00
|
|
|
|
|
|
|
StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
|
2014-11-19 11:06:06 +08:00
|
|
|
return FrameworkNames.insert(Framework).first->first();
|
2011-07-28 12:45:53 +08:00
|
|
|
}
|
2011-11-12 03:10:28 +08:00
|
|
|
|
|
|
|
bool HeaderSearch::hasModuleMap(StringRef FileName,
|
2013-06-22 00:28:10 +08:00
|
|
|
const DirectoryEntry *Root,
|
|
|
|
bool IsSystem) {
|
2015-06-16 08:08:24 +08:00
|
|
|
if (!HSOpts->ImplicitModuleMaps)
|
2013-12-13 00:08:33 +08:00
|
|
|
return false;
|
|
|
|
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
|
2011-11-12 03:10:28 +08:00
|
|
|
|
|
|
|
StringRef DirName = FileName;
|
|
|
|
do {
|
|
|
|
// Get the parent directory name.
|
|
|
|
DirName = llvm::sys::path::parent_path(DirName);
|
|
|
|
if (DirName.empty())
|
|
|
|
return false;
|
2013-09-24 17:27:13 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Determine whether this directory exists.
|
|
|
|
const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
|
|
|
|
if (!Dir)
|
|
|
|
return false;
|
2013-09-24 17:27:13 +08:00
|
|
|
|
2014-03-20 04:23:34 +08:00
|
|
|
// Try to load the module map file in this directory.
|
2014-12-02 08:08:08 +08:00
|
|
|
switch (loadModuleMapFile(Dir, IsSystem,
|
|
|
|
llvm::sys::path::extension(Dir->getName()) ==
|
|
|
|
".framework")) {
|
2011-11-12 08:22:19 +08:00
|
|
|
case LMM_NewlyLoaded:
|
|
|
|
case LMM_AlreadyLoaded:
|
2011-11-12 08:05:07 +08:00
|
|
|
// Success. All of the directories we stepped through inherit this module
|
|
|
|
// map file.
|
2011-11-12 03:10:28 +08:00
|
|
|
for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
|
|
|
|
DirectoryHasModuleMap[FixUpDirectories[I]] = true;
|
|
|
|
return true;
|
2013-10-22 16:09:47 +08:00
|
|
|
|
|
|
|
case LMM_NoDirectory:
|
|
|
|
case LMM_InvalidModuleMap:
|
|
|
|
break;
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
2011-11-12 08:05:07 +08:00
|
|
|
// If we hit the top of our search, we're done.
|
|
|
|
if (Dir == Root)
|
|
|
|
return false;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Keep track of all of the directories we checked, so we can mark them as
|
|
|
|
// having module maps if we eventually do find a module map.
|
|
|
|
FixUpDirectories.push_back(Dir);
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
2013-06-21 05:14:14 +08:00
|
|
|
ModuleMap::KnownHeader
|
2016-10-21 09:41:56 +08:00
|
|
|
HeaderSearch::findModuleForHeader(const FileEntry *File,
|
|
|
|
bool AllowTextual) const {
|
2013-03-14 05:13:51 +08:00
|
|
|
if (ExternalSource) {
|
|
|
|
// Make sure the external source has handled header info about this file,
|
|
|
|
// which includes whether the file is part of a module.
|
2015-08-19 07:42:23 +08:00
|
|
|
(void)getExistingFileInfo(File);
|
2013-03-14 05:13:51 +08:00
|
|
|
}
|
2016-10-21 09:41:56 +08:00
|
|
|
return ModMap.findModuleForHeader(File, AllowTextual);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
|
|
|
|
Module *RequestingModule,
|
|
|
|
ModuleMap::KnownHeader *SuggestedModule) {
|
|
|
|
ModuleMap::KnownHeader Module =
|
|
|
|
HS.findModuleForHeader(File, /*AllowTextual*/true);
|
|
|
|
if (SuggestedModule)
|
|
|
|
*SuggestedModule = (Module.getRole() & ModuleMap::TextualHeader)
|
|
|
|
? ModuleMap::KnownHeader()
|
|
|
|
: Module;
|
|
|
|
|
|
|
|
// If this module specifies [no_undeclared_includes], we cannot find any
|
|
|
|
// file that's in a non-dependency module.
|
|
|
|
if (RequestingModule && Module && RequestingModule->NoUndeclaredIncludes) {
|
|
|
|
HS.getModuleMap().resolveUses(RequestingModule, /*Complain*/false);
|
|
|
|
if (!RequestingModule->directlyUses(Module.getModule())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
2015-10-17 05:42:56 +08:00
|
|
|
bool HeaderSearch::findUsableModuleForHeader(
|
|
|
|
const FileEntry *File, const DirectoryEntry *Root, Module *RequestingModule,
|
|
|
|
ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) {
|
2016-10-21 09:41:56 +08:00
|
|
|
if (File && needModuleLookup(RequestingModule, SuggestedModule)) {
|
2015-10-17 05:42:56 +08:00
|
|
|
// If there is a module that corresponds to this header, suggest it.
|
|
|
|
hasModuleMap(File->getName(), Root, IsSystemHeaderDir);
|
2016-10-21 09:41:56 +08:00
|
|
|
return suggestModule(*this, File, RequestingModule, SuggestedModule);
|
2015-10-17 05:42:56 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HeaderSearch::findUsableModuleForFrameworkHeader(
|
|
|
|
const FileEntry *File, StringRef FrameworkName, Module *RequestingModule,
|
|
|
|
ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework) {
|
|
|
|
// If we're supposed to suggest a module, look for one now.
|
2016-10-21 09:41:56 +08:00
|
|
|
if (needModuleLookup(RequestingModule, SuggestedModule)) {
|
2015-10-17 05:42:56 +08:00
|
|
|
// Find the top-level framework based on this framework.
|
|
|
|
SmallVector<std::string, 4> SubmodulePath;
|
|
|
|
const DirectoryEntry *TopFrameworkDir
|
|
|
|
= ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
|
|
|
|
|
|
|
|
// Determine the name of the top-level framework.
|
|
|
|
StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
|
|
|
|
|
|
|
|
// Load this framework module. If that succeeds, find the suggested module
|
|
|
|
// for this header, if any.
|
|
|
|
loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystemFramework);
|
|
|
|
|
|
|
|
// FIXME: This can find a module not part of ModuleName, which is
|
|
|
|
// important so that we're consistent about whether this header
|
|
|
|
// corresponds to a module. Possibly we should lock down framework modules
|
|
|
|
// so that this is not possible.
|
2016-10-21 09:41:56 +08:00
|
|
|
return suggestModule(*this, File, RequestingModule, SuggestedModule);
|
2015-10-17 05:42:56 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-10 11:09:48 +08:00
|
|
|
static const FileEntry *getPrivateModuleMap(const FileEntry *File,
|
2014-03-20 04:23:34 +08:00
|
|
|
FileManager &FileMgr) {
|
2014-12-10 11:09:48 +08:00
|
|
|
StringRef Filename = llvm::sys::path::filename(File->getName());
|
|
|
|
SmallString<128> PrivateFilename(File->getDir()->getName());
|
2014-03-20 04:23:34 +08:00
|
|
|
if (Filename == "module.map")
|
|
|
|
llvm::sys::path::append(PrivateFilename, "module_private.map");
|
|
|
|
else if (Filename == "module.modulemap")
|
|
|
|
llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
|
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
return FileMgr.getFile(PrivateFilename);
|
|
|
|
}
|
|
|
|
|
2017-05-06 06:18:51 +08:00
|
|
|
bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
|
2017-06-01 04:56:55 +08:00
|
|
|
FileID ID, unsigned *Offset,
|
|
|
|
StringRef OriginalModuleMapFile) {
|
2014-12-10 11:09:48 +08:00
|
|
|
// Find the directory for the module. For frameworks, that may require going
|
|
|
|
// up from the 'Modules' directory.
|
|
|
|
const DirectoryEntry *Dir = nullptr;
|
|
|
|
if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd)
|
|
|
|
Dir = FileMgr.getDirectory(".");
|
|
|
|
else {
|
2017-06-01 04:56:55 +08:00
|
|
|
if (!OriginalModuleMapFile.empty()) {
|
|
|
|
// We're building a preprocessed module map. Find or invent the directory
|
|
|
|
// that it originally occupied.
|
|
|
|
Dir = FileMgr.getDirectory(
|
|
|
|
llvm::sys::path::parent_path(OriginalModuleMapFile));
|
|
|
|
if (!Dir) {
|
|
|
|
auto *FakeFile = FileMgr.getVirtualFile(OriginalModuleMapFile, 0, 0);
|
|
|
|
Dir = FakeFile->getDir();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Dir = File->getDir();
|
|
|
|
}
|
|
|
|
|
2014-12-10 11:09:48 +08:00
|
|
|
StringRef DirName(Dir->getName());
|
|
|
|
if (llvm::sys::path::filename(DirName) == "Modules") {
|
|
|
|
DirName = llvm::sys::path::parent_path(DirName);
|
|
|
|
if (DirName.endswith(".framework"))
|
|
|
|
Dir = FileMgr.getDirectory(DirName);
|
|
|
|
// FIXME: This assert can fail if there's a race between the above check
|
|
|
|
// and the removal of the directory.
|
|
|
|
assert(Dir && "parent must exist");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-06 06:18:51 +08:00
|
|
|
switch (loadModuleMapFileImpl(File, IsSystem, Dir, ID, Offset)) {
|
2014-03-20 04:23:34 +08:00
|
|
|
case LMM_AlreadyLoaded:
|
|
|
|
case LMM_NewlyLoaded:
|
|
|
|
return false;
|
|
|
|
case LMM_NoDirectory:
|
|
|
|
case LMM_InvalidModuleMap:
|
|
|
|
return true;
|
|
|
|
}
|
2014-03-20 22:22:33 +08:00
|
|
|
llvm_unreachable("Unknown load module map result");
|
2014-03-20 04:23:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
HeaderSearch::LoadModuleMapResult
|
2014-12-10 11:09:48 +08:00
|
|
|
HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem,
|
2017-05-06 06:18:51 +08:00
|
|
|
const DirectoryEntry *Dir, FileID ID,
|
|
|
|
unsigned *Offset) {
|
2014-03-20 04:23:34 +08:00
|
|
|
assert(File && "expected FileEntry");
|
|
|
|
|
2014-10-17 09:42:53 +08:00
|
|
|
// Check whether we've already loaded this module map, and mark it as being
|
|
|
|
// loaded in case we recursively try to load it from itself.
|
|
|
|
auto AddResult = LoadedModuleMaps.insert(std::make_pair(File, true));
|
|
|
|
if (!AddResult.second)
|
|
|
|
return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
|
2014-03-20 04:23:34 +08:00
|
|
|
|
2017-05-06 06:18:51 +08:00
|
|
|
if (ModMap.parseModuleMapFile(File, IsSystem, Dir, ID, Offset)) {
|
2014-10-17 09:42:53 +08:00
|
|
|
LoadedModuleMaps[File] = false;
|
2014-03-20 04:23:34 +08:00
|
|
|
return LMM_InvalidModuleMap;
|
2011-12-08 05:25:07 +08:00
|
|
|
}
|
2014-03-20 04:23:34 +08:00
|
|
|
|
|
|
|
// Try to load a corresponding private module map.
|
2014-12-10 11:09:48 +08:00
|
|
|
if (const FileEntry *PMMFile = getPrivateModuleMap(File, FileMgr)) {
|
|
|
|
if (ModMap.parseModuleMapFile(PMMFile, IsSystem, Dir)) {
|
2014-10-17 09:42:53 +08:00
|
|
|
LoadedModuleMaps[File] = false;
|
2014-03-20 04:23:34 +08:00
|
|
|
return LMM_InvalidModuleMap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This directory has a module map.
|
|
|
|
return LMM_NewlyLoaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FileEntry *
|
|
|
|
HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
|
2015-06-16 08:08:24 +08:00
|
|
|
if (!HSOpts->ImplicitModuleMaps)
|
2014-11-25 17:45:48 +08:00
|
|
|
return nullptr;
|
2014-03-20 04:23:34 +08:00
|
|
|
// For frameworks, the preferred spelling is Modules/module.modulemap, but
|
|
|
|
// module.map at the framework root is also accepted.
|
|
|
|
SmallString<128> ModuleMapFileName(Dir->getName());
|
|
|
|
if (IsFramework)
|
|
|
|
llvm::sys::path::append(ModuleMapFileName, "Modules");
|
|
|
|
llvm::sys::path::append(ModuleMapFileName, "module.modulemap");
|
|
|
|
if (const FileEntry *F = FileMgr.getFile(ModuleMapFileName))
|
|
|
|
return F;
|
|
|
|
|
|
|
|
// Continue to allow module.map
|
|
|
|
ModuleMapFileName = Dir->getName();
|
|
|
|
llvm::sys::path::append(ModuleMapFileName, "module.map");
|
|
|
|
return FileMgr.getFile(ModuleMapFileName);
|
2011-11-16 08:09:06 +08:00
|
|
|
}
|
|
|
|
|
2014-03-20 04:23:34 +08:00
|
|
|
Module *HeaderSearch::loadFrameworkModule(StringRef Name,
|
2012-01-30 01:08:11 +08:00
|
|
|
const DirectoryEntry *Dir,
|
|
|
|
bool IsSystem) {
|
2011-12-01 07:21:26 +08:00
|
|
|
if (Module *Module = ModMap.findModule(Name))
|
2011-11-17 09:41:17 +08:00
|
|
|
return Module;
|
2014-11-25 17:45:48 +08:00
|
|
|
|
2011-11-17 09:41:17 +08:00
|
|
|
// Try to load a module map file.
|
2014-03-20 04:23:34 +08:00
|
|
|
switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
|
2011-11-17 09:41:17 +08:00
|
|
|
case LMM_InvalidModuleMap:
|
2015-07-02 21:19:48 +08:00
|
|
|
// Try to infer a module map from the framework directory.
|
|
|
|
if (HSOpts->ImplicitModuleMaps)
|
|
|
|
ModMap.inferFrameworkModule(Dir, IsSystem, /*Parent=*/nullptr);
|
2011-11-17 09:41:17 +08:00
|
|
|
break;
|
2014-11-25 17:45:48 +08:00
|
|
|
|
2011-11-17 09:41:17 +08:00
|
|
|
case LMM_AlreadyLoaded:
|
|
|
|
case LMM_NoDirectory:
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2011-11-17 09:41:17 +08:00
|
|
|
case LMM_NewlyLoaded:
|
2015-07-02 21:19:48 +08:00
|
|
|
break;
|
2011-11-17 09:41:17 +08:00
|
|
|
}
|
2012-01-14 06:31:52 +08:00
|
|
|
|
2015-07-02 21:19:48 +08:00
|
|
|
return ModMap.findModule(Name);
|
2011-11-17 09:41:17 +08:00
|
|
|
}
|
|
|
|
|
2011-11-16 08:09:06 +08:00
|
|
|
|
2011-11-12 08:22:19 +08:00
|
|
|
HeaderSearch::LoadModuleMapResult
|
2014-03-20 04:23:34 +08:00
|
|
|
HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
|
|
|
|
bool IsFramework) {
|
2011-11-12 08:05:07 +08:00
|
|
|
if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
|
2014-03-20 04:23:34 +08:00
|
|
|
return loadModuleMapFile(Dir, IsSystem, IsFramework);
|
2011-11-12 08:05:07 +08:00
|
|
|
|
2011-11-12 08:22:19 +08:00
|
|
|
return LMM_NoDirectory;
|
2011-11-12 08:05:07 +08:00
|
|
|
}
|
|
|
|
|
2011-11-12 08:22:19 +08:00
|
|
|
HeaderSearch::LoadModuleMapResult
|
2014-03-20 04:23:34 +08:00
|
|
|
HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
|
|
|
|
bool IsFramework) {
|
|
|
|
auto KnownDir = DirectoryHasModuleMap.find(Dir);
|
2011-11-12 08:05:07 +08:00
|
|
|
if (KnownDir != DirectoryHasModuleMap.end())
|
2014-10-17 09:42:53 +08:00
|
|
|
return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
|
2011-12-07 10:23:45 +08:00
|
|
|
|
2014-03-20 04:23:34 +08:00
|
|
|
if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
|
2014-12-10 11:09:48 +08:00
|
|
|
LoadModuleMapResult Result =
|
|
|
|
loadModuleMapFileImpl(ModuleMapFile, IsSystem, Dir);
|
2014-03-20 04:23:34 +08:00
|
|
|
// Add Dir explicitly in case ModuleMapFile is in a subdirectory.
|
|
|
|
// E.g. Foo.framework/Modules/module.modulemap
|
|
|
|
// ^Dir ^ModuleMapFile
|
|
|
|
if (Result == LMM_NewlyLoaded)
|
|
|
|
DirectoryHasModuleMap[Dir] = true;
|
2014-10-17 09:42:53 +08:00
|
|
|
else if (Result == LMM_InvalidModuleMap)
|
|
|
|
DirectoryHasModuleMap[Dir] = false;
|
2014-03-20 04:23:34 +08:00
|
|
|
return Result;
|
2011-11-12 08:05:07 +08:00
|
|
|
}
|
2011-11-12 08:22:19 +08:00
|
|
|
return LMM_InvalidModuleMap;
|
2011-11-12 08:05:07 +08:00
|
|
|
}
|
2011-11-12 03:10:28 +08:00
|
|
|
|
2013-01-13 03:30:44 +08:00
|
|
|
void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
|
2012-01-30 02:15:03 +08:00
|
|
|
Modules.clear();
|
2014-11-25 17:45:48 +08:00
|
|
|
|
2015-06-16 08:08:24 +08:00
|
|
|
if (HSOpts->ImplicitModuleMaps) {
|
2014-11-25 17:45:48 +08:00
|
|
|
// Load module maps for each of the header search directories.
|
|
|
|
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
|
|
|
|
bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
|
|
|
|
if (SearchDirs[Idx].isFramework()) {
|
|
|
|
std::error_code EC;
|
|
|
|
SmallString<128> DirNative;
|
|
|
|
llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(),
|
|
|
|
DirNative);
|
|
|
|
|
|
|
|
// Search each of the ".framework" directories to load them as modules.
|
2016-05-17 00:46:01 +08:00
|
|
|
vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
|
|
|
|
for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
|
2014-11-25 17:45:48 +08:00
|
|
|
Dir != DirEnd && !EC; Dir.increment(EC)) {
|
2016-05-17 00:46:01 +08:00
|
|
|
if (llvm::sys::path::extension(Dir->getName()) != ".framework")
|
2014-11-25 17:45:48 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
const DirectoryEntry *FrameworkDir =
|
2016-05-17 00:46:01 +08:00
|
|
|
FileMgr.getDirectory(Dir->getName());
|
2014-11-25 17:45:48 +08:00
|
|
|
if (!FrameworkDir)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Load this framework module.
|
2016-05-17 00:46:01 +08:00
|
|
|
loadFrameworkModule(llvm::sys::path::stem(Dir->getName()),
|
|
|
|
FrameworkDir, IsSystem);
|
2014-11-25 17:45:48 +08:00
|
|
|
}
|
|
|
|
continue;
|
2012-01-30 02:15:03 +08:00
|
|
|
}
|
2014-11-25 17:45:48 +08:00
|
|
|
|
|
|
|
// FIXME: Deal with header maps.
|
|
|
|
if (SearchDirs[Idx].isHeaderMap())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Try to load a module map file for the search directory.
|
|
|
|
loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
|
|
|
|
/*IsFramework*/ false);
|
|
|
|
|
|
|
|
// Try to load module map files for immediate subdirectories of this
|
|
|
|
// search directory.
|
|
|
|
loadSubdirectoryModuleMaps(SearchDirs[Idx]);
|
2012-01-30 02:15:03 +08:00
|
|
|
}
|
|
|
|
}
|
2014-11-25 17:45:48 +08:00
|
|
|
|
2012-01-30 02:15:03 +08:00
|
|
|
// Populate the list of modules.
|
|
|
|
for (ModuleMap::module_iterator M = ModMap.module_begin(),
|
|
|
|
MEnd = ModMap.module_end();
|
|
|
|
M != MEnd; ++M) {
|
|
|
|
Modules.push_back(M->getValue());
|
|
|
|
}
|
|
|
|
}
|
2013-03-21 09:08:50 +08:00
|
|
|
|
2013-05-11 06:52:27 +08:00
|
|
|
void HeaderSearch::loadTopLevelSystemModules() {
|
2015-06-16 08:08:24 +08:00
|
|
|
if (!HSOpts->ImplicitModuleMaps)
|
2014-11-25 17:45:48 +08:00
|
|
|
return;
|
|
|
|
|
2013-05-11 06:52:27 +08:00
|
|
|
// Load module maps for each of the header search directories.
|
|
|
|
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
|
2013-11-02 07:08:38 +08:00
|
|
|
// We only care about normal header directories.
|
|
|
|
if (!SearchDirs[Idx].isNormalDir()) {
|
2013-05-11 06:52:27 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to load a module map file for the search directory.
|
2013-06-22 00:28:10 +08:00
|
|
|
loadModuleMapFile(SearchDirs[Idx].getDir(),
|
2014-03-20 04:23:34 +08:00
|
|
|
SearchDirs[Idx].isSystemHeaderDirectory(),
|
|
|
|
SearchDirs[Idx].isFramework());
|
2013-05-11 06:52:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-21 09:08:50 +08:00
|
|
|
void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
|
2015-06-16 08:08:24 +08:00
|
|
|
assert(HSOpts->ImplicitModuleMaps &&
|
2014-11-25 17:45:48 +08:00
|
|
|
"Should not be loading subdirectory module maps");
|
|
|
|
|
2013-03-21 09:08:50 +08:00
|
|
|
if (SearchDir.haveSearchedAllModuleMaps())
|
|
|
|
return;
|
2014-06-12 22:02:15 +08:00
|
|
|
|
|
|
|
std::error_code EC;
|
2013-03-21 09:08:50 +08:00
|
|
|
SmallString<128> DirNative;
|
|
|
|
llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
|
2016-05-17 00:46:01 +08:00
|
|
|
vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
|
|
|
|
for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
|
2013-03-21 09:08:50 +08:00
|
|
|
Dir != DirEnd && !EC; Dir.increment(EC)) {
|
2016-05-17 00:46:01 +08:00
|
|
|
bool IsFramework =
|
|
|
|
llvm::sys::path::extension(Dir->getName()) == ".framework";
|
2015-02-24 12:58:15 +08:00
|
|
|
if (IsFramework == SearchDir.isFramework())
|
2016-05-17 00:46:01 +08:00
|
|
|
loadModuleMapFile(Dir->getName(), SearchDir.isSystemHeaderDirectory(),
|
2015-02-24 12:58:15 +08:00
|
|
|
SearchDir.isFramework());
|
2013-03-21 09:08:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SearchDir.setSearchedAllModuleMaps(true);
|
|
|
|
}
|
2016-04-28 05:57:05 +08:00
|
|
|
|
|
|
|
std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
|
|
|
|
bool *IsSystem) {
|
|
|
|
// FIXME: We assume that the path name currently cached in the FileEntry is
|
|
|
|
// the most appropriate one for this analysis (and that it's spelled the same
|
|
|
|
// way as the corresponding header search path).
|
2016-10-11 06:52:47 +08:00
|
|
|
StringRef Name = File->getName();
|
2016-04-28 05:57:05 +08:00
|
|
|
|
|
|
|
unsigned BestPrefixLength = 0;
|
|
|
|
unsigned BestSearchDir;
|
|
|
|
|
|
|
|
for (unsigned I = 0; I != SearchDirs.size(); ++I) {
|
|
|
|
// FIXME: Support this search within frameworks and header maps.
|
|
|
|
if (!SearchDirs[I].isNormalDir())
|
|
|
|
continue;
|
|
|
|
|
2016-10-11 15:31:29 +08:00
|
|
|
StringRef Dir = SearchDirs[I].getDir()->getName();
|
2016-04-28 05:57:05 +08:00
|
|
|
for (auto NI = llvm::sys::path::begin(Name),
|
|
|
|
NE = llvm::sys::path::end(Name),
|
|
|
|
DI = llvm::sys::path::begin(Dir),
|
|
|
|
DE = llvm::sys::path::end(Dir);
|
|
|
|
/*termination condition in loop*/; ++NI, ++DI) {
|
|
|
|
// '.' components in Name are ignored.
|
|
|
|
while (NI != NE && *NI == ".")
|
|
|
|
++NI;
|
|
|
|
if (NI == NE)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// '.' components in Dir are ignored.
|
|
|
|
while (DI != DE && *DI == ".")
|
|
|
|
++DI;
|
|
|
|
if (DI == DE) {
|
|
|
|
// Dir is a prefix of Name, up to '.' components and choice of path
|
|
|
|
// separators.
|
|
|
|
unsigned PrefixLength = NI - llvm::sys::path::begin(Name);
|
|
|
|
if (PrefixLength > BestPrefixLength) {
|
|
|
|
BestPrefixLength = PrefixLength;
|
|
|
|
BestSearchDir = I;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*NI != *DI)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsSystem)
|
|
|
|
*IsSystem = BestPrefixLength ? BestSearchDir >= SystemDirIdx : false;
|
2016-10-11 06:52:47 +08:00
|
|
|
return Name.drop_front(BestPrefixLength);
|
2016-04-28 05:57:05 +08:00
|
|
|
}
|