Files
swift-mirror/include/swift/ClangImporter/ClangImporterRequests.h

626 lines
22 KiB
C++

//===--- ClangImporterRequests.h - Clang Importer Requests ------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 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 defines clang-importer requests.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_CLANG_IMPORTER_REQUESTS_H
#define SWIFT_CLANG_IMPORTER_REQUESTS_H
#include "swift/AST/ASTTypeIDs.h"
#include "swift/AST/EvaluatorDependencies.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/SimpleRequest.h"
#include "swift/Basic/Statistic.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "clang/AST/Type.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/TinyPtrVector.h"
namespace swift {
class Decl;
class DeclName;
class EnumDecl;
enum class ExplicitSafety;
/// The input type for a clang direct lookup request.
struct ClangDirectLookupDescriptor final {
Decl *decl;
const clang::Decl *clangDecl;
DeclName name;
ClangDirectLookupDescriptor(Decl *decl, const clang::Decl *clangDecl,
DeclName name)
: decl(decl), clangDecl(clangDecl), name(name) {}
friend llvm::hash_code hash_value(const ClangDirectLookupDescriptor &desc) {
return llvm::hash_combine(desc.name, desc.decl, desc.clangDecl);
}
friend bool operator==(const ClangDirectLookupDescriptor &lhs,
const ClangDirectLookupDescriptor &rhs) {
return lhs.name == rhs.name && lhs.decl == rhs.decl &&
lhs.clangDecl == rhs.clangDecl;
}
friend bool operator!=(const ClangDirectLookupDescriptor &lhs,
const ClangDirectLookupDescriptor &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out,
const ClangDirectLookupDescriptor &desc);
SourceLoc extractNearestSourceLoc(const ClangDirectLookupDescriptor &desc);
/// This matches SwiftLookupTable::SingleEntry;
using SingleEntry = llvm::PointerUnion<clang::NamedDecl *, clang::MacroInfo *,
clang::ModuleMacro *>;
/// Uses the appropriate SwiftLookupTable to find a set of clang decls given
/// their name.
class ClangDirectLookupRequest
: public SimpleRequest<ClangDirectLookupRequest,
SmallVector<SingleEntry, 4>(
ClangDirectLookupDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
SmallVector<SingleEntry, 4> evaluate(Evaluator &evaluator,
ClangDirectLookupDescriptor desc) const;
};
/// The input type for a namespace member lookup request.
struct CXXNamespaceMemberLookupDescriptor final {
EnumDecl *namespaceDecl;
DeclName name;
CXXNamespaceMemberLookupDescriptor(EnumDecl *namespaceDecl, DeclName name)
: namespaceDecl(namespaceDecl), name(name) {
assert(isa<clang::NamespaceDecl>(namespaceDecl->getClangDecl()));
}
friend llvm::hash_code
hash_value(const CXXNamespaceMemberLookupDescriptor &desc) {
return llvm::hash_combine(desc.name, desc.namespaceDecl);
}
friend bool operator==(const CXXNamespaceMemberLookupDescriptor &lhs,
const CXXNamespaceMemberLookupDescriptor &rhs) {
return lhs.name == rhs.name && lhs.namespaceDecl == rhs.namespaceDecl;
}
friend bool operator!=(const CXXNamespaceMemberLookupDescriptor &lhs,
const CXXNamespaceMemberLookupDescriptor &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out,
const CXXNamespaceMemberLookupDescriptor &desc);
SourceLoc
extractNearestSourceLoc(const CXXNamespaceMemberLookupDescriptor &desc);
/// Uses ClangDirectLookup to find a named member inside of the given namespace.
class CXXNamespaceMemberLookup
: public SimpleRequest<CXXNamespaceMemberLookup,
TinyPtrVector<ValueDecl *>(
CXXNamespaceMemberLookupDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
TinyPtrVector<ValueDecl *>
evaluate(Evaluator &evaluator, CXXNamespaceMemberLookupDescriptor desc) const;
};
/// The input type for a record member lookup request.
///
/// These lookups may be requested recursively in the case of inheritance,
/// for which we separately keep track of the derived class where we started
/// looking (startDecl) and the access level for the current inheritance.
struct ClangRecordMemberLookupDescriptor final {
NominalTypeDecl *recordDecl; // Where we are currently looking
NominalTypeDecl *inheritingDecl; // Where we started looking from
DeclName name; // What we are looking for
ClangInheritanceInfo inheritance;
ClangRecordMemberLookupDescriptor(NominalTypeDecl *recordDecl, DeclName name)
: recordDecl(recordDecl), inheritingDecl(recordDecl), name(name),
inheritance() {
assert(isa<clang::RecordDecl>(recordDecl->getClangDecl()));
}
friend llvm::hash_code
hash_value(const ClangRecordMemberLookupDescriptor &desc) {
return llvm::hash_combine(desc.name, desc.recordDecl, desc.inheritingDecl,
desc.inheritance);
}
friend bool operator==(const ClangRecordMemberLookupDescriptor &lhs,
const ClangRecordMemberLookupDescriptor &rhs) {
return lhs.name == rhs.name && lhs.recordDecl == rhs.recordDecl &&
lhs.inheritingDecl == rhs.inheritingDecl &&
lhs.inheritance == rhs.inheritance;
}
friend bool operator!=(const ClangRecordMemberLookupDescriptor &lhs,
const ClangRecordMemberLookupDescriptor &rhs) {
return !(lhs == rhs);
}
private:
friend class ClangRecordMemberLookup;
// This private constructor should only be used in ClangRecordMemberLookup,
// for recursively traversing base classes that inheritingDecl inherites from.
ClangRecordMemberLookupDescriptor(NominalTypeDecl *recordDecl, DeclName name,
NominalTypeDecl *inheritingDecl,
ClangInheritanceInfo inheritance)
: recordDecl(recordDecl), inheritingDecl(inheritingDecl), name(name),
inheritance(inheritance) {
assert(isa<clang::RecordDecl>(recordDecl->getClangDecl()));
assert(isa<clang::CXXRecordDecl>(inheritingDecl->getClangDecl()));
assert(inheritance.isInheriting() &&
"recursive calls should indicate inheritance");
assert(recordDecl != inheritingDecl &&
"recursive calls should lookup elsewhere");
}
};
void simple_display(llvm::raw_ostream &out,
const ClangRecordMemberLookupDescriptor &desc);
SourceLoc
extractNearestSourceLoc(const ClangRecordMemberLookupDescriptor &desc);
/// Uses ClangDirectLookup to find a named member inside of the given record.
class ClangRecordMemberLookup
: public SimpleRequest<ClangRecordMemberLookup,
TinyPtrVector<ValueDecl *>(
ClangRecordMemberLookupDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
TinyPtrVector<ValueDecl *>
evaluate(Evaluator &evaluator, ClangRecordMemberLookupDescriptor desc) const;
};
/// The input type for a clang category lookup request.
struct ClangCategoryLookupDescriptor final {
const ClassDecl *classDecl;
Identifier categoryName;
ClangCategoryLookupDescriptor(const ClassDecl *classDecl,
Identifier categoryName)
: classDecl(classDecl), categoryName(categoryName) {}
friend llvm::hash_code hash_value(const ClangCategoryLookupDescriptor &desc) {
return llvm::hash_combine(desc.classDecl, desc.categoryName);
}
friend bool operator==(const ClangCategoryLookupDescriptor &lhs,
const ClangCategoryLookupDescriptor &rhs) {
return lhs.classDecl == rhs.classDecl
&& lhs.categoryName == rhs.categoryName;
}
friend bool operator!=(const ClangCategoryLookupDescriptor &lhs,
const ClangCategoryLookupDescriptor &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out,
const ClangCategoryLookupDescriptor &desc);
SourceLoc extractNearestSourceLoc(const ClangCategoryLookupDescriptor &desc);
/// Given a Swift class, find the imported Swift decl(s) representing the
/// \c \@interface with the given category name. An empty \c categoryName
/// represents the main interface for the class.
///
/// That is, this request will return one of:
///
/// \li a single \c swift::ExtensionDecl backed by a \c clang::ObjCCategoryDecl
/// \li a \c swift::ClassDecl backed by a \c clang::ObjCInterfaceDecl, plus
/// zero or more \c swift::ExtensionDecl s backed by
/// \c clang::ObjCCategoryDecl s (representing ObjC class extensions).
/// \li an empty list if the class is not imported from Clang or it does not
/// have a category by that name.
class ClangCategoryLookupRequest
: public SimpleRequest<ClangCategoryLookupRequest,
TinyPtrVector<Decl *>(ClangCategoryLookupDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
TinyPtrVector<Decl *> evaluate(Evaluator &evaluator,
ClangCategoryLookupDescriptor desc) const;
};
/// Links an \c \@_objcImplementation decl to the imported declaration(s) that
/// it implements.
///
/// There is usually a 1:1 correspondence between interfaces and
/// implementations, except that a class's main implementation implements
/// both its main interface and any class extension interfaces. In this
/// situation, the main class is always the first decl in \c interfaceDecls.
struct ObjCInterfaceAndImplementation final {
llvm::TinyPtrVector<Decl *> interfaceDecls;
Decl *implementationDecl;
ObjCInterfaceAndImplementation(llvm::TinyPtrVector<Decl *> interfaceDecls,
Decl *implementationDecl)
: interfaceDecls(interfaceDecls), implementationDecl(implementationDecl)
{
assert(!interfaceDecls.empty() && implementationDecl &&
"interface and implementation are both non-null");
}
ObjCInterfaceAndImplementation()
: interfaceDecls(), implementationDecl(nullptr) {}
bool empty() const {
return interfaceDecls.empty();
}
friend llvm::hash_code
hash_value(const ObjCInterfaceAndImplementation &pair) {
return hash_combine(llvm::hash_combine_range(pair.interfaceDecls.begin(),
pair.interfaceDecls.end()),
pair.implementationDecl);
}
friend bool operator==(const ObjCInterfaceAndImplementation &lhs,
const ObjCInterfaceAndImplementation &rhs) {
return lhs.interfaceDecls == rhs.interfaceDecls
&& lhs.implementationDecl == rhs.implementationDecl;
}
friend bool operator!=(const ObjCInterfaceAndImplementation &lhs,
const ObjCInterfaceAndImplementation &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out,
const ObjCInterfaceAndImplementation &desc);
SourceLoc extractNearestSourceLoc(const ObjCInterfaceAndImplementation &desc);
/// Given a \c Decl , determine if it is an implementation with separate
/// interfaces imported from ObjC (or vice versa) and if so, return all of the
/// declarations involved in this relationship. Otherwise return an empty value.
///
/// We perform this lookup in both directions using a single request because
/// we want to cache the relationship on both sides to avoid duplicating work.
class ObjCInterfaceAndImplementationRequest
: public SimpleRequest<ObjCInterfaceAndImplementationRequest,
ObjCInterfaceAndImplementation(Decl *),
RequestFlags::SeparatelyCached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
ObjCInterfaceAndImplementation
evaluate(Evaluator &evaluator, Decl *decl) const;
public:
// Separate caching.
bool isCached() const { return true; }
std::optional<ObjCInterfaceAndImplementation> getCachedResult() const;
void cacheResult(ObjCInterfaceAndImplementation value) const;
};
enum class CxxRecordSemanticsKind {
Trivial,
Owned,
MoveOnly,
Reference,
Iterator,
// A record that is either not copyable/movable or not destructible.
MissingLifetimeOperation,
// A record that has no copy and no move operations
UnavailableConstructors,
// A C++ record that represents a Swift class type exposed to C++ from Swift.
SwiftClassType
};
struct CxxRecordSemanticsDescriptor final {
const clang::RecordDecl *decl;
ASTContext &ctx;
ClangImporter::Implementation *importerImpl;
/// Whether to emit warnings for missing destructor or copy constructor
/// whenever the classification of the type assumes that they exist (e.g. for
/// a value type).
bool shouldDiagnoseLifetimeOperations;
CxxRecordSemanticsDescriptor(const clang::RecordDecl *decl, ASTContext &ctx,
ClangImporter::Implementation *importerImpl,
bool shouldDiagnoseLifetimeOperations = true)
: decl(decl), ctx(ctx), importerImpl(importerImpl),
shouldDiagnoseLifetimeOperations(shouldDiagnoseLifetimeOperations) {}
friend llvm::hash_code hash_value(const CxxRecordSemanticsDescriptor &desc) {
return llvm::hash_combine(desc.decl);
}
friend bool operator==(const CxxRecordSemanticsDescriptor &lhs,
const CxxRecordSemanticsDescriptor &rhs) {
return lhs.decl == rhs.decl;
}
friend bool operator!=(const CxxRecordSemanticsDescriptor &lhs,
const CxxRecordSemanticsDescriptor &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out, CxxRecordSemanticsDescriptor desc);
SourceLoc extractNearestSourceLoc(CxxRecordSemanticsDescriptor desc);
/// What pattern does this C++ API fit? Uses attributes such as
/// import_owned and import_reference to determine the pattern.
///
/// Do not evaluate this request before importing has started. For example, it
/// is OK to invoke this request when importing a decl, but it is not OK to
/// evaluate this request when importing names. This is because when importing
/// names, Clang sema has not yet defined implicit special members, so the
/// results will be flakey/incorrect.
class CxxRecordSemantics
: public SimpleRequest<CxxRecordSemantics,
CxxRecordSemanticsKind(CxxRecordSemanticsDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
// Source location
SourceLoc getNearestLoc() const { return SourceLoc(); };
private:
friend SimpleRequest;
// Evaluation.
CxxRecordSemanticsKind evaluate(Evaluator &evaluator,
CxxRecordSemanticsDescriptor) const;
};
/// Does this C++ record represent a Swift type.
class CxxRecordAsSwiftType
: public SimpleRequest<CxxRecordAsSwiftType,
ValueDecl *(CxxRecordSemanticsDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
// Source location
SourceLoc getNearestLoc() const { return SourceLoc(); };
private:
friend SimpleRequest;
ValueDecl *evaluate(Evaluator &evaluator, CxxRecordSemanticsDescriptor) const;
};
struct SafeUseOfCxxDeclDescriptor final {
const clang::Decl *decl;
SafeUseOfCxxDeclDescriptor(const clang::Decl *decl) : decl(decl) {}
friend llvm::hash_code hash_value(const SafeUseOfCxxDeclDescriptor &desc) {
return llvm::hash_combine(desc.decl);
}
friend bool operator==(const SafeUseOfCxxDeclDescriptor &lhs,
const SafeUseOfCxxDeclDescriptor &rhs) {
return lhs.decl == rhs.decl;
}
friend bool operator!=(const SafeUseOfCxxDeclDescriptor &lhs,
const SafeUseOfCxxDeclDescriptor &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out, SafeUseOfCxxDeclDescriptor desc);
SourceLoc extractNearestSourceLoc(SafeUseOfCxxDeclDescriptor desc);
class IsSafeUseOfCxxDecl
: public SimpleRequest<IsSafeUseOfCxxDecl, bool(SafeUseOfCxxDeclDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
// Source location
SourceLoc getNearestLoc() const { return SourceLoc(); };
private:
friend SimpleRequest;
// Evaluation.
bool evaluate(Evaluator &evaluator, SafeUseOfCxxDeclDescriptor desc) const;
};
enum class CustomRefCountingOperationKind { retain, release };
struct CustomRefCountingOperationDescriptor final {
const ClassDecl *decl;
CustomRefCountingOperationKind kind;
CustomRefCountingOperationDescriptor(const ClassDecl *decl,
CustomRefCountingOperationKind kind)
: decl(decl), kind(kind) {}
friend llvm::hash_code
hash_value(const CustomRefCountingOperationDescriptor &desc) {
return llvm::hash_combine(desc.decl, desc.kind);
}
friend bool operator==(const CustomRefCountingOperationDescriptor &lhs,
const CustomRefCountingOperationDescriptor &rhs) {
return lhs.decl == rhs.decl && lhs.kind == rhs.kind;
}
friend bool operator!=(const CustomRefCountingOperationDescriptor &lhs,
const CustomRefCountingOperationDescriptor &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out,
CustomRefCountingOperationDescriptor desc);
SourceLoc extractNearestSourceLoc(CustomRefCountingOperationDescriptor desc);
struct CustomRefCountingOperationResult {
enum CustomRefCountingOperationResultKind {
noAttribute,
tooManyAttributes,
immortal,
notFound,
tooManyFound,
foundOperation
};
CustomRefCountingOperationResultKind kind;
ValueDecl *operation;
std::string name;
};
class CustomRefCountingOperation
: public SimpleRequest<CustomRefCountingOperation,
CustomRefCountingOperationResult(
CustomRefCountingOperationDescriptor),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
// Caching
bool isCached() const { return true; }
// Source location
SourceLoc getNearestLoc() const { return SourceLoc(); };
private:
friend SimpleRequest;
// Evaluation.
CustomRefCountingOperationResult
evaluate(Evaluator &evaluator,
CustomRefCountingOperationDescriptor desc) const;
};
enum class CxxEscapability { Escapable, NonEscapable, Unknown };
struct EscapabilityLookupDescriptor final {
const clang::Type *type;
ClangImporter::Implementation *impl;
bool annotationOnly = true;
friend llvm::hash_code hash_value(const EscapabilityLookupDescriptor &desc) {
return llvm::hash_combine(desc.type);
}
friend bool operator==(const EscapabilityLookupDescriptor &lhs,
const EscapabilityLookupDescriptor &rhs) {
return lhs.type == rhs.type && lhs.annotationOnly == rhs.annotationOnly;
}
friend bool operator!=(const EscapabilityLookupDescriptor &lhs,
const EscapabilityLookupDescriptor &rhs) {
return !(lhs == rhs);
}
};
class ClangTypeEscapability
: public SimpleRequest<ClangTypeEscapability,
CxxEscapability(EscapabilityLookupDescriptor),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
bool isCached() const { return true; }
private:
friend SimpleRequest;
CxxEscapability evaluate(Evaluator &evaluator,
EscapabilityLookupDescriptor desc) const;
};
void simple_display(llvm::raw_ostream &out, EscapabilityLookupDescriptor desc);
SourceLoc extractNearestSourceLoc(EscapabilityLookupDescriptor desc);
/// Determine the safety of the given Clang declaration.
class ClangDeclExplicitSafety
: public SimpleRequest<ClangDeclExplicitSafety,
ExplicitSafety(SafeUseOfCxxDeclDescriptor),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
// Source location
SourceLoc getNearestLoc() const { return SourceLoc(); };
bool isCached() const;
private:
friend SimpleRequest;
// Evaluation.
ExplicitSafety evaluate(Evaluator &evaluator, SafeUseOfCxxDeclDescriptor desc) const;
};
#define SWIFT_TYPEID_ZONE ClangImporter
#define SWIFT_TYPEID_HEADER "swift/ClangImporter/ClangImporterTypeIDZone.def"
#include "swift/Basic/DefineTypeIDZone.h"
#undef SWIFT_TYPEID_ZONE
#undef SWIFT_TYPEID_HEADER
// Set up reporting of evaluated requests.
template<typename Request>
void reportEvaluatedRequest(UnifiedStatsReporter &stats,
const Request &request);
#define SWIFT_REQUEST(Zone, RequestType, Sig, Caching, LocOptions) \
template <> \
inline void reportEvaluatedRequest(UnifiedStatsReporter &stats, \
const RequestType &request) { \
++stats.getFrontendCounters().RequestType; \
}
#include "swift/ClangImporter/ClangImporterTypeIDZone.def"
#undef SWIFT_REQUEST
} // end namespace swift
#endif // SWIFT_CLANG_IMPORTER_REQUESTS_H