mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[NFC] Clarify semantics of getImportedModules.
The lack of clarity manifested as unexpected behavior when using getImportedModules to create the module import graph. The new behavior makes SPI-ness and Shadowing-ness behave similarly in terms of filtering. We also check if a filter is well-formed to avoid accidental empty import lists.
This commit is contained in:
@@ -653,7 +653,8 @@ public:
|
|||||||
Default = 1 << 1,
|
Default = 1 << 1,
|
||||||
/// Include imports declared with `@_implementationOnly`.
|
/// Include imports declared with `@_implementationOnly`.
|
||||||
ImplementationOnly = 1 << 2,
|
ImplementationOnly = 1 << 2,
|
||||||
/// Include imports of SPIs declared with `@_spi`
|
/// Include imports of SPIs declared with `@_spi`. Non-SPI imports are
|
||||||
|
/// included whether or not this flag is specified.
|
||||||
SPIAccessControl = 1 << 3,
|
SPIAccessControl = 1 << 3,
|
||||||
/// Include imports shadowed by a cross-import overlay. Unshadowed imports
|
/// Include imports shadowed by a cross-import overlay. Unshadowed imports
|
||||||
/// are included whether or not this flag is specified.
|
/// are included whether or not this flag is specified.
|
||||||
@@ -664,8 +665,33 @@ public:
|
|||||||
|
|
||||||
/// Looks up which modules are imported by this module.
|
/// Looks up which modules are imported by this module.
|
||||||
///
|
///
|
||||||
/// \p filter controls whether public, private, or any imports are included
|
/// \p filter controls which imports are included in the list.
|
||||||
/// in this list.
|
///
|
||||||
|
/// There are three axes for categorizing imports:
|
||||||
|
/// 1. Privacy: Exported/Private/ImplementationOnly (mutually exclusive).
|
||||||
|
/// 2. SPI/non-SPI: An import of any privacy level may be @_spi("SPIName").
|
||||||
|
/// 3. Shadowed/Non-shadowed: An import of any privacy level may be shadowed
|
||||||
|
/// by a cross-import overlay.
|
||||||
|
///
|
||||||
|
/// It is also possible for SPI imports to be shadowed by a cross-import
|
||||||
|
/// overlay.
|
||||||
|
///
|
||||||
|
/// If \p filter contains multiple privacy levels, modules at all the privacy
|
||||||
|
/// levels are included.
|
||||||
|
///
|
||||||
|
/// If \p filter contains \c ImportFilterKind::SPIAccessControl, then both
|
||||||
|
/// SPI and non-SPI imports are included. Otherwise, only non-SPI imports are
|
||||||
|
/// included.
|
||||||
|
///
|
||||||
|
/// If \p filter contains \c ImportFilterKind::ShadowedByCrossImportOverlay,
|
||||||
|
/// both shadowed and non-shadowed imports are included. Otherwise, only
|
||||||
|
/// non-shadowed imports are included.
|
||||||
|
///
|
||||||
|
/// Clang modules have some additional complexities; see the implementation of
|
||||||
|
/// \c ClangModuleUnit::getImportedModules for details.
|
||||||
|
///
|
||||||
|
/// \pre \p filter must contain at least one privacy level, i.e. one of
|
||||||
|
/// \c Exported or \c Private or \c ImplementationOnly.
|
||||||
void getImportedModules(SmallVectorImpl<ImportedModule> &imports,
|
void getImportedModules(SmallVectorImpl<ImportedModule> &imports,
|
||||||
ImportFilter filter = ImportFilterKind::Exported) const;
|
ImportFilter filter = ImportFilterKind::Exported) const;
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/None.h"
|
#include "llvm/ADT/None.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
@@ -98,6 +99,14 @@ public:
|
|||||||
return Storage == set.Storage;
|
return Storage == set.Storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if this option set contains any options from \p set.
|
||||||
|
///
|
||||||
|
/// \pre \p set must be non-empty.
|
||||||
|
bool containsAny(OptionSet set) const {
|
||||||
|
assert((bool)set && "argument must be non-empty");
|
||||||
|
return (bool)((*this) & set);
|
||||||
|
}
|
||||||
|
|
||||||
// '==' and '!=' are deliberately not defined because they provide a pitfall
|
// '==' and '!=' are deliberately not defined because they provide a pitfall
|
||||||
// where someone might use '==' but really want 'contains'. If you actually
|
// where someone might use '==' but really want 'contains'. If you actually
|
||||||
// want '==' behavior, use 'containsOnly'.
|
// want '==' behavior, use 'containsOnly'.
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ ImportSet &ImportCache::getImportSet(const DeclContext *dc) {
|
|||||||
ModuleDecl::ImportedModule{ImportPath::Access(), mod});
|
ModuleDecl::ImportedModule{ImportPath::Access(), mod});
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
|
// Should include both SPI & non-SPI.
|
||||||
file->getImportedModules(imports,
|
file->getImportedModules(imports,
|
||||||
{ModuleDecl::ImportFilterKind::Default,
|
{ModuleDecl::ImportFilterKind::Default,
|
||||||
ModuleDecl::ImportFilterKind::ImplementationOnly,
|
ModuleDecl::ImportFilterKind::ImplementationOnly,
|
||||||
@@ -260,6 +261,7 @@ ImportCache::getAllAccessPathsNotShadowedBy(const ModuleDecl *mod,
|
|||||||
ModuleDecl::ImportedModule{ImportPath::Access(), currentMod});
|
ModuleDecl::ImportedModule{ImportPath::Access(), currentMod});
|
||||||
|
|
||||||
if (auto *file = dyn_cast<FileUnit>(dc)) {
|
if (auto *file = dyn_cast<FileUnit>(dc)) {
|
||||||
|
// Should include both SPI & non-SPI
|
||||||
file->getImportedModules(stack,
|
file->getImportedModules(stack,
|
||||||
{ModuleDecl::ImportFilterKind::Default,
|
{ModuleDecl::ImportFilterKind::Default,
|
||||||
ModuleDecl::ImportFilterKind::ImplementationOnly,
|
ModuleDecl::ImportFilterKind::ImplementationOnly,
|
||||||
|
|||||||
@@ -1163,6 +1163,13 @@ void SourceFile::lookupPrecedenceGroupDirect(
|
|||||||
|
|
||||||
void ModuleDecl::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
|
void ModuleDecl::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
|
||||||
ModuleDecl::ImportFilter filter) const {
|
ModuleDecl::ImportFilter filter) const {
|
||||||
|
assert(filter.containsAny(ImportFilter({
|
||||||
|
ModuleDecl::ImportFilterKind::Exported,
|
||||||
|
ModuleDecl::ImportFilterKind::Default,
|
||||||
|
ModuleDecl::ImportFilterKind::ImplementationOnly}))
|
||||||
|
&& "filter should have at least one of Exported|Private|ImplementationOnly"
|
||||||
|
);
|
||||||
|
|
||||||
FORWARD(getImportedModules, (modules, filter));
|
FORWARD(getImportedModules, (modules, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1187,11 +1194,12 @@ SourceFile::getImportedModules(SmallVectorImpl<ModuleDecl::ImportedModule> &modu
|
|||||||
requiredFilter |= ModuleDecl::ImportFilterKind::Exported;
|
requiredFilter |= ModuleDecl::ImportFilterKind::Exported;
|
||||||
else if (desc.importOptions.contains(ImportFlags::ImplementationOnly))
|
else if (desc.importOptions.contains(ImportFlags::ImplementationOnly))
|
||||||
requiredFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
|
requiredFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
|
||||||
else if (desc.importOptions.contains(ImportFlags::SPIAccessControl))
|
|
||||||
requiredFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl;
|
|
||||||
else
|
else
|
||||||
requiredFilter |= ModuleDecl::ImportFilterKind::Default;
|
requiredFilter |= ModuleDecl::ImportFilterKind::Default;
|
||||||
|
|
||||||
|
if (desc.importOptions.contains(ImportFlags::SPIAccessControl))
|
||||||
|
requiredFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl;
|
||||||
|
|
||||||
if (!separatelyImportedOverlays.lookup(desc.module.importedModule).empty())
|
if (!separatelyImportedOverlays.lookup(desc.module.importedModule).empty())
|
||||||
requiredFilter |= ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay;
|
requiredFilter |= ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay;
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,8 @@ static void printImports(raw_ostream &out,
|
|||||||
|
|
||||||
SmallVector<ModuleDecl::ImportedModule, 4> ioiImport;
|
SmallVector<ModuleDecl::ImportedModule, 4> ioiImport;
|
||||||
M->getImportedModules(ioiImport,
|
M->getImportedModules(ioiImport,
|
||||||
ModuleDecl::ImportFilterKind::ImplementationOnly);
|
{ModuleDecl::ImportFilterKind::ImplementationOnly,
|
||||||
|
ModuleDecl::ImportFilterKind::SPIAccessControl});
|
||||||
ioiImportSet.insert(ioiImport.begin(), ioiImport.end());
|
ioiImportSet.insert(ioiImport.begin(), ioiImport.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1039,7 +1039,11 @@ void Serializer::writeInputBlock(const SerializationOptions &options) {
|
|||||||
ImportSet privateImportSet =
|
ImportSet privateImportSet =
|
||||||
getImportsAsSet(M, ModuleDecl::ImportFilterKind::Default);
|
getImportsAsSet(M, ModuleDecl::ImportFilterKind::Default);
|
||||||
ImportSet spiImportSet =
|
ImportSet spiImportSet =
|
||||||
getImportsAsSet(M, ModuleDecl::ImportFilterKind::SPIAccessControl);
|
getImportsAsSet(M, {
|
||||||
|
ModuleDecl::ImportFilterKind::Exported,
|
||||||
|
ModuleDecl::ImportFilterKind::Default,
|
||||||
|
ModuleDecl::ImportFilterKind::SPIAccessControl
|
||||||
|
});
|
||||||
|
|
||||||
auto clangImporter =
|
auto clangImporter =
|
||||||
static_cast<ClangImporter *>(M->getASTContext().getClangModuleLoader());
|
static_cast<ClangImporter *>(M->getASTContext().getClangModuleLoader());
|
||||||
|
|||||||
Reference in New Issue
Block a user