[AST] Treat platform modules as non-user

Modules defined within the SDK are considered
non-user modules, extend this to any module found
within the parent platform directory if there is
one. This ensures we include modules such as
XCTest and Testing.

rdar://131854240
This commit is contained in:
Hamish Knight
2024-08-23 14:23:37 +01:00
parent 7075c05d62
commit 940f5f7c2a
6 changed files with 70 additions and 4 deletions

View File

@@ -380,6 +380,8 @@ private:
std::optional<StringRef> SysRoot = std::nullopt;
mutable std::optional<std::string> SDKPlatformPath = std::nullopt;
public:
StringRef getSDKPath() const { return SDKPath; }
@@ -398,6 +400,12 @@ public:
Lookup.searchPathsDidChange();
}
/// Retrieves the corresponding parent platform path for the SDK, or
/// \c nullopt if there isn't one.
/// NOTE: This computes and caches the result, and as such will not respect
/// a different FileSystem being passed later.
std::optional<StringRef> getSDKPlatformPath(llvm::vfs::FileSystem *FS) const;
std::optional<StringRef> getWinSDKRoot() const { return WinSDKRoot; }
void setWinSDKRoot(StringRef root) {
WinSDKRoot = root;

View File

@@ -4773,8 +4773,9 @@ void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);
/// Computes whether a module is part of the stdlib or contained within the
/// SDK. If no SDK was specified, falls back to whether the module was
/// specified as a system module (ie. it's on the system search path).
/// SDK or the platform directory. If no SDK was specified, falls back to
/// whether the module was specified as a system module (ie. it's on the system
/// search path).
class IsNonUserModuleRequest
: public SimpleRequest<IsNonUserModuleRequest,
bool(ModuleDecl *),

View File

@@ -4009,7 +4009,8 @@ FrontendStatsTracer::getTraceFormatter<const SourceFile *>() {
bool IsNonUserModuleRequest::evaluate(Evaluator &evaluator, ModuleDecl *mod) const {
// If there's no SDK path, fallback to checking whether the module was
// in the system search path or a clang system module
SearchPathOptions &searchPathOpts = mod->getASTContext().SearchPathOpts;
auto &ctx = mod->getASTContext();
SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
StringRef sdkPath = searchPathOpts.getSDKPath();
if (sdkPath.empty() && mod->isSystemModule())
return true;
@@ -4028,9 +4029,14 @@ bool IsNonUserModuleRequest::evaluate(Evaluator &evaluator, ModuleDecl *mod) con
if (modulePath.empty())
return false;
// If we have a platform path, check against that as it will be a parent of
// the SDK path.
auto *FS = ctx.SourceMgr.getFileSystem().get();
auto sdkOrPlatform = searchPathOpts.getSDKPlatformPath(FS).value_or(sdkPath);
StringRef runtimePath = searchPathOpts.RuntimeResourcePath;
return (!runtimePath.empty() && pathStartsWith(runtimePath, modulePath)) ||
(!sdkPath.empty() && pathStartsWith(sdkPath, modulePath));
(!sdkOrPlatform.empty() && pathStartsWith(sdkOrPlatform, modulePath));
}
version::Version ModuleDecl::getLanguageVersionBuiltWith() const {

View File

@@ -80,6 +80,34 @@ void ModuleSearchPathLookup::rebuildLookupTable(const SearchPathOptions *Opts,
State.IsPopulated = true;
}
static std::string computeSDKPlatformPath(StringRef SDKPath,
llvm::vfs::FileSystem *FS) {
if (SDKPath.empty())
return "";
SmallString<128> platformPath;
if (auto err = FS->getRealPath(SDKPath, platformPath))
llvm::sys::path::append(platformPath, SDKPath);
llvm::sys::path::remove_filename(platformPath); // specific SDK
llvm::sys::path::remove_filename(platformPath); // SDKs
llvm::sys::path::remove_filename(platformPath); // Developer
if (!llvm::sys::path::filename(platformPath).endswith(".platform"))
return "";
return platformPath.str().str();
}
std::optional<StringRef>
SearchPathOptions::getSDKPlatformPath(llvm::vfs::FileSystem *FS) const {
if (!SDKPlatformPath)
SDKPlatformPath = computeSDKPlatformPath(getSDKPath(), FS);
if (SDKPlatformPath->empty())
return std::nullopt;
return *SDKPlatformPath;
}
void SearchPathOptions::dump(bool isDarwin) const {
llvm::errs() << "Module import search paths (non system):\n";
for (auto Entry : llvm::enumerate(getImportSearchPaths())) {

View File

@@ -1321,6 +1321,9 @@ if run_vendor == 'apple':
(config.darwin_xcrun_toolchain, config.variant_sdk))
extra_frameworks_dir = make_path(config.variant_sdk, "..", "..", "..",
"Developer", "Library", "Frameworks")
extra_platform_swift_modules = make_path(config.variant_sdk, "..", "..", "..",
"Developer", "usr", "lib")
target_options = (
"-target %s %s %s" %
(config.variant_triple, config.resource_dir_opt, mcp_opt))
@@ -2805,7 +2808,9 @@ config.substitutions.insert(0, ('%test-resource-dir', test_resource_dir))
if run_vendor != 'apple':
extra_frameworks_dir = ''
extra_platform_swift_modules = ''
config.substitutions.append(('%xcode-extra-frameworks-dir', extra_frameworks_dir))
config.substitutions.append(('%xcode-extra-platform-swift-modules', extra_platform_swift_modules))
config.substitutions.append(('%target-swiftmodule-name', target_specific_module_triple + '.swiftmodule'))
config.substitutions.append(('%target-swiftdoc-name', target_specific_module_triple + '.swiftdoc'))

View File

@@ -0,0 +1,18 @@
// RUN: %empty-directory(%t)
// RUN: ln -s %sdk %t/sdk
// RUN: %batch-code-completion -F %xcode-extra-frameworks-dir -I %xcode-extra-platform-swift-modules
// Works if SDK is specified as a symlink too.
// RUN: %batch-code-completion -sdk %t/sdk -F %xcode-extra-frameworks-dir -I %xcode-extra-platform-swift-modules
// REQUIRES: VENDOR=apple
// rdar://131854240 - Make sure modules found in the platform dir are treated
// as system.
import XCTest
#^COMPLETE^#
// COMPLETE: Decl[Module]/None/IsSystem: XCTest[#Module#]; name=XCTest
// COMPLETE: Decl[FreeFunction]/OtherModule[XCTest]/IsSystem: XCTFail()[#Void#]; name=XCTFail()