mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Add an alternative to getTopLevelDecls and getDeclChecked to limit which decls are deserialized by first looking at their attributes. If the attributes are accepted by a function passed as argument the decl is fully deserialized, otherwise it is ignored. The filter is included in the signature of existing functions in the Serilalization services, but I’ve added new methods for it in FileUnit and its subclasses to leave existing implementations untouched.
463 lines
12 KiB
C++
463 lines
12 KiB
C++
//===--- DeserializationErrors.h - Problems in deserialization --*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SERIALIZATION_DESERIALIZATIONERRORS_H
|
|
#define SWIFT_SERIALIZATION_DESERIALIZATIONERRORS_H
|
|
|
|
#include "ModuleFormat.h"
|
|
#include "swift/AST/Identifier.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
|
|
namespace swift {
|
|
class ModuleFile;
|
|
|
|
StringRef getNameOfModule(const ModuleFile *);
|
|
|
|
namespace serialization {
|
|
|
|
class XRefTracePath {
|
|
class PathPiece {
|
|
public:
|
|
enum class Kind {
|
|
Value,
|
|
Type,
|
|
Operator,
|
|
OperatorFilter,
|
|
Accessor,
|
|
Extension,
|
|
GenericParam,
|
|
PrivateDiscriminator,
|
|
OpaqueReturnType,
|
|
Unknown
|
|
};
|
|
|
|
private:
|
|
Kind kind;
|
|
void *data;
|
|
|
|
template <typename T>
|
|
T getDataAs() const {
|
|
return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(data);
|
|
}
|
|
|
|
public:
|
|
template <typename T>
|
|
PathPiece(Kind K, T value)
|
|
: kind(K),
|
|
data(llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(value)) {}
|
|
|
|
DeclBaseName getAsBaseName() const {
|
|
switch (kind) {
|
|
case Kind::Value:
|
|
case Kind::Operator:
|
|
case Kind::PrivateDiscriminator:
|
|
case Kind::OpaqueReturnType:
|
|
return getDataAs<DeclBaseName>();
|
|
case Kind::Type:
|
|
case Kind::OperatorFilter:
|
|
case Kind::Accessor:
|
|
case Kind::Extension:
|
|
case Kind::GenericParam:
|
|
case Kind::Unknown:
|
|
return Identifier();
|
|
}
|
|
llvm_unreachable("unhandled kind");
|
|
}
|
|
|
|
void print(raw_ostream &os) const {
|
|
switch (kind) {
|
|
case Kind::Value:
|
|
os << getDataAs<DeclBaseName>();
|
|
break;
|
|
case Kind::Type:
|
|
os << "with type " << getDataAs<Type>();
|
|
break;
|
|
case Kind::Extension:
|
|
if (getDataAs<ModuleDecl *>()) {
|
|
os << "in an extension in module '"
|
|
<< getDataAs<ModuleDecl *>()->getName()
|
|
<< "'";
|
|
} else {
|
|
os << "in an extension in any module";
|
|
}
|
|
break;
|
|
case Kind::Operator:
|
|
os << "operator " << getDataAs<Identifier>();
|
|
break;
|
|
case Kind::OperatorFilter:
|
|
switch (getDataAs<uintptr_t>()) {
|
|
case Infix:
|
|
os << "(infix)";
|
|
break;
|
|
case Prefix:
|
|
os << "(prefix)";
|
|
break;
|
|
case Postfix:
|
|
os << "(postfix)";
|
|
break;
|
|
default:
|
|
os << "(unknown operator filter)";
|
|
break;
|
|
}
|
|
break;
|
|
case Kind::Accessor:
|
|
switch (getDataAs<uintptr_t>()) {
|
|
case Get:
|
|
os << "(getter)";
|
|
break;
|
|
case Set:
|
|
os << "(setter)";
|
|
break;
|
|
case Address:
|
|
os << "(addressor)";
|
|
break;
|
|
case MutableAddress:
|
|
os << "(mutableAddressor)";
|
|
break;
|
|
case WillSet:
|
|
os << "(willSet)";
|
|
break;
|
|
case DidSet:
|
|
os << "(didSet)";
|
|
break;
|
|
case Read:
|
|
os << "(read)";
|
|
break;
|
|
case Modify:
|
|
os << "(modify)";
|
|
break;
|
|
default:
|
|
os << "(unknown accessor kind)";
|
|
break;
|
|
}
|
|
break;
|
|
case Kind::GenericParam:
|
|
os << "generic param #" << getDataAs<uintptr_t>();
|
|
break;
|
|
case Kind::PrivateDiscriminator:
|
|
os << "(in " << getDataAs<Identifier>() << ")";
|
|
break;
|
|
case Kind::OpaqueReturnType:
|
|
os << "opaque return type of " << getDataAs<DeclBaseName>();
|
|
break;
|
|
case Kind::Unknown:
|
|
os << "unknown xref kind " << getDataAs<uintptr_t>();
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
ModuleDecl &baseM;
|
|
SmallVector<PathPiece, 8> path;
|
|
|
|
public:
|
|
explicit XRefTracePath(ModuleDecl &M) : baseM(M) {}
|
|
|
|
void addValue(DeclBaseName name) {
|
|
path.push_back({ PathPiece::Kind::Value, name });
|
|
}
|
|
|
|
void addType(Type ty) {
|
|
path.push_back({ PathPiece::Kind::Type, ty });
|
|
}
|
|
|
|
void addOperator(Identifier name) {
|
|
path.push_back({ PathPiece::Kind::Operator, name });
|
|
}
|
|
|
|
void addOperatorFilter(uint8_t fixity) {
|
|
path.push_back({ PathPiece::Kind::OperatorFilter,
|
|
static_cast<uintptr_t>(fixity) });
|
|
}
|
|
|
|
void addAccessor(uint8_t kind) {
|
|
path.push_back({ PathPiece::Kind::Accessor,
|
|
static_cast<uintptr_t>(kind) });
|
|
}
|
|
|
|
void addExtension(ModuleDecl *M) {
|
|
path.push_back({ PathPiece::Kind::Extension, M });
|
|
}
|
|
|
|
void addGenericParam(uintptr_t index) {
|
|
path.push_back({ PathPiece::Kind::GenericParam, index });
|
|
}
|
|
|
|
void addPrivateDiscriminator(Identifier name) {
|
|
path.push_back({ PathPiece::Kind::PrivateDiscriminator, name });
|
|
}
|
|
|
|
void addUnknown(uintptr_t kind) {
|
|
path.push_back({ PathPiece::Kind::Unknown, kind });
|
|
}
|
|
|
|
void addOpaqueReturnType(Identifier name) {
|
|
path.push_back({ PathPiece::Kind::OpaqueReturnType, name });
|
|
}
|
|
|
|
DeclBaseName getLastName() const {
|
|
for (auto &piece : llvm::reverse(path)) {
|
|
DeclBaseName result = piece.getAsBaseName();
|
|
if (!result.empty())
|
|
return result;
|
|
}
|
|
return DeclBaseName();
|
|
}
|
|
|
|
void removeLast() {
|
|
path.pop_back();
|
|
}
|
|
|
|
void print(raw_ostream &os, StringRef leading = "") const {
|
|
os << "Cross-reference to module '" << baseM.getName() << "'\n";
|
|
for (auto &piece : path) {
|
|
os << leading << "... ";
|
|
piece.print(os);
|
|
os << "\n";
|
|
}
|
|
}
|
|
};
|
|
|
|
class DeclDeserializationError : public llvm::ErrorInfoBase {
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
public:
|
|
enum Flag : unsigned {
|
|
DesignatedInitializer = 1 << 0,
|
|
NeedsFieldOffsetVectorEntry = 1 << 1,
|
|
};
|
|
using Flags = OptionSet<Flag>;
|
|
|
|
protected:
|
|
DeclName name;
|
|
Flags flags;
|
|
uint8_t numVTableEntries = 0;
|
|
|
|
public:
|
|
DeclName getName() const {
|
|
return name;
|
|
}
|
|
|
|
bool isDesignatedInitializer() const {
|
|
return flags.contains(Flag::DesignatedInitializer);
|
|
}
|
|
unsigned getNumberOfVTableEntries() const {
|
|
return numVTableEntries;
|
|
}
|
|
bool needsFieldOffsetVectorEntry() const {
|
|
return flags.contains(Flag::NeedsFieldOffsetVectorEntry);
|
|
}
|
|
|
|
bool isA(const void *const ClassID) const override {
|
|
return ClassID == classID() || ErrorInfoBase::isA(ClassID);
|
|
}
|
|
|
|
static const void *classID() { return &ID; }
|
|
};
|
|
|
|
class XRefError : public llvm::ErrorInfo<XRefError, DeclDeserializationError> {
|
|
friend ErrorInfo;
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
XRefTracePath path;
|
|
const char *message;
|
|
public:
|
|
template <size_t N>
|
|
XRefError(const char (&message)[N], XRefTracePath path, DeclName name)
|
|
: path(path), message(message) {
|
|
this->name = name;
|
|
}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << message << "\n";
|
|
path.print(OS);
|
|
}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::inconvertibleErrorCode();
|
|
}
|
|
};
|
|
|
|
class XRefNonLoadedModuleError :
|
|
public llvm::ErrorInfo<XRefNonLoadedModuleError, DeclDeserializationError> {
|
|
friend ErrorInfo;
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
public:
|
|
explicit XRefNonLoadedModuleError(Identifier name) {
|
|
this->name = name;
|
|
}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << "module '" << name << "' was not loaded";
|
|
}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::inconvertibleErrorCode();
|
|
}
|
|
};
|
|
|
|
class OverrideError : public llvm::ErrorInfo<OverrideError,
|
|
DeclDeserializationError> {
|
|
private:
|
|
friend ErrorInfo;
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
public:
|
|
explicit OverrideError(DeclName name,
|
|
Flags flags={}, unsigned numVTableEntries=0) {
|
|
this->name = name;
|
|
this->flags = flags;
|
|
this->numVTableEntries = numVTableEntries;
|
|
}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << "could not find '" << name << "' in parent class";
|
|
}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::inconvertibleErrorCode();
|
|
}
|
|
};
|
|
|
|
class TypeError : public llvm::ErrorInfo<TypeError, DeclDeserializationError> {
|
|
friend ErrorInfo;
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
std::unique_ptr<ErrorInfoBase> underlyingReason;
|
|
public:
|
|
explicit TypeError(DeclName name, std::unique_ptr<ErrorInfoBase> reason,
|
|
Flags flags={}, unsigned numVTableEntries=0)
|
|
: underlyingReason(std::move(reason)) {
|
|
this->name = name;
|
|
this->flags = flags;
|
|
this->numVTableEntries = numVTableEntries;
|
|
}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << "could not deserialize type for '" << name << "'";
|
|
if (underlyingReason) {
|
|
OS << ": ";
|
|
underlyingReason->log(OS);
|
|
}
|
|
}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::inconvertibleErrorCode();
|
|
}
|
|
};
|
|
|
|
class ExtensionError : public llvm::ErrorInfo<ExtensionError> {
|
|
friend ErrorInfo;
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
std::unique_ptr<ErrorInfoBase> underlyingReason;
|
|
|
|
public:
|
|
explicit ExtensionError(std::unique_ptr<ErrorInfoBase> reason)
|
|
: underlyingReason(std::move(reason)) {}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << "could not deserialize extension";
|
|
if (underlyingReason) {
|
|
OS << ": ";
|
|
underlyingReason->log(OS);
|
|
}
|
|
}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::inconvertibleErrorCode();
|
|
}
|
|
};
|
|
|
|
class SILEntityError : public llvm::ErrorInfo<SILEntityError> {
|
|
friend ErrorInfo;
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
std::unique_ptr<ErrorInfoBase> underlyingReason;
|
|
StringRef name;
|
|
public:
|
|
SILEntityError(StringRef name, std::unique_ptr<ErrorInfoBase> reason)
|
|
: underlyingReason(std::move(reason)), name(name) {}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << "could not deserialize SIL entity '" << name << "'";
|
|
if (underlyingReason) {
|
|
OS << ": ";
|
|
underlyingReason->log(OS);
|
|
}
|
|
}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::inconvertibleErrorCode();
|
|
}
|
|
};
|
|
|
|
// Decl was not deserialized because its attributes did not match the filter.
|
|
//
|
|
// \sa getDeclChecked
|
|
class DeclAttributesDidNotMatch : public llvm::ErrorInfo<DeclAttributesDidNotMatch> {
|
|
friend ErrorInfo;
|
|
static const char ID;
|
|
void anchor() override;
|
|
|
|
public:
|
|
DeclAttributesDidNotMatch() {}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << "Decl attributes did not match filter";
|
|
}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::inconvertibleErrorCode();
|
|
}
|
|
};
|
|
|
|
LLVM_NODISCARD
|
|
static inline std::unique_ptr<llvm::ErrorInfoBase>
|
|
takeErrorInfo(llvm::Error error) {
|
|
std::unique_ptr<llvm::ErrorInfoBase> result;
|
|
llvm::handleAllErrors(std::move(error),
|
|
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
|
|
result = std::move(info);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
|
|
const char *Action;
|
|
const ModuleFile &MF;
|
|
public:
|
|
explicit PrettyStackTraceModuleFile(const char *action, ModuleFile &module)
|
|
: Action(action), MF(module) {}
|
|
explicit PrettyStackTraceModuleFile(ModuleFile &module)
|
|
: PrettyStackTraceModuleFile("While reading from", module) {}
|
|
|
|
void print(raw_ostream &os) const override {
|
|
os << Action << " \'" << getNameOfModule(&MF) << "'\n";
|
|
}
|
|
};
|
|
|
|
} // end namespace serialization
|
|
} // end namespace swift
|
|
|
|
#endif
|