Skip to content

[FixCode] Add a diagnosis/fixit to help users convert void pointers. #4108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2201,6 +2201,9 @@ NOTE(generic_type_declared_here,none,
ERROR(cannot_partially_specialize_generic_function,none,
"cannot partially specialize a generic function", ())

WARNING(use_of_void_pointer,none,
"Unsafe%0Pointer<Void> has been replaced by Unsafe%0RawPointer", (StringRef))

// Ambiguities
ERROR(ambiguous_decl_ref,none,
"ambiguous use of %0", (DeclName))
Expand Down
32 changes: 30 additions & 2 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,24 @@ Type TypeChecker::resolveTypeInContext(
return ErrorType::get(Context);
}

/// This function checks if a bound generic type is UnsafePointer<Void> or
/// UnsafeMutablePointer<Void>. For these two type representations, we should
/// warn users that they are deprecated and replace them with more handy
/// UnsafeRawPointer and UnsafeMutableRawPointer, respectively.
static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) {
if (Ty.isNull())
return false;
auto *BGT = Ty->getAs<BoundGenericType>();
if (!BGT)
return false;
if (BGT->getDecl() != Ctx.getUnsafePointerDecl() &&
BGT->getDecl() != Ctx.getUnsafeMutablePointerDecl())
return false;
IsMutable = BGT->getDecl() == Ctx.getUnsafeMutablePointerDecl();
assert(BGT->getGenericArgs().size() == 1);
return BGT->getGenericArgs().front()->isVoid();
}

Type TypeChecker::applyGenericArguments(Type type, TypeDecl *decl,
SourceLoc loc, DeclContext *dc,
GenericIdentTypeRepr *generic,
Expand Down Expand Up @@ -473,8 +491,18 @@ Type TypeChecker::applyGenericArguments(Type type, TypeDecl *decl,
for (auto tyR : genericArgs)
args.push_back(tyR);

return applyUnboundGenericArguments(type, genericDecl, loc, dc, args,
isGenericSignature, resolver);
auto result = applyUnboundGenericArguments(type, genericDecl, loc, dc, args,
isGenericSignature, resolver);
bool isMutablePointer;
if (isPointerToVoid(dc->getASTContext(), result, isMutablePointer)) {
if (isMutablePointer)
diagnose(loc, diag::use_of_void_pointer, "Mutable").
fixItReplace(generic->getSourceRange(), "UnsafeMutableRawPointer");
else
diagnose(loc, diag::use_of_void_pointer, "").
fixItReplace(generic->getSourceRange(), "UnsafeRawPointer");
}
return result;
}

/// Apply generic arguments to the given type.
Expand Down
42 changes: 20 additions & 22 deletions test/1_stdlib/UnsafePointerDiagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
func unsafePointerConversionAvailability(
mrp: UnsafeMutableRawPointer,
rp: UnsafeRawPointer,
umpv: UnsafeMutablePointer<Void>, // FIXME: This should yield a warning to rename UnsafeMutablePointer<Void> to UnsafeMutableRawPointer
upv: UnsafePointer<Void>, // FIXME: This should yield a warning to rename UnsafePointer<Void> to UnsafeRawPointer
umpv: UnsafeMutablePointer<Void>, // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
upv: UnsafePointer<Void>, // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
umpi: UnsafeMutablePointer<Int>,
upi: UnsafePointer<Int>,
umps: UnsafeMutablePointer<String>,
Expand All @@ -31,27 +31,25 @@ func unsafePointerConversionAvailability(
_ = UnsafeRawPointer(umps)
_ = UnsafeRawPointer(ups)

// FIXME: All of these should yield a warning to rename
// UnsafeMutablePointer<Void> to UnsafeMutableRawPointer.
_ = UnsafeMutablePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
_ = UnsafeMutablePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
_ = UnsafeMutablePointer<Void>(umpv)
_ = UnsafeMutablePointer<Void>(upv) // expected-error {{'init' has been renamed to 'init(mutating:)'}}
_ = UnsafeMutablePointer<Void>(umpi)
_ = UnsafeMutablePointer<Void>(upi) // expected-error {{'init' has been renamed to 'init(mutating:)'}}
_ = UnsafeMutablePointer<Void>(umps)
_ = UnsafeMutablePointer<Void>(ups) // expected-error {{'init' has been renamed to 'init(mutating:)'}}
// UnsafeMutablePointer<Void> to UnsafeMutableRawPointer(umpv)
_ = UnsafeMutablePointer<Void>(rp) // expected-warning 3 {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}} expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{overloads for 'UnsafeMutablePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}} expected-note{{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type}}
_ = UnsafeMutablePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}} expected-warning 3 {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}} expected-note{{overloads for 'UnsafeMutablePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
_ = UnsafeMutablePointer<Void>(umpv) // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(upv) // expected-error {{'init' has been renamed to 'init(mutating:)'}} expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(umpi) // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(upi) // expected-error {{'init' has been renamed to 'init(mutating:)'}} expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(umps) // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(ups) // expected-error {{'init' has been renamed to 'init(mutating:)'}} expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}

// FIXME: All of these should yield a warning to rename
// UnsafePointer<Void> to UnsafeRawPointer.
_ = UnsafePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
_ = UnsafePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
_ = UnsafePointer<Void>(umpv)
_ = UnsafePointer<Void>(upv)
_ = UnsafePointer<Void>(umpi)
_ = UnsafePointer<Void>(upi)
_ = UnsafePointer<Void>(umps)
_ = UnsafePointer<Void>(ups)
// UnsafePointer<Void> to UnsafeRawPointer(umpv)
_ = UnsafePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{}} expected-warning 3 {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}} expected-note{{overloads for 'UnsafePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafePointer<Pointee>), (UnsafePointer<Pointee>?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
_ = UnsafePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}} expected-warning 3 {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}} expected-note{{overloads for 'UnsafePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafePointer<Pointee>), (UnsafePointer<Pointee>?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
_ = UnsafePointer<Void>(umpv) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
_ = UnsafePointer<Void>(upv) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
_ = UnsafePointer<Void>(umpi) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
_ = UnsafePointer<Void>(upi) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
_ = UnsafePointer<Void>(umps) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
_ = UnsafePointer<Void>(ups) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}

_ = UnsafeMutablePointer<Int>(rp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Int>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
_ = UnsafeMutablePointer<Int>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Int>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/optional_chain_addressor.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %target-swift-frontend -emit-silgen -verify -parse-as-library %s

func foo(x: UnsafeMutablePointer<UnsafeMutablePointer<()>?>) {
func foo(x: UnsafeMutablePointer<UnsafeMutablePointer<()>?>) { // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = x.pointee?.pointee
_ = x.pointee.map { type(of: $0) }
}
12 changes: 10 additions & 2 deletions test/type/types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,5 +159,13 @@ class r21949448 {
// SE-0066 - Standardize function type argument syntax to require parentheses
let _ : Int -> Float // expected-error {{single argument function types require parentheses}} {{9-9=(}} {{12-12=)}}



func foo1(a : UnsafePointer<Void>) {} // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}{{15-34=UnsafeRawPointer}}
func foo2(a : UnsafeMutablePointer<()>) {} // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}{{15-39=UnsafeMutableRawPointer}}
class C {
func foo1(a : UnsafePointer<Void>) {} // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}{{17-36=UnsafeRawPointer}}
func foo2(a : UnsafeMutablePointer<()>) {} // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}{{17-41=UnsafeMutableRawPointer}}
func foo3() {
let _ : UnsafePointer<Void> // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}{{13-32=UnsafeRawPointer}}
let _ : UnsafeMutablePointer<Void> // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}{{13-39=UnsafeMutableRawPointer}}
}
}