Skip to content

Commit b53eba0

Browse files
authored
Merge pull request #58545 from cbjeukendrup/fixit_deprec_self_init
Fix #57354: Fix-it for deprecated initializers removes the `.init` part from `self.init`
2 parents c4c1b82 + 7f9885b commit b53eba0

File tree

3 files changed

+103
-31
lines changed

3 files changed

+103
-31
lines changed

lib/AST/Availability.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "swift/AST/Availability.h"
1718
#include "swift/AST/ASTContext.h"
1819
#include "swift/AST/Attr.h"
1920
#include "swift/AST/Decl.h"
20-
#include "swift/AST/Types.h"
21-
#include "swift/AST/Availability.h"
2221
#include "swift/AST/PlatformKind.h"
2322
#include "swift/AST/TypeCheckRequests.h"
2423
#include "swift/AST/TypeWalker.h"
24+
#include "swift/AST/Types.h"
2525
#include <map>
2626

2727
using namespace swift;
@@ -96,10 +96,12 @@ static void mergeWithInferredAvailability(const AvailableAttr *Attr,
9696

9797
/// Create an implicit availability attribute for the given platform
9898
/// and with the inferred availability.
99-
static AvailableAttr *
100-
createAvailableAttr(PlatformKind Platform,
101-
const InferredAvailability &Inferred,
102-
ASTContext &Context) {
99+
static AvailableAttr *createAvailableAttr(PlatformKind Platform,
100+
const InferredAvailability &Inferred,
101+
StringRef Message,
102+
StringRef Rename,
103+
ValueDecl *RenameDecl,
104+
ASTContext &Context) {
103105

104106
llvm::VersionTuple Introduced =
105107
Inferred.Introduced.value_or(llvm::VersionTuple());
@@ -108,21 +110,27 @@ createAvailableAttr(PlatformKind Platform,
108110
llvm::VersionTuple Obsoleted =
109111
Inferred.Obsoleted.value_or(llvm::VersionTuple());
110112

111-
return new (Context) AvailableAttr(
112-
SourceLoc(), SourceRange(), Platform,
113-
/*Message=*/StringRef(),
114-
/*Rename=*/StringRef(), /*RenameDecl=*/nullptr,
115-
Introduced, /*IntroducedRange=*/SourceRange(),
116-
Deprecated, /*DeprecatedRange=*/SourceRange(),
117-
Obsoleted, /*ObsoletedRange=*/SourceRange(),
118-
Inferred.PlatformAgnostic, /*Implicit=*/true,
119-
Inferred.IsSPI);
113+
return new (Context)
114+
AvailableAttr(SourceLoc(), SourceRange(), Platform,
115+
Message, Rename, RenameDecl,
116+
Introduced, /*IntroducedRange=*/SourceRange(),
117+
Deprecated, /*DeprecatedRange=*/SourceRange(),
118+
Obsoleted, /*ObsoletedRange=*/SourceRange(),
119+
Inferred.PlatformAgnostic, /*Implicit=*/true,
120+
Inferred.IsSPI);
120121
}
121122

122123
void AvailabilityInference::applyInferredAvailableAttrs(
123124
Decl *ToDecl, ArrayRef<const Decl *> InferredFromDecls,
124125
ASTContext &Context) {
125126

127+
// Let the new AvailabilityAttr inherit the message and rename.
128+
// The first encountered message / rename will win; this matches the
129+
// behaviour of diagnostics for 'non-inherited' AvailabilityAttrs.
130+
StringRef Message;
131+
StringRef Rename;
132+
ValueDecl *RenameDecl = nullptr;
133+
126134
// Iterate over the declarations and infer required availability on
127135
// a per-platform basis.
128136
std::map<PlatformKind, InferredAvailability> Inferred;
@@ -133,14 +141,24 @@ void AvailabilityInference::applyInferredAvailableAttrs(
133141
continue;
134142

135143
mergeWithInferredAvailability(AvAttr, Inferred[AvAttr->Platform]);
144+
145+
if (Message.empty() && !AvAttr->Message.empty())
146+
Message = AvAttr->Message;
147+
148+
if (Rename.empty() && !AvAttr->Rename.empty()) {
149+
Rename = AvAttr->Rename;
150+
RenameDecl = AvAttr->RenameDecl;
151+
}
136152
}
137153
}
138154

139155
// Create an availability attribute for each observed platform and add
140156
// to ToDecl.
141157
DeclAttributes &Attrs = ToDecl->getAttrs();
142158
for (auto &Pair : Inferred) {
143-
auto *Attr = createAvailableAttr(Pair.first, Pair.second, Context);
159+
auto *Attr = createAvailableAttr(Pair.first, Pair.second, Message,
160+
Rename, RenameDecl, Context);
161+
144162
Attrs.add(Attr);
145163
}
146164
}

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2355,16 +2355,22 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag,
23552355
} else if (parsed.BaseName == "init" && isa_and_nonnull<CallExpr>(call)) {
23562356
auto *CE = cast<CallExpr>(call);
23572357

2358-
// For initializers, replace with a "call" of the context type...but only
2359-
// if we know we're doing a call (rather than a first-class reference).
2358+
// If it is a call to an initializer (rather than a first-class reference):
2359+
23602360
if (parsed.isMember()) {
2361+
// replace with a "call" to the type (instead of writing `.init`)
23612362
diag.fixItReplace(CE->getFn()->getSourceRange(), parsed.ContextName);
23622363
} else if (auto *dotCall = dyn_cast<DotSyntaxCallExpr>(CE->getFn())) {
2363-
SourceLoc removeLoc = dotCall->getDotLoc();
2364-
if (removeLoc.isInvalid())
2365-
return;
2366-
2367-
diag.fixItRemove(SourceRange(removeLoc, dotCall->getFn()->getEndLoc()));
2364+
// if it's a dot call, and the left side is a type (and not `self` or
2365+
// `super`, for example), just remove the dot and the right side, again
2366+
// in order to make it a "call" to the type
2367+
if (isa<TypeExpr>(dotCall->getBase())) {
2368+
SourceLoc removeLoc = dotCall->getDotLoc();
2369+
if (removeLoc.isInvalid())
2370+
return;
2371+
2372+
diag.fixItRemove(SourceRange(removeLoc, dotCall->getFn()->getEndLoc()));
2373+
}
23682374
} else if (!isa<ConstructorRefCallExpr>(CE->getFn())) {
23692375
return;
23702376
}

test/attr/attr_availability.swift

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,62 @@ func testFactoryMethods() {
615615
Int.factory2(other: 1) // expected-error {{'factory2(other:)' has been replaced by 'Int.init(other:)'}} {{3-15=Int}}
616616
}
617617

618+
class DeprecatedInitBase {
619+
@available(*, deprecated, renamed: "init(new:)")
620+
init(old: Int) {}
621+
622+
init(new: Int) {}
623+
624+
convenience init(testSelf: Int) {
625+
// https://github.com/apple/swift/issues/57354
626+
// The fix-it should not remove `.init`
627+
self.init(old: testSelf) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{15-18=new}}
628+
}
629+
630+
init(testSuper: Int) {}
631+
632+
@available(*, deprecated, renamed: "init(new:)")
633+
@available(*, deprecated, renamed: "init(new:)")
634+
init(multipleEqualAvailabilityAttributes: Int) {}
635+
636+
@available(*, deprecated, renamed: "init(old:)")
637+
@available(*, deprecated, renamed: "init(testSuper:)")
638+
@available(*, deprecated, renamed: "init(new:)")
639+
init(multipleUnequalAvailabilityAttributes: Int) {}
640+
}
641+
642+
class DeprecatedInitSub1: DeprecatedInitBase {
643+
override init(testSuper: Int) {
644+
// https://github.com/apple/swift/issues/57354
645+
// The fix-it should not remove `.init`
646+
super.init(old: testSuper) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{16-19=new}}
647+
}
648+
}
649+
650+
class DeprecatedInitSub2: DeprecatedInitBase { }
651+
652+
_ = DeprecatedInitBase(old: 0) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{24-27=new}}
653+
_ = DeprecatedInitBase.init(old: 0) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{29-32=new}}
654+
let _: DeprecatedInitBase = .init(old: 0) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{35-38=new}}
655+
_ = DeprecatedInitSub2(old: 0) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{24-27=new}}
656+
_ = DeprecatedInitSub2.init(old: 0) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{29-32=new}}
657+
let _: DeprecatedInitSub2 = .init(old: 0) // expected-warning {{'init(old:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{35-38=new}}
658+
659+
_ = DeprecatedInitBase(multipleEqualAvailabilityAttributes: 0) // expected-warning {{'init(multipleEqualAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{24-59=new}}
660+
_ = DeprecatedInitBase.init(multipleEqualAvailabilityAttributes: 0) // expected-warning {{'init(multipleEqualAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{29-64=new}}
661+
let _: DeprecatedInitBase = .init(multipleEqualAvailabilityAttributes: 0) // expected-warning {{'init(multipleEqualAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{35-70=new}}
662+
_ = DeprecatedInitSub2(multipleEqualAvailabilityAttributes: 0) // expected-warning {{'init(multipleEqualAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{24-59=new}}
663+
_ = DeprecatedInitSub2.init(multipleEqualAvailabilityAttributes: 0) // expected-warning {{'init(multipleEqualAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{29-64=new}}
664+
let _: DeprecatedInitSub2 = .init(multipleEqualAvailabilityAttributes: 0) // expected-warning {{'init(multipleEqualAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{35-70=new}}
665+
666+
_ = DeprecatedInitBase(multipleUnequalAvailabilityAttributes: 0) // expected-warning {{'init(multipleUnequalAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{24-61=new}}
667+
_ = DeprecatedInitBase.init(multipleUnequalAvailabilityAttributes: 0) // expected-warning {{'init(multipleUnequalAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{29-66=new}}
668+
let _: DeprecatedInitBase = .init(multipleUnequalAvailabilityAttributes: 0) // expected-warning {{'init(multipleUnequalAvailabilityAttributes:)' is deprecated: replaced by 'init(new:)'}} expected-note {{use 'init(new:)' instead}} {{35-72=new}}
669+
_ = DeprecatedInitSub2(multipleUnequalAvailabilityAttributes: 0) // expected-warning {{'init(multipleUnequalAvailabilityAttributes:)' is deprecated}} expected-note {{use 'init(new:)' instead}} {{24-61=new}}
670+
_ = DeprecatedInitSub2.init(multipleUnequalAvailabilityAttributes: 0) // expected-warning {{'init(multipleUnequalAvailabilityAttributes:)' is deprecated}} expected-note {{use 'init(new:)' instead}} {{29-66=new}}
671+
let _: DeprecatedInitSub2 = .init(multipleUnequalAvailabilityAttributes: 0) // expected-warning {{'init(multipleUnequalAvailabilityAttributes:)' is deprecated}} expected-note {{use 'init(new:)' instead}} {{35-72=new}}
672+
673+
618674
class Base {
619675
@available(*, unavailable)
620676
func bad() {} // expected-note {{here}}
@@ -1073,14 +1129,6 @@ struct UnavailableAccessors {
10731129
}
10741130
}
10751131

1076-
class BaseDeprecatedInit {
1077-
@available(*, deprecated) init(bad: Int) { }
1078-
}
1079-
1080-
class SubInheritedDeprecatedInit: BaseDeprecatedInit { }
1081-
1082-
_ = SubInheritedDeprecatedInit(bad: 0) // expected-warning {{'init(bad:)' is deprecated}}
1083-
10841132
// https://github.com/apple/swift/issues/51149
10851133
// Should produce no warnings.
10861134

0 commit comments

Comments
 (0)