This is an archive of the discontinued LLVM Phabricator instance.

[Sema][Objective-C] Add check to warn when property of objc type has assign attribute
ClosedPublic

Authored by QF5690 on Mar 15 2018, 2:07 PM.

Details

Summary

There is a problem, that assign attribute very often getting out of attention. For example, consider this code:

@property(nonatomic, strong, readonly, nullable) SomeObjcClassType1* foo;
@property(nonatomic, strong, readwrite) SomeObjcClassType2* bar;
@property(nonatomic, assign, readonly) SomeObjcClassType* property;
@property(nonatomic, assign, readonly) SomeCStructType state;

It is very easy to miss that assign keyword, and it leads to hard to find and reproduce bugs. Most of the time, we found such bugs in crash reports from already in production code.

Now, consider this code:

@property(nonatomic, strong, readonly, nullable) SomeObjcClassType1* foo;
@property(nonatomic, strong, readwrite) SomeObjcClassType2* bar;
@property(nonatomic, unsafe_unretained, readonly) SomeObjcClassType* property;
@property(nonatomic, assign, readonly) SomeCStructType state;

It is now much harder to even make that mistake and it will be much obvious during code review.

As there is no difference in behaviour between assign and unsafe_unretained attribute, but second is much more verbose, saying "think twice when doing this", I suggest to have, at least, optional warning, that will catch such constructs.

This is my first revision in llvm, so any help would be very much appreciated.

Diff Detail

Repository
rC Clang

Event Timeline

QF5690 created this revision.Mar 15 2018, 2:07 PM

Hey, saw many revisions around obj-c and sema that you are reviewing. Can you help me with this one?

aaron.ballman edited reviewers, added: rjmccall; removed: aaron.ballman.Mar 20 2018, 9:45 AM
aaron.ballman added a subscriber: rjmccall.

I don't know enough about ObjC to feel comfortable reviewing this, but I've added @rjmccall who may have opinions.

I wonder if this wouldn't be better as a clang-tidy check:

https://github.com/llvm-mirror/clang-tools-extra/tree/master/clang-tidy/objc

Border between clang-tidy checks and compiler diagnostics is not entirely clear for me, but, as I understand, clang-tidy is more about codestyle and some internal team agreements. The check that I'm adding is intended to prevent crashes, and it is much better to catch such things in compile time.

I think the problem is there are valid places to use assign on object types (especially delegates).

There are a lot of special cases to deal with here, and it's really up to each team to decide the rules for when assign on object types are OK, so I don't think a compiler warning is appropriate.

I think the problem is there are valid places to use assign on object types (especially delegates).

Isn't it better to have unsafe_unretained there? I thought unsafe_unretained keyword is introduced specifically for that kinds of things.

Ok, here is my last point :) Attributes like strong, retain, copy is commonly reffered as "ownership attribute". But assign does not tells anything about ownership, and from that point of view, it is semantically wrong to have assign on object types, and having unsafe_unretained that actually tells something about ownership – correct. If that's not the case, I can't understand the reason why unsafe_unreatined even exists.

Isn't it better to have unsafe_unretained there?

That is a good question for the author of that property attribute. I'm not sure of the entire history.

We added the unsafe_unretained property attribute as part of ARC because we were introducing __unsafe_retained as a type qualifier and we wanted all the type qualifiers to have corresponding attribute spellings. assign is the much-older attribute, and its non-owning behavior was widely understood. In fact, we briefly considered naming the qualifier __assign, but we quickly decided that that we wanted a more explicit name for the ARC age.

I like the idea of this warning, but I need to float it to our internal Objective-C language group before we can accept it.

It's been a couple of months now, @rjmccall any ETA's?

It's waiting on a discussion that's happening pretty slowly, sorry. I know this is frustrating.

Is there any case for property of ObjC types that we should use unsafe_unretained or assign rather than weak? In my understanding, weak is for properties of ObjC types as the replacement of unsafe_unretained and assign is for properties of primitive types.

This isn't really an Objective-C user forum, but I'll try to summarize briefly. unsafe_unretained is an unsafe version of weak — it's unsafe because it can be left dangling if the object is deallocated. It's necessary for a small (and getting smaller every year) set of classes that don't support true weak references, and it can be useful as an optimization to avoid the performance overhead of reference counting.

This was approved by the Objective-C language group as a default-off warning.

include/clang/Basic/DiagnosticSemaKinds.td
1018

"must" is rather strong for a warning. Maybe something more like "'assign' attribute on property of object type could be 'unsafe_unretained'"?

This was approved by the Objective-C language group as a default-off warning.

We usually do not expose new default-off warnings because experience shows that they rarely ever get enabled by users. If the ObjC group doesn't think this should be on by default, I wonder if it should be included in Clang at all.

QF5690 added inline comments.May 21 2018, 7:25 AM
include/clang/Basic/DiagnosticSemaKinds.td
1018

But "could be" is rather weak :)
May be "Prefer using explicit 'unsafe_unretained' attribute instead of 'assign' for object types", or "Using explicit 'unsafe_unretained' attribute instead of 'assign' for object types is preferred" (if passive voice is preferred)

This was approved by the Objective-C language group as a default-off warning.

We usually do not expose new default-off warnings because experience shows that they rarely ever get enabled by users. If the ObjC group doesn't think this should be on by default, I wonder if it should be included in Clang at all.

That's a fair question to ask. In this case, I'm in favor of adding it because we have evidence of there being a substantial set of users who would enable it enthusiastically.

include/clang/Basic/DiagnosticSemaKinds.td
1018

Neither of those is quite in the standard diagnostic "voice". Maybe something like "'assign' property of object type may become a dangling reference; consider using 'unsafe_unretained'"?

Oh, you should probably not warn about Class types.

This was approved by the Objective-C language group as a default-off warning.

We usually do not expose new default-off warnings because experience shows that they rarely ever get enabled by users. If the ObjC group doesn't think this should be on by default, I wonder if it should be included in Clang at all.

That's a fair question to ask. In this case, I'm in favor of adding it because we have evidence of there being a substantial set of users who would enable it enthusiastically.

Okay, that works for me. Thank you for verifying.

QF5690 updated this revision to Diff 150487.Jun 8 2018, 5:20 AM

Remove warning for Class type, change warning message.

rjmccall added inline comments.Jun 9 2018, 7:23 PM
lib/Sema/SemaObjCProperty.cpp
2554

Please use isObjCARCImplicitlyUnretainedType here.

test/SemaObjC/property-in-class-extension-1.m
18

Whoa, why is this test case using -Weverything? That seems unnecessarily fragile.

QF5690 added inline comments.Jul 6 2018, 10:18 AM
lib/Sema/SemaObjCProperty.cpp
2554

Thanks, didn't notice it.

test/SemaObjC/property-in-class-extension-1.m
18

Do you think it should be relaxed only to warnings that are appearing here?

rjmccall added inline comments.Jul 7 2018, 11:00 PM
test/SemaObjC/property-in-class-extension-1.m
18

Yeah, tests should generally only be testing specific categories. Opt-out warnings are different, of course, but it's understood that adding a new opt-out warning is an ambitious change.

Hey, still working on this?

QF5690 updated this revision to Diff 161684.Aug 21 2018, 4:31 AM

Using isObjCARCImplicitlyUnretainedType instead of isObjCClassType
Tests in property-in-class-extension-1.m relaxed to -Wproperty-attribute-mismatch (was -Weverything)

This revision is now accepted and ready to land.Aug 21 2018, 11:29 AM

LGTM.

Thanks! What I should do next? Haven't found any info in docs about it :)

LGTM.

Thanks! What I should do next? Haven't found any info in docs about it :)

https://llvm.org/docs/Contributing.html

It's up to you. We can certainly commit it for you, but if you're likely to work on more patches, you can ask for commit privileges yourself.

you can ask for commit privileges yourself.

Ok, how do I do it?

Please read the developer policy: https://llvm.org/docs/DeveloperPolicy.html

The information is on that page.

Please read the developer policy: https://llvm.org/docs/DeveloperPolicy.html

The information is on that page.

We grant commit access to contributors with a track record of submitting high quality patches.

I don't think I'm quite fitting these criteria yet :) Can you please commit this patch for me?

rjmccall closed this revision.Sep 5 2018, 12:03 PM

Committed as r341489.