diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 10049a934387b..8801ea0af36aa 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -1325,6 +1325,7 @@ bool swift::fixItOverrideDeclarationTypes(TypeChecker &TC, void swift::fixItAvailableAttrRename(TypeChecker &TC, InFlightDiagnostic &diag, SourceRange referenceRange, + const ValueDecl *renamedDecl, const AvailableAttr *attr, const ApplyExpr *call) { ParsedDeclName parsed = swift::parseDeclName(attr->Rename); @@ -1479,6 +1480,12 @@ void swift::fixItAvailableAttrRename(TypeChecker &TC, baseReplace += '.'; } baseReplace += parsed.BaseName; + if (parsed.IsFunctionName && parsed.ArgumentLabels.empty() && + isa(renamedDecl)) { + // If we're going from a var to a function with no arguments, emit an + // empty parameter list. + baseReplace += "()"; + } diag.fixItReplace(referenceRange, baseReplace); } @@ -1681,11 +1688,14 @@ describeRename(ASTContext &ctx, const AvailableAttr *attr, const ValueDecl *D, return ReplacementDeclKind::None; } -void TypeChecker::diagnoseDeprecated(SourceRange ReferenceRange, - const DeclContext *ReferenceDC, - const AvailableAttr *Attr, - DeclName Name, - const ApplyExpr *Call) { +void TypeChecker::diagnoseIfDeprecated(SourceRange ReferenceRange, + const DeclContext *ReferenceDC, + const ValueDecl *DeprecatedDecl, + const ApplyExpr *Call) { + const AvailableAttr *Attr = TypeChecker::getDeprecated(DeprecatedDecl); + if (!Attr) + return; + // We match the behavior of clang to not report deprecation warnings // inside declarations that are themselves deprecated on all deployment // targets. @@ -1704,6 +1714,7 @@ void TypeChecker::diagnoseDeprecated(SourceRange ReferenceRange, } } + DeclName Name = DeprecatedDecl->getFullName(); StringRef Platform = Attr->prettyPlatformString(); clang::VersionTuple DeprecatedVersion; if (Attr->Deprecated) @@ -1742,7 +1753,8 @@ void TypeChecker::diagnoseDeprecated(SourceRange ReferenceRange, auto renameDiag = diagnose(ReferenceRange.Start, diag::note_deprecated_rename, newName); - fixItAvailableAttrRename(*this, renameDiag, ReferenceRange, Attr, Call); + fixItAvailableAttrRename(*this, renameDiag, ReferenceRange, DeprecatedDecl, + Attr, Call); } } @@ -1798,7 +1810,7 @@ bool TypeChecker::diagnoseExplicitUnavailability(const ValueDecl *D, const ApplyExpr *call) { return diagnoseExplicitUnavailability(D, R, DC, [=](InFlightDiagnostic &diag) { - fixItAvailableAttrRename(*this, diag, R, AvailableAttr::isUnavailable(D), + fixItAvailableAttrRename(*this, diag, R, D, AvailableAttr::isUnavailable(D), call); }); } @@ -2126,9 +2138,7 @@ bool AvailabilityWalker::diagAvailability(const ValueDecl *D, SourceRange R, return true; // Diagnose for deprecation - if (const AvailableAttr *Attr = TypeChecker::getDeprecated(D)) { - TC.diagnoseDeprecated(R, DC, Attr, D->getFullName(), call); - } + TC.diagnoseIfDeprecated(R, DC, D, call); // Diagnose for potential unavailability auto maybeUnavail = TC.checkDeclarationAvailability(D, R.Start, DC); diff --git a/lib/Sema/MiscDiagnostics.h b/lib/Sema/MiscDiagnostics.h index 55f05a46918ea..45802de0c435f 100644 --- a/lib/Sema/MiscDiagnostics.h +++ b/lib/Sema/MiscDiagnostics.h @@ -73,6 +73,7 @@ bool diagnoseArgumentLabelError(TypeChecker &TC, const Expr *expr, void fixItAvailableAttrRename(TypeChecker &TC, InFlightDiagnostic &diag, SourceRange referenceRange, + const ValueDecl *renamedDecl, const AvailableAttr *attr, const ApplyExpr *call); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 0b302033cda22..7398653a1c898 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1260,10 +1260,11 @@ static Type resolveIdentTypeComponent( } // FIXME: Merge this with diagAvailability in MiscDiagnostics.cpp. -static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType, +static bool checkTypeDeclAvailability(const TypeDecl *TypeDecl, + IdentTypeRepr *IdType, SourceLoc Loc, DeclContext *DC, TypeChecker &TC, - bool AllowPotentiallyUnavailableProtocol) { + bool AllowPotentiallyUnavailableProtocol){ if (auto CI = dyn_cast(IdType)) { if (auto Attr = AvailableAttr::isUnavailable(TypeDecl)) { @@ -1283,7 +1284,8 @@ static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType, diag::availability_decl_unavailable_rename, CI->getIdentifier(), /*"replaced"*/false, /*special kind*/0, Attr->Rename); - fixItAvailableAttrRename(TC, diag, Loc, Attr, /*call*/nullptr); + fixItAvailableAttrRename(TC, diag, Loc, TypeDecl, Attr, + /*call*/nullptr); } else if (Attr->Message.empty()) { TC.diagnose(Loc, inSwift ? diag::availability_decl_unavailable_in_swift @@ -1309,11 +1311,9 @@ static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType, return true; } - if (auto *Attr = TypeChecker::getDeprecated(TypeDecl)) { - TC.diagnoseDeprecated(CI->getSourceRange(), DC, Attr, - CI->getIdentifier(), /*call, N/A*/nullptr); - } - + TC.diagnoseIfDeprecated(CI->getSourceRange(), DC, TypeDecl, + /*call, N/A*/nullptr); + if (AllowPotentiallyUnavailableProtocol && isa(TypeDecl)) return false; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 519d36a129cd9..0e056d5668d94 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1933,11 +1933,10 @@ class TypeChecker final : public LazyResolver { /// Emits a diagnostic for a reference to a declaration that is deprecated. /// Callers can provide a lambda that adds additional information (such as a /// fixit hint) to the deprecation diagnostic, if it is emitted. - void diagnoseDeprecated(SourceRange SourceRange, - const DeclContext *ReferenceDC, - const AvailableAttr *Attr, - DeclName Name, - const ApplyExpr *Call); + void diagnoseIfDeprecated(SourceRange SourceRange, + const DeclContext *ReferenceDC, + const ValueDecl *DeprecatedDecl, + const ApplyExpr *Call); /// @} /// If LangOptions::DebugForbidTypecheckPrefix is set and the given decl diff --git a/test/Sema/availability.swift b/test/Sema/availability.swift index 08a1b6b830d76..6654b182aefbc 100644 --- a/test/Sema/availability.swift +++ b/test/Sema/availability.swift @@ -130,3 +130,26 @@ func testPlatforms() { let _: UnavailableOnOSXAppExt = 0 let _: UnavailableOnMacOSAppExt = 0 } + +struct VarToFunc { + @available(*, unavailable, renamed: "function()") + var variable: Int // expected-note 2 {{explicitly marked unavailable here}} + + @available(*, unavailable, renamed: "function()") + func oldFunction() -> Int { return 42 } // expected-note 2 {{explicitly marked unavailable here}} + + func function() -> Int { + _ = variable // expected-error{{'variable' has been renamed to 'function()'}}{{9-17=function()}} + _ = oldFunction() //expected-error{{'oldFunction()' has been renamed to 'function()'}}{{9-20=function}} + _ = oldFunction // expected-error{{'oldFunction()' has been renamed to 'function()'}} {{9-20=function}} + + return 42 + } + + mutating func testAssignment() { + // This is nonsense, but someone shouldn't be using 'renamed' for this + // anyway. Just make sure we don't crash or anything. + variable = 2 // expected-error {{'variable' has been renamed to 'function()'}} {{5-13=function()}} + } +} + diff --git a/test/stdlib/Renames.swift b/test/stdlib/Renames.swift index 65144dc846e78..9dc865748c705 100644 --- a/test/stdlib/Renames.swift +++ b/test/stdlib/Renames.swift @@ -519,8 +519,8 @@ func _String(x: String, s: S, c: C, i: String.Index) x.replaceRange(i..; We should suggest to add '()' } func _String(s: S, sep: String) where S.Iterator.Element == String {