diff options
| author | 2020-08-03 15:06:44 +0000 | |
|---|---|---|
| committer | 2020-08-03 15:06:44 +0000 | |
| commit | b64793999546ed8adebaeebd9d8345d18db8927d (patch) | |
| tree | 4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp | |
| parent | Add support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff) | |
| download | wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip | |
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp')
| -rw-r--r-- | gnu/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp | 4539 |
1 files changed, 0 insertions, 4539 deletions
diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp deleted file mode 100644 index ed780efd4cf..00000000000 --- a/gnu/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ /dev/null @@ -1,4539 +0,0 @@ -//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for Objective-C expressions. -// -//===----------------------------------------------------------------------===// - -#include "clang/Sema/SemaInternal.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/ExprObjC.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeLoc.h" -#include "clang/Analysis/DomainSpecific/CocoaConventions.h" -#include "clang/Edit/Commit.h" -#include "clang/Edit/Rewriters.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Sema/Initialization.h" -#include "clang/Sema/Lookup.h" -#include "clang/Sema/Scope.h" -#include "clang/Sema/ScopeInfo.h" -#include "llvm/ADT/SmallString.h" - -using namespace clang; -using namespace sema; -using llvm::makeArrayRef; - -ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, - ArrayRef<Expr *> Strings) { - // Most ObjC strings are formed out of a single piece. However, we *can* - // have strings formed out of multiple @ strings with multiple pptokens in - // each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one - // StringLiteral for ObjCStringLiteral to hold onto. - StringLiteral *S = cast<StringLiteral>(Strings[0]); - - // If we have a multi-part string, merge it all together. - if (Strings.size() != 1) { - // Concatenate objc strings. - SmallString<128> StrBuf; - SmallVector<SourceLocation, 8> StrLocs; - - for (Expr *E : Strings) { - S = cast<StringLiteral>(E); - - // ObjC strings can't be wide or UTF. - if (!S->isAscii()) { - Diag(S->getBeginLoc(), diag::err_cfstring_literal_not_string_constant) - << S->getSourceRange(); - return true; - } - - // Append the string. - StrBuf += S->getString(); - - // Get the locations of the string tokens. - StrLocs.append(S->tokloc_begin(), S->tokloc_end()); - } - - // Create the aggregate string with the appropriate content and location - // information. - const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType()); - assert(CAT && "String literal not of constant array type!"); - QualType StrTy = Context.getConstantArrayType( - CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), - CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers()); - S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ascii, - /*Pascal=*/false, StrTy, &StrLocs[0], - StrLocs.size()); - } - - return BuildObjCStringLiteral(AtLocs[0], S); -} - -ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){ - // Verify that this composite string is acceptable for ObjC strings. - if (CheckObjCString(S)) - return true; - - // Initialize the constant string interface lazily. This assumes - // the NSString interface is seen in this translation unit. Note: We - // don't use NSConstantString, since the runtime team considers this - // interface private (even though it appears in the header files). - QualType Ty = Context.getObjCConstantStringInterface(); - if (!Ty.isNull()) { - Ty = Context.getObjCObjectPointerType(Ty); - } else if (getLangOpts().NoConstantCFStrings) { - IdentifierInfo *NSIdent=nullptr; - std::string StringClass(getLangOpts().ObjCConstantStringClass); - - if (StringClass.empty()) - NSIdent = &Context.Idents.get("NSConstantString"); - else - NSIdent = &Context.Idents.get(StringClass); - - NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc, - LookupOrdinaryName); - if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { - Context.setObjCConstantStringInterface(StrIF); - Ty = Context.getObjCConstantStringInterface(); - Ty = Context.getObjCObjectPointerType(Ty); - } else { - // If there is no NSConstantString interface defined then treat this - // as error and recover from it. - Diag(S->getBeginLoc(), diag::err_no_nsconstant_string_class) - << NSIdent << S->getSourceRange(); - Ty = Context.getObjCIdType(); - } - } else { - IdentifierInfo *NSIdent = NSAPIObj->getNSClassId(NSAPI::ClassId_NSString); - NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc, - LookupOrdinaryName); - if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { - Context.setObjCConstantStringInterface(StrIF); - Ty = Context.getObjCConstantStringInterface(); - Ty = Context.getObjCObjectPointerType(Ty); - } else { - // If there is no NSString interface defined, implicitly declare - // a @class NSString; and use that instead. This is to make sure - // type of an NSString literal is represented correctly, instead of - // being an 'id' type. - Ty = Context.getObjCNSStringType(); - if (Ty.isNull()) { - ObjCInterfaceDecl *NSStringIDecl = - ObjCInterfaceDecl::Create (Context, - Context.getTranslationUnitDecl(), - SourceLocation(), NSIdent, - nullptr, nullptr, SourceLocation()); - Ty = Context.getObjCInterfaceType(NSStringIDecl); - Context.setObjCNSStringType(Ty); - } - Ty = Context.getObjCObjectPointerType(Ty); - } - } - - return new (Context) ObjCStringLiteral(S, Ty, AtLoc); -} - -/// Emits an error if the given method does not exist, or if the return -/// type is not an Objective-C object. -static bool validateBoxingMethod(Sema &S, SourceLocation Loc, - const ObjCInterfaceDecl *Class, - Selector Sel, const ObjCMethodDecl *Method) { - if (!Method) { - // FIXME: Is there a better way to avoid quotes than using getName()? - S.Diag(Loc, diag::err_undeclared_boxing_method) << Sel << Class->getName(); - return false; - } - - // Make sure the return type is reasonable. - QualType ReturnType = Method->getReturnType(); - if (!ReturnType->isObjCObjectPointerType()) { - S.Diag(Loc, diag::err_objc_literal_method_sig) - << Sel; - S.Diag(Method->getLocation(), diag::note_objc_literal_method_return) - << ReturnType; - return false; - } - - return true; -} - -/// Maps ObjCLiteralKind to NSClassIdKindKind -static NSAPI::NSClassIdKindKind ClassKindFromLiteralKind( - Sema::ObjCLiteralKind LiteralKind) { - switch (LiteralKind) { - case Sema::LK_Array: - return NSAPI::ClassId_NSArray; - case Sema::LK_Dictionary: - return NSAPI::ClassId_NSDictionary; - case Sema::LK_Numeric: - return NSAPI::ClassId_NSNumber; - case Sema::LK_String: - return NSAPI::ClassId_NSString; - case Sema::LK_Boxed: - return NSAPI::ClassId_NSValue; - - // there is no corresponding matching - // between LK_None/LK_Block and NSClassIdKindKind - case Sema::LK_Block: - case Sema::LK_None: - break; - } - llvm_unreachable("LiteralKind can't be converted into a ClassKind"); -} - -/// Validates ObjCInterfaceDecl availability. -/// ObjCInterfaceDecl, used to create ObjC literals, should be defined -/// if clang not in a debugger mode. -static bool ValidateObjCLiteralInterfaceDecl(Sema &S, ObjCInterfaceDecl *Decl, - SourceLocation Loc, - Sema::ObjCLiteralKind LiteralKind) { - if (!Decl) { - NSAPI::NSClassIdKindKind Kind = ClassKindFromLiteralKind(LiteralKind); - IdentifierInfo *II = S.NSAPIObj->getNSClassId(Kind); - S.Diag(Loc, diag::err_undeclared_objc_literal_class) - << II->getName() << LiteralKind; - return false; - } else if (!Decl->hasDefinition() && !S.getLangOpts().DebuggerObjCLiteral) { - S.Diag(Loc, diag::err_undeclared_objc_literal_class) - << Decl->getName() << LiteralKind; - S.Diag(Decl->getLocation(), diag::note_forward_class); - return false; - } - - return true; -} - -/// Looks up ObjCInterfaceDecl of a given NSClassIdKindKind. -/// Used to create ObjC literals, such as NSDictionary (@{}), -/// NSArray (@[]) and Boxed Expressions (@()) -static ObjCInterfaceDecl *LookupObjCInterfaceDeclForLiteral(Sema &S, - SourceLocation Loc, - Sema::ObjCLiteralKind LiteralKind) { - NSAPI::NSClassIdKindKind ClassKind = ClassKindFromLiteralKind(LiteralKind); - IdentifierInfo *II = S.NSAPIObj->getNSClassId(ClassKind); - NamedDecl *IF = S.LookupSingleName(S.TUScope, II, Loc, - Sema::LookupOrdinaryName); - ObjCInterfaceDecl *ID = dyn_cast_or_null<ObjCInterfaceDecl>(IF); - if (!ID && S.getLangOpts().DebuggerObjCLiteral) { - ASTContext &Context = S.Context; - TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); - ID = ObjCInterfaceDecl::Create (Context, TU, SourceLocation(), II, - nullptr, nullptr, SourceLocation()); - } - - if (!ValidateObjCLiteralInterfaceDecl(S, ID, Loc, LiteralKind)) { - ID = nullptr; - } - - return ID; -} - -/// Retrieve the NSNumber factory method that should be used to create -/// an Objective-C literal for the given type. -static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, - QualType NumberType, - bool isLiteral = false, - SourceRange R = SourceRange()) { - Optional<NSAPI::NSNumberLiteralMethodKind> Kind = - S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType); - - if (!Kind) { - if (isLiteral) { - S.Diag(Loc, diag::err_invalid_nsnumber_type) - << NumberType << R; - } - return nullptr; - } - - // If we already looked up this method, we're done. - if (S.NSNumberLiteralMethods[*Kind]) - return S.NSNumberLiteralMethods[*Kind]; - - Selector Sel = S.NSAPIObj->getNSNumberLiteralSelector(*Kind, - /*Instance=*/false); - - ASTContext &CX = S.Context; - - // Look up the NSNumber class, if we haven't done so already. It's cached - // in the Sema instance. - if (!S.NSNumberDecl) { - S.NSNumberDecl = LookupObjCInterfaceDeclForLiteral(S, Loc, - Sema::LK_Numeric); - if (!S.NSNumberDecl) { - return nullptr; - } - } - - if (S.NSNumberPointer.isNull()) { - // generate the pointer to NSNumber type. - QualType NSNumberObject = CX.getObjCInterfaceType(S.NSNumberDecl); - S.NSNumberPointer = CX.getObjCObjectPointerType(NSNumberObject); - } - - // Look for the appropriate method within NSNumber. - ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel); - if (!Method && S.getLangOpts().DebuggerObjCLiteral) { - // create a stub definition this NSNumber factory method. - TypeSourceInfo *ReturnTInfo = nullptr; - Method = - ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel, - S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl, - /*isInstance=*/false, /*isVariadic=*/false, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, ObjCMethodDecl::Required, - /*HasRelatedResultType=*/false); - ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method, - SourceLocation(), SourceLocation(), - &CX.Idents.get("value"), - NumberType, /*TInfo=*/nullptr, - SC_None, nullptr); - Method->setMethodParams(S.Context, value, None); - } - - if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method)) - return nullptr; - - // Note: if the parameter type is out-of-line, we'll catch it later in the - // implicit conversion. - - S.NSNumberLiteralMethods[*Kind] = Method; - return Method; -} - -/// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the -/// numeric literal expression. Type of the expression will be "NSNumber *". -ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) { - // Determine the type of the literal. - QualType NumberType = Number->getType(); - if (CharacterLiteral *Char = dyn_cast<CharacterLiteral>(Number)) { - // In C, character literals have type 'int'. That's not the type we want - // to use to determine the Objective-c literal kind. - switch (Char->getKind()) { - case CharacterLiteral::Ascii: - case CharacterLiteral::UTF8: - NumberType = Context.CharTy; - break; - - case CharacterLiteral::Wide: - NumberType = Context.getWideCharType(); - break; - - case CharacterLiteral::UTF16: - NumberType = Context.Char16Ty; - break; - - case CharacterLiteral::UTF32: - NumberType = Context.Char32Ty; - break; - } - } - - // Look for the appropriate method within NSNumber. - // Construct the literal. - SourceRange NR(Number->getSourceRange()); - ObjCMethodDecl *Method = getNSNumberFactoryMethod(*this, AtLoc, NumberType, - true, NR); - if (!Method) - return ExprError(); - - // Convert the number to the type that the parameter expects. - ParmVarDecl *ParamDecl = Method->parameters()[0]; - InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - ParamDecl); - ExprResult ConvertedNumber = PerformCopyInitialization(Entity, - SourceLocation(), - Number); - if (ConvertedNumber.isInvalid()) - return ExprError(); - Number = ConvertedNumber.get(); - - // Use the effective source range of the literal, including the leading '@'. - return MaybeBindToTemporary( - new (Context) ObjCBoxedExpr(Number, NSNumberPointer, Method, - SourceRange(AtLoc, NR.getEnd()))); -} - -ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc, - SourceLocation ValueLoc, - bool Value) { - ExprResult Inner; - if (getLangOpts().CPlusPlus) { - Inner = ActOnCXXBoolLiteral(ValueLoc, Value? tok::kw_true : tok::kw_false); - } else { - // C doesn't actually have a way to represent literal values of type - // _Bool. So, we'll use 0/1 and implicit cast to _Bool. - Inner = ActOnIntegerConstant(ValueLoc, Value? 1 : 0); - Inner = ImpCastExprToType(Inner.get(), Context.BoolTy, - CK_IntegralToBoolean); - } - - return BuildObjCNumericLiteral(AtLoc, Inner.get()); -} - -/// Check that the given expression is a valid element of an Objective-C -/// collection literal. -static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, - QualType T, - bool ArrayLiteral = false) { - // If the expression is type-dependent, there's nothing for us to do. - if (Element->isTypeDependent()) - return Element; - - ExprResult Result = S.CheckPlaceholderExpr(Element); - if (Result.isInvalid()) - return ExprError(); - Element = Result.get(); - - // In C++, check for an implicit conversion to an Objective-C object pointer - // type. - if (S.getLangOpts().CPlusPlus && Element->getType()->isRecordType()) { - InitializedEntity Entity - = InitializedEntity::InitializeParameter(S.Context, T, - /*Consumed=*/false); - InitializationKind Kind = InitializationKind::CreateCopy( - Element->getBeginLoc(), SourceLocation()); - InitializationSequence Seq(S, Entity, Kind, Element); - if (!Seq.Failed()) - return Seq.Perform(S, Entity, Kind, Element); - } - - Expr *OrigElement = Element; - - // Perform lvalue-to-rvalue conversion. - Result = S.DefaultLvalueConversion(Element); - if (Result.isInvalid()) - return ExprError(); - Element = Result.get(); - - // Make sure that we have an Objective-C pointer type or block. - if (!Element->getType()->isObjCObjectPointerType() && - !Element->getType()->isBlockPointerType()) { - bool Recovered = false; - - // If this is potentially an Objective-C numeric literal, add the '@'. - if (isa<IntegerLiteral>(OrigElement) || - isa<CharacterLiteral>(OrigElement) || - isa<FloatingLiteral>(OrigElement) || - isa<ObjCBoolLiteralExpr>(OrigElement) || - isa<CXXBoolLiteralExpr>(OrigElement)) { - if (S.NSAPIObj->getNSNumberFactoryMethodKind(OrigElement->getType())) { - int Which = isa<CharacterLiteral>(OrigElement) ? 1 - : (isa<CXXBoolLiteralExpr>(OrigElement) || - isa<ObjCBoolLiteralExpr>(OrigElement)) ? 2 - : 3; - - S.Diag(OrigElement->getBeginLoc(), diag::err_box_literal_collection) - << Which << OrigElement->getSourceRange() - << FixItHint::CreateInsertion(OrigElement->getBeginLoc(), "@"); - - Result = - S.BuildObjCNumericLiteral(OrigElement->getBeginLoc(), OrigElement); - if (Result.isInvalid()) - return ExprError(); - - Element = Result.get(); - Recovered = true; - } - } - // If this is potentially an Objective-C string literal, add the '@'. - else if (StringLiteral *String = dyn_cast<StringLiteral>(OrigElement)) { - if (String->isAscii()) { - S.Diag(OrigElement->getBeginLoc(), diag::err_box_literal_collection) - << 0 << OrigElement->getSourceRange() - << FixItHint::CreateInsertion(OrigElement->getBeginLoc(), "@"); - - Result = S.BuildObjCStringLiteral(OrigElement->getBeginLoc(), String); - if (Result.isInvalid()) - return ExprError(); - - Element = Result.get(); - Recovered = true; - } - } - - if (!Recovered) { - S.Diag(Element->getBeginLoc(), diag::err_invalid_collection_element) - << Element->getType(); - return ExprError(); - } - } - if (ArrayLiteral) - if (ObjCStringLiteral *getString = - dyn_cast<ObjCStringLiteral>(OrigElement)) { - if (StringLiteral *SL = getString->getString()) { - unsigned numConcat = SL->getNumConcatenated(); - if (numConcat > 1) { - // Only warn if the concatenated string doesn't come from a macro. - bool hasMacro = false; - for (unsigned i = 0; i < numConcat ; ++i) - if (SL->getStrTokenLoc(i).isMacroID()) { - hasMacro = true; - break; - } - if (!hasMacro) - S.Diag(Element->getBeginLoc(), - diag::warn_concatenated_nsarray_literal) - << Element->getType(); - } - } - } - - // Make sure that the element has the type that the container factory - // function expects. - return S.PerformCopyInitialization( - InitializedEntity::InitializeParameter(S.Context, T, - /*Consumed=*/false), - Element->getBeginLoc(), Element); -} - -ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { - if (ValueExpr->isTypeDependent()) { - ObjCBoxedExpr *BoxedExpr = - new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, nullptr, SR); - return BoxedExpr; - } - ObjCMethodDecl *BoxingMethod = nullptr; - QualType BoxedType; - // Convert the expression to an RValue, so we can check for pointer types... - ExprResult RValue = DefaultFunctionArrayLvalueConversion(ValueExpr); - if (RValue.isInvalid()) { - return ExprError(); - } - SourceLocation Loc = SR.getBegin(); - ValueExpr = RValue.get(); - QualType ValueType(ValueExpr->getType()); - if (const PointerType *PT = ValueType->getAs<PointerType>()) { - QualType PointeeType = PT->getPointeeType(); - if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) { - - if (!NSStringDecl) { - NSStringDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc, - Sema::LK_String); - if (!NSStringDecl) { - return ExprError(); - } - QualType NSStringObject = Context.getObjCInterfaceType(NSStringDecl); - NSStringPointer = Context.getObjCObjectPointerType(NSStringObject); - } - - if (!StringWithUTF8StringMethod) { - IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String"); - Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II); - - // Look for the appropriate method within NSString. - BoxingMethod = NSStringDecl->lookupClassMethod(stringWithUTF8String); - if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) { - // Debugger needs to work even if NSString hasn't been defined. - TypeSourceInfo *ReturnTInfo = nullptr; - ObjCMethodDecl *M = ObjCMethodDecl::Create( - Context, SourceLocation(), SourceLocation(), stringWithUTF8String, - NSStringPointer, ReturnTInfo, NSStringDecl, - /*isInstance=*/false, /*isVariadic=*/false, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, ObjCMethodDecl::Required, - /*HasRelatedResultType=*/false); - QualType ConstCharType = Context.CharTy.withConst(); - ParmVarDecl *value = - ParmVarDecl::Create(Context, M, - SourceLocation(), SourceLocation(), - &Context.Idents.get("value"), - Context.getPointerType(ConstCharType), - /*TInfo=*/nullptr, - SC_None, nullptr); - M->setMethodParams(Context, value, None); - BoxingMethod = M; - } - - if (!validateBoxingMethod(*this, Loc, NSStringDecl, - stringWithUTF8String, BoxingMethod)) - return ExprError(); - - StringWithUTF8StringMethod = BoxingMethod; - } - - BoxingMethod = StringWithUTF8StringMethod; - BoxedType = NSStringPointer; - // Transfer the nullability from method's return type. - Optional<NullabilityKind> Nullability = - BoxingMethod->getReturnType()->getNullability(Context); - if (Nullability) - BoxedType = Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*Nullability), BoxedType, - BoxedType); - } - } else if (ValueType->isBuiltinType()) { - // The other types we support are numeric, char and BOOL/bool. We could also - // provide limited support for structure types, such as NSRange, NSRect, and - // NSSize. See NSValue (NSValueGeometryExtensions) in <Foundation/NSGeometry.h> - // for more details. - - // Check for a top-level character literal. - if (const CharacterLiteral *Char = - dyn_cast<CharacterLiteral>(ValueExpr->IgnoreParens())) { - // In C, character literals have type 'int'. That's not the type we want - // to use to determine the Objective-c literal kind. - switch (Char->getKind()) { - case CharacterLiteral::Ascii: - case CharacterLiteral::UTF8: - ValueType = Context.CharTy; - break; - - case CharacterLiteral::Wide: - ValueType = Context.getWideCharType(); - break; - - case CharacterLiteral::UTF16: - ValueType = Context.Char16Ty; - break; - - case CharacterLiteral::UTF32: - ValueType = Context.Char32Ty; - break; - } - } - // FIXME: Do I need to do anything special with BoolTy expressions? - - // Look for the appropriate method within NSNumber. - BoxingMethod = getNSNumberFactoryMethod(*this, Loc, ValueType); - BoxedType = NSNumberPointer; - } else if (const EnumType *ET = ValueType->getAs<EnumType>()) { - if (!ET->getDecl()->isComplete()) { - Diag(Loc, diag::err_objc_incomplete_boxed_expression_type) - << ValueType << ValueExpr->getSourceRange(); - return ExprError(); - } - - BoxingMethod = getNSNumberFactoryMethod(*this, Loc, - ET->getDecl()->getIntegerType()); - BoxedType = NSNumberPointer; - } else if (ValueType->isObjCBoxableRecordType()) { - // Support for structure types, that marked as objc_boxable - // struct __attribute__((objc_boxable)) s { ... }; - - // Look up the NSValue class, if we haven't done so already. It's cached - // in the Sema instance. - if (!NSValueDecl) { - NSValueDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc, - Sema::LK_Boxed); - if (!NSValueDecl) { - return ExprError(); - } - - // generate the pointer to NSValue type. - QualType NSValueObject = Context.getObjCInterfaceType(NSValueDecl); - NSValuePointer = Context.getObjCObjectPointerType(NSValueObject); - } - - if (!ValueWithBytesObjCTypeMethod) { - IdentifierInfo *II[] = { - &Context.Idents.get("valueWithBytes"), - &Context.Idents.get("objCType") - }; - Selector ValueWithBytesObjCType = Context.Selectors.getSelector(2, II); - - // Look for the appropriate method within NSValue. - BoxingMethod = NSValueDecl->lookupClassMethod(ValueWithBytesObjCType); - if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) { - // Debugger needs to work even if NSValue hasn't been defined. - TypeSourceInfo *ReturnTInfo = nullptr; - ObjCMethodDecl *M = ObjCMethodDecl::Create( - Context, - SourceLocation(), - SourceLocation(), - ValueWithBytesObjCType, - NSValuePointer, - ReturnTInfo, - NSValueDecl, - /*isInstance=*/false, - /*isVariadic=*/false, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, - ObjCMethodDecl::Required, - /*HasRelatedResultType=*/false); - - SmallVector<ParmVarDecl *, 2> Params; - - ParmVarDecl *bytes = - ParmVarDecl::Create(Context, M, - SourceLocation(), SourceLocation(), - &Context.Idents.get("bytes"), - Context.VoidPtrTy.withConst(), - /*TInfo=*/nullptr, - SC_None, nullptr); - Params.push_back(bytes); - - QualType ConstCharType = Context.CharTy.withConst(); - ParmVarDecl *type = - ParmVarDecl::Create(Context, M, - SourceLocation(), SourceLocation(), - &Context.Idents.get("type"), - Context.getPointerType(ConstCharType), - /*TInfo=*/nullptr, - SC_None, nullptr); - Params.push_back(type); - - M->setMethodParams(Context, Params, None); - BoxingMethod = M; - } - - if (!validateBoxingMethod(*this, Loc, NSValueDecl, - ValueWithBytesObjCType, BoxingMethod)) - return ExprError(); - - ValueWithBytesObjCTypeMethod = BoxingMethod; - } - - if (!ValueType.isTriviallyCopyableType(Context)) { - Diag(Loc, diag::err_objc_non_trivially_copyable_boxed_expression_type) - << ValueType << ValueExpr->getSourceRange(); - return ExprError(); - } - - BoxingMethod = ValueWithBytesObjCTypeMethod; - BoxedType = NSValuePointer; - } - - if (!BoxingMethod) { - Diag(Loc, diag::err_objc_illegal_boxed_expression_type) - << ValueType << ValueExpr->getSourceRange(); - return ExprError(); - } - - DiagnoseUseOfDecl(BoxingMethod, Loc); - - ExprResult ConvertedValueExpr; - if (ValueType->isObjCBoxableRecordType()) { - InitializedEntity IE = InitializedEntity::InitializeTemporary(ValueType); - ConvertedValueExpr = PerformCopyInitialization(IE, ValueExpr->getExprLoc(), - ValueExpr); - } else { - // Convert the expression to the type that the parameter requires. - ParmVarDecl *ParamDecl = BoxingMethod->parameters()[0]; - InitializedEntity IE = InitializedEntity::InitializeParameter(Context, - ParamDecl); - ConvertedValueExpr = PerformCopyInitialization(IE, SourceLocation(), - ValueExpr); - } - - if (ConvertedValueExpr.isInvalid()) - return ExprError(); - ValueExpr = ConvertedValueExpr.get(); - - ObjCBoxedExpr *BoxedExpr = - new (Context) ObjCBoxedExpr(ValueExpr, BoxedType, - BoxingMethod, SR); - return MaybeBindToTemporary(BoxedExpr); -} - -/// Build an ObjC subscript pseudo-object expression, given that -/// that's supported by the runtime. -ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, - Expr *IndexExpr, - ObjCMethodDecl *getterMethod, - ObjCMethodDecl *setterMethod) { - assert(!LangOpts.isSubscriptPointerArithmetic()); - - // We can't get dependent types here; our callers should have - // filtered them out. - assert((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) && - "base or index cannot have dependent type here"); - - // Filter out placeholders in the index. In theory, overloads could - // be preserved here, although that might not actually work correctly. - ExprResult Result = CheckPlaceholderExpr(IndexExpr); - if (Result.isInvalid()) - return ExprError(); - IndexExpr = Result.get(); - - // Perform lvalue-to-rvalue conversion on the base. - Result = DefaultLvalueConversion(BaseExpr); - if (Result.isInvalid()) - return ExprError(); - BaseExpr = Result.get(); - - // Build the pseudo-object expression. - return new (Context) ObjCSubscriptRefExpr( - BaseExpr, IndexExpr, Context.PseudoObjectTy, VK_LValue, OK_ObjCSubscript, - getterMethod, setterMethod, RB); -} - -ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { - SourceLocation Loc = SR.getBegin(); - - if (!NSArrayDecl) { - NSArrayDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc, - Sema::LK_Array); - if (!NSArrayDecl) { - return ExprError(); - } - } - - // Find the arrayWithObjects:count: method, if we haven't done so already. - QualType IdT = Context.getObjCIdType(); - if (!ArrayWithObjectsMethod) { - Selector - Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount); - ObjCMethodDecl *Method = NSArrayDecl->lookupClassMethod(Sel); - if (!Method && getLangOpts().DebuggerObjCLiteral) { - TypeSourceInfo *ReturnTInfo = nullptr; - Method = ObjCMethodDecl::Create( - Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo, - Context.getTranslationUnitDecl(), false /*Instance*/, - false /*isVariadic*/, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - ObjCMethodDecl::Required, false); - SmallVector<ParmVarDecl *, 2> Params; - ParmVarDecl *objects = ParmVarDecl::Create(Context, Method, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("objects"), - Context.getPointerType(IdT), - /*TInfo=*/nullptr, - SC_None, nullptr); - Params.push_back(objects); - ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("cnt"), - Context.UnsignedLongTy, - /*TInfo=*/nullptr, SC_None, - nullptr); - Params.push_back(cnt); - Method->setMethodParams(Context, Params, None); - } - - if (!validateBoxingMethod(*this, Loc, NSArrayDecl, Sel, Method)) - return ExprError(); - - // Dig out the type that all elements should be converted to. - QualType T = Method->parameters()[0]->getType(); - const PointerType *PtrT = T->getAs<PointerType>(); - if (!PtrT || - !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << Sel; - Diag(Method->parameters()[0]->getLocation(), - diag::note_objc_literal_method_param) - << 0 << T - << Context.getPointerType(IdT.withConst()); - return ExprError(); - } - - // Check that the 'count' parameter is integral. - if (!Method->parameters()[1]->getType()->isIntegerType()) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << Sel; - Diag(Method->parameters()[1]->getLocation(), - diag::note_objc_literal_method_param) - << 1 - << Method->parameters()[1]->getType() - << "integral"; - return ExprError(); - } - - // We've found a good +arrayWithObjects:count: method. Save it! - ArrayWithObjectsMethod = Method; - } - - QualType ObjectsType = ArrayWithObjectsMethod->parameters()[0]->getType(); - QualType RequiredType = ObjectsType->castAs<PointerType>()->getPointeeType(); - - // Check that each of the elements provided is valid in a collection literal, - // performing conversions as necessary. - Expr **ElementsBuffer = Elements.data(); - for (unsigned I = 0, N = Elements.size(); I != N; ++I) { - ExprResult Converted = CheckObjCCollectionLiteralElement(*this, - ElementsBuffer[I], - RequiredType, true); - if (Converted.isInvalid()) - return ExprError(); - - ElementsBuffer[I] = Converted.get(); - } - - QualType Ty - = Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(NSArrayDecl)); - - return MaybeBindToTemporary( - ObjCArrayLiteral::Create(Context, Elements, Ty, - ArrayWithObjectsMethod, SR)); -} - -ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, - MutableArrayRef<ObjCDictionaryElement> Elements) { - SourceLocation Loc = SR.getBegin(); - - if (!NSDictionaryDecl) { - NSDictionaryDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc, - Sema::LK_Dictionary); - if (!NSDictionaryDecl) { - return ExprError(); - } - } - - // Find the dictionaryWithObjects:forKeys:count: method, if we haven't done - // so already. - QualType IdT = Context.getObjCIdType(); - if (!DictionaryWithObjectsMethod) { - Selector Sel = NSAPIObj->getNSDictionarySelector( - NSAPI::NSDict_dictionaryWithObjectsForKeysCount); - ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel); - if (!Method && getLangOpts().DebuggerObjCLiteral) { - Method = ObjCMethodDecl::Create(Context, - SourceLocation(), SourceLocation(), Sel, - IdT, - nullptr /*TypeSourceInfo */, - Context.getTranslationUnitDecl(), - false /*Instance*/, false/*isVariadic*/, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - ObjCMethodDecl::Required, - false); - SmallVector<ParmVarDecl *, 3> Params; - ParmVarDecl *objects = ParmVarDecl::Create(Context, Method, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("objects"), - Context.getPointerType(IdT), - /*TInfo=*/nullptr, SC_None, - nullptr); - Params.push_back(objects); - ParmVarDecl *keys = ParmVarDecl::Create(Context, Method, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("keys"), - Context.getPointerType(IdT), - /*TInfo=*/nullptr, SC_None, - nullptr); - Params.push_back(keys); - ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("cnt"), - Context.UnsignedLongTy, - /*TInfo=*/nullptr, SC_None, - nullptr); - Params.push_back(cnt); - Method->setMethodParams(Context, Params, None); - } - - if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel, - Method)) - return ExprError(); - - // Dig out the type that all values should be converted to. - QualType ValueT = Method->parameters()[0]->getType(); - const PointerType *PtrValue = ValueT->getAs<PointerType>(); - if (!PtrValue || - !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << Sel; - Diag(Method->parameters()[0]->getLocation(), - diag::note_objc_literal_method_param) - << 0 << ValueT - << Context.getPointerType(IdT.withConst()); - return ExprError(); - } - - // Dig out the type that all keys should be converted to. - QualType KeyT = Method->parameters()[1]->getType(); - const PointerType *PtrKey = KeyT->getAs<PointerType>(); - if (!PtrKey || - !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(), - IdT)) { - bool err = true; - if (PtrKey) { - if (QIDNSCopying.isNull()) { - // key argument of selector is id<NSCopying>? - if (ObjCProtocolDecl *NSCopyingPDecl = - LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { - ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; - QIDNSCopying = - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, - llvm::makeArrayRef( - (ObjCProtocolDecl**) PQ, - 1), - false); - QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); - } - } - if (!QIDNSCopying.isNull()) - err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(), - QIDNSCopying); - } - - if (err) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << Sel; - Diag(Method->parameters()[1]->getLocation(), - diag::note_objc_literal_method_param) - << 1 << KeyT - << Context.getPointerType(IdT.withConst()); - return ExprError(); - } - } - - // Check that the 'count' parameter is integral. - QualType CountType = Method->parameters()[2]->getType(); - if (!CountType->isIntegerType()) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << Sel; - Diag(Method->parameters()[2]->getLocation(), - diag::note_objc_literal_method_param) - << 2 << CountType - << "integral"; - return ExprError(); - } - - // We've found a good +dictionaryWithObjects:keys:count: method; save it! - DictionaryWithObjectsMethod = Method; - } - - QualType ValuesT = DictionaryWithObjectsMethod->parameters()[0]->getType(); - QualType ValueT = ValuesT->castAs<PointerType>()->getPointeeType(); - QualType KeysT = DictionaryWithObjectsMethod->parameters()[1]->getType(); - QualType KeyT = KeysT->castAs<PointerType>()->getPointeeType(); - - // Check that each of the keys and values provided is valid in a collection - // literal, performing conversions as necessary. - bool HasPackExpansions = false; - for (ObjCDictionaryElement &Element : Elements) { - // Check the key. - ExprResult Key = CheckObjCCollectionLiteralElement(*this, Element.Key, - KeyT); - if (Key.isInvalid()) - return ExprError(); - - // Check the value. - ExprResult Value - = CheckObjCCollectionLiteralElement(*this, Element.Value, ValueT); - if (Value.isInvalid()) - return ExprError(); - - Element.Key = Key.get(); - Element.Value = Value.get(); - - if (Element.EllipsisLoc.isInvalid()) - continue; - - if (!Element.Key->containsUnexpandedParameterPack() && - !Element.Value->containsUnexpandedParameterPack()) { - Diag(Element.EllipsisLoc, - diag::err_pack_expansion_without_parameter_packs) - << SourceRange(Element.Key->getBeginLoc(), - Element.Value->getEndLoc()); - return ExprError(); - } - - HasPackExpansions = true; - } - - QualType Ty - = Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(NSDictionaryDecl)); - return MaybeBindToTemporary(ObjCDictionaryLiteral::Create( - Context, Elements, HasPackExpansions, Ty, - DictionaryWithObjectsMethod, SR)); -} - -ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, - TypeSourceInfo *EncodedTypeInfo, - SourceLocation RParenLoc) { - QualType EncodedType = EncodedTypeInfo->getType(); - QualType StrTy; - if (EncodedType->isDependentType()) - StrTy = Context.DependentTy; - else { - if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled. - !EncodedType->isVoidType()) // void is handled too. - if (RequireCompleteType(AtLoc, EncodedType, - diag::err_incomplete_type_objc_at_encode, - EncodedTypeInfo->getTypeLoc())) - return ExprError(); - - std::string Str; - QualType NotEncodedT; - Context.getObjCEncodingForType(EncodedType, Str, nullptr, &NotEncodedT); - if (!NotEncodedT.isNull()) - Diag(AtLoc, diag::warn_incomplete_encoded_type) - << EncodedType << NotEncodedT; - - // The type of @encode is the same as the type of the corresponding string, - // which is an array type. - StrTy = Context.CharTy; - // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). - if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings) - StrTy.addConst(); - StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1), - ArrayType::Normal, 0); - } - - return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc); -} - -ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, - SourceLocation EncodeLoc, - SourceLocation LParenLoc, - ParsedType ty, - SourceLocation RParenLoc) { - // FIXME: Preserve type source info ? - TypeSourceInfo *TInfo; - QualType EncodedType = GetTypeFromParser(ty, &TInfo); - if (!TInfo) - TInfo = Context.getTrivialTypeSourceInfo(EncodedType, - getLocForEndOfToken(LParenLoc)); - - return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc); -} - -static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, - SourceLocation AtLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc, - ObjCMethodDecl *Method, - ObjCMethodList &MethList) { - ObjCMethodList *M = &MethList; - bool Warned = false; - for (M = M->getNext(); M; M=M->getNext()) { - ObjCMethodDecl *MatchingMethodDecl = M->getMethod(); - if (MatchingMethodDecl == Method || - isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()) || - MatchingMethodDecl->getSelector() != Method->getSelector()) - continue; - if (!S.MatchTwoMethodDeclarations(Method, - MatchingMethodDecl, Sema::MMS_loose)) { - if (!Warned) { - Warned = true; - S.Diag(AtLoc, diag::warn_multiple_selectors) - << Method->getSelector() << FixItHint::CreateInsertion(LParenLoc, "(") - << FixItHint::CreateInsertion(RParenLoc, ")"); - S.Diag(Method->getLocation(), diag::note_method_declared_at) - << Method->getDeclName(); - } - S.Diag(MatchingMethodDecl->getLocation(), diag::note_method_declared_at) - << MatchingMethodDecl->getDeclName(); - } - } - return Warned; -} - -static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc, - ObjCMethodDecl *Method, - SourceLocation LParenLoc, - SourceLocation RParenLoc, - bool WarnMultipleSelectors) { - if (!WarnMultipleSelectors || - S.Diags.isIgnored(diag::warn_multiple_selectors, SourceLocation())) - return; - bool Warned = false; - for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(), - e = S.MethodPool.end(); b != e; b++) { - // first, instance methods - ObjCMethodList &InstMethList = b->second.first; - if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc, - Method, InstMethList)) - Warned = true; - - // second, class methods - ObjCMethodList &ClsMethList = b->second.second; - if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc, - Method, ClsMethList) || Warned) - return; - } -} - -ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, - SourceLocation AtLoc, - SourceLocation SelLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc, - bool WarnMultipleSelectors) { - ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LParenLoc, RParenLoc)); - if (!Method) - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LParenLoc, RParenLoc)); - if (!Method) { - if (const ObjCMethodDecl *OM = SelectorsForTypoCorrection(Sel)) { - Selector MatchedSel = OM->getSelector(); - SourceRange SelectorRange(LParenLoc.getLocWithOffset(1), - RParenLoc.getLocWithOffset(-1)); - Diag(SelLoc, diag::warn_undeclared_selector_with_typo) - << Sel << MatchedSel - << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); - - } else - Diag(SelLoc, diag::warn_undeclared_selector) << Sel; - } else - DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc, - WarnMultipleSelectors); - - if (Method && - Method->getImplementationControl() != ObjCMethodDecl::Optional && - !getSourceManager().isInSystemHeader(Method->getLocation())) - ReferencedSelectors.insert(std::make_pair(Sel, AtLoc)); - - // In ARC, forbid the user from using @selector for - // retain/release/autorelease/dealloc/retainCount. - if (getLangOpts().ObjCAutoRefCount) { - switch (Sel.getMethodFamily()) { - case OMF_retain: - case OMF_release: - case OMF_autorelease: - case OMF_retainCount: - case OMF_dealloc: - Diag(AtLoc, diag::err_arc_illegal_selector) << - Sel << SourceRange(LParenLoc, RParenLoc); - break; - - case OMF_None: - case OMF_alloc: - case OMF_copy: - case OMF_finalize: - case OMF_init: - case OMF_mutableCopy: - case OMF_new: - case OMF_self: - case OMF_initialize: - case OMF_performSelector: - break; - } - } - QualType Ty = Context.getObjCSelType(); - return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc); -} - -ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, - SourceLocation AtLoc, - SourceLocation ProtoLoc, - SourceLocation LParenLoc, - SourceLocation ProtoIdLoc, - SourceLocation RParenLoc) { - ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoIdLoc); - if (!PDecl) { - Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; - return true; - } - if (!PDecl->hasDefinition()) { - Diag(ProtoLoc, diag::err_atprotocol_protocol) << PDecl; - Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl; - } else { - PDecl = PDecl->getDefinition(); - } - - QualType Ty = Context.getObjCProtoType(); - if (Ty.isNull()) - return true; - Ty = Context.getObjCObjectPointerType(Ty); - return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, ProtoIdLoc, RParenLoc); -} - -/// Try to capture an implicit reference to 'self'. -ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) { - DeclContext *DC = getFunctionLevelDeclContext(); - - // If we're not in an ObjC method, error out. Note that, unlike the - // C++ case, we don't require an instance method --- class methods - // still have a 'self', and we really do still need to capture it! - ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(DC); - if (!method) - return nullptr; - - tryCaptureVariable(method->getSelfDecl(), Loc); - - return method; -} - -static QualType stripObjCInstanceType(ASTContext &Context, QualType T) { - QualType origType = T; - if (auto nullability = AttributedType::stripOuterNullability(T)) { - if (T == Context.getObjCInstanceType()) { - return Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*nullability), - Context.getObjCIdType(), - Context.getObjCIdType()); - } - - return origType; - } - - if (T == Context.getObjCInstanceType()) - return Context.getObjCIdType(); - - return origType; -} - -/// Determine the result type of a message send based on the receiver type, -/// method, and the kind of message send. -/// -/// This is the "base" result type, which will still need to be adjusted -/// to account for nullability. -static QualType getBaseMessageSendResultType(Sema &S, - QualType ReceiverType, - ObjCMethodDecl *Method, - bool isClassMessage, - bool isSuperMessage) { - assert(Method && "Must have a method"); - if (!Method->hasRelatedResultType()) - return Method->getSendResultType(ReceiverType); - - ASTContext &Context = S.Context; - - // Local function that transfers the nullability of the method's - // result type to the returned result. - auto transferNullability = [&](QualType type) -> QualType { - // If the method's result type has nullability, extract it. - if (auto nullability = Method->getSendResultType(ReceiverType) - ->getNullability(Context)){ - // Strip off any outer nullability sugar from the provided type. - (void)AttributedType::stripOuterNullability(type); - - // Form a new attributed type using the method result type's nullability. - return Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*nullability), - type, - type); - } - - return type; - }; - - // If a method has a related return type: - // - if the method found is an instance method, but the message send - // was a class message send, T is the declared return type of the method - // found - if (Method->isInstanceMethod() && isClassMessage) - return stripObjCInstanceType(Context, - Method->getSendResultType(ReceiverType)); - - // - if the receiver is super, T is a pointer to the class of the - // enclosing method definition - if (isSuperMessage) { - if (ObjCMethodDecl *CurMethod = S.getCurMethodDecl()) - if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) { - return transferNullability( - Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(Class))); - } - } - - // - if the receiver is the name of a class U, T is a pointer to U - if (ReceiverType->getAsObjCInterfaceType()) - return transferNullability(Context.getObjCObjectPointerType(ReceiverType)); - // - if the receiver is of type Class or qualified Class type, - // T is the declared return type of the method. - if (ReceiverType->isObjCClassType() || - ReceiverType->isObjCQualifiedClassType()) - return stripObjCInstanceType(Context, - Method->getSendResultType(ReceiverType)); - - // - if the receiver is id, qualified id, Class, or qualified Class, T - // is the receiver type, otherwise - // - T is the type of the receiver expression. - return transferNullability(ReceiverType); -} - -QualType Sema::getMessageSendResultType(const Expr *Receiver, - QualType ReceiverType, - ObjCMethodDecl *Method, - bool isClassMessage, - bool isSuperMessage) { - // Produce the result type. - QualType resultType = getBaseMessageSendResultType(*this, ReceiverType, - Method, - isClassMessage, - isSuperMessage); - - // If this is a class message, ignore the nullability of the receiver. - if (isClassMessage) { - // In a class method, class messages to 'self' that return instancetype can - // be typed as the current class. We can safely do this in ARC because self - // can't be reassigned, and we do it unsafely outside of ARC because in - // practice people never reassign self in class methods and there's some - // virtue in not being aggressively pedantic. - if (Receiver && Receiver->isObjCSelfExpr()) { - assert(ReceiverType->isObjCClassType() && "expected a Class self"); - QualType T = Method->getSendResultType(ReceiverType); - AttributedType::stripOuterNullability(T); - if (T == Context.getObjCInstanceType()) { - const ObjCMethodDecl *MD = cast<ObjCMethodDecl>( - cast<ImplicitParamDecl>( - cast<DeclRefExpr>(Receiver->IgnoreParenImpCasts())->getDecl()) - ->getDeclContext()); - assert(MD->isClassMethod() && "expected a class method"); - QualType NewResultType = Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(MD->getClassInterface())); - if (auto Nullability = resultType->getNullability(Context)) - NewResultType = Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*Nullability), - NewResultType, NewResultType); - return NewResultType; - } - } - return resultType; - } - - // There is nothing left to do if the result type cannot have a nullability - // specifier. - if (!resultType->canHaveNullability()) - return resultType; - - // Map the nullability of the result into a table index. - unsigned receiverNullabilityIdx = 0; - if (auto nullability = ReceiverType->getNullability(Context)) - receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability); - - unsigned resultNullabilityIdx = 0; - if (auto nullability = resultType->getNullability(Context)) - resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability); - - // The table of nullability mappings, indexed by the receiver's nullability - // and then the result type's nullability. - static const uint8_t None = 0; - static const uint8_t NonNull = 1; - static const uint8_t Nullable = 2; - static const uint8_t Unspecified = 3; - static const uint8_t nullabilityMap[4][4] = { - // None NonNull Nullable Unspecified - /* None */ { None, None, Nullable, None }, - /* NonNull */ { None, NonNull, Nullable, Unspecified }, - /* Nullable */ { Nullable, Nullable, Nullable, Nullable }, - /* Unspecified */ { None, Unspecified, Nullable, Unspecified } - }; - - unsigned newResultNullabilityIdx - = nullabilityMap[receiverNullabilityIdx][resultNullabilityIdx]; - if (newResultNullabilityIdx == resultNullabilityIdx) - return resultType; - - // Strip off the existing nullability. This removes as little type sugar as - // possible. - do { - if (auto attributed = dyn_cast<AttributedType>(resultType.getTypePtr())) { - resultType = attributed->getModifiedType(); - } else { - resultType = resultType.getDesugaredType(Context); - } - } while (resultType->getNullability(Context)); - - // Add nullability back if needed. - if (newResultNullabilityIdx > 0) { - auto newNullability - = static_cast<NullabilityKind>(newResultNullabilityIdx-1); - return Context.getAttributedType( - AttributedType::getNullabilityAttrKind(newNullability), - resultType, resultType); - } - - return resultType; -} - -/// Look for an ObjC method whose result type exactly matches the given type. -static const ObjCMethodDecl * -findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD, - QualType instancetype) { - if (MD->getReturnType() == instancetype) - return MD; - - // For these purposes, a method in an @implementation overrides a - // declaration in the @interface. - if (const ObjCImplDecl *impl = - dyn_cast<ObjCImplDecl>(MD->getDeclContext())) { - const ObjCContainerDecl *iface; - if (const ObjCCategoryImplDecl *catImpl = - dyn_cast<ObjCCategoryImplDecl>(impl)) { - iface = catImpl->getCategoryDecl(); - } else { - iface = impl->getClassInterface(); - } - - const ObjCMethodDecl *ifaceMD = - iface->getMethod(MD->getSelector(), MD->isInstanceMethod()); - if (ifaceMD) return findExplicitInstancetypeDeclarer(ifaceMD, instancetype); - } - - SmallVector<const ObjCMethodDecl *, 4> overrides; - MD->getOverriddenMethods(overrides); - for (unsigned i = 0, e = overrides.size(); i != e; ++i) { - if (const ObjCMethodDecl *result = - findExplicitInstancetypeDeclarer(overrides[i], instancetype)) - return result; - } - - return nullptr; -} - -void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) { - // Only complain if we're in an ObjC method and the required return - // type doesn't match the method's declared return type. - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurContext); - if (!MD || !MD->hasRelatedResultType() || - Context.hasSameUnqualifiedType(destType, MD->getReturnType())) - return; - - // Look for a method overridden by this method which explicitly uses - // 'instancetype'. - if (const ObjCMethodDecl *overridden = - findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) { - SourceRange range = overridden->getReturnTypeSourceRange(); - SourceLocation loc = range.getBegin(); - if (loc.isInvalid()) - loc = overridden->getLocation(); - Diag(loc, diag::note_related_result_type_explicit) - << /*current method*/ 1 << range; - return; - } - - // Otherwise, if we have an interesting method family, note that. - // This should always trigger if the above didn't. - if (ObjCMethodFamily family = MD->getMethodFamily()) - Diag(MD->getLocation(), diag::note_related_result_type_family) - << /*current method*/ 1 - << family; -} - -void Sema::EmitRelatedResultTypeNote(const Expr *E) { - E = E->IgnoreParenImpCasts(); - const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E); - if (!MsgSend) - return; - - const ObjCMethodDecl *Method = MsgSend->getMethodDecl(); - if (!Method) - return; - - if (!Method->hasRelatedResultType()) - return; - - if (Context.hasSameUnqualifiedType( - Method->getReturnType().getNonReferenceType(), MsgSend->getType())) - return; - - if (!Context.hasSameUnqualifiedType(Method->getReturnType(), - Context.getObjCInstanceType())) - return; - - Diag(Method->getLocation(), diag::note_related_result_type_inferred) - << Method->isInstanceMethod() << Method->getSelector() - << MsgSend->getType(); -} - -bool Sema::CheckMessageArgumentTypes( - const Expr *Receiver, QualType ReceiverType, MultiExprArg Args, - Selector Sel, ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method, - bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, - SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType, - ExprValueKind &VK) { - SourceLocation SelLoc; - if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) - SelLoc = SelectorLocs.front(); - else - SelLoc = lbrac; - - if (!Method) { - // Apply default argument promotion as for (C99 6.5.2.2p6). - for (unsigned i = 0, e = Args.size(); i != e; i++) { - if (Args[i]->isTypeDependent()) - continue; - - ExprResult result; - if (getLangOpts().DebuggerSupport) { - QualType paramTy; // ignored - result = checkUnknownAnyArg(SelLoc, Args[i], paramTy); - } else { - result = DefaultArgumentPromotion(Args[i]); - } - if (result.isInvalid()) - return true; - Args[i] = result.get(); - } - - unsigned DiagID; - if (getLangOpts().ObjCAutoRefCount) - DiagID = diag::err_arc_method_not_found; - else - DiagID = isClassMessage ? diag::warn_class_method_not_found - : diag::warn_inst_method_not_found; - if (!getLangOpts().DebuggerSupport) { - const ObjCMethodDecl *OMD = SelectorsForTypoCorrection(Sel, ReceiverType); - if (OMD && !OMD->isInvalidDecl()) { - if (getLangOpts().ObjCAutoRefCount) - DiagID = diag::err_method_not_found_with_typo; - else - DiagID = isClassMessage ? diag::warn_class_method_not_found_with_typo - : diag::warn_instance_method_not_found_with_typo; - Selector MatchedSel = OMD->getSelector(); - SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back()); - if (MatchedSel.isUnarySelector()) - Diag(SelLoc, DiagID) - << Sel<< isClassMessage << MatchedSel - << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); - else - Diag(SelLoc, DiagID) << Sel<< isClassMessage << MatchedSel; - } - else - Diag(SelLoc, DiagID) - << Sel << isClassMessage << SourceRange(SelectorLocs.front(), - SelectorLocs.back()); - // Find the class to which we are sending this message. - if (ReceiverType->isObjCObjectPointerType()) { - if (ObjCInterfaceDecl *ThisClass = - ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) { - Diag(ThisClass->getLocation(), diag::note_receiver_class_declared); - if (!RecRange.isInvalid()) - if (ThisClass->lookupClassMethod(Sel)) - Diag(RecRange.getBegin(),diag::note_receiver_expr_here) - << FixItHint::CreateReplacement(RecRange, - ThisClass->getNameAsString()); - } - } - } - - // In debuggers, we want to use __unknown_anytype for these - // results so that clients can cast them. - if (getLangOpts().DebuggerSupport) { - ReturnType = Context.UnknownAnyTy; - } else { - ReturnType = Context.getObjCIdType(); - } - VK = VK_RValue; - return false; - } - - ReturnType = getMessageSendResultType(Receiver, ReceiverType, Method, - isClassMessage, isSuperMessage); - VK = Expr::getValueKindForType(Method->getReturnType()); - - unsigned NumNamedArgs = Sel.getNumArgs(); - // Method might have more arguments than selector indicates. This is due - // to addition of c-style arguments in method. - if (Method->param_size() > Sel.getNumArgs()) - NumNamedArgs = Method->param_size(); - // FIXME. This need be cleaned up. - if (Args.size() < NumNamedArgs) { - Diag(SelLoc, diag::err_typecheck_call_too_few_args) - << 2 << NumNamedArgs << static_cast<unsigned>(Args.size()); - return false; - } - - // Compute the set of type arguments to be substituted into each parameter - // type. - Optional<ArrayRef<QualType>> typeArgs - = ReceiverType->getObjCSubstitutions(Method->getDeclContext()); - bool IsError = false; - for (unsigned i = 0; i < NumNamedArgs; i++) { - // We can't do any type-checking on a type-dependent argument. - if (Args[i]->isTypeDependent()) - continue; - - Expr *argExpr = Args[i]; - - ParmVarDecl *param = Method->parameters()[i]; - assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); - - if (param->hasAttr<NoEscapeAttr>()) - if (auto *BE = dyn_cast<BlockExpr>( - argExpr->IgnoreParenNoopCasts(Context))) - BE->getBlockDecl()->setDoesNotEscape(); - - // Strip the unbridged-cast placeholder expression off unless it's - // a consumed argument. - if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) && - !param->hasAttr<CFConsumedAttr>()) - argExpr = stripARCUnbridgedCast(argExpr); - - // If the parameter is __unknown_anytype, infer its type - // from the argument. - if (param->getType() == Context.UnknownAnyTy) { - QualType paramType; - ExprResult argE = checkUnknownAnyArg(SelLoc, argExpr, paramType); - if (argE.isInvalid()) { - IsError = true; - } else { - Args[i] = argE.get(); - - // Update the parameter type in-place. - param->setType(paramType); - } - continue; - } - - QualType origParamType = param->getType(); - QualType paramType = param->getType(); - if (typeArgs) - paramType = paramType.substObjCTypeArgs( - Context, - *typeArgs, - ObjCSubstitutionContext::Parameter); - - if (RequireCompleteType(argExpr->getSourceRange().getBegin(), - paramType, - diag::err_call_incomplete_argument, argExpr)) - return true; - - InitializedEntity Entity - = InitializedEntity::InitializeParameter(Context, param, paramType); - ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr); - if (ArgE.isInvalid()) - IsError = true; - else { - Args[i] = ArgE.getAs<Expr>(); - - // If we are type-erasing a block to a block-compatible - // Objective-C pointer type, we may need to extend the lifetime - // of the block object. - if (typeArgs && Args[i]->isRValue() && paramType->isBlockPointerType() && - Args[i]->getType()->isBlockPointerType() && - origParamType->isObjCObjectPointerType()) { - ExprResult arg = Args[i]; - maybeExtendBlockObject(arg); - Args[i] = arg.get(); - } - } - } - - // Promote additional arguments to variadic methods. - if (Method->isVariadic()) { - for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) { - if (Args[i]->isTypeDependent()) - continue; - - ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, - nullptr); - IsError |= Arg.isInvalid(); - Args[i] = Arg.get(); - } - } else { - // Check for extra arguments to non-variadic methods. - if (Args.size() != NumNamedArgs) { - Diag(Args[NumNamedArgs]->getBeginLoc(), - diag::err_typecheck_call_too_many_args) - << 2 /*method*/ << NumNamedArgs << static_cast<unsigned>(Args.size()) - << Method->getSourceRange() - << SourceRange(Args[NumNamedArgs]->getBeginLoc(), - Args.back()->getEndLoc()); - } - } - - DiagnoseSentinelCalls(Method, SelLoc, Args); - - // Do additional checkings on method. - IsError |= CheckObjCMethodCall( - Method, SelLoc, makeArrayRef(Args.data(), Args.size())); - - return IsError; -} - -bool Sema::isSelfExpr(Expr *RExpr) { - // 'self' is objc 'self' in an objc method only. - ObjCMethodDecl *Method = - dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor()); - return isSelfExpr(RExpr, Method); -} - -bool Sema::isSelfExpr(Expr *receiver, const ObjCMethodDecl *method) { - if (!method) return false; - - receiver = receiver->IgnoreParenLValueCasts(); - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver)) - if (DRE->getDecl() == method->getSelfDecl()) - return true; - return false; -} - -/// LookupMethodInType - Look up a method in an ObjCObjectType. -ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type, - bool isInstance) { - const ObjCObjectType *objType = type->castAs<ObjCObjectType>(); - if (ObjCInterfaceDecl *iface = objType->getInterface()) { - // Look it up in the main interface (and categories, etc.) - if (ObjCMethodDecl *method = iface->lookupMethod(sel, isInstance)) - return method; - - // Okay, look for "private" methods declared in any - // @implementations we've seen. - if (ObjCMethodDecl *method = iface->lookupPrivateMethod(sel, isInstance)) - return method; - } - - // Check qualifiers. - for (const auto *I : objType->quals()) - if (ObjCMethodDecl *method = I->lookupMethod(sel, isInstance)) - return method; - - return nullptr; -} - -/// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier -/// list of a qualified objective pointer type. -ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel, - const ObjCObjectPointerType *OPT, - bool Instance) -{ - ObjCMethodDecl *MD = nullptr; - for (const auto *PROTO : OPT->quals()) { - if ((MD = PROTO->lookupMethod(Sel, Instance))) { - return MD; - } - } - return nullptr; -} - -/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an -/// objective C interface. This is a property reference expression. -ExprResult Sema:: -HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, - Expr *BaseExpr, SourceLocation OpLoc, - DeclarationName MemberName, - SourceLocation MemberLoc, - SourceLocation SuperLoc, QualType SuperType, - bool Super) { - const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); - ObjCInterfaceDecl *IFace = IFaceT->getDecl(); - - if (!MemberName.isIdentifier()) { - Diag(MemberLoc, diag::err_invalid_property_name) - << MemberName << QualType(OPT, 0); - return ExprError(); - } - - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - SourceRange BaseRange = Super? SourceRange(SuperLoc) - : BaseExpr->getSourceRange(); - if (RequireCompleteType(MemberLoc, OPT->getPointeeType(), - diag::err_property_not_found_forward_class, - MemberName, BaseRange)) - return ExprError(); - - if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration( - Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { - // Check whether we can reference this property. - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - if (Super) - return new (Context) - ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue, - OK_ObjCProperty, MemberLoc, SuperLoc, SuperType); - else - return new (Context) - ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue, - OK_ObjCProperty, MemberLoc, BaseExpr); - } - // Check protocols on qualified interfaces. - for (const auto *I : OPT->quals()) - if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration( - Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { - // Check whether we can reference this property. - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - if (Super) - return new (Context) ObjCPropertyRefExpr( - PD, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, MemberLoc, - SuperLoc, SuperType); - else - return new (Context) - ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue, - OK_ObjCProperty, MemberLoc, BaseExpr); - } - // If that failed, look for an "implicit" property by seeing if the nullary - // selector is implemented. - - // FIXME: The logic for looking up nullary and unary selectors should be - // shared with the code in ActOnInstanceMessage. - - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - - // May be found in property's qualified list. - if (!Getter) - Getter = LookupMethodInQualifiedType(Sel, OPT, true); - - // If this reference is in an @implementation, check for 'private' methods. - if (!Getter) - Getter = IFace->lookupPrivateMethod(Sel); - - if (Getter) { - // Check if we can reference this property. - if (DiagnoseUseOfDecl(Getter, MemberLoc)) - return ExprError(); - } - // If we found a getter then this may be a valid dot-reference, we - // will look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterSelector(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); - ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); - - // May be found in property's qualified list. - if (!Setter) - Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); - - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = IFace->lookupPrivateMethod(SetterSel); - } - - if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) - return ExprError(); - - // Special warning if member name used in a property-dot for a setter accessor - // does not use a property with same name; e.g. obj.X = ... for a property with - // name 'x'. - if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() && - !IFace->FindPropertyDeclaration( - Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { - if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) { - // Do not warn if user is using property-dot syntax to make call to - // user named setter. - if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter)) - Diag(MemberLoc, - diag::warn_property_access_suggest) - << MemberName << QualType(OPT, 0) << PDecl->getName() - << FixItHint::CreateReplacement(MemberLoc, PDecl->getName()); - } - } - - if (Getter || Setter) { - if (Super) - return new (Context) - ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue, - OK_ObjCProperty, MemberLoc, SuperLoc, SuperType); - else - return new (Context) - ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue, - OK_ObjCProperty, MemberLoc, BaseExpr); - - } - - // Attempt to correct for typos in property names. - if (TypoCorrection Corrected = - CorrectTypo(DeclarationNameInfo(MemberName, MemberLoc), - LookupOrdinaryName, nullptr, nullptr, - llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(), - CTK_ErrorRecovery, IFace, false, OPT)) { - DeclarationName TypoResult = Corrected.getCorrection(); - if (TypoResult.isIdentifier() && - TypoResult.getAsIdentifierInfo() == Member) { - // There is no need to try the correction if it is the same. - NamedDecl *ChosenDecl = - Corrected.isKeyword() ? nullptr : Corrected.getFoundDecl(); - if (ChosenDecl && isa<ObjCPropertyDecl>(ChosenDecl)) - if (cast<ObjCPropertyDecl>(ChosenDecl)->isClassProperty()) { - // This is a class property, we should not use the instance to - // access it. - Diag(MemberLoc, diag::err_class_property_found) << MemberName - << OPT->getInterfaceDecl()->getName() - << FixItHint::CreateReplacement(BaseExpr->getSourceRange(), - OPT->getInterfaceDecl()->getName()); - return ExprError(); - } - } else { - diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) - << MemberName << QualType(OPT, 0)); - return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, - TypoResult, MemberLoc, - SuperLoc, SuperType, Super); - } - } - ObjCInterfaceDecl *ClassDeclared; - if (ObjCIvarDecl *Ivar = - IFace->lookupInstanceVariable(Member, ClassDeclared)) { - QualType T = Ivar->getType(); - if (const ObjCObjectPointerType * OBJPT = - T->getAsObjCInterfacePointerType()) { - if (RequireCompleteType(MemberLoc, OBJPT->getPointeeType(), - diag::err_property_not_as_forward_class, - MemberName, BaseExpr)) - return ExprError(); - } - Diag(MemberLoc, - diag::err_ivar_access_using_property_syntax_suggest) - << MemberName << QualType(OPT, 0) << Ivar->getDeclName() - << FixItHint::CreateReplacement(OpLoc, "->"); - return ExprError(); - } - - Diag(MemberLoc, diag::err_property_not_found) - << MemberName << QualType(OPT, 0); - if (Setter) - Diag(Setter->getLocation(), diag::note_getter_unavailable) - << MemberName << BaseExpr->getSourceRange(); - return ExprError(); -} - -ExprResult Sema:: -ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation receiverNameLoc, - SourceLocation propertyNameLoc) { - - IdentifierInfo *receiverNamePtr = &receiverName; - ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, - receiverNameLoc); - - QualType SuperType; - if (!IFace) { - // If the "receiver" is 'super' in a method, handle it as an expression-like - // property reference. - if (receiverNamePtr->isStr("super")) { - if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) { - if (auto classDecl = CurMethod->getClassInterface()) { - SuperType = QualType(classDecl->getSuperClassType(), 0); - if (CurMethod->isInstanceMethod()) { - if (SuperType.isNull()) { - // The current class does not have a superclass. - Diag(receiverNameLoc, diag::err_root_class_cannot_use_super) - << CurMethod->getClassInterface()->getIdentifier(); - return ExprError(); - } - QualType T = Context.getObjCObjectPointerType(SuperType); - - return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(), - /*BaseExpr*/nullptr, - SourceLocation()/*OpLoc*/, - &propertyName, - propertyNameLoc, - receiverNameLoc, T, true); - } - - // Otherwise, if this is a class method, try dispatching to our - // superclass. - IFace = CurMethod->getClassInterface()->getSuperClass(); - } - } - } - - if (!IFace) { - Diag(receiverNameLoc, diag::err_expected_either) << tok::identifier - << tok::l_paren; - return ExprError(); - } - } - - Selector GetterSel; - Selector SetterSel; - if (auto PD = IFace->FindPropertyDeclaration( - &propertyName, ObjCPropertyQueryKind::OBJC_PR_query_class)) { - GetterSel = PD->getGetterName(); - SetterSel = PD->getSetterName(); - } else { - GetterSel = PP.getSelectorTable().getNullarySelector(&propertyName); - SetterSel = SelectorTable::constructSetterSelector( - PP.getIdentifierTable(), PP.getSelectorTable(), &propertyName); - } - - // Search for a declared property first. - ObjCMethodDecl *Getter = IFace->lookupClassMethod(GetterSel); - - // If this reference is in an @implementation, check for 'private' methods. - if (!Getter) - Getter = IFace->lookupPrivateClassMethod(GetterSel); - - if (Getter) { - // FIXME: refactor/share with ActOnMemberReference(). - // Check if we can reference this property. - if (DiagnoseUseOfDecl(Getter, propertyNameLoc)) - return ExprError(); - } - - // Look for the matching setter, in case it is needed. - ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = IFace->lookupPrivateClassMethod(SetterSel); - } - // Look through local category implementations associated with the class. - if (!Setter) - Setter = IFace->getCategoryClassMethod(SetterSel); - - if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc)) - return ExprError(); - - if (Getter || Setter) { - if (!SuperType.isNull()) - return new (Context) - ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue, - OK_ObjCProperty, propertyNameLoc, receiverNameLoc, - SuperType); - - return new (Context) ObjCPropertyRefExpr( - Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, - propertyNameLoc, receiverNameLoc, IFace); - } - return ExprError(Diag(propertyNameLoc, diag::err_property_not_found) - << &propertyName << Context.getObjCInterfaceType(IFace)); -} - -namespace { - -class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback { - public: - ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) { - // Determine whether "super" is acceptable in the current context. - if (Method && Method->getClassInterface()) - WantObjCSuper = Method->getClassInterface()->getSuperClass(); - } - - bool ValidateCandidate(const TypoCorrection &candidate) override { - return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() || - candidate.isKeyword("super"); - } -}; - -} // end anonymous namespace - -Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, - IdentifierInfo *Name, - SourceLocation NameLoc, - bool IsSuper, - bool HasTrailingDot, - ParsedType &ReceiverType) { - ReceiverType = nullptr; - - // If the identifier is "super" and there is no trailing dot, we're - // messaging super. If the identifier is "super" and there is a - // trailing dot, it's an instance message. - if (IsSuper && S->isInObjcMethodScope()) - return HasTrailingDot? ObjCInstanceMessage : ObjCSuperMessage; - - LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); - LookupName(Result, S); - - switch (Result.getResultKind()) { - case LookupResult::NotFound: - // Normal name lookup didn't find anything. If we're in an - // Objective-C method, look for ivars. If we find one, we're done! - // FIXME: This is a hack. Ivar lookup should be part of normal - // lookup. - if (ObjCMethodDecl *Method = getCurMethodDecl()) { - if (!Method->getClassInterface()) { - // Fall back: let the parser try to parse it as an instance message. - return ObjCInstanceMessage; - } - - ObjCInterfaceDecl *ClassDeclared; - if (Method->getClassInterface()->lookupInstanceVariable(Name, - ClassDeclared)) - return ObjCInstanceMessage; - } - - // Break out; we'll perform typo correction below. - break; - - case LookupResult::NotFoundInCurrentInstantiation: - case LookupResult::FoundOverloaded: - case LookupResult::FoundUnresolvedValue: - case LookupResult::Ambiguous: - Result.suppressDiagnostics(); - return ObjCInstanceMessage; - - case LookupResult::Found: { - // If the identifier is a class or not, and there is a trailing dot, - // it's an instance message. - if (HasTrailingDot) - return ObjCInstanceMessage; - // We found something. If it's a type, then we have a class - // message. Otherwise, it's an instance message. - NamedDecl *ND = Result.getFoundDecl(); - QualType T; - if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) - T = Context.getObjCInterfaceType(Class); - else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) { - T = Context.getTypeDeclType(Type); - DiagnoseUseOfDecl(Type, NameLoc); - } - else - return ObjCInstanceMessage; - - // We have a class message, and T is the type we're - // messaging. Build source-location information for it. - TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); - ReceiverType = CreateParsedType(T, TSInfo); - return ObjCClassMessage; - } - } - - if (TypoCorrection Corrected = CorrectTypo( - Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, - llvm::make_unique<ObjCInterfaceOrSuperCCC>(getCurMethodDecl()), - CTK_ErrorRecovery, nullptr, false, nullptr, false)) { - if (Corrected.isKeyword()) { - // If we've found the keyword "super" (the only keyword that would be - // returned by CorrectTypo), this is a send to super. - diagnoseTypo(Corrected, - PDiag(diag::err_unknown_receiver_suggest) << Name); - return ObjCSuperMessage; - } else if (ObjCInterfaceDecl *Class = - Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { - // If we found a declaration, correct when it refers to an Objective-C - // class. - diagnoseTypo(Corrected, - PDiag(diag::err_unknown_receiver_suggest) << Name); - QualType T = Context.getObjCInterfaceType(Class); - TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); - ReceiverType = CreateParsedType(T, TSInfo); - return ObjCClassMessage; - } - } - - // Fall back: let the parser try to parse it as an instance message. - return ObjCInstanceMessage; -} - -ExprResult Sema::ActOnSuperMessage(Scope *S, - SourceLocation SuperLoc, - Selector Sel, - SourceLocation LBracLoc, - ArrayRef<SourceLocation> SelectorLocs, - SourceLocation RBracLoc, - MultiExprArg Args) { - // Determine whether we are inside a method or not. - ObjCMethodDecl *Method = tryCaptureObjCSelf(SuperLoc); - if (!Method) { - Diag(SuperLoc, diag::err_invalid_receiver_to_message_super); - return ExprError(); - } - - ObjCInterfaceDecl *Class = Method->getClassInterface(); - if (!Class) { - Diag(SuperLoc, diag::err_no_super_class_message) - << Method->getDeclName(); - return ExprError(); - } - - QualType SuperTy(Class->getSuperClassType(), 0); - if (SuperTy.isNull()) { - // The current class does not have a superclass. - Diag(SuperLoc, diag::err_root_class_cannot_use_super) - << Class->getIdentifier(); - return ExprError(); - } - - // We are in a method whose class has a superclass, so 'super' - // is acting as a keyword. - if (Method->getSelector() == Sel) - getCurFunction()->ObjCShouldCallSuper = false; - - if (Method->isInstanceMethod()) { - // Since we are in an instance method, this is an instance - // message to the superclass instance. - SuperTy = Context.getObjCObjectPointerType(SuperTy); - return BuildInstanceMessage(nullptr, SuperTy, SuperLoc, - Sel, /*Method=*/nullptr, - LBracLoc, SelectorLocs, RBracLoc, Args); - } - - // Since we are in a class method, this is a class message to - // the superclass. - return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr, - SuperTy, - SuperLoc, Sel, /*Method=*/nullptr, - LBracLoc, SelectorLocs, RBracLoc, Args); -} - -ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType, - bool isSuperReceiver, - SourceLocation Loc, - Selector Sel, - ObjCMethodDecl *Method, - MultiExprArg Args) { - TypeSourceInfo *receiverTypeInfo = nullptr; - if (!ReceiverType.isNull()) - receiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType); - - return BuildClassMessage(receiverTypeInfo, ReceiverType, - /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(), - Sel, Method, Loc, Loc, Loc, Args, - /*isImplicit=*/true); -} - -static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg, - unsigned DiagID, - bool (*refactor)(const ObjCMessageExpr *, - const NSAPI &, edit::Commit &)) { - SourceLocation MsgLoc = Msg->getExprLoc(); - if (S.Diags.isIgnored(DiagID, MsgLoc)) - return; - - SourceManager &SM = S.SourceMgr; - edit::Commit ECommit(SM, S.LangOpts); - if (refactor(Msg,*S.NSAPIObj, ECommit)) { - DiagnosticBuilder Builder = S.Diag(MsgLoc, DiagID) - << Msg->getSelector() << Msg->getSourceRange(); - // FIXME: Don't emit diagnostic at all if fixits are non-commitable. - if (!ECommit.isCommitable()) - return; - for (edit::Commit::edit_iterator - I = ECommit.edit_begin(), E = ECommit.edit_end(); I != E; ++I) { - const edit::Commit::Edit &Edit = *I; - switch (Edit.Kind) { - case edit::Commit::Act_Insert: - Builder.AddFixItHint(FixItHint::CreateInsertion(Edit.OrigLoc, - Edit.Text, - Edit.BeforePrev)); - break; - case edit::Commit::Act_InsertFromRange: - Builder.AddFixItHint( - FixItHint::CreateInsertionFromRange(Edit.OrigLoc, - Edit.getInsertFromRange(SM), - Edit.BeforePrev)); - break; - case edit::Commit::Act_Remove: - Builder.AddFixItHint(FixItHint::CreateRemoval(Edit.getFileRange(SM))); - break; - } - } - } -} - -static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) { - applyCocoaAPICheck(S, Msg, diag::warn_objc_redundant_literal_use, - edit::rewriteObjCRedundantCallWithLiteral); -} - -static void checkFoundationAPI(Sema &S, SourceLocation Loc, - const ObjCMethodDecl *Method, - ArrayRef<Expr *> Args, QualType ReceiverType, - bool IsClassObjectCall) { - // Check if this is a performSelector method that uses a selector that returns - // a record or a vector type. - if (Method->getSelector().getMethodFamily() != OMF_performSelector || - Args.empty()) - return; - const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens()); - if (!SE) - return; - ObjCMethodDecl *ImpliedMethod; - if (!IsClassObjectCall) { - const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>(); - if (!OPT || !OPT->getInterfaceDecl()) - return; - ImpliedMethod = - OPT->getInterfaceDecl()->lookupInstanceMethod(SE->getSelector()); - if (!ImpliedMethod) - ImpliedMethod = - OPT->getInterfaceDecl()->lookupPrivateMethod(SE->getSelector()); - } else { - const auto *IT = ReceiverType->getAs<ObjCInterfaceType>(); - if (!IT) - return; - ImpliedMethod = IT->getDecl()->lookupClassMethod(SE->getSelector()); - if (!ImpliedMethod) - ImpliedMethod = - IT->getDecl()->lookupPrivateClassMethod(SE->getSelector()); - } - if (!ImpliedMethod) - return; - QualType Ret = ImpliedMethod->getReturnType(); - if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) { - QualType Ret = ImpliedMethod->getReturnType(); - S.Diag(Loc, diag::warn_objc_unsafe_perform_selector) - << Method->getSelector() - << (!Ret->isRecordType() - ? /*Vector*/ 2 - : Ret->isUnionType() ? /*Union*/ 1 : /*Struct*/ 0); - S.Diag(ImpliedMethod->getBeginLoc(), - diag::note_objc_unsafe_perform_selector_method_declared_here) - << ImpliedMethod->getSelector() << Ret; - } -} - -/// Diagnose use of %s directive in an NSString which is being passed -/// as formatting string to formatting method. -static void -DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S, - ObjCMethodDecl *Method, - Selector Sel, - Expr **Args, unsigned NumArgs) { - unsigned Idx = 0; - bool Format = false; - ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily(); - if (SFFamily == ObjCStringFormatFamily::SFF_NSString) { - Idx = 0; - Format = true; - } - else if (Method) { - for (const auto *I : Method->specific_attrs<FormatAttr>()) { - if (S.GetFormatNSStringIdx(I, Idx)) { - Format = true; - break; - } - } - } - if (!Format || NumArgs <= Idx) - return; - - Expr *FormatExpr = Args[Idx]; - if (ObjCStringLiteral *OSL = - dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) { - StringLiteral *FormatString = OSL->getString(); - if (S.FormatStringHasSArg(FormatString)) { - S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) - << "%s" << 0 << 0; - if (Method) - S.Diag(Method->getLocation(), diag::note_method_declared_at) - << Method->getDeclName(); - } - } -} - -/// Build an Objective-C class message expression. -/// -/// This routine takes care of both normal class messages and -/// class messages to the superclass. -/// -/// \param ReceiverTypeInfo Type source information that describes the -/// receiver of this message. This may be NULL, in which case we are -/// sending to the superclass and \p SuperLoc must be a valid source -/// location. - -/// \param ReceiverType The type of the object receiving the -/// message. When \p ReceiverTypeInfo is non-NULL, this is the same -/// type as that refers to. For a superclass send, this is the type of -/// the superclass. -/// -/// \param SuperLoc The location of the "super" keyword in a -/// superclass message. -/// -/// \param Sel The selector to which the message is being sent. -/// -/// \param Method The method that this class message is invoking, if -/// already known. -/// -/// \param LBracLoc The location of the opening square bracket ']'. -/// -/// \param RBracLoc The location of the closing square bracket ']'. -/// -/// \param ArgsIn The message arguments. -ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, - QualType ReceiverType, - SourceLocation SuperLoc, - Selector Sel, - ObjCMethodDecl *Method, - SourceLocation LBracLoc, - ArrayRef<SourceLocation> SelectorLocs, - SourceLocation RBracLoc, - MultiExprArg ArgsIn, - bool isImplicit) { - SourceLocation Loc = SuperLoc.isValid()? SuperLoc - : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin(); - if (LBracLoc.isInvalid()) { - Diag(Loc, diag::err_missing_open_square_message_send) - << FixItHint::CreateInsertion(Loc, "["); - LBracLoc = Loc; - } - ArrayRef<SourceLocation> SelectorSlotLocs; - if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) - SelectorSlotLocs = SelectorLocs; - else - SelectorSlotLocs = Loc; - SourceLocation SelLoc = SelectorSlotLocs.front(); - - if (ReceiverType->isDependentType()) { - // If the receiver type is dependent, we can't type-check anything - // at this point. Build a dependent expression. - unsigned NumArgs = ArgsIn.size(); - Expr **Args = ArgsIn.data(); - assert(SuperLoc.isInvalid() && "Message to super with dependent type"); - return ObjCMessageExpr::Create( - Context, ReceiverType, VK_RValue, LBracLoc, ReceiverTypeInfo, Sel, - SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs), RBracLoc, - isImplicit); - } - - // Find the class to which we are sending this message. - ObjCInterfaceDecl *Class = nullptr; - const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>(); - if (!ClassType || !(Class = ClassType->getInterface())) { - Diag(Loc, diag::err_invalid_receiver_class_message) - << ReceiverType; - return ExprError(); - } - assert(Class && "We don't know which class we're messaging?"); - // objc++ diagnoses during typename annotation. - if (!getLangOpts().CPlusPlus) - (void)DiagnoseUseOfDecl(Class, SelectorSlotLocs); - // Find the method we are messaging. - if (!Method) { - SourceRange TypeRange - = SuperLoc.isValid()? SourceRange(SuperLoc) - : ReceiverTypeInfo->getTypeLoc().getSourceRange(); - if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class), - (getLangOpts().ObjCAutoRefCount - ? diag::err_arc_receiver_forward_class - : diag::warn_receiver_forward_class), - TypeRange)) { - // A forward class used in messaging is treated as a 'Class' - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (Method && !getLangOpts().ObjCAutoRefCount) - Diag(Method->getLocation(), diag::note_method_sent_forward_class) - << Method->getDeclName(); - } - if (!Method) - Method = Class->lookupClassMethod(Sel); - - // If we have an implementation in scope, check "private" methods. - if (!Method) - Method = Class->lookupPrivateClassMethod(Sel); - - if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, - nullptr, false, false, Class)) - return ExprError(); - } - - // Check the argument types and determine the result type. - QualType ReturnType; - ExprValueKind VK = VK_RValue; - - unsigned NumArgs = ArgsIn.size(); - Expr **Args = ArgsIn.data(); - if (CheckMessageArgumentTypes(/*Receiver=*/nullptr, ReceiverType, - MultiExprArg(Args, NumArgs), Sel, SelectorLocs, - Method, true, SuperLoc.isValid(), LBracLoc, - RBracLoc, SourceRange(), ReturnType, VK)) - return ExprError(); - - if (Method && !Method->getReturnType()->isVoidType() && - RequireCompleteType(LBracLoc, Method->getReturnType(), - diag::err_illegal_message_expr_incomplete_type)) - return ExprError(); - - // Warn about explicit call of +initialize on its own class. But not on 'super'. - if (Method && Method->getMethodFamily() == OMF_initialize) { - if (!SuperLoc.isValid()) { - const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext()); - if (ID == Class) { - Diag(Loc, diag::warn_direct_initialize_call); - Diag(Method->getLocation(), diag::note_method_declared_at) - << Method->getDeclName(); - } - } - else if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - // [super initialize] is allowed only within an +initialize implementation - if (CurMeth->getMethodFamily() != OMF_initialize) { - Diag(Loc, diag::warn_direct_super_initialize_call); - Diag(Method->getLocation(), diag::note_method_declared_at) - << Method->getDeclName(); - Diag(CurMeth->getLocation(), diag::note_method_declared_at) - << CurMeth->getDeclName(); - } - } - } - - DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs); - - // Construct the appropriate ObjCMessageExpr. - ObjCMessageExpr *Result; - if (SuperLoc.isValid()) - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, SelectorLocs, - Method, makeArrayRef(Args, NumArgs), - RBracLoc, isImplicit); - else { - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - ReceiverTypeInfo, Sel, SelectorLocs, - Method, makeArrayRef(Args, NumArgs), - RBracLoc, isImplicit); - if (!isImplicit) - checkCocoaAPI(*this, Result); - } - if (Method) - checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), - ReceiverType, /*IsClassObjectCall=*/true); - return MaybeBindToTemporary(Result); -} - -// ActOnClassMessage - used for both unary and keyword messages. -// ArgExprs is optional - if it is present, the number of expressions -// is obtained from Sel.getNumArgs(). -ExprResult Sema::ActOnClassMessage(Scope *S, - ParsedType Receiver, - Selector Sel, - SourceLocation LBracLoc, - ArrayRef<SourceLocation> SelectorLocs, - SourceLocation RBracLoc, - MultiExprArg Args) { - TypeSourceInfo *ReceiverTypeInfo; - QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo); - if (ReceiverType.isNull()) - return ExprError(); - - if (!ReceiverTypeInfo) - ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc); - - return BuildClassMessage(ReceiverTypeInfo, ReceiverType, - /*SuperLoc=*/SourceLocation(), Sel, - /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc, - Args); -} - -ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver, - QualType ReceiverType, - SourceLocation Loc, - Selector Sel, - ObjCMethodDecl *Method, - MultiExprArg Args) { - return BuildInstanceMessage(Receiver, ReceiverType, - /*SuperLoc=*/!Receiver ? Loc : SourceLocation(), - Sel, Method, Loc, Loc, Loc, Args, - /*isImplicit=*/true); -} - -static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) { - if (!S.NSAPIObj) - return false; - const auto *Protocol = dyn_cast<ObjCProtocolDecl>(M->getDeclContext()); - if (!Protocol) - return false; - const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); - if (const auto *RootClass = dyn_cast_or_null<ObjCInterfaceDecl>( - S.LookupSingleName(S.TUScope, II, Protocol->getBeginLoc(), - Sema::LookupOrdinaryName))) { - for (const ObjCProtocolDecl *P : RootClass->all_referenced_protocols()) { - if (P->getCanonicalDecl() == Protocol->getCanonicalDecl()) - return true; - } - } - return false; -} - -/// Build an Objective-C instance message expression. -/// -/// This routine takes care of both normal instance messages and -/// instance messages to the superclass instance. -/// -/// \param Receiver The expression that computes the object that will -/// receive this message. This may be empty, in which case we are -/// sending to the superclass instance and \p SuperLoc must be a valid -/// source location. -/// -/// \param ReceiverType The (static) type of the object receiving the -/// message. When a \p Receiver expression is provided, this is the -/// same type as that expression. For a superclass instance send, this -/// is a pointer to the type of the superclass. -/// -/// \param SuperLoc The location of the "super" keyword in a -/// superclass instance message. -/// -/// \param Sel The selector to which the message is being sent. -/// -/// \param Method The method that this instance message is invoking, if -/// already known. -/// -/// \param LBracLoc The location of the opening square bracket ']'. -/// -/// \param RBracLoc The location of the closing square bracket ']'. -/// -/// \param ArgsIn The message arguments. -ExprResult Sema::BuildInstanceMessage(Expr *Receiver, - QualType ReceiverType, - SourceLocation SuperLoc, - Selector Sel, - ObjCMethodDecl *Method, - SourceLocation LBracLoc, - ArrayRef<SourceLocation> SelectorLocs, - SourceLocation RBracLoc, - MultiExprArg ArgsIn, - bool isImplicit) { - assert((Receiver || SuperLoc.isValid()) && "If the Receiver is null, the " - "SuperLoc must be valid so we can " - "use it instead."); - - // The location of the receiver. - SourceLocation Loc = SuperLoc.isValid() ? SuperLoc : Receiver->getBeginLoc(); - SourceRange RecRange = - SuperLoc.isValid()? SuperLoc : Receiver->getSourceRange(); - ArrayRef<SourceLocation> SelectorSlotLocs; - if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) - SelectorSlotLocs = SelectorLocs; - else - SelectorSlotLocs = Loc; - SourceLocation SelLoc = SelectorSlotLocs.front(); - - if (LBracLoc.isInvalid()) { - Diag(Loc, diag::err_missing_open_square_message_send) - << FixItHint::CreateInsertion(Loc, "["); - LBracLoc = Loc; - } - - // If we have a receiver expression, perform appropriate promotions - // and determine receiver type. - if (Receiver) { - if (Receiver->hasPlaceholderType()) { - ExprResult Result; - if (Receiver->getType() == Context.UnknownAnyTy) - Result = forceUnknownAnyToType(Receiver, Context.getObjCIdType()); - else - Result = CheckPlaceholderExpr(Receiver); - if (Result.isInvalid()) return ExprError(); - Receiver = Result.get(); - } - - if (Receiver->isTypeDependent()) { - // If the receiver is type-dependent, we can't type-check anything - // at this point. Build a dependent expression. - unsigned NumArgs = ArgsIn.size(); - Expr **Args = ArgsIn.data(); - assert(SuperLoc.isInvalid() && "Message to super with dependent type"); - return ObjCMessageExpr::Create( - Context, Context.DependentTy, VK_RValue, LBracLoc, Receiver, Sel, - SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs), - RBracLoc, isImplicit); - } - - // If necessary, apply function/array conversion to the receiver. - // C99 6.7.5.3p[7,8]. - ExprResult Result = DefaultFunctionArrayLvalueConversion(Receiver); - if (Result.isInvalid()) - return ExprError(); - Receiver = Result.get(); - ReceiverType = Receiver->getType(); - - // If the receiver is an ObjC pointer, a block pointer, or an - // __attribute__((NSObject)) pointer, we don't need to do any - // special conversion in order to look up a receiver. - if (ReceiverType->isObjCRetainableType()) { - // do nothing - } else if (!getLangOpts().ObjCAutoRefCount && - !Context.getObjCIdType().isNull() && - (ReceiverType->isPointerType() || - ReceiverType->isIntegerType())) { - // Implicitly convert integers and pointers to 'id' but emit a warning. - // But not in ARC. - Diag(Loc, diag::warn_bad_receiver_type) - << ReceiverType - << Receiver->getSourceRange(); - if (ReceiverType->isPointerType()) { - Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - CK_CPointerToObjCPointerCast).get(); - } else { - // TODO: specialized warning on null receivers? - bool IsNull = Receiver->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull); - CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer; - Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - Kind).get(); - } - ReceiverType = Receiver->getType(); - } else if (getLangOpts().CPlusPlus) { - // The receiver must be a complete type. - if (RequireCompleteType(Loc, Receiver->getType(), - diag::err_incomplete_receiver_type)) - return ExprError(); - - ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver); - if (result.isUsable()) { - Receiver = result.get(); - ReceiverType = Receiver->getType(); - } - } - } - - if (ReceiverType->isObjCIdType() && !isImplicit) - Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id); - - // There's a somewhat weird interaction here where we assume that we - // won't actually have a method unless we also don't need to do some - // of the more detailed type-checking on the receiver. - - if (!Method) { - // Handle messages to id and __kindof types (where we use the - // global method pool). - const ObjCObjectType *typeBound = nullptr; - bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context, - typeBound); - if (receiverIsIdLike || ReceiverType->isBlockPointerType() || - (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { - SmallVector<ObjCMethodDecl*, 4> Methods; - // If we have a type bound, further filter the methods. - CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/, - true/*CheckTheOther*/, typeBound); - if (!Methods.empty()) { - // We choose the first method as the initial candidate, then try to - // select a better one. - Method = Methods[0]; - - if (ObjCMethodDecl *BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), Methods)) - Method = BestMethod; - - if (!AreMultipleMethodsInGlobalPool(Sel, Method, - SourceRange(LBracLoc, RBracLoc), - receiverIsIdLike, Methods)) - DiagnoseUseOfDecl(Method, SelectorSlotLocs); - } - } else if (ReceiverType->isObjCClassOrClassKindOfType() || - ReceiverType->isObjCQualifiedClassType()) { - // Handle messages to Class. - // We allow sending a message to a qualified Class ("Class<foo>"), which - // is ok as long as one of the protocols implements the selector (if not, - // warn). - if (!ReceiverType->isObjCClassOrClassKindOfType()) { - const ObjCObjectPointerType *QClassTy - = ReceiverType->getAsObjCQualifiedClassType(); - // Search protocols for class methods. - Method = LookupMethodInQualifiedType(Sel, QClassTy, false); - if (!Method) { - Method = LookupMethodInQualifiedType(Sel, QClassTy, true); - // warn if instance method found for a Class message. - if (Method && !isMethodDeclaredInRootProtocol(*this, Method)) { - Diag(SelLoc, diag::warn_instance_method_on_class_found) - << Method->getSelector() << Sel; - Diag(Method->getLocation(), diag::note_method_declared_at) - << Method->getDeclName(); - } - } - } else { - if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { - // FIXME: Is this correct? Why are we assuming that a message to - // Class will call a method in the current interface? - - // First check the public methods in the class interface. - Method = ClassDecl->lookupClassMethod(Sel); - - if (!Method) - Method = ClassDecl->lookupPrivateClassMethod(Sel); - - if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, nullptr, - false, false, ClassDecl)) - return ExprError(); - } - } - if (!Method) { - // If not messaging 'self', look for any factory method named 'Sel'. - if (!Receiver || !isSelfExpr(Receiver)) { - // If no class (factory) method was found, check if an _instance_ - // method of the same name exists in the root class only. - SmallVector<ObjCMethodDecl*, 4> Methods; - CollectMultipleMethodsInGlobalPool(Sel, Methods, - false/*InstanceFirst*/, - true/*CheckTheOther*/); - if (!Methods.empty()) { - // We choose the first method as the initial candidate, then try - // to select a better one. - Method = Methods[0]; - - // If we find an instance method, emit warning. - if (Method->isInstanceMethod()) { - if (const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { - if (ID->getSuperClass()) - Diag(SelLoc, diag::warn_root_inst_method_not_found) - << Sel << SourceRange(LBracLoc, RBracLoc); - } - } - - if (ObjCMethodDecl *BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), - Methods)) - Method = BestMethod; - } - } - } - } - } else { - ObjCInterfaceDecl *ClassDecl = nullptr; - - // We allow sending a message to a qualified ID ("id<foo>"), which is ok as - // long as one of the protocols implements the selector (if not, warn). - // And as long as message is not deprecated/unavailable (warn if it is). - if (const ObjCObjectPointerType *QIdTy - = ReceiverType->getAsObjCQualifiedIdType()) { - // Search protocols for instance methods. - Method = LookupMethodInQualifiedType(Sel, QIdTy, true); - if (!Method) - Method = LookupMethodInQualifiedType(Sel, QIdTy, false); - if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) - return ExprError(); - } else if (const ObjCObjectPointerType *OCIType - = ReceiverType->getAsObjCInterfacePointerType()) { - // We allow sending a message to a pointer to an interface (an object). - ClassDecl = OCIType->getInterfaceDecl(); - - // Try to complete the type. Under ARC, this is a hard error from which - // we don't try to recover. - // FIXME: In the non-ARC case, this will still be a hard error if the - // definition is found in a module that's not visible. - const ObjCInterfaceDecl *forwardClass = nullptr; - if (RequireCompleteType(Loc, OCIType->getPointeeType(), - getLangOpts().ObjCAutoRefCount - ? diag::err_arc_receiver_forward_instance - : diag::warn_receiver_forward_instance, - Receiver? Receiver->getSourceRange() - : SourceRange(SuperLoc))) { - if (getLangOpts().ObjCAutoRefCount) - return ExprError(); - - forwardClass = OCIType->getInterfaceDecl(); - Diag(Receiver ? Receiver->getBeginLoc() : SuperLoc, - diag::note_receiver_is_id); - Method = nullptr; - } else { - Method = ClassDecl->lookupInstanceMethod(Sel); - } - - if (!Method) - // Search protocol qualifiers. - Method = LookupMethodInQualifiedType(Sel, OCIType, true); - - if (!Method) { - // If we have implementations in scope, check "private" methods. - Method = ClassDecl->lookupPrivateMethod(Sel); - - if (!Method && getLangOpts().ObjCAutoRefCount) { - Diag(SelLoc, diag::err_arc_may_not_respond) - << OCIType->getPointeeType() << Sel << RecRange - << SourceRange(SelectorLocs.front(), SelectorLocs.back()); - return ExprError(); - } - - if (!Method && (!Receiver || !isSelfExpr(Receiver))) { - // If we still haven't found a method, look in the global pool. This - // behavior isn't very desirable, however we need it for GCC - // compatibility. FIXME: should we deviate?? - if (OCIType->qual_empty()) { - SmallVector<ObjCMethodDecl*, 4> Methods; - CollectMultipleMethodsInGlobalPool(Sel, Methods, - true/*InstanceFirst*/, - false/*CheckTheOther*/); - if (!Methods.empty()) { - // We choose the first method as the initial candidate, then try - // to select a better one. - Method = Methods[0]; - - if (ObjCMethodDecl *BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), - Methods)) - Method = BestMethod; - - AreMultipleMethodsInGlobalPool(Sel, Method, - SourceRange(LBracLoc, RBracLoc), - true/*receiverIdOrClass*/, - Methods); - } - if (Method && !forwardClass) - Diag(SelLoc, diag::warn_maynot_respond) - << OCIType->getInterfaceDecl()->getIdentifier() - << Sel << RecRange; - } - } - } - if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, forwardClass)) - return ExprError(); - } else { - // Reject other random receiver types (e.g. structs). - Diag(Loc, diag::err_bad_receiver_type) - << ReceiverType << Receiver->getSourceRange(); - return ExprError(); - } - } - } - - FunctionScopeInfo *DIFunctionScopeInfo = - (Method && Method->getMethodFamily() == OMF_init) - ? getEnclosingFunction() : nullptr; - - if (DIFunctionScopeInfo && - DIFunctionScopeInfo->ObjCIsDesignatedInit && - (SuperLoc.isValid() || isSelfExpr(Receiver))) { - bool isDesignatedInitChain = false; - if (SuperLoc.isValid()) { - if (const ObjCObjectPointerType * - OCIType = ReceiverType->getAsObjCInterfacePointerType()) { - if (const ObjCInterfaceDecl *ID = OCIType->getInterfaceDecl()) { - // Either we know this is a designated initializer or we - // conservatively assume it because we don't know for sure. - if (!ID->declaresOrInheritsDesignatedInitializers() || - ID->isDesignatedInitializer(Sel)) { - isDesignatedInitChain = true; - DIFunctionScopeInfo->ObjCWarnForNoDesignatedInitChain = false; - } - } - } - } - if (!isDesignatedInitChain) { - const ObjCMethodDecl *InitMethod = nullptr; - bool isDesignated = - getCurMethodDecl()->isDesignatedInitializerForTheInterface(&InitMethod); - assert(isDesignated && InitMethod); - (void)isDesignated; - Diag(SelLoc, SuperLoc.isValid() ? - diag::warn_objc_designated_init_non_designated_init_call : - diag::warn_objc_designated_init_non_super_designated_init_call); - Diag(InitMethod->getLocation(), - diag::note_objc_designated_init_marked_here); - } - } - - if (DIFunctionScopeInfo && - DIFunctionScopeInfo->ObjCIsSecondaryInit && - (SuperLoc.isValid() || isSelfExpr(Receiver))) { - if (SuperLoc.isValid()) { - Diag(SelLoc, diag::warn_objc_secondary_init_super_init_call); - } else { - DIFunctionScopeInfo->ObjCWarnForNoInitDelegation = false; - } - } - - // Check the message arguments. - unsigned NumArgs = ArgsIn.size(); - Expr **Args = ArgsIn.data(); - QualType ReturnType; - ExprValueKind VK = VK_RValue; - bool ClassMessage = (ReceiverType->isObjCClassType() || - ReceiverType->isObjCQualifiedClassType()); - if (CheckMessageArgumentTypes(Receiver, ReceiverType, - MultiExprArg(Args, NumArgs), Sel, SelectorLocs, - Method, ClassMessage, SuperLoc.isValid(), - LBracLoc, RBracLoc, RecRange, ReturnType, VK)) - return ExprError(); - - if (Method && !Method->getReturnType()->isVoidType() && - RequireCompleteType(LBracLoc, Method->getReturnType(), - diag::err_illegal_message_expr_incomplete_type)) - return ExprError(); - - // In ARC, forbid the user from sending messages to - // retain/release/autorelease/dealloc/retainCount explicitly. - if (getLangOpts().ObjCAutoRefCount) { - ObjCMethodFamily family = - (Method ? Method->getMethodFamily() : Sel.getMethodFamily()); - switch (family) { - case OMF_init: - if (Method) - checkInitMethod(Method, ReceiverType); - break; - - case OMF_None: - case OMF_alloc: - case OMF_copy: - case OMF_finalize: - case OMF_mutableCopy: - case OMF_new: - case OMF_self: - case OMF_initialize: - break; - - case OMF_dealloc: - case OMF_retain: - case OMF_release: - case OMF_autorelease: - case OMF_retainCount: - Diag(SelLoc, diag::err_arc_illegal_explicit_message) - << Sel << RecRange; - break; - - case OMF_performSelector: - if (Method && NumArgs >= 1) { - if (const auto *SelExp = - dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens())) { - Selector ArgSel = SelExp->getSelector(); - ObjCMethodDecl *SelMethod = - LookupInstanceMethodInGlobalPool(ArgSel, - SelExp->getSourceRange()); - if (!SelMethod) - SelMethod = - LookupFactoryMethodInGlobalPool(ArgSel, - SelExp->getSourceRange()); - if (SelMethod) { - ObjCMethodFamily SelFamily = SelMethod->getMethodFamily(); - switch (SelFamily) { - case OMF_alloc: - case OMF_copy: - case OMF_mutableCopy: - case OMF_new: - case OMF_init: - // Issue error, unless ns_returns_not_retained. - if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) { - // selector names a +1 method - Diag(SelLoc, - diag::err_arc_perform_selector_retains); - Diag(SelMethod->getLocation(), diag::note_method_declared_at) - << SelMethod->getDeclName(); - } - break; - default: - // +0 call. OK. unless ns_returns_retained. - if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) { - // selector names a +1 method - Diag(SelLoc, - diag::err_arc_perform_selector_retains); - Diag(SelMethod->getLocation(), diag::note_method_declared_at) - << SelMethod->getDeclName(); - } - break; - } - } - } else { - // error (may leak). - Diag(SelLoc, diag::warn_arc_perform_selector_leaks); - Diag(Args[0]->getExprLoc(), diag::note_used_here); - } - } - break; - } - } - - DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs); - - // Construct the appropriate ObjCMessageExpr instance. - ObjCMessageExpr *Result; - if (SuperLoc.isValid()) - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, SelectorLocs, Method, - makeArrayRef(Args, NumArgs), RBracLoc, - isImplicit); - else { - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - Receiver, Sel, SelectorLocs, Method, - makeArrayRef(Args, NumArgs), RBracLoc, - isImplicit); - if (!isImplicit) - checkCocoaAPI(*this, Result); - } - if (Method) { - bool IsClassObjectCall = ClassMessage; - // 'self' message receivers in class methods should be treated as message - // sends to the class object in order for the semantic checks to be - // performed correctly. Messages to 'super' already count as class messages, - // so they don't need to be handled here. - if (Receiver && isSelfExpr(Receiver)) { - if (const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>()) { - if (OPT->getObjectType()->isObjCClass()) { - if (const auto *CurMeth = getCurMethodDecl()) { - IsClassObjectCall = true; - ReceiverType = - Context.getObjCInterfaceType(CurMeth->getClassInterface()); - } - } - } - } - checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), - ReceiverType, IsClassObjectCall); - } - - if (getLangOpts().ObjCAutoRefCount) { - // In ARC, annotate delegate init calls. - if (Result->getMethodFamily() == OMF_init && - (SuperLoc.isValid() || isSelfExpr(Receiver))) { - // Only consider init calls *directly* in init implementations, - // not within blocks. - ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CurContext); - if (method && method->getMethodFamily() == OMF_init) { - // The implicit assignment to self means we also don't want to - // consume the result. - Result->setDelegateInitCall(true); - return Result; - } - } - - // In ARC, check for message sends which are likely to introduce - // retain cycles. - checkRetainCycles(Result); - } - - if (getLangOpts().ObjCWeak) { - if (!isImplicit && Method) { - if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) { - bool IsWeak = - Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak; - if (!IsWeak && Sel.isUnarySelector()) - IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak; - if (IsWeak && !isUnevaluatedContext() && - !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, LBracLoc)) - getCurFunction()->recordUseOfWeak(Result, Prop); - } - } - } - - CheckObjCCircularContainer(Result); - - return MaybeBindToTemporary(Result); -} - -static void RemoveSelectorFromWarningCache(Sema &S, Expr* Arg) { - if (ObjCSelectorExpr *OSE = - dyn_cast<ObjCSelectorExpr>(Arg->IgnoreParenCasts())) { - Selector Sel = OSE->getSelector(); - SourceLocation Loc = OSE->getAtLoc(); - auto Pos = S.ReferencedSelectors.find(Sel); - if (Pos != S.ReferencedSelectors.end() && Pos->second == Loc) - S.ReferencedSelectors.erase(Pos); - } -} - -// ActOnInstanceMessage - used for both unary and keyword messages. -// ArgExprs is optional - if it is present, the number of expressions -// is obtained from Sel.getNumArgs(). -ExprResult Sema::ActOnInstanceMessage(Scope *S, - Expr *Receiver, - Selector Sel, - SourceLocation LBracLoc, - ArrayRef<SourceLocation> SelectorLocs, - SourceLocation RBracLoc, - MultiExprArg Args) { - if (!Receiver) - return ExprError(); - - // A ParenListExpr can show up while doing error recovery with invalid code. - if (isa<ParenListExpr>(Receiver)) { - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Receiver); - if (Result.isInvalid()) return ExprError(); - Receiver = Result.get(); - } - - if (RespondsToSelectorSel.isNull()) { - IdentifierInfo *SelectorId = &Context.Idents.get("respondsToSelector"); - RespondsToSelectorSel = Context.Selectors.getUnarySelector(SelectorId); - } - if (Sel == RespondsToSelectorSel) - RemoveSelectorFromWarningCache(*this, Args[0]); - - return BuildInstanceMessage(Receiver, Receiver->getType(), - /*SuperLoc=*/SourceLocation(), Sel, - /*Method=*/nullptr, LBracLoc, SelectorLocs, - RBracLoc, Args); -} - -enum ARCConversionTypeClass { - /// int, void, struct A - ACTC_none, - - /// id, void (^)() - ACTC_retainable, - - /// id*, id***, void (^*)(), - ACTC_indirectRetainable, - - /// void* might be a normal C type, or it might a CF type. - ACTC_voidPtr, - - /// struct A* - ACTC_coreFoundation -}; - -static bool isAnyRetainable(ARCConversionTypeClass ACTC) { - return (ACTC == ACTC_retainable || - ACTC == ACTC_coreFoundation || - ACTC == ACTC_voidPtr); -} - -static bool isAnyCLike(ARCConversionTypeClass ACTC) { - return ACTC == ACTC_none || - ACTC == ACTC_voidPtr || - ACTC == ACTC_coreFoundation; -} - -static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) { - bool isIndirect = false; - - // Ignore an outermost reference type. - if (const ReferenceType *ref = type->getAs<ReferenceType>()) { - type = ref->getPointeeType(); - isIndirect = true; - } - - // Drill through pointers and arrays recursively. - while (true) { - if (const PointerType *ptr = type->getAs<PointerType>()) { - type = ptr->getPointeeType(); - - // The first level of pointer may be the innermost pointer on a CF type. - if (!isIndirect) { - if (type->isVoidType()) return ACTC_voidPtr; - if (type->isRecordType()) return ACTC_coreFoundation; - } - } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) { - type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0); - } else { - break; - } - isIndirect = true; - } - - if (isIndirect) { - if (type->isObjCARCBridgableType()) - return ACTC_indirectRetainable; - return ACTC_none; - } - - if (type->isObjCARCBridgableType()) - return ACTC_retainable; - - return ACTC_none; -} - -namespace { - /// A result from the cast checker. - enum ACCResult { - /// Cannot be casted. - ACC_invalid, - - /// Can be safely retained or not retained. - ACC_bottom, - - /// Can be casted at +0. - ACC_plusZero, - - /// Can be casted at +1. - ACC_plusOne - }; - ACCResult merge(ACCResult left, ACCResult right) { - if (left == right) return left; - if (left == ACC_bottom) return right; - if (right == ACC_bottom) return left; - return ACC_invalid; - } - - /// A checker which white-lists certain expressions whose conversion - /// to or from retainable type would otherwise be forbidden in ARC. - class ARCCastChecker : public StmtVisitor<ARCCastChecker, ACCResult> { - typedef StmtVisitor<ARCCastChecker, ACCResult> super; - - ASTContext &Context; - ARCConversionTypeClass SourceClass; - ARCConversionTypeClass TargetClass; - bool Diagnose; - - static bool isCFType(QualType type) { - // Someday this can use ns_bridged. For now, it has to do this. - return type->isCARCBridgableType(); - } - - public: - ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source, - ARCConversionTypeClass target, bool diagnose) - : Context(Context), SourceClass(source), TargetClass(target), - Diagnose(diagnose) {} - - using super::Visit; - ACCResult Visit(Expr *e) { - return super::Visit(e->IgnoreParens()); - } - - ACCResult VisitStmt(Stmt *s) { - return ACC_invalid; - } - - /// Null pointer constants can be casted however you please. - ACCResult VisitExpr(Expr *e) { - if (e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - return ACC_bottom; - return ACC_invalid; - } - - /// Objective-C string literals can be safely casted. - ACCResult VisitObjCStringLiteral(ObjCStringLiteral *e) { - // If we're casting to any retainable type, go ahead. Global - // strings are immune to retains, so this is bottom. - if (isAnyRetainable(TargetClass)) return ACC_bottom; - - return ACC_invalid; - } - - /// Look through certain implicit and explicit casts. - ACCResult VisitCastExpr(CastExpr *e) { - switch (e->getCastKind()) { - case CK_NullToPointer: - return ACC_bottom; - - case CK_NoOp: - case CK_LValueToRValue: - case CK_BitCast: - case CK_CPointerToObjCPointerCast: - case CK_BlockPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - return Visit(e->getSubExpr()); - - default: - return ACC_invalid; - } - } - - /// Look through unary extension. - ACCResult VisitUnaryExtension(UnaryOperator *e) { - return Visit(e->getSubExpr()); - } - - /// Ignore the LHS of a comma operator. - ACCResult VisitBinComma(BinaryOperator *e) { - return Visit(e->getRHS()); - } - - /// Conditional operators are okay if both sides are okay. - ACCResult VisitConditionalOperator(ConditionalOperator *e) { - ACCResult left = Visit(e->getTrueExpr()); - if (left == ACC_invalid) return ACC_invalid; - return merge(left, Visit(e->getFalseExpr())); - } - - /// Look through pseudo-objects. - ACCResult VisitPseudoObjectExpr(PseudoObjectExpr *e) { - // If we're getting here, we should always have a result. - return Visit(e->getResultExpr()); - } - - /// Statement expressions are okay if their result expression is okay. - ACCResult VisitStmtExpr(StmtExpr *e) { - return Visit(e->getSubStmt()->body_back()); - } - - /// Some declaration references are okay. - ACCResult VisitDeclRefExpr(DeclRefExpr *e) { - VarDecl *var = dyn_cast<VarDecl>(e->getDecl()); - // References to global constants are okay. - if (isAnyRetainable(TargetClass) && - isAnyRetainable(SourceClass) && - var && - !var->hasDefinition(Context) && - var->getType().isConstQualified()) { - - // In system headers, they can also be assumed to be immune to retains. - // These are things like 'kCFStringTransformToLatin'. - if (Context.getSourceManager().isInSystemHeader(var->getLocation())) - return ACC_bottom; - - return ACC_plusZero; - } - - // Nothing else. - return ACC_invalid; - } - - /// Some calls are okay. - ACCResult VisitCallExpr(CallExpr *e) { - if (FunctionDecl *fn = e->getDirectCallee()) - if (ACCResult result = checkCallToFunction(fn)) - return result; - - return super::VisitCallExpr(e); - } - - ACCResult checkCallToFunction(FunctionDecl *fn) { - // Require a CF*Ref return type. - if (!isCFType(fn->getReturnType())) - return ACC_invalid; - - if (!isAnyRetainable(TargetClass)) - return ACC_invalid; - - // Honor an explicit 'not retained' attribute. - if (fn->hasAttr<CFReturnsNotRetainedAttr>()) - return ACC_plusZero; - - // Honor an explicit 'retained' attribute, except that for - // now we're not going to permit implicit handling of +1 results, - // because it's a bit frightening. - if (fn->hasAttr<CFReturnsRetainedAttr>()) - return Diagnose ? ACC_plusOne - : ACC_invalid; // ACC_plusOne if we start accepting this - - // Recognize this specific builtin function, which is used by CFSTR. - unsigned builtinID = fn->getBuiltinID(); - if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString) - return ACC_bottom; - - // Otherwise, don't do anything implicit with an unaudited function. - if (!fn->hasAttr<CFAuditedTransferAttr>()) - return ACC_invalid; - - // Otherwise, it's +0 unless it follows the create convention. - if (ento::coreFoundation::followsCreateRule(fn)) - return Diagnose ? ACC_plusOne - : ACC_invalid; // ACC_plusOne if we start accepting this - - return ACC_plusZero; - } - - ACCResult VisitObjCMessageExpr(ObjCMessageExpr *e) { - return checkCallToMethod(e->getMethodDecl()); - } - - ACCResult VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *e) { - ObjCMethodDecl *method; - if (e->isExplicitProperty()) - method = e->getExplicitProperty()->getGetterMethodDecl(); - else - method = e->getImplicitPropertyGetter(); - return checkCallToMethod(method); - } - - ACCResult checkCallToMethod(ObjCMethodDecl *method) { - if (!method) return ACC_invalid; - - // Check for message sends to functions returning CF types. We - // just obey the Cocoa conventions with these, even though the - // return type is CF. - if (!isAnyRetainable(TargetClass) || !isCFType(method->getReturnType())) - return ACC_invalid; - - // If the method is explicitly marked not-retained, it's +0. - if (method->hasAttr<CFReturnsNotRetainedAttr>()) - return ACC_plusZero; - - // If the method is explicitly marked as returning retained, or its - // selector follows a +1 Cocoa convention, treat it as +1. - if (method->hasAttr<CFReturnsRetainedAttr>()) - return ACC_plusOne; - - switch (method->getSelector().getMethodFamily()) { - case OMF_alloc: - case OMF_copy: - case OMF_mutableCopy: - case OMF_new: - return ACC_plusOne; - - default: - // Otherwise, treat it as +0. - return ACC_plusZero; - } - } - }; -} // end anonymous namespace - -bool Sema::isKnownName(StringRef name) { - if (name.empty()) - return false; - LookupResult R(*this, &Context.Idents.get(name), SourceLocation(), - Sema::LookupOrdinaryName); - return LookupName(R, TUScope, false); -} - -static void addFixitForObjCARCConversion(Sema &S, - DiagnosticBuilder &DiagB, - Sema::CheckedConversionKind CCK, - SourceLocation afterLParen, - QualType castType, - Expr *castExpr, - Expr *realCast, - const char *bridgeKeyword, - const char *CFBridgeName) { - // We handle C-style and implicit casts here. - switch (CCK) { - case Sema::CCK_ImplicitConversion: - case Sema::CCK_ForBuiltinOverloadedOp: - case Sema::CCK_CStyleCast: - case Sema::CCK_OtherCast: - break; - case Sema::CCK_FunctionalCast: - return; - } - - if (CFBridgeName) { - if (CCK == Sema::CCK_OtherCast) { - if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) { - SourceRange range(NCE->getOperatorLoc(), - NCE->getAngleBrackets().getEnd()); - SmallString<32> BridgeCall; - - SourceManager &SM = S.getSourceManager(); - char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1)); - if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts())) - BridgeCall += ' '; - - BridgeCall += CFBridgeName; - DiagB.AddFixItHint(FixItHint::CreateReplacement(range, BridgeCall)); - } - return; - } - Expr *castedE = castExpr; - if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(castedE)) - castedE = CCE->getSubExpr(); - castedE = castedE->IgnoreImpCasts(); - SourceRange range = castedE->getSourceRange(); - - SmallString<32> BridgeCall; - - SourceManager &SM = S.getSourceManager(); - char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1)); - if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts())) - BridgeCall += ' '; - - BridgeCall += CFBridgeName; - - if (isa<ParenExpr>(castedE)) { - DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(), - BridgeCall)); - } else { - BridgeCall += '('; - DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(), - BridgeCall)); - DiagB.AddFixItHint(FixItHint::CreateInsertion( - S.getLocForEndOfToken(range.getEnd()), - ")")); - } - return; - } - - if (CCK == Sema::CCK_CStyleCast) { - DiagB.AddFixItHint(FixItHint::CreateInsertion(afterLParen, bridgeKeyword)); - } else if (CCK == Sema::CCK_OtherCast) { - if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) { - std::string castCode = "("; - castCode += bridgeKeyword; - castCode += castType.getAsString(); - castCode += ")"; - SourceRange Range(NCE->getOperatorLoc(), - NCE->getAngleBrackets().getEnd()); - DiagB.AddFixItHint(FixItHint::CreateReplacement(Range, castCode)); - } - } else { - std::string castCode = "("; - castCode += bridgeKeyword; - castCode += castType.getAsString(); - castCode += ")"; - Expr *castedE = castExpr->IgnoreImpCasts(); - SourceRange range = castedE->getSourceRange(); - if (isa<ParenExpr>(castedE)) { - DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(), - castCode)); - } else { - castCode += "("; - DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(), - castCode)); - DiagB.AddFixItHint(FixItHint::CreateInsertion( - S.getLocForEndOfToken(range.getEnd()), - ")")); - } - } -} - -template <typename T> -static inline T *getObjCBridgeAttr(const TypedefType *TD) { - TypedefNameDecl *TDNDecl = TD->getDecl(); - QualType QT = TDNDecl->getUnderlyingType(); - if (QT->isPointerType()) { - QT = QT->getPointeeType(); - if (const RecordType *RT = QT->getAs<RecordType>()) - if (RecordDecl *RD = RT->getDecl()->getMostRecentDecl()) - return RD->getAttr<T>(); - } - return nullptr; -} - -static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T, - TypedefNameDecl *&TDNDecl) { - while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { - TDNDecl = TD->getDecl(); - if (ObjCBridgeRelatedAttr *ObjCBAttr = - getObjCBridgeAttr<ObjCBridgeRelatedAttr>(TD)) - return ObjCBAttr; - T = TDNDecl->getUnderlyingType(); - } - return nullptr; -} - -static void -diagnoseObjCARCConversion(Sema &S, SourceRange castRange, - QualType castType, ARCConversionTypeClass castACTC, - Expr *castExpr, Expr *realCast, - ARCConversionTypeClass exprACTC, - Sema::CheckedConversionKind CCK) { - SourceLocation loc = - (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); - - if (S.makeUnavailableInSystemHeader(loc, - UnavailableAttr::IR_ARCForbiddenConversion)) - return; - - QualType castExprType = castExpr->getType(); - // Defer emitting a diagnostic for bridge-related casts; that will be - // handled by CheckObjCBridgeRelatedConversions. - TypedefNameDecl *TDNDecl = nullptr; - if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable && - ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) || - (exprACTC == ACTC_coreFoundation && castACTC == ACTC_retainable && - ObjCBridgeRelatedAttrFromType(castExprType, TDNDecl))) - return; - - unsigned srcKind = 0; - switch (exprACTC) { - case ACTC_none: - case ACTC_coreFoundation: - case ACTC_voidPtr: - srcKind = (castExprType->isPointerType() ? 1 : 0); - break; - case ACTC_retainable: - srcKind = (castExprType->isBlockPointerType() ? 2 : 3); - break; - case ACTC_indirectRetainable: - srcKind = 4; - break; - } - - // Check whether this could be fixed with a bridge cast. - SourceLocation afterLParen = S.getLocForEndOfToken(castRange.getBegin()); - SourceLocation noteLoc = afterLParen.isValid() ? afterLParen : loc; - - unsigned convKindForDiag = Sema::isCast(CCK) ? 0 : 1; - - // Bridge from an ARC type to a CF type. - if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) { - - S.Diag(loc, diag::err_arc_cast_requires_bridge) - << convKindForDiag - << 2 // of C pointer type - << castExprType - << unsigned(castType->isBlockPointerType()) // to ObjC|block type - << castType - << castRange - << castExpr->getSourceRange(); - bool br = S.isKnownName("CFBridgingRelease"); - ACCResult CreateRule = - ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr); - assert(CreateRule != ACC_bottom && "This cast should already be accepted."); - if (CreateRule != ACC_plusOne) - { - DiagnosticBuilder DiagB = - (CCK != Sema::CCK_OtherCast) ? S.Diag(noteLoc, diag::note_arc_bridge) - : S.Diag(noteLoc, diag::note_arc_cstyle_bridge); - - addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, - castType, castExpr, realCast, "__bridge ", - nullptr); - } - if (CreateRule != ACC_plusZero) - { - DiagnosticBuilder DiagB = - (CCK == Sema::CCK_OtherCast && !br) ? - S.Diag(noteLoc, diag::note_arc_cstyle_bridge_transfer) << castExprType : - S.Diag(br ? castExpr->getExprLoc() : noteLoc, - diag::note_arc_bridge_transfer) - << castExprType << br; - - addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, - castType, castExpr, realCast, "__bridge_transfer ", - br ? "CFBridgingRelease" : nullptr); - } - - return; - } - - // Bridge from a CF type to an ARC type. - if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) { - bool br = S.isKnownName("CFBridgingRetain"); - S.Diag(loc, diag::err_arc_cast_requires_bridge) - << convKindForDiag - << unsigned(castExprType->isBlockPointerType()) // of ObjC|block type - << castExprType - << 2 // to C pointer type - << castType - << castRange - << castExpr->getSourceRange(); - ACCResult CreateRule = - ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr); - assert(CreateRule != ACC_bottom && "This cast should already be accepted."); - if (CreateRule != ACC_plusOne) - { - DiagnosticBuilder DiagB = - (CCK != Sema::CCK_OtherCast) ? S.Diag(noteLoc, diag::note_arc_bridge) - : S.Diag(noteLoc, diag::note_arc_cstyle_bridge); - addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, - castType, castExpr, realCast, "__bridge ", - nullptr); - } - if (CreateRule != ACC_plusZero) - { - DiagnosticBuilder DiagB = - (CCK == Sema::CCK_OtherCast && !br) ? - S.Diag(noteLoc, diag::note_arc_cstyle_bridge_retained) << castType : - S.Diag(br ? castExpr->getExprLoc() : noteLoc, - diag::note_arc_bridge_retained) - << castType << br; - - addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, - castType, castExpr, realCast, "__bridge_retained ", - br ? "CFBridgingRetain" : nullptr); - } - - return; - } - - S.Diag(loc, diag::err_arc_mismatched_cast) - << !convKindForDiag - << srcKind << castExprType << castType - << castRange << castExpr->getSourceRange(); -} - -template <typename TB> -static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, - bool &HadTheAttribute, bool warn) { - QualType T = castExpr->getType(); - HadTheAttribute = false; - while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { - TypedefNameDecl *TDNDecl = TD->getDecl(); - if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) { - if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { - HadTheAttribute = true; - if (Parm->isStr("id")) - return true; - - NamedDecl *Target = nullptr; - // Check for an existing type with this name. - LookupResult R(S, DeclarationName(Parm), SourceLocation(), - Sema::LookupOrdinaryName); - if (S.LookupName(R, S.TUScope)) { - Target = R.getFoundDecl(); - if (Target && isa<ObjCInterfaceDecl>(Target)) { - ObjCInterfaceDecl *ExprClass = cast<ObjCInterfaceDecl>(Target); - if (const ObjCObjectPointerType *InterfacePointerType = - castType->getAsObjCInterfacePointerType()) { - ObjCInterfaceDecl *CastClass - = InterfacePointerType->getObjectType()->getInterface(); - if ((CastClass == ExprClass) || - (CastClass && CastClass->isSuperClassOf(ExprClass))) - return true; - if (warn) - S.Diag(castExpr->getBeginLoc(), diag::warn_objc_invalid_bridge) - << T << Target->getName() << castType->getPointeeType(); - return false; - } else if (castType->isObjCIdType() || - (S.Context.ObjCObjectAdoptsQTypeProtocols( - castType, ExprClass))) - // ok to cast to 'id'. - // casting to id<p-list> is ok if bridge type adopts all of - // p-list protocols. - return true; - else { - if (warn) { - S.Diag(castExpr->getBeginLoc(), diag::warn_objc_invalid_bridge) - << T << Target->getName() << castType; - S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - S.Diag(Target->getBeginLoc(), diag::note_declared_at); - } - return false; - } - } - } else if (!castType->isObjCIdType()) { - S.Diag(castExpr->getBeginLoc(), - diag::err_objc_cf_bridged_not_interface) - << castExpr->getType() << Parm; - S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - if (Target) - S.Diag(Target->getBeginLoc(), diag::note_declared_at); - } - return true; - } - return false; - } - T = TDNDecl->getUnderlyingType(); - } - return true; -} - -template <typename TB> -static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr, - bool &HadTheAttribute, bool warn) { - QualType T = castType; - HadTheAttribute = false; - while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { - TypedefNameDecl *TDNDecl = TD->getDecl(); - if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) { - if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { - HadTheAttribute = true; - if (Parm->isStr("id")) - return true; - - NamedDecl *Target = nullptr; - // Check for an existing type with this name. - LookupResult R(S, DeclarationName(Parm), SourceLocation(), - Sema::LookupOrdinaryName); - if (S.LookupName(R, S.TUScope)) { - Target = R.getFoundDecl(); - if (Target && isa<ObjCInterfaceDecl>(Target)) { - ObjCInterfaceDecl *CastClass = cast<ObjCInterfaceDecl>(Target); - if (const ObjCObjectPointerType *InterfacePointerType = - castExpr->getType()->getAsObjCInterfacePointerType()) { - ObjCInterfaceDecl *ExprClass - = InterfacePointerType->getObjectType()->getInterface(); - if ((CastClass == ExprClass) || - (ExprClass && CastClass->isSuperClassOf(ExprClass))) - return true; - if (warn) { - S.Diag(castExpr->getBeginLoc(), - diag::warn_objc_invalid_bridge_to_cf) - << castExpr->getType()->getPointeeType() << T; - S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - } - return false; - } else if (castExpr->getType()->isObjCIdType() || - (S.Context.QIdProtocolsAdoptObjCObjectProtocols( - castExpr->getType(), CastClass))) - // ok to cast an 'id' expression to a CFtype. - // ok to cast an 'id<plist>' expression to CFtype provided plist - // adopts all of CFtype's ObjetiveC's class plist. - return true; - else { - if (warn) { - S.Diag(castExpr->getBeginLoc(), - diag::warn_objc_invalid_bridge_to_cf) - << castExpr->getType() << castType; - S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - S.Diag(Target->getBeginLoc(), diag::note_declared_at); - } - return false; - } - } - } - S.Diag(castExpr->getBeginLoc(), - diag::err_objc_ns_bridged_invalid_cfobject) - << castExpr->getType() << castType; - S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - if (Target) - S.Diag(Target->getBeginLoc(), diag::note_declared_at); - return true; - } - return false; - } - T = TDNDecl->getUnderlyingType(); - } - return true; -} - -void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) { - if (!getLangOpts().ObjC) - return; - // warn in presence of __bridge casting to or from a toll free bridge cast. - ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType()); - ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType); - if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) { - bool HasObjCBridgeAttr; - bool ObjCBridgeAttrWillNotWarn = - CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr, - false); - if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr) - return; - bool HasObjCBridgeMutableAttr; - bool ObjCBridgeMutableAttrWillNotWarn = - CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr, - HasObjCBridgeMutableAttr, false); - if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr) - return; - - if (HasObjCBridgeAttr) - CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr, - true); - else if (HasObjCBridgeMutableAttr) - CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr, - HasObjCBridgeMutableAttr, true); - } - else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) { - bool HasObjCBridgeAttr; - bool ObjCBridgeAttrWillNotWarn = - CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr, - false); - if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr) - return; - bool HasObjCBridgeMutableAttr; - bool ObjCBridgeMutableAttrWillNotWarn = - CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr, - HasObjCBridgeMutableAttr, false); - if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr) - return; - - if (HasObjCBridgeAttr) - CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr, - true); - else if (HasObjCBridgeMutableAttr) - CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr, - HasObjCBridgeMutableAttr, true); - } -} - -void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) { - QualType SrcType = castExpr->getType(); - if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(castExpr)) { - if (PRE->isExplicitProperty()) { - if (ObjCPropertyDecl *PDecl = PRE->getExplicitProperty()) - SrcType = PDecl->getType(); - } - else if (PRE->isImplicitProperty()) { - if (ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) - SrcType = Getter->getReturnType(); - } - } - - ARCConversionTypeClass srcExprACTC = classifyTypeForARCConversion(SrcType); - ARCConversionTypeClass castExprACTC = classifyTypeForARCConversion(castType); - if (srcExprACTC != ACTC_retainable || castExprACTC != ACTC_coreFoundation) - return; - CheckObjCBridgeRelatedConversions(castExpr->getBeginLoc(), castType, SrcType, - castExpr); -} - -bool Sema::CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, - CastKind &Kind) { - if (!getLangOpts().ObjC) - return false; - ARCConversionTypeClass exprACTC = - classifyTypeForARCConversion(castExpr->getType()); - ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType); - if ((castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) || - (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable)) { - CheckTollFreeBridgeCast(castType, castExpr); - Kind = (castACTC == ACTC_coreFoundation) ? CK_BitCast - : CK_CPointerToObjCPointerCast; - return true; - } - return false; -} - -bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc, - QualType DestType, QualType SrcType, - ObjCInterfaceDecl *&RelatedClass, - ObjCMethodDecl *&ClassMethod, - ObjCMethodDecl *&InstanceMethod, - TypedefNameDecl *&TDNDecl, - bool CfToNs, bool Diagnose) { - QualType T = CfToNs ? SrcType : DestType; - ObjCBridgeRelatedAttr *ObjCBAttr = ObjCBridgeRelatedAttrFromType(T, TDNDecl); - if (!ObjCBAttr) - return false; - - IdentifierInfo *RCId = ObjCBAttr->getRelatedClass(); - IdentifierInfo *CMId = ObjCBAttr->getClassMethod(); - IdentifierInfo *IMId = ObjCBAttr->getInstanceMethod(); - if (!RCId) - return false; - NamedDecl *Target = nullptr; - // Check for an existing type with this name. - LookupResult R(*this, DeclarationName(RCId), SourceLocation(), - Sema::LookupOrdinaryName); - if (!LookupName(R, TUScope)) { - if (Diagnose) { - Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId - << SrcType << DestType; - Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - } - return false; - } - Target = R.getFoundDecl(); - if (Target && isa<ObjCInterfaceDecl>(Target)) - RelatedClass = cast<ObjCInterfaceDecl>(Target); - else { - if (Diagnose) { - Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId - << SrcType << DestType; - Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - if (Target) - Diag(Target->getBeginLoc(), 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) { - if (Diagnose) { - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << Sel << false; - Diag(TDNDecl->getBeginLoc(), 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) { - if (Diagnose) { - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << Sel << true; - Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - } - return false; - } - } - return true; -} - -bool -Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, - QualType DestType, QualType SrcType, - Expr *&SrcExpr, bool Diagnose) { - 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 = nullptr; - ObjCMethodDecl *InstanceMethod = nullptr; - TypedefNameDecl *TDNDecl = nullptr; - if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass, - ClassMethod, InstanceMethod, TDNDecl, - CfToNs, Diagnose)) - return false; - - if (CfToNs) { - // Implicit conversion from CF to ObjC object is needed. - if (ClassMethod) { - if (Diagnose) { - std::string ExpressionString = "["; - ExpressionString += RelatedClass->getNameAsString(); - ExpressionString += " "; - ExpressionString += ClassMethod->getSelector().getAsString(); - SourceLocation SrcExprEndLoc = - getLocForEndOfToken(SrcExpr->getEndLoc()); - // Provide a fixit: [RelatedClass ClassMethod SrcExpr] - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << ClassMethod->getSelector() << false - << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(), - ExpressionString) - << FixItHint::CreateInsertion(SrcExprEndLoc, "]"); - Diag(RelatedClass->getBeginLoc(), diag::note_declared_at); - Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - - QualType receiverType = Context.getObjCInterfaceType(RelatedClass); - // Argument. - Expr *args[] = { SrcExpr }; - ExprResult msg = BuildClassMessageImplicit(receiverType, false, - ClassMethod->getLocation(), - ClassMethod->getSelector(), ClassMethod, - MultiExprArg(args, 1)); - SrcExpr = msg.get(); - } - return true; - } - } - else { - // Implicit conversion from ObjC type to CF object is needed. - if (InstanceMethod) { - if (Diagnose) { - std::string ExpressionString; - SourceLocation SrcExprEndLoc = - getLocForEndOfToken(SrcExpr->getEndLoc()); - if (InstanceMethod->isPropertyAccessor()) - if (const ObjCPropertyDecl *PDecl = - InstanceMethod->findPropertyDecl()) { - // fixit: ObjectExpr.propertyname when it is aproperty accessor. - ExpressionString = "."; - ExpressionString += PDecl->getNameAsString(); - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << InstanceMethod->getSelector() << true - << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString); - } - if (ExpressionString.empty()) { - // Provide a fixit: [ObjectExpr InstanceMethod] - ExpressionString = " "; - ExpressionString += InstanceMethod->getSelector().getAsString(); - ExpressionString += "]"; - - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << InstanceMethod->getSelector() << true - << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(), "[") - << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString); - } - Diag(RelatedClass->getBeginLoc(), diag::note_declared_at); - Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - - ExprResult msg = - BuildInstanceMessageImplicit(SrcExpr, SrcType, - InstanceMethod->getLocation(), - InstanceMethod->getSelector(), - InstanceMethod, None); - SrcExpr = msg.get(); - } - return true; - } - } - return false; -} - -Sema::ARCConversionResult -Sema::CheckObjCConversion(SourceRange castRange, QualType castType, - Expr *&castExpr, CheckedConversionKind CCK, - bool Diagnose, bool DiagnoseCFAudited, - BinaryOperatorKind Opc) { - QualType castExprType = castExpr->getType(); - - // For the purposes of the classification, we assume reference types - // will bind to temporaries. - QualType effCastType = castType; - if (const ReferenceType *ref = castType->getAs<ReferenceType>()) - effCastType = ref->getPointeeType(); - - ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); - ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType); - if (exprACTC == castACTC) { - // Check for viability and report error if casting an rvalue to a - // life-time qualifier. - if (castACTC == ACTC_retainable && - (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) && - castType != castExprType) { - const Type *DT = castType.getTypePtr(); - QualType QDT = castType; - // We desugar some types but not others. We ignore those - // that cannot happen in a cast; i.e. auto, and those which - // should not be de-sugared; i.e typedef. - if (const ParenType *PT = dyn_cast<ParenType>(DT)) - QDT = PT->desugar(); - else if (const TypeOfType *TP = dyn_cast<TypeOfType>(DT)) - QDT = TP->desugar(); - else if (const AttributedType *AT = dyn_cast<AttributedType>(DT)) - QDT = AT->desugar(); - if (QDT != castType && - QDT.getObjCLifetime() != Qualifiers::OCL_None) { - if (Diagnose) { - SourceLocation loc = (castRange.isValid() ? castRange.getBegin() - : castExpr->getExprLoc()); - Diag(loc, diag::err_arc_nolifetime_behavior); - } - return ACR_error; - } - } - return ACR_okay; - } - - // The life-time qualifier cast check above is all we need for ObjCWeak. - // ObjCAutoRefCount has more restrictions on what is legal. - if (!getLangOpts().ObjCAutoRefCount) - return ACR_okay; - - if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return ACR_okay; - - // Allow all of these types to be cast to integer types (but not - // vice-versa). - if (castACTC == ACTC_none && castType->isIntegralType(Context)) - return ACR_okay; - - // Allow casts between pointers to lifetime types (e.g., __strong id*) - // and pointers to void (e.g., cv void *). Casting from void* to lifetime* - // must be explicit. - if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr) - return ACR_okay; - if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr && - isCast(CCK)) - return ACR_okay; - - switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) { - // For invalid casts, fall through. - case ACC_invalid: - break; - - // Do nothing for both bottom and +0. - case ACC_bottom: - case ACC_plusZero: - return ACR_okay; - - // If the result is +1, consume it here. - case ACC_plusOne: - castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(), - CK_ARCConsumeObject, castExpr, - nullptr, VK_RValue); - Cleanup.setExprNeedsCleanups(true); - return ACR_okay; - } - - // If this is a non-implicit cast from id or block type to a - // CoreFoundation type, delay complaining in case the cast is used - // in an acceptable context. - if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC) && isCast(CCK)) - return ACR_unbridged; - - // Issue a diagnostic about a missing @-sign when implicit casting a cstring - // to 'NSString *', instead of falling through to report a "bridge cast" - // diagnostic. - if (castACTC == ACTC_retainable && exprACTC == ACTC_none && - ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose)) - return ACR_error; - - // Do not issue "bridge cast" diagnostic when implicit casting - // a retainable object to a CF type parameter belonging to an audited - // CF API function. Let caller issue a normal type mismatched diagnostic - // instead. - if ((!DiagnoseCFAudited || exprACTC != ACTC_retainable || - castACTC != ACTC_coreFoundation) && - !(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && - (Opc == BO_NE || Opc == BO_EQ))) { - if (Diagnose) - diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr, - castExpr, exprACTC, CCK); - return ACR_error; - } - return ACR_okay; -} - -/// Given that we saw an expression with the ARCUnbridgedCastTy -/// placeholder type, complain bitterly. -void Sema::diagnoseARCUnbridgedCast(Expr *e) { - // We expect the spurious ImplicitCastExpr to already have been stripped. - assert(!e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast)); - CastExpr *realCast = cast<CastExpr>(e->IgnoreParens()); - - SourceRange castRange; - QualType castType; - CheckedConversionKind CCK; - - if (CStyleCastExpr *cast = dyn_cast<CStyleCastExpr>(realCast)) { - castRange = SourceRange(cast->getLParenLoc(), cast->getRParenLoc()); - castType = cast->getTypeAsWritten(); - CCK = CCK_CStyleCast; - } else if (ExplicitCastExpr *cast = dyn_cast<ExplicitCastExpr>(realCast)) { - castRange = cast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(); - castType = cast->getTypeAsWritten(); - CCK = CCK_OtherCast; - } else { - llvm_unreachable("Unexpected ImplicitCastExpr"); - } - - ARCConversionTypeClass castACTC = - classifyTypeForARCConversion(castType.getNonReferenceType()); - - Expr *castExpr = realCast->getSubExpr(); - assert(classifyTypeForARCConversion(castExpr->getType()) == ACTC_retainable); - - diagnoseObjCARCConversion(*this, castRange, castType, castACTC, - castExpr, realCast, ACTC_retainable, CCK); -} - -/// stripARCUnbridgedCast - Given an expression of ARCUnbridgedCast -/// type, remove the placeholder cast. -Expr *Sema::stripARCUnbridgedCast(Expr *e) { - assert(e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast)); - - if (ParenExpr *pe = dyn_cast<ParenExpr>(e)) { - Expr *sub = stripARCUnbridgedCast(pe->getSubExpr()); - return new (Context) ParenExpr(pe->getLParen(), pe->getRParen(), sub); - } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) { - assert(uo->getOpcode() == UO_Extension); - Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); - return new (Context) - UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(), - sub->getObjectKind(), uo->getOperatorLoc(), false); - } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { - assert(!gse->isResultDependent()); - - unsigned n = gse->getNumAssocs(); - SmallVector<Expr*, 4> subExprs(n); - SmallVector<TypeSourceInfo*, 4> subTypes(n); - for (unsigned i = 0; i != n; ++i) { - subTypes[i] = gse->getAssocTypeSourceInfo(i); - Expr *sub = gse->getAssocExpr(i); - if (i == gse->getResultIndex()) - sub = stripARCUnbridgedCast(sub); - subExprs[i] = sub; - } - - return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(), - gse->getControllingExpr(), - subTypes, subExprs, - gse->getDefaultLoc(), - gse->getRParenLoc(), - gse->containsUnexpandedParameterPack(), - gse->getResultIndex()); - } else { - assert(isa<ImplicitCastExpr>(e) && "bad form of unbridged cast!"); - return cast<ImplicitCastExpr>(e)->getSubExpr(); - } -} - -bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType, - QualType exprType) { - QualType canCastType = - Context.getCanonicalType(castType).getUnqualifiedType(); - QualType canExprType = - Context.getCanonicalType(exprType).getUnqualifiedType(); - if (isa<ObjCObjectPointerType>(canCastType) && - castType.getObjCLifetime() == Qualifiers::OCL_Weak && - canExprType->isObjCObjectPointerType()) { - if (const ObjCObjectPointerType *ObjT = - canExprType->getAs<ObjCObjectPointerType>()) - if (const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl()) - return !ObjI->isArcWeakrefUnavailable(); - } - return true; -} - -/// Look for an ObjCReclaimReturnedObject cast and destroy it. -static Expr *maybeUndoReclaimObject(Expr *e) { - Expr *curExpr = e, *prevExpr = nullptr; - - // Walk down the expression until we hit an implicit cast of kind - // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast. - while (true) { - if (auto *pe = dyn_cast<ParenExpr>(curExpr)) { - prevExpr = curExpr; - curExpr = pe->getSubExpr(); - continue; - } - - if (auto *ce = dyn_cast<CastExpr>(curExpr)) { - if (auto *ice = dyn_cast<ImplicitCastExpr>(ce)) - if (ice->getCastKind() == CK_ARCReclaimReturnedObject) { - if (!prevExpr) - return ice->getSubExpr(); - if (auto *pe = dyn_cast<ParenExpr>(prevExpr)) - pe->setSubExpr(ice->getSubExpr()); - else - cast<CastExpr>(prevExpr)->setSubExpr(ice->getSubExpr()); - return e; - } - - prevExpr = curExpr; - curExpr = ce->getSubExpr(); - continue; - } - - // Break out of the loop if curExpr is neither a Paren nor a Cast. - break; - } - - return e; -} - -ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, - ObjCBridgeCastKind Kind, - SourceLocation BridgeKeywordLoc, - TypeSourceInfo *TSInfo, - Expr *SubExpr) { - ExprResult SubResult = UsualUnaryConversions(SubExpr); - if (SubResult.isInvalid()) return ExprError(); - SubExpr = SubResult.get(); - - QualType T = TSInfo->getType(); - QualType FromType = SubExpr->getType(); - - CastKind CK; - - bool MustConsume = false; - if (T->isDependentType() || SubExpr->isTypeDependent()) { - // Okay: we'll build a dependent expression type. - CK = CK_Dependent; - } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) { - // Casting CF -> id - CK = (T->isBlockPointerType() ? CK_AnyPointerToBlockPointerCast - : CK_CPointerToObjCPointerCast); - switch (Kind) { - case OBC_Bridge: - break; - - case OBC_BridgeRetained: { - bool br = isKnownName("CFBridgingRelease"); - Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind) - << 2 - << FromType - << (T->isBlockPointerType()? 1 : 0) - << T - << SubExpr->getSourceRange() - << Kind; - Diag(BridgeKeywordLoc, diag::note_arc_bridge) - << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge"); - Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer) - << FromType << br - << FixItHint::CreateReplacement(BridgeKeywordLoc, - br ? "CFBridgingRelease " - : "__bridge_transfer "); - - Kind = OBC_Bridge; - break; - } - - case OBC_BridgeTransfer: - // We must consume the Objective-C object produced by the cast. - MustConsume = true; - break; - } - } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) { - // Okay: id -> CF - CK = CK_BitCast; - switch (Kind) { - case OBC_Bridge: - // Reclaiming a value that's going to be __bridge-casted to CF - // is very dangerous, so we don't do it. - SubExpr = maybeUndoReclaimObject(SubExpr); - break; - - case OBC_BridgeRetained: - // Produce the object before casting it. - SubExpr = ImplicitCastExpr::Create(Context, FromType, - CK_ARCProduceObject, - SubExpr, nullptr, VK_RValue); - break; - - case OBC_BridgeTransfer: { - bool br = isKnownName("CFBridgingRetain"); - Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind) - << (FromType->isBlockPointerType()? 1 : 0) - << FromType - << 2 - << T - << SubExpr->getSourceRange() - << Kind; - - Diag(BridgeKeywordLoc, diag::note_arc_bridge) - << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge "); - Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained) - << T << br - << FixItHint::CreateReplacement(BridgeKeywordLoc, - br ? "CFBridgingRetain " : "__bridge_retained"); - - Kind = OBC_Bridge; - break; - } - } - } else { - Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible) - << FromType << T << Kind - << SubExpr->getSourceRange() - << TSInfo->getTypeLoc().getSourceRange(); - return ExprError(); - } - - Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, CK, - BridgeKeywordLoc, - TSInfo, SubExpr); - - if (MustConsume) { - Cleanup.setExprNeedsCleanups(true); - Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result, - nullptr, VK_RValue); - } - - return Result; -} - -ExprResult Sema::ActOnObjCBridgedCast(Scope *S, - SourceLocation LParenLoc, - ObjCBridgeCastKind Kind, - SourceLocation BridgeKeywordLoc, - ParsedType Type, - SourceLocation RParenLoc, - Expr *SubExpr) { - TypeSourceInfo *TSInfo = nullptr; - QualType T = GetTypeFromParser(Type, &TSInfo); - if (Kind == OBC_Bridge) - CheckTollFreeBridgeCast(T, SubExpr); - if (!TSInfo) - TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc); - return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo, - SubExpr); -} |
