mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge remote-tracking branch 'origin/main' into rebranch
This commit is contained in:
@@ -2294,6 +2294,22 @@ int swift::ide::api::deserializeSDKDump(StringRef dumpPath, StringRef OutputPath
|
||||
return 0;
|
||||
}
|
||||
|
||||
void swift::ide::api::dumpModuleContent(ModuleDecl *MD, StringRef OutputFile,
|
||||
bool ABI) {
|
||||
CheckerOptions opts;
|
||||
opts.ABI = ABI;
|
||||
opts.SwiftOnly = true;
|
||||
opts.AvoidLocation = true;
|
||||
opts.AvoidToolArgs = true;
|
||||
opts.Migrator = false;
|
||||
opts.SkipOSCheck = false;
|
||||
opts.Verbose = false;
|
||||
SDKContext ctx(opts);
|
||||
SwiftDeclCollector collector(ctx);
|
||||
collector.lookupVisibleDecls({MD});
|
||||
dumpSDKRoot(collector.getSDKRoot(), OutputFile);
|
||||
}
|
||||
|
||||
int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) {
|
||||
std::error_code EC;
|
||||
if (!fs::exists(dumpPath)) {
|
||||
@@ -2323,3 +2339,301 @@ int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeDeclType::diagnose(SDKNode *Right) {
|
||||
SDKNodeDecl::diagnose(Right);
|
||||
auto *R = dyn_cast<SDKNodeDeclType>(Right);
|
||||
if (!R)
|
||||
return;
|
||||
auto Loc = R->getLoc();
|
||||
if (getDeclKind() != R->getDeclKind()) {
|
||||
emitDiag(Loc, diag::decl_kind_changed, getDeclKindStr(R->getDeclKind(),
|
||||
getSDKContext().getOpts().CompilerStyle));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(getDeclKind() == R->getDeclKind());
|
||||
auto DKind = getDeclKind();
|
||||
switch (DKind) {
|
||||
case DeclKind::Class: {
|
||||
auto LSuperClass = getSuperClassName();
|
||||
auto RSuperClass = R->getSuperClassName();
|
||||
if (!LSuperClass.empty() && LSuperClass != RSuperClass) {
|
||||
if (RSuperClass.empty()) {
|
||||
emitDiag(Loc, diag::super_class_removed, LSuperClass);
|
||||
} else if (!llvm::is_contained(R->getClassInheritanceChain(), LSuperClass)) {
|
||||
emitDiag(Loc, diag::super_class_changed, LSuperClass, RSuperClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for @_hasMissingDesignatedInitializers and
|
||||
// @_inheritsConvenienceInitializers changes.
|
||||
if (isOpen() && R->isOpen()) {
|
||||
// It's not safe to add new, invisible designated inits to open
|
||||
// classes.
|
||||
if (!hasMissingDesignatedInitializers() &&
|
||||
R->hasMissingDesignatedInitializers())
|
||||
R->emitDiag(R->getLoc(), diag::added_invisible_designated_init);
|
||||
}
|
||||
|
||||
// It's not safe to stop inheriting convenience inits, it changes
|
||||
// the set of initializers that are available.
|
||||
if (!Ctx.checkingABI() &&
|
||||
inheritsConvenienceInitializers() &&
|
||||
!R->inheritsConvenienceInitializers())
|
||||
R->emitDiag(R->getLoc(), diag::not_inheriting_convenience_inits);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeDeclAbstractFunc::diagnose(SDKNode *Right) {
|
||||
SDKNodeDecl::diagnose(Right);
|
||||
auto *R = dyn_cast<SDKNodeDeclAbstractFunc>(Right);
|
||||
if (!R)
|
||||
return;
|
||||
auto Loc = R->getLoc();
|
||||
if (!isThrowing() && R->isThrowing()) {
|
||||
emitDiag(Loc, diag::decl_new_attr, Ctx.buffer("throwing"));
|
||||
}
|
||||
if (Ctx.checkingABI()) {
|
||||
if (reqNewWitnessTableEntry() != R->reqNewWitnessTableEntry()) {
|
||||
emitDiag(Loc, diag::decl_new_witness_table_entry, reqNewWitnessTableEntry());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeDeclFunction::diagnose(SDKNode *Right) {
|
||||
SDKNodeDeclAbstractFunc::diagnose(Right);
|
||||
auto *R = dyn_cast<SDKNodeDeclFunction>(Right);
|
||||
if (!R)
|
||||
return;
|
||||
auto Loc = R->getLoc();
|
||||
if (getSelfAccessKind() != R->getSelfAccessKind()) {
|
||||
emitDiag(Loc, diag::func_self_access_change, getSelfAccessKind(),
|
||||
R->getSelfAccessKind());
|
||||
}
|
||||
if (Ctx.checkingABI()) {
|
||||
if (hasFixedBinaryOrder() != R->hasFixedBinaryOrder()) {
|
||||
emitDiag(Loc, diag::func_has_fixed_order_change, hasFixedBinaryOrder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static StringRef getAttrName(DeclAttrKind Kind) {
|
||||
switch (Kind) {
|
||||
#define DECL_ATTR(NAME, CLASS, ...) \
|
||||
case DAK_##CLASS: \
|
||||
return DeclAttribute::isDeclModifier(DAK_##CLASS) ? #NAME : "@"#NAME;
|
||||
#include "swift/AST/Attr.def"
|
||||
case DAK_Count:
|
||||
llvm_unreachable("unrecognized attribute kind.");
|
||||
}
|
||||
llvm_unreachable("covered switch");
|
||||
}
|
||||
|
||||
static bool shouldDiagnoseAddingAttribute(SDKNodeDecl *D, DeclAttrKind Kind) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool shouldDiagnoseRemovingAttribute(SDKNodeDecl *D, DeclAttrKind Kind) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isOwnershipEquivalent(ReferenceOwnership Left,
|
||||
ReferenceOwnership Right) {
|
||||
if (Left == Right)
|
||||
return true;
|
||||
if (Left == ReferenceOwnership::Unowned && Right == ReferenceOwnership::Weak)
|
||||
return true;
|
||||
if (Left == ReferenceOwnership::Weak && Right == ReferenceOwnership::Unowned)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void swift::ide::api::detectRename(SDKNode *L, SDKNode *R) {
|
||||
if (L->getKind() == R->getKind() && isa<SDKNodeDecl>(L) &&
|
||||
L->getPrintedName() != R->getPrintedName()) {
|
||||
L->annotate(NodeAnnotation::Rename);
|
||||
L->annotate(NodeAnnotation::RenameOldName, L->getPrintedName());
|
||||
L->annotate(NodeAnnotation::RenameNewName, R->getPrintedName());
|
||||
}
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeDecl::diagnose(SDKNode *Right) {
|
||||
SDKNode::diagnose(Right);
|
||||
auto *RD = dyn_cast<SDKNodeDecl>(Right);
|
||||
if (!RD)
|
||||
return;
|
||||
detectRename(this, RD);
|
||||
auto Loc = RD->getLoc();
|
||||
if (isOpen() && !RD->isOpen()) {
|
||||
emitDiag(Loc, diag::no_longer_open);
|
||||
}
|
||||
|
||||
// Diagnose static attribute change.
|
||||
if (isStatic() ^ RD->isStatic()) {
|
||||
emitDiag(Loc, diag::decl_new_attr, Ctx.buffer(isStatic() ? "not static" :
|
||||
"static"));
|
||||
}
|
||||
|
||||
// Diagnose ownership change.
|
||||
if (!isOwnershipEquivalent(getReferenceOwnership(),
|
||||
RD->getReferenceOwnership())) {
|
||||
auto getOwnershipDescription = [&](swift::ReferenceOwnership O) {
|
||||
if (O == ReferenceOwnership::Strong)
|
||||
return Ctx.buffer("strong");
|
||||
return keywordOf(O);
|
||||
};
|
||||
emitDiag(Loc, diag::decl_attr_change,
|
||||
getOwnershipDescription(getReferenceOwnership()),
|
||||
getOwnershipDescription(RD->getReferenceOwnership()));
|
||||
}
|
||||
// Diagnose generic signature change
|
||||
if (getGenericSignature() != RD->getGenericSignature()) {
|
||||
// Prefer sugared signature in diagnostics to be more user-friendly.
|
||||
if (Ctx.commonVersionAtLeast(2) &&
|
||||
getSugaredGenericSignature() != RD->getSugaredGenericSignature()) {
|
||||
emitDiag(Loc, diag::generic_sig_change,
|
||||
getSugaredGenericSignature(), RD->getSugaredGenericSignature());
|
||||
} else {
|
||||
emitDiag(Loc, diag::generic_sig_change,
|
||||
getGenericSignature(), RD->getGenericSignature());
|
||||
}
|
||||
}
|
||||
|
||||
// ObjC name changes are considered breakage
|
||||
if (getObjCName() != RD->getObjCName()) {
|
||||
if (Ctx.commonVersionAtLeast(4)) {
|
||||
emitDiag(Loc, diag::objc_name_change, getObjCName(), RD->getObjCName());
|
||||
}
|
||||
}
|
||||
|
||||
if (isOptional() != RD->isOptional()) {
|
||||
if (Ctx.checkingABI()) {
|
||||
// Both adding/removing optional is ABI-breaking.
|
||||
emitDiag(Loc, diag::optional_req_changed, isOptional());
|
||||
} else if (isOptional()) {
|
||||
// Removing optional is source-breaking.
|
||||
emitDiag(Loc, diag::optional_req_changed, isOptional());
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnose removing attributes.
|
||||
for (auto Kind: getDeclAttributes()) {
|
||||
if (!RD->hasDeclAttribute(Kind)) {
|
||||
if ((Ctx.checkingABI() ? DeclAttribute::isRemovingBreakingABI(Kind) :
|
||||
DeclAttribute::isRemovingBreakingAPI(Kind)) &&
|
||||
shouldDiagnoseRemovingAttribute(this, Kind)) {
|
||||
emitDiag(Loc, diag::decl_new_attr,
|
||||
Ctx.buffer((llvm::Twine("without ") + getAttrName(Kind)).str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnose adding attributes.
|
||||
for (auto Kind: RD->getDeclAttributes()) {
|
||||
if (!hasDeclAttribute(Kind)) {
|
||||
if ((Ctx.checkingABI() ? DeclAttribute::isAddingBreakingABI(Kind) :
|
||||
DeclAttribute::isAddingBreakingAPI(Kind)) &&
|
||||
shouldDiagnoseAddingAttribute(this, Kind)) {
|
||||
emitDiag(Loc, diag::decl_new_attr,
|
||||
Ctx.buffer((llvm::Twine("with ") + getAttrName(Kind)).str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Ctx.checkingABI()) {
|
||||
if (hasFixedBinaryOrder() && RD->hasFixedBinaryOrder() &&
|
||||
getFixedBinaryOrder() != RD->getFixedBinaryOrder()) {
|
||||
emitDiag(Loc, diag::decl_reorder, getFixedBinaryOrder(),
|
||||
RD->getFixedBinaryOrder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeDeclOperator::diagnose(SDKNode *Right) {
|
||||
SDKNodeDecl::diagnose(Right);
|
||||
auto *RO = dyn_cast<SDKNodeDeclOperator>(Right);
|
||||
if (!RO)
|
||||
return;
|
||||
auto Loc = RO->getLoc();
|
||||
if (getDeclKind() != RO->getDeclKind()) {
|
||||
emitDiag(Loc, diag::decl_kind_changed, getDeclKindStr(RO->getDeclKind(),
|
||||
getSDKContext().getOpts().CompilerStyle));
|
||||
}
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeDeclVar::diagnose(SDKNode *Right) {
|
||||
SDKNodeDecl::diagnose(Right);
|
||||
auto *RV = dyn_cast<SDKNodeDeclVar>(Right);
|
||||
if (!RV)
|
||||
return;
|
||||
auto Loc = RV->getLoc();
|
||||
if (Ctx.checkingABI()) {
|
||||
if (hasFixedBinaryOrder() != RV->hasFixedBinaryOrder()) {
|
||||
emitDiag(Loc, diag::var_has_fixed_order_change, hasFixedBinaryOrder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool shouldDiagnoseType(SDKNodeType *T) {
|
||||
return T->isTopLevelType();
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeType::diagnose(SDKNode *Right) {
|
||||
SDKNode::diagnose(Right);
|
||||
auto *RT = dyn_cast<SDKNodeType>(Right);
|
||||
if (!RT || !shouldDiagnoseType(this))
|
||||
return;
|
||||
assert(isTopLevelType());
|
||||
|
||||
// Diagnose type witness changes when diagnosing ABI breakages.
|
||||
if (auto *Wit = dyn_cast<SDKNodeTypeWitness>(getParent())) {
|
||||
auto *Conform = Wit->getParent()->getAs<SDKNodeConformance>();
|
||||
if (Ctx.checkingABI() && getPrintedName() != RT->getPrintedName()) {
|
||||
auto *LD = Conform->getNominalTypeDecl();
|
||||
LD->emitDiag(SourceLoc(), diag::type_witness_change,
|
||||
Wit->getWitnessedTypeName(),
|
||||
getPrintedName(), RT->getPrintedName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Descriptor = getTypeRoleDescription();
|
||||
assert(isa<SDKNodeDecl>(getParent()));
|
||||
auto LParent = cast<SDKNodeDecl>(getParent());
|
||||
assert(LParent->getKind() == RT->getParent()->getAs<SDKNodeDecl>()->getKind());
|
||||
auto Loc = RT->getParent()->getAs<SDKNodeDecl>()->getLoc();
|
||||
if (getPrintedName() != RT->getPrintedName()) {
|
||||
LParent->emitDiag(Loc, diag::decl_type_change,
|
||||
Descriptor, getPrintedName(), RT->getPrintedName());
|
||||
}
|
||||
|
||||
if (hasDefaultArgument() && !RT->hasDefaultArgument()) {
|
||||
LParent->emitDiag(Loc, diag::default_arg_removed, Descriptor);
|
||||
}
|
||||
if (getParamValueOwnership() != RT->getParamValueOwnership()) {
|
||||
LParent->emitDiag(Loc, diag::param_ownership_change,
|
||||
getTypeRoleDescription(),
|
||||
getParamValueOwnership(),
|
||||
RT->getParamValueOwnership());
|
||||
}
|
||||
}
|
||||
|
||||
void swift::ide::api::SDKNodeTypeFunc::diagnose(SDKNode *Right) {
|
||||
SDKNodeType::diagnose(Right);
|
||||
auto *RT = dyn_cast<SDKNodeTypeFunc>(Right);
|
||||
if (!RT || !shouldDiagnoseType(this))
|
||||
return;
|
||||
assert(isTopLevelType());
|
||||
auto Loc = RT->getParent()->getAs<SDKNodeDecl>()->getLoc();
|
||||
if (Ctx.checkingABI() && isEscaping() != RT->isEscaping()) {
|
||||
getParent()->getAs<SDKNodeDecl>()->emitDiag(Loc,
|
||||
diag::func_type_escaping_changed,
|
||||
getTypeRoleDescription(),
|
||||
isEscaping());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user