| //===- ExprObjC.cpp - (ObjC) Expression AST Node Implementation -----------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the subclesses of Expr class declared in ExprObjC.h |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/AST/ExprObjC.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/SelectorLocationsKind.h" |
| #include "clang/AST/Type.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <cstdint> |
| |
| using namespace clang; |
| |
| ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements, QualType T, |
| ObjCMethodDecl *Method, SourceRange SR) |
| : Expr(ObjCArrayLiteralClass, T, VK_RValue, OK_Ordinary, false, false, |
| false, false), |
| NumElements(Elements.size()), Range(SR), ArrayWithObjectsMethod(Method) { |
| Expr **SaveElements = getElements(); |
| for (unsigned I = 0, N = Elements.size(); I != N; ++I) { |
| if (Elements[I]->isTypeDependent() || Elements[I]->isValueDependent()) |
| ExprBits.ValueDependent = true; |
| if (Elements[I]->isInstantiationDependent()) |
| ExprBits.InstantiationDependent = true; |
| if (Elements[I]->containsUnexpandedParameterPack()) |
| ExprBits.ContainsUnexpandedParameterPack = true; |
| |
| SaveElements[I] = Elements[I]; |
| } |
| } |
| |
| ObjCArrayLiteral *ObjCArrayLiteral::Create(const ASTContext &C, |
| ArrayRef<Expr *> Elements, |
| QualType T, ObjCMethodDecl *Method, |
| SourceRange SR) { |
| void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Elements.size())); |
| return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR); |
| } |
| |
| ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C, |
| unsigned NumElements) { |
| void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumElements)); |
| return new (Mem) ObjCArrayLiteral(EmptyShell(), NumElements); |
| } |
| |
| ObjCDictionaryLiteral::ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK, |
| bool HasPackExpansions, QualType T, |
| ObjCMethodDecl *method, |
| SourceRange SR) |
| : Expr(ObjCDictionaryLiteralClass, T, VK_RValue, OK_Ordinary, false, false, |
| false, false), |
| NumElements(VK.size()), HasPackExpansions(HasPackExpansions), Range(SR), |
| DictWithObjectsMethod(method) { |
| KeyValuePair *KeyValues = getTrailingObjects<KeyValuePair>(); |
| ExpansionData *Expansions = |
| HasPackExpansions ? getTrailingObjects<ExpansionData>() : nullptr; |
| for (unsigned I = 0; I < NumElements; I++) { |
| if (VK[I].Key->isTypeDependent() || VK[I].Key->isValueDependent() || |
| VK[I].Value->isTypeDependent() || VK[I].Value->isValueDependent()) |
| ExprBits.ValueDependent = true; |
| if (VK[I].Key->isInstantiationDependent() || |
| VK[I].Value->isInstantiationDependent()) |
| ExprBits.InstantiationDependent = true; |
| if (VK[I].EllipsisLoc.isInvalid() && |
| (VK[I].Key->containsUnexpandedParameterPack() || |
| VK[I].Value->containsUnexpandedParameterPack())) |
| ExprBits.ContainsUnexpandedParameterPack = true; |
| |
| KeyValues[I].Key = VK[I].Key; |
| KeyValues[I].Value = VK[I].Value; |
| if (Expansions) { |
| Expansions[I].EllipsisLoc = VK[I].EllipsisLoc; |
| if (VK[I].NumExpansions) |
| Expansions[I].NumExpansionsPlusOne = *VK[I].NumExpansions + 1; |
| else |
| Expansions[I].NumExpansionsPlusOne = 0; |
| } |
| } |
| } |
| |
| ObjCDictionaryLiteral * |
| ObjCDictionaryLiteral::Create(const ASTContext &C, |
| ArrayRef<ObjCDictionaryElement> VK, |
| bool HasPackExpansions, QualType T, |
| ObjCMethodDecl *method, SourceRange SR) { |
| void *Mem = C.Allocate(totalSizeToAlloc<KeyValuePair, ExpansionData>( |
| VK.size(), HasPackExpansions ? VK.size() : 0)); |
| return new (Mem) ObjCDictionaryLiteral(VK, HasPackExpansions, T, method, SR); |
| } |
| |
| ObjCDictionaryLiteral * |
| ObjCDictionaryLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements, |
| bool HasPackExpansions) { |
| void *Mem = C.Allocate(totalSizeToAlloc<KeyValuePair, ExpansionData>( |
| NumElements, HasPackExpansions ? NumElements : 0)); |
| return new (Mem) |
| ObjCDictionaryLiteral(EmptyShell(), NumElements, HasPackExpansions); |
| } |
| |
| QualType ObjCPropertyRefExpr::getReceiverType(const ASTContext &ctx) const { |
| if (isClassReceiver()) |
| return ctx.getObjCInterfaceType(getClassReceiver()); |
| |
| if (isSuperReceiver()) |
| return getSuperReceiverType(); |
| |
| return getBase()->getType(); |
| } |
| |
| ObjCMessageExpr::ObjCMessageExpr(QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, |
| SourceLocation SuperLoc, bool IsInstanceSuper, |
| QualType SuperType, Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK, |
| ObjCMethodDecl *Method, ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, bool isImplicit) |
| : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, |
| /*TypeDependent=*/false, /*ValueDependent=*/false, |
| /*InstantiationDependent=*/false, |
| /*ContainsUnexpandedParameterPack=*/false), |
| SelectorOrMethod( |
| reinterpret_cast<uintptr_t>(Method ? Method : Sel.getAsOpaquePtr())), |
| Kind(IsInstanceSuper ? SuperInstance : SuperClass), |
| HasMethod(Method != nullptr), IsDelegateInitCall(false), |
| IsImplicit(isImplicit), SuperLoc(SuperLoc), LBracLoc(LBracLoc), |
| RBracLoc(RBracLoc) { |
| initArgsAndSelLocs(Args, SelLocs, SelLocsK); |
| setReceiverPointer(SuperType.getAsOpaquePtr()); |
| } |
| |
| ObjCMessageExpr::ObjCMessageExpr(QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, |
| TypeSourceInfo *Receiver, Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK, |
| ObjCMethodDecl *Method, ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, bool isImplicit) |
| : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(), |
| T->isDependentType(), T->isInstantiationDependentType(), |
| T->containsUnexpandedParameterPack()), |
| SelectorOrMethod( |
| reinterpret_cast<uintptr_t>(Method ? Method : Sel.getAsOpaquePtr())), |
| Kind(Class), HasMethod(Method != nullptr), IsDelegateInitCall(false), |
| IsImplicit(isImplicit), LBracLoc(LBracLoc), RBracLoc(RBracLoc) { |
| initArgsAndSelLocs(Args, SelLocs, SelLocsK); |
| setReceiverPointer(Receiver); |
| } |
| |
| ObjCMessageExpr::ObjCMessageExpr(QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, Expr *Receiver, |
| Selector Sel, ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK, |
| ObjCMethodDecl *Method, ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, bool isImplicit) |
| : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, |
| Receiver->isTypeDependent(), Receiver->isTypeDependent(), |
| Receiver->isInstantiationDependent(), |
| Receiver->containsUnexpandedParameterPack()), |
| SelectorOrMethod( |
| reinterpret_cast<uintptr_t>(Method ? Method : Sel.getAsOpaquePtr())), |
| Kind(Instance), HasMethod(Method != nullptr), IsDelegateInitCall(false), |
| IsImplicit(isImplicit), LBracLoc(LBracLoc), RBracLoc(RBracLoc) { |
| initArgsAndSelLocs(Args, SelLocs, SelLocsK); |
| setReceiverPointer(Receiver); |
| } |
| |
| void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args, |
| ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK) { |
| setNumArgs(Args.size()); |
| Expr **MyArgs = getArgs(); |
| for (unsigned I = 0; I != Args.size(); ++I) { |
| if (Args[I]->isTypeDependent()) |
| ExprBits.TypeDependent = true; |
| if (Args[I]->isValueDependent()) |
| ExprBits.ValueDependent = true; |
| if (Args[I]->isInstantiationDependent()) |
| ExprBits.InstantiationDependent = true; |
| if (Args[I]->containsUnexpandedParameterPack()) |
| ExprBits.ContainsUnexpandedParameterPack = true; |
| |
| MyArgs[I] = Args[I]; |
| } |
| |
| SelLocsKind = SelLocsK; |
| if (!isImplicit()) { |
| if (SelLocsK == SelLoc_NonStandard) |
| std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs()); |
| } |
| } |
| |
| ObjCMessageExpr * |
| ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, SourceLocation SuperLoc, |
| bool IsInstanceSuper, QualType SuperType, Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| ObjCMethodDecl *Method, ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, bool isImplicit) { |
| assert((!SelLocs.empty() || isImplicit) && |
| "No selector locs for non-implicit message"); |
| ObjCMessageExpr *Mem; |
| SelectorLocationsKind SelLocsK = SelectorLocationsKind(); |
| if (isImplicit) |
| Mem = alloc(Context, Args.size(), 0); |
| else |
| Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK); |
| return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, SuperLoc, IsInstanceSuper, |
| SuperType, Sel, SelLocs, SelLocsK, Method, |
| Args, RBracLoc, isImplicit); |
| } |
| |
| ObjCMessageExpr * |
| ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, TypeSourceInfo *Receiver, |
| Selector Sel, ArrayRef<SourceLocation> SelLocs, |
| ObjCMethodDecl *Method, ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, bool isImplicit) { |
| assert((!SelLocs.empty() || isImplicit) && |
| "No selector locs for non-implicit message"); |
| ObjCMessageExpr *Mem; |
| SelectorLocationsKind SelLocsK = SelectorLocationsKind(); |
| if (isImplicit) |
| Mem = alloc(Context, Args.size(), 0); |
| else |
| Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK); |
| return new (Mem) |
| ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLocs, SelLocsK, Method, |
| Args, RBracLoc, isImplicit); |
| } |
| |
| ObjCMessageExpr * |
| ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, Expr *Receiver, Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| ObjCMethodDecl *Method, ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, bool isImplicit) { |
| assert((!SelLocs.empty() || isImplicit) && |
| "No selector locs for non-implicit message"); |
| ObjCMessageExpr *Mem; |
| SelectorLocationsKind SelLocsK = SelectorLocationsKind(); |
| if (isImplicit) |
| Mem = alloc(Context, Args.size(), 0); |
| else |
| Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK); |
| return new (Mem) |
| ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLocs, SelLocsK, Method, |
| Args, RBracLoc, isImplicit); |
| } |
| |
| ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(const ASTContext &Context, |
| unsigned NumArgs, |
| unsigned NumStoredSelLocs) { |
| ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs); |
| return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); |
| } |
| |
| ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBraceLoc, |
| ArrayRef<SourceLocation> SelLocs, |
| Selector Sel, |
| SelectorLocationsKind &SelLocsK) { |
| SelLocsK = hasStandardSelectorLocs(Sel, SelLocs, Args, RBraceLoc); |
| unsigned NumStoredSelLocs = |
| (SelLocsK == SelLoc_NonStandard) ? SelLocs.size() : 0; |
| return alloc(C, Args.size(), NumStoredSelLocs); |
| } |
| |
| ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C, unsigned NumArgs, |
| unsigned NumStoredSelLocs) { |
| return (ObjCMessageExpr *)C.Allocate( |
| totalSizeToAlloc<void *, SourceLocation>(NumArgs + 1, NumStoredSelLocs), |
| alignof(ObjCMessageExpr)); |
| } |
| |
| void ObjCMessageExpr::getSelectorLocs( |
| SmallVectorImpl<SourceLocation> &SelLocs) const { |
| for (unsigned i = 0, e = getNumSelectorLocs(); i != e; ++i) |
| SelLocs.push_back(getSelectorLoc(i)); |
| } |
| |
| |
| QualType ObjCMessageExpr::getCallReturnType(ASTContext &Ctx) const { |
| if (const ObjCMethodDecl *MD = getMethodDecl()) { |
| QualType QT = MD->getReturnType(); |
| if (QT == Ctx.getObjCInstanceType()) { |
| // instancetype corresponds to expression types. |
| return getType(); |
| } |
| return QT; |
| } |
| |
| // Expression type might be different from an expected call return type, |
| // as expression type would never be a reference even if call returns a |
| // reference. Reconstruct the original expression type. |
| QualType QT = getType(); |
| switch (getValueKind()) { |
| case VK_LValue: |
| return Ctx.getLValueReferenceType(QT); |
| case VK_XValue: |
| return Ctx.getRValueReferenceType(QT); |
| case VK_RValue: |
| return QT; |
| } |
| llvm_unreachable("Unsupported ExprValueKind"); |
| } |
| |
| SourceRange ObjCMessageExpr::getReceiverRange() const { |
| switch (getReceiverKind()) { |
| case Instance: |
| return getInstanceReceiver()->getSourceRange(); |
| |
| case Class: |
| return getClassReceiverTypeInfo()->getTypeLoc().getSourceRange(); |
| |
| case SuperInstance: |
| case SuperClass: |
| return getSuperLoc(); |
| } |
| |
| llvm_unreachable("Invalid ReceiverKind!"); |
| } |
| |
| Selector ObjCMessageExpr::getSelector() const { |
| if (HasMethod) |
| return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod) |
| ->getSelector(); |
| return Selector(SelectorOrMethod); |
| } |
| |
| QualType ObjCMessageExpr::getReceiverType() const { |
| switch (getReceiverKind()) { |
| case Instance: |
| return getInstanceReceiver()->getType(); |
| case Class: |
| return getClassReceiver(); |
| case SuperInstance: |
| case SuperClass: |
| return getSuperType(); |
| } |
| |
| llvm_unreachable("unexpected receiver kind"); |
| } |
| |
| ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { |
| QualType T = getReceiverType(); |
| |
| if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>()) |
| return Ptr->getInterfaceDecl(); |
| |
| if (const ObjCObjectType *Ty = T->getAs<ObjCObjectType>()) |
| return Ty->getInterface(); |
| |
| return nullptr; |
| } |
| |
| Stmt::child_range ObjCMessageExpr::children() { |
| Stmt **begin; |
| if (getReceiverKind() == Instance) |
| begin = reinterpret_cast<Stmt **>(getTrailingObjects<void *>()); |
| else |
| begin = reinterpret_cast<Stmt **>(getArgs()); |
| return child_range(begin, |
| reinterpret_cast<Stmt **>(getArgs() + getNumArgs())); |
| } |
| |
| Stmt::const_child_range ObjCMessageExpr::children() const { |
| auto Children = const_cast<ObjCMessageExpr *>(this)->children(); |
| return const_child_range(Children.begin(), Children.end()); |
| } |
| |
| StringRef ObjCBridgedCastExpr::getBridgeKindName() const { |
| switch (getBridgeKind()) { |
| case OBC_Bridge: |
| return "__bridge"; |
| case OBC_BridgeTransfer: |
| return "__bridge_transfer"; |
| case OBC_BridgeRetained: |
| return "__bridge_retained"; |
| } |
| |
| llvm_unreachable("Invalid BridgeKind!"); |
| } |