Skip to content

Commit 866880f

Browse files
committed
Soften ObjC selector conflicts from access notes
1 parent 1c2c111 commit 866880f

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5018,10 +5018,11 @@ NOTE(objc_declared_here,none,
50185018
OBJC_DIAG_SELECT " declared here",
50195019
(unsigned, DeclName))
50205020

5021+
// %2 and %3 are unused to make signature match with diag::objc_redecl.
50215022
ERROR(objc_redecl_same,none,
5022-
OBJC_DIAG_SELECT " with Objective-C selector %2 conflicts with "
5023+
OBJC_DIAG_SELECT " with Objective-C selector %4 conflicts with "
50235024
"previous declaration with the same Objective-C selector",
5024-
(unsigned, DeclName, ObjCSelector))
5025+
(unsigned, DeclName, unsigned, DeclName, ObjCSelector))
50255026

50265027
ERROR(objc_override_other,none,
50275028
OBJC_DIAG_SELECT " with Objective-C selector %4 conflicts with "

include/swift/AST/SourceFile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ class SourceFile final : public FileUnit {
241241
/// unsatisfied, which might conflict with other Objective-C methods.
242242
std::vector<ObjCUnsatisfiedOptReq> ObjCUnsatisfiedOptReqs;
243243

244+
/// A selector that is used by two different declarations in the same class.
245+
/// Fields: classDecl, selector, isInstanceMethod.
244246
using ObjCMethodConflict = std::tuple<ClassDecl *, ObjCSelector, bool>;
245247

246248
/// List of Objective-C member conflicts we have found during type checking.

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,17 @@ getObjCMethodConflictDecls(const SourceFile::ObjCMethodConflict &conflict) {
24112411
return classDecl->lookupDirect(selector, isInstanceMethod);
24122412
}
24132413

2414+
static ObjCAttr *getObjCAttrIfFromAccessNote(ValueDecl *VD) {
2415+
if (auto objc = VD->getAttrs().getAttribute<ObjCAttr>())
2416+
if (objc->getAddedByAccessNote())
2417+
return objc;
2418+
2419+
if (auto accessor = dyn_cast<AccessorDecl>(VD))
2420+
return getObjCAttrIfFromAccessNote(accessor->getStorage());
2421+
2422+
return nullptr;
2423+
}
2424+
24142425
bool swift::diagnoseObjCMethodConflicts(SourceFile &sf) {
24152426
// If there were no conflicts, we're done.
24162427
if (sf.ObjCMethodConflicts.empty())
@@ -2473,6 +2484,10 @@ bool swift::diagnoseObjCMethodConflicts(SourceFile &sf) {
24732484
return false; \
24742485
} while (0)
24752486

2487+
// Is one of these from an access note?
2488+
RULE(getObjCAttrIfFromAccessNote(a),
2489+
getObjCAttrIfFromAccessNote(b));
2490+
24762491
// Is one of these from the main declaration?
24772492
RULE(!isa<ExtensionDecl>(a->getDeclContext()),
24782493
!isa<ExtensionDecl>(b->getDeclContext()));
@@ -2505,18 +2520,25 @@ bool swift::diagnoseObjCMethodConflicts(SourceFile &sf) {
25052520
if (auto accessor = dyn_cast<AccessorDecl>(originalMethod))
25062521
originalDecl = accessor->getStorage();
25072522

2508-
if (diagInfo == origDiagInfo) {
2509-
Ctx.Diags.diagnose(conflictingDecl, diag::objc_redecl_same,
2510-
diagInfo.first, diagInfo.second, selector);
2523+
bool redeclSame = (diagInfo == origDiagInfo);
2524+
auto diag = Ctx.Diags.diagnose(conflictingDecl,
2525+
redeclSame ? diag::objc_redecl_same
2526+
: diag::objc_redecl,
2527+
diagInfo.first, diagInfo.second,
2528+
origDiagInfo.first, origDiagInfo.second,
2529+
selector);
2530+
2531+
auto objcAttr = getObjCAttrIfFromAccessNote(conflictingDecl);
2532+
swift::softenIfAccessNote(conflictingDecl, objcAttr, diag);
2533+
if (objcAttr)
2534+
objcAttr->setInvalid();
2535+
2536+
if (redeclSame)
25112537
Ctx.Diags.diagnose(originalDecl, diag::invalid_redecl_prev,
25122538
originalDecl->getBaseName());
2513-
} else {
2514-
Ctx.Diags.diagnose(conflictingDecl, diag::objc_redecl, diagInfo.first,
2515-
diagInfo.second, origDiagInfo.first,
2516-
origDiagInfo.second, selector);
2539+
else
25172540
Ctx.Diags.diagnose(originalDecl, diag::objc_declared_here,
25182541
origDiagInfo.first, origDiagInfo.second);
2519-
}
25202542
}
25212543
}
25222544

test/attr/attr_objc.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,33 +2366,33 @@ class SubclassImplicitClassThrows1 : ImplicitClassThrows1 {
23662366
class ThrowsRedecl1 {
23672367
@objc // access-note-move{{ThrowsRedecl1.method1(_:error:)}}
23682368
func method1(_ x: Int, error: Class_ObjC1) { } // expected-note{{declared here}}
2369-
@objc // access-note-move{{ThrowsRedecl1.method1(_:)}}
2370-
func method1(_ x: Int) throws { } // expected-error {{with Objective-C selector 'method1:error:'}}
2369+
@objc // bad-access-note-move{{ThrowsRedecl1.method1(_:)}}
2370+
func method1(_ x: Int) throws { } // access-note-adjust{{@objc}} expected-error {{method 'method1' with Objective-C selector 'method1:error:' conflicts with method 'method1(_:error:)' with the same Objective-C selector}}
23712371

23722372
@objc // access-note-move{{ThrowsRedecl1.method2AndReturnError(_:)}}
23732373
func method2AndReturnError(_ x: Int) { } // expected-note{{declared here}}
2374-
@objc // access-note-move{{ThrowsRedecl1.method2()}}
2375-
func method2() throws { } // expected-error {{with Objective-C selector 'method2AndReturnError:'}}
2374+
@objc // bad-access-note-move{{ThrowsRedecl1.method2()}}
2375+
func method2() throws { } // access-note-adjust{{@objc}} expected-error {{method 'method2()' with Objective-C selector 'method2AndReturnError:' conflicts with method 'method2AndReturnError' with the same Objective-C selector}}
23762376

23772377
@objc // access-note-move{{ThrowsRedecl1.method3(_:error:closure:)}}
23782378
func method3(_ x: Int, error: Int, closure: @escaping (Int) -> Int) { } // expected-note{{declared here}}
2379-
@objc // access-note-move{{ThrowsRedecl1.method3(_:closure:)}}
2380-
func method3(_ x: Int, closure: (Int) -> Int) throws { } // expected-error {{with Objective-C selector 'method3:error:closure:'}}
2379+
@objc // bad-access-note-move{{ThrowsRedecl1.method3(_:closure:)}}
2380+
func method3(_ x: Int, closure: (Int) -> Int) throws { } // access-note-adjust{{@objc}} expected-error {{method 'method3(_:closure:)' with Objective-C selector 'method3:error:closure:' conflicts with method 'method3(_:error:closure:)' with the same Objective-C selector}}
23812381

23822382
@objc(initAndReturnError:) // access-note-move{{ThrowsRedecl1.initMethod1(error:)}}
23832383
func initMethod1(error: Int) { } // expected-note{{declared here}}
2384-
@objc // access-note-move{{ThrowsRedecl1.init()}}
2385-
init() throws { } // expected-error {{with Objective-C selector 'initAndReturnError:'}}
2384+
@objc // bad-access-note-move{{ThrowsRedecl1.init()}}
2385+
init() throws { } // access-note-adjust{{@objc}} expected-error {{initializer 'init()' with Objective-C selector 'initAndReturnError:' conflicts with method 'initMethod1(error:)' with the same Objective-C selector}}
23862386

23872387
@objc(initWithString:error:) // access-note-move{{ThrowsRedecl1.initMethod2(string:error:)}}
23882388
func initMethod2(string: String, error: Int) { } // expected-note{{declared here}}
2389-
@objc // access-note-move{{ThrowsRedecl1.init(string:)}}
2390-
init(string: String) throws { } // expected-error {{with Objective-C selector 'initWithString:error:'}}
2389+
@objc // bad-access-note-move{{ThrowsRedecl1.init(string:)}}
2390+
init(string: String) throws { } // access-note-adjust{{@objc}} expected-error {{initializer 'init(string:)' with Objective-C selector 'initWithString:error:' conflicts with method 'initMethod2(string:error:)' with the same Objective-C selector}}
23912391

23922392
@objc(initAndReturnError:fn:) // access-note-move{{ThrowsRedecl1.initMethod3(error:fn:)}}
23932393
func initMethod3(error: Int, fn: @escaping (Int) -> Int) { } // expected-note{{declared here}}
2394-
@objc // access-note-move{{ThrowsRedecl1.init(fn:)}}
2395-
init(fn: (Int) -> Int) throws { } // expected-error {{with Objective-C selector 'initAndReturnError:fn:'}}
2394+
@objc // bad-access-note-move{{ThrowsRedecl1.init(fn:)}}
2395+
init(fn: (Int) -> Int) throws { } // access-note-adjust{{@objc}} expected-error {{initializer 'init(fn:)' with Objective-C selector 'initAndReturnError:fn:' conflicts with method 'initMethod3(error:fn:)' with the same Objective-C selector}}
23962396
}
23972397

23982398
class ThrowsObjCName {

0 commit comments

Comments
 (0)