Skip to content

Commit a1b6469

Browse files
Merge pull request #38989 from mininny/improve-open-extension-diagnostic
[Diagnostics] Improve diagnostics on invalid open extensions
2 parents 404badb + 0b48569 commit a1b6469

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,7 @@ ERROR(access_control_extension_more,none,
14961496
"be declared %select{%error|fileprivate|internal|public|%error}2",
14971497
(AccessLevel, DescriptiveDeclKind, AccessLevel))
14981498
ERROR(access_control_extension_open,none,
1499-
"extensions cannot use 'open' as their default access; use 'public'",
1499+
"extensions cannot be declared 'open'; declare individual members as 'open' instead",
15001500
())
15011501
ERROR(access_control_open_bad_decl,none,
15021502
"only classes and overridable class members can be declared 'open';"

lib/Sema/TypeCheckAttr.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,8 +737,25 @@ void AttributeChecker::visitAccessControlAttr(AccessControlAttr *attr) {
737737

738738
if (auto extension = dyn_cast<ExtensionDecl>(D)) {
739739
if (attr->getAccess() == AccessLevel::Open) {
740-
diagnose(attr->getLocation(), diag::access_control_extension_open)
741-
.fixItReplace(attr->getRange(), "public");
740+
auto diag =
741+
diagnose(attr->getLocation(), diag::access_control_extension_open);
742+
diag.fixItRemove(attr->getRange());
743+
for (auto Member : extension->getMembers()) {
744+
if (auto *VD = dyn_cast<ValueDecl>(Member)) {
745+
if (VD->getAttrs().hasAttribute<AccessControlAttr>())
746+
continue;
747+
748+
StringRef accessLevel = VD->isObjC() ? "open " : "public ";
749+
750+
if (auto *FD = dyn_cast<FuncDecl>(VD))
751+
diag.fixItInsert(FD->getFuncLoc(), accessLevel);
752+
753+
if (auto *VAD = dyn_cast<VarDecl>(VD))
754+
diag.fixItInsert(VAD->getParentPatternBinding()->getLoc(),
755+
accessLevel);
756+
}
757+
}
758+
742759
attr->setInvalid();
743760
return;
744761
}

test/attr/open.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,12 @@ open class OpenSubClass : OpenSuperClass {
134134
open override subscript(index: MarkerForNonOpenSubscripts) -> Int { return 0 }
135135

136136
}
137+
138+
class InvalidOpenExtensionClass { }
139+
140+
open extension InvalidOpenExtensionClass { // expected-error {{extensions cannot be declared 'open'; declare individual members as 'open' instead}} {{1-6=}} {{3-3=public }} {{3-3=public }}
141+
func C() { } // Insert public
142+
private func A() { } // OK
143+
var F: Int { 3 } // Insert public
144+
private var G: Int { 3 } // Okay
145+
}

test/attr/open_objc.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-typecheck-verify-swift -sdk %clang-importer-sdk -I %t
3+
// REQUIRES: objc_interop
4+
5+
import Foundation
6+
7+
class InvalidOpenExtensionClass { }
8+
9+
open extension InvalidOpenExtensionClass { // expected-error {{extensions cannot be declared 'open'; declare individual members as 'open' instead}} {{1-6=}} {{3-3=public }} {{9-9=open }} {{9-9=open }} {{3-3=public }}
10+
private func A() { } // OK
11+
@objc func B() { } // Insert open
12+
func C() { } // Insert public
13+
@objc private var D: Int { 3 } // Okay
14+
@objc var E: Int { 3 } // Insert open
15+
var F: Int { 3 } // Insert public
16+
private var G: Int { 3 } // Okay
17+
}
18+
19+
@objc
20+
@objcMembers
21+
class InvalidOpenExtensionObjcClass: NSObject { }
22+
23+
open extension InvalidOpenExtensionObjcClass { // expected-error {{extensions cannot be declared 'open'; declare individual members as 'open' instead}} {{1-6=}} {{3-3=open }} {{9-9=open }} {{9-9=open }} {{3-3=open }}
24+
private func A() { } // OK
25+
@objc func B() { } // Insert open
26+
func C() { } // Insert open
27+
@objc private var D: Int { 3 } // Okay
28+
@objc var E: Int { 3 } // Insert open
29+
var F: Int { 3 } // Insert open
30+
private var G: Int { 3 } // Okay
31+
}

0 commit comments

Comments
 (0)