diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2013-12-07 00:34:23 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2013-12-07 00:34:23 +0000 |
commit | 1f0b3bfd75029463625643b1650e097afe227b5c (patch) | |
tree | 455bc593d9918c54c6c7575676f74a8180802490 /clang/lib | |
parent | 32c3f17d3655fa97817c697e8e2456e9283567ae (diff) | |
download | bcm5719-llvm-1f0b3bfd75029463625643b1650e097afe227b5c.tar.gz bcm5719-llvm-1f0b3bfd75029463625643b1650e097afe227b5c.zip |
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
llvm-svn: 196629
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 114 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 3 |
3 files changed, 123 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3db3e383482..8efdffaf090 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index ba3c5e375df..3e547fdebfd 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/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<TypedefType>(T.getTypePtr())) { + TDNDecl = TD->getDecl(); + if (ObjCBridgeRelatedAttr *ObjCBAttr = + getObjCBridgeAttr<ObjCBridgeRelatedAttr>(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<ObjCInterfaceDecl>(Target)) + RelatedClass = cast<ObjCInterfaceDecl>(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/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 4188005c762..50ea42714fa 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/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 |