[DiagnosticsQoI] SR-3359: Add a fix-it to remove @discardableResult on functions that return Void or Never (#6681)

This commit adds a fix-it to remove @discardableResult on functions that return Void or Never. The fix-it is at the warning level. A test was added to verify that the fix-it removes the @discardableResult. This issue was reported in SR-3359:
https://bugs.swift.org/browse/SR-3359

Changes:
TypeCheckAttr.cpp: implemented AttributeChecker::visitDiscardableResultAttr to add a fix-it to remove @discardableResult on functions returning Void or Never.

DiagnosticsSema.def: Added a warning with a diagnostic message.

LoggingWrappers.swift.gyb, HashedCollections.swift.gyb: Removed @discardableResult on functions returning Void.

fixits-apply-all.swift, fixits-apply-all.swift.result: Added tests to verify that @discardableResult is removed from functions returning Void or Never.
This commit is contained in:
Matthew Carroll
2017-01-11 18:12:36 -05:00
committed by Jordan Rose
parent f462ce7852
commit 0e09bbbb83
6 changed files with 32 additions and 3 deletions

View File

@@ -3295,6 +3295,14 @@ NOTE(availability_protocol_requirement_here, none,
NOTE(availability_conformance_introduced_here, none, NOTE(availability_conformance_introduced_here, none,
"conformance introduced here", ()) "conformance introduced here", ())
//------------------------------------------------------------------------------
// @discardableResult
//------------------------------------------------------------------------------
WARNING(discardable_result_on_void_never_function, none,
"@discardableResult declared on a function returning %select{Never|Void}0 is unnecessary",
(bool))
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Resilience diagnostics // Resilience diagnostics
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -726,7 +726,6 @@ public:
IGNORED_ATTR(Testable) IGNORED_ATTR(Testable)
IGNORED_ATTR(WarnUnqualifiedAccess) IGNORED_ATTR(WarnUnqualifiedAccess)
IGNORED_ATTR(ShowInInterface) IGNORED_ATTR(ShowInInterface)
IGNORED_ATTR(DiscardableResult)
#undef IGNORED_ATTR #undef IGNORED_ATTR
void visitAvailableAttr(AvailableAttr *attr); void visitAvailableAttr(AvailableAttr *attr);
@@ -763,6 +762,8 @@ public:
void visitSpecializeAttr(SpecializeAttr *attr); void visitSpecializeAttr(SpecializeAttr *attr);
void visitVersionedAttr(VersionedAttr *attr); void visitVersionedAttr(VersionedAttr *attr);
void visitDiscardableResultAttr(DiscardableResultAttr *attr);
}; };
} // end anonymous namespace } // end anonymous namespace
@@ -1534,6 +1535,20 @@ void AttributeChecker::visitVersionedAttr(VersionedAttr *attr) {
} }
} }
void AttributeChecker::visitDiscardableResultAttr(DiscardableResultAttr *attr) {
if (auto *FD = dyn_cast<FuncDecl>(D)) {
if (auto result = FD->getResultInterfaceType()) {
auto resultIsVoid = result->isVoid();
if (resultIsVoid || result->isUninhabited()) {
auto warn = diag::discardable_result_on_void_never_function;
auto diagnostic = TC.diagnose(D->getStartLoc(), warn, resultIsVoid);
diagnostic.fixItRemove(attr->getRangeWithAt());
attr->setInvalid();
}
}
}
}
void TypeChecker::checkDeclAttributes(Decl *D) { void TypeChecker::checkDeclAttributes(Decl *D) {
AttributeChecker Checker(*this, D); AttributeChecker Checker(*this, D);

View File

@@ -541,7 +541,6 @@ public struct ${Self}<
return base.removeFirst() return base.removeFirst()
} }
@discardableResult
public mutating func removeFirst(_ n: Int) { public mutating func removeFirst(_ n: Int) {
Log.removeFirstN[selfType] += 1 Log.removeFirstN[selfType] += 1
base.removeFirst(n) base.removeFirst(n)

View File

@@ -243,7 +243,6 @@ internal protocol _HashBuffer {
@discardableResult @discardableResult
mutating func removeValue(forKey key: Key) -> Value? mutating func removeValue(forKey key: Key) -> Value?
@discardableResult
mutating func removeAll(keepingCapacity keepCapacity: Bool) mutating func removeAll(keepingCapacity keepCapacity: Bool)
var count: Int { get } var count: Int { get }

View File

@@ -20,3 +20,7 @@ func goo(_ e: Error) {
@warn_unused_result(message="test message") @warn_unused_result(message="test message")
func warn_unused_result_removal() -> Int { return 5 } func warn_unused_result_removal() -> Int { return 5 }
@discardableResult func discardableResultOnVoidFunc() {}
@discardableResult func discardableResultOnNeverFunc() -> Never { fatalError() }

View File

@@ -20,3 +20,7 @@ func goo(_ e: Error) {
func warn_unused_result_removal() -> Int { return 5 } func warn_unused_result_removal() -> Int { return 5 }
func discardableResultOnVoidFunc() {}
func discardableResultOnNeverFunc() -> Never { fatalError() }