Skip to content

Commit b660abc

Browse files
committed
[ObjC] Add a command line flag that disables recognition of objc_direct for testability
Programmers would like to be able to test direct methods by calling them from a different linkage unit or mocking them, both of which are impossible. This patch adds a flag that effectively disables the attribute, which will fix this when enabled in testable builds. rdar://71190891 Differential revision: https://reviews.llvm.org/D95845
1 parent 8440129 commit b660abc

File tree

9 files changed

+87
-9
lines changed

9 files changed

+87
-9
lines changed

clang/include/clang/AST/DeclObjC.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -852,9 +852,7 @@ class ObjCPropertyDecl : public NamedDecl {
852852
bool isClassProperty() const {
853853
return PropertyAttributes & ObjCPropertyAttribute::kind_class;
854854
}
855-
bool isDirectProperty() const {
856-
return PropertyAttributes & ObjCPropertyAttribute::kind_direct;
857-
}
855+
bool isDirectProperty() const;
858856

859857
ObjCPropertyQueryKind getQueryKind() const {
860858
return isClassProperty() ? ObjCPropertyQueryKind::OBJC_PR_query_class :

clang/include/clang/Basic/LangOptions.def

+2
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in l
298298
BENIGN_LANGOPT(CompatibilityQualifiedIdBlockParamTypeChecking, 1, 0,
299299
"compatibility mode for type checking block parameters "
300300
"involving qualified id types")
301+
LANGOPT(ObjCDisableDirectMethodsForTesting, 1, 0,
302+
"Disable recognition of objc_direct methods")
301303
LANGOPT(CFProtectionBranch , 1, 0, "Control-Flow Branch Protection enabled")
302304
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
303305
ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")

clang/include/clang/Driver/Options.td

+6
Original file line numberDiff line numberDiff line change
@@ -2225,6 +2225,12 @@ def fobjc_nonfragile_abi : Flag<["-"], "fobjc-nonfragile-abi">, Group<f_Group>;
22252225
def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group<f_Group>;
22262226

22272227
def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>;
2228+
def fobjc_disable_direct_methods_for_testing :
2229+
Flag<["-"], "fobjc-disable-direct-methods-for-testing">,
2230+
Group<f_Group>, Flags<[CC1Option]>,
2231+
HelpText<"Ignore attribute objc_direct so that direct methods can be tested">,
2232+
MarshallingInfoFlag<LangOpts<"ObjCDisableDirectMethodsForTesting">>;
2233+
22282234
def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
22292235
def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused, FlangOption, FC1Option]>,
22302236
HelpText<"Parse OpenMP pragmas and generate parallel code.">;

clang/lib/AST/DeclObjC.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,8 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
826826
}
827827

828828
bool ObjCMethodDecl::isDirectMethod() const {
829-
return hasAttr<ObjCDirectAttr>();
829+
return hasAttr<ObjCDirectAttr>() &&
830+
!getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting;
830831
}
831832

832833
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
@@ -2295,6 +2296,11 @@ QualType ObjCPropertyDecl::getUsageType(QualType objectType) const {
22952296
ObjCSubstitutionContext::Property);
22962297
}
22972298

2299+
bool ObjCPropertyDecl::isDirectProperty() const {
2300+
return (PropertyAttributes & ObjCPropertyAttribute::kind_direct) &&
2301+
!getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting;
2302+
}
2303+
22982304
//===----------------------------------------------------------------------===//
22992305
// ObjCPropertyImplDecl
23002306
//===----------------------------------------------------------------------===//

clang/lib/Driver/ToolChains/Clang.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -3665,6 +3665,9 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D,
36653665
WeakArg->render(Args, CmdArgs);
36663666
}
36673667
}
3668+
3669+
if (Args.hasArg(options::OPT_fobjc_disable_direct_methods_for_testing))
3670+
CmdArgs.push_back("-fobjc-disable-direct-methods-for-testing");
36683671
}
36693672

36703673
static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,

clang/lib/Sema/SemaDeclObjC.cpp

+10-5
Original file line numberDiff line numberDiff line change
@@ -4407,10 +4407,12 @@ class OverrideSearch {
44074407

44084408
void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method,
44094409
ObjCMethodDecl *overridden) {
4410-
if (const auto *attr = overridden->getAttr<ObjCDirectAttr>()) {
4410+
if (overridden->isDirectMethod()) {
4411+
const auto *attr = overridden->getAttr<ObjCDirectAttr>();
44114412
Diag(method->getLocation(), diag::err_objc_override_direct_method);
44124413
Diag(attr->getLocation(), diag::note_previous_declaration);
4413-
} else if (const auto *attr = method->getAttr<ObjCDirectAttr>()) {
4414+
} else if (method->isDirectMethod()) {
4415+
const auto *attr = method->getAttr<ObjCDirectAttr>();
44144416
Diag(attr->getLocation(), diag::err_objc_direct_on_override)
44154417
<< isa<ObjCProtocolDecl>(overridden->getDeclContext());
44164418
Diag(overridden->getLocation(), diag::note_previous_declaration);
@@ -4856,7 +4858,8 @@ Decl *Sema::ActOnMethodDeclaration(
48564858
// the canonical declaration.
48574859
if (!ObjCMethod->isDirectMethod()) {
48584860
const ObjCMethodDecl *CanonicalMD = ObjCMethod->getCanonicalDecl();
4859-
if (const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>()) {
4861+
if (CanonicalMD->isDirectMethod()) {
4862+
const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>();
48604863
ObjCMethod->addAttr(
48614864
ObjCDirectAttr::CreateImplicit(Context, attr->getLocation()));
48624865
}
@@ -4901,14 +4904,16 @@ Decl *Sema::ActOnMethodDeclaration(
49014904
Diag(IMD->getLocation(), diag::note_previous_declaration);
49024905
};
49034906

4904-
if (const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>()) {
4907+
if (ObjCMethod->isDirectMethod()) {
4908+
const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>();
49054909
if (ObjCMethod->getCanonicalDecl() != IMD) {
49064910
diagContainerMismatch();
49074911
} else if (!IMD->isDirectMethod()) {
49084912
Diag(attr->getLocation(), diag::err_objc_direct_missing_on_decl);
49094913
Diag(IMD->getLocation(), diag::note_previous_declaration);
49104914
}
4911-
} else if (const auto *attr = IMD->getAttr<ObjCDirectAttr>()) {
4915+
} else if (IMD->isDirectMethod()) {
4916+
const auto *attr = IMD->getAttr<ObjCDirectAttr>();
49124917
if (ObjCMethod->getCanonicalDecl() != IMD) {
49134918
diagContainerMismatch();
49144919
} else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 -fobjc-disable-direct-methods-for-testing %s -o - | FileCheck %s
2+
3+
@interface Y
4+
@property (direct) int direct_property;
5+
@end
6+
@implementation Y @end
7+
8+
// CHECK: @OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [16 x i8] c"direct_property\00"
9+
// CHECK: @"_OBJC_$_PROP_LIST_Y" =
10+
// CHECK-SAME: @OBJC_PROP_NAME_ATTR_,
11+
12+
@interface X
13+
-(void)m __attribute__((objc_direct));
14+
@end
15+
16+
// CHECK-LABEL: define void @f
17+
void f(X *x) {
18+
[x m];
19+
20+
// CHECK: call void bitcast ({{.*}} @objc_msgSend to {{.*}})
21+
}

clang/test/Driver/clang_f_opts.c

+5
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,8 @@
576576

577577
// RUN: %clang -### -S -fno-temp-file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-TEMP-FILE %s
578578
// CHECK-NO-TEMP-FILE: "-fno-temp-file"
579+
580+
// RUN: %clang -### -xobjective-c -fobjc-disable-direct-methods-for-testing %s 2>&1 | FileCheck -check-prefix=CHECK_DISABLE_DIRECT %s
581+
// RUN: %clang -### -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DISABLE_DIRECT %s
582+
// CHECK_DISABLE_DIRECT: -fobjc-disable-direct-methods-for-testing
583+
// CHECK_NO_DISABLE_DIRECT-NOT: -fobjc-disable-direct-methods-for-testing
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -verify -fobjc-disable-direct-methods-for-testing %s
2+
3+
// expected-no-diagnostics
4+
5+
#define DIRECT __attribute__((objc_direct))
6+
#define DIRECT_MEMBERS __attribute__((objc_direct_members))
7+
8+
__attribute__((objc_root_class))
9+
@interface X
10+
-(void)direct_method DIRECT;
11+
@end
12+
13+
@implementation X
14+
-(void)direct_method DIRECT {}
15+
@end
16+
17+
__attribute__((objc_root_class))
18+
DIRECT_MEMBERS
19+
@interface Y
20+
-(void)direct_method2;
21+
@end
22+
23+
@implementation Y
24+
-(void)direct_method2 {}
25+
@end
26+
27+
__attribute__((objc_root_class))
28+
@interface Z
29+
@property (direct) int direct_property;
30+
@end
31+
32+
@implementation Z @end

0 commit comments

Comments
 (0)