Skip to content

Commit d433919

Browse files
authored
Merge pull request #75694 from tshortli/member-import-visibility-import-access-level
Sema: Add an access level to the fix-its for missing imports when appropriate
2 parents eea22c2 + 3ef1600 commit d433919

15 files changed

+344
-94
lines changed

include/swift/AST/FileUnit.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,8 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
273273
ModuleDecl::ImportFilter filter) const {}
274274

275275
/// Lists modules that are not imported from this file and used in API.
276-
virtual void
277-
getMissingImportedModules(SmallVectorImpl<ImportedModule> &imports) const {}
276+
virtual void getImplicitImportsForModuleInterface(
277+
SmallVectorImpl<ImportedModule> &imports) const {}
278278

279279
/// \see ModuleDecl::getImportedModulesForLookup
280280
virtual void getImportedModulesForLookup(

include/swift/AST/Module.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,8 +1034,8 @@ class ModuleDecl
10341034
ImportFilter filter = ImportFilterKind::Exported) const;
10351035

10361036
/// Lists modules that are not imported from a file and used in API.
1037-
void
1038-
getMissingImportedModules(SmallVectorImpl<ImportedModule> &imports) const;
1037+
void getImplicitImportsForModuleInterface(
1038+
SmallVectorImpl<ImportedModule> &imports) const;
10391039

10401040
/// Looks up which modules are imported by this module, ignoring any that
10411041
/// won't contain top-level decls.
@@ -1319,11 +1319,6 @@ inline SourceLoc extractNearestSourceLoc(const ModuleDecl *mod) {
13191319
return extractNearestSourceLoc(static_cast<const Decl *>(mod));
13201320
}
13211321

1322-
/// If the import that would make the given declaration visibile is absent,
1323-
/// emit a diagnostic and a fix-it suggesting adding the missing import.
1324-
bool diagnoseMissingImportForMember(const ValueDecl *decl,
1325-
const DeclContext *dc, SourceLoc loc);
1326-
13271322
} // end namespace swift
13281323

13291324
#endif

include/swift/AST/SourceFile.h

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ class SourceFile final : public FileUnit {
159159
/// The highest access level of declarations referencing each import.
160160
llvm::DenseMap<const ModuleDecl *, AccessLevel> ImportsUseAccessLevel;
161161

162+
/// Imports that should be printed in the module interface even though they
163+
/// were not written in the source file.
164+
llvm::SmallDenseSet<ImportedModule> ImplicitImportsForModuleInterface;
165+
166+
/// Associates a list of source locations to the member declarations that must
167+
/// be diagnosed as being out of scope due to a missing import.
168+
using DelayedMissingImportForMemberDiags =
169+
llvm::SmallDenseMap<const ValueDecl *, std::vector<SourceLoc>>;
170+
DelayedMissingImportForMemberDiags MissingImportForMemberDiagnostics;
171+
162172
/// A unique identifier representing this file; used to mark private decls
163173
/// within the file to keep them from conflicting with other files in the
164174
/// same module.
@@ -463,8 +473,11 @@ class SourceFile final : public FileUnit {
463473
/// If not, we can fast-path module checks.
464474
bool hasImportsWithFlag(ImportFlags flag) const;
465475

466-
/// Returns the import flags that are active on imports of \p module.
467-
ImportFlags getImportFlags(const ModuleDecl *module) const;
476+
/// Enumerates each of the direct imports of \p module in the file.
477+
using AttributedImportCallback =
478+
llvm::function_ref<void(AttributedImport<ImportedModule> &)>;
479+
void forEachImportOfModule(const ModuleDecl *module,
480+
AttributedImportCallback callback);
468481

469482
/// Get the most permissive restriction applied to the imports of \p module.
470483
RestrictedImportKind getRestrictedImportKind(const ModuleDecl *module) const;
@@ -510,10 +523,32 @@ class SourceFile final : public FileUnit {
510523

511524
SWIFT_DEBUG_DUMPER(dumpSeparatelyImportedOverlays());
512525

513-
llvm::SmallDenseSet<ImportedModule> MissingImportedModules;
526+
/// Record an import that should be printed in the module interface even
527+
/// though it was not written in the source file. These imports are needed in
528+
/// Swift 5 mode to preserve the integrity of swiftinterface files when code
529+
/// publicly use declarations from modules that were \c `@_implementationOnly`
530+
/// imported in other source files.
531+
void addImplicitImportForModuleInterface(ImportedModule module) {
532+
ImplicitImportsForModuleInterface.insert(module);
533+
}
534+
535+
/// Gather implicit imports that should printed in swiftinterfaces for
536+
/// compatibility with code in some Swift 5 modules.
537+
void getImplicitImportsForModuleInterface(
538+
SmallVectorImpl<ImportedModule> &imports) const override;
514539

515-
void addMissingImportedModule(ImportedModule module) const {
516-
const_cast<SourceFile *>(this)->MissingImportedModules.insert(module);
540+
/// Add a source location for which a delayed missing import for member
541+
/// diagnostic should be emited.
542+
void addDelayedMissingImportForMemberDiagnostic(const ValueDecl *decl,
543+
SourceLoc loc) {
544+
MissingImportForMemberDiagnostics[decl].push_back(loc);
545+
}
546+
547+
DelayedMissingImportForMemberDiags
548+
takeDelayedMissingImportForMemberDiagnostics() {
549+
DelayedMissingImportForMemberDiags diags;
550+
std::swap(diags, MissingImportForMemberDiagnostics);
551+
return diags;
517552
}
518553

519554
/// Record the source range info for a parsed \c #if clause.
@@ -527,10 +562,10 @@ class SourceFile final : public FileUnit {
527562
ArrayRef<IfConfigClauseRangeInfo>
528563
getIfConfigClausesWithin(SourceRange outer) const;
529564

530-
void getMissingImportedModules(
531-
SmallVectorImpl<ImportedModule> &imports) const override;
532-
565+
/// Record visible declarations for use in code completion and refactoring.
533566
void cacheVisibleDecls(SmallVectorImpl<ValueDecl *> &&globals) const;
567+
568+
/// Retrieve visible declarations for use in code completion and refactoring.
534569
const SmallVectorImpl<ValueDecl *> &getCachedVisibleDecls() const;
535570

536571
virtual void lookupValue(DeclName name, NLKind lookupKind,

lib/AST/Module.cpp

Lines changed: 8 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,9 +1720,9 @@ void ModuleDecl::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
17201720
FORWARD(getImportedModules, (modules, filter));
17211721
}
17221722

1723-
void ModuleDecl::getMissingImportedModules(
1723+
void ModuleDecl::getImplicitImportsForModuleInterface(
17241724
SmallVectorImpl<ImportedModule> &imports) const {
1725-
FORWARD(getMissingImportedModules, (imports));
1725+
FORWARD(getImplicitImportsForModuleInterface, (imports));
17261726
}
17271727

17281728
const llvm::DenseMap<const clang::Module *, ModuleDecl *> &
@@ -1811,9 +1811,9 @@ SourceFile::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
18111811
}
18121812
}
18131813

1814-
void SourceFile::getMissingImportedModules(
1814+
void SourceFile::getImplicitImportsForModuleInterface(
18151815
SmallVectorImpl<ImportedModule> &modules) const {
1816-
for (auto module : MissingImportedModules)
1816+
for (auto module : ImplicitImportsForModuleInterface)
18171817
modules.push_back(module);
18181818
}
18191819

@@ -2817,13 +2817,13 @@ bool SourceFile::hasImportsWithFlag(ImportFlags flag) const {
28172817
ctx.evaluator, HasImportsMatchingFlagRequest{mutableThis, flag}, false);
28182818
}
28192819

2820-
ImportFlags SourceFile::getImportFlags(const ModuleDecl *module) const {
2821-
unsigned flags = 0x0;
2820+
void SourceFile::forEachImportOfModule(
2821+
const ModuleDecl *module,
2822+
llvm::function_ref<void(AttributedImport<ImportedModule> &)> callback) {
28222823
for (auto import : *Imports) {
28232824
if (import.module.importedModule == module)
2824-
flags |= import.options.toRaw();
2825+
callback(import);
28252826
}
2826-
return ImportFlags(flags);
28272827
}
28282828

28292829
bool SourceFile::hasTestableOrPrivateImport(
@@ -4093,62 +4093,3 @@ version::Version ModuleDecl::getLanguageVersionBuiltWith() const {
40934093

40944094
return version::Version();
40954095
}
4096-
4097-
bool swift::diagnoseMissingImportForMember(const ValueDecl *decl,
4098-
const DeclContext *dc,
4099-
SourceLoc loc) {
4100-
if (decl->findImport(dc))
4101-
return false;
4102-
4103-
auto &ctx = dc->getASTContext();
4104-
auto definingModule = decl->getModuleContext();
4105-
ctx.Diags.diagnose(loc, diag::candidate_from_missing_import,
4106-
decl->getDescriptiveKind(), decl->getName(),
4107-
definingModule);
4108-
4109-
SourceLoc bestLoc =
4110-
ctx.Diags.getBestAddImportFixItLoc(decl, dc->getParentSourceFile());
4111-
if (!bestLoc.isValid())
4112-
return false;
4113-
4114-
llvm::SmallString<64> importText;
4115-
4116-
// Check other source files for import flags that should be applied to the
4117-
// fix-it for consistency with the rest of the imports in the module.
4118-
auto parentModule = dc->getParentModule();
4119-
OptionSet<ImportFlags> flags;
4120-
for (auto file : parentModule->getFiles()) {
4121-
if (auto sf = dyn_cast<SourceFile>(file))
4122-
flags |= sf->getImportFlags(definingModule);
4123-
}
4124-
4125-
if (flags.contains(ImportFlags::Exported) ||
4126-
parentModule->isClangOverlayOf(definingModule))
4127-
importText += "@_exported ";
4128-
if (flags.contains(ImportFlags::ImplementationOnly))
4129-
importText += "@_implementationOnly ";
4130-
if (flags.contains(ImportFlags::WeakLinked))
4131-
importText += "@_weakLinked ";
4132-
if (flags.contains(ImportFlags::SPIOnly))
4133-
importText += "@_spiOnly ";
4134-
4135-
// FIXME: Access level should be considered, too.
4136-
4137-
// @_spi imports.
4138-
if (decl->isSPI()) {
4139-
auto spiGroups = decl->getSPIGroups();
4140-
if (!spiGroups.empty()) {
4141-
importText += "@_spi(";
4142-
importText += spiGroups[0].str();
4143-
importText += ") ";
4144-
}
4145-
}
4146-
4147-
importText += "import ";
4148-
importText += definingModule->getName().str();
4149-
importText += "\n";
4150-
ctx.Diags.diagnose(bestLoc, diag::candidate_add_import, definingModule)
4151-
.fixItInsert(bestLoc, importText);
4152-
4153-
return true;
4154-
}

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static void printToolVersionAndFlagsComment(raw_ostream &out,
8787

8888
SmallVector<ImportedModule> imports;
8989
M->getImportedModules(imports, filter);
90-
M->getMissingImportedModules(imports);
90+
M->getImplicitImportsForModuleInterface(imports);
9191

9292
for (ImportedModule import: imports) {
9393
StringRef importedName = import.importedModule->getNameStr();
@@ -338,7 +338,7 @@ static void printImports(raw_ostream &out,
338338
M->getImportedModules(allImports, allImportFilter);
339339

340340
if (Opts.PrintMissingImports)
341-
M->getMissingImportedModules(allImports);
341+
M->getImplicitImportsForModuleInterface(allImports);
342342

343343
ImportedModule::removeDuplicates(allImports);
344344
diagnoseScopedImports(ctx.Diags, allImports);

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6188,7 +6188,7 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
61886188

61896189
auto loc = nameLoc.isValid() ? nameLoc.getStartLoc() : ::getLoc(anchor);
61906190
if (IsMissingImport) {
6191-
diagnoseMissingImportForMember(Member, getDC(), loc);
6191+
maybeDiagnoseMissingImportForMember(Member, getDC(), loc);
61926192
return true;
61936193
}
61946194

lib/Sema/PreCheckExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
629629
TypeChecker::lookupUnqualified(DC, LookupName, Loc, relookupOptions);
630630
if (nonImportedResults) {
631631
const ValueDecl *first = nonImportedResults.front().getValueDecl();
632-
diagnoseMissingImportForMember(first, DC, Loc);
632+
maybeDiagnoseMissingImportForMember(first, DC, Loc);
633633

634634
// Don't try to recover here; we'll get more access-related diagnostics
635635
// downstream if the type of the inaccessible decl is also inaccessible.

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static bool addMissingImport(SourceLoc loc, const Decl *D,
4545
// API.
4646
auto missingImport = ImportedModule(ImportPath::Access(),
4747
const_cast<ModuleDecl *>(M));
48-
SF->addMissingImportedModule(missingImport);
48+
SF->addImplicitImportForModuleInterface(missingImport);
4949
ctx.Diags.diagnose(loc, diag::missing_import_inserted, M->getName());
5050
return true;
5151
}

0 commit comments

Comments
 (0)