From ea97886bacc97fcc57dc97b17054d3de0d92407b Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Sat, 7 Dec 2013 00:34:23 +0000 Subject: [PATCH] ObjectiveC. Continuing implementation of objc_bridge_related attribute in sema and issuing a variety of diagnostics lazily for misuse of this attribute (and what to do) when converting from CF types to ObjectiveC types (and vice versa). // rdar://15499111 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196629 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 17 +++ include/clang/Sema/Sema.h | 11 ++ lib/Sema/SemaExpr.cpp | 6 + lib/Sema/SemaExprObjC.cpp | 114 ++++++++++++++++++ lib/Sema/SemaInit.cpp | 3 + .../arc-objcbridge-related-attribute.m | 71 +++++++++++ ...heck-objcbridge-related-attribute-lookup.m | 41 +++++++ test/SemaObjC/objcbridge-related-attribute.m | 41 +++++++ .../objcbridge-related-attribute.mm | 31 +++++ 9 files changed, 335 insertions(+) create mode 100644 test/SemaObjC/arc-objcbridge-related-attribute.m create mode 100644 test/SemaObjC/check-objcbridge-related-attribute-lookup.m create mode 100644 test/SemaObjC/objcbridge-related-attribute.m create mode 100644 test/SemaObjCXX/objcbridge-related-attribute.mm diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 07c6cbbdff..76738d0ef3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2468,6 +2468,23 @@ def warn_objc_invalid_bridge : Warning< def warn_objc_invalid_bridge_to_cf : Warning< "%0 cannot bridge to %1">, InGroup; +// objc_bridge_related attribute diagnostics. +def err_objc_bridged_related_invalid_class : Error< + "could not find ObjectiveC class %0 to convert %1 to %2">; +def err_objc_bridged_related_invalid_class_name : Error< + "%0 must be name of an ObjectiveC class to be able to convert %1 to %2">; +def err_objc_bridged_related_class_method : Error< + "class method %0 for conversion of CF type %1 to an " + "ObjectiveC object of type %2 not found">; +def err_objc_bridged_related_instance_method : Error< + "instance method %0 for conversion of an ObjectiveC type %1 to a CF " + "object of type %2 not found">; +def err_objc_bridged_related_known_method : Error< + "%0 must be explicitly converted to %1, use %2 method for this conversion">; +def err_objc_bridged_related_unknown_method : Error< + "%0 must be explicitly converted to %1, define and then use " + "%select{a singular class|an instance}3 method in %2 for this conversion">; + // Function Parameter Semantic Analysis. def err_param_with_void_type : Error<"argument may not have 'void' type">; def err_void_only_param : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ece5140550..0778b1b235 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6908,6 +6908,17 @@ public: void CheckTollFreeBridgeCast(QualType castType, Expr *castExpr); + bool checkObjCBridgeRelatedComponents(SourceLocation Loc, + QualType DestType, QualType SrcType, + ObjCInterfaceDecl *&RelatedClass, + ObjCMethodDecl *&ClassMethod, + ObjCMethodDecl *&InstanceMethod, + TypedefNameDecl *&TDNDecl, + bool CfToNs); + + bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, + QualType DestType, QualType SrcType); + bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); /// \brief Check whether the given new method is a valid override of the diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 3db3e38348..8efdffaf09 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -10639,6 +10639,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, MayHaveConvFixit = true; break; case IncompatiblePointer: + if (getLangOpts().ObjC1 && + CheckObjCBridgeRelatedConversions(Loc, DstType, SrcType)) + return false; MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint, IsNSString); DiagKind = (Action == AA_Passing_CFAudited ? @@ -10718,6 +10721,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, DiagKind = diag::err_arc_weak_unavailable_assign; break; case Incompatible: + if (getLangOpts().ObjC1 && + CheckObjCBridgeRelatedConversions(Loc, DstType, SrcType)) + return true; DiagKind = diag::err_typecheck_convert_incompatible; ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index ba3c5e375d..3e547fdebf 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -3341,6 +3341,120 @@ void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) { } } + +bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc, + QualType DestType, QualType SrcType, + ObjCInterfaceDecl *&RelatedClass, + ObjCMethodDecl *&ClassMethod, + ObjCMethodDecl *&InstanceMethod, + TypedefNameDecl *&TDNDecl, + bool CfToNs) { + QualType T = CfToNs ? SrcType : DestType; + while (const TypedefType *TD = dyn_cast(T.getTypePtr())) { + TDNDecl = TD->getDecl(); + if (ObjCBridgeRelatedAttr *ObjCBAttr = + getObjCBridgeAttr(TD)) { + IdentifierInfo *RCId = ObjCBAttr->getRelatedClass(); + IdentifierInfo *CMId = ObjCBAttr->getClassMethod(); + IdentifierInfo *IMId = ObjCBAttr->getInstanceMethod(); + if (!RCId) + return false; + NamedDecl *Target = 0; + // Check for an existing type with this name. + LookupResult R(*this, DeclarationName(RCId), SourceLocation(), + Sema::LookupOrdinaryName); + if (!LookupName(R, TUScope)) { + Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId + << SrcType << DestType; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + return false; + } + Target = R.getFoundDecl(); + if (Target && isa(Target)) + RelatedClass = cast(Target); + else { + Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId + << SrcType << DestType; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Target) + Diag(Target->getLocStart(), diag::note_declared_at); + return false; + } + + // Check for an existing class method with the given selector name. + if (CfToNs && CMId) { + Selector Sel = Context.Selectors.getUnarySelector(CMId); + ClassMethod = RelatedClass->lookupMethod(Sel, false); + if (!ClassMethod) { + Diag(Loc, diag::err_objc_bridged_related_class_method) + << Sel << SrcType << DestType; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + return false; + } + } + + // Check for an existing instance method with the given selector name. + if (!CfToNs && IMId) { + Selector Sel = Context.Selectors.getNullarySelector(IMId); + InstanceMethod = RelatedClass->lookupMethod(Sel, true); + if (!InstanceMethod) { + Diag(Loc, diag::err_objc_bridged_related_instance_method) + << Sel << SrcType << DestType; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + return false; + } + } + return true; + } + T = TDNDecl->getUnderlyingType(); + } + return false; +} + +bool +Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, + QualType DestType, QualType SrcType) { + ARCConversionTypeClass rhsExprACTC = classifyTypeForARCConversion(SrcType); + ARCConversionTypeClass lhsExprACTC = classifyTypeForARCConversion(DestType); + bool CfToNs = (rhsExprACTC == ACTC_coreFoundation && lhsExprACTC == ACTC_retainable); + bool NsToCf = (rhsExprACTC == ACTC_retainable && lhsExprACTC == ACTC_coreFoundation); + if (!CfToNs && !NsToCf) + return false; + + ObjCInterfaceDecl *RelatedClass; + ObjCMethodDecl *ClassMethod = 0; + ObjCMethodDecl *InstanceMethod = 0; + TypedefNameDecl *TDNDecl = 0; + if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass, + ClassMethod, InstanceMethod, TDNDecl, CfToNs)) + return false; + + if (CfToNs) { + // Implicit conversion from CF to ObjC object is needed. + if (ClassMethod) + Diag(Loc, diag::err_objc_bridged_related_known_method) + << SrcType << DestType << ClassMethod->getSelector() << 0; + else + Diag(Loc, diag::err_objc_bridged_related_unknown_method) + << SrcType << DestType << RelatedClass->getName() << 0; + Diag(RelatedClass->getLocStart(), diag::note_declared_at); + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + } + else { + // Implicit conversion from ObjC type to CF object is needed. + if (InstanceMethod) + Diag(Loc, diag::err_objc_bridged_related_known_method) + << SrcType << DestType << InstanceMethod->getSelector() << 1; + else + Diag(Loc, diag::err_objc_bridged_related_unknown_method) + << SrcType << DestType << RelatedClass->getName() << 1; + Diag(RelatedClass->getLocStart(), diag::note_declared_at); + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + } + + return true; +} + Sema::ARCConversionResult Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK, diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 4188005c76..50ea42714f 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -6482,6 +6482,9 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_ConversionFailed: { QualType FromType = Args[0]->getType(); + if (S.getLangOpts().ObjC1) + S.CheckObjCBridgeRelatedConversions(Kind.getLocation(), + DestType, FromType); PartialDiagnostic PDiag = S.PDiag(diag::err_init_conversion_failed) << (int)Entity.getKind() << DestType diff --git a/test/SemaObjC/arc-objcbridge-related-attribute.m b/test/SemaObjC/arc-objcbridge-related-attribute.m new file mode 100644 index 0000000000..c6bdb27b62 --- /dev/null +++ b/test/SemaObjC/arc-objcbridge-related-attribute.m @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -fsyntax-only -x objective-c -verify -fobjc-arc -Wno-objc-root-class %s +// rdar://15499111 + +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,CGColor))) CGColor *CGColorRef; // expected-note 5 {{declared here}} +typedef struct __attribute__((objc_bridge_related(NSColor,,CGColor1))) CGColor1 *CGColorRef1; // expected-note 3 {{declared here}} +typedef struct __attribute__((objc_bridge_related(NSColor,,))) CGColor2 *CGColorRef2; // expected-note 2 {{declared here}} + +@interface NSColor // expected-note 10 {{declared here}} ++ (NSColor *)colorWithCGColor:(CGColorRef)cgColor; +- (CGColorRef)CGColor; +- (CGColorRef1)CGColor1; +@end + +@interface NSTextField +- (void)setBackgroundColor:(NSColor *)color; +- (NSColor *)backgroundColor; +@end + +void foo(NSColor*); + +NSColor * Test1(NSTextField *textField, CGColorRef newColor) { + foo(newColor); // expected-error {{'CGColorRef' (aka 'struct CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} \ + // expected-error {{implicit conversion of C pointer type 'CGColorRef' (aka 'struct CGColor *') to Objective-C pointer type 'NSColor *' requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CGColorRef' (aka 'struct CGColor *') into ARC}} + textField.backgroundColor = newColor; // expected-error {{'CGColorRef' (aka 'struct CGColor *') must be explicitly converted to 'NSColor *__strong', use 'colorWithCGColor:' method for this conversion}} \ + // expected-error {{implicit conversion of C pointer type 'CGColorRef' (aka 'struct CGColor *') to Objective-C pointer type 'NSColor *' requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CGColorRef' (aka 'struct CGColor *') into ARC}} + return newColor; // expected-error {{'CGColorRef' (aka 'struct CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} \ + // expected-error {{implicit conversion of C pointer type 'CGColorRef' (aka 'struct CGColor *') to Objective-C pointer type 'NSColor *' requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CGColorRef' (aka 'struct CGColor *') into ARC}} +} + +NSColor * Test2(NSTextField *textField, CGColorRef1 newColor) { + foo(newColor); // expected-error {{'CGColorRef1' (aka 'struct CGColor1 *') must be explicitly converted to 'NSColor *', define and then use a singular class method in NSColor for this conversion}} \ + // expected-error {{implicit conversion of C pointer type 'CGColorRef1' (aka 'struct CGColor1 *') to Objective-C pointer type 'NSColor *' requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CGColorRef1' (aka 'struct CGColor1 *') into ARC}} + textField.backgroundColor = newColor; // expected-error {{'CGColorRef1' (aka 'struct CGColor1 *') must be explicitly converted to 'NSColor *__strong', define and then use a singular class method in NSColor for this conversion}} \ + // expected-error {{implicit conversion of C pointer type 'CGColorRef1' (aka 'struct CGColor1 *') to Objective-C pointer type 'NSColor *' requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CGColorRef1' (aka 'struct CGColor1 *') into ARC}} + return newColor; // expected-error {{'CGColorRef1' (aka 'struct CGColor1 *') must be explicitly converted to 'NSColor *', define and then use a singular class method in NSColor for this conversion}} \ + // expected-error {{implicit conversion of C pointer type 'CGColorRef1' (aka 'struct CGColor1 *') to Objective-C pointer type 'NSColor *' requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CGColorRef1' (aka 'struct CGColor1 *') into ARC}} +} + +CGColorRef Test3(NSTextField *textField, CGColorRef newColor) { + newColor = textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef' (aka 'struct CGColor *'), use 'CGColor' method for this conversion}} \ + // expected-error {{implicit conversion of Objective-C pointer type 'NSColor *' to C pointer type 'CGColorRef' (aka 'struct CGColor *') requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_retained to make an ARC object available as a +1 'CGColorRef' (aka 'struct CGColor *')}} + return textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef' (aka 'struct CGColor *'), use 'CGColor' method for this conversion}} \ + // expected-error {{implicit conversion of Objective-C pointer type 'NSColor *' to C pointer type 'CGColorRef' (aka 'struct CGColor *') requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_retained to make an ARC object available as a +1 'CGColorRef' (aka 'struct CGColor *')}} +} + +CGColorRef2 Test4(NSTextField *textField, CGColorRef2 newColor) { + newColor = textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef2' (aka 'struct CGColor2 *'), define and then use an instance method in NSColor for this conversion}} \ + // expected-error {{implicit conversion of Objective-C pointer type 'NSColor *' to C pointer type 'CGColorRef2' (aka 'struct CGColor2 *') requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_retained to make an ARC object available as a +1 'CGColorRef2' (aka 'struct CGColor2 *')}} + return textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef2' (aka 'struct CGColor2 *'), define and then use an instance method in NSColor for this conversion}} \ + // expected-error {{implicit conversion of Objective-C pointer type 'NSColor *' to C pointer type 'CGColorRef2' (aka 'struct CGColor2 *') requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_retained to make an ARC object available as a +1 'CGColorRef2' (aka 'struct CGColor2 *')}} +} diff --git a/test/SemaObjC/check-objcbridge-related-attribute-lookup.m b/test/SemaObjC/check-objcbridge-related-attribute-lookup.m new file mode 100644 index 0000000000..66f56cfed4 --- /dev/null +++ b/test/SemaObjC/check-objcbridge-related-attribute-lookup.m @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -fsyntax-only -x objective-c -verify -Wno-objc-root-class %s +// rdar://15499111 + +typedef struct __attribute__((objc_bridge_related(NSColor,colorXWithCGColor:,CXGColor))) CGColor *CGColorRef; // expected-note 2 {{declared here}} + +typedef struct __attribute__((objc_bridge_related(XNSColor,colorWithCGColor:,CGColor))) CGColor1 *CGColorRef1; // expected-note 2 {{declared here}} + +typedef struct __attribute__((objc_bridge_related(PNsColor,colorWithCGColor:,CGColor))) CGColor2 *CGColorRef2; // expected-note 2 {{declared here}} + +@interface NSColor ++ (NSColor *)colorWithCGColor:(CGColorRef)cgColor; +- (CGColorRef)CGColor; +@end + +@interface NSTextField +- (void)setBackgroundColor:(NSColor *)color; +- (NSColor *)backgroundColor; +@end + +typedef int PNsColor; // expected-note 2 {{declared here}} + +NSColor * Test1(NSTextField *textField, CGColorRef newColor) { + textField.backgroundColor = newColor; // expected-error {{class method 'colorXWithCGColor:' for conversion of CF type 'CGColorRef' (aka 'struct CGColor *') to an ObjectiveC object of type 'NSColor *' not found}} \ + // expected-warning {{incompatible pointer types assigning to 'NSColor *' from 'CGColorRef' (aka 'struct CGColor *')}} + newColor = textField.backgroundColor; // expected-error {{instance method 'CXGColor' for conversion of an ObjectiveC type 'NSColor *' to a CF object of type 'CGColorRef' (aka 'struct CGColor *') not found}} \ + // expected-warning {{incompatible pointer types assigning to 'CGColorRef' (aka 'struct CGColor *') from 'NSColor *'}} +} +NSColor * Test2(NSTextField *textField, CGColorRef1 newColor) { + textField.backgroundColor = newColor; // expected-error {{could not find ObjectiveC class 'XNSColor' to convert 'CGColorRef1' (aka 'struct CGColor1 *') to 'NSColor *'}} \ + // expected-warning {{incompatible pointer types assigning to 'NSColor *' from 'CGColorRef1' (aka 'struct CGColor1 *')}} + newColor = textField.backgroundColor ; // expected-error {{could not find ObjectiveC class 'XNSColor' to convert 'NSColor *' to 'CGColorRef1' (aka 'struct CGColor1 *')}} \ + // expected-warning {{incompatible pointer types assigning to 'CGColorRef1' (aka 'struct CGColor1 *') from 'NSColor *'}} +} + +NSColor * Test3(NSTextField *textField, CGColorRef2 newColor) { + textField.backgroundColor = newColor; // expected-error {{'PNsColor' must be name of an ObjectiveC class to be able to convert 'CGColorRef2' (aka 'struct CGColor2 *') to 'NSColor *'}} \ + // expected-warning {{incompatible pointer types assigning to 'NSColor *' from 'CGColorRef2' (aka 'struct CGColor2 *')}} + newColor = textField.backgroundColor; // expected-error {{'PNsColor' must be name of an ObjectiveC class to be able to convert 'NSColor *' to 'CGColorRef2' (aka 'struct CGColor2 *')}} \ + // expected-warning {{incompatible pointer types assigning to 'CGColorRef2' (aka 'struct CGColor2 *') from 'NSColor *'}} +} + diff --git a/test/SemaObjC/objcbridge-related-attribute.m b/test/SemaObjC/objcbridge-related-attribute.m new file mode 100644 index 0000000000..bf6b4e7e35 --- /dev/null +++ b/test/SemaObjC/objcbridge-related-attribute.m @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -fsyntax-only -x objective-c -verify -Wno-objc-root-class %s +// rdar://15499111 + +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,CGColor))) CGColor *CGColorRef; // expected-note 5 {{declared here}} +typedef struct __attribute__((objc_bridge_related(NSColor,,CGColor1))) CGColor1 *CGColorRef1; // expected-note 3 {{declared here}} +typedef struct __attribute__((objc_bridge_related(NSColor,,))) CGColor2 *CGColorRef2; // expected-note 2 {{declared here}} + +@interface NSColor // expected-note 10 {{declared here}} ++ (NSColor *)colorWithCGColor:(CGColorRef)cgColor; +- (CGColorRef)CGColor; +- (CGColorRef1)CGColor1; +@end + +@interface NSTextField +- (void)setBackgroundColor:(NSColor *)color; +- (NSColor *)backgroundColor; +@end + +void foo(NSColor*); + +NSColor * Test1(NSTextField *textField, CGColorRef newColor) { + foo(newColor); // expected-error {{'CGColorRef' (aka 'struct CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} + textField.backgroundColor = newColor; // expected-error {{'CGColorRef' (aka 'struct CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} + return newColor; // expected-error {{'CGColorRef' (aka 'struct CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} +} + +NSColor * Test2(NSTextField *textField, CGColorRef1 newColor) { + foo(newColor); // expected-error {{'CGColorRef1' (aka 'struct CGColor1 *') must be explicitly converted to 'NSColor *', define and then use a singular class method in NSColor for this conversion}} + textField.backgroundColor = newColor; // expected-error {{'CGColorRef1' (aka 'struct CGColor1 *') must be explicitly converted to 'NSColor *', define and then use a singular class method in NSColor for this conversion}} + return newColor; // expected-error {{'CGColorRef1' (aka 'struct CGColor1 *') must be explicitly converted to 'NSColor *', define and then use a singular class method in NSColor for this conversion}} +} + +CGColorRef Test3(NSTextField *textField, CGColorRef newColor) { + newColor = textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef' (aka 'struct CGColor *'), use 'CGColor' method for this conversion}} + return textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef' (aka 'struct CGColor *'), use 'CGColor' method for this conversion}} +} + +CGColorRef2 Test4(NSTextField *textField, CGColorRef2 newColor) { + newColor = textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef2' (aka 'struct CGColor2 *'), define and then use an instance method in NSColor for this conversion}} + return textField.backgroundColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef2' (aka 'struct CGColor2 *'), define and then use an instance method in NSColor for this conversion}} +} diff --git a/test/SemaObjCXX/objcbridge-related-attribute.mm b/test/SemaObjCXX/objcbridge-related-attribute.mm new file mode 100644 index 0000000000..787e94081d --- /dev/null +++ b/test/SemaObjCXX/objcbridge-related-attribute.mm @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -x objective-c++ -verify -Wno-objc-root-class %s +// rdar://15499111 +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,CGColor))) CGColor *CGColorRef; // expected-note 6 {{declared here}} + +@interface NSColor // expected-note 6 {{declared here}} ++ (NSColor *)colorWithCGColor:(CGColorRef)cgColor; +- (CGColorRef)CGColor; +@end + +@interface NSTextField +- (void)setBackgroundColor:(NSColor *)color; +- (NSColor *)backgroundColor; +@end + + +NSColor *Test1(NSColor *nsColor, CGColorRef newColor) { + nsColor = newColor; // expected-error {{'CGColorRef' (aka 'CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} + NSColor *ns = newColor; // expected-error {{'CGColorRef' (aka 'CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} \ + // expected-error {{cannot initialize a variable of type 'NSColor *' with an lvalue of type 'CGColorRef' (aka 'CGColor *')}} + return newColor; // expected-error {{'CGColorRef' (aka 'CGColor *') must be explicitly converted to 'NSColor *', use 'colorWithCGColor:' method for this conversion}} \ + // expected-error {{cannot initialize return object of type 'NSColor *' with an lvalue of type 'CGColorRef' (aka 'CGColor *')}} +} + +CGColorRef Test2(NSColor *newColor, CGColorRef cgColor) { + cgColor = newColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef' (aka 'CGColor *'), use 'CGColor' method for this conversion}} + CGColorRef cg = newColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef' (aka 'CGColor *'), use 'CGColor' method for this conversion}} \ + // expected-error {{cannot initialize a variable of type 'CGColorRef' (aka 'CGColor *') with an lvalue of type 'NSColor *'}} + return newColor; // expected-error {{'NSColor *' must be explicitly converted to 'CGColorRef' (aka 'CGColor *'), use 'CGColor' method for this conversion}}\ + // expected-error {{cannot initialize return object of type 'CGColorRef' (aka 'CGColor *') with an lvalue of type 'NSColor *'}} +} + -- 2.40.0