1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
//===--- TypeCheckObjC.h - Type Checking for ObjC interop -------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file provides utilities for type-checking interoperability with
// Objective-C.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SEMA_TYPE_CHECK_OBJC_H
#define SWIFT_SEMA_TYPE_CHECK_OBJC_H
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/ForeignAsyncConvention.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "llvm/ADT/PointerUnion.h"
#include <optional>
namespace swift {
class AbstractFunctionDecl;
class ASTContext;
class ObjCAttr;
class SubscriptDecl;
class ValueDecl;
class VarDecl;
class InFlightDiagnostic;
/// Describes the reason why are we trying to apply @objc to a declaration.
///
/// Should only affect diagnostics. If you change this enum, also change
/// the OBJC_ATTR_SELECT macro in DiagnosticsSema.def.
class ObjCReason {
public:
// The kind of reason.
enum Kind {
/// Has the '@cdecl' attribute.
ExplicitlyCDecl,
/// Has the 'dynamic' modifier.
ExplicitlyDynamic,
/// Has an explicit '@objc' attribute.
ExplicitlyObjC,
/// Has an explicit '@objcmembers' attribute.
ExplicitlyObjCMembers,
/// Has an explicit '@IBOutlet' attribute.
ExplicitlyIBOutlet,
/// Has an explicit '@IBAction' attribute.
ExplicitlyIBAction,
/// Has an explicit '@IBSegueAction' attribute.
ExplicitlyIBSegueAction,
/// Has an explicit '@NSManaged' attribute.
ExplicitlyNSManaged,
/// Is a member of an @objc protocol.
MemberOfObjCProtocol,
/// Implicitly-introduced @objc.
ImplicitlyObjC,
/// Is an override of an @objc member.
OverridesObjC,
/// Is a witness to an @objc protocol requirement.
WitnessToObjC,
/// Has an explicit '@IBInspectable' attribute.
ExplicitlyIBInspectable,
/// Has an explicit '@GKInspectable' attribute.
ExplicitlyGKInspectable,
/// Is it a member of an @objc extension of a class.
MemberOfObjCExtension,
/// Is it a member of an \@\_objcImplementation extension.
MemberOfObjCImplementationExtension,
/// Has an explicit '@objc' attribute added by an access note, rather than
/// written in source code.
ExplicitlyObjCByAccessNote,
// These kinds do not appear in diagnostics.
/// Is it a member of an @objcMembers class.
MemberOfObjCMembersClass,
/// A member of an Objective-C-defined class or subclass.
MemberOfObjCSubclass,
/// Is a member of an @objc enum.
ElementOfObjCEnum,
/// An accessor to a property.
Accessor,
};
private:
Kind kind;
/// When the kind is \c WitnessToObjC, the requirement being witnessed.
llvm::PointerUnion<ValueDecl *, DeclAttribute *> declOrAttr =
static_cast<DeclAttribute *>(nullptr);
ObjCReason(Kind kind, ValueDecl *decl) : kind(kind), declOrAttr(decl) { }
static bool requiresAttr(Kind kind) {
switch (kind) {
case ExplicitlyCDecl:
case ExplicitlyDynamic:
case ExplicitlyObjC:
case ExplicitlyObjCMembers:
case ExplicitlyIBOutlet:
case ExplicitlyIBAction:
case ExplicitlyIBSegueAction:
case ExplicitlyNSManaged:
case ExplicitlyIBInspectable:
case ExplicitlyGKInspectable:
case MemberOfObjCImplementationExtension:
case ExplicitlyObjCByAccessNote:
return true;
case MemberOfObjCProtocol:
case ImplicitlyObjC:
case OverridesObjC:
case WitnessToObjC:
case MemberOfObjCExtension:
case MemberOfObjCMembersClass:
case MemberOfObjCSubclass:
case ElementOfObjCEnum:
case Accessor:
return false;
}
}
public:
/// Implicit conversion from the trivial reason kinds.
ObjCReason(Kind kind) : kind(kind) {
assert(kind != WitnessToObjC && "Use ObjCReason::witnessToObjC()");
assert(!requiresAttr(kind) && "Use ObjCReason(Kind, DeclAttribute*)");
}
ObjCReason(Kind kind, const DeclAttribute *attr)
: kind(kind), declOrAttr(const_cast<DeclAttribute *>(attr)) {
// const_cast above because it's difficult to get a non-const DeclAttribute.
assert(requiresAttr(kind) && "Use ObjCReason(Kind)");
}
/// Retrieve the kind of requirement.
operator Kind() const { return kind; }
/// Form a reason specifying that we have a witness to the given @objc
/// requirement.
static ObjCReason witnessToObjC(ValueDecl *requirement) {
return ObjCReason(WitnessToObjC, requirement);
}
/// When the entity should be @objc because it is a witness to an @objc
/// requirement, retrieve the requirement.
ValueDecl *getObjCRequirement() const {
assert(kind == WitnessToObjC);
return declOrAttr.get<ValueDecl *>();
}
DeclAttribute *getAttr() const {
if (!requiresAttr(kind))
return nullptr;
return declOrAttr.get<DeclAttribute *>();
}
void setAttrInvalid() const;
/// Emit an additional diagnostic describing why we are applying @objc to the
/// decl, if this is not obvious from the decl itself.
void describe(const Decl *VD) const;
};
/// Determine how to diagnose conflicts due to inferring @objc with this
/// particular reason.
DiagnosticBehavior
behaviorLimitForObjCReason(ObjCReason reason, ASTContext &ctx);
/// Returns the ObjCReason for this ObjCAttr to be attached to the declaration.
ObjCReason objCReasonForObjCAttr(const ObjCAttr *attr);
/// Return the %select discriminator for the OBJC_ATTR_SELECT macro used to
/// complain about the correct attribute during @objc inference.
unsigned getObjCDiagnosticAttrKind(ObjCReason reason);
/// Determine whether the given function can be represented in Objective-C,
/// and figure out its foreign error convention (if any).
bool isRepresentableInObjC(
const AbstractFunctionDecl *AFD, ObjCReason Reason,
std::optional<ForeignAsyncConvention> &asyncConvention,
std::optional<ForeignErrorConvention> &errorConvention);
/// Determine whether the given variable can be represented in Objective-C.
bool isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason);
/// Determine whether the given subscript can be represented in Objective-C.
bool isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason);
/// Check whether the given declaration can be represented in Objective-C.
bool canBeRepresentedInObjC(const ValueDecl *decl);
/// Attach Fix-Its to the given diagnostic that updates the name of the
/// given declaration to the desired target name.
///
/// \returns false if the name could not be fixed.
bool fixDeclarationName(InFlightDiagnostic &diag, const ValueDecl *decl,
DeclName targetName);
/// Fix the Objective-C name of the given declaration to match the provided
/// Objective-C selector.
///
/// \param ignoreImpliedName When true, ignore the implied name of the
/// given declaration, because it no longer applies.
///
/// For properties, the selector should be a zero-parameter selector of the
/// given property's name.
bool fixDeclarationObjCName(InFlightDiagnostic &diag, const ValueDecl *decl,
std::optional<ObjCSelector> nameOpt,
std::optional<ObjCSelector> targetNameOpt,
bool ignoreImpliedName = false);
} // end namespace swift
#endif // SWIFT_SEMA_TYPE_CHECK_OBJC_H
|