1e5dd7070Spatrick //===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements semantic analysis for Objective-C expressions.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/AST/ASTContext.h"
14e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
15e5dd7070Spatrick #include "clang/AST/ExprObjC.h"
16e5dd7070Spatrick #include "clang/AST/StmtVisitor.h"
17e5dd7070Spatrick #include "clang/AST/TypeLoc.h"
18e5dd7070Spatrick #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
19e5dd7070Spatrick #include "clang/Basic/Builtins.h"
20e5dd7070Spatrick #include "clang/Edit/Commit.h"
21e5dd7070Spatrick #include "clang/Edit/Rewriters.h"
22e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
23e5dd7070Spatrick #include "clang/Sema/Initialization.h"
24e5dd7070Spatrick #include "clang/Sema/Lookup.h"
25e5dd7070Spatrick #include "clang/Sema/Scope.h"
26e5dd7070Spatrick #include "clang/Sema/ScopeInfo.h"
27e5dd7070Spatrick #include "clang/Sema/SemaInternal.h"
28e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
29e5dd7070Spatrick #include "llvm/Support/ConvertUTF.h"
30*12c85518Srobert #include <optional>
31e5dd7070Spatrick
32e5dd7070Spatrick using namespace clang;
33e5dd7070Spatrick using namespace sema;
34*12c85518Srobert using llvm::ArrayRef;
35e5dd7070Spatrick
ParseObjCStringLiteral(SourceLocation * AtLocs,ArrayRef<Expr * > Strings)36e5dd7070Spatrick ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
37e5dd7070Spatrick ArrayRef<Expr *> Strings) {
38e5dd7070Spatrick // Most ObjC strings are formed out of a single piece. However, we *can*
39e5dd7070Spatrick // have strings formed out of multiple @ strings with multiple pptokens in
40e5dd7070Spatrick // each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one
41e5dd7070Spatrick // StringLiteral for ObjCStringLiteral to hold onto.
42e5dd7070Spatrick StringLiteral *S = cast<StringLiteral>(Strings[0]);
43e5dd7070Spatrick
44e5dd7070Spatrick // If we have a multi-part string, merge it all together.
45e5dd7070Spatrick if (Strings.size() != 1) {
46e5dd7070Spatrick // Concatenate objc strings.
47e5dd7070Spatrick SmallString<128> StrBuf;
48e5dd7070Spatrick SmallVector<SourceLocation, 8> StrLocs;
49e5dd7070Spatrick
50e5dd7070Spatrick for (Expr *E : Strings) {
51e5dd7070Spatrick S = cast<StringLiteral>(E);
52e5dd7070Spatrick
53e5dd7070Spatrick // ObjC strings can't be wide or UTF.
54*12c85518Srobert if (!S->isOrdinary()) {
55e5dd7070Spatrick Diag(S->getBeginLoc(), diag::err_cfstring_literal_not_string_constant)
56e5dd7070Spatrick << S->getSourceRange();
57e5dd7070Spatrick return true;
58e5dd7070Spatrick }
59e5dd7070Spatrick
60e5dd7070Spatrick // Append the string.
61e5dd7070Spatrick StrBuf += S->getString();
62e5dd7070Spatrick
63e5dd7070Spatrick // Get the locations of the string tokens.
64e5dd7070Spatrick StrLocs.append(S->tokloc_begin(), S->tokloc_end());
65e5dd7070Spatrick }
66e5dd7070Spatrick
67e5dd7070Spatrick // Create the aggregate string with the appropriate content and location
68e5dd7070Spatrick // information.
69e5dd7070Spatrick const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
70e5dd7070Spatrick assert(CAT && "String literal not of constant array type!");
71e5dd7070Spatrick QualType StrTy = Context.getConstantArrayType(
72e5dd7070Spatrick CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), nullptr,
73e5dd7070Spatrick CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers());
74*12c85518Srobert S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ordinary,
75e5dd7070Spatrick /*Pascal=*/false, StrTy, &StrLocs[0],
76e5dd7070Spatrick StrLocs.size());
77e5dd7070Spatrick }
78e5dd7070Spatrick
79e5dd7070Spatrick return BuildObjCStringLiteral(AtLocs[0], S);
80e5dd7070Spatrick }
81e5dd7070Spatrick
BuildObjCStringLiteral(SourceLocation AtLoc,StringLiteral * S)82e5dd7070Spatrick ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
83e5dd7070Spatrick // Verify that this composite string is acceptable for ObjC strings.
84e5dd7070Spatrick if (CheckObjCString(S))
85e5dd7070Spatrick return true;
86e5dd7070Spatrick
87e5dd7070Spatrick // Initialize the constant string interface lazily. This assumes
88e5dd7070Spatrick // the NSString interface is seen in this translation unit. Note: We
89e5dd7070Spatrick // don't use NSConstantString, since the runtime team considers this
90e5dd7070Spatrick // interface private (even though it appears in the header files).
91e5dd7070Spatrick QualType Ty = Context.getObjCConstantStringInterface();
92e5dd7070Spatrick if (!Ty.isNull()) {
93e5dd7070Spatrick Ty = Context.getObjCObjectPointerType(Ty);
94e5dd7070Spatrick } else if (getLangOpts().NoConstantCFStrings) {
95e5dd7070Spatrick IdentifierInfo *NSIdent=nullptr;
96e5dd7070Spatrick std::string StringClass(getLangOpts().ObjCConstantStringClass);
97e5dd7070Spatrick
98e5dd7070Spatrick if (StringClass.empty())
99e5dd7070Spatrick NSIdent = &Context.Idents.get("NSConstantString");
100e5dd7070Spatrick else
101e5dd7070Spatrick NSIdent = &Context.Idents.get(StringClass);
102e5dd7070Spatrick
103e5dd7070Spatrick NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
104e5dd7070Spatrick LookupOrdinaryName);
105e5dd7070Spatrick if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
106e5dd7070Spatrick Context.setObjCConstantStringInterface(StrIF);
107e5dd7070Spatrick Ty = Context.getObjCConstantStringInterface();
108e5dd7070Spatrick Ty = Context.getObjCObjectPointerType(Ty);
109e5dd7070Spatrick } else {
110e5dd7070Spatrick // If there is no NSConstantString interface defined then treat this
111e5dd7070Spatrick // as error and recover from it.
112e5dd7070Spatrick Diag(S->getBeginLoc(), diag::err_no_nsconstant_string_class)
113e5dd7070Spatrick << NSIdent << S->getSourceRange();
114e5dd7070Spatrick Ty = Context.getObjCIdType();
115e5dd7070Spatrick }
116e5dd7070Spatrick } else {
117e5dd7070Spatrick IdentifierInfo *NSIdent = NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
118e5dd7070Spatrick NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
119e5dd7070Spatrick LookupOrdinaryName);
120e5dd7070Spatrick if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
121e5dd7070Spatrick Context.setObjCConstantStringInterface(StrIF);
122e5dd7070Spatrick Ty = Context.getObjCConstantStringInterface();
123e5dd7070Spatrick Ty = Context.getObjCObjectPointerType(Ty);
124e5dd7070Spatrick } else {
125e5dd7070Spatrick // If there is no NSString interface defined, implicitly declare
126e5dd7070Spatrick // a @class NSString; and use that instead. This is to make sure
127e5dd7070Spatrick // type of an NSString literal is represented correctly, instead of
128e5dd7070Spatrick // being an 'id' type.
129e5dd7070Spatrick Ty = Context.getObjCNSStringType();
130e5dd7070Spatrick if (Ty.isNull()) {
131e5dd7070Spatrick ObjCInterfaceDecl *NSStringIDecl =
132e5dd7070Spatrick ObjCInterfaceDecl::Create (Context,
133e5dd7070Spatrick Context.getTranslationUnitDecl(),
134e5dd7070Spatrick SourceLocation(), NSIdent,
135e5dd7070Spatrick nullptr, nullptr, SourceLocation());
136e5dd7070Spatrick Ty = Context.getObjCInterfaceType(NSStringIDecl);
137e5dd7070Spatrick Context.setObjCNSStringType(Ty);
138e5dd7070Spatrick }
139e5dd7070Spatrick Ty = Context.getObjCObjectPointerType(Ty);
140e5dd7070Spatrick }
141e5dd7070Spatrick }
142e5dd7070Spatrick
143e5dd7070Spatrick return new (Context) ObjCStringLiteral(S, Ty, AtLoc);
144e5dd7070Spatrick }
145e5dd7070Spatrick
146e5dd7070Spatrick /// Emits an error if the given method does not exist, or if the return
147e5dd7070Spatrick /// type is not an Objective-C object.
validateBoxingMethod(Sema & S,SourceLocation Loc,const ObjCInterfaceDecl * Class,Selector Sel,const ObjCMethodDecl * Method)148e5dd7070Spatrick static bool validateBoxingMethod(Sema &S, SourceLocation Loc,
149e5dd7070Spatrick const ObjCInterfaceDecl *Class,
150e5dd7070Spatrick Selector Sel, const ObjCMethodDecl *Method) {
151e5dd7070Spatrick if (!Method) {
152e5dd7070Spatrick // FIXME: Is there a better way to avoid quotes than using getName()?
153e5dd7070Spatrick S.Diag(Loc, diag::err_undeclared_boxing_method) << Sel << Class->getName();
154e5dd7070Spatrick return false;
155e5dd7070Spatrick }
156e5dd7070Spatrick
157e5dd7070Spatrick // Make sure the return type is reasonable.
158e5dd7070Spatrick QualType ReturnType = Method->getReturnType();
159e5dd7070Spatrick if (!ReturnType->isObjCObjectPointerType()) {
160e5dd7070Spatrick S.Diag(Loc, diag::err_objc_literal_method_sig)
161e5dd7070Spatrick << Sel;
162e5dd7070Spatrick S.Diag(Method->getLocation(), diag::note_objc_literal_method_return)
163e5dd7070Spatrick << ReturnType;
164e5dd7070Spatrick return false;
165e5dd7070Spatrick }
166e5dd7070Spatrick
167e5dd7070Spatrick return true;
168e5dd7070Spatrick }
169e5dd7070Spatrick
170e5dd7070Spatrick /// Maps ObjCLiteralKind to NSClassIdKindKind
ClassKindFromLiteralKind(Sema::ObjCLiteralKind LiteralKind)171e5dd7070Spatrick static NSAPI::NSClassIdKindKind ClassKindFromLiteralKind(
172e5dd7070Spatrick Sema::ObjCLiteralKind LiteralKind) {
173e5dd7070Spatrick switch (LiteralKind) {
174e5dd7070Spatrick case Sema::LK_Array:
175e5dd7070Spatrick return NSAPI::ClassId_NSArray;
176e5dd7070Spatrick case Sema::LK_Dictionary:
177e5dd7070Spatrick return NSAPI::ClassId_NSDictionary;
178e5dd7070Spatrick case Sema::LK_Numeric:
179e5dd7070Spatrick return NSAPI::ClassId_NSNumber;
180e5dd7070Spatrick case Sema::LK_String:
181e5dd7070Spatrick return NSAPI::ClassId_NSString;
182e5dd7070Spatrick case Sema::LK_Boxed:
183e5dd7070Spatrick return NSAPI::ClassId_NSValue;
184e5dd7070Spatrick
185e5dd7070Spatrick // there is no corresponding matching
186e5dd7070Spatrick // between LK_None/LK_Block and NSClassIdKindKind
187e5dd7070Spatrick case Sema::LK_Block:
188e5dd7070Spatrick case Sema::LK_None:
189e5dd7070Spatrick break;
190e5dd7070Spatrick }
191e5dd7070Spatrick llvm_unreachable("LiteralKind can't be converted into a ClassKind");
192e5dd7070Spatrick }
193e5dd7070Spatrick
194e5dd7070Spatrick /// Validates ObjCInterfaceDecl availability.
195e5dd7070Spatrick /// ObjCInterfaceDecl, used to create ObjC literals, should be defined
196e5dd7070Spatrick /// if clang not in a debugger mode.
ValidateObjCLiteralInterfaceDecl(Sema & S,ObjCInterfaceDecl * Decl,SourceLocation Loc,Sema::ObjCLiteralKind LiteralKind)197e5dd7070Spatrick static bool ValidateObjCLiteralInterfaceDecl(Sema &S, ObjCInterfaceDecl *Decl,
198e5dd7070Spatrick SourceLocation Loc,
199e5dd7070Spatrick Sema::ObjCLiteralKind LiteralKind) {
200e5dd7070Spatrick if (!Decl) {
201e5dd7070Spatrick NSAPI::NSClassIdKindKind Kind = ClassKindFromLiteralKind(LiteralKind);
202e5dd7070Spatrick IdentifierInfo *II = S.NSAPIObj->getNSClassId(Kind);
203e5dd7070Spatrick S.Diag(Loc, diag::err_undeclared_objc_literal_class)
204e5dd7070Spatrick << II->getName() << LiteralKind;
205e5dd7070Spatrick return false;
206e5dd7070Spatrick } else if (!Decl->hasDefinition() && !S.getLangOpts().DebuggerObjCLiteral) {
207e5dd7070Spatrick S.Diag(Loc, diag::err_undeclared_objc_literal_class)
208e5dd7070Spatrick << Decl->getName() << LiteralKind;
209e5dd7070Spatrick S.Diag(Decl->getLocation(), diag::note_forward_class);
210e5dd7070Spatrick return false;
211e5dd7070Spatrick }
212e5dd7070Spatrick
213e5dd7070Spatrick return true;
214e5dd7070Spatrick }
215e5dd7070Spatrick
216e5dd7070Spatrick /// Looks up ObjCInterfaceDecl of a given NSClassIdKindKind.
217e5dd7070Spatrick /// Used to create ObjC literals, such as NSDictionary (@{}),
218e5dd7070Spatrick /// NSArray (@[]) and Boxed Expressions (@())
LookupObjCInterfaceDeclForLiteral(Sema & S,SourceLocation Loc,Sema::ObjCLiteralKind LiteralKind)219e5dd7070Spatrick static ObjCInterfaceDecl *LookupObjCInterfaceDeclForLiteral(Sema &S,
220e5dd7070Spatrick SourceLocation Loc,
221e5dd7070Spatrick Sema::ObjCLiteralKind LiteralKind) {
222e5dd7070Spatrick NSAPI::NSClassIdKindKind ClassKind = ClassKindFromLiteralKind(LiteralKind);
223e5dd7070Spatrick IdentifierInfo *II = S.NSAPIObj->getNSClassId(ClassKind);
224e5dd7070Spatrick NamedDecl *IF = S.LookupSingleName(S.TUScope, II, Loc,
225e5dd7070Spatrick Sema::LookupOrdinaryName);
226e5dd7070Spatrick ObjCInterfaceDecl *ID = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
227e5dd7070Spatrick if (!ID && S.getLangOpts().DebuggerObjCLiteral) {
228e5dd7070Spatrick ASTContext &Context = S.Context;
229e5dd7070Spatrick TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
230e5dd7070Spatrick ID = ObjCInterfaceDecl::Create (Context, TU, SourceLocation(), II,
231e5dd7070Spatrick nullptr, nullptr, SourceLocation());
232e5dd7070Spatrick }
233e5dd7070Spatrick
234e5dd7070Spatrick if (!ValidateObjCLiteralInterfaceDecl(S, ID, Loc, LiteralKind)) {
235e5dd7070Spatrick ID = nullptr;
236e5dd7070Spatrick }
237e5dd7070Spatrick
238e5dd7070Spatrick return ID;
239e5dd7070Spatrick }
240e5dd7070Spatrick
241e5dd7070Spatrick /// Retrieve the NSNumber factory method that should be used to create
242e5dd7070Spatrick /// an Objective-C literal for the given type.
getNSNumberFactoryMethod(Sema & S,SourceLocation Loc,QualType NumberType,bool isLiteral=false,SourceRange R=SourceRange ())243e5dd7070Spatrick static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
244e5dd7070Spatrick QualType NumberType,
245e5dd7070Spatrick bool isLiteral = false,
246e5dd7070Spatrick SourceRange R = SourceRange()) {
247*12c85518Srobert std::optional<NSAPI::NSNumberLiteralMethodKind> Kind =
248e5dd7070Spatrick S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
249e5dd7070Spatrick
250e5dd7070Spatrick if (!Kind) {
251e5dd7070Spatrick if (isLiteral) {
252e5dd7070Spatrick S.Diag(Loc, diag::err_invalid_nsnumber_type)
253e5dd7070Spatrick << NumberType << R;
254e5dd7070Spatrick }
255e5dd7070Spatrick return nullptr;
256e5dd7070Spatrick }
257e5dd7070Spatrick
258e5dd7070Spatrick // If we already looked up this method, we're done.
259e5dd7070Spatrick if (S.NSNumberLiteralMethods[*Kind])
260e5dd7070Spatrick return S.NSNumberLiteralMethods[*Kind];
261e5dd7070Spatrick
262e5dd7070Spatrick Selector Sel = S.NSAPIObj->getNSNumberLiteralSelector(*Kind,
263e5dd7070Spatrick /*Instance=*/false);
264e5dd7070Spatrick
265e5dd7070Spatrick ASTContext &CX = S.Context;
266e5dd7070Spatrick
267e5dd7070Spatrick // Look up the NSNumber class, if we haven't done so already. It's cached
268e5dd7070Spatrick // in the Sema instance.
269e5dd7070Spatrick if (!S.NSNumberDecl) {
270e5dd7070Spatrick S.NSNumberDecl = LookupObjCInterfaceDeclForLiteral(S, Loc,
271e5dd7070Spatrick Sema::LK_Numeric);
272e5dd7070Spatrick if (!S.NSNumberDecl) {
273e5dd7070Spatrick return nullptr;
274e5dd7070Spatrick }
275e5dd7070Spatrick }
276e5dd7070Spatrick
277e5dd7070Spatrick if (S.NSNumberPointer.isNull()) {
278e5dd7070Spatrick // generate the pointer to NSNumber type.
279e5dd7070Spatrick QualType NSNumberObject = CX.getObjCInterfaceType(S.NSNumberDecl);
280e5dd7070Spatrick S.NSNumberPointer = CX.getObjCObjectPointerType(NSNumberObject);
281e5dd7070Spatrick }
282e5dd7070Spatrick
283e5dd7070Spatrick // Look for the appropriate method within NSNumber.
284e5dd7070Spatrick ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);
285e5dd7070Spatrick if (!Method && S.getLangOpts().DebuggerObjCLiteral) {
286e5dd7070Spatrick // create a stub definition this NSNumber factory method.
287e5dd7070Spatrick TypeSourceInfo *ReturnTInfo = nullptr;
288e5dd7070Spatrick Method =
289e5dd7070Spatrick ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel,
290e5dd7070Spatrick S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl,
291e5dd7070Spatrick /*isInstance=*/false, /*isVariadic=*/false,
292e5dd7070Spatrick /*isPropertyAccessor=*/false,
293e5dd7070Spatrick /*isSynthesizedAccessorStub=*/false,
294e5dd7070Spatrick /*isImplicitlyDeclared=*/true,
295e5dd7070Spatrick /*isDefined=*/false, ObjCMethodDecl::Required,
296e5dd7070Spatrick /*HasRelatedResultType=*/false);
297e5dd7070Spatrick ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method,
298e5dd7070Spatrick SourceLocation(), SourceLocation(),
299e5dd7070Spatrick &CX.Idents.get("value"),
300e5dd7070Spatrick NumberType, /*TInfo=*/nullptr,
301e5dd7070Spatrick SC_None, nullptr);
302*12c85518Srobert Method->setMethodParams(S.Context, value, std::nullopt);
303e5dd7070Spatrick }
304e5dd7070Spatrick
305e5dd7070Spatrick if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method))
306e5dd7070Spatrick return nullptr;
307e5dd7070Spatrick
308e5dd7070Spatrick // Note: if the parameter type is out-of-line, we'll catch it later in the
309e5dd7070Spatrick // implicit conversion.
310e5dd7070Spatrick
311e5dd7070Spatrick S.NSNumberLiteralMethods[*Kind] = Method;
312e5dd7070Spatrick return Method;
313e5dd7070Spatrick }
314e5dd7070Spatrick
315e5dd7070Spatrick /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the
316e5dd7070Spatrick /// numeric literal expression. Type of the expression will be "NSNumber *".
BuildObjCNumericLiteral(SourceLocation AtLoc,Expr * Number)317e5dd7070Spatrick ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
318e5dd7070Spatrick // Determine the type of the literal.
319e5dd7070Spatrick QualType NumberType = Number->getType();
320e5dd7070Spatrick if (CharacterLiteral *Char = dyn_cast<CharacterLiteral>(Number)) {
321e5dd7070Spatrick // In C, character literals have type 'int'. That's not the type we want
322e5dd7070Spatrick // to use to determine the Objective-c literal kind.
323e5dd7070Spatrick switch (Char->getKind()) {
324e5dd7070Spatrick case CharacterLiteral::Ascii:
325e5dd7070Spatrick case CharacterLiteral::UTF8:
326e5dd7070Spatrick NumberType = Context.CharTy;
327e5dd7070Spatrick break;
328e5dd7070Spatrick
329e5dd7070Spatrick case CharacterLiteral::Wide:
330e5dd7070Spatrick NumberType = Context.getWideCharType();
331e5dd7070Spatrick break;
332e5dd7070Spatrick
333e5dd7070Spatrick case CharacterLiteral::UTF16:
334e5dd7070Spatrick NumberType = Context.Char16Ty;
335e5dd7070Spatrick break;
336e5dd7070Spatrick
337e5dd7070Spatrick case CharacterLiteral::UTF32:
338e5dd7070Spatrick NumberType = Context.Char32Ty;
339e5dd7070Spatrick break;
340e5dd7070Spatrick }
341e5dd7070Spatrick }
342e5dd7070Spatrick
343e5dd7070Spatrick // Look for the appropriate method within NSNumber.
344e5dd7070Spatrick // Construct the literal.
345e5dd7070Spatrick SourceRange NR(Number->getSourceRange());
346e5dd7070Spatrick ObjCMethodDecl *Method = getNSNumberFactoryMethod(*this, AtLoc, NumberType,
347e5dd7070Spatrick true, NR);
348e5dd7070Spatrick if (!Method)
349e5dd7070Spatrick return ExprError();
350e5dd7070Spatrick
351e5dd7070Spatrick // Convert the number to the type that the parameter expects.
352e5dd7070Spatrick ParmVarDecl *ParamDecl = Method->parameters()[0];
353e5dd7070Spatrick InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
354e5dd7070Spatrick ParamDecl);
355e5dd7070Spatrick ExprResult ConvertedNumber = PerformCopyInitialization(Entity,
356e5dd7070Spatrick SourceLocation(),
357e5dd7070Spatrick Number);
358e5dd7070Spatrick if (ConvertedNumber.isInvalid())
359e5dd7070Spatrick return ExprError();
360e5dd7070Spatrick Number = ConvertedNumber.get();
361e5dd7070Spatrick
362e5dd7070Spatrick // Use the effective source range of the literal, including the leading '@'.
363e5dd7070Spatrick return MaybeBindToTemporary(
364e5dd7070Spatrick new (Context) ObjCBoxedExpr(Number, NSNumberPointer, Method,
365e5dd7070Spatrick SourceRange(AtLoc, NR.getEnd())));
366e5dd7070Spatrick }
367e5dd7070Spatrick
ActOnObjCBoolLiteral(SourceLocation AtLoc,SourceLocation ValueLoc,bool Value)368e5dd7070Spatrick ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc,
369e5dd7070Spatrick SourceLocation ValueLoc,
370e5dd7070Spatrick bool Value) {
371e5dd7070Spatrick ExprResult Inner;
372e5dd7070Spatrick if (getLangOpts().CPlusPlus) {
373e5dd7070Spatrick Inner = ActOnCXXBoolLiteral(ValueLoc, Value? tok::kw_true : tok::kw_false);
374e5dd7070Spatrick } else {
375e5dd7070Spatrick // C doesn't actually have a way to represent literal values of type
376e5dd7070Spatrick // _Bool. So, we'll use 0/1 and implicit cast to _Bool.
377e5dd7070Spatrick Inner = ActOnIntegerConstant(ValueLoc, Value? 1 : 0);
378e5dd7070Spatrick Inner = ImpCastExprToType(Inner.get(), Context.BoolTy,
379e5dd7070Spatrick CK_IntegralToBoolean);
380e5dd7070Spatrick }
381e5dd7070Spatrick
382e5dd7070Spatrick return BuildObjCNumericLiteral(AtLoc, Inner.get());
383e5dd7070Spatrick }
384e5dd7070Spatrick
385e5dd7070Spatrick /// Check that the given expression is a valid element of an Objective-C
386e5dd7070Spatrick /// collection literal.
CheckObjCCollectionLiteralElement(Sema & S,Expr * Element,QualType T,bool ArrayLiteral=false)387e5dd7070Spatrick static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
388e5dd7070Spatrick QualType T,
389e5dd7070Spatrick bool ArrayLiteral = false) {
390e5dd7070Spatrick // If the expression is type-dependent, there's nothing for us to do.
391e5dd7070Spatrick if (Element->isTypeDependent())
392e5dd7070Spatrick return Element;
393e5dd7070Spatrick
394e5dd7070Spatrick ExprResult Result = S.CheckPlaceholderExpr(Element);
395e5dd7070Spatrick if (Result.isInvalid())
396e5dd7070Spatrick return ExprError();
397e5dd7070Spatrick Element = Result.get();
398e5dd7070Spatrick
399e5dd7070Spatrick // In C++, check for an implicit conversion to an Objective-C object pointer
400e5dd7070Spatrick // type.
401e5dd7070Spatrick if (S.getLangOpts().CPlusPlus && Element->getType()->isRecordType()) {
402e5dd7070Spatrick InitializedEntity Entity
403e5dd7070Spatrick = InitializedEntity::InitializeParameter(S.Context, T,
404e5dd7070Spatrick /*Consumed=*/false);
405e5dd7070Spatrick InitializationKind Kind = InitializationKind::CreateCopy(
406e5dd7070Spatrick Element->getBeginLoc(), SourceLocation());
407e5dd7070Spatrick InitializationSequence Seq(S, Entity, Kind, Element);
408e5dd7070Spatrick if (!Seq.Failed())
409e5dd7070Spatrick return Seq.Perform(S, Entity, Kind, Element);
410e5dd7070Spatrick }
411e5dd7070Spatrick
412e5dd7070Spatrick Expr *OrigElement = Element;
413e5dd7070Spatrick
414e5dd7070Spatrick // Perform lvalue-to-rvalue conversion.
415e5dd7070Spatrick Result = S.DefaultLvalueConversion(Element);
416e5dd7070Spatrick if (Result.isInvalid())
417e5dd7070Spatrick return ExprError();
418e5dd7070Spatrick Element = Result.get();
419e5dd7070Spatrick
420e5dd7070Spatrick // Make sure that we have an Objective-C pointer type or block.
421e5dd7070Spatrick if (!Element->getType()->isObjCObjectPointerType() &&
422e5dd7070Spatrick !Element->getType()->isBlockPointerType()) {
423e5dd7070Spatrick bool Recovered = false;
424e5dd7070Spatrick
425e5dd7070Spatrick // If this is potentially an Objective-C numeric literal, add the '@'.
426e5dd7070Spatrick if (isa<IntegerLiteral>(OrigElement) ||
427e5dd7070Spatrick isa<CharacterLiteral>(OrigElement) ||
428e5dd7070Spatrick isa<FloatingLiteral>(OrigElement) ||
429e5dd7070Spatrick isa<ObjCBoolLiteralExpr>(OrigElement) ||
430e5dd7070Spatrick isa<CXXBoolLiteralExpr>(OrigElement)) {
431e5dd7070Spatrick if (S.NSAPIObj->getNSNumberFactoryMethodKind(OrigElement->getType())) {
432e5dd7070Spatrick int Which = isa<CharacterLiteral>(OrigElement) ? 1
433e5dd7070Spatrick : (isa<CXXBoolLiteralExpr>(OrigElement) ||
434e5dd7070Spatrick isa<ObjCBoolLiteralExpr>(OrigElement)) ? 2
435e5dd7070Spatrick : 3;
436e5dd7070Spatrick
437e5dd7070Spatrick S.Diag(OrigElement->getBeginLoc(), diag::err_box_literal_collection)
438e5dd7070Spatrick << Which << OrigElement->getSourceRange()
439e5dd7070Spatrick << FixItHint::CreateInsertion(OrigElement->getBeginLoc(), "@");
440e5dd7070Spatrick
441e5dd7070Spatrick Result =
442e5dd7070Spatrick S.BuildObjCNumericLiteral(OrigElement->getBeginLoc(), OrigElement);
443e5dd7070Spatrick if (Result.isInvalid())
444e5dd7070Spatrick return ExprError();
445e5dd7070Spatrick
446e5dd7070Spatrick Element = Result.get();
447e5dd7070Spatrick Recovered = true;
448e5dd7070Spatrick }
449e5dd7070Spatrick }
450e5dd7070Spatrick // If this is potentially an Objective-C string literal, add the '@'.
451e5dd7070Spatrick else if (StringLiteral *String = dyn_cast<StringLiteral>(OrigElement)) {
452*12c85518Srobert if (String->isOrdinary()) {
453e5dd7070Spatrick S.Diag(OrigElement->getBeginLoc(), diag::err_box_literal_collection)
454e5dd7070Spatrick << 0 << OrigElement->getSourceRange()
455e5dd7070Spatrick << FixItHint::CreateInsertion(OrigElement->getBeginLoc(), "@");
456e5dd7070Spatrick
457e5dd7070Spatrick Result = S.BuildObjCStringLiteral(OrigElement->getBeginLoc(), String);
458e5dd7070Spatrick if (Result.isInvalid())
459e5dd7070Spatrick return ExprError();
460e5dd7070Spatrick
461e5dd7070Spatrick Element = Result.get();
462e5dd7070Spatrick Recovered = true;
463e5dd7070Spatrick }
464e5dd7070Spatrick }
465e5dd7070Spatrick
466e5dd7070Spatrick if (!Recovered) {
467e5dd7070Spatrick S.Diag(Element->getBeginLoc(), diag::err_invalid_collection_element)
468e5dd7070Spatrick << Element->getType();
469e5dd7070Spatrick return ExprError();
470e5dd7070Spatrick }
471e5dd7070Spatrick }
472e5dd7070Spatrick if (ArrayLiteral)
473e5dd7070Spatrick if (ObjCStringLiteral *getString =
474e5dd7070Spatrick dyn_cast<ObjCStringLiteral>(OrigElement)) {
475e5dd7070Spatrick if (StringLiteral *SL = getString->getString()) {
476e5dd7070Spatrick unsigned numConcat = SL->getNumConcatenated();
477e5dd7070Spatrick if (numConcat > 1) {
478e5dd7070Spatrick // Only warn if the concatenated string doesn't come from a macro.
479e5dd7070Spatrick bool hasMacro = false;
480e5dd7070Spatrick for (unsigned i = 0; i < numConcat ; ++i)
481e5dd7070Spatrick if (SL->getStrTokenLoc(i).isMacroID()) {
482e5dd7070Spatrick hasMacro = true;
483e5dd7070Spatrick break;
484e5dd7070Spatrick }
485e5dd7070Spatrick if (!hasMacro)
486e5dd7070Spatrick S.Diag(Element->getBeginLoc(),
487e5dd7070Spatrick diag::warn_concatenated_nsarray_literal)
488e5dd7070Spatrick << Element->getType();
489e5dd7070Spatrick }
490e5dd7070Spatrick }
491e5dd7070Spatrick }
492e5dd7070Spatrick
493e5dd7070Spatrick // Make sure that the element has the type that the container factory
494e5dd7070Spatrick // function expects.
495e5dd7070Spatrick return S.PerformCopyInitialization(
496e5dd7070Spatrick InitializedEntity::InitializeParameter(S.Context, T,
497e5dd7070Spatrick /*Consumed=*/false),
498e5dd7070Spatrick Element->getBeginLoc(), Element);
499e5dd7070Spatrick }
500e5dd7070Spatrick
BuildObjCBoxedExpr(SourceRange SR,Expr * ValueExpr)501e5dd7070Spatrick ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
502e5dd7070Spatrick if (ValueExpr->isTypeDependent()) {
503e5dd7070Spatrick ObjCBoxedExpr *BoxedExpr =
504e5dd7070Spatrick new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, nullptr, SR);
505e5dd7070Spatrick return BoxedExpr;
506e5dd7070Spatrick }
507e5dd7070Spatrick ObjCMethodDecl *BoxingMethod = nullptr;
508e5dd7070Spatrick QualType BoxedType;
509e5dd7070Spatrick // Convert the expression to an RValue, so we can check for pointer types...
510e5dd7070Spatrick ExprResult RValue = DefaultFunctionArrayLvalueConversion(ValueExpr);
511e5dd7070Spatrick if (RValue.isInvalid()) {
512e5dd7070Spatrick return ExprError();
513e5dd7070Spatrick }
514e5dd7070Spatrick SourceLocation Loc = SR.getBegin();
515e5dd7070Spatrick ValueExpr = RValue.get();
516e5dd7070Spatrick QualType ValueType(ValueExpr->getType());
517e5dd7070Spatrick if (const PointerType *PT = ValueType->getAs<PointerType>()) {
518e5dd7070Spatrick QualType PointeeType = PT->getPointeeType();
519e5dd7070Spatrick if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) {
520e5dd7070Spatrick
521e5dd7070Spatrick if (!NSStringDecl) {
522e5dd7070Spatrick NSStringDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
523e5dd7070Spatrick Sema::LK_String);
524e5dd7070Spatrick if (!NSStringDecl) {
525e5dd7070Spatrick return ExprError();
526e5dd7070Spatrick }
527e5dd7070Spatrick QualType NSStringObject = Context.getObjCInterfaceType(NSStringDecl);
528e5dd7070Spatrick NSStringPointer = Context.getObjCObjectPointerType(NSStringObject);
529e5dd7070Spatrick }
530e5dd7070Spatrick
531e5dd7070Spatrick // The boxed expression can be emitted as a compile time constant if it is
532e5dd7070Spatrick // a string literal whose character encoding is compatible with UTF-8.
533e5dd7070Spatrick if (auto *CE = dyn_cast<ImplicitCastExpr>(ValueExpr))
534e5dd7070Spatrick if (CE->getCastKind() == CK_ArrayToPointerDecay)
535e5dd7070Spatrick if (auto *SL =
536e5dd7070Spatrick dyn_cast<StringLiteral>(CE->getSubExpr()->IgnoreParens())) {
537*12c85518Srobert assert((SL->isOrdinary() || SL->isUTF8()) &&
538e5dd7070Spatrick "unexpected character encoding");
539e5dd7070Spatrick StringRef Str = SL->getString();
540e5dd7070Spatrick const llvm::UTF8 *StrBegin = Str.bytes_begin();
541e5dd7070Spatrick const llvm::UTF8 *StrEnd = Str.bytes_end();
542e5dd7070Spatrick // Check that this is a valid UTF-8 string.
543e5dd7070Spatrick if (llvm::isLegalUTF8String(&StrBegin, StrEnd)) {
544e5dd7070Spatrick BoxedType = Context.getAttributedType(
545e5dd7070Spatrick AttributedType::getNullabilityAttrKind(
546e5dd7070Spatrick NullabilityKind::NonNull),
547e5dd7070Spatrick NSStringPointer, NSStringPointer);
548e5dd7070Spatrick return new (Context) ObjCBoxedExpr(CE, BoxedType, nullptr, SR);
549e5dd7070Spatrick }
550e5dd7070Spatrick
551e5dd7070Spatrick Diag(SL->getBeginLoc(), diag::warn_objc_boxing_invalid_utf8_string)
552e5dd7070Spatrick << NSStringPointer << SL->getSourceRange();
553e5dd7070Spatrick }
554e5dd7070Spatrick
555e5dd7070Spatrick if (!StringWithUTF8StringMethod) {
556e5dd7070Spatrick IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String");
557e5dd7070Spatrick Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II);
558e5dd7070Spatrick
559e5dd7070Spatrick // Look for the appropriate method within NSString.
560e5dd7070Spatrick BoxingMethod = NSStringDecl->lookupClassMethod(stringWithUTF8String);
561e5dd7070Spatrick if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) {
562e5dd7070Spatrick // Debugger needs to work even if NSString hasn't been defined.
563e5dd7070Spatrick TypeSourceInfo *ReturnTInfo = nullptr;
564e5dd7070Spatrick ObjCMethodDecl *M = ObjCMethodDecl::Create(
565e5dd7070Spatrick Context, SourceLocation(), SourceLocation(), stringWithUTF8String,
566e5dd7070Spatrick NSStringPointer, ReturnTInfo, NSStringDecl,
567e5dd7070Spatrick /*isInstance=*/false, /*isVariadic=*/false,
568e5dd7070Spatrick /*isPropertyAccessor=*/false,
569e5dd7070Spatrick /*isSynthesizedAccessorStub=*/false,
570e5dd7070Spatrick /*isImplicitlyDeclared=*/true,
571e5dd7070Spatrick /*isDefined=*/false, ObjCMethodDecl::Required,
572e5dd7070Spatrick /*HasRelatedResultType=*/false);
573e5dd7070Spatrick QualType ConstCharType = Context.CharTy.withConst();
574e5dd7070Spatrick ParmVarDecl *value =
575e5dd7070Spatrick ParmVarDecl::Create(Context, M,
576e5dd7070Spatrick SourceLocation(), SourceLocation(),
577e5dd7070Spatrick &Context.Idents.get("value"),
578e5dd7070Spatrick Context.getPointerType(ConstCharType),
579e5dd7070Spatrick /*TInfo=*/nullptr,
580e5dd7070Spatrick SC_None, nullptr);
581*12c85518Srobert M->setMethodParams(Context, value, std::nullopt);
582e5dd7070Spatrick BoxingMethod = M;
583e5dd7070Spatrick }
584e5dd7070Spatrick
585e5dd7070Spatrick if (!validateBoxingMethod(*this, Loc, NSStringDecl,
586e5dd7070Spatrick stringWithUTF8String, BoxingMethod))
587e5dd7070Spatrick return ExprError();
588e5dd7070Spatrick
589e5dd7070Spatrick StringWithUTF8StringMethod = BoxingMethod;
590e5dd7070Spatrick }
591e5dd7070Spatrick
592e5dd7070Spatrick BoxingMethod = StringWithUTF8StringMethod;
593e5dd7070Spatrick BoxedType = NSStringPointer;
594e5dd7070Spatrick // Transfer the nullability from method's return type.
595*12c85518Srobert std::optional<NullabilityKind> Nullability =
596*12c85518Srobert BoxingMethod->getReturnType()->getNullability();
597e5dd7070Spatrick if (Nullability)
598e5dd7070Spatrick BoxedType = Context.getAttributedType(
599e5dd7070Spatrick AttributedType::getNullabilityAttrKind(*Nullability), BoxedType,
600e5dd7070Spatrick BoxedType);
601e5dd7070Spatrick }
602e5dd7070Spatrick } else if (ValueType->isBuiltinType()) {
603e5dd7070Spatrick // The other types we support are numeric, char and BOOL/bool. We could also
604e5dd7070Spatrick // provide limited support for structure types, such as NSRange, NSRect, and
605e5dd7070Spatrick // NSSize. See NSValue (NSValueGeometryExtensions) in <Foundation/NSGeometry.h>
606e5dd7070Spatrick // for more details.
607e5dd7070Spatrick
608e5dd7070Spatrick // Check for a top-level character literal.
609e5dd7070Spatrick if (const CharacterLiteral *Char =
610e5dd7070Spatrick dyn_cast<CharacterLiteral>(ValueExpr->IgnoreParens())) {
611e5dd7070Spatrick // In C, character literals have type 'int'. That's not the type we want
612e5dd7070Spatrick // to use to determine the Objective-c literal kind.
613e5dd7070Spatrick switch (Char->getKind()) {
614e5dd7070Spatrick case CharacterLiteral::Ascii:
615e5dd7070Spatrick case CharacterLiteral::UTF8:
616e5dd7070Spatrick ValueType = Context.CharTy;
617e5dd7070Spatrick break;
618e5dd7070Spatrick
619e5dd7070Spatrick case CharacterLiteral::Wide:
620e5dd7070Spatrick ValueType = Context.getWideCharType();
621e5dd7070Spatrick break;
622e5dd7070Spatrick
623e5dd7070Spatrick case CharacterLiteral::UTF16:
624e5dd7070Spatrick ValueType = Context.Char16Ty;
625e5dd7070Spatrick break;
626e5dd7070Spatrick
627e5dd7070Spatrick case CharacterLiteral::UTF32:
628e5dd7070Spatrick ValueType = Context.Char32Ty;
629e5dd7070Spatrick break;
630e5dd7070Spatrick }
631e5dd7070Spatrick }
632e5dd7070Spatrick // FIXME: Do I need to do anything special with BoolTy expressions?
633e5dd7070Spatrick
634e5dd7070Spatrick // Look for the appropriate method within NSNumber.
635e5dd7070Spatrick BoxingMethod = getNSNumberFactoryMethod(*this, Loc, ValueType);
636e5dd7070Spatrick BoxedType = NSNumberPointer;
637e5dd7070Spatrick } else if (const EnumType *ET = ValueType->getAs<EnumType>()) {
638e5dd7070Spatrick if (!ET->getDecl()->isComplete()) {
639e5dd7070Spatrick Diag(Loc, diag::err_objc_incomplete_boxed_expression_type)
640e5dd7070Spatrick << ValueType << ValueExpr->getSourceRange();
641e5dd7070Spatrick return ExprError();
642e5dd7070Spatrick }
643e5dd7070Spatrick
644e5dd7070Spatrick BoxingMethod = getNSNumberFactoryMethod(*this, Loc,
645e5dd7070Spatrick ET->getDecl()->getIntegerType());
646e5dd7070Spatrick BoxedType = NSNumberPointer;
647e5dd7070Spatrick } else if (ValueType->isObjCBoxableRecordType()) {
648e5dd7070Spatrick // Support for structure types, that marked as objc_boxable
649e5dd7070Spatrick // struct __attribute__((objc_boxable)) s { ... };
650e5dd7070Spatrick
651e5dd7070Spatrick // Look up the NSValue class, if we haven't done so already. It's cached
652e5dd7070Spatrick // in the Sema instance.
653e5dd7070Spatrick if (!NSValueDecl) {
654e5dd7070Spatrick NSValueDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
655e5dd7070Spatrick Sema::LK_Boxed);
656e5dd7070Spatrick if (!NSValueDecl) {
657e5dd7070Spatrick return ExprError();
658e5dd7070Spatrick }
659e5dd7070Spatrick
660e5dd7070Spatrick // generate the pointer to NSValue type.
661e5dd7070Spatrick QualType NSValueObject = Context.getObjCInterfaceType(NSValueDecl);
662e5dd7070Spatrick NSValuePointer = Context.getObjCObjectPointerType(NSValueObject);
663e5dd7070Spatrick }
664e5dd7070Spatrick
665e5dd7070Spatrick if (!ValueWithBytesObjCTypeMethod) {
666e5dd7070Spatrick IdentifierInfo *II[] = {
667e5dd7070Spatrick &Context.Idents.get("valueWithBytes"),
668e5dd7070Spatrick &Context.Idents.get("objCType")
669e5dd7070Spatrick };
670e5dd7070Spatrick Selector ValueWithBytesObjCType = Context.Selectors.getSelector(2, II);
671e5dd7070Spatrick
672e5dd7070Spatrick // Look for the appropriate method within NSValue.
673e5dd7070Spatrick BoxingMethod = NSValueDecl->lookupClassMethod(ValueWithBytesObjCType);
674e5dd7070Spatrick if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) {
675e5dd7070Spatrick // Debugger needs to work even if NSValue hasn't been defined.
676e5dd7070Spatrick TypeSourceInfo *ReturnTInfo = nullptr;
677e5dd7070Spatrick ObjCMethodDecl *M = ObjCMethodDecl::Create(
678e5dd7070Spatrick Context, SourceLocation(), SourceLocation(), ValueWithBytesObjCType,
679e5dd7070Spatrick NSValuePointer, ReturnTInfo, NSValueDecl,
680e5dd7070Spatrick /*isInstance=*/false,
681e5dd7070Spatrick /*isVariadic=*/false,
682e5dd7070Spatrick /*isPropertyAccessor=*/false,
683e5dd7070Spatrick /*isSynthesizedAccessorStub=*/false,
684e5dd7070Spatrick /*isImplicitlyDeclared=*/true,
685e5dd7070Spatrick /*isDefined=*/false, ObjCMethodDecl::Required,
686e5dd7070Spatrick /*HasRelatedResultType=*/false);
687e5dd7070Spatrick
688e5dd7070Spatrick SmallVector<ParmVarDecl *, 2> Params;
689e5dd7070Spatrick
690e5dd7070Spatrick ParmVarDecl *bytes =
691e5dd7070Spatrick ParmVarDecl::Create(Context, M,
692e5dd7070Spatrick SourceLocation(), SourceLocation(),
693e5dd7070Spatrick &Context.Idents.get("bytes"),
694e5dd7070Spatrick Context.VoidPtrTy.withConst(),
695e5dd7070Spatrick /*TInfo=*/nullptr,
696e5dd7070Spatrick SC_None, nullptr);
697e5dd7070Spatrick Params.push_back(bytes);
698e5dd7070Spatrick
699e5dd7070Spatrick QualType ConstCharType = Context.CharTy.withConst();
700e5dd7070Spatrick ParmVarDecl *type =
701e5dd7070Spatrick ParmVarDecl::Create(Context, M,
702e5dd7070Spatrick SourceLocation(), SourceLocation(),
703e5dd7070Spatrick &Context.Idents.get("type"),
704e5dd7070Spatrick Context.getPointerType(ConstCharType),
705e5dd7070Spatrick /*TInfo=*/nullptr,
706e5dd7070Spatrick SC_None, nullptr);
707e5dd7070Spatrick Params.push_back(type);
708e5dd7070Spatrick
709*12c85518Srobert M->setMethodParams(Context, Params, std::nullopt);
710e5dd7070Spatrick BoxingMethod = M;
711e5dd7070Spatrick }
712e5dd7070Spatrick
713e5dd7070Spatrick if (!validateBoxingMethod(*this, Loc, NSValueDecl,
714e5dd7070Spatrick ValueWithBytesObjCType, BoxingMethod))
715e5dd7070Spatrick return ExprError();
716e5dd7070Spatrick
717e5dd7070Spatrick ValueWithBytesObjCTypeMethod = BoxingMethod;
718e5dd7070Spatrick }
719e5dd7070Spatrick
720e5dd7070Spatrick if (!ValueType.isTriviallyCopyableType(Context)) {
721e5dd7070Spatrick Diag(Loc, diag::err_objc_non_trivially_copyable_boxed_expression_type)
722e5dd7070Spatrick << ValueType << ValueExpr->getSourceRange();
723e5dd7070Spatrick return ExprError();
724e5dd7070Spatrick }
725e5dd7070Spatrick
726e5dd7070Spatrick BoxingMethod = ValueWithBytesObjCTypeMethod;
727e5dd7070Spatrick BoxedType = NSValuePointer;
728e5dd7070Spatrick }
729e5dd7070Spatrick
730e5dd7070Spatrick if (!BoxingMethod) {
731e5dd7070Spatrick Diag(Loc, diag::err_objc_illegal_boxed_expression_type)
732e5dd7070Spatrick << ValueType << ValueExpr->getSourceRange();
733e5dd7070Spatrick return ExprError();
734e5dd7070Spatrick }
735e5dd7070Spatrick
736e5dd7070Spatrick DiagnoseUseOfDecl(BoxingMethod, Loc);
737e5dd7070Spatrick
738e5dd7070Spatrick ExprResult ConvertedValueExpr;
739e5dd7070Spatrick if (ValueType->isObjCBoxableRecordType()) {
740e5dd7070Spatrick InitializedEntity IE = InitializedEntity::InitializeTemporary(ValueType);
741e5dd7070Spatrick ConvertedValueExpr = PerformCopyInitialization(IE, ValueExpr->getExprLoc(),
742e5dd7070Spatrick ValueExpr);
743e5dd7070Spatrick } else {
744e5dd7070Spatrick // Convert the expression to the type that the parameter requires.
745e5dd7070Spatrick ParmVarDecl *ParamDecl = BoxingMethod->parameters()[0];
746e5dd7070Spatrick InitializedEntity IE = InitializedEntity::InitializeParameter(Context,
747e5dd7070Spatrick ParamDecl);
748e5dd7070Spatrick ConvertedValueExpr = PerformCopyInitialization(IE, SourceLocation(),
749e5dd7070Spatrick ValueExpr);
750e5dd7070Spatrick }
751e5dd7070Spatrick
752e5dd7070Spatrick if (ConvertedValueExpr.isInvalid())
753e5dd7070Spatrick return ExprError();
754e5dd7070Spatrick ValueExpr = ConvertedValueExpr.get();
755e5dd7070Spatrick
756e5dd7070Spatrick ObjCBoxedExpr *BoxedExpr =
757e5dd7070Spatrick new (Context) ObjCBoxedExpr(ValueExpr, BoxedType,
758e5dd7070Spatrick BoxingMethod, SR);
759e5dd7070Spatrick return MaybeBindToTemporary(BoxedExpr);
760e5dd7070Spatrick }
761e5dd7070Spatrick
762e5dd7070Spatrick /// Build an ObjC subscript pseudo-object expression, given that
763e5dd7070Spatrick /// that's supported by the runtime.
BuildObjCSubscriptExpression(SourceLocation RB,Expr * BaseExpr,Expr * IndexExpr,ObjCMethodDecl * getterMethod,ObjCMethodDecl * setterMethod)764e5dd7070Spatrick ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
765e5dd7070Spatrick Expr *IndexExpr,
766e5dd7070Spatrick ObjCMethodDecl *getterMethod,
767e5dd7070Spatrick ObjCMethodDecl *setterMethod) {
768e5dd7070Spatrick assert(!LangOpts.isSubscriptPointerArithmetic());
769e5dd7070Spatrick
770e5dd7070Spatrick // We can't get dependent types here; our callers should have
771e5dd7070Spatrick // filtered them out.
772e5dd7070Spatrick assert((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) &&
773e5dd7070Spatrick "base or index cannot have dependent type here");
774e5dd7070Spatrick
775e5dd7070Spatrick // Filter out placeholders in the index. In theory, overloads could
776e5dd7070Spatrick // be preserved here, although that might not actually work correctly.
777e5dd7070Spatrick ExprResult Result = CheckPlaceholderExpr(IndexExpr);
778e5dd7070Spatrick if (Result.isInvalid())
779e5dd7070Spatrick return ExprError();
780e5dd7070Spatrick IndexExpr = Result.get();
781e5dd7070Spatrick
782e5dd7070Spatrick // Perform lvalue-to-rvalue conversion on the base.
783e5dd7070Spatrick Result = DefaultLvalueConversion(BaseExpr);
784e5dd7070Spatrick if (Result.isInvalid())
785e5dd7070Spatrick return ExprError();
786e5dd7070Spatrick BaseExpr = Result.get();
787e5dd7070Spatrick
788e5dd7070Spatrick // Build the pseudo-object expression.
789e5dd7070Spatrick return new (Context) ObjCSubscriptRefExpr(
790e5dd7070Spatrick BaseExpr, IndexExpr, Context.PseudoObjectTy, VK_LValue, OK_ObjCSubscript,
791e5dd7070Spatrick getterMethod, setterMethod, RB);
792e5dd7070Spatrick }
793e5dd7070Spatrick
BuildObjCArrayLiteral(SourceRange SR,MultiExprArg Elements)794e5dd7070Spatrick ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
795e5dd7070Spatrick SourceLocation Loc = SR.getBegin();
796e5dd7070Spatrick
797e5dd7070Spatrick if (!NSArrayDecl) {
798e5dd7070Spatrick NSArrayDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
799e5dd7070Spatrick Sema::LK_Array);
800e5dd7070Spatrick if (!NSArrayDecl) {
801e5dd7070Spatrick return ExprError();
802e5dd7070Spatrick }
803e5dd7070Spatrick }
804e5dd7070Spatrick
805e5dd7070Spatrick // Find the arrayWithObjects:count: method, if we haven't done so already.
806e5dd7070Spatrick QualType IdT = Context.getObjCIdType();
807e5dd7070Spatrick if (!ArrayWithObjectsMethod) {
808e5dd7070Spatrick Selector
809e5dd7070Spatrick Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount);
810e5dd7070Spatrick ObjCMethodDecl *Method = NSArrayDecl->lookupClassMethod(Sel);
811e5dd7070Spatrick if (!Method && getLangOpts().DebuggerObjCLiteral) {
812e5dd7070Spatrick TypeSourceInfo *ReturnTInfo = nullptr;
813e5dd7070Spatrick Method = ObjCMethodDecl::Create(
814e5dd7070Spatrick Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo,
815e5dd7070Spatrick Context.getTranslationUnitDecl(), false /*Instance*/,
816e5dd7070Spatrick false /*isVariadic*/,
817e5dd7070Spatrick /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
818e5dd7070Spatrick /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
819e5dd7070Spatrick ObjCMethodDecl::Required, false);
820e5dd7070Spatrick SmallVector<ParmVarDecl *, 2> Params;
821e5dd7070Spatrick ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
822e5dd7070Spatrick SourceLocation(),
823e5dd7070Spatrick SourceLocation(),
824e5dd7070Spatrick &Context.Idents.get("objects"),
825e5dd7070Spatrick Context.getPointerType(IdT),
826e5dd7070Spatrick /*TInfo=*/nullptr,
827e5dd7070Spatrick SC_None, nullptr);
828e5dd7070Spatrick Params.push_back(objects);
829e5dd7070Spatrick ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
830e5dd7070Spatrick SourceLocation(),
831e5dd7070Spatrick SourceLocation(),
832e5dd7070Spatrick &Context.Idents.get("cnt"),
833e5dd7070Spatrick Context.UnsignedLongTy,
834e5dd7070Spatrick /*TInfo=*/nullptr, SC_None,
835e5dd7070Spatrick nullptr);
836e5dd7070Spatrick Params.push_back(cnt);
837*12c85518Srobert Method->setMethodParams(Context, Params, std::nullopt);
838e5dd7070Spatrick }
839e5dd7070Spatrick
840e5dd7070Spatrick if (!validateBoxingMethod(*this, Loc, NSArrayDecl, Sel, Method))
841e5dd7070Spatrick return ExprError();
842e5dd7070Spatrick
843e5dd7070Spatrick // Dig out the type that all elements should be converted to.
844e5dd7070Spatrick QualType T = Method->parameters()[0]->getType();
845e5dd7070Spatrick const PointerType *PtrT = T->getAs<PointerType>();
846e5dd7070Spatrick if (!PtrT ||
847e5dd7070Spatrick !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) {
848e5dd7070Spatrick Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
849e5dd7070Spatrick << Sel;
850e5dd7070Spatrick Diag(Method->parameters()[0]->getLocation(),
851e5dd7070Spatrick diag::note_objc_literal_method_param)
852e5dd7070Spatrick << 0 << T
853e5dd7070Spatrick << Context.getPointerType(IdT.withConst());
854e5dd7070Spatrick return ExprError();
855e5dd7070Spatrick }
856e5dd7070Spatrick
857e5dd7070Spatrick // Check that the 'count' parameter is integral.
858e5dd7070Spatrick if (!Method->parameters()[1]->getType()->isIntegerType()) {
859e5dd7070Spatrick Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
860e5dd7070Spatrick << Sel;
861e5dd7070Spatrick Diag(Method->parameters()[1]->getLocation(),
862e5dd7070Spatrick diag::note_objc_literal_method_param)
863e5dd7070Spatrick << 1
864e5dd7070Spatrick << Method->parameters()[1]->getType()
865e5dd7070Spatrick << "integral";
866e5dd7070Spatrick return ExprError();
867e5dd7070Spatrick }
868e5dd7070Spatrick
869e5dd7070Spatrick // We've found a good +arrayWithObjects:count: method. Save it!
870e5dd7070Spatrick ArrayWithObjectsMethod = Method;
871e5dd7070Spatrick }
872e5dd7070Spatrick
873e5dd7070Spatrick QualType ObjectsType = ArrayWithObjectsMethod->parameters()[0]->getType();
874e5dd7070Spatrick QualType RequiredType = ObjectsType->castAs<PointerType>()->getPointeeType();
875e5dd7070Spatrick
876e5dd7070Spatrick // Check that each of the elements provided is valid in a collection literal,
877e5dd7070Spatrick // performing conversions as necessary.
878e5dd7070Spatrick Expr **ElementsBuffer = Elements.data();
879e5dd7070Spatrick for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
880e5dd7070Spatrick ExprResult Converted = CheckObjCCollectionLiteralElement(*this,
881e5dd7070Spatrick ElementsBuffer[I],
882e5dd7070Spatrick RequiredType, true);
883e5dd7070Spatrick if (Converted.isInvalid())
884e5dd7070Spatrick return ExprError();
885e5dd7070Spatrick
886e5dd7070Spatrick ElementsBuffer[I] = Converted.get();
887e5dd7070Spatrick }
888e5dd7070Spatrick
889e5dd7070Spatrick QualType Ty
890e5dd7070Spatrick = Context.getObjCObjectPointerType(
891e5dd7070Spatrick Context.getObjCInterfaceType(NSArrayDecl));
892e5dd7070Spatrick
893e5dd7070Spatrick return MaybeBindToTemporary(
894e5dd7070Spatrick ObjCArrayLiteral::Create(Context, Elements, Ty,
895e5dd7070Spatrick ArrayWithObjectsMethod, SR));
896e5dd7070Spatrick }
897e5dd7070Spatrick
898ec727ea7Spatrick /// Check for duplicate keys in an ObjC dictionary literal. For instance:
899ec727ea7Spatrick /// NSDictionary *nd = @{ @"foo" : @"bar", @"foo" : @"baz" };
900ec727ea7Spatrick static void
CheckObjCDictionaryLiteralDuplicateKeys(Sema & S,ObjCDictionaryLiteral * Literal)901ec727ea7Spatrick CheckObjCDictionaryLiteralDuplicateKeys(Sema &S,
902ec727ea7Spatrick ObjCDictionaryLiteral *Literal) {
903ec727ea7Spatrick if (Literal->isValueDependent() || Literal->isTypeDependent())
904ec727ea7Spatrick return;
905ec727ea7Spatrick
906ec727ea7Spatrick // NSNumber has quite relaxed equality semantics (for instance, @YES is
907ec727ea7Spatrick // considered equal to @1.0). For now, ignore floating points and just do a
908ec727ea7Spatrick // bit-width and sign agnostic integer compare.
909ec727ea7Spatrick struct APSIntCompare {
910ec727ea7Spatrick bool operator()(const llvm::APSInt &LHS, const llvm::APSInt &RHS) const {
911ec727ea7Spatrick return llvm::APSInt::compareValues(LHS, RHS) < 0;
912ec727ea7Spatrick }
913ec727ea7Spatrick };
914ec727ea7Spatrick
915ec727ea7Spatrick llvm::DenseMap<StringRef, SourceLocation> StringKeys;
916ec727ea7Spatrick std::map<llvm::APSInt, SourceLocation, APSIntCompare> IntegralKeys;
917ec727ea7Spatrick
918ec727ea7Spatrick auto checkOneKey = [&](auto &Map, const auto &Key, SourceLocation Loc) {
919ec727ea7Spatrick auto Pair = Map.insert({Key, Loc});
920ec727ea7Spatrick if (!Pair.second) {
921ec727ea7Spatrick S.Diag(Loc, diag::warn_nsdictionary_duplicate_key);
922ec727ea7Spatrick S.Diag(Pair.first->second, diag::note_nsdictionary_duplicate_key_here);
923ec727ea7Spatrick }
924ec727ea7Spatrick };
925ec727ea7Spatrick
926ec727ea7Spatrick for (unsigned Idx = 0, End = Literal->getNumElements(); Idx != End; ++Idx) {
927ec727ea7Spatrick Expr *Key = Literal->getKeyValueElement(Idx).Key->IgnoreParenImpCasts();
928ec727ea7Spatrick
929ec727ea7Spatrick if (auto *StrLit = dyn_cast<ObjCStringLiteral>(Key)) {
930ec727ea7Spatrick StringRef Bytes = StrLit->getString()->getBytes();
931ec727ea7Spatrick SourceLocation Loc = StrLit->getExprLoc();
932ec727ea7Spatrick checkOneKey(StringKeys, Bytes, Loc);
933ec727ea7Spatrick }
934ec727ea7Spatrick
935ec727ea7Spatrick if (auto *BE = dyn_cast<ObjCBoxedExpr>(Key)) {
936ec727ea7Spatrick Expr *Boxed = BE->getSubExpr();
937ec727ea7Spatrick SourceLocation Loc = BE->getExprLoc();
938ec727ea7Spatrick
939ec727ea7Spatrick // Check for @("foo").
940ec727ea7Spatrick if (auto *Str = dyn_cast<StringLiteral>(Boxed->IgnoreParenImpCasts())) {
941ec727ea7Spatrick checkOneKey(StringKeys, Str->getBytes(), Loc);
942ec727ea7Spatrick continue;
943ec727ea7Spatrick }
944ec727ea7Spatrick
945ec727ea7Spatrick Expr::EvalResult Result;
946ec727ea7Spatrick if (Boxed->EvaluateAsInt(Result, S.getASTContext(),
947ec727ea7Spatrick Expr::SE_AllowSideEffects)) {
948ec727ea7Spatrick checkOneKey(IntegralKeys, Result.Val.getInt(), Loc);
949ec727ea7Spatrick }
950ec727ea7Spatrick }
951ec727ea7Spatrick }
952ec727ea7Spatrick }
953ec727ea7Spatrick
BuildObjCDictionaryLiteral(SourceRange SR,MutableArrayRef<ObjCDictionaryElement> Elements)954e5dd7070Spatrick ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
955e5dd7070Spatrick MutableArrayRef<ObjCDictionaryElement> Elements) {
956e5dd7070Spatrick SourceLocation Loc = SR.getBegin();
957e5dd7070Spatrick
958e5dd7070Spatrick if (!NSDictionaryDecl) {
959e5dd7070Spatrick NSDictionaryDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
960e5dd7070Spatrick Sema::LK_Dictionary);
961e5dd7070Spatrick if (!NSDictionaryDecl) {
962e5dd7070Spatrick return ExprError();
963e5dd7070Spatrick }
964e5dd7070Spatrick }
965e5dd7070Spatrick
966e5dd7070Spatrick // Find the dictionaryWithObjects:forKeys:count: method, if we haven't done
967e5dd7070Spatrick // so already.
968e5dd7070Spatrick QualType IdT = Context.getObjCIdType();
969e5dd7070Spatrick if (!DictionaryWithObjectsMethod) {
970e5dd7070Spatrick Selector Sel = NSAPIObj->getNSDictionarySelector(
971e5dd7070Spatrick NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
972e5dd7070Spatrick ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel);
973e5dd7070Spatrick if (!Method && getLangOpts().DebuggerObjCLiteral) {
974e5dd7070Spatrick Method = ObjCMethodDecl::Create(
975e5dd7070Spatrick Context, SourceLocation(), SourceLocation(), Sel, IdT,
976e5dd7070Spatrick nullptr /*TypeSourceInfo */, Context.getTranslationUnitDecl(),
977e5dd7070Spatrick false /*Instance*/, false /*isVariadic*/,
978e5dd7070Spatrick /*isPropertyAccessor=*/false,
979e5dd7070Spatrick /*isSynthesizedAccessorStub=*/false,
980e5dd7070Spatrick /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
981e5dd7070Spatrick ObjCMethodDecl::Required, false);
982e5dd7070Spatrick SmallVector<ParmVarDecl *, 3> Params;
983e5dd7070Spatrick ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
984e5dd7070Spatrick SourceLocation(),
985e5dd7070Spatrick SourceLocation(),
986e5dd7070Spatrick &Context.Idents.get("objects"),
987e5dd7070Spatrick Context.getPointerType(IdT),
988e5dd7070Spatrick /*TInfo=*/nullptr, SC_None,
989e5dd7070Spatrick nullptr);
990e5dd7070Spatrick Params.push_back(objects);
991e5dd7070Spatrick ParmVarDecl *keys = ParmVarDecl::Create(Context, Method,
992e5dd7070Spatrick SourceLocation(),
993e5dd7070Spatrick SourceLocation(),
994e5dd7070Spatrick &Context.Idents.get("keys"),
995e5dd7070Spatrick Context.getPointerType(IdT),
996e5dd7070Spatrick /*TInfo=*/nullptr, SC_None,
997e5dd7070Spatrick nullptr);
998e5dd7070Spatrick Params.push_back(keys);
999e5dd7070Spatrick ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
1000e5dd7070Spatrick SourceLocation(),
1001e5dd7070Spatrick SourceLocation(),
1002e5dd7070Spatrick &Context.Idents.get("cnt"),
1003e5dd7070Spatrick Context.UnsignedLongTy,
1004e5dd7070Spatrick /*TInfo=*/nullptr, SC_None,
1005e5dd7070Spatrick nullptr);
1006e5dd7070Spatrick Params.push_back(cnt);
1007*12c85518Srobert Method->setMethodParams(Context, Params, std::nullopt);
1008e5dd7070Spatrick }
1009e5dd7070Spatrick
1010e5dd7070Spatrick if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel,
1011e5dd7070Spatrick Method))
1012e5dd7070Spatrick return ExprError();
1013e5dd7070Spatrick
1014e5dd7070Spatrick // Dig out the type that all values should be converted to.
1015e5dd7070Spatrick QualType ValueT = Method->parameters()[0]->getType();
1016e5dd7070Spatrick const PointerType *PtrValue = ValueT->getAs<PointerType>();
1017e5dd7070Spatrick if (!PtrValue ||
1018e5dd7070Spatrick !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) {
1019e5dd7070Spatrick Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
1020e5dd7070Spatrick << Sel;
1021e5dd7070Spatrick Diag(Method->parameters()[0]->getLocation(),
1022e5dd7070Spatrick diag::note_objc_literal_method_param)
1023e5dd7070Spatrick << 0 << ValueT
1024e5dd7070Spatrick << Context.getPointerType(IdT.withConst());
1025e5dd7070Spatrick return ExprError();
1026e5dd7070Spatrick }
1027e5dd7070Spatrick
1028e5dd7070Spatrick // Dig out the type that all keys should be converted to.
1029e5dd7070Spatrick QualType KeyT = Method->parameters()[1]->getType();
1030e5dd7070Spatrick const PointerType *PtrKey = KeyT->getAs<PointerType>();
1031e5dd7070Spatrick if (!PtrKey ||
1032e5dd7070Spatrick !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
1033e5dd7070Spatrick IdT)) {
1034e5dd7070Spatrick bool err = true;
1035e5dd7070Spatrick if (PtrKey) {
1036e5dd7070Spatrick if (QIDNSCopying.isNull()) {
1037e5dd7070Spatrick // key argument of selector is id<NSCopying>?
1038e5dd7070Spatrick if (ObjCProtocolDecl *NSCopyingPDecl =
1039e5dd7070Spatrick LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
1040e5dd7070Spatrick ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
1041*12c85518Srobert QIDNSCopying = Context.getObjCObjectType(
1042*12c85518Srobert Context.ObjCBuiltinIdTy, {},
1043*12c85518Srobert llvm::ArrayRef((ObjCProtocolDecl **)PQ, 1), false);
1044e5dd7070Spatrick QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
1045e5dd7070Spatrick }
1046e5dd7070Spatrick }
1047e5dd7070Spatrick if (!QIDNSCopying.isNull())
1048e5dd7070Spatrick err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
1049e5dd7070Spatrick QIDNSCopying);
1050e5dd7070Spatrick }
1051e5dd7070Spatrick
1052e5dd7070Spatrick if (err) {
1053e5dd7070Spatrick Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
1054e5dd7070Spatrick << Sel;
1055e5dd7070Spatrick Diag(Method->parameters()[1]->getLocation(),
1056e5dd7070Spatrick diag::note_objc_literal_method_param)
1057e5dd7070Spatrick << 1 << KeyT
1058e5dd7070Spatrick << Context.getPointerType(IdT.withConst());
1059e5dd7070Spatrick return ExprError();
1060e5dd7070Spatrick }
1061e5dd7070Spatrick }
1062e5dd7070Spatrick
1063e5dd7070Spatrick // Check that the 'count' parameter is integral.
1064e5dd7070Spatrick QualType CountType = Method->parameters()[2]->getType();
1065e5dd7070Spatrick if (!CountType->isIntegerType()) {
1066e5dd7070Spatrick Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
1067e5dd7070Spatrick << Sel;
1068e5dd7070Spatrick Diag(Method->parameters()[2]->getLocation(),
1069e5dd7070Spatrick diag::note_objc_literal_method_param)
1070e5dd7070Spatrick << 2 << CountType
1071e5dd7070Spatrick << "integral";
1072e5dd7070Spatrick return ExprError();
1073e5dd7070Spatrick }
1074e5dd7070Spatrick
1075e5dd7070Spatrick // We've found a good +dictionaryWithObjects:keys:count: method; save it!
1076e5dd7070Spatrick DictionaryWithObjectsMethod = Method;
1077e5dd7070Spatrick }
1078e5dd7070Spatrick
1079e5dd7070Spatrick QualType ValuesT = DictionaryWithObjectsMethod->parameters()[0]->getType();
1080e5dd7070Spatrick QualType ValueT = ValuesT->castAs<PointerType>()->getPointeeType();
1081e5dd7070Spatrick QualType KeysT = DictionaryWithObjectsMethod->parameters()[1]->getType();
1082e5dd7070Spatrick QualType KeyT = KeysT->castAs<PointerType>()->getPointeeType();
1083e5dd7070Spatrick
1084e5dd7070Spatrick // Check that each of the keys and values provided is valid in a collection
1085e5dd7070Spatrick // literal, performing conversions as necessary.
1086e5dd7070Spatrick bool HasPackExpansions = false;
1087e5dd7070Spatrick for (ObjCDictionaryElement &Element : Elements) {
1088e5dd7070Spatrick // Check the key.
1089e5dd7070Spatrick ExprResult Key = CheckObjCCollectionLiteralElement(*this, Element.Key,
1090e5dd7070Spatrick KeyT);
1091e5dd7070Spatrick if (Key.isInvalid())
1092e5dd7070Spatrick return ExprError();
1093e5dd7070Spatrick
1094e5dd7070Spatrick // Check the value.
1095e5dd7070Spatrick ExprResult Value
1096e5dd7070Spatrick = CheckObjCCollectionLiteralElement(*this, Element.Value, ValueT);
1097e5dd7070Spatrick if (Value.isInvalid())
1098e5dd7070Spatrick return ExprError();
1099e5dd7070Spatrick
1100e5dd7070Spatrick Element.Key = Key.get();
1101e5dd7070Spatrick Element.Value = Value.get();
1102e5dd7070Spatrick
1103e5dd7070Spatrick if (Element.EllipsisLoc.isInvalid())
1104e5dd7070Spatrick continue;
1105e5dd7070Spatrick
1106e5dd7070Spatrick if (!Element.Key->containsUnexpandedParameterPack() &&
1107e5dd7070Spatrick !Element.Value->containsUnexpandedParameterPack()) {
1108e5dd7070Spatrick Diag(Element.EllipsisLoc,
1109e5dd7070Spatrick diag::err_pack_expansion_without_parameter_packs)
1110e5dd7070Spatrick << SourceRange(Element.Key->getBeginLoc(),
1111e5dd7070Spatrick Element.Value->getEndLoc());
1112e5dd7070Spatrick return ExprError();
1113e5dd7070Spatrick }
1114e5dd7070Spatrick
1115e5dd7070Spatrick HasPackExpansions = true;
1116e5dd7070Spatrick }
1117e5dd7070Spatrick
1118ec727ea7Spatrick QualType Ty = Context.getObjCObjectPointerType(
1119e5dd7070Spatrick Context.getObjCInterfaceType(NSDictionaryDecl));
1120ec727ea7Spatrick
1121ec727ea7Spatrick auto *Literal =
1122ec727ea7Spatrick ObjCDictionaryLiteral::Create(Context, Elements, HasPackExpansions, Ty,
1123ec727ea7Spatrick DictionaryWithObjectsMethod, SR);
1124ec727ea7Spatrick CheckObjCDictionaryLiteralDuplicateKeys(*this, Literal);
1125ec727ea7Spatrick return MaybeBindToTemporary(Literal);
1126e5dd7070Spatrick }
1127e5dd7070Spatrick
BuildObjCEncodeExpression(SourceLocation AtLoc,TypeSourceInfo * EncodedTypeInfo,SourceLocation RParenLoc)1128e5dd7070Spatrick ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
1129e5dd7070Spatrick TypeSourceInfo *EncodedTypeInfo,
1130e5dd7070Spatrick SourceLocation RParenLoc) {
1131e5dd7070Spatrick QualType EncodedType = EncodedTypeInfo->getType();
1132e5dd7070Spatrick QualType StrTy;
1133e5dd7070Spatrick if (EncodedType->isDependentType())
1134e5dd7070Spatrick StrTy = Context.DependentTy;
1135e5dd7070Spatrick else {
1136e5dd7070Spatrick if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled.
1137e5dd7070Spatrick !EncodedType->isVoidType()) // void is handled too.
1138e5dd7070Spatrick if (RequireCompleteType(AtLoc, EncodedType,
1139e5dd7070Spatrick diag::err_incomplete_type_objc_at_encode,
1140e5dd7070Spatrick EncodedTypeInfo->getTypeLoc()))
1141e5dd7070Spatrick return ExprError();
1142e5dd7070Spatrick
1143e5dd7070Spatrick std::string Str;
1144e5dd7070Spatrick QualType NotEncodedT;
1145e5dd7070Spatrick Context.getObjCEncodingForType(EncodedType, Str, nullptr, &NotEncodedT);
1146e5dd7070Spatrick if (!NotEncodedT.isNull())
1147e5dd7070Spatrick Diag(AtLoc, diag::warn_incomplete_encoded_type)
1148e5dd7070Spatrick << EncodedType << NotEncodedT;
1149e5dd7070Spatrick
1150e5dd7070Spatrick // The type of @encode is the same as the type of the corresponding string,
1151e5dd7070Spatrick // which is an array type.
1152e5dd7070Spatrick StrTy = Context.getStringLiteralArrayType(Context.CharTy, Str.size());
1153e5dd7070Spatrick }
1154e5dd7070Spatrick
1155e5dd7070Spatrick return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc);
1156e5dd7070Spatrick }
1157e5dd7070Spatrick
ParseObjCEncodeExpression(SourceLocation AtLoc,SourceLocation EncodeLoc,SourceLocation LParenLoc,ParsedType ty,SourceLocation RParenLoc)1158e5dd7070Spatrick ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
1159e5dd7070Spatrick SourceLocation EncodeLoc,
1160e5dd7070Spatrick SourceLocation LParenLoc,
1161e5dd7070Spatrick ParsedType ty,
1162e5dd7070Spatrick SourceLocation RParenLoc) {
1163e5dd7070Spatrick // FIXME: Preserve type source info ?
1164e5dd7070Spatrick TypeSourceInfo *TInfo;
1165e5dd7070Spatrick QualType EncodedType = GetTypeFromParser(ty, &TInfo);
1166e5dd7070Spatrick if (!TInfo)
1167e5dd7070Spatrick TInfo = Context.getTrivialTypeSourceInfo(EncodedType,
1168e5dd7070Spatrick getLocForEndOfToken(LParenLoc));
1169e5dd7070Spatrick
1170e5dd7070Spatrick return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc);
1171e5dd7070Spatrick }
1172e5dd7070Spatrick
HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema & S,SourceLocation AtLoc,SourceLocation LParenLoc,SourceLocation RParenLoc,ObjCMethodDecl * Method,ObjCMethodList & MethList)1173e5dd7070Spatrick static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
1174e5dd7070Spatrick SourceLocation AtLoc,
1175e5dd7070Spatrick SourceLocation LParenLoc,
1176e5dd7070Spatrick SourceLocation RParenLoc,
1177e5dd7070Spatrick ObjCMethodDecl *Method,
1178e5dd7070Spatrick ObjCMethodList &MethList) {
1179e5dd7070Spatrick ObjCMethodList *M = &MethList;
1180e5dd7070Spatrick bool Warned = false;
1181e5dd7070Spatrick for (M = M->getNext(); M; M=M->getNext()) {
1182e5dd7070Spatrick ObjCMethodDecl *MatchingMethodDecl = M->getMethod();
1183e5dd7070Spatrick if (MatchingMethodDecl == Method ||
1184e5dd7070Spatrick isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()) ||
1185e5dd7070Spatrick MatchingMethodDecl->getSelector() != Method->getSelector())
1186e5dd7070Spatrick continue;
1187e5dd7070Spatrick if (!S.MatchTwoMethodDeclarations(Method,
1188e5dd7070Spatrick MatchingMethodDecl, Sema::MMS_loose)) {
1189e5dd7070Spatrick if (!Warned) {
1190e5dd7070Spatrick Warned = true;
1191e5dd7070Spatrick S.Diag(AtLoc, diag::warn_multiple_selectors)
1192e5dd7070Spatrick << Method->getSelector() << FixItHint::CreateInsertion(LParenLoc, "(")
1193e5dd7070Spatrick << FixItHint::CreateInsertion(RParenLoc, ")");
1194e5dd7070Spatrick S.Diag(Method->getLocation(), diag::note_method_declared_at)
1195e5dd7070Spatrick << Method->getDeclName();
1196e5dd7070Spatrick }
1197e5dd7070Spatrick S.Diag(MatchingMethodDecl->getLocation(), diag::note_method_declared_at)
1198e5dd7070Spatrick << MatchingMethodDecl->getDeclName();
1199e5dd7070Spatrick }
1200e5dd7070Spatrick }
1201e5dd7070Spatrick return Warned;
1202e5dd7070Spatrick }
1203e5dd7070Spatrick
DiagnoseMismatchedSelectors(Sema & S,SourceLocation AtLoc,ObjCMethodDecl * Method,SourceLocation LParenLoc,SourceLocation RParenLoc,bool WarnMultipleSelectors)1204e5dd7070Spatrick static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc,
1205e5dd7070Spatrick ObjCMethodDecl *Method,
1206e5dd7070Spatrick SourceLocation LParenLoc,
1207e5dd7070Spatrick SourceLocation RParenLoc,
1208e5dd7070Spatrick bool WarnMultipleSelectors) {
1209e5dd7070Spatrick if (!WarnMultipleSelectors ||
1210e5dd7070Spatrick S.Diags.isIgnored(diag::warn_multiple_selectors, SourceLocation()))
1211e5dd7070Spatrick return;
1212e5dd7070Spatrick bool Warned = false;
1213e5dd7070Spatrick for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
1214e5dd7070Spatrick e = S.MethodPool.end(); b != e; b++) {
1215e5dd7070Spatrick // first, instance methods
1216e5dd7070Spatrick ObjCMethodList &InstMethList = b->second.first;
1217e5dd7070Spatrick if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
1218e5dd7070Spatrick Method, InstMethList))
1219e5dd7070Spatrick Warned = true;
1220e5dd7070Spatrick
1221e5dd7070Spatrick // second, class methods
1222e5dd7070Spatrick ObjCMethodList &ClsMethList = b->second.second;
1223e5dd7070Spatrick if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
1224e5dd7070Spatrick Method, ClsMethList) || Warned)
1225e5dd7070Spatrick return;
1226e5dd7070Spatrick }
1227e5dd7070Spatrick }
1228e5dd7070Spatrick
LookupDirectMethodInMethodList(Sema & S,Selector Sel,ObjCMethodList & MethList,bool & onlyDirect,bool & anyDirect)1229ec727ea7Spatrick static ObjCMethodDecl *LookupDirectMethodInMethodList(Sema &S, Selector Sel,
1230e5dd7070Spatrick ObjCMethodList &MethList,
1231ec727ea7Spatrick bool &onlyDirect,
1232ec727ea7Spatrick bool &anyDirect) {
1233ec727ea7Spatrick (void)Sel;
1234e5dd7070Spatrick ObjCMethodList *M = &MethList;
1235ec727ea7Spatrick ObjCMethodDecl *DirectMethod = nullptr;
1236ec727ea7Spatrick for (; M; M = M->getNext()) {
1237e5dd7070Spatrick ObjCMethodDecl *Method = M->getMethod();
1238ec727ea7Spatrick if (!Method)
1239e5dd7070Spatrick continue;
1240ec727ea7Spatrick assert(Method->getSelector() == Sel && "Method with wrong selector in method list");
1241ec727ea7Spatrick if (Method->isDirectMethod()) {
1242ec727ea7Spatrick anyDirect = true;
1243ec727ea7Spatrick DirectMethod = Method;
1244ec727ea7Spatrick } else
1245e5dd7070Spatrick onlyDirect = false;
1246e5dd7070Spatrick }
1247ec727ea7Spatrick
1248ec727ea7Spatrick return DirectMethod;
1249e5dd7070Spatrick }
1250e5dd7070Spatrick
1251ec727ea7Spatrick // Search the global pool for (potentially) direct methods matching the given
1252ec727ea7Spatrick // selector. If a non-direct method is found, set \param onlyDirect to false. If
1253ec727ea7Spatrick // a direct method is found, set \param anyDirect to true. Returns a direct
1254ec727ea7Spatrick // method, if any.
LookupDirectMethodInGlobalPool(Sema & S,Selector Sel,bool & onlyDirect,bool & anyDirect)1255ec727ea7Spatrick static ObjCMethodDecl *LookupDirectMethodInGlobalPool(Sema &S, Selector Sel,
1256ec727ea7Spatrick bool &onlyDirect,
1257ec727ea7Spatrick bool &anyDirect) {
1258ec727ea7Spatrick auto Iter = S.MethodPool.find(Sel);
1259ec727ea7Spatrick if (Iter == S.MethodPool.end())
1260ec727ea7Spatrick return nullptr;
1261e5dd7070Spatrick
1262ec727ea7Spatrick ObjCMethodDecl *DirectInstance = LookupDirectMethodInMethodList(
1263ec727ea7Spatrick S, Sel, Iter->second.first, onlyDirect, anyDirect);
1264ec727ea7Spatrick ObjCMethodDecl *DirectClass = LookupDirectMethodInMethodList(
1265ec727ea7Spatrick S, Sel, Iter->second.second, onlyDirect, anyDirect);
1266ec727ea7Spatrick
1267ec727ea7Spatrick return DirectInstance ? DirectInstance : DirectClass;
1268e5dd7070Spatrick }
1269ec727ea7Spatrick
findMethodInCurrentClass(Sema & S,Selector Sel)1270ec727ea7Spatrick static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) {
1271ec727ea7Spatrick auto *CurMD = S.getCurMethodDecl();
1272ec727ea7Spatrick if (!CurMD)
1273ec727ea7Spatrick return nullptr;
1274ec727ea7Spatrick ObjCInterfaceDecl *IFace = CurMD->getClassInterface();
1275ec727ea7Spatrick
1276ec727ea7Spatrick // The language enforce that only one direct method is present in a given
1277ec727ea7Spatrick // class, so we just need to find one method in the current class to know
1278ec727ea7Spatrick // whether Sel is potentially direct in this context.
1279ec727ea7Spatrick if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true))
1280ec727ea7Spatrick return MD;
1281*12c85518Srobert if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/true))
1282ec727ea7Spatrick return MD;
1283ec727ea7Spatrick if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/false))
1284ec727ea7Spatrick return MD;
1285*12c85518Srobert if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/false))
1286ec727ea7Spatrick return MD;
1287ec727ea7Spatrick
1288ec727ea7Spatrick return nullptr;
1289e5dd7070Spatrick }
1290e5dd7070Spatrick
ParseObjCSelectorExpression(Selector Sel,SourceLocation AtLoc,SourceLocation SelLoc,SourceLocation LParenLoc,SourceLocation RParenLoc,bool WarnMultipleSelectors)1291e5dd7070Spatrick ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
1292e5dd7070Spatrick SourceLocation AtLoc,
1293e5dd7070Spatrick SourceLocation SelLoc,
1294e5dd7070Spatrick SourceLocation LParenLoc,
1295e5dd7070Spatrick SourceLocation RParenLoc,
1296e5dd7070Spatrick bool WarnMultipleSelectors) {
1297e5dd7070Spatrick ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
1298e5dd7070Spatrick SourceRange(LParenLoc, RParenLoc));
1299e5dd7070Spatrick if (!Method)
1300e5dd7070Spatrick Method = LookupFactoryMethodInGlobalPool(Sel,
1301e5dd7070Spatrick SourceRange(LParenLoc, RParenLoc));
1302e5dd7070Spatrick if (!Method) {
1303e5dd7070Spatrick if (const ObjCMethodDecl *OM = SelectorsForTypoCorrection(Sel)) {
1304e5dd7070Spatrick Selector MatchedSel = OM->getSelector();
1305e5dd7070Spatrick SourceRange SelectorRange(LParenLoc.getLocWithOffset(1),
1306e5dd7070Spatrick RParenLoc.getLocWithOffset(-1));
1307e5dd7070Spatrick Diag(SelLoc, diag::warn_undeclared_selector_with_typo)
1308e5dd7070Spatrick << Sel << MatchedSel
1309e5dd7070Spatrick << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
1310e5dd7070Spatrick
1311e5dd7070Spatrick } else
1312e5dd7070Spatrick Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
1313e5dd7070Spatrick } else {
1314e5dd7070Spatrick DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
1315e5dd7070Spatrick WarnMultipleSelectors);
1316ec727ea7Spatrick
1317ec727ea7Spatrick bool onlyDirect = true;
1318ec727ea7Spatrick bool anyDirect = false;
1319ec727ea7Spatrick ObjCMethodDecl *GlobalDirectMethod =
1320ec727ea7Spatrick LookupDirectMethodInGlobalPool(*this, Sel, onlyDirect, anyDirect);
1321ec727ea7Spatrick
1322e5dd7070Spatrick if (onlyDirect) {
1323e5dd7070Spatrick Diag(AtLoc, diag::err_direct_selector_expression)
1324e5dd7070Spatrick << Method->getSelector();
1325e5dd7070Spatrick Diag(Method->getLocation(), diag::note_direct_method_declared_at)
1326e5dd7070Spatrick << Method->getDeclName();
1327ec727ea7Spatrick } else if (anyDirect) {
1328ec727ea7Spatrick // If we saw any direct methods, see if we see a direct member of the
1329ec727ea7Spatrick // current class. If so, the @selector will likely be used to refer to
1330ec727ea7Spatrick // this direct method.
1331ec727ea7Spatrick ObjCMethodDecl *LikelyTargetMethod = findMethodInCurrentClass(*this, Sel);
1332ec727ea7Spatrick if (LikelyTargetMethod && LikelyTargetMethod->isDirectMethod()) {
1333ec727ea7Spatrick Diag(AtLoc, diag::warn_potentially_direct_selector_expression) << Sel;
1334ec727ea7Spatrick Diag(LikelyTargetMethod->getLocation(),
1335ec727ea7Spatrick diag::note_direct_method_declared_at)
1336ec727ea7Spatrick << LikelyTargetMethod->getDeclName();
1337ec727ea7Spatrick } else if (!LikelyTargetMethod) {
1338ec727ea7Spatrick // Otherwise, emit the "strict" variant of this diagnostic, unless
1339ec727ea7Spatrick // LikelyTargetMethod is non-direct.
1340ec727ea7Spatrick Diag(AtLoc, diag::warn_strict_potentially_direct_selector_expression)
1341ec727ea7Spatrick << Sel;
1342ec727ea7Spatrick Diag(GlobalDirectMethod->getLocation(),
1343ec727ea7Spatrick diag::note_direct_method_declared_at)
1344ec727ea7Spatrick << GlobalDirectMethod->getDeclName();
1345ec727ea7Spatrick }
1346e5dd7070Spatrick }
1347e5dd7070Spatrick }
1348e5dd7070Spatrick
1349e5dd7070Spatrick if (Method &&
1350e5dd7070Spatrick Method->getImplementationControl() != ObjCMethodDecl::Optional &&
1351e5dd7070Spatrick !getSourceManager().isInSystemHeader(Method->getLocation()))
1352e5dd7070Spatrick ReferencedSelectors.insert(std::make_pair(Sel, AtLoc));
1353e5dd7070Spatrick
1354e5dd7070Spatrick // In ARC, forbid the user from using @selector for
1355e5dd7070Spatrick // retain/release/autorelease/dealloc/retainCount.
1356e5dd7070Spatrick if (getLangOpts().ObjCAutoRefCount) {
1357e5dd7070Spatrick switch (Sel.getMethodFamily()) {
1358e5dd7070Spatrick case OMF_retain:
1359e5dd7070Spatrick case OMF_release:
1360e5dd7070Spatrick case OMF_autorelease:
1361e5dd7070Spatrick case OMF_retainCount:
1362e5dd7070Spatrick case OMF_dealloc:
1363e5dd7070Spatrick Diag(AtLoc, diag::err_arc_illegal_selector) <<
1364e5dd7070Spatrick Sel << SourceRange(LParenLoc, RParenLoc);
1365e5dd7070Spatrick break;
1366e5dd7070Spatrick
1367e5dd7070Spatrick case OMF_None:
1368e5dd7070Spatrick case OMF_alloc:
1369e5dd7070Spatrick case OMF_copy:
1370e5dd7070Spatrick case OMF_finalize:
1371e5dd7070Spatrick case OMF_init:
1372e5dd7070Spatrick case OMF_mutableCopy:
1373e5dd7070Spatrick case OMF_new:
1374e5dd7070Spatrick case OMF_self:
1375e5dd7070Spatrick case OMF_initialize:
1376e5dd7070Spatrick case OMF_performSelector:
1377e5dd7070Spatrick break;
1378e5dd7070Spatrick }
1379e5dd7070Spatrick }
1380e5dd7070Spatrick QualType Ty = Context.getObjCSelType();
1381e5dd7070Spatrick return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
1382e5dd7070Spatrick }
1383e5dd7070Spatrick
ParseObjCProtocolExpression(IdentifierInfo * ProtocolId,SourceLocation AtLoc,SourceLocation ProtoLoc,SourceLocation LParenLoc,SourceLocation ProtoIdLoc,SourceLocation RParenLoc)1384e5dd7070Spatrick ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
1385e5dd7070Spatrick SourceLocation AtLoc,
1386e5dd7070Spatrick SourceLocation ProtoLoc,
1387e5dd7070Spatrick SourceLocation LParenLoc,
1388e5dd7070Spatrick SourceLocation ProtoIdLoc,
1389e5dd7070Spatrick SourceLocation RParenLoc) {
1390e5dd7070Spatrick ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoIdLoc);
1391e5dd7070Spatrick if (!PDecl) {
1392e5dd7070Spatrick Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
1393e5dd7070Spatrick return true;
1394e5dd7070Spatrick }
1395a9ac8606Spatrick if (PDecl->isNonRuntimeProtocol())
1396a9ac8606Spatrick Diag(ProtoLoc, diag::err_objc_non_runtime_protocol_in_protocol_expr)
1397a9ac8606Spatrick << PDecl;
1398e5dd7070Spatrick if (!PDecl->hasDefinition()) {
1399e5dd7070Spatrick Diag(ProtoLoc, diag::err_atprotocol_protocol) << PDecl;
1400e5dd7070Spatrick Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl;
1401e5dd7070Spatrick } else {
1402e5dd7070Spatrick PDecl = PDecl->getDefinition();
1403e5dd7070Spatrick }
1404e5dd7070Spatrick
1405e5dd7070Spatrick QualType Ty = Context.getObjCProtoType();
1406e5dd7070Spatrick if (Ty.isNull())
1407e5dd7070Spatrick return true;
1408e5dd7070Spatrick Ty = Context.getObjCObjectPointerType(Ty);
1409e5dd7070Spatrick return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, ProtoIdLoc, RParenLoc);
1410e5dd7070Spatrick }
1411e5dd7070Spatrick
1412e5dd7070Spatrick /// Try to capture an implicit reference to 'self'.
tryCaptureObjCSelf(SourceLocation Loc)1413e5dd7070Spatrick ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) {
1414e5dd7070Spatrick DeclContext *DC = getFunctionLevelDeclContext();
1415e5dd7070Spatrick
1416e5dd7070Spatrick // If we're not in an ObjC method, error out. Note that, unlike the
1417e5dd7070Spatrick // C++ case, we don't require an instance method --- class methods
1418e5dd7070Spatrick // still have a 'self', and we really do still need to capture it!
1419e5dd7070Spatrick ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(DC);
1420e5dd7070Spatrick if (!method)
1421e5dd7070Spatrick return nullptr;
1422e5dd7070Spatrick
1423e5dd7070Spatrick tryCaptureVariable(method->getSelfDecl(), Loc);
1424e5dd7070Spatrick
1425e5dd7070Spatrick return method;
1426e5dd7070Spatrick }
1427e5dd7070Spatrick
stripObjCInstanceType(ASTContext & Context,QualType T)1428e5dd7070Spatrick static QualType stripObjCInstanceType(ASTContext &Context, QualType T) {
1429e5dd7070Spatrick QualType origType = T;
1430e5dd7070Spatrick if (auto nullability = AttributedType::stripOuterNullability(T)) {
1431e5dd7070Spatrick if (T == Context.getObjCInstanceType()) {
1432e5dd7070Spatrick return Context.getAttributedType(
1433e5dd7070Spatrick AttributedType::getNullabilityAttrKind(*nullability),
1434e5dd7070Spatrick Context.getObjCIdType(),
1435e5dd7070Spatrick Context.getObjCIdType());
1436e5dd7070Spatrick }
1437e5dd7070Spatrick
1438e5dd7070Spatrick return origType;
1439e5dd7070Spatrick }
1440e5dd7070Spatrick
1441e5dd7070Spatrick if (T == Context.getObjCInstanceType())
1442e5dd7070Spatrick return Context.getObjCIdType();
1443e5dd7070Spatrick
1444e5dd7070Spatrick return origType;
1445e5dd7070Spatrick }
1446e5dd7070Spatrick
1447e5dd7070Spatrick /// Determine the result type of a message send based on the receiver type,
1448e5dd7070Spatrick /// method, and the kind of message send.
1449e5dd7070Spatrick ///
1450e5dd7070Spatrick /// This is the "base" result type, which will still need to be adjusted
1451e5dd7070Spatrick /// to account for nullability.
getBaseMessageSendResultType(Sema & S,QualType ReceiverType,ObjCMethodDecl * Method,bool isClassMessage,bool isSuperMessage)1452e5dd7070Spatrick static QualType getBaseMessageSendResultType(Sema &S,
1453e5dd7070Spatrick QualType ReceiverType,
1454e5dd7070Spatrick ObjCMethodDecl *Method,
1455e5dd7070Spatrick bool isClassMessage,
1456e5dd7070Spatrick bool isSuperMessage) {
1457e5dd7070Spatrick assert(Method && "Must have a method");
1458e5dd7070Spatrick if (!Method->hasRelatedResultType())
1459e5dd7070Spatrick return Method->getSendResultType(ReceiverType);
1460e5dd7070Spatrick
1461e5dd7070Spatrick ASTContext &Context = S.Context;
1462e5dd7070Spatrick
1463e5dd7070Spatrick // Local function that transfers the nullability of the method's
1464e5dd7070Spatrick // result type to the returned result.
1465e5dd7070Spatrick auto transferNullability = [&](QualType type) -> QualType {
1466e5dd7070Spatrick // If the method's result type has nullability, extract it.
1467*12c85518Srobert if (auto nullability =
1468*12c85518Srobert Method->getSendResultType(ReceiverType)->getNullability()) {
1469e5dd7070Spatrick // Strip off any outer nullability sugar from the provided type.
1470e5dd7070Spatrick (void)AttributedType::stripOuterNullability(type);
1471e5dd7070Spatrick
1472e5dd7070Spatrick // Form a new attributed type using the method result type's nullability.
1473e5dd7070Spatrick return Context.getAttributedType(
1474e5dd7070Spatrick AttributedType::getNullabilityAttrKind(*nullability),
1475e5dd7070Spatrick type,
1476e5dd7070Spatrick type);
1477e5dd7070Spatrick }
1478e5dd7070Spatrick
1479e5dd7070Spatrick return type;
1480e5dd7070Spatrick };
1481e5dd7070Spatrick
1482e5dd7070Spatrick // If a method has a related return type:
1483e5dd7070Spatrick // - if the method found is an instance method, but the message send
1484e5dd7070Spatrick // was a class message send, T is the declared return type of the method
1485e5dd7070Spatrick // found
1486e5dd7070Spatrick if (Method->isInstanceMethod() && isClassMessage)
1487e5dd7070Spatrick return stripObjCInstanceType(Context,
1488e5dd7070Spatrick Method->getSendResultType(ReceiverType));
1489e5dd7070Spatrick
1490e5dd7070Spatrick // - if the receiver is super, T is a pointer to the class of the
1491e5dd7070Spatrick // enclosing method definition
1492e5dd7070Spatrick if (isSuperMessage) {
1493e5dd7070Spatrick if (ObjCMethodDecl *CurMethod = S.getCurMethodDecl())
1494e5dd7070Spatrick if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) {
1495e5dd7070Spatrick return transferNullability(
1496e5dd7070Spatrick Context.getObjCObjectPointerType(
1497e5dd7070Spatrick Context.getObjCInterfaceType(Class)));
1498e5dd7070Spatrick }
1499e5dd7070Spatrick }
1500e5dd7070Spatrick
1501e5dd7070Spatrick // - if the receiver is the name of a class U, T is a pointer to U
1502e5dd7070Spatrick if (ReceiverType->getAsObjCInterfaceType())
1503e5dd7070Spatrick return transferNullability(Context.getObjCObjectPointerType(ReceiverType));
1504e5dd7070Spatrick // - if the receiver is of type Class or qualified Class type,
1505e5dd7070Spatrick // T is the declared return type of the method.
1506e5dd7070Spatrick if (ReceiverType->isObjCClassType() ||
1507e5dd7070Spatrick ReceiverType->isObjCQualifiedClassType())
1508e5dd7070Spatrick return stripObjCInstanceType(Context,
1509e5dd7070Spatrick Method->getSendResultType(ReceiverType));
1510e5dd7070Spatrick
1511e5dd7070Spatrick // - if the receiver is id, qualified id, Class, or qualified Class, T
1512e5dd7070Spatrick // is the receiver type, otherwise
1513e5dd7070Spatrick // - T is the type of the receiver expression.
1514e5dd7070Spatrick return transferNullability(ReceiverType);
1515e5dd7070Spatrick }
1516e5dd7070Spatrick
getMessageSendResultType(const Expr * Receiver,QualType ReceiverType,ObjCMethodDecl * Method,bool isClassMessage,bool isSuperMessage)1517e5dd7070Spatrick QualType Sema::getMessageSendResultType(const Expr *Receiver,
1518e5dd7070Spatrick QualType ReceiverType,
1519e5dd7070Spatrick ObjCMethodDecl *Method,
1520e5dd7070Spatrick bool isClassMessage,
1521e5dd7070Spatrick bool isSuperMessage) {
1522e5dd7070Spatrick // Produce the result type.
1523e5dd7070Spatrick QualType resultType = getBaseMessageSendResultType(*this, ReceiverType,
1524e5dd7070Spatrick Method,
1525e5dd7070Spatrick isClassMessage,
1526e5dd7070Spatrick isSuperMessage);
1527e5dd7070Spatrick
1528e5dd7070Spatrick // If this is a class message, ignore the nullability of the receiver.
1529e5dd7070Spatrick if (isClassMessage) {
1530e5dd7070Spatrick // In a class method, class messages to 'self' that return instancetype can
1531e5dd7070Spatrick // be typed as the current class. We can safely do this in ARC because self
1532e5dd7070Spatrick // can't be reassigned, and we do it unsafely outside of ARC because in
1533e5dd7070Spatrick // practice people never reassign self in class methods and there's some
1534e5dd7070Spatrick // virtue in not being aggressively pedantic.
1535e5dd7070Spatrick if (Receiver && Receiver->isObjCSelfExpr()) {
1536e5dd7070Spatrick assert(ReceiverType->isObjCClassType() && "expected a Class self");
1537e5dd7070Spatrick QualType T = Method->getSendResultType(ReceiverType);
1538e5dd7070Spatrick AttributedType::stripOuterNullability(T);
1539e5dd7070Spatrick if (T == Context.getObjCInstanceType()) {
1540e5dd7070Spatrick const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(
1541e5dd7070Spatrick cast<ImplicitParamDecl>(
1542e5dd7070Spatrick cast<DeclRefExpr>(Receiver->IgnoreParenImpCasts())->getDecl())
1543e5dd7070Spatrick ->getDeclContext());
1544e5dd7070Spatrick assert(MD->isClassMethod() && "expected a class method");
1545e5dd7070Spatrick QualType NewResultType = Context.getObjCObjectPointerType(
1546e5dd7070Spatrick Context.getObjCInterfaceType(MD->getClassInterface()));
1547*12c85518Srobert if (auto Nullability = resultType->getNullability())
1548e5dd7070Spatrick NewResultType = Context.getAttributedType(
1549e5dd7070Spatrick AttributedType::getNullabilityAttrKind(*Nullability),
1550e5dd7070Spatrick NewResultType, NewResultType);
1551e5dd7070Spatrick return NewResultType;
1552e5dd7070Spatrick }
1553e5dd7070Spatrick }
1554e5dd7070Spatrick return resultType;
1555e5dd7070Spatrick }
1556e5dd7070Spatrick
1557e5dd7070Spatrick // There is nothing left to do if the result type cannot have a nullability
1558e5dd7070Spatrick // specifier.
1559e5dd7070Spatrick if (!resultType->canHaveNullability())
1560e5dd7070Spatrick return resultType;
1561e5dd7070Spatrick
1562e5dd7070Spatrick // Map the nullability of the result into a table index.
1563e5dd7070Spatrick unsigned receiverNullabilityIdx = 0;
1564*12c85518Srobert if (std::optional<NullabilityKind> nullability =
1565*12c85518Srobert ReceiverType->getNullability()) {
1566a9ac8606Spatrick if (*nullability == NullabilityKind::NullableResult)
1567a9ac8606Spatrick nullability = NullabilityKind::Nullable;
1568e5dd7070Spatrick receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
1569a9ac8606Spatrick }
1570e5dd7070Spatrick
1571e5dd7070Spatrick unsigned resultNullabilityIdx = 0;
1572*12c85518Srobert if (std::optional<NullabilityKind> nullability =
1573*12c85518Srobert resultType->getNullability()) {
1574a9ac8606Spatrick if (*nullability == NullabilityKind::NullableResult)
1575a9ac8606Spatrick nullability = NullabilityKind::Nullable;
1576e5dd7070Spatrick resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
1577a9ac8606Spatrick }
1578e5dd7070Spatrick
1579e5dd7070Spatrick // The table of nullability mappings, indexed by the receiver's nullability
1580e5dd7070Spatrick // and then the result type's nullability.
1581e5dd7070Spatrick static const uint8_t None = 0;
1582e5dd7070Spatrick static const uint8_t NonNull = 1;
1583e5dd7070Spatrick static const uint8_t Nullable = 2;
1584e5dd7070Spatrick static const uint8_t Unspecified = 3;
1585e5dd7070Spatrick static const uint8_t nullabilityMap[4][4] = {
1586e5dd7070Spatrick // None NonNull Nullable Unspecified
1587e5dd7070Spatrick /* None */ { None, None, Nullable, None },
1588e5dd7070Spatrick /* NonNull */ { None, NonNull, Nullable, Unspecified },
1589e5dd7070Spatrick /* Nullable */ { Nullable, Nullable, Nullable, Nullable },
1590e5dd7070Spatrick /* Unspecified */ { None, Unspecified, Nullable, Unspecified }
1591e5dd7070Spatrick };
1592e5dd7070Spatrick
1593e5dd7070Spatrick unsigned newResultNullabilityIdx
1594e5dd7070Spatrick = nullabilityMap[receiverNullabilityIdx][resultNullabilityIdx];
1595e5dd7070Spatrick if (newResultNullabilityIdx == resultNullabilityIdx)
1596e5dd7070Spatrick return resultType;
1597e5dd7070Spatrick
1598e5dd7070Spatrick // Strip off the existing nullability. This removes as little type sugar as
1599e5dd7070Spatrick // possible.
1600e5dd7070Spatrick do {
1601e5dd7070Spatrick if (auto attributed = dyn_cast<AttributedType>(resultType.getTypePtr())) {
1602e5dd7070Spatrick resultType = attributed->getModifiedType();
1603e5dd7070Spatrick } else {
1604e5dd7070Spatrick resultType = resultType.getDesugaredType(Context);
1605e5dd7070Spatrick }
1606*12c85518Srobert } while (resultType->getNullability());
1607e5dd7070Spatrick
1608e5dd7070Spatrick // Add nullability back if needed.
1609e5dd7070Spatrick if (newResultNullabilityIdx > 0) {
1610e5dd7070Spatrick auto newNullability
1611e5dd7070Spatrick = static_cast<NullabilityKind>(newResultNullabilityIdx-1);
1612e5dd7070Spatrick return Context.getAttributedType(
1613e5dd7070Spatrick AttributedType::getNullabilityAttrKind(newNullability),
1614e5dd7070Spatrick resultType, resultType);
1615e5dd7070Spatrick }
1616e5dd7070Spatrick
1617e5dd7070Spatrick return resultType;
1618e5dd7070Spatrick }
1619e5dd7070Spatrick
1620e5dd7070Spatrick /// Look for an ObjC method whose result type exactly matches the given type.
1621e5dd7070Spatrick static const ObjCMethodDecl *
findExplicitInstancetypeDeclarer(const ObjCMethodDecl * MD,QualType instancetype)1622e5dd7070Spatrick findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD,
1623e5dd7070Spatrick QualType instancetype) {
1624e5dd7070Spatrick if (MD->getReturnType() == instancetype)
1625e5dd7070Spatrick return MD;
1626e5dd7070Spatrick
1627e5dd7070Spatrick // For these purposes, a method in an @implementation overrides a
1628e5dd7070Spatrick // declaration in the @interface.
1629e5dd7070Spatrick if (const ObjCImplDecl *impl =
1630e5dd7070Spatrick dyn_cast<ObjCImplDecl>(MD->getDeclContext())) {
1631e5dd7070Spatrick const ObjCContainerDecl *iface;
1632e5dd7070Spatrick if (const ObjCCategoryImplDecl *catImpl =
1633e5dd7070Spatrick dyn_cast<ObjCCategoryImplDecl>(impl)) {
1634e5dd7070Spatrick iface = catImpl->getCategoryDecl();
1635e5dd7070Spatrick } else {
1636e5dd7070Spatrick iface = impl->getClassInterface();
1637e5dd7070Spatrick }
1638e5dd7070Spatrick
1639e5dd7070Spatrick const ObjCMethodDecl *ifaceMD =
1640e5dd7070Spatrick iface->getMethod(MD->getSelector(), MD->isInstanceMethod());
1641e5dd7070Spatrick if (ifaceMD) return findExplicitInstancetypeDeclarer(ifaceMD, instancetype);
1642e5dd7070Spatrick }
1643e5dd7070Spatrick
1644e5dd7070Spatrick SmallVector<const ObjCMethodDecl *, 4> overrides;
1645e5dd7070Spatrick MD->getOverriddenMethods(overrides);
1646e5dd7070Spatrick for (unsigned i = 0, e = overrides.size(); i != e; ++i) {
1647e5dd7070Spatrick if (const ObjCMethodDecl *result =
1648e5dd7070Spatrick findExplicitInstancetypeDeclarer(overrides[i], instancetype))
1649e5dd7070Spatrick return result;
1650e5dd7070Spatrick }
1651e5dd7070Spatrick
1652e5dd7070Spatrick return nullptr;
1653e5dd7070Spatrick }
1654e5dd7070Spatrick
EmitRelatedResultTypeNoteForReturn(QualType destType)1655e5dd7070Spatrick void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
1656e5dd7070Spatrick // Only complain if we're in an ObjC method and the required return
1657e5dd7070Spatrick // type doesn't match the method's declared return type.
1658e5dd7070Spatrick ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurContext);
1659e5dd7070Spatrick if (!MD || !MD->hasRelatedResultType() ||
1660e5dd7070Spatrick Context.hasSameUnqualifiedType(destType, MD->getReturnType()))
1661e5dd7070Spatrick return;
1662e5dd7070Spatrick
1663e5dd7070Spatrick // Look for a method overridden by this method which explicitly uses
1664e5dd7070Spatrick // 'instancetype'.
1665e5dd7070Spatrick if (const ObjCMethodDecl *overridden =
1666e5dd7070Spatrick findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) {
1667e5dd7070Spatrick SourceRange range = overridden->getReturnTypeSourceRange();
1668e5dd7070Spatrick SourceLocation loc = range.getBegin();
1669e5dd7070Spatrick if (loc.isInvalid())
1670e5dd7070Spatrick loc = overridden->getLocation();
1671e5dd7070Spatrick Diag(loc, diag::note_related_result_type_explicit)
1672e5dd7070Spatrick << /*current method*/ 1 << range;
1673e5dd7070Spatrick return;
1674e5dd7070Spatrick }
1675e5dd7070Spatrick
1676e5dd7070Spatrick // Otherwise, if we have an interesting method family, note that.
1677e5dd7070Spatrick // This should always trigger if the above didn't.
1678e5dd7070Spatrick if (ObjCMethodFamily family = MD->getMethodFamily())
1679e5dd7070Spatrick Diag(MD->getLocation(), diag::note_related_result_type_family)
1680e5dd7070Spatrick << /*current method*/ 1
1681e5dd7070Spatrick << family;
1682e5dd7070Spatrick }
1683e5dd7070Spatrick
EmitRelatedResultTypeNote(const Expr * E)1684e5dd7070Spatrick void Sema::EmitRelatedResultTypeNote(const Expr *E) {
1685e5dd7070Spatrick E = E->IgnoreParenImpCasts();
1686e5dd7070Spatrick const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E);
1687e5dd7070Spatrick if (!MsgSend)
1688e5dd7070Spatrick return;
1689e5dd7070Spatrick
1690e5dd7070Spatrick const ObjCMethodDecl *Method = MsgSend->getMethodDecl();
1691e5dd7070Spatrick if (!Method)
1692e5dd7070Spatrick return;
1693e5dd7070Spatrick
1694e5dd7070Spatrick if (!Method->hasRelatedResultType())
1695e5dd7070Spatrick return;
1696e5dd7070Spatrick
1697e5dd7070Spatrick if (Context.hasSameUnqualifiedType(
1698e5dd7070Spatrick Method->getReturnType().getNonReferenceType(), MsgSend->getType()))
1699e5dd7070Spatrick return;
1700e5dd7070Spatrick
1701e5dd7070Spatrick if (!Context.hasSameUnqualifiedType(Method->getReturnType(),
1702e5dd7070Spatrick Context.getObjCInstanceType()))
1703e5dd7070Spatrick return;
1704e5dd7070Spatrick
1705e5dd7070Spatrick Diag(Method->getLocation(), diag::note_related_result_type_inferred)
1706e5dd7070Spatrick << Method->isInstanceMethod() << Method->getSelector()
1707e5dd7070Spatrick << MsgSend->getType();
1708e5dd7070Spatrick }
1709e5dd7070Spatrick
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)1710e5dd7070Spatrick bool Sema::CheckMessageArgumentTypes(
1711e5dd7070Spatrick const Expr *Receiver, QualType ReceiverType, MultiExprArg Args,
1712e5dd7070Spatrick Selector Sel, ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method,
1713e5dd7070Spatrick bool isClassMessage, bool isSuperMessage, SourceLocation lbrac,
1714e5dd7070Spatrick SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType,
1715e5dd7070Spatrick ExprValueKind &VK) {
1716e5dd7070Spatrick SourceLocation SelLoc;
1717e5dd7070Spatrick if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
1718e5dd7070Spatrick SelLoc = SelectorLocs.front();
1719e5dd7070Spatrick else
1720e5dd7070Spatrick SelLoc = lbrac;
1721e5dd7070Spatrick
1722e5dd7070Spatrick if (!Method) {
1723e5dd7070Spatrick // Apply default argument promotion as for (C99 6.5.2.2p6).
1724e5dd7070Spatrick for (unsigned i = 0, e = Args.size(); i != e; i++) {
1725e5dd7070Spatrick if (Args[i]->isTypeDependent())
1726e5dd7070Spatrick continue;
1727e5dd7070Spatrick
1728e5dd7070Spatrick ExprResult result;
1729e5dd7070Spatrick if (getLangOpts().DebuggerSupport) {
1730e5dd7070Spatrick QualType paramTy; // ignored
1731e5dd7070Spatrick result = checkUnknownAnyArg(SelLoc, Args[i], paramTy);
1732e5dd7070Spatrick } else {
1733e5dd7070Spatrick result = DefaultArgumentPromotion(Args[i]);
1734e5dd7070Spatrick }
1735e5dd7070Spatrick if (result.isInvalid())
1736e5dd7070Spatrick return true;
1737e5dd7070Spatrick Args[i] = result.get();
1738e5dd7070Spatrick }
1739e5dd7070Spatrick
1740e5dd7070Spatrick unsigned DiagID;
1741e5dd7070Spatrick if (getLangOpts().ObjCAutoRefCount)
1742e5dd7070Spatrick DiagID = diag::err_arc_method_not_found;
1743e5dd7070Spatrick else
1744e5dd7070Spatrick DiagID = isClassMessage ? diag::warn_class_method_not_found
1745e5dd7070Spatrick : diag::warn_inst_method_not_found;
1746e5dd7070Spatrick if (!getLangOpts().DebuggerSupport) {
1747e5dd7070Spatrick const ObjCMethodDecl *OMD = SelectorsForTypoCorrection(Sel, ReceiverType);
1748e5dd7070Spatrick if (OMD && !OMD->isInvalidDecl()) {
1749e5dd7070Spatrick if (getLangOpts().ObjCAutoRefCount)
1750e5dd7070Spatrick DiagID = diag::err_method_not_found_with_typo;
1751e5dd7070Spatrick else
1752e5dd7070Spatrick DiagID = isClassMessage ? diag::warn_class_method_not_found_with_typo
1753e5dd7070Spatrick : diag::warn_instance_method_not_found_with_typo;
1754e5dd7070Spatrick Selector MatchedSel = OMD->getSelector();
1755e5dd7070Spatrick SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back());
1756e5dd7070Spatrick if (MatchedSel.isUnarySelector())
1757e5dd7070Spatrick Diag(SelLoc, DiagID)
1758e5dd7070Spatrick << Sel<< isClassMessage << MatchedSel
1759e5dd7070Spatrick << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
1760e5dd7070Spatrick else
1761e5dd7070Spatrick Diag(SelLoc, DiagID) << Sel<< isClassMessage << MatchedSel;
1762e5dd7070Spatrick }
1763e5dd7070Spatrick else
1764e5dd7070Spatrick Diag(SelLoc, DiagID)
1765e5dd7070Spatrick << Sel << isClassMessage << SourceRange(SelectorLocs.front(),
1766e5dd7070Spatrick SelectorLocs.back());
1767e5dd7070Spatrick // Find the class to which we are sending this message.
1768e5dd7070Spatrick if (auto *ObjPT = ReceiverType->getAs<ObjCObjectPointerType>()) {
1769e5dd7070Spatrick if (ObjCInterfaceDecl *ThisClass = ObjPT->getInterfaceDecl()) {
1770e5dd7070Spatrick Diag(ThisClass->getLocation(), diag::note_receiver_class_declared);
1771e5dd7070Spatrick if (!RecRange.isInvalid())
1772e5dd7070Spatrick if (ThisClass->lookupClassMethod(Sel))
1773e5dd7070Spatrick Diag(RecRange.getBegin(), diag::note_receiver_expr_here)
1774e5dd7070Spatrick << FixItHint::CreateReplacement(RecRange,
1775e5dd7070Spatrick ThisClass->getNameAsString());
1776e5dd7070Spatrick }
1777e5dd7070Spatrick }
1778e5dd7070Spatrick }
1779e5dd7070Spatrick
1780e5dd7070Spatrick // In debuggers, we want to use __unknown_anytype for these
1781e5dd7070Spatrick // results so that clients can cast them.
1782e5dd7070Spatrick if (getLangOpts().DebuggerSupport) {
1783e5dd7070Spatrick ReturnType = Context.UnknownAnyTy;
1784e5dd7070Spatrick } else {
1785e5dd7070Spatrick ReturnType = Context.getObjCIdType();
1786e5dd7070Spatrick }
1787a9ac8606Spatrick VK = VK_PRValue;
1788e5dd7070Spatrick return false;
1789e5dd7070Spatrick }
1790e5dd7070Spatrick
1791e5dd7070Spatrick ReturnType = getMessageSendResultType(Receiver, ReceiverType, Method,
1792e5dd7070Spatrick isClassMessage, isSuperMessage);
1793e5dd7070Spatrick VK = Expr::getValueKindForType(Method->getReturnType());
1794e5dd7070Spatrick
1795e5dd7070Spatrick unsigned NumNamedArgs = Sel.getNumArgs();
1796e5dd7070Spatrick // Method might have more arguments than selector indicates. This is due
1797e5dd7070Spatrick // to addition of c-style arguments in method.
1798e5dd7070Spatrick if (Method->param_size() > Sel.getNumArgs())
1799e5dd7070Spatrick NumNamedArgs = Method->param_size();
1800e5dd7070Spatrick // FIXME. This need be cleaned up.
1801e5dd7070Spatrick if (Args.size() < NumNamedArgs) {
1802e5dd7070Spatrick Diag(SelLoc, diag::err_typecheck_call_too_few_args)
1803e5dd7070Spatrick << 2 << NumNamedArgs << static_cast<unsigned>(Args.size());
1804e5dd7070Spatrick return false;
1805e5dd7070Spatrick }
1806e5dd7070Spatrick
1807e5dd7070Spatrick // Compute the set of type arguments to be substituted into each parameter
1808e5dd7070Spatrick // type.
1809*12c85518Srobert std::optional<ArrayRef<QualType>> typeArgs =
1810*12c85518Srobert ReceiverType->getObjCSubstitutions(Method->getDeclContext());
1811e5dd7070Spatrick bool IsError = false;
1812e5dd7070Spatrick for (unsigned i = 0; i < NumNamedArgs; i++) {
1813e5dd7070Spatrick // We can't do any type-checking on a type-dependent argument.
1814e5dd7070Spatrick if (Args[i]->isTypeDependent())
1815e5dd7070Spatrick continue;
1816e5dd7070Spatrick
1817e5dd7070Spatrick Expr *argExpr = Args[i];
1818e5dd7070Spatrick
1819e5dd7070Spatrick ParmVarDecl *param = Method->parameters()[i];
1820e5dd7070Spatrick assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
1821e5dd7070Spatrick
1822a9ac8606Spatrick if (param->hasAttr<NoEscapeAttr>() &&
1823a9ac8606Spatrick param->getType()->isBlockPointerType())
1824e5dd7070Spatrick if (auto *BE = dyn_cast<BlockExpr>(
1825e5dd7070Spatrick argExpr->IgnoreParenNoopCasts(Context)))
1826e5dd7070Spatrick BE->getBlockDecl()->setDoesNotEscape();
1827e5dd7070Spatrick
1828e5dd7070Spatrick // Strip the unbridged-cast placeholder expression off unless it's
1829e5dd7070Spatrick // a consumed argument.
1830e5dd7070Spatrick if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
1831e5dd7070Spatrick !param->hasAttr<CFConsumedAttr>())
1832e5dd7070Spatrick argExpr = stripARCUnbridgedCast(argExpr);
1833e5dd7070Spatrick
1834e5dd7070Spatrick // If the parameter is __unknown_anytype, infer its type
1835e5dd7070Spatrick // from the argument.
1836e5dd7070Spatrick if (param->getType() == Context.UnknownAnyTy) {
1837e5dd7070Spatrick QualType paramType;
1838e5dd7070Spatrick ExprResult argE = checkUnknownAnyArg(SelLoc, argExpr, paramType);
1839e5dd7070Spatrick if (argE.isInvalid()) {
1840e5dd7070Spatrick IsError = true;
1841e5dd7070Spatrick } else {
1842e5dd7070Spatrick Args[i] = argE.get();
1843e5dd7070Spatrick
1844e5dd7070Spatrick // Update the parameter type in-place.
1845e5dd7070Spatrick param->setType(paramType);
1846e5dd7070Spatrick }
1847e5dd7070Spatrick continue;
1848e5dd7070Spatrick }
1849e5dd7070Spatrick
1850e5dd7070Spatrick QualType origParamType = param->getType();
1851e5dd7070Spatrick QualType paramType = param->getType();
1852e5dd7070Spatrick if (typeArgs)
1853e5dd7070Spatrick paramType = paramType.substObjCTypeArgs(
1854e5dd7070Spatrick Context,
1855e5dd7070Spatrick *typeArgs,
1856e5dd7070Spatrick ObjCSubstitutionContext::Parameter);
1857e5dd7070Spatrick
1858e5dd7070Spatrick if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
1859e5dd7070Spatrick paramType,
1860e5dd7070Spatrick diag::err_call_incomplete_argument, argExpr))
1861e5dd7070Spatrick return true;
1862e5dd7070Spatrick
1863e5dd7070Spatrick InitializedEntity Entity
1864e5dd7070Spatrick = InitializedEntity::InitializeParameter(Context, param, paramType);
1865e5dd7070Spatrick ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr);
1866e5dd7070Spatrick if (ArgE.isInvalid())
1867e5dd7070Spatrick IsError = true;
1868e5dd7070Spatrick else {
1869e5dd7070Spatrick Args[i] = ArgE.getAs<Expr>();
1870e5dd7070Spatrick
1871e5dd7070Spatrick // If we are type-erasing a block to a block-compatible
1872e5dd7070Spatrick // Objective-C pointer type, we may need to extend the lifetime
1873e5dd7070Spatrick // of the block object.
1874a9ac8606Spatrick if (typeArgs && Args[i]->isPRValue() && paramType->isBlockPointerType() &&
1875e5dd7070Spatrick Args[i]->getType()->isBlockPointerType() &&
1876e5dd7070Spatrick origParamType->isObjCObjectPointerType()) {
1877e5dd7070Spatrick ExprResult arg = Args[i];
1878e5dd7070Spatrick maybeExtendBlockObject(arg);
1879e5dd7070Spatrick Args[i] = arg.get();
1880e5dd7070Spatrick }
1881e5dd7070Spatrick }
1882e5dd7070Spatrick }
1883e5dd7070Spatrick
1884e5dd7070Spatrick // Promote additional arguments to variadic methods.
1885e5dd7070Spatrick if (Method->isVariadic()) {
1886e5dd7070Spatrick for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) {
1887e5dd7070Spatrick if (Args[i]->isTypeDependent())
1888e5dd7070Spatrick continue;
1889e5dd7070Spatrick
1890e5dd7070Spatrick ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
1891e5dd7070Spatrick nullptr);
1892e5dd7070Spatrick IsError |= Arg.isInvalid();
1893e5dd7070Spatrick Args[i] = Arg.get();
1894e5dd7070Spatrick }
1895e5dd7070Spatrick } else {
1896e5dd7070Spatrick // Check for extra arguments to non-variadic methods.
1897e5dd7070Spatrick if (Args.size() != NumNamedArgs) {
1898e5dd7070Spatrick Diag(Args[NumNamedArgs]->getBeginLoc(),
1899e5dd7070Spatrick diag::err_typecheck_call_too_many_args)
1900e5dd7070Spatrick << 2 /*method*/ << NumNamedArgs << static_cast<unsigned>(Args.size())
1901e5dd7070Spatrick << Method->getSourceRange()
1902e5dd7070Spatrick << SourceRange(Args[NumNamedArgs]->getBeginLoc(),
1903e5dd7070Spatrick Args.back()->getEndLoc());
1904e5dd7070Spatrick }
1905e5dd7070Spatrick }
1906e5dd7070Spatrick
1907e5dd7070Spatrick DiagnoseSentinelCalls(Method, SelLoc, Args);
1908e5dd7070Spatrick
1909e5dd7070Spatrick // Do additional checkings on method.
1910*12c85518Srobert IsError |=
1911*12c85518Srobert CheckObjCMethodCall(Method, SelLoc, ArrayRef(Args.data(), Args.size()));
1912e5dd7070Spatrick
1913e5dd7070Spatrick return IsError;
1914e5dd7070Spatrick }
1915e5dd7070Spatrick
isSelfExpr(Expr * RExpr)1916e5dd7070Spatrick bool Sema::isSelfExpr(Expr *RExpr) {
1917e5dd7070Spatrick // 'self' is objc 'self' in an objc method only.
1918e5dd7070Spatrick ObjCMethodDecl *Method =
1919e5dd7070Spatrick dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
1920e5dd7070Spatrick return isSelfExpr(RExpr, Method);
1921e5dd7070Spatrick }
1922e5dd7070Spatrick
isSelfExpr(Expr * receiver,const ObjCMethodDecl * method)1923e5dd7070Spatrick bool Sema::isSelfExpr(Expr *receiver, const ObjCMethodDecl *method) {
1924e5dd7070Spatrick if (!method) return false;
1925e5dd7070Spatrick
1926e5dd7070Spatrick receiver = receiver->IgnoreParenLValueCasts();
1927e5dd7070Spatrick if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))
1928e5dd7070Spatrick if (DRE->getDecl() == method->getSelfDecl())
1929e5dd7070Spatrick return true;
1930e5dd7070Spatrick return false;
1931e5dd7070Spatrick }
1932e5dd7070Spatrick
1933e5dd7070Spatrick /// LookupMethodInType - Look up a method in an ObjCObjectType.
LookupMethodInObjectType(Selector sel,QualType type,bool isInstance)1934e5dd7070Spatrick ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
1935e5dd7070Spatrick bool isInstance) {
1936e5dd7070Spatrick const ObjCObjectType *objType = type->castAs<ObjCObjectType>();
1937e5dd7070Spatrick if (ObjCInterfaceDecl *iface = objType->getInterface()) {
1938e5dd7070Spatrick // Look it up in the main interface (and categories, etc.)
1939e5dd7070Spatrick if (ObjCMethodDecl *method = iface->lookupMethod(sel, isInstance))
1940e5dd7070Spatrick return method;
1941e5dd7070Spatrick
1942e5dd7070Spatrick // Okay, look for "private" methods declared in any
1943e5dd7070Spatrick // @implementations we've seen.
1944e5dd7070Spatrick if (ObjCMethodDecl *method = iface->lookupPrivateMethod(sel, isInstance))
1945e5dd7070Spatrick return method;
1946e5dd7070Spatrick }
1947e5dd7070Spatrick
1948e5dd7070Spatrick // Check qualifiers.
1949e5dd7070Spatrick for (const auto *I : objType->quals())
1950e5dd7070Spatrick if (ObjCMethodDecl *method = I->lookupMethod(sel, isInstance))
1951e5dd7070Spatrick return method;
1952e5dd7070Spatrick
1953e5dd7070Spatrick return nullptr;
1954e5dd7070Spatrick }
1955e5dd7070Spatrick
1956e5dd7070Spatrick /// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier
1957e5dd7070Spatrick /// list of a qualified objective pointer type.
LookupMethodInQualifiedType(Selector Sel,const ObjCObjectPointerType * OPT,bool Instance)1958e5dd7070Spatrick ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
1959e5dd7070Spatrick const ObjCObjectPointerType *OPT,
1960e5dd7070Spatrick bool Instance)
1961e5dd7070Spatrick {
1962e5dd7070Spatrick ObjCMethodDecl *MD = nullptr;
1963e5dd7070Spatrick for (const auto *PROTO : OPT->quals()) {
1964e5dd7070Spatrick if ((MD = PROTO->lookupMethod(Sel, Instance))) {
1965e5dd7070Spatrick return MD;
1966e5dd7070Spatrick }
1967e5dd7070Spatrick }
1968e5dd7070Spatrick return nullptr;
1969e5dd7070Spatrick }
1970e5dd7070Spatrick
1971e5dd7070Spatrick /// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
1972e5dd7070Spatrick /// objective C interface. This is a property reference expression.
1973e5dd7070Spatrick ExprResult Sema::
HandleExprPropertyRefExpr(const ObjCObjectPointerType * OPT,Expr * BaseExpr,SourceLocation OpLoc,DeclarationName MemberName,SourceLocation MemberLoc,SourceLocation SuperLoc,QualType SuperType,bool Super)1974e5dd7070Spatrick HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
1975e5dd7070Spatrick Expr *BaseExpr, SourceLocation OpLoc,
1976e5dd7070Spatrick DeclarationName MemberName,
1977e5dd7070Spatrick SourceLocation MemberLoc,
1978e5dd7070Spatrick SourceLocation SuperLoc, QualType SuperType,
1979e5dd7070Spatrick bool Super) {
1980e5dd7070Spatrick const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
1981e5dd7070Spatrick ObjCInterfaceDecl *IFace = IFaceT->getDecl();
1982e5dd7070Spatrick
1983e5dd7070Spatrick if (!MemberName.isIdentifier()) {
1984e5dd7070Spatrick Diag(MemberLoc, diag::err_invalid_property_name)
1985e5dd7070Spatrick << MemberName << QualType(OPT, 0);
1986e5dd7070Spatrick return ExprError();
1987e5dd7070Spatrick }
1988e5dd7070Spatrick
1989e5dd7070Spatrick IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
1990e5dd7070Spatrick
1991e5dd7070Spatrick SourceRange BaseRange = Super? SourceRange(SuperLoc)
1992e5dd7070Spatrick : BaseExpr->getSourceRange();
1993e5dd7070Spatrick if (RequireCompleteType(MemberLoc, OPT->getPointeeType(),
1994e5dd7070Spatrick diag::err_property_not_found_forward_class,
1995e5dd7070Spatrick MemberName, BaseRange))
1996e5dd7070Spatrick return ExprError();
1997e5dd7070Spatrick
1998e5dd7070Spatrick if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(
1999e5dd7070Spatrick Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
2000e5dd7070Spatrick // Check whether we can reference this property.
2001e5dd7070Spatrick if (DiagnoseUseOfDecl(PD, MemberLoc))
2002e5dd7070Spatrick return ExprError();
2003e5dd7070Spatrick if (Super)
2004e5dd7070Spatrick return new (Context)
2005e5dd7070Spatrick ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
2006e5dd7070Spatrick OK_ObjCProperty, MemberLoc, SuperLoc, SuperType);
2007e5dd7070Spatrick else
2008e5dd7070Spatrick return new (Context)
2009e5dd7070Spatrick ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
2010e5dd7070Spatrick OK_ObjCProperty, MemberLoc, BaseExpr);
2011e5dd7070Spatrick }
2012e5dd7070Spatrick // Check protocols on qualified interfaces.
2013e5dd7070Spatrick for (const auto *I : OPT->quals())
2014e5dd7070Spatrick if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(
2015e5dd7070Spatrick Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
2016e5dd7070Spatrick // Check whether we can reference this property.
2017e5dd7070Spatrick if (DiagnoseUseOfDecl(PD, MemberLoc))
2018e5dd7070Spatrick return ExprError();
2019e5dd7070Spatrick
2020e5dd7070Spatrick if (Super)
2021e5dd7070Spatrick return new (Context) ObjCPropertyRefExpr(
2022e5dd7070Spatrick PD, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, MemberLoc,
2023e5dd7070Spatrick SuperLoc, SuperType);
2024e5dd7070Spatrick else
2025e5dd7070Spatrick return new (Context)
2026e5dd7070Spatrick ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
2027e5dd7070Spatrick OK_ObjCProperty, MemberLoc, BaseExpr);
2028e5dd7070Spatrick }
2029e5dd7070Spatrick // If that failed, look for an "implicit" property by seeing if the nullary
2030e5dd7070Spatrick // selector is implemented.
2031e5dd7070Spatrick
2032e5dd7070Spatrick // FIXME: The logic for looking up nullary and unary selectors should be
2033e5dd7070Spatrick // shared with the code in ActOnInstanceMessage.
2034e5dd7070Spatrick
2035e5dd7070Spatrick Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
2036e5dd7070Spatrick ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
2037e5dd7070Spatrick
2038e5dd7070Spatrick // May be found in property's qualified list.
2039e5dd7070Spatrick if (!Getter)
2040e5dd7070Spatrick Getter = LookupMethodInQualifiedType(Sel, OPT, true);
2041e5dd7070Spatrick
2042e5dd7070Spatrick // If this reference is in an @implementation, check for 'private' methods.
2043e5dd7070Spatrick if (!Getter)
2044e5dd7070Spatrick Getter = IFace->lookupPrivateMethod(Sel);
2045e5dd7070Spatrick
2046e5dd7070Spatrick if (Getter) {
2047e5dd7070Spatrick // Check if we can reference this property.
2048e5dd7070Spatrick if (DiagnoseUseOfDecl(Getter, MemberLoc))
2049e5dd7070Spatrick return ExprError();
2050e5dd7070Spatrick }
2051e5dd7070Spatrick // If we found a getter then this may be a valid dot-reference, we
2052e5dd7070Spatrick // will look for the matching setter, in case it is needed.
2053e5dd7070Spatrick Selector SetterSel =
2054e5dd7070Spatrick SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
2055e5dd7070Spatrick PP.getSelectorTable(), Member);
2056e5dd7070Spatrick ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
2057e5dd7070Spatrick
2058e5dd7070Spatrick // May be found in property's qualified list.
2059e5dd7070Spatrick if (!Setter)
2060e5dd7070Spatrick Setter = LookupMethodInQualifiedType(SetterSel, OPT, true);
2061e5dd7070Spatrick
2062e5dd7070Spatrick if (!Setter) {
2063e5dd7070Spatrick // If this reference is in an @implementation, also check for 'private'
2064e5dd7070Spatrick // methods.
2065e5dd7070Spatrick Setter = IFace->lookupPrivateMethod(SetterSel);
2066e5dd7070Spatrick }
2067e5dd7070Spatrick
2068e5dd7070Spatrick if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
2069e5dd7070Spatrick return ExprError();
2070e5dd7070Spatrick
2071e5dd7070Spatrick // Special warning if member name used in a property-dot for a setter accessor
2072e5dd7070Spatrick // does not use a property with same name; e.g. obj.X = ... for a property with
2073e5dd7070Spatrick // name 'x'.
2074e5dd7070Spatrick if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() &&
2075e5dd7070Spatrick !IFace->FindPropertyDeclaration(
2076e5dd7070Spatrick Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
2077e5dd7070Spatrick if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) {
2078e5dd7070Spatrick // Do not warn if user is using property-dot syntax to make call to
2079e5dd7070Spatrick // user named setter.
2080ec727ea7Spatrick if (!(PDecl->getPropertyAttributes() &
2081ec727ea7Spatrick ObjCPropertyAttribute::kind_setter))
2082e5dd7070Spatrick Diag(MemberLoc,
2083e5dd7070Spatrick diag::warn_property_access_suggest)
2084e5dd7070Spatrick << MemberName << QualType(OPT, 0) << PDecl->getName()
2085e5dd7070Spatrick << FixItHint::CreateReplacement(MemberLoc, PDecl->getName());
2086e5dd7070Spatrick }
2087e5dd7070Spatrick }
2088e5dd7070Spatrick
2089e5dd7070Spatrick if (Getter || Setter) {
2090e5dd7070Spatrick if (Super)
2091e5dd7070Spatrick return new (Context)
2092e5dd7070Spatrick ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
2093e5dd7070Spatrick OK_ObjCProperty, MemberLoc, SuperLoc, SuperType);
2094e5dd7070Spatrick else
2095e5dd7070Spatrick return new (Context)
2096e5dd7070Spatrick ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
2097e5dd7070Spatrick OK_ObjCProperty, MemberLoc, BaseExpr);
2098e5dd7070Spatrick
2099e5dd7070Spatrick }
2100e5dd7070Spatrick
2101e5dd7070Spatrick // Attempt to correct for typos in property names.
2102e5dd7070Spatrick DeclFilterCCC<ObjCPropertyDecl> CCC{};
2103e5dd7070Spatrick if (TypoCorrection Corrected = CorrectTypo(
2104e5dd7070Spatrick DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName,
2105e5dd7070Spatrick nullptr, nullptr, CCC, CTK_ErrorRecovery, IFace, false, OPT)) {
2106e5dd7070Spatrick DeclarationName TypoResult = Corrected.getCorrection();
2107e5dd7070Spatrick if (TypoResult.isIdentifier() &&
2108e5dd7070Spatrick TypoResult.getAsIdentifierInfo() == Member) {
2109e5dd7070Spatrick // There is no need to try the correction if it is the same.
2110e5dd7070Spatrick NamedDecl *ChosenDecl =
2111e5dd7070Spatrick Corrected.isKeyword() ? nullptr : Corrected.getFoundDecl();
2112e5dd7070Spatrick if (ChosenDecl && isa<ObjCPropertyDecl>(ChosenDecl))
2113e5dd7070Spatrick if (cast<ObjCPropertyDecl>(ChosenDecl)->isClassProperty()) {
2114e5dd7070Spatrick // This is a class property, we should not use the instance to
2115e5dd7070Spatrick // access it.
2116e5dd7070Spatrick Diag(MemberLoc, diag::err_class_property_found) << MemberName
2117e5dd7070Spatrick << OPT->getInterfaceDecl()->getName()
2118e5dd7070Spatrick << FixItHint::CreateReplacement(BaseExpr->getSourceRange(),
2119e5dd7070Spatrick OPT->getInterfaceDecl()->getName());
2120e5dd7070Spatrick return ExprError();
2121e5dd7070Spatrick }
2122e5dd7070Spatrick } else {
2123e5dd7070Spatrick diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
2124e5dd7070Spatrick << MemberName << QualType(OPT, 0));
2125e5dd7070Spatrick return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
2126e5dd7070Spatrick TypoResult, MemberLoc,
2127e5dd7070Spatrick SuperLoc, SuperType, Super);
2128e5dd7070Spatrick }
2129e5dd7070Spatrick }
2130e5dd7070Spatrick ObjCInterfaceDecl *ClassDeclared;
2131e5dd7070Spatrick if (ObjCIvarDecl *Ivar =
2132e5dd7070Spatrick IFace->lookupInstanceVariable(Member, ClassDeclared)) {
2133e5dd7070Spatrick QualType T = Ivar->getType();
2134e5dd7070Spatrick if (const ObjCObjectPointerType * OBJPT =
2135e5dd7070Spatrick T->getAsObjCInterfacePointerType()) {
2136e5dd7070Spatrick if (RequireCompleteType(MemberLoc, OBJPT->getPointeeType(),
2137e5dd7070Spatrick diag::err_property_not_as_forward_class,
2138e5dd7070Spatrick MemberName, BaseExpr))
2139e5dd7070Spatrick return ExprError();
2140e5dd7070Spatrick }
2141e5dd7070Spatrick Diag(MemberLoc,
2142e5dd7070Spatrick diag::err_ivar_access_using_property_syntax_suggest)
2143e5dd7070Spatrick << MemberName << QualType(OPT, 0) << Ivar->getDeclName()
2144e5dd7070Spatrick << FixItHint::CreateReplacement(OpLoc, "->");
2145e5dd7070Spatrick return ExprError();
2146e5dd7070Spatrick }
2147e5dd7070Spatrick
2148e5dd7070Spatrick Diag(MemberLoc, diag::err_property_not_found)
2149e5dd7070Spatrick << MemberName << QualType(OPT, 0);
2150e5dd7070Spatrick if (Setter)
2151e5dd7070Spatrick Diag(Setter->getLocation(), diag::note_getter_unavailable)
2152e5dd7070Spatrick << MemberName << BaseExpr->getSourceRange();
2153e5dd7070Spatrick return ExprError();
2154e5dd7070Spatrick }
2155e5dd7070Spatrick
2156e5dd7070Spatrick ExprResult Sema::
ActOnClassPropertyRefExpr(IdentifierInfo & receiverName,IdentifierInfo & propertyName,SourceLocation receiverNameLoc,SourceLocation propertyNameLoc)2157e5dd7070Spatrick ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
2158e5dd7070Spatrick IdentifierInfo &propertyName,
2159e5dd7070Spatrick SourceLocation receiverNameLoc,
2160e5dd7070Spatrick SourceLocation propertyNameLoc) {
2161e5dd7070Spatrick
2162e5dd7070Spatrick IdentifierInfo *receiverNamePtr = &receiverName;
2163e5dd7070Spatrick ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
2164e5dd7070Spatrick receiverNameLoc);
2165e5dd7070Spatrick
2166e5dd7070Spatrick QualType SuperType;
2167e5dd7070Spatrick if (!IFace) {
2168e5dd7070Spatrick // If the "receiver" is 'super' in a method, handle it as an expression-like
2169e5dd7070Spatrick // property reference.
2170e5dd7070Spatrick if (receiverNamePtr->isStr("super")) {
2171e5dd7070Spatrick if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
2172e5dd7070Spatrick if (auto classDecl = CurMethod->getClassInterface()) {
2173e5dd7070Spatrick SuperType = QualType(classDecl->getSuperClassType(), 0);
2174e5dd7070Spatrick if (CurMethod->isInstanceMethod()) {
2175e5dd7070Spatrick if (SuperType.isNull()) {
2176e5dd7070Spatrick // The current class does not have a superclass.
2177e5dd7070Spatrick Diag(receiverNameLoc, diag::err_root_class_cannot_use_super)
2178e5dd7070Spatrick << CurMethod->getClassInterface()->getIdentifier();
2179e5dd7070Spatrick return ExprError();
2180e5dd7070Spatrick }
2181e5dd7070Spatrick QualType T = Context.getObjCObjectPointerType(SuperType);
2182e5dd7070Spatrick
2183e5dd7070Spatrick return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(),
2184e5dd7070Spatrick /*BaseExpr*/nullptr,
2185e5dd7070Spatrick SourceLocation()/*OpLoc*/,
2186e5dd7070Spatrick &propertyName,
2187e5dd7070Spatrick propertyNameLoc,
2188e5dd7070Spatrick receiverNameLoc, T, true);
2189e5dd7070Spatrick }
2190e5dd7070Spatrick
2191e5dd7070Spatrick // Otherwise, if this is a class method, try dispatching to our
2192e5dd7070Spatrick // superclass.
2193e5dd7070Spatrick IFace = CurMethod->getClassInterface()->getSuperClass();
2194e5dd7070Spatrick }
2195e5dd7070Spatrick }
2196e5dd7070Spatrick }
2197e5dd7070Spatrick
2198e5dd7070Spatrick if (!IFace) {
2199e5dd7070Spatrick Diag(receiverNameLoc, diag::err_expected_either) << tok::identifier
2200e5dd7070Spatrick << tok::l_paren;
2201e5dd7070Spatrick return ExprError();
2202e5dd7070Spatrick }
2203e5dd7070Spatrick }
2204e5dd7070Spatrick
2205e5dd7070Spatrick Selector GetterSel;
2206e5dd7070Spatrick Selector SetterSel;
2207e5dd7070Spatrick if (auto PD = IFace->FindPropertyDeclaration(
2208e5dd7070Spatrick &propertyName, ObjCPropertyQueryKind::OBJC_PR_query_class)) {
2209e5dd7070Spatrick GetterSel = PD->getGetterName();
2210e5dd7070Spatrick SetterSel = PD->getSetterName();
2211e5dd7070Spatrick } else {
2212e5dd7070Spatrick GetterSel = PP.getSelectorTable().getNullarySelector(&propertyName);
2213e5dd7070Spatrick SetterSel = SelectorTable::constructSetterSelector(
2214e5dd7070Spatrick PP.getIdentifierTable(), PP.getSelectorTable(), &propertyName);
2215e5dd7070Spatrick }
2216e5dd7070Spatrick
2217e5dd7070Spatrick // Search for a declared property first.
2218e5dd7070Spatrick ObjCMethodDecl *Getter = IFace->lookupClassMethod(GetterSel);
2219e5dd7070Spatrick
2220e5dd7070Spatrick // If this reference is in an @implementation, check for 'private' methods.
2221e5dd7070Spatrick if (!Getter)
2222e5dd7070Spatrick Getter = IFace->lookupPrivateClassMethod(GetterSel);
2223e5dd7070Spatrick
2224e5dd7070Spatrick if (Getter) {
2225e5dd7070Spatrick // FIXME: refactor/share with ActOnMemberReference().
2226e5dd7070Spatrick // Check if we can reference this property.
2227e5dd7070Spatrick if (DiagnoseUseOfDecl(Getter, propertyNameLoc))
2228e5dd7070Spatrick return ExprError();
2229e5dd7070Spatrick }
2230e5dd7070Spatrick
2231e5dd7070Spatrick // Look for the matching setter, in case it is needed.
2232e5dd7070Spatrick ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
2233e5dd7070Spatrick if (!Setter) {
2234e5dd7070Spatrick // If this reference is in an @implementation, also check for 'private'
2235e5dd7070Spatrick // methods.
2236e5dd7070Spatrick Setter = IFace->lookupPrivateClassMethod(SetterSel);
2237e5dd7070Spatrick }
2238e5dd7070Spatrick // Look through local category implementations associated with the class.
2239e5dd7070Spatrick if (!Setter)
2240e5dd7070Spatrick Setter = IFace->getCategoryClassMethod(SetterSel);
2241e5dd7070Spatrick
2242e5dd7070Spatrick if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc))
2243e5dd7070Spatrick return ExprError();
2244e5dd7070Spatrick
2245e5dd7070Spatrick if (Getter || Setter) {
2246e5dd7070Spatrick if (!SuperType.isNull())
2247e5dd7070Spatrick return new (Context)
2248e5dd7070Spatrick ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
2249e5dd7070Spatrick OK_ObjCProperty, propertyNameLoc, receiverNameLoc,
2250e5dd7070Spatrick SuperType);
2251e5dd7070Spatrick
2252e5dd7070Spatrick return new (Context) ObjCPropertyRefExpr(
2253e5dd7070Spatrick Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty,
2254e5dd7070Spatrick propertyNameLoc, receiverNameLoc, IFace);
2255e5dd7070Spatrick }
2256e5dd7070Spatrick return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
2257e5dd7070Spatrick << &propertyName << Context.getObjCInterfaceType(IFace));
2258e5dd7070Spatrick }
2259e5dd7070Spatrick
2260e5dd7070Spatrick namespace {
2261e5dd7070Spatrick
2262e5dd7070Spatrick class ObjCInterfaceOrSuperCCC final : public CorrectionCandidateCallback {
2263e5dd7070Spatrick public:
ObjCInterfaceOrSuperCCC(ObjCMethodDecl * Method)2264e5dd7070Spatrick ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) {
2265e5dd7070Spatrick // Determine whether "super" is acceptable in the current context.
2266e5dd7070Spatrick if (Method && Method->getClassInterface())
2267e5dd7070Spatrick WantObjCSuper = Method->getClassInterface()->getSuperClass();
2268e5dd7070Spatrick }
2269e5dd7070Spatrick
ValidateCandidate(const TypoCorrection & candidate)2270e5dd7070Spatrick bool ValidateCandidate(const TypoCorrection &candidate) override {
2271e5dd7070Spatrick return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() ||
2272e5dd7070Spatrick candidate.isKeyword("super");
2273e5dd7070Spatrick }
2274e5dd7070Spatrick
clone()2275e5dd7070Spatrick std::unique_ptr<CorrectionCandidateCallback> clone() override {
2276e5dd7070Spatrick return std::make_unique<ObjCInterfaceOrSuperCCC>(*this);
2277e5dd7070Spatrick }
2278e5dd7070Spatrick };
2279e5dd7070Spatrick
2280e5dd7070Spatrick } // end anonymous namespace
2281e5dd7070Spatrick
getObjCMessageKind(Scope * S,IdentifierInfo * Name,SourceLocation NameLoc,bool IsSuper,bool HasTrailingDot,ParsedType & ReceiverType)2282e5dd7070Spatrick Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
2283e5dd7070Spatrick IdentifierInfo *Name,
2284e5dd7070Spatrick SourceLocation NameLoc,
2285e5dd7070Spatrick bool IsSuper,
2286e5dd7070Spatrick bool HasTrailingDot,
2287e5dd7070Spatrick ParsedType &ReceiverType) {
2288e5dd7070Spatrick ReceiverType = nullptr;
2289e5dd7070Spatrick
2290e5dd7070Spatrick // If the identifier is "super" and there is no trailing dot, we're
2291e5dd7070Spatrick // messaging super. If the identifier is "super" and there is a
2292e5dd7070Spatrick // trailing dot, it's an instance message.
2293e5dd7070Spatrick if (IsSuper && S->isInObjcMethodScope())
2294e5dd7070Spatrick return HasTrailingDot? ObjCInstanceMessage : ObjCSuperMessage;
2295e5dd7070Spatrick
2296e5dd7070Spatrick LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
2297e5dd7070Spatrick LookupName(Result, S);
2298e5dd7070Spatrick
2299e5dd7070Spatrick switch (Result.getResultKind()) {
2300e5dd7070Spatrick case LookupResult::NotFound:
2301e5dd7070Spatrick // Normal name lookup didn't find anything. If we're in an
2302e5dd7070Spatrick // Objective-C method, look for ivars. If we find one, we're done!
2303e5dd7070Spatrick // FIXME: This is a hack. Ivar lookup should be part of normal
2304e5dd7070Spatrick // lookup.
2305e5dd7070Spatrick if (ObjCMethodDecl *Method = getCurMethodDecl()) {
2306e5dd7070Spatrick if (!Method->getClassInterface()) {
2307e5dd7070Spatrick // Fall back: let the parser try to parse it as an instance message.
2308e5dd7070Spatrick return ObjCInstanceMessage;
2309e5dd7070Spatrick }
2310e5dd7070Spatrick
2311e5dd7070Spatrick ObjCInterfaceDecl *ClassDeclared;
2312e5dd7070Spatrick if (Method->getClassInterface()->lookupInstanceVariable(Name,
2313e5dd7070Spatrick ClassDeclared))
2314e5dd7070Spatrick return ObjCInstanceMessage;
2315e5dd7070Spatrick }
2316e5dd7070Spatrick
2317e5dd7070Spatrick // Break out; we'll perform typo correction below.
2318e5dd7070Spatrick break;
2319e5dd7070Spatrick
2320e5dd7070Spatrick case LookupResult::NotFoundInCurrentInstantiation:
2321e5dd7070Spatrick case LookupResult::FoundOverloaded:
2322e5dd7070Spatrick case LookupResult::FoundUnresolvedValue:
2323e5dd7070Spatrick case LookupResult::Ambiguous:
2324e5dd7070Spatrick Result.suppressDiagnostics();
2325e5dd7070Spatrick return ObjCInstanceMessage;
2326e5dd7070Spatrick
2327e5dd7070Spatrick case LookupResult::Found: {
2328e5dd7070Spatrick // If the identifier is a class or not, and there is a trailing dot,
2329e5dd7070Spatrick // it's an instance message.
2330e5dd7070Spatrick if (HasTrailingDot)
2331e5dd7070Spatrick return ObjCInstanceMessage;
2332e5dd7070Spatrick // We found something. If it's a type, then we have a class
2333e5dd7070Spatrick // message. Otherwise, it's an instance message.
2334e5dd7070Spatrick NamedDecl *ND = Result.getFoundDecl();
2335e5dd7070Spatrick QualType T;
2336e5dd7070Spatrick if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND))
2337e5dd7070Spatrick T = Context.getObjCInterfaceType(Class);
2338e5dd7070Spatrick else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) {
2339e5dd7070Spatrick T = Context.getTypeDeclType(Type);
2340e5dd7070Spatrick DiagnoseUseOfDecl(Type, NameLoc);
2341e5dd7070Spatrick }
2342e5dd7070Spatrick else
2343e5dd7070Spatrick return ObjCInstanceMessage;
2344e5dd7070Spatrick
2345e5dd7070Spatrick // We have a class message, and T is the type we're
2346e5dd7070Spatrick // messaging. Build source-location information for it.
2347e5dd7070Spatrick TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
2348e5dd7070Spatrick ReceiverType = CreateParsedType(T, TSInfo);
2349e5dd7070Spatrick return ObjCClassMessage;
2350e5dd7070Spatrick }
2351e5dd7070Spatrick }
2352e5dd7070Spatrick
2353e5dd7070Spatrick ObjCInterfaceOrSuperCCC CCC(getCurMethodDecl());
2354e5dd7070Spatrick if (TypoCorrection Corrected = CorrectTypo(
2355e5dd7070Spatrick Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, CCC,
2356e5dd7070Spatrick CTK_ErrorRecovery, nullptr, false, nullptr, false)) {
2357e5dd7070Spatrick if (Corrected.isKeyword()) {
2358e5dd7070Spatrick // If we've found the keyword "super" (the only keyword that would be
2359e5dd7070Spatrick // returned by CorrectTypo), this is a send to super.
2360e5dd7070Spatrick diagnoseTypo(Corrected,
2361e5dd7070Spatrick PDiag(diag::err_unknown_receiver_suggest) << Name);
2362e5dd7070Spatrick return ObjCSuperMessage;
2363e5dd7070Spatrick } else if (ObjCInterfaceDecl *Class =
2364e5dd7070Spatrick Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
2365e5dd7070Spatrick // If we found a declaration, correct when it refers to an Objective-C
2366e5dd7070Spatrick // class.
2367e5dd7070Spatrick diagnoseTypo(Corrected,
2368e5dd7070Spatrick PDiag(diag::err_unknown_receiver_suggest) << Name);
2369e5dd7070Spatrick QualType T = Context.getObjCInterfaceType(Class);
2370e5dd7070Spatrick TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
2371e5dd7070Spatrick ReceiverType = CreateParsedType(T, TSInfo);
2372e5dd7070Spatrick return ObjCClassMessage;
2373e5dd7070Spatrick }
2374e5dd7070Spatrick }
2375e5dd7070Spatrick
2376e5dd7070Spatrick // Fall back: let the parser try to parse it as an instance message.
2377e5dd7070Spatrick return ObjCInstanceMessage;
2378e5dd7070Spatrick }
2379e5dd7070Spatrick
ActOnSuperMessage(Scope * S,SourceLocation SuperLoc,Selector Sel,SourceLocation LBracLoc,ArrayRef<SourceLocation> SelectorLocs,SourceLocation RBracLoc,MultiExprArg Args)2380e5dd7070Spatrick ExprResult Sema::ActOnSuperMessage(Scope *S,
2381e5dd7070Spatrick SourceLocation SuperLoc,
2382e5dd7070Spatrick Selector Sel,
2383e5dd7070Spatrick SourceLocation LBracLoc,
2384e5dd7070Spatrick ArrayRef<SourceLocation> SelectorLocs,
2385e5dd7070Spatrick SourceLocation RBracLoc,
2386e5dd7070Spatrick MultiExprArg Args) {
2387e5dd7070Spatrick // Determine whether we are inside a method or not.
2388e5dd7070Spatrick ObjCMethodDecl *Method = tryCaptureObjCSelf(SuperLoc);
2389e5dd7070Spatrick if (!Method) {
2390e5dd7070Spatrick Diag(SuperLoc, diag::err_invalid_receiver_to_message_super);
2391e5dd7070Spatrick return ExprError();
2392e5dd7070Spatrick }
2393e5dd7070Spatrick
2394e5dd7070Spatrick ObjCInterfaceDecl *Class = Method->getClassInterface();
2395e5dd7070Spatrick if (!Class) {
2396e5dd7070Spatrick Diag(SuperLoc, diag::err_no_super_class_message)
2397e5dd7070Spatrick << Method->getDeclName();
2398e5dd7070Spatrick return ExprError();
2399e5dd7070Spatrick }
2400e5dd7070Spatrick
2401e5dd7070Spatrick QualType SuperTy(Class->getSuperClassType(), 0);
2402e5dd7070Spatrick if (SuperTy.isNull()) {
2403e5dd7070Spatrick // The current class does not have a superclass.
2404e5dd7070Spatrick Diag(SuperLoc, diag::err_root_class_cannot_use_super)
2405e5dd7070Spatrick << Class->getIdentifier();
2406e5dd7070Spatrick return ExprError();
2407e5dd7070Spatrick }
2408e5dd7070Spatrick
2409e5dd7070Spatrick // We are in a method whose class has a superclass, so 'super'
2410e5dd7070Spatrick // is acting as a keyword.
2411e5dd7070Spatrick if (Method->getSelector() == Sel)
2412e5dd7070Spatrick getCurFunction()->ObjCShouldCallSuper = false;
2413e5dd7070Spatrick
2414e5dd7070Spatrick if (Method->isInstanceMethod()) {
2415e5dd7070Spatrick // Since we are in an instance method, this is an instance
2416e5dd7070Spatrick // message to the superclass instance.
2417e5dd7070Spatrick SuperTy = Context.getObjCObjectPointerType(SuperTy);
2418e5dd7070Spatrick return BuildInstanceMessage(nullptr, SuperTy, SuperLoc,
2419e5dd7070Spatrick Sel, /*Method=*/nullptr,
2420e5dd7070Spatrick LBracLoc, SelectorLocs, RBracLoc, Args);
2421e5dd7070Spatrick }
2422e5dd7070Spatrick
2423e5dd7070Spatrick // Since we are in a class method, this is a class message to
2424e5dd7070Spatrick // the superclass.
2425e5dd7070Spatrick return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr,
2426e5dd7070Spatrick SuperTy,
2427e5dd7070Spatrick SuperLoc, Sel, /*Method=*/nullptr,
2428e5dd7070Spatrick LBracLoc, SelectorLocs, RBracLoc, Args);
2429e5dd7070Spatrick }
2430e5dd7070Spatrick
BuildClassMessageImplicit(QualType ReceiverType,bool isSuperReceiver,SourceLocation Loc,Selector Sel,ObjCMethodDecl * Method,MultiExprArg Args)2431e5dd7070Spatrick ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType,
2432e5dd7070Spatrick bool isSuperReceiver,
2433e5dd7070Spatrick SourceLocation Loc,
2434e5dd7070Spatrick Selector Sel,
2435e5dd7070Spatrick ObjCMethodDecl *Method,
2436e5dd7070Spatrick MultiExprArg Args) {
2437e5dd7070Spatrick TypeSourceInfo *receiverTypeInfo = nullptr;
2438e5dd7070Spatrick if (!ReceiverType.isNull())
2439e5dd7070Spatrick receiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType);
2440e5dd7070Spatrick
2441e5dd7070Spatrick return BuildClassMessage(receiverTypeInfo, ReceiverType,
2442e5dd7070Spatrick /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(),
2443e5dd7070Spatrick Sel, Method, Loc, Loc, Loc, Args,
2444e5dd7070Spatrick /*isImplicit=*/true);
2445e5dd7070Spatrick }
2446e5dd7070Spatrick
applyCocoaAPICheck(Sema & S,const ObjCMessageExpr * Msg,unsigned DiagID,bool (* refactor)(const ObjCMessageExpr *,const NSAPI &,edit::Commit &))2447e5dd7070Spatrick static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg,
2448e5dd7070Spatrick unsigned DiagID,
2449e5dd7070Spatrick bool (*refactor)(const ObjCMessageExpr *,
2450e5dd7070Spatrick const NSAPI &, edit::Commit &)) {
2451e5dd7070Spatrick SourceLocation MsgLoc = Msg->getExprLoc();
2452e5dd7070Spatrick if (S.Diags.isIgnored(DiagID, MsgLoc))
2453e5dd7070Spatrick return;
2454e5dd7070Spatrick
2455e5dd7070Spatrick SourceManager &SM = S.SourceMgr;
2456e5dd7070Spatrick edit::Commit ECommit(SM, S.LangOpts);
2457e5dd7070Spatrick if (refactor(Msg,*S.NSAPIObj, ECommit)) {
2458a9ac8606Spatrick auto Builder = S.Diag(MsgLoc, DiagID)
2459e5dd7070Spatrick << Msg->getSelector() << Msg->getSourceRange();
2460e5dd7070Spatrick // FIXME: Don't emit diagnostic at all if fixits are non-commitable.
2461e5dd7070Spatrick if (!ECommit.isCommitable())
2462e5dd7070Spatrick return;
2463e5dd7070Spatrick for (edit::Commit::edit_iterator
2464e5dd7070Spatrick I = ECommit.edit_begin(), E = ECommit.edit_end(); I != E; ++I) {
2465e5dd7070Spatrick const edit::Commit::Edit &Edit = *I;
2466e5dd7070Spatrick switch (Edit.Kind) {
2467e5dd7070Spatrick case edit::Commit::Act_Insert:
2468e5dd7070Spatrick Builder.AddFixItHint(FixItHint::CreateInsertion(Edit.OrigLoc,
2469e5dd7070Spatrick Edit.Text,
2470e5dd7070Spatrick Edit.BeforePrev));
2471e5dd7070Spatrick break;
2472e5dd7070Spatrick case edit::Commit::Act_InsertFromRange:
2473e5dd7070Spatrick Builder.AddFixItHint(
2474e5dd7070Spatrick FixItHint::CreateInsertionFromRange(Edit.OrigLoc,
2475e5dd7070Spatrick Edit.getInsertFromRange(SM),
2476e5dd7070Spatrick Edit.BeforePrev));
2477e5dd7070Spatrick break;
2478e5dd7070Spatrick case edit::Commit::Act_Remove:
2479e5dd7070Spatrick Builder.AddFixItHint(FixItHint::CreateRemoval(Edit.getFileRange(SM)));
2480e5dd7070Spatrick break;
2481e5dd7070Spatrick }
2482e5dd7070Spatrick }
2483e5dd7070Spatrick }
2484e5dd7070Spatrick }
2485e5dd7070Spatrick
checkCocoaAPI(Sema & S,const ObjCMessageExpr * Msg)2486e5dd7070Spatrick static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) {
2487e5dd7070Spatrick applyCocoaAPICheck(S, Msg, diag::warn_objc_redundant_literal_use,
2488e5dd7070Spatrick edit::rewriteObjCRedundantCallWithLiteral);
2489e5dd7070Spatrick }
2490e5dd7070Spatrick
checkFoundationAPI(Sema & S,SourceLocation Loc,const ObjCMethodDecl * Method,ArrayRef<Expr * > Args,QualType ReceiverType,bool IsClassObjectCall)2491e5dd7070Spatrick static void checkFoundationAPI(Sema &S, SourceLocation Loc,
2492e5dd7070Spatrick const ObjCMethodDecl *Method,
2493e5dd7070Spatrick ArrayRef<Expr *> Args, QualType ReceiverType,
2494e5dd7070Spatrick bool IsClassObjectCall) {
2495e5dd7070Spatrick // Check if this is a performSelector method that uses a selector that returns
2496e5dd7070Spatrick // a record or a vector type.
2497e5dd7070Spatrick if (Method->getSelector().getMethodFamily() != OMF_performSelector ||
2498e5dd7070Spatrick Args.empty())
2499e5dd7070Spatrick return;
2500e5dd7070Spatrick const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens());
2501e5dd7070Spatrick if (!SE)
2502e5dd7070Spatrick return;
2503e5dd7070Spatrick ObjCMethodDecl *ImpliedMethod;
2504e5dd7070Spatrick if (!IsClassObjectCall) {
2505e5dd7070Spatrick const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>();
2506e5dd7070Spatrick if (!OPT || !OPT->getInterfaceDecl())
2507e5dd7070Spatrick return;
2508e5dd7070Spatrick ImpliedMethod =
2509e5dd7070Spatrick OPT->getInterfaceDecl()->lookupInstanceMethod(SE->getSelector());
2510e5dd7070Spatrick if (!ImpliedMethod)
2511e5dd7070Spatrick ImpliedMethod =
2512e5dd7070Spatrick OPT->getInterfaceDecl()->lookupPrivateMethod(SE->getSelector());
2513e5dd7070Spatrick } else {
2514e5dd7070Spatrick const auto *IT = ReceiverType->getAs<ObjCInterfaceType>();
2515e5dd7070Spatrick if (!IT)
2516e5dd7070Spatrick return;
2517e5dd7070Spatrick ImpliedMethod = IT->getDecl()->lookupClassMethod(SE->getSelector());
2518e5dd7070Spatrick if (!ImpliedMethod)
2519e5dd7070Spatrick ImpliedMethod =
2520e5dd7070Spatrick IT->getDecl()->lookupPrivateClassMethod(SE->getSelector());
2521e5dd7070Spatrick }
2522e5dd7070Spatrick if (!ImpliedMethod)
2523e5dd7070Spatrick return;
2524e5dd7070Spatrick QualType Ret = ImpliedMethod->getReturnType();
2525e5dd7070Spatrick if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) {
2526e5dd7070Spatrick S.Diag(Loc, diag::warn_objc_unsafe_perform_selector)
2527e5dd7070Spatrick << Method->getSelector()
2528e5dd7070Spatrick << (!Ret->isRecordType()
2529e5dd7070Spatrick ? /*Vector*/ 2
2530e5dd7070Spatrick : Ret->isUnionType() ? /*Union*/ 1 : /*Struct*/ 0);
2531e5dd7070Spatrick S.Diag(ImpliedMethod->getBeginLoc(),
2532e5dd7070Spatrick diag::note_objc_unsafe_perform_selector_method_declared_here)
2533e5dd7070Spatrick << ImpliedMethod->getSelector() << Ret;
2534e5dd7070Spatrick }
2535e5dd7070Spatrick }
2536e5dd7070Spatrick
2537e5dd7070Spatrick /// Diagnose use of %s directive in an NSString which is being passed
2538e5dd7070Spatrick /// as formatting string to formatting method.
2539e5dd7070Spatrick static void
DiagnoseCStringFormatDirectiveInObjCAPI(Sema & S,ObjCMethodDecl * Method,Selector Sel,Expr ** Args,unsigned NumArgs)2540e5dd7070Spatrick DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S,
2541e5dd7070Spatrick ObjCMethodDecl *Method,
2542e5dd7070Spatrick Selector Sel,
2543e5dd7070Spatrick Expr **Args, unsigned NumArgs) {
2544e5dd7070Spatrick unsigned Idx = 0;
2545e5dd7070Spatrick bool Format = false;
2546e5dd7070Spatrick ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily();
2547e5dd7070Spatrick if (SFFamily == ObjCStringFormatFamily::SFF_NSString) {
2548e5dd7070Spatrick Idx = 0;
2549e5dd7070Spatrick Format = true;
2550e5dd7070Spatrick }
2551e5dd7070Spatrick else if (Method) {
2552e5dd7070Spatrick for (const auto *I : Method->specific_attrs<FormatAttr>()) {
2553e5dd7070Spatrick if (S.GetFormatNSStringIdx(I, Idx)) {
2554e5dd7070Spatrick Format = true;
2555e5dd7070Spatrick break;
2556e5dd7070Spatrick }
2557e5dd7070Spatrick }
2558e5dd7070Spatrick }
2559e5dd7070Spatrick if (!Format || NumArgs <= Idx)
2560e5dd7070Spatrick return;
2561e5dd7070Spatrick
2562e5dd7070Spatrick Expr *FormatExpr = Args[Idx];
2563e5dd7070Spatrick if (ObjCStringLiteral *OSL =
2564e5dd7070Spatrick dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) {
2565e5dd7070Spatrick StringLiteral *FormatString = OSL->getString();
2566e5dd7070Spatrick if (S.FormatStringHasSArg(FormatString)) {
2567e5dd7070Spatrick S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
2568e5dd7070Spatrick << "%s" << 0 << 0;
2569e5dd7070Spatrick if (Method)
2570e5dd7070Spatrick S.Diag(Method->getLocation(), diag::note_method_declared_at)
2571e5dd7070Spatrick << Method->getDeclName();
2572e5dd7070Spatrick }
2573e5dd7070Spatrick }
2574e5dd7070Spatrick }
2575e5dd7070Spatrick
2576e5dd7070Spatrick /// Build an Objective-C class message expression.
2577e5dd7070Spatrick ///
2578e5dd7070Spatrick /// This routine takes care of both normal class messages and
2579e5dd7070Spatrick /// class messages to the superclass.
2580e5dd7070Spatrick ///
2581e5dd7070Spatrick /// \param ReceiverTypeInfo Type source information that describes the
2582e5dd7070Spatrick /// receiver of this message. This may be NULL, in which case we are
2583e5dd7070Spatrick /// sending to the superclass and \p SuperLoc must be a valid source
2584e5dd7070Spatrick /// location.
2585e5dd7070Spatrick
2586e5dd7070Spatrick /// \param ReceiverType The type of the object receiving the
2587e5dd7070Spatrick /// message. When \p ReceiverTypeInfo is non-NULL, this is the same
2588e5dd7070Spatrick /// type as that refers to. For a superclass send, this is the type of
2589e5dd7070Spatrick /// the superclass.
2590e5dd7070Spatrick ///
2591e5dd7070Spatrick /// \param SuperLoc The location of the "super" keyword in a
2592e5dd7070Spatrick /// superclass message.
2593e5dd7070Spatrick ///
2594e5dd7070Spatrick /// \param Sel The selector to which the message is being sent.
2595e5dd7070Spatrick ///
2596e5dd7070Spatrick /// \param Method The method that this class message is invoking, if
2597e5dd7070Spatrick /// already known.
2598e5dd7070Spatrick ///
2599e5dd7070Spatrick /// \param LBracLoc The location of the opening square bracket ']'.
2600e5dd7070Spatrick ///
2601e5dd7070Spatrick /// \param RBracLoc The location of the closing square bracket ']'.
2602e5dd7070Spatrick ///
2603e5dd7070Spatrick /// \param ArgsIn The message arguments.
BuildClassMessage(TypeSourceInfo * ReceiverTypeInfo,QualType ReceiverType,SourceLocation SuperLoc,Selector Sel,ObjCMethodDecl * Method,SourceLocation LBracLoc,ArrayRef<SourceLocation> SelectorLocs,SourceLocation RBracLoc,MultiExprArg ArgsIn,bool isImplicit)2604e5dd7070Spatrick ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
2605e5dd7070Spatrick QualType ReceiverType,
2606e5dd7070Spatrick SourceLocation SuperLoc,
2607e5dd7070Spatrick Selector Sel,
2608e5dd7070Spatrick ObjCMethodDecl *Method,
2609e5dd7070Spatrick SourceLocation LBracLoc,
2610e5dd7070Spatrick ArrayRef<SourceLocation> SelectorLocs,
2611e5dd7070Spatrick SourceLocation RBracLoc,
2612e5dd7070Spatrick MultiExprArg ArgsIn,
2613e5dd7070Spatrick bool isImplicit) {
2614e5dd7070Spatrick SourceLocation Loc = SuperLoc.isValid()? SuperLoc
2615e5dd7070Spatrick : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
2616e5dd7070Spatrick if (LBracLoc.isInvalid()) {
2617e5dd7070Spatrick Diag(Loc, diag::err_missing_open_square_message_send)
2618e5dd7070Spatrick << FixItHint::CreateInsertion(Loc, "[");
2619e5dd7070Spatrick LBracLoc = Loc;
2620e5dd7070Spatrick }
2621e5dd7070Spatrick ArrayRef<SourceLocation> SelectorSlotLocs;
2622e5dd7070Spatrick if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
2623e5dd7070Spatrick SelectorSlotLocs = SelectorLocs;
2624e5dd7070Spatrick else
2625e5dd7070Spatrick SelectorSlotLocs = Loc;
2626e5dd7070Spatrick SourceLocation SelLoc = SelectorSlotLocs.front();
2627e5dd7070Spatrick
2628e5dd7070Spatrick if (ReceiverType->isDependentType()) {
2629e5dd7070Spatrick // If the receiver type is dependent, we can't type-check anything
2630e5dd7070Spatrick // at this point. Build a dependent expression.
2631e5dd7070Spatrick unsigned NumArgs = ArgsIn.size();
2632e5dd7070Spatrick Expr **Args = ArgsIn.data();
2633e5dd7070Spatrick assert(SuperLoc.isInvalid() && "Message to super with dependent type");
2634*12c85518Srobert return ObjCMessageExpr::Create(Context, ReceiverType, VK_PRValue, LBracLoc,
2635*12c85518Srobert ReceiverTypeInfo, Sel, SelectorLocs,
2636*12c85518Srobert /*Method=*/nullptr, ArrayRef(Args, NumArgs),
2637*12c85518Srobert RBracLoc, isImplicit);
2638e5dd7070Spatrick }
2639e5dd7070Spatrick
2640e5dd7070Spatrick // Find the class to which we are sending this message.
2641e5dd7070Spatrick ObjCInterfaceDecl *Class = nullptr;
2642e5dd7070Spatrick const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>();
2643e5dd7070Spatrick if (!ClassType || !(Class = ClassType->getInterface())) {
2644e5dd7070Spatrick Diag(Loc, diag::err_invalid_receiver_class_message)
2645e5dd7070Spatrick << ReceiverType;
2646e5dd7070Spatrick return ExprError();
2647e5dd7070Spatrick }
2648e5dd7070Spatrick assert(Class && "We don't know which class we're messaging?");
2649e5dd7070Spatrick // objc++ diagnoses during typename annotation.
2650e5dd7070Spatrick if (!getLangOpts().CPlusPlus)
2651e5dd7070Spatrick (void)DiagnoseUseOfDecl(Class, SelectorSlotLocs);
2652e5dd7070Spatrick // Find the method we are messaging.
2653e5dd7070Spatrick if (!Method) {
2654e5dd7070Spatrick SourceRange TypeRange
2655e5dd7070Spatrick = SuperLoc.isValid()? SourceRange(SuperLoc)
2656e5dd7070Spatrick : ReceiverTypeInfo->getTypeLoc().getSourceRange();
2657e5dd7070Spatrick if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class),
2658e5dd7070Spatrick (getLangOpts().ObjCAutoRefCount
2659e5dd7070Spatrick ? diag::err_arc_receiver_forward_class
2660e5dd7070Spatrick : diag::warn_receiver_forward_class),
2661e5dd7070Spatrick TypeRange)) {
2662e5dd7070Spatrick // A forward class used in messaging is treated as a 'Class'
2663e5dd7070Spatrick Method = LookupFactoryMethodInGlobalPool(Sel,
2664e5dd7070Spatrick SourceRange(LBracLoc, RBracLoc));
2665e5dd7070Spatrick if (Method && !getLangOpts().ObjCAutoRefCount)
2666e5dd7070Spatrick Diag(Method->getLocation(), diag::note_method_sent_forward_class)
2667e5dd7070Spatrick << Method->getDeclName();
2668e5dd7070Spatrick }
2669e5dd7070Spatrick if (!Method)
2670e5dd7070Spatrick Method = Class->lookupClassMethod(Sel);
2671e5dd7070Spatrick
2672e5dd7070Spatrick // If we have an implementation in scope, check "private" methods.
2673e5dd7070Spatrick if (!Method)
2674e5dd7070Spatrick Method = Class->lookupPrivateClassMethod(Sel);
2675e5dd7070Spatrick
2676e5dd7070Spatrick if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs,
2677e5dd7070Spatrick nullptr, false, false, Class))
2678e5dd7070Spatrick return ExprError();
2679e5dd7070Spatrick }
2680e5dd7070Spatrick
2681e5dd7070Spatrick // Check the argument types and determine the result type.
2682e5dd7070Spatrick QualType ReturnType;
2683a9ac8606Spatrick ExprValueKind VK = VK_PRValue;
2684e5dd7070Spatrick
2685e5dd7070Spatrick unsigned NumArgs = ArgsIn.size();
2686e5dd7070Spatrick Expr **Args = ArgsIn.data();
2687e5dd7070Spatrick if (CheckMessageArgumentTypes(/*Receiver=*/nullptr, ReceiverType,
2688e5dd7070Spatrick MultiExprArg(Args, NumArgs), Sel, SelectorLocs,
2689e5dd7070Spatrick Method, true, SuperLoc.isValid(), LBracLoc,
2690e5dd7070Spatrick RBracLoc, SourceRange(), ReturnType, VK))
2691e5dd7070Spatrick return ExprError();
2692e5dd7070Spatrick
2693e5dd7070Spatrick if (Method && !Method->getReturnType()->isVoidType() &&
2694e5dd7070Spatrick RequireCompleteType(LBracLoc, Method->getReturnType(),
2695e5dd7070Spatrick diag::err_illegal_message_expr_incomplete_type))
2696e5dd7070Spatrick return ExprError();
2697e5dd7070Spatrick
2698ec727ea7Spatrick if (Method && Method->isDirectMethod() && SuperLoc.isValid()) {
2699ec727ea7Spatrick Diag(SuperLoc, diag::err_messaging_super_with_direct_method)
2700ec727ea7Spatrick << FixItHint::CreateReplacement(
2701ec727ea7Spatrick SuperLoc, getLangOpts().ObjCAutoRefCount
2702ec727ea7Spatrick ? "self"
2703ec727ea7Spatrick : Method->getClassInterface()->getName());
2704ec727ea7Spatrick Diag(Method->getLocation(), diag::note_direct_method_declared_at)
2705ec727ea7Spatrick << Method->getDeclName();
2706ec727ea7Spatrick }
2707ec727ea7Spatrick
2708e5dd7070Spatrick // Warn about explicit call of +initialize on its own class. But not on 'super'.
2709e5dd7070Spatrick if (Method && Method->getMethodFamily() == OMF_initialize) {
2710e5dd7070Spatrick if (!SuperLoc.isValid()) {
2711e5dd7070Spatrick const ObjCInterfaceDecl *ID =
2712e5dd7070Spatrick dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext());
2713e5dd7070Spatrick if (ID == Class) {
2714e5dd7070Spatrick Diag(Loc, diag::warn_direct_initialize_call);
2715e5dd7070Spatrick Diag(Method->getLocation(), diag::note_method_declared_at)
2716e5dd7070Spatrick << Method->getDeclName();
2717e5dd7070Spatrick }
2718e5dd7070Spatrick }
2719e5dd7070Spatrick else if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
2720e5dd7070Spatrick // [super initialize] is allowed only within an +initialize implementation
2721e5dd7070Spatrick if (CurMeth->getMethodFamily() != OMF_initialize) {
2722e5dd7070Spatrick Diag(Loc, diag::warn_direct_super_initialize_call);
2723e5dd7070Spatrick Diag(Method->getLocation(), diag::note_method_declared_at)
2724e5dd7070Spatrick << Method->getDeclName();
2725e5dd7070Spatrick Diag(CurMeth->getLocation(), diag::note_method_declared_at)
2726e5dd7070Spatrick << CurMeth->getDeclName();
2727e5dd7070Spatrick }
2728e5dd7070Spatrick }
2729e5dd7070Spatrick }
2730e5dd7070Spatrick
2731e5dd7070Spatrick DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
2732e5dd7070Spatrick
2733e5dd7070Spatrick // Construct the appropriate ObjCMessageExpr.
2734e5dd7070Spatrick ObjCMessageExpr *Result;
2735e5dd7070Spatrick if (SuperLoc.isValid())
2736*12c85518Srobert Result = ObjCMessageExpr::Create(
2737*12c85518Srobert Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false,
2738*12c85518Srobert ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
2739e5dd7070Spatrick RBracLoc, isImplicit);
2740e5dd7070Spatrick else {
2741*12c85518Srobert Result = ObjCMessageExpr::Create(
2742*12c85518Srobert Context, ReturnType, VK, LBracLoc, ReceiverTypeInfo, Sel, SelectorLocs,
2743*12c85518Srobert Method, ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
2744e5dd7070Spatrick if (!isImplicit)
2745e5dd7070Spatrick checkCocoaAPI(*this, Result);
2746e5dd7070Spatrick }
2747e5dd7070Spatrick if (Method)
2748*12c85518Srobert checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
2749e5dd7070Spatrick ReceiverType, /*IsClassObjectCall=*/true);
2750e5dd7070Spatrick return MaybeBindToTemporary(Result);
2751e5dd7070Spatrick }
2752e5dd7070Spatrick
2753e5dd7070Spatrick // ActOnClassMessage - used for both unary and keyword messages.
2754e5dd7070Spatrick // ArgExprs is optional - if it is present, the number of expressions
2755e5dd7070Spatrick // is obtained from Sel.getNumArgs().
ActOnClassMessage(Scope * S,ParsedType Receiver,Selector Sel,SourceLocation LBracLoc,ArrayRef<SourceLocation> SelectorLocs,SourceLocation RBracLoc,MultiExprArg Args)2756e5dd7070Spatrick ExprResult Sema::ActOnClassMessage(Scope *S,
2757e5dd7070Spatrick ParsedType Receiver,
2758e5dd7070Spatrick Selector Sel,
2759e5dd7070Spatrick SourceLocation LBracLoc,
2760e5dd7070Spatrick ArrayRef<SourceLocation> SelectorLocs,
2761e5dd7070Spatrick SourceLocation RBracLoc,
2762e5dd7070Spatrick MultiExprArg Args) {
2763e5dd7070Spatrick TypeSourceInfo *ReceiverTypeInfo;
2764e5dd7070Spatrick QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo);
2765e5dd7070Spatrick if (ReceiverType.isNull())
2766e5dd7070Spatrick return ExprError();
2767e5dd7070Spatrick
2768e5dd7070Spatrick if (!ReceiverTypeInfo)
2769e5dd7070Spatrick ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc);
2770e5dd7070Spatrick
2771e5dd7070Spatrick return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
2772e5dd7070Spatrick /*SuperLoc=*/SourceLocation(), Sel,
2773e5dd7070Spatrick /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc,
2774e5dd7070Spatrick Args);
2775e5dd7070Spatrick }
2776e5dd7070Spatrick
BuildInstanceMessageImplicit(Expr * Receiver,QualType ReceiverType,SourceLocation Loc,Selector Sel,ObjCMethodDecl * Method,MultiExprArg Args)2777e5dd7070Spatrick ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
2778e5dd7070Spatrick QualType ReceiverType,
2779e5dd7070Spatrick SourceLocation Loc,
2780e5dd7070Spatrick Selector Sel,
2781e5dd7070Spatrick ObjCMethodDecl *Method,
2782e5dd7070Spatrick MultiExprArg Args) {
2783e5dd7070Spatrick return BuildInstanceMessage(Receiver, ReceiverType,
2784e5dd7070Spatrick /*SuperLoc=*/!Receiver ? Loc : SourceLocation(),
2785e5dd7070Spatrick Sel, Method, Loc, Loc, Loc, Args,
2786e5dd7070Spatrick /*isImplicit=*/true);
2787e5dd7070Spatrick }
2788e5dd7070Spatrick
isMethodDeclaredInRootProtocol(Sema & S,const ObjCMethodDecl * M)2789e5dd7070Spatrick static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) {
2790e5dd7070Spatrick if (!S.NSAPIObj)
2791e5dd7070Spatrick return false;
2792e5dd7070Spatrick const auto *Protocol = dyn_cast<ObjCProtocolDecl>(M->getDeclContext());
2793e5dd7070Spatrick if (!Protocol)
2794e5dd7070Spatrick return false;
2795e5dd7070Spatrick const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject);
2796e5dd7070Spatrick if (const auto *RootClass = dyn_cast_or_null<ObjCInterfaceDecl>(
2797e5dd7070Spatrick S.LookupSingleName(S.TUScope, II, Protocol->getBeginLoc(),
2798e5dd7070Spatrick Sema::LookupOrdinaryName))) {
2799e5dd7070Spatrick for (const ObjCProtocolDecl *P : RootClass->all_referenced_protocols()) {
2800e5dd7070Spatrick if (P->getCanonicalDecl() == Protocol->getCanonicalDecl())
2801e5dd7070Spatrick return true;
2802e5dd7070Spatrick }
2803e5dd7070Spatrick }
2804e5dd7070Spatrick return false;
2805e5dd7070Spatrick }
2806e5dd7070Spatrick
2807e5dd7070Spatrick /// Build an Objective-C instance message expression.
2808e5dd7070Spatrick ///
2809e5dd7070Spatrick /// This routine takes care of both normal instance messages and
2810e5dd7070Spatrick /// instance messages to the superclass instance.
2811e5dd7070Spatrick ///
2812e5dd7070Spatrick /// \param Receiver The expression that computes the object that will
2813e5dd7070Spatrick /// receive this message. This may be empty, in which case we are
2814e5dd7070Spatrick /// sending to the superclass instance and \p SuperLoc must be a valid
2815e5dd7070Spatrick /// source location.
2816e5dd7070Spatrick ///
2817e5dd7070Spatrick /// \param ReceiverType The (static) type of the object receiving the
2818e5dd7070Spatrick /// message. When a \p Receiver expression is provided, this is the
2819e5dd7070Spatrick /// same type as that expression. For a superclass instance send, this
2820e5dd7070Spatrick /// is a pointer to the type of the superclass.
2821e5dd7070Spatrick ///
2822e5dd7070Spatrick /// \param SuperLoc The location of the "super" keyword in a
2823e5dd7070Spatrick /// superclass instance message.
2824e5dd7070Spatrick ///
2825e5dd7070Spatrick /// \param Sel The selector to which the message is being sent.
2826e5dd7070Spatrick ///
2827e5dd7070Spatrick /// \param Method The method that this instance message is invoking, if
2828e5dd7070Spatrick /// already known.
2829e5dd7070Spatrick ///
2830e5dd7070Spatrick /// \param LBracLoc The location of the opening square bracket ']'.
2831e5dd7070Spatrick ///
2832e5dd7070Spatrick /// \param RBracLoc The location of the closing square bracket ']'.
2833e5dd7070Spatrick ///
2834e5dd7070Spatrick /// \param ArgsIn The message arguments.
BuildInstanceMessage(Expr * Receiver,QualType ReceiverType,SourceLocation SuperLoc,Selector Sel,ObjCMethodDecl * Method,SourceLocation LBracLoc,ArrayRef<SourceLocation> SelectorLocs,SourceLocation RBracLoc,MultiExprArg ArgsIn,bool isImplicit)2835e5dd7070Spatrick ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
2836e5dd7070Spatrick QualType ReceiverType,
2837e5dd7070Spatrick SourceLocation SuperLoc,
2838e5dd7070Spatrick Selector Sel,
2839e5dd7070Spatrick ObjCMethodDecl *Method,
2840e5dd7070Spatrick SourceLocation LBracLoc,
2841e5dd7070Spatrick ArrayRef<SourceLocation> SelectorLocs,
2842e5dd7070Spatrick SourceLocation RBracLoc,
2843e5dd7070Spatrick MultiExprArg ArgsIn,
2844e5dd7070Spatrick bool isImplicit) {
2845e5dd7070Spatrick assert((Receiver || SuperLoc.isValid()) && "If the Receiver is null, the "
2846e5dd7070Spatrick "SuperLoc must be valid so we can "
2847e5dd7070Spatrick "use it instead.");
2848e5dd7070Spatrick
2849e5dd7070Spatrick // The location of the receiver.
2850e5dd7070Spatrick SourceLocation Loc = SuperLoc.isValid() ? SuperLoc : Receiver->getBeginLoc();
2851e5dd7070Spatrick SourceRange RecRange =
2852e5dd7070Spatrick SuperLoc.isValid()? SuperLoc : Receiver->getSourceRange();
2853e5dd7070Spatrick ArrayRef<SourceLocation> SelectorSlotLocs;
2854e5dd7070Spatrick if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
2855e5dd7070Spatrick SelectorSlotLocs = SelectorLocs;
2856e5dd7070Spatrick else
2857e5dd7070Spatrick SelectorSlotLocs = Loc;
2858e5dd7070Spatrick SourceLocation SelLoc = SelectorSlotLocs.front();
2859e5dd7070Spatrick
2860e5dd7070Spatrick if (LBracLoc.isInvalid()) {
2861e5dd7070Spatrick Diag(Loc, diag::err_missing_open_square_message_send)
2862e5dd7070Spatrick << FixItHint::CreateInsertion(Loc, "[");
2863e5dd7070Spatrick LBracLoc = Loc;
2864e5dd7070Spatrick }
2865e5dd7070Spatrick
2866e5dd7070Spatrick // If we have a receiver expression, perform appropriate promotions
2867e5dd7070Spatrick // and determine receiver type.
2868e5dd7070Spatrick if (Receiver) {
2869e5dd7070Spatrick if (Receiver->hasPlaceholderType()) {
2870e5dd7070Spatrick ExprResult Result;
2871e5dd7070Spatrick if (Receiver->getType() == Context.UnknownAnyTy)
2872e5dd7070Spatrick Result = forceUnknownAnyToType(Receiver, Context.getObjCIdType());
2873e5dd7070Spatrick else
2874e5dd7070Spatrick Result = CheckPlaceholderExpr(Receiver);
2875e5dd7070Spatrick if (Result.isInvalid()) return ExprError();
2876e5dd7070Spatrick Receiver = Result.get();
2877e5dd7070Spatrick }
2878e5dd7070Spatrick
2879e5dd7070Spatrick if (Receiver->isTypeDependent()) {
2880e5dd7070Spatrick // If the receiver is type-dependent, we can't type-check anything
2881e5dd7070Spatrick // at this point. Build a dependent expression.
2882e5dd7070Spatrick unsigned NumArgs = ArgsIn.size();
2883e5dd7070Spatrick Expr **Args = ArgsIn.data();
2884e5dd7070Spatrick assert(SuperLoc.isInvalid() && "Message to super with dependent type");
2885e5dd7070Spatrick return ObjCMessageExpr::Create(
2886a9ac8606Spatrick Context, Context.DependentTy, VK_PRValue, LBracLoc, Receiver, Sel,
2887*12c85518Srobert SelectorLocs, /*Method=*/nullptr, ArrayRef(Args, NumArgs), RBracLoc,
2888*12c85518Srobert isImplicit);
2889e5dd7070Spatrick }
2890e5dd7070Spatrick
2891e5dd7070Spatrick // If necessary, apply function/array conversion to the receiver.
2892e5dd7070Spatrick // C99 6.7.5.3p[7,8].
2893e5dd7070Spatrick ExprResult Result = DefaultFunctionArrayLvalueConversion(Receiver);
2894e5dd7070Spatrick if (Result.isInvalid())
2895e5dd7070Spatrick return ExprError();
2896e5dd7070Spatrick Receiver = Result.get();
2897e5dd7070Spatrick ReceiverType = Receiver->getType();
2898e5dd7070Spatrick
2899e5dd7070Spatrick // If the receiver is an ObjC pointer, a block pointer, or an
2900e5dd7070Spatrick // __attribute__((NSObject)) pointer, we don't need to do any
2901e5dd7070Spatrick // special conversion in order to look up a receiver.
2902e5dd7070Spatrick if (ReceiverType->isObjCRetainableType()) {
2903e5dd7070Spatrick // do nothing
2904e5dd7070Spatrick } else if (!getLangOpts().ObjCAutoRefCount &&
2905e5dd7070Spatrick !Context.getObjCIdType().isNull() &&
2906e5dd7070Spatrick (ReceiverType->isPointerType() ||
2907e5dd7070Spatrick ReceiverType->isIntegerType())) {
2908e5dd7070Spatrick // Implicitly convert integers and pointers to 'id' but emit a warning.
2909e5dd7070Spatrick // But not in ARC.
2910ec727ea7Spatrick Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << RecRange;
2911e5dd7070Spatrick if (ReceiverType->isPointerType()) {
2912e5dd7070Spatrick Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
2913e5dd7070Spatrick CK_CPointerToObjCPointerCast).get();
2914e5dd7070Spatrick } else {
2915e5dd7070Spatrick // TODO: specialized warning on null receivers?
2916e5dd7070Spatrick bool IsNull = Receiver->isNullPointerConstant(Context,
2917e5dd7070Spatrick Expr::NPC_ValueDependentIsNull);
2918e5dd7070Spatrick CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
2919e5dd7070Spatrick Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
2920e5dd7070Spatrick Kind).get();
2921e5dd7070Spatrick }
2922e5dd7070Spatrick ReceiverType = Receiver->getType();
2923e5dd7070Spatrick } else if (getLangOpts().CPlusPlus) {
2924e5dd7070Spatrick // The receiver must be a complete type.
2925e5dd7070Spatrick if (RequireCompleteType(Loc, Receiver->getType(),
2926e5dd7070Spatrick diag::err_incomplete_receiver_type))
2927e5dd7070Spatrick return ExprError();
2928e5dd7070Spatrick
2929e5dd7070Spatrick ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver);
2930e5dd7070Spatrick if (result.isUsable()) {
2931e5dd7070Spatrick Receiver = result.get();
2932e5dd7070Spatrick ReceiverType = Receiver->getType();
2933e5dd7070Spatrick }
2934e5dd7070Spatrick }
2935e5dd7070Spatrick }
2936e5dd7070Spatrick
2937e5dd7070Spatrick // There's a somewhat weird interaction here where we assume that we
2938e5dd7070Spatrick // won't actually have a method unless we also don't need to do some
2939e5dd7070Spatrick // of the more detailed type-checking on the receiver.
2940e5dd7070Spatrick
2941e5dd7070Spatrick if (!Method) {
2942e5dd7070Spatrick // Handle messages to id and __kindof types (where we use the
2943e5dd7070Spatrick // global method pool).
2944e5dd7070Spatrick const ObjCObjectType *typeBound = nullptr;
2945e5dd7070Spatrick bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context,
2946e5dd7070Spatrick typeBound);
2947e5dd7070Spatrick if (receiverIsIdLike || ReceiverType->isBlockPointerType() ||
2948e5dd7070Spatrick (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
2949e5dd7070Spatrick SmallVector<ObjCMethodDecl*, 4> Methods;
2950e5dd7070Spatrick // If we have a type bound, further filter the methods.
2951e5dd7070Spatrick CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/,
2952e5dd7070Spatrick true/*CheckTheOther*/, typeBound);
2953e5dd7070Spatrick if (!Methods.empty()) {
2954e5dd7070Spatrick // We choose the first method as the initial candidate, then try to
2955e5dd7070Spatrick // select a better one.
2956e5dd7070Spatrick Method = Methods[0];
2957e5dd7070Spatrick
2958e5dd7070Spatrick if (ObjCMethodDecl *BestMethod =
2959e5dd7070Spatrick SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), Methods))
2960e5dd7070Spatrick Method = BestMethod;
2961e5dd7070Spatrick
2962e5dd7070Spatrick if (!AreMultipleMethodsInGlobalPool(Sel, Method,
2963e5dd7070Spatrick SourceRange(LBracLoc, RBracLoc),
2964e5dd7070Spatrick receiverIsIdLike, Methods))
2965e5dd7070Spatrick DiagnoseUseOfDecl(Method, SelectorSlotLocs);
2966e5dd7070Spatrick }
2967e5dd7070Spatrick } else if (ReceiverType->isObjCClassOrClassKindOfType() ||
2968e5dd7070Spatrick ReceiverType->isObjCQualifiedClassType()) {
2969e5dd7070Spatrick // Handle messages to Class.
2970e5dd7070Spatrick // We allow sending a message to a qualified Class ("Class<foo>"), which
2971e5dd7070Spatrick // is ok as long as one of the protocols implements the selector (if not,
2972e5dd7070Spatrick // warn).
2973e5dd7070Spatrick if (!ReceiverType->isObjCClassOrClassKindOfType()) {
2974e5dd7070Spatrick const ObjCObjectPointerType *QClassTy
2975e5dd7070Spatrick = ReceiverType->getAsObjCQualifiedClassType();
2976e5dd7070Spatrick // Search protocols for class methods.
2977e5dd7070Spatrick Method = LookupMethodInQualifiedType(Sel, QClassTy, false);
2978e5dd7070Spatrick if (!Method) {
2979e5dd7070Spatrick Method = LookupMethodInQualifiedType(Sel, QClassTy, true);
2980e5dd7070Spatrick // warn if instance method found for a Class message.
2981e5dd7070Spatrick if (Method && !isMethodDeclaredInRootProtocol(*this, Method)) {
2982e5dd7070Spatrick Diag(SelLoc, diag::warn_instance_method_on_class_found)
2983e5dd7070Spatrick << Method->getSelector() << Sel;
2984e5dd7070Spatrick Diag(Method->getLocation(), diag::note_method_declared_at)
2985e5dd7070Spatrick << Method->getDeclName();
2986e5dd7070Spatrick }
2987e5dd7070Spatrick }
2988e5dd7070Spatrick } else {
2989e5dd7070Spatrick if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
2990e5dd7070Spatrick if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
2991e5dd7070Spatrick // As a guess, try looking for the method in the current interface.
2992e5dd7070Spatrick // This very well may not produce the "right" method.
2993e5dd7070Spatrick
2994e5dd7070Spatrick // First check the public methods in the class interface.
2995e5dd7070Spatrick Method = ClassDecl->lookupClassMethod(Sel);
2996e5dd7070Spatrick
2997e5dd7070Spatrick if (!Method)
2998e5dd7070Spatrick Method = ClassDecl->lookupPrivateClassMethod(Sel);
2999e5dd7070Spatrick
3000e5dd7070Spatrick if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs))
3001e5dd7070Spatrick return ExprError();
3002e5dd7070Spatrick }
3003e5dd7070Spatrick }
3004e5dd7070Spatrick if (!Method) {
3005e5dd7070Spatrick // If not messaging 'self', look for any factory method named 'Sel'.
3006e5dd7070Spatrick if (!Receiver || !isSelfExpr(Receiver)) {
3007e5dd7070Spatrick // If no class (factory) method was found, check if an _instance_
3008e5dd7070Spatrick // method of the same name exists in the root class only.
3009e5dd7070Spatrick SmallVector<ObjCMethodDecl*, 4> Methods;
3010e5dd7070Spatrick CollectMultipleMethodsInGlobalPool(Sel, Methods,
3011e5dd7070Spatrick false/*InstanceFirst*/,
3012e5dd7070Spatrick true/*CheckTheOther*/);
3013e5dd7070Spatrick if (!Methods.empty()) {
3014e5dd7070Spatrick // We choose the first method as the initial candidate, then try
3015e5dd7070Spatrick // to select a better one.
3016e5dd7070Spatrick Method = Methods[0];
3017e5dd7070Spatrick
3018e5dd7070Spatrick // If we find an instance method, emit warning.
3019e5dd7070Spatrick if (Method->isInstanceMethod()) {
3020e5dd7070Spatrick if (const ObjCInterfaceDecl *ID =
3021e5dd7070Spatrick dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
3022e5dd7070Spatrick if (ID->getSuperClass())
3023e5dd7070Spatrick Diag(SelLoc, diag::warn_root_inst_method_not_found)
3024e5dd7070Spatrick << Sel << SourceRange(LBracLoc, RBracLoc);
3025e5dd7070Spatrick }
3026e5dd7070Spatrick }
3027e5dd7070Spatrick
3028e5dd7070Spatrick if (ObjCMethodDecl *BestMethod =
3029e5dd7070Spatrick SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
3030e5dd7070Spatrick Methods))
3031e5dd7070Spatrick Method = BestMethod;
3032e5dd7070Spatrick }
3033e5dd7070Spatrick }
3034e5dd7070Spatrick }
3035e5dd7070Spatrick }
3036e5dd7070Spatrick } else {
3037e5dd7070Spatrick ObjCInterfaceDecl *ClassDecl = nullptr;
3038e5dd7070Spatrick
3039e5dd7070Spatrick // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
3040e5dd7070Spatrick // long as one of the protocols implements the selector (if not, warn).
3041e5dd7070Spatrick // And as long as message is not deprecated/unavailable (warn if it is).
3042e5dd7070Spatrick if (const ObjCObjectPointerType *QIdTy
3043e5dd7070Spatrick = ReceiverType->getAsObjCQualifiedIdType()) {
3044e5dd7070Spatrick // Search protocols for instance methods.
3045e5dd7070Spatrick Method = LookupMethodInQualifiedType(Sel, QIdTy, true);
3046e5dd7070Spatrick if (!Method)
3047e5dd7070Spatrick Method = LookupMethodInQualifiedType(Sel, QIdTy, false);
3048e5dd7070Spatrick if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs))
3049e5dd7070Spatrick return ExprError();
3050e5dd7070Spatrick } else if (const ObjCObjectPointerType *OCIType
3051e5dd7070Spatrick = ReceiverType->getAsObjCInterfacePointerType()) {
3052e5dd7070Spatrick // We allow sending a message to a pointer to an interface (an object).
3053e5dd7070Spatrick ClassDecl = OCIType->getInterfaceDecl();
3054e5dd7070Spatrick
3055e5dd7070Spatrick // Try to complete the type. Under ARC, this is a hard error from which
3056e5dd7070Spatrick // we don't try to recover.
3057e5dd7070Spatrick // FIXME: In the non-ARC case, this will still be a hard error if the
3058e5dd7070Spatrick // definition is found in a module that's not visible.
3059e5dd7070Spatrick const ObjCInterfaceDecl *forwardClass = nullptr;
3060e5dd7070Spatrick if (RequireCompleteType(Loc, OCIType->getPointeeType(),
3061e5dd7070Spatrick getLangOpts().ObjCAutoRefCount
3062e5dd7070Spatrick ? diag::err_arc_receiver_forward_instance
3063e5dd7070Spatrick : diag::warn_receiver_forward_instance,
3064ec727ea7Spatrick RecRange)) {
3065e5dd7070Spatrick if (getLangOpts().ObjCAutoRefCount)
3066e5dd7070Spatrick return ExprError();
3067e5dd7070Spatrick
3068e5dd7070Spatrick forwardClass = OCIType->getInterfaceDecl();
3069e5dd7070Spatrick Diag(Receiver ? Receiver->getBeginLoc() : SuperLoc,
3070e5dd7070Spatrick diag::note_receiver_is_id);
3071e5dd7070Spatrick Method = nullptr;
3072e5dd7070Spatrick } else {
3073e5dd7070Spatrick Method = ClassDecl->lookupInstanceMethod(Sel);
3074e5dd7070Spatrick }
3075e5dd7070Spatrick
3076e5dd7070Spatrick if (!Method)
3077e5dd7070Spatrick // Search protocol qualifiers.
3078e5dd7070Spatrick Method = LookupMethodInQualifiedType(Sel, OCIType, true);
3079e5dd7070Spatrick
3080e5dd7070Spatrick if (!Method) {
3081e5dd7070Spatrick // If we have implementations in scope, check "private" methods.
3082e5dd7070Spatrick Method = ClassDecl->lookupPrivateMethod(Sel);
3083e5dd7070Spatrick
3084e5dd7070Spatrick if (!Method && getLangOpts().ObjCAutoRefCount) {
3085e5dd7070Spatrick Diag(SelLoc, diag::err_arc_may_not_respond)
3086e5dd7070Spatrick << OCIType->getPointeeType() << Sel << RecRange
3087e5dd7070Spatrick << SourceRange(SelectorLocs.front(), SelectorLocs.back());
3088e5dd7070Spatrick return ExprError();
3089e5dd7070Spatrick }
3090e5dd7070Spatrick
3091e5dd7070Spatrick if (!Method && (!Receiver || !isSelfExpr(Receiver))) {
3092e5dd7070Spatrick // If we still haven't found a method, look in the global pool. This
3093e5dd7070Spatrick // behavior isn't very desirable, however we need it for GCC
3094e5dd7070Spatrick // compatibility. FIXME: should we deviate??
3095e5dd7070Spatrick if (OCIType->qual_empty()) {
3096e5dd7070Spatrick SmallVector<ObjCMethodDecl*, 4> Methods;
3097e5dd7070Spatrick CollectMultipleMethodsInGlobalPool(Sel, Methods,
3098e5dd7070Spatrick true/*InstanceFirst*/,
3099e5dd7070Spatrick false/*CheckTheOther*/);
3100e5dd7070Spatrick if (!Methods.empty()) {
3101e5dd7070Spatrick // We choose the first method as the initial candidate, then try
3102e5dd7070Spatrick // to select a better one.
3103e5dd7070Spatrick Method = Methods[0];
3104e5dd7070Spatrick
3105e5dd7070Spatrick if (ObjCMethodDecl *BestMethod =
3106e5dd7070Spatrick SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
3107e5dd7070Spatrick Methods))
3108e5dd7070Spatrick Method = BestMethod;
3109e5dd7070Spatrick
3110e5dd7070Spatrick AreMultipleMethodsInGlobalPool(Sel, Method,
3111e5dd7070Spatrick SourceRange(LBracLoc, RBracLoc),
3112e5dd7070Spatrick true/*receiverIdOrClass*/,
3113e5dd7070Spatrick Methods);
3114e5dd7070Spatrick }
3115e5dd7070Spatrick if (Method && !forwardClass)
3116e5dd7070Spatrick Diag(SelLoc, diag::warn_maynot_respond)
3117e5dd7070Spatrick << OCIType->getInterfaceDecl()->getIdentifier()
3118e5dd7070Spatrick << Sel << RecRange;
3119e5dd7070Spatrick }
3120e5dd7070Spatrick }
3121e5dd7070Spatrick }
3122e5dd7070Spatrick if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, forwardClass))
3123e5dd7070Spatrick return ExprError();
3124e5dd7070Spatrick } else {
3125e5dd7070Spatrick // Reject other random receiver types (e.g. structs).
3126ec727ea7Spatrick Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << RecRange;
3127e5dd7070Spatrick return ExprError();
3128e5dd7070Spatrick }
3129e5dd7070Spatrick }
3130e5dd7070Spatrick }
3131e5dd7070Spatrick
3132e5dd7070Spatrick FunctionScopeInfo *DIFunctionScopeInfo =
3133e5dd7070Spatrick (Method && Method->getMethodFamily() == OMF_init)
3134e5dd7070Spatrick ? getEnclosingFunction() : nullptr;
3135e5dd7070Spatrick
3136e5dd7070Spatrick if (Method && Method->isDirectMethod()) {
3137e5dd7070Spatrick if (ReceiverType->isObjCIdType() && !isImplicit) {
3138e5dd7070Spatrick Diag(Receiver->getExprLoc(),
3139e5dd7070Spatrick diag::err_messaging_unqualified_id_with_direct_method);
3140e5dd7070Spatrick Diag(Method->getLocation(), diag::note_direct_method_declared_at)
3141e5dd7070Spatrick << Method->getDeclName();
3142e5dd7070Spatrick }
3143e5dd7070Spatrick
3144ec727ea7Spatrick // Under ARC, self can't be assigned, and doing a direct call to `self`
3145ec727ea7Spatrick // when it's a Class is hence safe. For other cases, we can't trust `self`
3146ec727ea7Spatrick // is what we think it is, so we reject it.
3147ec727ea7Spatrick if (ReceiverType->isObjCClassType() && !isImplicit &&
3148ec727ea7Spatrick !(Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount)) {
3149ec727ea7Spatrick {
3150a9ac8606Spatrick auto Builder = Diag(Receiver->getExprLoc(),
3151e5dd7070Spatrick diag::err_messaging_class_with_direct_method);
3152ec727ea7Spatrick if (Receiver->isObjCSelfExpr()) {
3153ec727ea7Spatrick Builder.AddFixItHint(FixItHint::CreateReplacement(
3154ec727ea7Spatrick RecRange, Method->getClassInterface()->getName()));
3155ec727ea7Spatrick }
3156ec727ea7Spatrick }
3157e5dd7070Spatrick Diag(Method->getLocation(), diag::note_direct_method_declared_at)
3158e5dd7070Spatrick << Method->getDeclName();
3159e5dd7070Spatrick }
3160e5dd7070Spatrick
3161e5dd7070Spatrick if (SuperLoc.isValid()) {
3162ec727ea7Spatrick {
3163a9ac8606Spatrick auto Builder =
3164e5dd7070Spatrick Diag(SuperLoc, diag::err_messaging_super_with_direct_method);
3165ec727ea7Spatrick if (ReceiverType->isObjCClassType()) {
3166ec727ea7Spatrick Builder.AddFixItHint(FixItHint::CreateReplacement(
3167ec727ea7Spatrick SuperLoc, Method->getClassInterface()->getName()));
3168ec727ea7Spatrick } else {
3169ec727ea7Spatrick Builder.AddFixItHint(FixItHint::CreateReplacement(SuperLoc, "self"));
3170ec727ea7Spatrick }
3171ec727ea7Spatrick }
3172e5dd7070Spatrick Diag(Method->getLocation(), diag::note_direct_method_declared_at)
3173e5dd7070Spatrick << Method->getDeclName();
3174e5dd7070Spatrick }
3175e5dd7070Spatrick } else if (ReceiverType->isObjCIdType() && !isImplicit) {
3176e5dd7070Spatrick Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
3177e5dd7070Spatrick }
3178e5dd7070Spatrick
3179e5dd7070Spatrick if (DIFunctionScopeInfo &&
3180e5dd7070Spatrick DIFunctionScopeInfo->ObjCIsDesignatedInit &&
3181e5dd7070Spatrick (SuperLoc.isValid() || isSelfExpr(Receiver))) {
3182e5dd7070Spatrick bool isDesignatedInitChain = false;
3183e5dd7070Spatrick if (SuperLoc.isValid()) {
3184e5dd7070Spatrick if (const ObjCObjectPointerType *
3185e5dd7070Spatrick OCIType = ReceiverType->getAsObjCInterfacePointerType()) {
3186e5dd7070Spatrick if (const ObjCInterfaceDecl *ID = OCIType->getInterfaceDecl()) {
3187e5dd7070Spatrick // Either we know this is a designated initializer or we
3188e5dd7070Spatrick // conservatively assume it because we don't know for sure.
3189e5dd7070Spatrick if (!ID->declaresOrInheritsDesignatedInitializers() ||
3190e5dd7070Spatrick ID->isDesignatedInitializer(Sel)) {
3191e5dd7070Spatrick isDesignatedInitChain = true;
3192e5dd7070Spatrick DIFunctionScopeInfo->ObjCWarnForNoDesignatedInitChain = false;
3193e5dd7070Spatrick }
3194e5dd7070Spatrick }
3195e5dd7070Spatrick }
3196e5dd7070Spatrick }
3197e5dd7070Spatrick if (!isDesignatedInitChain) {
3198e5dd7070Spatrick const ObjCMethodDecl *InitMethod = nullptr;
3199e5dd7070Spatrick bool isDesignated =
3200e5dd7070Spatrick getCurMethodDecl()->isDesignatedInitializerForTheInterface(&InitMethod);
3201e5dd7070Spatrick assert(isDesignated && InitMethod);
3202e5dd7070Spatrick (void)isDesignated;
3203e5dd7070Spatrick Diag(SelLoc, SuperLoc.isValid() ?
3204e5dd7070Spatrick diag::warn_objc_designated_init_non_designated_init_call :
3205e5dd7070Spatrick diag::warn_objc_designated_init_non_super_designated_init_call);
3206e5dd7070Spatrick Diag(InitMethod->getLocation(),
3207e5dd7070Spatrick diag::note_objc_designated_init_marked_here);
3208e5dd7070Spatrick }
3209e5dd7070Spatrick }
3210e5dd7070Spatrick
3211e5dd7070Spatrick if (DIFunctionScopeInfo &&
3212e5dd7070Spatrick DIFunctionScopeInfo->ObjCIsSecondaryInit &&
3213e5dd7070Spatrick (SuperLoc.isValid() || isSelfExpr(Receiver))) {
3214e5dd7070Spatrick if (SuperLoc.isValid()) {
3215e5dd7070Spatrick Diag(SelLoc, diag::warn_objc_secondary_init_super_init_call);
3216e5dd7070Spatrick } else {
3217e5dd7070Spatrick DIFunctionScopeInfo->ObjCWarnForNoInitDelegation = false;
3218e5dd7070Spatrick }
3219e5dd7070Spatrick }
3220e5dd7070Spatrick
3221e5dd7070Spatrick // Check the message arguments.
3222e5dd7070Spatrick unsigned NumArgs = ArgsIn.size();
3223e5dd7070Spatrick Expr **Args = ArgsIn.data();
3224e5dd7070Spatrick QualType ReturnType;
3225a9ac8606Spatrick ExprValueKind VK = VK_PRValue;
3226e5dd7070Spatrick bool ClassMessage = (ReceiverType->isObjCClassType() ||
3227e5dd7070Spatrick ReceiverType->isObjCQualifiedClassType());
3228e5dd7070Spatrick if (CheckMessageArgumentTypes(Receiver, ReceiverType,
3229e5dd7070Spatrick MultiExprArg(Args, NumArgs), Sel, SelectorLocs,
3230e5dd7070Spatrick Method, ClassMessage, SuperLoc.isValid(),
3231e5dd7070Spatrick LBracLoc, RBracLoc, RecRange, ReturnType, VK))
3232e5dd7070Spatrick return ExprError();
3233e5dd7070Spatrick
3234e5dd7070Spatrick if (Method && !Method->getReturnType()->isVoidType() &&
3235e5dd7070Spatrick RequireCompleteType(LBracLoc, Method->getReturnType(),
3236e5dd7070Spatrick diag::err_illegal_message_expr_incomplete_type))
3237e5dd7070Spatrick return ExprError();
3238e5dd7070Spatrick
3239e5dd7070Spatrick // In ARC, forbid the user from sending messages to
3240e5dd7070Spatrick // retain/release/autorelease/dealloc/retainCount explicitly.
3241e5dd7070Spatrick if (getLangOpts().ObjCAutoRefCount) {
3242e5dd7070Spatrick ObjCMethodFamily family =
3243e5dd7070Spatrick (Method ? Method->getMethodFamily() : Sel.getMethodFamily());
3244e5dd7070Spatrick switch (family) {
3245e5dd7070Spatrick case OMF_init:
3246e5dd7070Spatrick if (Method)
3247e5dd7070Spatrick checkInitMethod(Method, ReceiverType);
3248e5dd7070Spatrick break;
3249e5dd7070Spatrick
3250e5dd7070Spatrick case OMF_None:
3251e5dd7070Spatrick case OMF_alloc:
3252e5dd7070Spatrick case OMF_copy:
3253e5dd7070Spatrick case OMF_finalize:
3254e5dd7070Spatrick case OMF_mutableCopy:
3255e5dd7070Spatrick case OMF_new:
3256e5dd7070Spatrick case OMF_self:
3257e5dd7070Spatrick case OMF_initialize:
3258e5dd7070Spatrick break;
3259e5dd7070Spatrick
3260e5dd7070Spatrick case OMF_dealloc:
3261e5dd7070Spatrick case OMF_retain:
3262e5dd7070Spatrick case OMF_release:
3263e5dd7070Spatrick case OMF_autorelease:
3264e5dd7070Spatrick case OMF_retainCount:
3265e5dd7070Spatrick Diag(SelLoc, diag::err_arc_illegal_explicit_message)
3266e5dd7070Spatrick << Sel << RecRange;
3267e5dd7070Spatrick break;
3268e5dd7070Spatrick
3269e5dd7070Spatrick case OMF_performSelector:
3270e5dd7070Spatrick if (Method && NumArgs >= 1) {
3271e5dd7070Spatrick if (const auto *SelExp =
3272e5dd7070Spatrick dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens())) {
3273e5dd7070Spatrick Selector ArgSel = SelExp->getSelector();
3274e5dd7070Spatrick ObjCMethodDecl *SelMethod =
3275e5dd7070Spatrick LookupInstanceMethodInGlobalPool(ArgSel,
3276e5dd7070Spatrick SelExp->getSourceRange());
3277e5dd7070Spatrick if (!SelMethod)
3278e5dd7070Spatrick SelMethod =
3279e5dd7070Spatrick LookupFactoryMethodInGlobalPool(ArgSel,
3280e5dd7070Spatrick SelExp->getSourceRange());
3281e5dd7070Spatrick if (SelMethod) {
3282e5dd7070Spatrick ObjCMethodFamily SelFamily = SelMethod->getMethodFamily();
3283e5dd7070Spatrick switch (SelFamily) {
3284e5dd7070Spatrick case OMF_alloc:
3285e5dd7070Spatrick case OMF_copy:
3286e5dd7070Spatrick case OMF_mutableCopy:
3287e5dd7070Spatrick case OMF_new:
3288e5dd7070Spatrick case OMF_init:
3289e5dd7070Spatrick // Issue error, unless ns_returns_not_retained.
3290e5dd7070Spatrick if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
3291e5dd7070Spatrick // selector names a +1 method
3292e5dd7070Spatrick Diag(SelLoc,
3293e5dd7070Spatrick diag::err_arc_perform_selector_retains);
3294e5dd7070Spatrick Diag(SelMethod->getLocation(), diag::note_method_declared_at)
3295e5dd7070Spatrick << SelMethod->getDeclName();
3296e5dd7070Spatrick }
3297e5dd7070Spatrick break;
3298e5dd7070Spatrick default:
3299e5dd7070Spatrick // +0 call. OK. unless ns_returns_retained.
3300e5dd7070Spatrick if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) {
3301e5dd7070Spatrick // selector names a +1 method
3302e5dd7070Spatrick Diag(SelLoc,
3303e5dd7070Spatrick diag::err_arc_perform_selector_retains);
3304e5dd7070Spatrick Diag(SelMethod->getLocation(), diag::note_method_declared_at)
3305e5dd7070Spatrick << SelMethod->getDeclName();
3306e5dd7070Spatrick }
3307e5dd7070Spatrick break;
3308e5dd7070Spatrick }
3309e5dd7070Spatrick }
3310e5dd7070Spatrick } else {
3311e5dd7070Spatrick // error (may leak).
3312e5dd7070Spatrick Diag(SelLoc, diag::warn_arc_perform_selector_leaks);
3313e5dd7070Spatrick Diag(Args[0]->getExprLoc(), diag::note_used_here);
3314e5dd7070Spatrick }
3315e5dd7070Spatrick }
3316e5dd7070Spatrick break;
3317e5dd7070Spatrick }
3318e5dd7070Spatrick }
3319e5dd7070Spatrick
3320e5dd7070Spatrick DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
3321e5dd7070Spatrick
3322e5dd7070Spatrick // Construct the appropriate ObjCMessageExpr instance.
3323e5dd7070Spatrick ObjCMessageExpr *Result;
3324e5dd7070Spatrick if (SuperLoc.isValid())
3325*12c85518Srobert Result = ObjCMessageExpr::Create(
3326*12c85518Srobert Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true,
3327*12c85518Srobert ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
3328*12c85518Srobert RBracLoc, isImplicit);
3329e5dd7070Spatrick else {
3330*12c85518Srobert Result = ObjCMessageExpr::Create(
3331*12c85518Srobert Context, ReturnType, VK, LBracLoc, Receiver, Sel, SelectorLocs, Method,
3332*12c85518Srobert ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
3333e5dd7070Spatrick if (!isImplicit)
3334e5dd7070Spatrick checkCocoaAPI(*this, Result);
3335e5dd7070Spatrick }
3336e5dd7070Spatrick if (Method) {
3337e5dd7070Spatrick bool IsClassObjectCall = ClassMessage;
3338e5dd7070Spatrick // 'self' message receivers in class methods should be treated as message
3339e5dd7070Spatrick // sends to the class object in order for the semantic checks to be
3340e5dd7070Spatrick // performed correctly. Messages to 'super' already count as class messages,
3341e5dd7070Spatrick // so they don't need to be handled here.
3342e5dd7070Spatrick if (Receiver && isSelfExpr(Receiver)) {
3343e5dd7070Spatrick if (const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>()) {
3344e5dd7070Spatrick if (OPT->getObjectType()->isObjCClass()) {
3345e5dd7070Spatrick if (const auto *CurMeth = getCurMethodDecl()) {
3346e5dd7070Spatrick IsClassObjectCall = true;
3347e5dd7070Spatrick ReceiverType =
3348e5dd7070Spatrick Context.getObjCInterfaceType(CurMeth->getClassInterface());
3349e5dd7070Spatrick }
3350e5dd7070Spatrick }
3351e5dd7070Spatrick }
3352e5dd7070Spatrick }
3353*12c85518Srobert checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
3354e5dd7070Spatrick ReceiverType, IsClassObjectCall);
3355e5dd7070Spatrick }
3356e5dd7070Spatrick
3357e5dd7070Spatrick if (getLangOpts().ObjCAutoRefCount) {
3358e5dd7070Spatrick // In ARC, annotate delegate init calls.
3359e5dd7070Spatrick if (Result->getMethodFamily() == OMF_init &&
3360e5dd7070Spatrick (SuperLoc.isValid() || isSelfExpr(Receiver))) {
3361e5dd7070Spatrick // Only consider init calls *directly* in init implementations,
3362e5dd7070Spatrick // not within blocks.
3363e5dd7070Spatrick ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CurContext);
3364e5dd7070Spatrick if (method && method->getMethodFamily() == OMF_init) {
3365e5dd7070Spatrick // The implicit assignment to self means we also don't want to
3366e5dd7070Spatrick // consume the result.
3367e5dd7070Spatrick Result->setDelegateInitCall(true);
3368e5dd7070Spatrick return Result;
3369e5dd7070Spatrick }
3370e5dd7070Spatrick }
3371e5dd7070Spatrick
3372e5dd7070Spatrick // In ARC, check for message sends which are likely to introduce
3373e5dd7070Spatrick // retain cycles.
3374e5dd7070Spatrick checkRetainCycles(Result);
3375e5dd7070Spatrick }
3376e5dd7070Spatrick
3377e5dd7070Spatrick if (getLangOpts().ObjCWeak) {
3378e5dd7070Spatrick if (!isImplicit && Method) {
3379e5dd7070Spatrick if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) {
3380e5dd7070Spatrick bool IsWeak =
3381ec727ea7Spatrick Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak;
3382e5dd7070Spatrick if (!IsWeak && Sel.isUnarySelector())
3383e5dd7070Spatrick IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak;
3384e5dd7070Spatrick if (IsWeak && !isUnevaluatedContext() &&
3385e5dd7070Spatrick !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, LBracLoc))
3386e5dd7070Spatrick getCurFunction()->recordUseOfWeak(Result, Prop);
3387e5dd7070Spatrick }
3388e5dd7070Spatrick }
3389e5dd7070Spatrick }
3390e5dd7070Spatrick
3391e5dd7070Spatrick CheckObjCCircularContainer(Result);
3392e5dd7070Spatrick
3393e5dd7070Spatrick return MaybeBindToTemporary(Result);
3394e5dd7070Spatrick }
3395e5dd7070Spatrick
RemoveSelectorFromWarningCache(Sema & S,Expr * Arg)3396e5dd7070Spatrick static void RemoveSelectorFromWarningCache(Sema &S, Expr* Arg) {
3397e5dd7070Spatrick if (ObjCSelectorExpr *OSE =
3398e5dd7070Spatrick dyn_cast<ObjCSelectorExpr>(Arg->IgnoreParenCasts())) {
3399e5dd7070Spatrick Selector Sel = OSE->getSelector();
3400e5dd7070Spatrick SourceLocation Loc = OSE->getAtLoc();
3401e5dd7070Spatrick auto Pos = S.ReferencedSelectors.find(Sel);
3402e5dd7070Spatrick if (Pos != S.ReferencedSelectors.end() && Pos->second == Loc)
3403e5dd7070Spatrick S.ReferencedSelectors.erase(Pos);
3404e5dd7070Spatrick }
3405e5dd7070Spatrick }
3406e5dd7070Spatrick
3407e5dd7070Spatrick // ActOnInstanceMessage - used for both unary and keyword messages.
3408e5dd7070Spatrick // ArgExprs is optional - if it is present, the number of expressions
3409e5dd7070Spatrick // is obtained from Sel.getNumArgs().
ActOnInstanceMessage(Scope * S,Expr * Receiver,Selector Sel,SourceLocation LBracLoc,ArrayRef<SourceLocation> SelectorLocs,SourceLocation RBracLoc,MultiExprArg Args)3410e5dd7070Spatrick ExprResult Sema::ActOnInstanceMessage(Scope *S,
3411e5dd7070Spatrick Expr *Receiver,
3412e5dd7070Spatrick Selector Sel,
3413e5dd7070Spatrick SourceLocation LBracLoc,
3414e5dd7070Spatrick ArrayRef<SourceLocation> SelectorLocs,
3415e5dd7070Spatrick SourceLocation RBracLoc,
3416e5dd7070Spatrick MultiExprArg Args) {
3417e5dd7070Spatrick if (!Receiver)
3418e5dd7070Spatrick return ExprError();
3419e5dd7070Spatrick
3420e5dd7070Spatrick // A ParenListExpr can show up while doing error recovery with invalid code.
3421e5dd7070Spatrick if (isa<ParenListExpr>(Receiver)) {
3422e5dd7070Spatrick ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Receiver);
3423e5dd7070Spatrick if (Result.isInvalid()) return ExprError();
3424e5dd7070Spatrick Receiver = Result.get();
3425e5dd7070Spatrick }
3426e5dd7070Spatrick
3427e5dd7070Spatrick if (RespondsToSelectorSel.isNull()) {
3428e5dd7070Spatrick IdentifierInfo *SelectorId = &Context.Idents.get("respondsToSelector");
3429e5dd7070Spatrick RespondsToSelectorSel = Context.Selectors.getUnarySelector(SelectorId);
3430e5dd7070Spatrick }
3431e5dd7070Spatrick if (Sel == RespondsToSelectorSel)
3432e5dd7070Spatrick RemoveSelectorFromWarningCache(*this, Args[0]);
3433e5dd7070Spatrick
3434e5dd7070Spatrick return BuildInstanceMessage(Receiver, Receiver->getType(),
3435e5dd7070Spatrick /*SuperLoc=*/SourceLocation(), Sel,
3436e5dd7070Spatrick /*Method=*/nullptr, LBracLoc, SelectorLocs,
3437e5dd7070Spatrick RBracLoc, Args);
3438e5dd7070Spatrick }
3439e5dd7070Spatrick
3440e5dd7070Spatrick enum ARCConversionTypeClass {
3441e5dd7070Spatrick /// int, void, struct A
3442e5dd7070Spatrick ACTC_none,
3443e5dd7070Spatrick
3444e5dd7070Spatrick /// id, void (^)()
3445e5dd7070Spatrick ACTC_retainable,
3446e5dd7070Spatrick
3447e5dd7070Spatrick /// id*, id***, void (^*)(),
3448e5dd7070Spatrick ACTC_indirectRetainable,
3449e5dd7070Spatrick
3450e5dd7070Spatrick /// void* might be a normal C type, or it might a CF type.
3451e5dd7070Spatrick ACTC_voidPtr,
3452e5dd7070Spatrick
3453e5dd7070Spatrick /// struct A*
3454e5dd7070Spatrick ACTC_coreFoundation
3455e5dd7070Spatrick };
3456e5dd7070Spatrick
isAnyRetainable(ARCConversionTypeClass ACTC)3457e5dd7070Spatrick static bool isAnyRetainable(ARCConversionTypeClass ACTC) {
3458e5dd7070Spatrick return (ACTC == ACTC_retainable ||
3459e5dd7070Spatrick ACTC == ACTC_coreFoundation ||
3460e5dd7070Spatrick ACTC == ACTC_voidPtr);
3461e5dd7070Spatrick }
3462e5dd7070Spatrick
isAnyCLike(ARCConversionTypeClass ACTC)3463e5dd7070Spatrick static bool isAnyCLike(ARCConversionTypeClass ACTC) {
3464e5dd7070Spatrick return ACTC == ACTC_none ||
3465e5dd7070Spatrick ACTC == ACTC_voidPtr ||
3466e5dd7070Spatrick ACTC == ACTC_coreFoundation;
3467e5dd7070Spatrick }
3468e5dd7070Spatrick
classifyTypeForARCConversion(QualType type)3469e5dd7070Spatrick static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) {
3470e5dd7070Spatrick bool isIndirect = false;
3471e5dd7070Spatrick
3472e5dd7070Spatrick // Ignore an outermost reference type.
3473e5dd7070Spatrick if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
3474e5dd7070Spatrick type = ref->getPointeeType();
3475e5dd7070Spatrick isIndirect = true;
3476e5dd7070Spatrick }
3477e5dd7070Spatrick
3478e5dd7070Spatrick // Drill through pointers and arrays recursively.
3479e5dd7070Spatrick while (true) {
3480e5dd7070Spatrick if (const PointerType *ptr = type->getAs<PointerType>()) {
3481e5dd7070Spatrick type = ptr->getPointeeType();
3482e5dd7070Spatrick
3483e5dd7070Spatrick // The first level of pointer may be the innermost pointer on a CF type.
3484e5dd7070Spatrick if (!isIndirect) {
3485e5dd7070Spatrick if (type->isVoidType()) return ACTC_voidPtr;
3486e5dd7070Spatrick if (type->isRecordType()) return ACTC_coreFoundation;
3487e5dd7070Spatrick }
3488e5dd7070Spatrick } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) {
3489e5dd7070Spatrick type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0);
3490e5dd7070Spatrick } else {
3491e5dd7070Spatrick break;
3492e5dd7070Spatrick }
3493e5dd7070Spatrick isIndirect = true;
3494e5dd7070Spatrick }
3495e5dd7070Spatrick
3496e5dd7070Spatrick if (isIndirect) {
3497e5dd7070Spatrick if (type->isObjCARCBridgableType())
3498e5dd7070Spatrick return ACTC_indirectRetainable;
3499e5dd7070Spatrick return ACTC_none;
3500e5dd7070Spatrick }
3501e5dd7070Spatrick
3502e5dd7070Spatrick if (type->isObjCARCBridgableType())
3503e5dd7070Spatrick return ACTC_retainable;
3504e5dd7070Spatrick
3505e5dd7070Spatrick return ACTC_none;
3506e5dd7070Spatrick }
3507e5dd7070Spatrick
3508e5dd7070Spatrick namespace {
3509e5dd7070Spatrick /// A result from the cast checker.
3510e5dd7070Spatrick enum ACCResult {
3511e5dd7070Spatrick /// Cannot be casted.
3512e5dd7070Spatrick ACC_invalid,
3513e5dd7070Spatrick
3514e5dd7070Spatrick /// Can be safely retained or not retained.
3515e5dd7070Spatrick ACC_bottom,
3516e5dd7070Spatrick
3517e5dd7070Spatrick /// Can be casted at +0.
3518e5dd7070Spatrick ACC_plusZero,
3519e5dd7070Spatrick
3520e5dd7070Spatrick /// Can be casted at +1.
3521e5dd7070Spatrick ACC_plusOne
3522e5dd7070Spatrick };
merge(ACCResult left,ACCResult right)3523e5dd7070Spatrick ACCResult merge(ACCResult left, ACCResult right) {
3524e5dd7070Spatrick if (left == right) return left;
3525e5dd7070Spatrick if (left == ACC_bottom) return right;
3526e5dd7070Spatrick if (right == ACC_bottom) return left;
3527e5dd7070Spatrick return ACC_invalid;
3528e5dd7070Spatrick }
3529e5dd7070Spatrick
3530e5dd7070Spatrick /// A checker which white-lists certain expressions whose conversion
3531e5dd7070Spatrick /// to or from retainable type would otherwise be forbidden in ARC.
3532e5dd7070Spatrick class ARCCastChecker : public StmtVisitor<ARCCastChecker, ACCResult> {
3533e5dd7070Spatrick typedef StmtVisitor<ARCCastChecker, ACCResult> super;
3534e5dd7070Spatrick
3535e5dd7070Spatrick ASTContext &Context;
3536e5dd7070Spatrick ARCConversionTypeClass SourceClass;
3537e5dd7070Spatrick ARCConversionTypeClass TargetClass;
3538e5dd7070Spatrick bool Diagnose;
3539e5dd7070Spatrick
isCFType(QualType type)3540e5dd7070Spatrick static bool isCFType(QualType type) {
3541e5dd7070Spatrick // Someday this can use ns_bridged. For now, it has to do this.
3542e5dd7070Spatrick return type->isCARCBridgableType();
3543e5dd7070Spatrick }
3544e5dd7070Spatrick
3545e5dd7070Spatrick public:
ARCCastChecker(ASTContext & Context,ARCConversionTypeClass source,ARCConversionTypeClass target,bool diagnose)3546e5dd7070Spatrick ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source,
3547e5dd7070Spatrick ARCConversionTypeClass target, bool diagnose)
3548e5dd7070Spatrick : Context(Context), SourceClass(source), TargetClass(target),
3549e5dd7070Spatrick Diagnose(diagnose) {}
3550e5dd7070Spatrick
3551e5dd7070Spatrick using super::Visit;
Visit(Expr * e)3552e5dd7070Spatrick ACCResult Visit(Expr *e) {
3553e5dd7070Spatrick return super::Visit(e->IgnoreParens());
3554e5dd7070Spatrick }
3555e5dd7070Spatrick
VisitStmt(Stmt * s)3556e5dd7070Spatrick ACCResult VisitStmt(Stmt *s) {
3557e5dd7070Spatrick return ACC_invalid;
3558e5dd7070Spatrick }
3559e5dd7070Spatrick
3560e5dd7070Spatrick /// Null pointer constants can be casted however you please.
VisitExpr(Expr * e)3561e5dd7070Spatrick ACCResult VisitExpr(Expr *e) {
3562e5dd7070Spatrick if (e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
3563e5dd7070Spatrick return ACC_bottom;
3564e5dd7070Spatrick return ACC_invalid;
3565e5dd7070Spatrick }
3566e5dd7070Spatrick
3567e5dd7070Spatrick /// Objective-C string literals can be safely casted.
VisitObjCStringLiteral(ObjCStringLiteral * e)3568e5dd7070Spatrick ACCResult VisitObjCStringLiteral(ObjCStringLiteral *e) {
3569e5dd7070Spatrick // If we're casting to any retainable type, go ahead. Global
3570e5dd7070Spatrick // strings are immune to retains, so this is bottom.
3571e5dd7070Spatrick if (isAnyRetainable(TargetClass)) return ACC_bottom;
3572e5dd7070Spatrick
3573e5dd7070Spatrick return ACC_invalid;
3574e5dd7070Spatrick }
3575e5dd7070Spatrick
3576e5dd7070Spatrick /// Look through certain implicit and explicit casts.
VisitCastExpr(CastExpr * e)3577e5dd7070Spatrick ACCResult VisitCastExpr(CastExpr *e) {
3578e5dd7070Spatrick switch (e->getCastKind()) {
3579e5dd7070Spatrick case CK_NullToPointer:
3580e5dd7070Spatrick return ACC_bottom;
3581e5dd7070Spatrick
3582e5dd7070Spatrick case CK_NoOp:
3583e5dd7070Spatrick case CK_LValueToRValue:
3584e5dd7070Spatrick case CK_BitCast:
3585e5dd7070Spatrick case CK_CPointerToObjCPointerCast:
3586e5dd7070Spatrick case CK_BlockPointerToObjCPointerCast:
3587e5dd7070Spatrick case CK_AnyPointerToBlockPointerCast:
3588e5dd7070Spatrick return Visit(e->getSubExpr());
3589e5dd7070Spatrick
3590e5dd7070Spatrick default:
3591e5dd7070Spatrick return ACC_invalid;
3592e5dd7070Spatrick }
3593e5dd7070Spatrick }
3594e5dd7070Spatrick
3595e5dd7070Spatrick /// Look through unary extension.
VisitUnaryExtension(UnaryOperator * e)3596e5dd7070Spatrick ACCResult VisitUnaryExtension(UnaryOperator *e) {
3597e5dd7070Spatrick return Visit(e->getSubExpr());
3598e5dd7070Spatrick }
3599e5dd7070Spatrick
3600e5dd7070Spatrick /// Ignore the LHS of a comma operator.
VisitBinComma(BinaryOperator * e)3601e5dd7070Spatrick ACCResult VisitBinComma(BinaryOperator *e) {
3602e5dd7070Spatrick return Visit(e->getRHS());
3603e5dd7070Spatrick }
3604e5dd7070Spatrick
3605e5dd7070Spatrick /// Conditional operators are okay if both sides are okay.
VisitConditionalOperator(ConditionalOperator * e)3606e5dd7070Spatrick ACCResult VisitConditionalOperator(ConditionalOperator *e) {
3607e5dd7070Spatrick ACCResult left = Visit(e->getTrueExpr());
3608e5dd7070Spatrick if (left == ACC_invalid) return ACC_invalid;
3609e5dd7070Spatrick return merge(left, Visit(e->getFalseExpr()));
3610e5dd7070Spatrick }
3611e5dd7070Spatrick
3612e5dd7070Spatrick /// Look through pseudo-objects.
VisitPseudoObjectExpr(PseudoObjectExpr * e)3613e5dd7070Spatrick ACCResult VisitPseudoObjectExpr(PseudoObjectExpr *e) {
3614e5dd7070Spatrick // If we're getting here, we should always have a result.
3615e5dd7070Spatrick return Visit(e->getResultExpr());
3616e5dd7070Spatrick }
3617e5dd7070Spatrick
3618e5dd7070Spatrick /// Statement expressions are okay if their result expression is okay.
VisitStmtExpr(StmtExpr * e)3619e5dd7070Spatrick ACCResult VisitStmtExpr(StmtExpr *e) {
3620e5dd7070Spatrick return Visit(e->getSubStmt()->body_back());
3621e5dd7070Spatrick }
3622e5dd7070Spatrick
3623e5dd7070Spatrick /// Some declaration references are okay.
VisitDeclRefExpr(DeclRefExpr * e)3624e5dd7070Spatrick ACCResult VisitDeclRefExpr(DeclRefExpr *e) {
3625e5dd7070Spatrick VarDecl *var = dyn_cast<VarDecl>(e->getDecl());
3626e5dd7070Spatrick // References to global constants are okay.
3627e5dd7070Spatrick if (isAnyRetainable(TargetClass) &&
3628e5dd7070Spatrick isAnyRetainable(SourceClass) &&
3629e5dd7070Spatrick var &&
3630e5dd7070Spatrick !var->hasDefinition(Context) &&
3631e5dd7070Spatrick var->getType().isConstQualified()) {
3632e5dd7070Spatrick
3633e5dd7070Spatrick // In system headers, they can also be assumed to be immune to retains.
3634e5dd7070Spatrick // These are things like 'kCFStringTransformToLatin'.
3635e5dd7070Spatrick if (Context.getSourceManager().isInSystemHeader(var->getLocation()))
3636e5dd7070Spatrick return ACC_bottom;
3637e5dd7070Spatrick
3638e5dd7070Spatrick return ACC_plusZero;
3639e5dd7070Spatrick }
3640e5dd7070Spatrick
3641e5dd7070Spatrick // Nothing else.
3642e5dd7070Spatrick return ACC_invalid;
3643e5dd7070Spatrick }
3644e5dd7070Spatrick
3645e5dd7070Spatrick /// Some calls are okay.
VisitCallExpr(CallExpr * e)3646e5dd7070Spatrick ACCResult VisitCallExpr(CallExpr *e) {
3647e5dd7070Spatrick if (FunctionDecl *fn = e->getDirectCallee())
3648e5dd7070Spatrick if (ACCResult result = checkCallToFunction(fn))
3649e5dd7070Spatrick return result;
3650e5dd7070Spatrick
3651e5dd7070Spatrick return super::VisitCallExpr(e);
3652e5dd7070Spatrick }
3653e5dd7070Spatrick
checkCallToFunction(FunctionDecl * fn)3654e5dd7070Spatrick ACCResult checkCallToFunction(FunctionDecl *fn) {
3655e5dd7070Spatrick // Require a CF*Ref return type.
3656e5dd7070Spatrick if (!isCFType(fn->getReturnType()))
3657e5dd7070Spatrick return ACC_invalid;
3658e5dd7070Spatrick
3659e5dd7070Spatrick if (!isAnyRetainable(TargetClass))
3660e5dd7070Spatrick return ACC_invalid;
3661e5dd7070Spatrick
3662e5dd7070Spatrick // Honor an explicit 'not retained' attribute.
3663e5dd7070Spatrick if (fn->hasAttr<CFReturnsNotRetainedAttr>())
3664e5dd7070Spatrick return ACC_plusZero;
3665e5dd7070Spatrick
3666e5dd7070Spatrick // Honor an explicit 'retained' attribute, except that for
3667e5dd7070Spatrick // now we're not going to permit implicit handling of +1 results,
3668e5dd7070Spatrick // because it's a bit frightening.
3669e5dd7070Spatrick if (fn->hasAttr<CFReturnsRetainedAttr>())
3670e5dd7070Spatrick return Diagnose ? ACC_plusOne
3671e5dd7070Spatrick : ACC_invalid; // ACC_plusOne if we start accepting this
3672e5dd7070Spatrick
3673e5dd7070Spatrick // Recognize this specific builtin function, which is used by CFSTR.
3674e5dd7070Spatrick unsigned builtinID = fn->getBuiltinID();
3675e5dd7070Spatrick if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString)
3676e5dd7070Spatrick return ACC_bottom;
3677e5dd7070Spatrick
3678e5dd7070Spatrick // Otherwise, don't do anything implicit with an unaudited function.
3679e5dd7070Spatrick if (!fn->hasAttr<CFAuditedTransferAttr>())
3680e5dd7070Spatrick return ACC_invalid;
3681e5dd7070Spatrick
3682e5dd7070Spatrick // Otherwise, it's +0 unless it follows the create convention.
3683e5dd7070Spatrick if (ento::coreFoundation::followsCreateRule(fn))
3684e5dd7070Spatrick return Diagnose ? ACC_plusOne
3685e5dd7070Spatrick : ACC_invalid; // ACC_plusOne if we start accepting this
3686e5dd7070Spatrick
3687e5dd7070Spatrick return ACC_plusZero;
3688e5dd7070Spatrick }
3689e5dd7070Spatrick
VisitObjCMessageExpr(ObjCMessageExpr * e)3690e5dd7070Spatrick ACCResult VisitObjCMessageExpr(ObjCMessageExpr *e) {
3691e5dd7070Spatrick return checkCallToMethod(e->getMethodDecl());
3692e5dd7070Spatrick }
3693e5dd7070Spatrick
VisitObjCPropertyRefExpr(ObjCPropertyRefExpr * e)3694e5dd7070Spatrick ACCResult VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *e) {
3695e5dd7070Spatrick ObjCMethodDecl *method;
3696e5dd7070Spatrick if (e->isExplicitProperty())
3697e5dd7070Spatrick method = e->getExplicitProperty()->getGetterMethodDecl();
3698e5dd7070Spatrick else
3699e5dd7070Spatrick method = e->getImplicitPropertyGetter();
3700e5dd7070Spatrick return checkCallToMethod(method);
3701e5dd7070Spatrick }
3702e5dd7070Spatrick
checkCallToMethod(ObjCMethodDecl * method)3703e5dd7070Spatrick ACCResult checkCallToMethod(ObjCMethodDecl *method) {
3704e5dd7070Spatrick if (!method) return ACC_invalid;
3705e5dd7070Spatrick
3706e5dd7070Spatrick // Check for message sends to functions returning CF types. We
3707e5dd7070Spatrick // just obey the Cocoa conventions with these, even though the
3708e5dd7070Spatrick // return type is CF.
3709e5dd7070Spatrick if (!isAnyRetainable(TargetClass) || !isCFType(method->getReturnType()))
3710e5dd7070Spatrick return ACC_invalid;
3711e5dd7070Spatrick
3712e5dd7070Spatrick // If the method is explicitly marked not-retained, it's +0.
3713e5dd7070Spatrick if (method->hasAttr<CFReturnsNotRetainedAttr>())
3714e5dd7070Spatrick return ACC_plusZero;
3715e5dd7070Spatrick
3716e5dd7070Spatrick // If the method is explicitly marked as returning retained, or its
3717e5dd7070Spatrick // selector follows a +1 Cocoa convention, treat it as +1.
3718e5dd7070Spatrick if (method->hasAttr<CFReturnsRetainedAttr>())
3719e5dd7070Spatrick return ACC_plusOne;
3720e5dd7070Spatrick
3721e5dd7070Spatrick switch (method->getSelector().getMethodFamily()) {
3722e5dd7070Spatrick case OMF_alloc:
3723e5dd7070Spatrick case OMF_copy:
3724e5dd7070Spatrick case OMF_mutableCopy:
3725e5dd7070Spatrick case OMF_new:
3726e5dd7070Spatrick return ACC_plusOne;
3727e5dd7070Spatrick
3728e5dd7070Spatrick default:
3729e5dd7070Spatrick // Otherwise, treat it as +0.
3730e5dd7070Spatrick return ACC_plusZero;
3731e5dd7070Spatrick }
3732e5dd7070Spatrick }
3733e5dd7070Spatrick };
3734e5dd7070Spatrick } // end anonymous namespace
3735e5dd7070Spatrick
isKnownName(StringRef name)3736e5dd7070Spatrick bool Sema::isKnownName(StringRef name) {
3737e5dd7070Spatrick if (name.empty())
3738e5dd7070Spatrick return false;
3739e5dd7070Spatrick LookupResult R(*this, &Context.Idents.get(name), SourceLocation(),
3740e5dd7070Spatrick Sema::LookupOrdinaryName);
3741e5dd7070Spatrick return LookupName(R, TUScope, false);
3742e5dd7070Spatrick }
3743e5dd7070Spatrick
3744a9ac8606Spatrick template <typename DiagBuilderT>
addFixitForObjCARCConversion(Sema & S,DiagBuilderT & DiagB,Sema::CheckedConversionKind CCK,SourceLocation afterLParen,QualType castType,Expr * castExpr,Expr * realCast,const char * bridgeKeyword,const char * CFBridgeName)3745a9ac8606Spatrick static void addFixitForObjCARCConversion(
3746a9ac8606Spatrick Sema &S, DiagBuilderT &DiagB, Sema::CheckedConversionKind CCK,
3747a9ac8606Spatrick SourceLocation afterLParen, QualType castType, Expr *castExpr,
3748a9ac8606Spatrick Expr *realCast, const char *bridgeKeyword, const char *CFBridgeName) {
3749e5dd7070Spatrick // We handle C-style and implicit casts here.
3750e5dd7070Spatrick switch (CCK) {
3751e5dd7070Spatrick case Sema::CCK_ImplicitConversion:
3752e5dd7070Spatrick case Sema::CCK_ForBuiltinOverloadedOp:
3753e5dd7070Spatrick case Sema::CCK_CStyleCast:
3754e5dd7070Spatrick case Sema::CCK_OtherCast:
3755e5dd7070Spatrick break;
3756e5dd7070Spatrick case Sema::CCK_FunctionalCast:
3757e5dd7070Spatrick return;
3758e5dd7070Spatrick }
3759e5dd7070Spatrick
3760e5dd7070Spatrick if (CFBridgeName) {
3761e5dd7070Spatrick if (CCK == Sema::CCK_OtherCast) {
3762e5dd7070Spatrick if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
3763e5dd7070Spatrick SourceRange range(NCE->getOperatorLoc(),
3764e5dd7070Spatrick NCE->getAngleBrackets().getEnd());
3765e5dd7070Spatrick SmallString<32> BridgeCall;
3766e5dd7070Spatrick
3767e5dd7070Spatrick SourceManager &SM = S.getSourceManager();
3768e5dd7070Spatrick char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
3769*12c85518Srobert if (Lexer::isAsciiIdentifierContinueChar(PrevChar, S.getLangOpts()))
3770e5dd7070Spatrick BridgeCall += ' ';
3771e5dd7070Spatrick
3772e5dd7070Spatrick BridgeCall += CFBridgeName;
3773e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateReplacement(range, BridgeCall));
3774e5dd7070Spatrick }
3775e5dd7070Spatrick return;
3776e5dd7070Spatrick }
3777e5dd7070Spatrick Expr *castedE = castExpr;
3778e5dd7070Spatrick if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(castedE))
3779e5dd7070Spatrick castedE = CCE->getSubExpr();
3780e5dd7070Spatrick castedE = castedE->IgnoreImpCasts();
3781e5dd7070Spatrick SourceRange range = castedE->getSourceRange();
3782e5dd7070Spatrick
3783e5dd7070Spatrick SmallString<32> BridgeCall;
3784e5dd7070Spatrick
3785e5dd7070Spatrick SourceManager &SM = S.getSourceManager();
3786e5dd7070Spatrick char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
3787*12c85518Srobert if (Lexer::isAsciiIdentifierContinueChar(PrevChar, S.getLangOpts()))
3788e5dd7070Spatrick BridgeCall += ' ';
3789e5dd7070Spatrick
3790e5dd7070Spatrick BridgeCall += CFBridgeName;
3791e5dd7070Spatrick
3792e5dd7070Spatrick if (isa<ParenExpr>(castedE)) {
3793e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
3794e5dd7070Spatrick BridgeCall));
3795e5dd7070Spatrick } else {
3796e5dd7070Spatrick BridgeCall += '(';
3797e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
3798e5dd7070Spatrick BridgeCall));
3799e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateInsertion(
3800e5dd7070Spatrick S.getLocForEndOfToken(range.getEnd()),
3801e5dd7070Spatrick ")"));
3802e5dd7070Spatrick }
3803e5dd7070Spatrick return;
3804e5dd7070Spatrick }
3805e5dd7070Spatrick
3806e5dd7070Spatrick if (CCK == Sema::CCK_CStyleCast) {
3807e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateInsertion(afterLParen, bridgeKeyword));
3808e5dd7070Spatrick } else if (CCK == Sema::CCK_OtherCast) {
3809e5dd7070Spatrick if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
3810e5dd7070Spatrick std::string castCode = "(";
3811e5dd7070Spatrick castCode += bridgeKeyword;
3812e5dd7070Spatrick castCode += castType.getAsString();
3813e5dd7070Spatrick castCode += ")";
3814e5dd7070Spatrick SourceRange Range(NCE->getOperatorLoc(),
3815e5dd7070Spatrick NCE->getAngleBrackets().getEnd());
3816e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateReplacement(Range, castCode));
3817e5dd7070Spatrick }
3818e5dd7070Spatrick } else {
3819e5dd7070Spatrick std::string castCode = "(";
3820e5dd7070Spatrick castCode += bridgeKeyword;
3821e5dd7070Spatrick castCode += castType.getAsString();
3822e5dd7070Spatrick castCode += ")";
3823e5dd7070Spatrick Expr *castedE = castExpr->IgnoreImpCasts();
3824e5dd7070Spatrick SourceRange range = castedE->getSourceRange();
3825e5dd7070Spatrick if (isa<ParenExpr>(castedE)) {
3826e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
3827e5dd7070Spatrick castCode));
3828e5dd7070Spatrick } else {
3829e5dd7070Spatrick castCode += "(";
3830e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
3831e5dd7070Spatrick castCode));
3832e5dd7070Spatrick DiagB.AddFixItHint(FixItHint::CreateInsertion(
3833e5dd7070Spatrick S.getLocForEndOfToken(range.getEnd()),
3834e5dd7070Spatrick ")"));
3835e5dd7070Spatrick }
3836e5dd7070Spatrick }
3837e5dd7070Spatrick }
3838e5dd7070Spatrick
3839e5dd7070Spatrick template <typename T>
getObjCBridgeAttr(const TypedefType * TD)3840e5dd7070Spatrick static inline T *getObjCBridgeAttr(const TypedefType *TD) {
3841e5dd7070Spatrick TypedefNameDecl *TDNDecl = TD->getDecl();
3842e5dd7070Spatrick QualType QT = TDNDecl->getUnderlyingType();
3843e5dd7070Spatrick if (QT->isPointerType()) {
3844e5dd7070Spatrick QT = QT->getPointeeType();
3845a9ac8606Spatrick if (const RecordType *RT = QT->getAs<RecordType>()) {
3846a9ac8606Spatrick for (auto *Redecl : RT->getDecl()->getMostRecentDecl()->redecls()) {
3847a9ac8606Spatrick if (auto *attr = Redecl->getAttr<T>())
3848a9ac8606Spatrick return attr;
3849a9ac8606Spatrick }
3850a9ac8606Spatrick }
3851e5dd7070Spatrick }
3852e5dd7070Spatrick return nullptr;
3853e5dd7070Spatrick }
3854e5dd7070Spatrick
ObjCBridgeRelatedAttrFromType(QualType T,TypedefNameDecl * & TDNDecl)3855e5dd7070Spatrick static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T,
3856e5dd7070Spatrick TypedefNameDecl *&TDNDecl) {
3857*12c85518Srobert while (const auto *TD = T->getAs<TypedefType>()) {
3858e5dd7070Spatrick TDNDecl = TD->getDecl();
3859e5dd7070Spatrick if (ObjCBridgeRelatedAttr *ObjCBAttr =
3860e5dd7070Spatrick getObjCBridgeAttr<ObjCBridgeRelatedAttr>(TD))
3861e5dd7070Spatrick return ObjCBAttr;
3862e5dd7070Spatrick T = TDNDecl->getUnderlyingType();
3863e5dd7070Spatrick }
3864e5dd7070Spatrick return nullptr;
3865e5dd7070Spatrick }
3866e5dd7070Spatrick
3867e5dd7070Spatrick static void
diagnoseObjCARCConversion(Sema & S,SourceRange castRange,QualType castType,ARCConversionTypeClass castACTC,Expr * castExpr,Expr * realCast,ARCConversionTypeClass exprACTC,Sema::CheckedConversionKind CCK)3868e5dd7070Spatrick diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
3869e5dd7070Spatrick QualType castType, ARCConversionTypeClass castACTC,
3870e5dd7070Spatrick Expr *castExpr, Expr *realCast,
3871e5dd7070Spatrick ARCConversionTypeClass exprACTC,
3872e5dd7070Spatrick Sema::CheckedConversionKind CCK) {
3873e5dd7070Spatrick SourceLocation loc =
3874e5dd7070Spatrick (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
3875e5dd7070Spatrick
3876e5dd7070Spatrick if (S.makeUnavailableInSystemHeader(loc,
3877e5dd7070Spatrick UnavailableAttr::IR_ARCForbiddenConversion))
3878e5dd7070Spatrick return;
3879e5dd7070Spatrick
3880e5dd7070Spatrick QualType castExprType = castExpr->getType();
3881e5dd7070Spatrick // Defer emitting a diagnostic for bridge-related casts; that will be
3882e5dd7070Spatrick // handled by CheckObjCBridgeRelatedConversions.
3883e5dd7070Spatrick TypedefNameDecl *TDNDecl = nullptr;
3884e5dd7070Spatrick if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
3885e5dd7070Spatrick ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) ||
3886e5dd7070Spatrick (exprACTC == ACTC_coreFoundation && castACTC == ACTC_retainable &&
3887e5dd7070Spatrick ObjCBridgeRelatedAttrFromType(castExprType, TDNDecl)))
3888e5dd7070Spatrick return;
3889e5dd7070Spatrick
3890e5dd7070Spatrick unsigned srcKind = 0;
3891e5dd7070Spatrick switch (exprACTC) {
3892e5dd7070Spatrick case ACTC_none:
3893e5dd7070Spatrick case ACTC_coreFoundation:
3894e5dd7070Spatrick case ACTC_voidPtr:
3895e5dd7070Spatrick srcKind = (castExprType->isPointerType() ? 1 : 0);
3896e5dd7070Spatrick break;
3897e5dd7070Spatrick case ACTC_retainable:
3898e5dd7070Spatrick srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
3899e5dd7070Spatrick break;
3900e5dd7070Spatrick case ACTC_indirectRetainable:
3901e5dd7070Spatrick srcKind = 4;
3902e5dd7070Spatrick break;
3903e5dd7070Spatrick }
3904e5dd7070Spatrick
3905e5dd7070Spatrick // Check whether this could be fixed with a bridge cast.
3906e5dd7070Spatrick SourceLocation afterLParen = S.getLocForEndOfToken(castRange.getBegin());
3907e5dd7070Spatrick SourceLocation noteLoc = afterLParen.isValid() ? afterLParen : loc;
3908e5dd7070Spatrick
3909e5dd7070Spatrick unsigned convKindForDiag = Sema::isCast(CCK) ? 0 : 1;
3910e5dd7070Spatrick
3911e5dd7070Spatrick // Bridge from an ARC type to a CF type.
3912e5dd7070Spatrick if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) {
3913e5dd7070Spatrick
3914e5dd7070Spatrick S.Diag(loc, diag::err_arc_cast_requires_bridge)
3915e5dd7070Spatrick << convKindForDiag
3916e5dd7070Spatrick << 2 // of C pointer type
3917e5dd7070Spatrick << castExprType
3918e5dd7070Spatrick << unsigned(castType->isBlockPointerType()) // to ObjC|block type
3919e5dd7070Spatrick << castType
3920e5dd7070Spatrick << castRange
3921e5dd7070Spatrick << castExpr->getSourceRange();
3922e5dd7070Spatrick bool br = S.isKnownName("CFBridgingRelease");
3923e5dd7070Spatrick ACCResult CreateRule =
3924e5dd7070Spatrick ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr);
3925e5dd7070Spatrick assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
3926e5dd7070Spatrick if (CreateRule != ACC_plusOne)
3927e5dd7070Spatrick {
3928a9ac8606Spatrick auto DiagB = (CCK != Sema::CCK_OtherCast)
3929a9ac8606Spatrick ? S.Diag(noteLoc, diag::note_arc_bridge)
3930e5dd7070Spatrick : S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
3931e5dd7070Spatrick
3932e5dd7070Spatrick addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
3933e5dd7070Spatrick castType, castExpr, realCast, "__bridge ",
3934e5dd7070Spatrick nullptr);
3935e5dd7070Spatrick }
3936e5dd7070Spatrick if (CreateRule != ACC_plusZero)
3937e5dd7070Spatrick {
3938a9ac8606Spatrick auto DiagB = (CCK == Sema::CCK_OtherCast && !br)
3939a9ac8606Spatrick ? S.Diag(noteLoc, diag::note_arc_cstyle_bridge_transfer)
3940a9ac8606Spatrick << castExprType
3941a9ac8606Spatrick : S.Diag(br ? castExpr->getExprLoc() : noteLoc,
3942e5dd7070Spatrick diag::note_arc_bridge_transfer)
3943e5dd7070Spatrick << castExprType << br;
3944e5dd7070Spatrick
3945e5dd7070Spatrick addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
3946e5dd7070Spatrick castType, castExpr, realCast, "__bridge_transfer ",
3947e5dd7070Spatrick br ? "CFBridgingRelease" : nullptr);
3948e5dd7070Spatrick }
3949e5dd7070Spatrick
3950e5dd7070Spatrick return;
3951e5dd7070Spatrick }
3952e5dd7070Spatrick
3953e5dd7070Spatrick // Bridge from a CF type to an ARC type.
3954e5dd7070Spatrick if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) {
3955e5dd7070Spatrick bool br = S.isKnownName("CFBridgingRetain");
3956e5dd7070Spatrick S.Diag(loc, diag::err_arc_cast_requires_bridge)
3957e5dd7070Spatrick << convKindForDiag
3958e5dd7070Spatrick << unsigned(castExprType->isBlockPointerType()) // of ObjC|block type
3959e5dd7070Spatrick << castExprType
3960e5dd7070Spatrick << 2 // to C pointer type
3961e5dd7070Spatrick << castType
3962e5dd7070Spatrick << castRange
3963e5dd7070Spatrick << castExpr->getSourceRange();
3964e5dd7070Spatrick ACCResult CreateRule =
3965e5dd7070Spatrick ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr);
3966e5dd7070Spatrick assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
3967e5dd7070Spatrick if (CreateRule != ACC_plusOne)
3968e5dd7070Spatrick {
3969a9ac8606Spatrick auto DiagB = (CCK != Sema::CCK_OtherCast)
3970a9ac8606Spatrick ? S.Diag(noteLoc, diag::note_arc_bridge)
3971e5dd7070Spatrick : S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
3972e5dd7070Spatrick addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
3973e5dd7070Spatrick castType, castExpr, realCast, "__bridge ",
3974e5dd7070Spatrick nullptr);
3975e5dd7070Spatrick }
3976e5dd7070Spatrick if (CreateRule != ACC_plusZero)
3977e5dd7070Spatrick {
3978a9ac8606Spatrick auto DiagB = (CCK == Sema::CCK_OtherCast && !br)
3979a9ac8606Spatrick ? S.Diag(noteLoc, diag::note_arc_cstyle_bridge_retained)
3980a9ac8606Spatrick << castType
3981a9ac8606Spatrick : S.Diag(br ? castExpr->getExprLoc() : noteLoc,
3982e5dd7070Spatrick diag::note_arc_bridge_retained)
3983e5dd7070Spatrick << castType << br;
3984e5dd7070Spatrick
3985e5dd7070Spatrick addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
3986e5dd7070Spatrick castType, castExpr, realCast, "__bridge_retained ",
3987e5dd7070Spatrick br ? "CFBridgingRetain" : nullptr);
3988e5dd7070Spatrick }
3989e5dd7070Spatrick
3990e5dd7070Spatrick return;
3991e5dd7070Spatrick }
3992e5dd7070Spatrick
3993e5dd7070Spatrick S.Diag(loc, diag::err_arc_mismatched_cast)
3994e5dd7070Spatrick << !convKindForDiag
3995e5dd7070Spatrick << srcKind << castExprType << castType
3996e5dd7070Spatrick << castRange << castExpr->getSourceRange();
3997e5dd7070Spatrick }
3998e5dd7070Spatrick
3999e5dd7070Spatrick template <typename TB>
CheckObjCBridgeNSCast(Sema & S,QualType castType,Expr * castExpr,bool & HadTheAttribute,bool warn)4000e5dd7070Spatrick static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr,
4001e5dd7070Spatrick bool &HadTheAttribute, bool warn) {
4002e5dd7070Spatrick QualType T = castExpr->getType();
4003e5dd7070Spatrick HadTheAttribute = false;
4004*12c85518Srobert while (const auto *TD = T->getAs<TypedefType>()) {
4005e5dd7070Spatrick TypedefNameDecl *TDNDecl = TD->getDecl();
4006e5dd7070Spatrick if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
4007e5dd7070Spatrick if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
4008e5dd7070Spatrick HadTheAttribute = true;
4009e5dd7070Spatrick if (Parm->isStr("id"))
4010e5dd7070Spatrick return true;
4011e5dd7070Spatrick
4012e5dd7070Spatrick // Check for an existing type with this name.
4013e5dd7070Spatrick LookupResult R(S, DeclarationName(Parm), SourceLocation(),
4014e5dd7070Spatrick Sema::LookupOrdinaryName);
4015e5dd7070Spatrick if (S.LookupName(R, S.TUScope)) {
4016*12c85518Srobert NamedDecl *Target = R.getFoundDecl();
4017e5dd7070Spatrick if (Target && isa<ObjCInterfaceDecl>(Target)) {
4018e5dd7070Spatrick ObjCInterfaceDecl *ExprClass = cast<ObjCInterfaceDecl>(Target);
4019e5dd7070Spatrick if (const ObjCObjectPointerType *InterfacePointerType =
4020e5dd7070Spatrick castType->getAsObjCInterfacePointerType()) {
4021e5dd7070Spatrick ObjCInterfaceDecl *CastClass
4022e5dd7070Spatrick = InterfacePointerType->getObjectType()->getInterface();
4023e5dd7070Spatrick if ((CastClass == ExprClass) ||
4024e5dd7070Spatrick (CastClass && CastClass->isSuperClassOf(ExprClass)))
4025e5dd7070Spatrick return true;
4026e5dd7070Spatrick if (warn)
4027e5dd7070Spatrick S.Diag(castExpr->getBeginLoc(), diag::warn_objc_invalid_bridge)
4028e5dd7070Spatrick << T << Target->getName() << castType->getPointeeType();
4029e5dd7070Spatrick return false;
4030e5dd7070Spatrick } else if (castType->isObjCIdType() ||
4031e5dd7070Spatrick (S.Context.ObjCObjectAdoptsQTypeProtocols(
4032e5dd7070Spatrick castType, ExprClass)))
4033e5dd7070Spatrick // ok to cast to 'id'.
4034e5dd7070Spatrick // casting to id<p-list> is ok if bridge type adopts all of
4035e5dd7070Spatrick // p-list protocols.
4036e5dd7070Spatrick return true;
4037e5dd7070Spatrick else {
4038e5dd7070Spatrick if (warn) {
4039e5dd7070Spatrick S.Diag(castExpr->getBeginLoc(), diag::warn_objc_invalid_bridge)
4040e5dd7070Spatrick << T << Target->getName() << castType;
4041e5dd7070Spatrick S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4042e5dd7070Spatrick S.Diag(Target->getBeginLoc(), diag::note_declared_at);
4043e5dd7070Spatrick }
4044e5dd7070Spatrick return false;
4045e5dd7070Spatrick }
4046e5dd7070Spatrick }
4047e5dd7070Spatrick } else if (!castType->isObjCIdType()) {
4048e5dd7070Spatrick S.Diag(castExpr->getBeginLoc(),
4049e5dd7070Spatrick diag::err_objc_cf_bridged_not_interface)
4050e5dd7070Spatrick << castExpr->getType() << Parm;
4051e5dd7070Spatrick S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4052e5dd7070Spatrick }
4053e5dd7070Spatrick return true;
4054e5dd7070Spatrick }
4055e5dd7070Spatrick return false;
4056e5dd7070Spatrick }
4057e5dd7070Spatrick T = TDNDecl->getUnderlyingType();
4058e5dd7070Spatrick }
4059e5dd7070Spatrick return true;
4060e5dd7070Spatrick }
4061e5dd7070Spatrick
4062e5dd7070Spatrick template <typename TB>
CheckObjCBridgeCFCast(Sema & S,QualType castType,Expr * castExpr,bool & HadTheAttribute,bool warn)4063e5dd7070Spatrick static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr,
4064e5dd7070Spatrick bool &HadTheAttribute, bool warn) {
4065e5dd7070Spatrick QualType T = castType;
4066e5dd7070Spatrick HadTheAttribute = false;
4067*12c85518Srobert while (const auto *TD = T->getAs<TypedefType>()) {
4068e5dd7070Spatrick TypedefNameDecl *TDNDecl = TD->getDecl();
4069e5dd7070Spatrick if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
4070e5dd7070Spatrick if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
4071e5dd7070Spatrick HadTheAttribute = true;
4072e5dd7070Spatrick if (Parm->isStr("id"))
4073e5dd7070Spatrick return true;
4074e5dd7070Spatrick
4075e5dd7070Spatrick NamedDecl *Target = nullptr;
4076e5dd7070Spatrick // Check for an existing type with this name.
4077e5dd7070Spatrick LookupResult R(S, DeclarationName(Parm), SourceLocation(),
4078e5dd7070Spatrick Sema::LookupOrdinaryName);
4079e5dd7070Spatrick if (S.LookupName(R, S.TUScope)) {
4080e5dd7070Spatrick Target = R.getFoundDecl();
4081e5dd7070Spatrick if (Target && isa<ObjCInterfaceDecl>(Target)) {
4082e5dd7070Spatrick ObjCInterfaceDecl *CastClass = cast<ObjCInterfaceDecl>(Target);
4083e5dd7070Spatrick if (const ObjCObjectPointerType *InterfacePointerType =
4084e5dd7070Spatrick castExpr->getType()->getAsObjCInterfacePointerType()) {
4085e5dd7070Spatrick ObjCInterfaceDecl *ExprClass
4086e5dd7070Spatrick = InterfacePointerType->getObjectType()->getInterface();
4087e5dd7070Spatrick if ((CastClass == ExprClass) ||
4088e5dd7070Spatrick (ExprClass && CastClass->isSuperClassOf(ExprClass)))
4089e5dd7070Spatrick return true;
4090e5dd7070Spatrick if (warn) {
4091e5dd7070Spatrick S.Diag(castExpr->getBeginLoc(),
4092e5dd7070Spatrick diag::warn_objc_invalid_bridge_to_cf)
4093e5dd7070Spatrick << castExpr->getType()->getPointeeType() << T;
4094e5dd7070Spatrick S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4095e5dd7070Spatrick }
4096e5dd7070Spatrick return false;
4097e5dd7070Spatrick } else if (castExpr->getType()->isObjCIdType() ||
4098e5dd7070Spatrick (S.Context.QIdProtocolsAdoptObjCObjectProtocols(
4099e5dd7070Spatrick castExpr->getType(), CastClass)))
4100e5dd7070Spatrick // ok to cast an 'id' expression to a CFtype.
4101e5dd7070Spatrick // ok to cast an 'id<plist>' expression to CFtype provided plist
4102e5dd7070Spatrick // adopts all of CFtype's ObjetiveC's class plist.
4103e5dd7070Spatrick return true;
4104e5dd7070Spatrick else {
4105e5dd7070Spatrick if (warn) {
4106e5dd7070Spatrick S.Diag(castExpr->getBeginLoc(),
4107e5dd7070Spatrick diag::warn_objc_invalid_bridge_to_cf)
4108e5dd7070Spatrick << castExpr->getType() << castType;
4109e5dd7070Spatrick S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4110e5dd7070Spatrick S.Diag(Target->getBeginLoc(), diag::note_declared_at);
4111e5dd7070Spatrick }
4112e5dd7070Spatrick return false;
4113e5dd7070Spatrick }
4114e5dd7070Spatrick }
4115e5dd7070Spatrick }
4116e5dd7070Spatrick S.Diag(castExpr->getBeginLoc(),
4117e5dd7070Spatrick diag::err_objc_ns_bridged_invalid_cfobject)
4118e5dd7070Spatrick << castExpr->getType() << castType;
4119e5dd7070Spatrick S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4120e5dd7070Spatrick if (Target)
4121e5dd7070Spatrick S.Diag(Target->getBeginLoc(), diag::note_declared_at);
4122e5dd7070Spatrick return true;
4123e5dd7070Spatrick }
4124e5dd7070Spatrick return false;
4125e5dd7070Spatrick }
4126e5dd7070Spatrick T = TDNDecl->getUnderlyingType();
4127e5dd7070Spatrick }
4128e5dd7070Spatrick return true;
4129e5dd7070Spatrick }
4130e5dd7070Spatrick
CheckTollFreeBridgeCast(QualType castType,Expr * castExpr)4131e5dd7070Spatrick void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) {
4132e5dd7070Spatrick if (!getLangOpts().ObjC)
4133e5dd7070Spatrick return;
4134e5dd7070Spatrick // warn in presence of __bridge casting to or from a toll free bridge cast.
4135e5dd7070Spatrick ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType());
4136e5dd7070Spatrick ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
4137e5dd7070Spatrick if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) {
4138e5dd7070Spatrick bool HasObjCBridgeAttr;
4139e5dd7070Spatrick bool ObjCBridgeAttrWillNotWarn =
4140e5dd7070Spatrick CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
4141e5dd7070Spatrick false);
4142e5dd7070Spatrick if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr)
4143e5dd7070Spatrick return;
4144e5dd7070Spatrick bool HasObjCBridgeMutableAttr;
4145e5dd7070Spatrick bool ObjCBridgeMutableAttrWillNotWarn =
4146e5dd7070Spatrick CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
4147e5dd7070Spatrick HasObjCBridgeMutableAttr, false);
4148e5dd7070Spatrick if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr)
4149e5dd7070Spatrick return;
4150e5dd7070Spatrick
4151e5dd7070Spatrick if (HasObjCBridgeAttr)
4152e5dd7070Spatrick CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
4153e5dd7070Spatrick true);
4154e5dd7070Spatrick else if (HasObjCBridgeMutableAttr)
4155e5dd7070Spatrick CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
4156e5dd7070Spatrick HasObjCBridgeMutableAttr, true);
4157e5dd7070Spatrick }
4158e5dd7070Spatrick else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) {
4159e5dd7070Spatrick bool HasObjCBridgeAttr;
4160e5dd7070Spatrick bool ObjCBridgeAttrWillNotWarn =
4161e5dd7070Spatrick CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
4162e5dd7070Spatrick false);
4163e5dd7070Spatrick if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr)
4164e5dd7070Spatrick return;
4165e5dd7070Spatrick bool HasObjCBridgeMutableAttr;
4166e5dd7070Spatrick bool ObjCBridgeMutableAttrWillNotWarn =
4167e5dd7070Spatrick CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
4168e5dd7070Spatrick HasObjCBridgeMutableAttr, false);
4169e5dd7070Spatrick if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr)
4170e5dd7070Spatrick return;
4171e5dd7070Spatrick
4172e5dd7070Spatrick if (HasObjCBridgeAttr)
4173e5dd7070Spatrick CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
4174e5dd7070Spatrick true);
4175e5dd7070Spatrick else if (HasObjCBridgeMutableAttr)
4176e5dd7070Spatrick CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
4177e5dd7070Spatrick HasObjCBridgeMutableAttr, true);
4178e5dd7070Spatrick }
4179e5dd7070Spatrick }
4180e5dd7070Spatrick
CheckObjCBridgeRelatedCast(QualType castType,Expr * castExpr)4181e5dd7070Spatrick void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) {
4182e5dd7070Spatrick QualType SrcType = castExpr->getType();
4183e5dd7070Spatrick if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(castExpr)) {
4184e5dd7070Spatrick if (PRE->isExplicitProperty()) {
4185e5dd7070Spatrick if (ObjCPropertyDecl *PDecl = PRE->getExplicitProperty())
4186e5dd7070Spatrick SrcType = PDecl->getType();
4187e5dd7070Spatrick }
4188e5dd7070Spatrick else if (PRE->isImplicitProperty()) {
4189e5dd7070Spatrick if (ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter())
4190e5dd7070Spatrick SrcType = Getter->getReturnType();
4191e5dd7070Spatrick }
4192e5dd7070Spatrick }
4193e5dd7070Spatrick
4194e5dd7070Spatrick ARCConversionTypeClass srcExprACTC = classifyTypeForARCConversion(SrcType);
4195e5dd7070Spatrick ARCConversionTypeClass castExprACTC = classifyTypeForARCConversion(castType);
4196e5dd7070Spatrick if (srcExprACTC != ACTC_retainable || castExprACTC != ACTC_coreFoundation)
4197e5dd7070Spatrick return;
4198e5dd7070Spatrick CheckObjCBridgeRelatedConversions(castExpr->getBeginLoc(), castType, SrcType,
4199e5dd7070Spatrick castExpr);
4200e5dd7070Spatrick }
4201e5dd7070Spatrick
CheckTollFreeBridgeStaticCast(QualType castType,Expr * castExpr,CastKind & Kind)4202e5dd7070Spatrick bool Sema::CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr,
4203e5dd7070Spatrick CastKind &Kind) {
4204e5dd7070Spatrick if (!getLangOpts().ObjC)
4205e5dd7070Spatrick return false;
4206e5dd7070Spatrick ARCConversionTypeClass exprACTC =
4207e5dd7070Spatrick classifyTypeForARCConversion(castExpr->getType());
4208e5dd7070Spatrick ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
4209e5dd7070Spatrick if ((castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) ||
4210e5dd7070Spatrick (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable)) {
4211e5dd7070Spatrick CheckTollFreeBridgeCast(castType, castExpr);
4212e5dd7070Spatrick Kind = (castACTC == ACTC_coreFoundation) ? CK_BitCast
4213e5dd7070Spatrick : CK_CPointerToObjCPointerCast;
4214e5dd7070Spatrick return true;
4215e5dd7070Spatrick }
4216e5dd7070Spatrick return false;
4217e5dd7070Spatrick }
4218e5dd7070Spatrick
checkObjCBridgeRelatedComponents(SourceLocation Loc,QualType DestType,QualType SrcType,ObjCInterfaceDecl * & RelatedClass,ObjCMethodDecl * & ClassMethod,ObjCMethodDecl * & InstanceMethod,TypedefNameDecl * & TDNDecl,bool CfToNs,bool Diagnose)4219e5dd7070Spatrick bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
4220e5dd7070Spatrick QualType DestType, QualType SrcType,
4221e5dd7070Spatrick ObjCInterfaceDecl *&RelatedClass,
4222e5dd7070Spatrick ObjCMethodDecl *&ClassMethod,
4223e5dd7070Spatrick ObjCMethodDecl *&InstanceMethod,
4224e5dd7070Spatrick TypedefNameDecl *&TDNDecl,
4225e5dd7070Spatrick bool CfToNs, bool Diagnose) {
4226e5dd7070Spatrick QualType T = CfToNs ? SrcType : DestType;
4227e5dd7070Spatrick ObjCBridgeRelatedAttr *ObjCBAttr = ObjCBridgeRelatedAttrFromType(T, TDNDecl);
4228e5dd7070Spatrick if (!ObjCBAttr)
4229e5dd7070Spatrick return false;
4230e5dd7070Spatrick
4231e5dd7070Spatrick IdentifierInfo *RCId = ObjCBAttr->getRelatedClass();
4232e5dd7070Spatrick IdentifierInfo *CMId = ObjCBAttr->getClassMethod();
4233e5dd7070Spatrick IdentifierInfo *IMId = ObjCBAttr->getInstanceMethod();
4234e5dd7070Spatrick if (!RCId)
4235e5dd7070Spatrick return false;
4236e5dd7070Spatrick NamedDecl *Target = nullptr;
4237e5dd7070Spatrick // Check for an existing type with this name.
4238e5dd7070Spatrick LookupResult R(*this, DeclarationName(RCId), SourceLocation(),
4239e5dd7070Spatrick Sema::LookupOrdinaryName);
4240e5dd7070Spatrick if (!LookupName(R, TUScope)) {
4241e5dd7070Spatrick if (Diagnose) {
4242e5dd7070Spatrick Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId
4243e5dd7070Spatrick << SrcType << DestType;
4244e5dd7070Spatrick Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4245e5dd7070Spatrick }
4246e5dd7070Spatrick return false;
4247e5dd7070Spatrick }
4248e5dd7070Spatrick Target = R.getFoundDecl();
4249e5dd7070Spatrick if (Target && isa<ObjCInterfaceDecl>(Target))
4250e5dd7070Spatrick RelatedClass = cast<ObjCInterfaceDecl>(Target);
4251e5dd7070Spatrick else {
4252e5dd7070Spatrick if (Diagnose) {
4253e5dd7070Spatrick Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId
4254e5dd7070Spatrick << SrcType << DestType;
4255e5dd7070Spatrick Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4256e5dd7070Spatrick if (Target)
4257e5dd7070Spatrick Diag(Target->getBeginLoc(), diag::note_declared_at);
4258e5dd7070Spatrick }
4259e5dd7070Spatrick return false;
4260e5dd7070Spatrick }
4261e5dd7070Spatrick
4262e5dd7070Spatrick // Check for an existing class method with the given selector name.
4263e5dd7070Spatrick if (CfToNs && CMId) {
4264e5dd7070Spatrick Selector Sel = Context.Selectors.getUnarySelector(CMId);
4265e5dd7070Spatrick ClassMethod = RelatedClass->lookupMethod(Sel, false);
4266e5dd7070Spatrick if (!ClassMethod) {
4267e5dd7070Spatrick if (Diagnose) {
4268e5dd7070Spatrick Diag(Loc, diag::err_objc_bridged_related_known_method)
4269e5dd7070Spatrick << SrcType << DestType << Sel << false;
4270e5dd7070Spatrick Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4271e5dd7070Spatrick }
4272e5dd7070Spatrick return false;
4273e5dd7070Spatrick }
4274e5dd7070Spatrick }
4275e5dd7070Spatrick
4276e5dd7070Spatrick // Check for an existing instance method with the given selector name.
4277e5dd7070Spatrick if (!CfToNs && IMId) {
4278e5dd7070Spatrick Selector Sel = Context.Selectors.getNullarySelector(IMId);
4279e5dd7070Spatrick InstanceMethod = RelatedClass->lookupMethod(Sel, true);
4280e5dd7070Spatrick if (!InstanceMethod) {
4281e5dd7070Spatrick if (Diagnose) {
4282e5dd7070Spatrick Diag(Loc, diag::err_objc_bridged_related_known_method)
4283e5dd7070Spatrick << SrcType << DestType << Sel << true;
4284e5dd7070Spatrick Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4285e5dd7070Spatrick }
4286e5dd7070Spatrick return false;
4287e5dd7070Spatrick }
4288e5dd7070Spatrick }
4289e5dd7070Spatrick return true;
4290e5dd7070Spatrick }
4291e5dd7070Spatrick
4292e5dd7070Spatrick bool
CheckObjCBridgeRelatedConversions(SourceLocation Loc,QualType DestType,QualType SrcType,Expr * & SrcExpr,bool Diagnose)4293e5dd7070Spatrick Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
4294e5dd7070Spatrick QualType DestType, QualType SrcType,
4295e5dd7070Spatrick Expr *&SrcExpr, bool Diagnose) {
4296e5dd7070Spatrick ARCConversionTypeClass rhsExprACTC = classifyTypeForARCConversion(SrcType);
4297e5dd7070Spatrick ARCConversionTypeClass lhsExprACTC = classifyTypeForARCConversion(DestType);
4298e5dd7070Spatrick bool CfToNs = (rhsExprACTC == ACTC_coreFoundation && lhsExprACTC == ACTC_retainable);
4299e5dd7070Spatrick bool NsToCf = (rhsExprACTC == ACTC_retainable && lhsExprACTC == ACTC_coreFoundation);
4300e5dd7070Spatrick if (!CfToNs && !NsToCf)
4301e5dd7070Spatrick return false;
4302e5dd7070Spatrick
4303e5dd7070Spatrick ObjCInterfaceDecl *RelatedClass;
4304e5dd7070Spatrick ObjCMethodDecl *ClassMethod = nullptr;
4305e5dd7070Spatrick ObjCMethodDecl *InstanceMethod = nullptr;
4306e5dd7070Spatrick TypedefNameDecl *TDNDecl = nullptr;
4307e5dd7070Spatrick if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass,
4308e5dd7070Spatrick ClassMethod, InstanceMethod, TDNDecl,
4309e5dd7070Spatrick CfToNs, Diagnose))
4310e5dd7070Spatrick return false;
4311e5dd7070Spatrick
4312e5dd7070Spatrick if (CfToNs) {
4313e5dd7070Spatrick // Implicit conversion from CF to ObjC object is needed.
4314e5dd7070Spatrick if (ClassMethod) {
4315e5dd7070Spatrick if (Diagnose) {
4316e5dd7070Spatrick std::string ExpressionString = "[";
4317e5dd7070Spatrick ExpressionString += RelatedClass->getNameAsString();
4318e5dd7070Spatrick ExpressionString += " ";
4319e5dd7070Spatrick ExpressionString += ClassMethod->getSelector().getAsString();
4320e5dd7070Spatrick SourceLocation SrcExprEndLoc =
4321e5dd7070Spatrick getLocForEndOfToken(SrcExpr->getEndLoc());
4322e5dd7070Spatrick // Provide a fixit: [RelatedClass ClassMethod SrcExpr]
4323e5dd7070Spatrick Diag(Loc, diag::err_objc_bridged_related_known_method)
4324e5dd7070Spatrick << SrcType << DestType << ClassMethod->getSelector() << false
4325e5dd7070Spatrick << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(),
4326e5dd7070Spatrick ExpressionString)
4327e5dd7070Spatrick << FixItHint::CreateInsertion(SrcExprEndLoc, "]");
4328e5dd7070Spatrick Diag(RelatedClass->getBeginLoc(), diag::note_declared_at);
4329e5dd7070Spatrick Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4330e5dd7070Spatrick
4331e5dd7070Spatrick QualType receiverType = Context.getObjCInterfaceType(RelatedClass);
4332e5dd7070Spatrick // Argument.
4333e5dd7070Spatrick Expr *args[] = { SrcExpr };
4334e5dd7070Spatrick ExprResult msg = BuildClassMessageImplicit(receiverType, false,
4335e5dd7070Spatrick ClassMethod->getLocation(),
4336e5dd7070Spatrick ClassMethod->getSelector(), ClassMethod,
4337e5dd7070Spatrick MultiExprArg(args, 1));
4338e5dd7070Spatrick SrcExpr = msg.get();
4339e5dd7070Spatrick }
4340e5dd7070Spatrick return true;
4341e5dd7070Spatrick }
4342e5dd7070Spatrick }
4343e5dd7070Spatrick else {
4344e5dd7070Spatrick // Implicit conversion from ObjC type to CF object is needed.
4345e5dd7070Spatrick if (InstanceMethod) {
4346e5dd7070Spatrick if (Diagnose) {
4347e5dd7070Spatrick std::string ExpressionString;
4348e5dd7070Spatrick SourceLocation SrcExprEndLoc =
4349e5dd7070Spatrick getLocForEndOfToken(SrcExpr->getEndLoc());
4350e5dd7070Spatrick if (InstanceMethod->isPropertyAccessor())
4351e5dd7070Spatrick if (const ObjCPropertyDecl *PDecl =
4352e5dd7070Spatrick InstanceMethod->findPropertyDecl()) {
4353e5dd7070Spatrick // fixit: ObjectExpr.propertyname when it is aproperty accessor.
4354e5dd7070Spatrick ExpressionString = ".";
4355e5dd7070Spatrick ExpressionString += PDecl->getNameAsString();
4356e5dd7070Spatrick Diag(Loc, diag::err_objc_bridged_related_known_method)
4357e5dd7070Spatrick << SrcType << DestType << InstanceMethod->getSelector() << true
4358e5dd7070Spatrick << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
4359e5dd7070Spatrick }
4360e5dd7070Spatrick if (ExpressionString.empty()) {
4361e5dd7070Spatrick // Provide a fixit: [ObjectExpr InstanceMethod]
4362e5dd7070Spatrick ExpressionString = " ";
4363e5dd7070Spatrick ExpressionString += InstanceMethod->getSelector().getAsString();
4364e5dd7070Spatrick ExpressionString += "]";
4365e5dd7070Spatrick
4366e5dd7070Spatrick Diag(Loc, diag::err_objc_bridged_related_known_method)
4367e5dd7070Spatrick << SrcType << DestType << InstanceMethod->getSelector() << true
4368e5dd7070Spatrick << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(), "[")
4369e5dd7070Spatrick << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
4370e5dd7070Spatrick }
4371e5dd7070Spatrick Diag(RelatedClass->getBeginLoc(), diag::note_declared_at);
4372e5dd7070Spatrick Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
4373e5dd7070Spatrick
4374*12c85518Srobert ExprResult msg = BuildInstanceMessageImplicit(
4375*12c85518Srobert SrcExpr, SrcType, InstanceMethod->getLocation(),
4376*12c85518Srobert InstanceMethod->getSelector(), InstanceMethod, std::nullopt);
4377e5dd7070Spatrick SrcExpr = msg.get();
4378e5dd7070Spatrick }
4379e5dd7070Spatrick return true;
4380e5dd7070Spatrick }
4381e5dd7070Spatrick }
4382e5dd7070Spatrick return false;
4383e5dd7070Spatrick }
4384e5dd7070Spatrick
4385e5dd7070Spatrick Sema::ARCConversionResult
CheckObjCConversion(SourceRange castRange,QualType castType,Expr * & castExpr,CheckedConversionKind CCK,bool Diagnose,bool DiagnoseCFAudited,BinaryOperatorKind Opc)4386e5dd7070Spatrick Sema::CheckObjCConversion(SourceRange castRange, QualType castType,
4387e5dd7070Spatrick Expr *&castExpr, CheckedConversionKind CCK,
4388e5dd7070Spatrick bool Diagnose, bool DiagnoseCFAudited,
4389e5dd7070Spatrick BinaryOperatorKind Opc) {
4390e5dd7070Spatrick QualType castExprType = castExpr->getType();
4391e5dd7070Spatrick
4392e5dd7070Spatrick // For the purposes of the classification, we assume reference types
4393e5dd7070Spatrick // will bind to temporaries.
4394e5dd7070Spatrick QualType effCastType = castType;
4395e5dd7070Spatrick if (const ReferenceType *ref = castType->getAs<ReferenceType>())
4396e5dd7070Spatrick effCastType = ref->getPointeeType();
4397e5dd7070Spatrick
4398e5dd7070Spatrick ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
4399e5dd7070Spatrick ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType);
4400e5dd7070Spatrick if (exprACTC == castACTC) {
4401e5dd7070Spatrick // Check for viability and report error if casting an rvalue to a
4402e5dd7070Spatrick // life-time qualifier.
4403e5dd7070Spatrick if (castACTC == ACTC_retainable &&
4404e5dd7070Spatrick (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) &&
4405e5dd7070Spatrick castType != castExprType) {
4406e5dd7070Spatrick const Type *DT = castType.getTypePtr();
4407e5dd7070Spatrick QualType QDT = castType;
4408e5dd7070Spatrick // We desugar some types but not others. We ignore those
4409e5dd7070Spatrick // that cannot happen in a cast; i.e. auto, and those which
4410e5dd7070Spatrick // should not be de-sugared; i.e typedef.
4411e5dd7070Spatrick if (const ParenType *PT = dyn_cast<ParenType>(DT))
4412e5dd7070Spatrick QDT = PT->desugar();
4413e5dd7070Spatrick else if (const TypeOfType *TP = dyn_cast<TypeOfType>(DT))
4414e5dd7070Spatrick QDT = TP->desugar();
4415e5dd7070Spatrick else if (const AttributedType *AT = dyn_cast<AttributedType>(DT))
4416e5dd7070Spatrick QDT = AT->desugar();
4417e5dd7070Spatrick if (QDT != castType &&
4418e5dd7070Spatrick QDT.getObjCLifetime() != Qualifiers::OCL_None) {
4419e5dd7070Spatrick if (Diagnose) {
4420e5dd7070Spatrick SourceLocation loc = (castRange.isValid() ? castRange.getBegin()
4421e5dd7070Spatrick : castExpr->getExprLoc());
4422e5dd7070Spatrick Diag(loc, diag::err_arc_nolifetime_behavior);
4423e5dd7070Spatrick }
4424e5dd7070Spatrick return ACR_error;
4425e5dd7070Spatrick }
4426e5dd7070Spatrick }
4427e5dd7070Spatrick return ACR_okay;
4428e5dd7070Spatrick }
4429e5dd7070Spatrick
4430e5dd7070Spatrick // The life-time qualifier cast check above is all we need for ObjCWeak.
4431e5dd7070Spatrick // ObjCAutoRefCount has more restrictions on what is legal.
4432e5dd7070Spatrick if (!getLangOpts().ObjCAutoRefCount)
4433e5dd7070Spatrick return ACR_okay;
4434e5dd7070Spatrick
4435e5dd7070Spatrick if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return ACR_okay;
4436e5dd7070Spatrick
4437e5dd7070Spatrick // Allow all of these types to be cast to integer types (but not
4438e5dd7070Spatrick // vice-versa).
4439e5dd7070Spatrick if (castACTC == ACTC_none && castType->isIntegralType(Context))
4440e5dd7070Spatrick return ACR_okay;
4441e5dd7070Spatrick
4442e5dd7070Spatrick // Allow casts between pointers to lifetime types (e.g., __strong id*)
4443e5dd7070Spatrick // and pointers to void (e.g., cv void *). Casting from void* to lifetime*
4444e5dd7070Spatrick // must be explicit.
4445*12c85518Srobert // Allow conversions between pointers to lifetime types and coreFoundation
4446*12c85518Srobert // pointers too, but only when the conversions are explicit.
4447*12c85518Srobert if (exprACTC == ACTC_indirectRetainable &&
4448*12c85518Srobert (castACTC == ACTC_voidPtr ||
4449*12c85518Srobert (castACTC == ACTC_coreFoundation && isCast(CCK))))
4450e5dd7070Spatrick return ACR_okay;
4451*12c85518Srobert if (castACTC == ACTC_indirectRetainable &&
4452*12c85518Srobert (exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) &&
4453e5dd7070Spatrick isCast(CCK))
4454e5dd7070Spatrick return ACR_okay;
4455e5dd7070Spatrick
4456e5dd7070Spatrick switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) {
4457e5dd7070Spatrick // For invalid casts, fall through.
4458e5dd7070Spatrick case ACC_invalid:
4459e5dd7070Spatrick break;
4460e5dd7070Spatrick
4461e5dd7070Spatrick // Do nothing for both bottom and +0.
4462e5dd7070Spatrick case ACC_bottom:
4463e5dd7070Spatrick case ACC_plusZero:
4464e5dd7070Spatrick return ACR_okay;
4465e5dd7070Spatrick
4466e5dd7070Spatrick // If the result is +1, consume it here.
4467e5dd7070Spatrick case ACC_plusOne:
4468e5dd7070Spatrick castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(),
4469a9ac8606Spatrick CK_ARCConsumeObject, castExpr, nullptr,
4470a9ac8606Spatrick VK_PRValue, FPOptionsOverride());
4471e5dd7070Spatrick Cleanup.setExprNeedsCleanups(true);
4472e5dd7070Spatrick return ACR_okay;
4473e5dd7070Spatrick }
4474e5dd7070Spatrick
4475e5dd7070Spatrick // If this is a non-implicit cast from id or block type to a
4476e5dd7070Spatrick // CoreFoundation type, delay complaining in case the cast is used
4477e5dd7070Spatrick // in an acceptable context.
4478e5dd7070Spatrick if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC) && isCast(CCK))
4479e5dd7070Spatrick return ACR_unbridged;
4480e5dd7070Spatrick
4481e5dd7070Spatrick // Issue a diagnostic about a missing @-sign when implicit casting a cstring
4482e5dd7070Spatrick // to 'NSString *', instead of falling through to report a "bridge cast"
4483e5dd7070Spatrick // diagnostic.
4484e5dd7070Spatrick if (castACTC == ACTC_retainable && exprACTC == ACTC_none &&
4485ec727ea7Spatrick CheckConversionToObjCLiteral(castType, castExpr, Diagnose))
4486e5dd7070Spatrick return ACR_error;
4487e5dd7070Spatrick
4488e5dd7070Spatrick // Do not issue "bridge cast" diagnostic when implicit casting
4489e5dd7070Spatrick // a retainable object to a CF type parameter belonging to an audited
4490e5dd7070Spatrick // CF API function. Let caller issue a normal type mismatched diagnostic
4491e5dd7070Spatrick // instead.
4492e5dd7070Spatrick if ((!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
4493e5dd7070Spatrick castACTC != ACTC_coreFoundation) &&
4494e5dd7070Spatrick !(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable &&
4495e5dd7070Spatrick (Opc == BO_NE || Opc == BO_EQ))) {
4496e5dd7070Spatrick if (Diagnose)
4497e5dd7070Spatrick diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr,
4498e5dd7070Spatrick castExpr, exprACTC, CCK);
4499e5dd7070Spatrick return ACR_error;
4500e5dd7070Spatrick }
4501e5dd7070Spatrick return ACR_okay;
4502e5dd7070Spatrick }
4503e5dd7070Spatrick
4504e5dd7070Spatrick /// Given that we saw an expression with the ARCUnbridgedCastTy
4505e5dd7070Spatrick /// placeholder type, complain bitterly.
diagnoseARCUnbridgedCast(Expr * e)4506e5dd7070Spatrick void Sema::diagnoseARCUnbridgedCast(Expr *e) {
4507e5dd7070Spatrick // We expect the spurious ImplicitCastExpr to already have been stripped.
4508e5dd7070Spatrick assert(!e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
4509e5dd7070Spatrick CastExpr *realCast = cast<CastExpr>(e->IgnoreParens());
4510e5dd7070Spatrick
4511e5dd7070Spatrick SourceRange castRange;
4512e5dd7070Spatrick QualType castType;
4513e5dd7070Spatrick CheckedConversionKind CCK;
4514e5dd7070Spatrick
4515e5dd7070Spatrick if (CStyleCastExpr *cast = dyn_cast<CStyleCastExpr>(realCast)) {
4516e5dd7070Spatrick castRange = SourceRange(cast->getLParenLoc(), cast->getRParenLoc());
4517e5dd7070Spatrick castType = cast->getTypeAsWritten();
4518e5dd7070Spatrick CCK = CCK_CStyleCast;
4519e5dd7070Spatrick } else if (ExplicitCastExpr *cast = dyn_cast<ExplicitCastExpr>(realCast)) {
4520e5dd7070Spatrick castRange = cast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange();
4521e5dd7070Spatrick castType = cast->getTypeAsWritten();
4522e5dd7070Spatrick CCK = CCK_OtherCast;
4523e5dd7070Spatrick } else {
4524e5dd7070Spatrick llvm_unreachable("Unexpected ImplicitCastExpr");
4525e5dd7070Spatrick }
4526e5dd7070Spatrick
4527e5dd7070Spatrick ARCConversionTypeClass castACTC =
4528e5dd7070Spatrick classifyTypeForARCConversion(castType.getNonReferenceType());
4529e5dd7070Spatrick
4530e5dd7070Spatrick Expr *castExpr = realCast->getSubExpr();
4531e5dd7070Spatrick assert(classifyTypeForARCConversion(castExpr->getType()) == ACTC_retainable);
4532e5dd7070Spatrick
4533e5dd7070Spatrick diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
4534e5dd7070Spatrick castExpr, realCast, ACTC_retainable, CCK);
4535e5dd7070Spatrick }
4536e5dd7070Spatrick
4537e5dd7070Spatrick /// stripARCUnbridgedCast - Given an expression of ARCUnbridgedCast
4538e5dd7070Spatrick /// type, remove the placeholder cast.
stripARCUnbridgedCast(Expr * e)4539e5dd7070Spatrick Expr *Sema::stripARCUnbridgedCast(Expr *e) {
4540e5dd7070Spatrick assert(e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
4541e5dd7070Spatrick
4542e5dd7070Spatrick if (ParenExpr *pe = dyn_cast<ParenExpr>(e)) {
4543e5dd7070Spatrick Expr *sub = stripARCUnbridgedCast(pe->getSubExpr());
4544e5dd7070Spatrick return new (Context) ParenExpr(pe->getLParen(), pe->getRParen(), sub);
4545e5dd7070Spatrick } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
4546e5dd7070Spatrick assert(uo->getOpcode() == UO_Extension);
4547e5dd7070Spatrick Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
4548ec727ea7Spatrick return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(),
4549ec727ea7Spatrick sub->getValueKind(), sub->getObjectKind(),
4550ec727ea7Spatrick uo->getOperatorLoc(), false,
4551ec727ea7Spatrick CurFPFeatureOverrides());
4552e5dd7070Spatrick } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
4553e5dd7070Spatrick assert(!gse->isResultDependent());
4554e5dd7070Spatrick
4555e5dd7070Spatrick unsigned n = gse->getNumAssocs();
4556e5dd7070Spatrick SmallVector<Expr *, 4> subExprs;
4557e5dd7070Spatrick SmallVector<TypeSourceInfo *, 4> subTypes;
4558e5dd7070Spatrick subExprs.reserve(n);
4559e5dd7070Spatrick subTypes.reserve(n);
4560e5dd7070Spatrick for (const GenericSelectionExpr::Association assoc : gse->associations()) {
4561e5dd7070Spatrick subTypes.push_back(assoc.getTypeSourceInfo());
4562e5dd7070Spatrick Expr *sub = assoc.getAssociationExpr();
4563e5dd7070Spatrick if (assoc.isSelected())
4564e5dd7070Spatrick sub = stripARCUnbridgedCast(sub);
4565e5dd7070Spatrick subExprs.push_back(sub);
4566e5dd7070Spatrick }
4567e5dd7070Spatrick
4568e5dd7070Spatrick return GenericSelectionExpr::Create(
4569e5dd7070Spatrick Context, gse->getGenericLoc(), gse->getControllingExpr(), subTypes,
4570e5dd7070Spatrick subExprs, gse->getDefaultLoc(), gse->getRParenLoc(),
4571e5dd7070Spatrick gse->containsUnexpandedParameterPack(), gse->getResultIndex());
4572e5dd7070Spatrick } else {
4573e5dd7070Spatrick assert(isa<ImplicitCastExpr>(e) && "bad form of unbridged cast!");
4574e5dd7070Spatrick return cast<ImplicitCastExpr>(e)->getSubExpr();
4575e5dd7070Spatrick }
4576e5dd7070Spatrick }
4577e5dd7070Spatrick
CheckObjCARCUnavailableWeakConversion(QualType castType,QualType exprType)4578e5dd7070Spatrick bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
4579e5dd7070Spatrick QualType exprType) {
4580e5dd7070Spatrick QualType canCastType =
4581e5dd7070Spatrick Context.getCanonicalType(castType).getUnqualifiedType();
4582e5dd7070Spatrick QualType canExprType =
4583e5dd7070Spatrick Context.getCanonicalType(exprType).getUnqualifiedType();
4584e5dd7070Spatrick if (isa<ObjCObjectPointerType>(canCastType) &&
4585e5dd7070Spatrick castType.getObjCLifetime() == Qualifiers::OCL_Weak &&
4586e5dd7070Spatrick canExprType->isObjCObjectPointerType()) {
4587e5dd7070Spatrick if (const ObjCObjectPointerType *ObjT =
4588e5dd7070Spatrick canExprType->getAs<ObjCObjectPointerType>())
4589e5dd7070Spatrick if (const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl())
4590e5dd7070Spatrick return !ObjI->isArcWeakrefUnavailable();
4591e5dd7070Spatrick }
4592e5dd7070Spatrick return true;
4593e5dd7070Spatrick }
4594e5dd7070Spatrick
4595e5dd7070Spatrick /// Look for an ObjCReclaimReturnedObject cast and destroy it.
maybeUndoReclaimObject(Expr * e)4596e5dd7070Spatrick static Expr *maybeUndoReclaimObject(Expr *e) {
4597e5dd7070Spatrick Expr *curExpr = e, *prevExpr = nullptr;
4598e5dd7070Spatrick
4599e5dd7070Spatrick // Walk down the expression until we hit an implicit cast of kind
4600e5dd7070Spatrick // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
4601e5dd7070Spatrick while (true) {
4602e5dd7070Spatrick if (auto *pe = dyn_cast<ParenExpr>(curExpr)) {
4603e5dd7070Spatrick prevExpr = curExpr;
4604e5dd7070Spatrick curExpr = pe->getSubExpr();
4605e5dd7070Spatrick continue;
4606e5dd7070Spatrick }
4607e5dd7070Spatrick
4608e5dd7070Spatrick if (auto *ce = dyn_cast<CastExpr>(curExpr)) {
4609e5dd7070Spatrick if (auto *ice = dyn_cast<ImplicitCastExpr>(ce))
4610e5dd7070Spatrick if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
4611e5dd7070Spatrick if (!prevExpr)
4612e5dd7070Spatrick return ice->getSubExpr();
4613e5dd7070Spatrick if (auto *pe = dyn_cast<ParenExpr>(prevExpr))
4614e5dd7070Spatrick pe->setSubExpr(ice->getSubExpr());
4615e5dd7070Spatrick else
4616e5dd7070Spatrick cast<CastExpr>(prevExpr)->setSubExpr(ice->getSubExpr());
4617e5dd7070Spatrick return e;
4618e5dd7070Spatrick }
4619e5dd7070Spatrick
4620e5dd7070Spatrick prevExpr = curExpr;
4621e5dd7070Spatrick curExpr = ce->getSubExpr();
4622e5dd7070Spatrick continue;
4623e5dd7070Spatrick }
4624e5dd7070Spatrick
4625e5dd7070Spatrick // Break out of the loop if curExpr is neither a Paren nor a Cast.
4626e5dd7070Spatrick break;
4627e5dd7070Spatrick }
4628e5dd7070Spatrick
4629e5dd7070Spatrick return e;
4630e5dd7070Spatrick }
4631e5dd7070Spatrick
BuildObjCBridgedCast(SourceLocation LParenLoc,ObjCBridgeCastKind Kind,SourceLocation BridgeKeywordLoc,TypeSourceInfo * TSInfo,Expr * SubExpr)4632e5dd7070Spatrick ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
4633e5dd7070Spatrick ObjCBridgeCastKind Kind,
4634e5dd7070Spatrick SourceLocation BridgeKeywordLoc,
4635e5dd7070Spatrick TypeSourceInfo *TSInfo,
4636e5dd7070Spatrick Expr *SubExpr) {
4637e5dd7070Spatrick ExprResult SubResult = UsualUnaryConversions(SubExpr);
4638e5dd7070Spatrick if (SubResult.isInvalid()) return ExprError();
4639e5dd7070Spatrick SubExpr = SubResult.get();
4640e5dd7070Spatrick
4641e5dd7070Spatrick QualType T = TSInfo->getType();
4642e5dd7070Spatrick QualType FromType = SubExpr->getType();
4643e5dd7070Spatrick
4644e5dd7070Spatrick CastKind CK;
4645e5dd7070Spatrick
4646e5dd7070Spatrick bool MustConsume = false;
4647e5dd7070Spatrick if (T->isDependentType() || SubExpr->isTypeDependent()) {
4648e5dd7070Spatrick // Okay: we'll build a dependent expression type.
4649e5dd7070Spatrick CK = CK_Dependent;
4650e5dd7070Spatrick } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) {
4651e5dd7070Spatrick // Casting CF -> id
4652e5dd7070Spatrick CK = (T->isBlockPointerType() ? CK_AnyPointerToBlockPointerCast
4653e5dd7070Spatrick : CK_CPointerToObjCPointerCast);
4654e5dd7070Spatrick switch (Kind) {
4655e5dd7070Spatrick case OBC_Bridge:
4656e5dd7070Spatrick break;
4657e5dd7070Spatrick
4658e5dd7070Spatrick case OBC_BridgeRetained: {
4659e5dd7070Spatrick bool br = isKnownName("CFBridgingRelease");
4660e5dd7070Spatrick Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
4661e5dd7070Spatrick << 2
4662e5dd7070Spatrick << FromType
4663e5dd7070Spatrick << (T->isBlockPointerType()? 1 : 0)
4664e5dd7070Spatrick << T
4665e5dd7070Spatrick << SubExpr->getSourceRange()
4666e5dd7070Spatrick << Kind;
4667e5dd7070Spatrick Diag(BridgeKeywordLoc, diag::note_arc_bridge)
4668e5dd7070Spatrick << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge");
4669e5dd7070Spatrick Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer)
4670e5dd7070Spatrick << FromType << br
4671e5dd7070Spatrick << FixItHint::CreateReplacement(BridgeKeywordLoc,
4672e5dd7070Spatrick br ? "CFBridgingRelease "
4673e5dd7070Spatrick : "__bridge_transfer ");
4674e5dd7070Spatrick
4675e5dd7070Spatrick Kind = OBC_Bridge;
4676e5dd7070Spatrick break;
4677e5dd7070Spatrick }
4678e5dd7070Spatrick
4679e5dd7070Spatrick case OBC_BridgeTransfer:
4680e5dd7070Spatrick // We must consume the Objective-C object produced by the cast.
4681e5dd7070Spatrick MustConsume = true;
4682e5dd7070Spatrick break;
4683e5dd7070Spatrick }
4684e5dd7070Spatrick } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) {
4685e5dd7070Spatrick // Okay: id -> CF
4686e5dd7070Spatrick CK = CK_BitCast;
4687e5dd7070Spatrick switch (Kind) {
4688e5dd7070Spatrick case OBC_Bridge:
4689e5dd7070Spatrick // Reclaiming a value that's going to be __bridge-casted to CF
4690e5dd7070Spatrick // is very dangerous, so we don't do it.
4691e5dd7070Spatrick SubExpr = maybeUndoReclaimObject(SubExpr);
4692e5dd7070Spatrick break;
4693e5dd7070Spatrick
4694e5dd7070Spatrick case OBC_BridgeRetained:
4695e5dd7070Spatrick // Produce the object before casting it.
4696a9ac8606Spatrick SubExpr = ImplicitCastExpr::Create(Context, FromType, CK_ARCProduceObject,
4697a9ac8606Spatrick SubExpr, nullptr, VK_PRValue,
4698a9ac8606Spatrick FPOptionsOverride());
4699e5dd7070Spatrick break;
4700e5dd7070Spatrick
4701e5dd7070Spatrick case OBC_BridgeTransfer: {
4702e5dd7070Spatrick bool br = isKnownName("CFBridgingRetain");
4703e5dd7070Spatrick Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
4704e5dd7070Spatrick << (FromType->isBlockPointerType()? 1 : 0)
4705e5dd7070Spatrick << FromType
4706e5dd7070Spatrick << 2
4707e5dd7070Spatrick << T
4708e5dd7070Spatrick << SubExpr->getSourceRange()
4709e5dd7070Spatrick << Kind;
4710e5dd7070Spatrick
4711e5dd7070Spatrick Diag(BridgeKeywordLoc, diag::note_arc_bridge)
4712e5dd7070Spatrick << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge ");
4713e5dd7070Spatrick Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained)
4714e5dd7070Spatrick << T << br
4715e5dd7070Spatrick << FixItHint::CreateReplacement(BridgeKeywordLoc,
4716e5dd7070Spatrick br ? "CFBridgingRetain " : "__bridge_retained");
4717e5dd7070Spatrick
4718e5dd7070Spatrick Kind = OBC_Bridge;
4719e5dd7070Spatrick break;
4720e5dd7070Spatrick }
4721e5dd7070Spatrick }
4722e5dd7070Spatrick } else {
4723e5dd7070Spatrick Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible)
4724e5dd7070Spatrick << FromType << T << Kind
4725e5dd7070Spatrick << SubExpr->getSourceRange()
4726e5dd7070Spatrick << TSInfo->getTypeLoc().getSourceRange();
4727e5dd7070Spatrick return ExprError();
4728e5dd7070Spatrick }
4729e5dd7070Spatrick
4730e5dd7070Spatrick Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, CK,
4731e5dd7070Spatrick BridgeKeywordLoc,
4732e5dd7070Spatrick TSInfo, SubExpr);
4733e5dd7070Spatrick
4734e5dd7070Spatrick if (MustConsume) {
4735e5dd7070Spatrick Cleanup.setExprNeedsCleanups(true);
4736e5dd7070Spatrick Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result,
4737a9ac8606Spatrick nullptr, VK_PRValue, FPOptionsOverride());
4738e5dd7070Spatrick }
4739e5dd7070Spatrick
4740e5dd7070Spatrick return Result;
4741e5dd7070Spatrick }
4742e5dd7070Spatrick
ActOnObjCBridgedCast(Scope * S,SourceLocation LParenLoc,ObjCBridgeCastKind Kind,SourceLocation BridgeKeywordLoc,ParsedType Type,SourceLocation RParenLoc,Expr * SubExpr)4743e5dd7070Spatrick ExprResult Sema::ActOnObjCBridgedCast(Scope *S,
4744e5dd7070Spatrick SourceLocation LParenLoc,
4745e5dd7070Spatrick ObjCBridgeCastKind Kind,
4746e5dd7070Spatrick SourceLocation BridgeKeywordLoc,
4747e5dd7070Spatrick ParsedType Type,
4748e5dd7070Spatrick SourceLocation RParenLoc,
4749e5dd7070Spatrick Expr *SubExpr) {
4750e5dd7070Spatrick TypeSourceInfo *TSInfo = nullptr;
4751e5dd7070Spatrick QualType T = GetTypeFromParser(Type, &TSInfo);
4752e5dd7070Spatrick if (Kind == OBC_Bridge)
4753e5dd7070Spatrick CheckTollFreeBridgeCast(T, SubExpr);
4754e5dd7070Spatrick if (!TSInfo)
4755e5dd7070Spatrick TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc);
4756e5dd7070Spatrick return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo,
4757e5dd7070Spatrick SubExpr);
4758e5dd7070Spatrick }
4759