[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-07 Thread Erik Pilkington via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
erik.pilkington marked an inline comment as done.
Closed by commit rG7437a9496528: [SemaObjC] Add a warning for @selector 
expressions that potentially refer to… (authored by erik.pilkington).
Herald added a project: clang.

Changed prior to commit:
  https://reviews.llvm.org/D82611?vs=273549&id=275674#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611

Files:
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/SemaObjC/potentially-direct-selector.m

Index: clang/test/SemaObjC/potentially-direct-selector.m
===
--- /dev/null
+++ clang/test/SemaObjC/potentially-direct-selector.m
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 %s -Wpotentially-direct-selector -verify
+// RUN: %clang_cc1 %s -Wstrict-potentially-direct-selector -verify=expected,strict
+
+#define NS_DIRECT __attribute__((objc_direct))
+
+__attribute__((objc_root_class))
+@interface Dummies
+-(void)inBase;
+-(void)inBaseImpl;
+-(void)inBaseCat;
+-(void)inBaseCatImpl;
+-(void)inDerived;
+-(void)inDerivedImpl;
+-(void)inDerivedCat;
+-(void)inDerivedCatImpl;
++(void)inBaseClass;
++(void)inDerivedClass;
++(void)inDerivedCatClass;
+@end
+
+__attribute__((objc_root_class))
+@interface Base
+-(void)inBase NS_DIRECT; // expected-note + {{direct method}}
++(void)inBaseClass NS_DIRECT;  // expected-note + {{direct method}}
+@end
+
+@implementation Base
+-(void)inBaseImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inBase {}
++(void)inBaseClass {}
+@end
+
+@interface Base (Cat)
+-(void)inBaseCat NS_DIRECT; // expected-note + {{direct method}}
+@end
+
+@implementation Base (Cat)
+-(void)inBaseCatImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inBaseCat {}
+@end
+
+@interface Derived : Base
+-(void)inDerived NS_DIRECT; // expected-note + {{direct method}}
++(void)inDerivedClass NS_DIRECT;  // expected-note + {{direct method}}
+@end
+
+@implementation Derived
+-(void)inDerivedImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inDerived {}
++(void)inDerivedClass {}
+@end
+
+@interface Derived (Cat)
+-(void)inDerivedCat NS_DIRECT; // expected-note + {{direct method}}
++(void)inDerivedCatClass NS_DIRECT; // expected-note + {{direct method}}
+@end
+
+@implementation Derived (Cat)
+-(void)inDerivedCatImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inDerivedCat {}
++(void)inDerivedCatClass {}
+
+-(void)test1 {
+  (void)@selector(inBase); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+}
+@end
+
+void test2() {
+  (void)@selector(inBase); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCat); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (v

[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-07 Thread Erik Pilkington via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG7437a9496528: [SemaObjC] Add a warning for @selector 
expressions that potentially refer to… (authored by erik.pilkington).
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611

Files:
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/SemaObjC/potentially-direct-selector.m

Index: clang/test/SemaObjC/potentially-direct-selector.m
===
--- /dev/null
+++ clang/test/SemaObjC/potentially-direct-selector.m
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 %s -Wpotentially-direct-selector -verify
+// RUN: %clang_cc1 %s -Wstrict-potentially-direct-selector -verify=expected,strict
+
+#define NS_DIRECT __attribute__((objc_direct))
+
+__attribute__((objc_root_class))
+@interface Dummies
+-(void)inBase;
+-(void)inBaseImpl;
+-(void)inBaseCat;
+-(void)inBaseCatImpl;
+-(void)inDerived;
+-(void)inDerivedImpl;
+-(void)inDerivedCat;
+-(void)inDerivedCatImpl;
++(void)inBaseClass;
++(void)inDerivedClass;
++(void)inDerivedCatClass;
+@end
+
+__attribute__((objc_root_class))
+@interface Base
+-(void)inBase NS_DIRECT; // expected-note + {{direct method}}
++(void)inBaseClass NS_DIRECT;  // expected-note + {{direct method}}
+@end
+
+@implementation Base
+-(void)inBaseImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inBase {}
++(void)inBaseClass {}
+@end
+
+@interface Base (Cat)
+-(void)inBaseCat NS_DIRECT; // expected-note + {{direct method}}
+@end
+
+@implementation Base (Cat)
+-(void)inBaseCatImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inBaseCat {}
+@end
+
+@interface Derived : Base
+-(void)inDerived NS_DIRECT; // expected-note + {{direct method}}
++(void)inDerivedClass NS_DIRECT;  // expected-note + {{direct method}}
+@end
+
+@implementation Derived
+-(void)inDerivedImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inDerived {}
++(void)inDerivedClass {}
+@end
+
+@interface Derived (Cat)
+-(void)inDerivedCat NS_DIRECT; // expected-note + {{direct method}}
++(void)inDerivedCatClass NS_DIRECT; // expected-note + {{direct method}}
+@end
+
+@implementation Derived (Cat)
+-(void)inDerivedCatImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inDerivedCat {}
++(void)inDerivedCatClass {}
+
+-(void)test1 {
+  (void)@selector(inBase); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+}
+@end
+
+void test2() {
+  (void)@selector(inBase); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCat); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedClass); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseClass); // strict-warning{{@selector expression formed with potentially direct 

[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-06 Thread Pierre Habouzit via Phabricator via cfe-commits
MadCoder added a comment.

In D82611#2133521 , @erik.pilkington 
wrote:

> In D82611#2125868 , @MadCoder wrote:
>
> >
>




>> I would suggest something like `-Wstrict-direct-dispatch` or something.
> 
> I kinda prefer `-Wpotentially-direct-selector`, since that seems to more 
> closely correspond to what the compiler is complaining about. WDYT?

Yes, that is better, I wasn't dead-set on the name.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-06 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington added a comment.

In D82611#2125868 , @MadCoder wrote:

> So the risk with that one is that if someone had say the `-didSomething` 
> direct selector and that some UIKit/Apple SDK API now adds this as a thing 
> that you use with CFNotification center for example, where you _need_ 
> dynamism, then the uses of the API would warn all the time when the internal 
> to the client project `-didSomething` is in scope.
>
> So we ideally need a way to silence this warning, so at the very least this 
> needs to be a new `-W` flag (on by default (?)) so that callers that have an 
> issue can use a `_Pragma` at the call site to ignore the error for when it's 
> legal.


The `DiagGroup<"potentially-direct-selector">` creates a command line flag, so 
the pragma thing works. I couldn't think of a decent way of suppressing this 
without pragmas, but ISTM that this will have a low enough false-positive rate 
that it won't be a big problem.

> I would suggest something like `-Wstrict-direct-dispatch` or something.

I kinda prefer `-Wpotentially-direct-selector`, since that seems to more 
closely correspond to what the compiler is complaining about. WDYT?




Comment at: clang/test/SemaObjC/potentially-direct-selector.m:84
+  (void)@selector(inBaseCat);
+  (void)@selector(inBaseCatImpl);
+  (void)@selector(inDerived);

MadCoder wrote:
> I think this might be too weak, if we add a warning then maybe what we want 
> is a tri-state:
> 
> `-Wstrict-direct-dispatch=none|self|all`
> 
> because I can see cases where the heuristic here would be too weak
Sure - new patch adds an off-by-default "strict" variant, since I think that's 
a bit more common in clang then the `-Wx=y` approach.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-06 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington updated this revision to Diff 275759.
erik.pilkington marked 3 inline comments as done.
erik.pilkington added a comment.

Add an off-by-default variant of this warning.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611

Files:
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/SemaObjC/potentially-direct-selector.m

Index: clang/test/SemaObjC/potentially-direct-selector.m
===
--- /dev/null
+++ clang/test/SemaObjC/potentially-direct-selector.m
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 %s -Wpotentially-direct-selector -verify
+// RUN: %clang_cc1 %s -Wstrict-potentially-direct-selector -verify=expected,strict
+
+#define NS_DIRECT __attribute__((objc_direct))
+
+__attribute__((objc_root_class))
+@interface Dummies
+-(void)inBase;
+-(void)inBaseImpl;
+-(void)inBaseCat;
+-(void)inBaseCatImpl;
+-(void)inDerived;
+-(void)inDerivedImpl;
+-(void)inDerivedCat;
+-(void)inDerivedCatImpl;
++(void)inBaseClass;
++(void)inDerivedClass;
++(void)inDerivedCatClass;
+@end
+
+__attribute__((objc_root_class))
+@interface Base
+-(void)inBase NS_DIRECT; // expected-note + {{direct method}}
++(void)inBaseClass NS_DIRECT;  // expected-note + {{direct method}}
+@end
+
+@implementation Base
+-(void)inBaseImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inBase {}
++(void)inBaseClass {}
+@end
+
+@interface Base (Cat)
+-(void)inBaseCat NS_DIRECT; // expected-note + {{direct method}}
+@end
+
+@implementation Base (Cat)
+-(void)inBaseCatImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inBaseCat {}
+@end
+
+@interface Derived : Base
+-(void)inDerived NS_DIRECT; // expected-note + {{direct method}}
++(void)inDerivedClass NS_DIRECT;  // expected-note + {{direct method}}
+@end
+
+@implementation Derived
+-(void)inDerivedImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inDerived {}
++(void)inDerivedClass {}
+@end
+
+@interface Derived (Cat)
+-(void)inDerivedCat NS_DIRECT; // expected-note + {{direct method}}
++(void)inDerivedCatClass NS_DIRECT; // expected-note + {{direct method}}
+@end
+
+@implementation Derived (Cat)
+-(void)inDerivedCatImpl NS_DIRECT { // expected-note + {{direct method}}
+}
+-(void)inDerivedCat {}
++(void)inDerivedCatClass {}
+
+-(void)test1 {
+  (void)@selector(inBase); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+}
+@end
+
+void test2() {
+  (void)@selector(inBase); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCat); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedClass); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseClass); // strict-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatClass); // strict-warning{{@selector expression formed with

[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-01 Thread Pierre Habouzit via Phabricator via cfe-commits
MadCoder added a comment.

So the risk with that one is that if someone had say the `-didSomething` direct 
selector and that some UIKit/Apple SDK API now adds this as a thing that you 
use with CFNotification center for example, where you _need_ dynamism, then the 
uses of the API would warn all the time when the internal to the client project 
`-didSomething` is in scope.

So we ideally need a way to silence this warning, so at the very least this 
needs to be a new `-W` flag (on by default (?)) so that callers that have an 
issue can use a `_Pragma` at the call site to ignore the error for when it's 
legal.

I would suggest something like `-Wstrict-direct-dispatch` or something.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-01 Thread Pierre Habouzit via Phabricator via cfe-commits
MadCoder added inline comments.



Comment at: clang/lib/Sema/SemaExprObjC.cpp:1230
 }
-
-static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
-Selector Sel,
+static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, Selector Sel,
 ObjCMethodList &MethList,

missing line between the functions?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-07-01 Thread Pierre Habouzit via Phabricator via cfe-commits
MadCoder added inline comments.



Comment at: clang/test/SemaObjC/potentially-direct-selector.m:84
+  (void)@selector(inBaseCat);
+  (void)@selector(inBaseCatImpl);
+  (void)@selector(inDerived);

I think this might be too weak, if we add a warning then maybe what we want is 
a tri-state:

`-Wstrict-direct-dispatch=none|self|all`

because I can see cases where the heuristic here would be too weak


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82611/new/

https://reviews.llvm.org/D82611



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82611: [SemaObjC] Add a warning for @selector expressions that potentially refer to objc_direct methods

2020-06-25 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington created this revision.
erik.pilkington added reviewers: rjmccall, MadCoder.
Herald added subscribers: ributzka, dexonsmith, jkorous.

As a heuristic, only warn if the selector matches a method declared in the 
current interface.

rdar://64621668


https://reviews.llvm.org/D82611

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/SemaObjC/potentially-direct-selector.m

Index: clang/test/SemaObjC/potentially-direct-selector.m
===
--- /dev/null
+++ clang/test/SemaObjC/potentially-direct-selector.m
@@ -0,0 +1,127 @@
+// RUN: %clang_cc1 %s -Wpotentially-direct-selector -verify
+
+#define NS_DIRECT __attribute__((objc_direct))
+
+@interface Dummies
+-(void)inBase;
+-(void)inBaseImpl;
+-(void)inBaseCat;
+-(void)inBaseCatImpl;
+-(void)inDerived;
+-(void)inDerivedImpl;
+-(void)inDerivedCat;
+-(void)inDerivedCatImpl;
++(void)inBaseClass;
++(void)inDerivedClass;
++(void)inDerivedCatClass;
+@end
+
+__attribute__((objc_root_class))
+@interface Base
+-(void)inBase NS_DIRECT; // expected-note 2 {{direct method}}
++(void)inBaseClass NS_DIRECT;  // expected-note 2 {{direct method}}
+@end
+
+@implementation Base
+-(void)inBaseImpl NS_DIRECT { // expected-note 2 {{direct method}}
+}
+-(void)inBase {}
++(void)inBaseClass {}
+@end
+
+@interface Base (Cat)
+-(void)inBaseCat NS_DIRECT; // expected-note 2 {{direct method}}
+@end
+
+@implementation Base (Cat)
+-(void)inBaseCatImpl NS_DIRECT { // expected-note 2 {{direct method}}
+}
+-(void)inBaseCat {}
+@end
+
+@interface Derived : Base
+-(void)inDerived NS_DIRECT; // expected-note{{direct method}}
++(void)inDerivedClass NS_DIRECT;  // expected-note{{direct method}}
+@end
+
+@implementation Derived
+-(void)inDerivedImpl NS_DIRECT { // expected-note{{direct method}}
+}
+-(void)inDerived {}
++(void)inDerivedClass {}
+@end
+
+@interface Derived (Cat)
+-(void)inDerivedCat NS_DIRECT; // expected-note{{direct method}}
++(void)inDerivedCatClass NS_DIRECT; // expected-note{{direct method}}
+@end
+
+@implementation Derived (Cat)
+-(void)inDerivedCatImpl NS_DIRECT { // expected-note{{direct method}}
+}
+-(void)inDerivedCat {}
++(void)inDerivedCatClass {}
+
+-(void)test1 {
+  (void)@selector(inBase); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+}
+@end
+
+void test2() {
+  (void)@selector(inBase);
+  (void)@selector(inBaseImpl);
+  (void)@selector(inBaseCat);
+  (void)@selector(inBaseCatImpl);
+  (void)@selector(inDerived);
+  (void)@selector(inDerivedImpl);
+  (void)@selector(inDerivedCat);
+  (void)@selector(inDerivedCatImpl);
+  (void)@selector(inDerivedClass);
+  (void)@selector(inBaseClass);
+  (void)@selector(inDerivedCatClass);
+}
+
+@interface OnlyBase : Base @end
+@implementation OnlyBase
+-(void)test3 {
+  (void)@selector(inBase); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCat); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inBaseCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerived);
+  (void)@selector(inDerivedImpl);
+  (void)@selector(inDerivedCat);
+  (void)@selector(inDerivedCatImpl);
+  (void)@selector(inDerivedClass);
+  (void)@selector(inBaseClass); // expected-warning{{@selector expression formed with potentially direct selector}}
+  (void)@selector(inDerivedCatClass);
+}
+@end
+
+__attribute__((objc_root_class))
+@interface Unrelated @end
+@implementation Unrelated
+-(void)test3 {
+  (void)@selector(inBase);
+  (void)@selector(inBaseImpl