Skip to content

Commit fa88348

Browse files
committed
Only emit error about missing import when we're missing the import
This eliminates some diagnostics that incorrectly refer to a missin `@_spi` import as an outright missing import, which is incorrect. The one test case changed here really is a case of a missing import that happens to be SPI.
1 parent cff9184 commit fa88348

File tree

2 files changed

+48
-36
lines changed

2 files changed

+48
-36
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6164,49 +6164,60 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
61646164
auto loc = nameLoc.isValid() ? nameLoc.getStartLoc() : ::getLoc(anchor);
61656165
auto accessLevel = Member->getFormalAccessScope().accessLevelForDiagnostics();
61666166
bool suppressDeclHereNote = false;
6167-
if (accessLevel == AccessLevel::Public) {
6167+
if (accessLevel == AccessLevel::Public &&
6168+
!Member->findImport(getDC())) {
61686169
auto definingModule = Member->getDeclContext()->getParentModule();
61696170
emitDiagnosticAt(loc, diag::candidate_from_missing_import,
61706171
Member->getDescriptiveKind(), Member->getName(),
61716172
definingModule->getName());
61726173

6173-
if (auto enclosingSF = getDC()->getParentSourceFile()) {
6174-
SourceLoc bestLoc;
6175-
SourceManager &srcMgr = Member->getASTContext().SourceMgr;
6176-
for (auto item : enclosingSF->getTopLevelItems()) {
6177-
// If we found an import declaration, we want to insert after it.
6178-
if (auto importDecl =
6179-
dyn_cast_or_null<ImportDecl>(item.dyn_cast<Decl *>())) {
6180-
SourceLoc loc = importDecl->getEndLoc();
6181-
if (loc.isValid()) {
6182-
bestLoc = Lexer::getLocForEndOfLine(srcMgr, loc);
6183-
}
6184-
6185-
// Keep looking for more import declarations.
6186-
continue;
6187-
}
6188-
6189-
// If we got a location based on import declarations, we're done.
6190-
if (bestLoc.isValid())
6191-
break;
6192-
6193-
// For any other item, we want to insert before it.
6194-
SourceLoc loc = item.getStartLoc();
6174+
auto enclosingSF = getDC()->getParentSourceFile();
6175+
SourceLoc bestLoc;
6176+
SourceManager &srcMgr = Member->getASTContext().SourceMgr;
6177+
for (auto item : enclosingSF->getTopLevelItems()) {
6178+
// If we found an import declaration, we want to insert after it.
6179+
if (auto importDecl =
6180+
dyn_cast_or_null<ImportDecl>(item.dyn_cast<Decl *>())) {
6181+
SourceLoc loc = importDecl->getEndLoc();
61956182
if (loc.isValid()) {
6196-
bestLoc = Lexer::getLocForStartOfLine(srcMgr, loc);
6197-
break;
6183+
bestLoc = Lexer::getLocForEndOfLine(srcMgr, loc);
61986184
}
6185+
6186+
// Keep looking for more import declarations.
6187+
continue;
6188+
}
6189+
6190+
// If we got a location based on import declarations, we're done.
6191+
if (bestLoc.isValid())
6192+
break;
6193+
6194+
// For any other item, we want to insert before it.
6195+
SourceLoc loc = item.getStartLoc();
6196+
if (loc.isValid()) {
6197+
bestLoc = Lexer::getLocForStartOfLine(srcMgr, loc);
6198+
break;
61996199
}
6200+
}
6201+
6202+
if (bestLoc.isValid()) {
6203+
llvm::SmallString<64> importText;
62006204

6201-
if (bestLoc.isValid()) {
6202-
llvm::SmallString<64> importText;
6203-
importText += "import ";
6204-
importText += definingModule->getName().str();
6205-
importText += "\n";
6206-
emitDiagnosticAt(bestLoc, diag::candidate_add_import,
6207-
definingModule->getName())
6208-
.fixItInsert(bestLoc, importText);
6205+
// @_spi imports.
6206+
if (Member->isSPI()) {
6207+
auto spiGroups = Member->getSPIGroups();
6208+
if (!spiGroups.empty()) {
6209+
importText += "@_spi(";
6210+
importText += spiGroups[0].str();
6211+
importText += ") ";
6212+
}
62096213
}
6214+
6215+
importText += "import ";
6216+
importText += definingModule->getName().str();
6217+
importText += "\n";
6218+
emitDiagnosticAt(bestLoc, diag::candidate_add_import,
6219+
definingModule->getName())
6220+
.fixItInsert(bestLoc, importText);
62106221
}
62116222

62126223
suppressDeclHereNote = true;
@@ -6220,7 +6231,8 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
62206231
.highlight(nameLoc.getSourceRange());
62216232
}
62226233

6223-
emitDiagnosticAt(Member, diag::decl_declared_here, Member);
6234+
if (!suppressDeclHereNote)
6235+
emitDiagnosticAt(Member, diag::decl_declared_here, Member);
62246236
return true;
62256237
}
62266238

test/SPI/client_reuse_spi.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -DLIB_C %s -I %t
77

88
#if LIB_A
9-
9+
// expected-note@-1{{add import of module 'A'}}{{1-1=@_spi(A) import A\n}}
1010
@_spi(A) public struct SecretStruct {
1111
@_spi(A) public func bar() {}
1212
}
@@ -22,7 +22,7 @@
2222
@_spi(B) import B
2323

2424
var a = foo() // OK
25-
a.bar() // expected-error{{'bar' is inaccessible due to '@_spi' protection level}}
25+
a.bar() // expected-error{{instance method 'bar()' is not available due to missing import of defining module 'A'}}
2626

2727
var b = SecretStruct() // expected-error{{cannot find 'SecretStruct' in scope}}
2828

0 commit comments

Comments
 (0)