@@ -6187,7 +6187,65 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
61876187
61886188 auto loc = nameLoc.isValid () ? nameLoc.getStartLoc () : ::getLoc (anchor);
61896189 auto accessLevel = Member->getFormalAccessScope ().accessLevelForDiagnostics ();
6190- if (auto *CD = dyn_cast<ConstructorDecl>(Member)) {
6190+ bool suppressDeclHereNote = false ;
6191+ if (accessLevel == AccessLevel::Public &&
6192+ !Member->findImport (getDC ())) {
6193+ auto definingModule = Member->getDeclContext ()->getParentModule ();
6194+ emitDiagnosticAt (loc, diag::candidate_from_missing_import,
6195+ Member->getDescriptiveKind (), Member->getName (),
6196+ definingModule->getName ());
6197+
6198+ auto enclosingSF = getDC ()->getParentSourceFile ();
6199+ SourceLoc bestLoc;
6200+ SourceManager &srcMgr = Member->getASTContext ().SourceMgr ;
6201+ for (auto item : enclosingSF->getTopLevelItems ()) {
6202+ // If we found an import declaration, we want to insert after it.
6203+ if (auto importDecl =
6204+ dyn_cast_or_null<ImportDecl>(item.dyn_cast <Decl *>())) {
6205+ SourceLoc loc = importDecl->getEndLoc ();
6206+ if (loc.isValid ()) {
6207+ bestLoc = Lexer::getLocForEndOfLine (srcMgr, loc);
6208+ }
6209+
6210+ // Keep looking for more import declarations.
6211+ continue ;
6212+ }
6213+
6214+ // If we got a location based on import declarations, we're done.
6215+ if (bestLoc.isValid ())
6216+ break ;
6217+
6218+ // For any other item, we want to insert before it.
6219+ SourceLoc loc = item.getStartLoc ();
6220+ if (loc.isValid ()) {
6221+ bestLoc = Lexer::getLocForStartOfLine (srcMgr, loc);
6222+ break ;
6223+ }
6224+ }
6225+
6226+ if (bestLoc.isValid ()) {
6227+ llvm::SmallString<64 > importText;
6228+
6229+ // @_spi imports.
6230+ if (Member->isSPI ()) {
6231+ auto spiGroups = Member->getSPIGroups ();
6232+ if (!spiGroups.empty ()) {
6233+ importText += " @_spi(" ;
6234+ importText += spiGroups[0 ].str ();
6235+ importText += " ) " ;
6236+ }
6237+ }
6238+
6239+ importText += " import " ;
6240+ importText += definingModule->getName ().str ();
6241+ importText += " \n " ;
6242+ emitDiagnosticAt (bestLoc, diag::candidate_add_import,
6243+ definingModule->getName ())
6244+ .fixItInsert (bestLoc, importText);
6245+ }
6246+
6247+ suppressDeclHereNote = true ;
6248+ } else if (auto *CD = dyn_cast<ConstructorDecl>(Member)) {
61916249 emitDiagnosticAt (loc, diag::init_candidate_inaccessible,
61926250 CD->getResultInterfaceType (), accessLevel)
61936251 .highlight (nameLoc.getSourceRange ());
@@ -6197,7 +6255,8 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
61976255 .highlight (nameLoc.getSourceRange ());
61986256 }
61996257
6200- emitDiagnosticAt (Member, diag::decl_declared_here, Member);
6258+ if (!suppressDeclHereNote)
6259+ emitDiagnosticAt (Member, diag::decl_declared_here, Member);
62016260 return true ;
62026261}
62036262
0 commit comments