@@ -2702,6 +2702,15 @@ bool SourceFile::hasImportsWithFlag(ImportFlags flag) const {
27022702 ctx.evaluator , HasImportsMatchingFlagRequest{mutableThis, flag}, false );
27032703}
27042704
2705+ ImportFlags SourceFile::getImportFlags (const ModuleDecl *module ) const {
2706+ unsigned flags = 0x0 ;
2707+ for (auto import : *Imports) {
2708+ if (import .module .importedModule == module )
2709+ flags |= import .options .toRaw ();
2710+ }
2711+ return ImportFlags (flags);
2712+ }
2713+
27052714bool SourceFile::hasTestableOrPrivateImport (
27062715 AccessLevel accessLevel, const swift::ValueDecl *ofDecl,
27072716 SourceFile::ImportQueryKind queryKind) const {
@@ -4001,3 +4010,62 @@ version::Version ModuleDecl::getLanguageVersionBuiltWith() const {
40014010
40024011 return version::Version ();
40034012}
4013+
4014+ bool swift::diagnoseMissingImportForMember (const ValueDecl *decl,
4015+ const DeclContext *dc,
4016+ SourceLoc loc) {
4017+ if (decl->findImport (dc))
4018+ return false ;
4019+
4020+ auto &ctx = dc->getASTContext ();
4021+ auto definingModule = decl->getModuleContext ();
4022+ ctx.Diags .diagnose (loc, diag::candidate_from_missing_import,
4023+ decl->getDescriptiveKind (), decl->getName (),
4024+ definingModule);
4025+
4026+ SourceLoc bestLoc =
4027+ ctx.Diags .getBestAddImportFixItLoc (decl, dc->getParentSourceFile ());
4028+ if (!bestLoc.isValid ())
4029+ return false ;
4030+
4031+ llvm::SmallString<64 > importText;
4032+
4033+ // Check other source files for import flags that should be applied to the
4034+ // fix-it for consistency with the rest of the imports in the module.
4035+ auto parentModule = dc->getParentModule ();
4036+ OptionSet<ImportFlags> flags;
4037+ for (auto file : parentModule->getFiles ()) {
4038+ if (auto sf = dyn_cast<SourceFile>(file))
4039+ flags |= sf->getImportFlags (definingModule);
4040+ }
4041+
4042+ if (flags.contains (ImportFlags::Exported) ||
4043+ parentModule->isClangOverlayOf (definingModule))
4044+ importText += " @_exported " ;
4045+ if (flags.contains (ImportFlags::ImplementationOnly))
4046+ importText += " @_implementationOnly " ;
4047+ if (flags.contains (ImportFlags::WeakLinked))
4048+ importText += " @_weakLinked " ;
4049+ if (flags.contains (ImportFlags::SPIOnly))
4050+ importText += " @_spiOnly " ;
4051+
4052+ // FIXME: Access level should be considered, too.
4053+
4054+ // @_spi imports.
4055+ if (decl->isSPI ()) {
4056+ auto spiGroups = decl->getSPIGroups ();
4057+ if (!spiGroups.empty ()) {
4058+ importText += " @_spi(" ;
4059+ importText += spiGroups[0 ].str ();
4060+ importText += " ) " ;
4061+ }
4062+ }
4063+
4064+ importText += " import " ;
4065+ importText += definingModule->getName ().str ();
4066+ importText += " \n " ;
4067+ ctx.Diags .diagnose (bestLoc, diag::candidate_add_import, definingModule)
4068+ .fixItInsert (bestLoc, importText);
4069+
4070+ return true ;
4071+ }
0 commit comments