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

686 lines
24 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//===--- 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 {
Value,
Reference,
Iterator,
// 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;
CxxRecordSemanticsDescriptor(const clang::RecordDecl *decl, ASTContext &ctx,
ClangImporter::Implementation *importerImpl)
: decl(decl), ctx(ctx), importerImpl(importerImpl) {}
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;
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;
}
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);
// Swift value semantics of C++ types
// These are usually equivalent, with the exception of references.
// When a reference type is copied, the pointers value is copied rather than
// the objects storage. This means reference types can be imported as
// copyable to Swift, even when they are non-copyable in C++.
enum class CxxValueSemanticsKind { Unknown, Copyable, MoveOnly };
struct CxxValueSemanticsDescriptor final {
const clang::Type *type;
ClangImporter::Implementation *importerImpl;
friend llvm::hash_code hash_value(const CxxValueSemanticsDescriptor &desc) {
return llvm::hash_combine(desc.type);
}
friend bool operator==(const CxxValueSemanticsDescriptor &lhs,
const CxxValueSemanticsDescriptor &rhs) {
return lhs.type == rhs.type;
}
friend bool operator!=(const CxxValueSemanticsDescriptor &lhs,
const CxxValueSemanticsDescriptor &rhs) {
return !(lhs == rhs);
}
};
class CxxValueSemantics
: public SimpleRequest<CxxValueSemantics,
CxxValueSemanticsKind(
CxxValueSemanticsDescriptor),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
bool isCached() const { return true; }
private:
friend SimpleRequest;
CxxValueSemanticsKind evaluate(Evaluator &evaluator,
CxxValueSemanticsDescriptor desc) const;
};
void simple_display(llvm::raw_ostream &out, CxxValueSemanticsDescriptor desc);
SourceLoc extractNearestSourceLoc(CxxValueSemanticsDescriptor desc);
struct ClangDeclExplicitSafetyDescriptor final {
const clang::Decl *decl;
bool isClass;
ClangDeclExplicitSafetyDescriptor(const clang::Decl *decl, bool isClass)
: decl(decl), isClass(isClass) {}
friend llvm::hash_code
hash_value(const ClangDeclExplicitSafetyDescriptor &desc) {
return llvm::hash_combine(desc.decl, desc.isClass);
}
friend bool operator==(const ClangDeclExplicitSafetyDescriptor &lhs,
const ClangDeclExplicitSafetyDescriptor &rhs) {
return lhs.decl == rhs.decl && lhs.isClass == rhs.isClass;
}
friend bool operator!=(const ClangDeclExplicitSafetyDescriptor &lhs,
const ClangDeclExplicitSafetyDescriptor &rhs) {
return !(lhs == rhs);
}
};
void simple_display(llvm::raw_ostream &out,
ClangDeclExplicitSafetyDescriptor desc);
SourceLoc extractNearestSourceLoc(ClangDeclExplicitSafetyDescriptor desc);
/// Determine the safety of the given Clang declaration.
class ClangDeclExplicitSafety
: public SimpleRequest<ClangDeclExplicitSafety,
ExplicitSafety(ClangDeclExplicitSafetyDescriptor),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
// Source location
SourceLoc getNearestLoc() const { return SourceLoc(); };
bool isCached() const;
private:
friend SimpleRequest;
// Evaluation.
ExplicitSafety evaluate(Evaluator &evaluator,
ClangDeclExplicitSafetyDescriptor 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